github.com/drud/ddev@v1.21.5-alpha1.0.20230226034409-94fcc4b94453/pkg/ddevapp/settings_test.go (about)

     1  package ddevapp_test
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  	"time"
     9  
    10  	. "github.com/drud/ddev/pkg/ddevapp"
    11  	"github.com/drud/ddev/pkg/fileutil"
    12  	"github.com/drud/ddev/pkg/nodeps"
    13  	"github.com/drud/ddev/pkg/testcommon"
    14  	"github.com/drud/ddev/pkg/util"
    15  	asrt "github.com/stretchr/testify/assert"
    16  )
    17  
    18  type settingsLocations struct {
    19  	main  string
    20  	local string
    21  }
    22  
    23  var drupalBackdropSettingsLocations = map[string]settingsLocations{
    24  	nodeps.AppTypeDrupal6:  {main: "sites/default/settings.php", local: "sites/default/settings.ddev.php"},
    25  	nodeps.AppTypeDrupal7:  {main: "sites/default/settings.php", local: "sites/default/settings.ddev.php"},
    26  	nodeps.AppTypeDrupal8:  {main: "sites/default/settings.php", local: "sites/default/settings.ddev.php"},
    27  	nodeps.AppTypeDrupal9:  {main: "sites/default/settings.php", local: "sites/default/settings.ddev.php"},
    28  	nodeps.AppTypeBackdrop: {main: "settings.php", local: "settings.ddev.php"},
    29  }
    30  
    31  // TestWriteSettings tests writing app settings (like Drupal
    32  // settings.php/settings.ddev.php
    33  func TestWriteSettings(t *testing.T) {
    34  	assert := asrt.New(t)
    35  
    36  	expectations := map[string]string{
    37  		nodeps.AppTypeBackdrop:  "settings.ddev.php",
    38  		nodeps.AppTypeDrupal6:   "sites/default/settings.ddev.php",
    39  		nodeps.AppTypeDrupal7:   "sites/default/settings.ddev.php",
    40  		nodeps.AppTypeDrupal8:   "sites/default/settings.ddev.php",
    41  		nodeps.AppTypeDrupal9:   "sites/default/settings.ddev.php",
    42  		nodeps.AppTypeWordPress: "wp-config-ddev.php",
    43  		nodeps.AppTypeTYPO3:     "typo3conf/AdditionalConfiguration.php",
    44  	}
    45  	testDir := testcommon.CreateTmpDir(t.Name())
    46  
    47  	app, err := NewApp(testDir, true)
    48  	assert.NoError(err)
    49  
    50  	t.Cleanup(func() {
    51  		err = app.Stop(true, false)
    52  		assert.NoError(err)
    53  		_ = os.RemoveAll(testDir)
    54  	})
    55  
    56  	err = os.MkdirAll(filepath.Join(testDir, app.Docroot, "sites", "default"), 0777)
    57  	assert.NoError(err)
    58  
    59  	// Create expected folders for TYPO3.
    60  	err = os.MkdirAll(filepath.Join(testDir, app.Docroot, "typo3"), 0777)
    61  	assert.NoError(err)
    62  
    63  	err = os.MkdirAll(filepath.Join(testDir, app.Docroot, "typo3conf"), 0777)
    64  	assert.NoError(err)
    65  
    66  	// TYPO3 wants LocalConfiguration.php to exist in the repo ahead of time.
    67  	err = os.WriteFile(filepath.Join(testDir, app.Docroot, "typo3conf", "LocalConfiguration.php"), []byte("<?php\n"), 0644)
    68  	assert.NoError(err)
    69  
    70  	for apptype, settingsRelativePath := range expectations {
    71  		app.Type = apptype
    72  
    73  		expectedSettingsFile := filepath.Join(testDir, settingsRelativePath)
    74  		_, err = os.Stat(expectedSettingsFile)
    75  		assert.True(os.IsNotExist(err))
    76  		createdFile, err := app.CreateSettingsFile()
    77  		assert.NoError(err)
    78  		assert.EqualValues(expectedSettingsFile, createdFile)
    79  		_, err = os.Stat(expectedSettingsFile)
    80  		assert.NoError(err)
    81  		signatureFound, err := fileutil.FgrepStringInFile(expectedSettingsFile, nodeps.DdevFileSignature)
    82  		assert.NoError(err)
    83  		assert.True(signatureFound, "Failed to find %s in %s", nodeps.DdevFileSignature, expectedSettingsFile)
    84  		_ = os.Remove(expectedSettingsFile)
    85  	}
    86  
    87  	println("") // Just lets Goland find the PASS when done.
    88  }
    89  
    90  // TestWriteDrushConfig test the drush config we write
    91  func TestWriteDrushConfig(t *testing.T) {
    92  	assert := asrt.New(t)
    93  	app := &DdevApp{}
    94  	origDir, _ := os.Getwd()
    95  
    96  	for _, site := range TestSites {
    97  		runTime := util.TimeTrack(time.Now(), fmt.Sprintf("%s WriteDrushrc", site.Name))
    98  
    99  		testcommon.ClearDockerEnv()
   100  
   101  		if !nodeps.ArrayContainsString([]string{"drupal7", "drupal8", "drupal9", "drupal10", "backdrop"}, site.Type) {
   102  			continue
   103  		}
   104  		err := app.Init(site.Dir)
   105  		if err != nil {
   106  			assert.NoError(err, "failed init of %s: %v", site.Name, err)
   107  			continue
   108  		}
   109  		t.Cleanup(func() {
   110  			err = os.Chdir(origDir)
   111  			assert.NoError(err)
   112  			err = app.Stop(true, false)
   113  			assert.NoError(err)
   114  		})
   115  
   116  		_, err = app.CreateSettingsFile()
   117  		assert.NoError(err)
   118  
   119  		startErr := app.Start()
   120  		//nolint: errcheck
   121  		defer app.Stop(true, false)
   122  		if startErr != nil {
   123  			logs, _ := GetErrLogsFromApp(app, startErr)
   124  			t.Fatalf("app.Start failed, startErr=%v, logs=\n========\n%s\n===========\n", startErr, logs)
   125  		}
   126  
   127  		drushFilePath := filepath.Join(filepath.Dir(app.SiteSettingsPath), "drushrc.php")
   128  
   129  		switch app.Type {
   130  		case nodeps.AppTypeDrupal6, nodeps.AppTypeDrupal7, nodeps.AppTypeBackdrop:
   131  			if !fileutil.FileExists(drushFilePath) {
   132  				assert.True(fileutil.FileExists(drushFilePath))
   133  				continue
   134  			}
   135  			optionFound, err := fileutil.FgrepStringInFile(drushFilePath, "options")
   136  			assert.NoError(err)
   137  			assert.True(optionFound)
   138  
   139  		default:
   140  			if fileutil.FileExists(drushFilePath) {
   141  				assert.False(fileutil.FileExists(drushFilePath), "Drush settings file (%s) should not exist but it does (app.Type=%s)", drushFilePath, app.Type)
   142  				continue
   143  			}
   144  		}
   145  
   146  		runTime()
   147  	}
   148  }
   149  
   150  // TestDrupalBackdropIncludeSettingsDdevInNewSettingsFile verifies that when no settings.php file exists,
   151  // a settings.php file is created that includes settings.ddev.php.
   152  func TestDrupalBackdropIncludeSettingsDdevInNewSettingsFile(t *testing.T) {
   153  	assert := asrt.New(t)
   154  
   155  	dir := testcommon.CreateTmpDir(t.Name())
   156  
   157  	app, err := NewApp(dir, true)
   158  	assert.NoError(err)
   159  
   160  	err = os.MkdirAll(filepath.Join(dir, app.Docroot, "sites", "default"), 0777)
   161  	assert.NoError(err)
   162  
   163  	for appType, relativeSettingsLocations := range drupalBackdropSettingsLocations {
   164  		app.Type = appType
   165  
   166  		relativeSettingsLocation := relativeSettingsLocations.main
   167  		relativeSettingsDdevLocation := relativeSettingsLocations.local
   168  		expectedSettingsLocation := filepath.Join(dir, relativeSettingsLocation)
   169  		expectedSettingsDdevLocation := filepath.Join(dir, relativeSettingsDdevLocation)
   170  
   171  		// Ensure that no settings.php exists
   172  		_ = os.Remove(expectedSettingsLocation)
   173  
   174  		// Ensure that no settings.ddev.php file exists
   175  		_ = os.Remove(expectedSettingsDdevLocation)
   176  
   177  		// Invoke the settings file creation process
   178  		_, err := app.CreateSettingsFile()
   179  		assert.NoError(err)
   180  
   181  		// Ensure that a settings.php was created
   182  		assert.True(fileutil.FileExists(expectedSettingsLocation))
   183  
   184  		// Ensure that settings.php references settings.ddev.php
   185  		settingsDdev := filepath.Base(relativeSettingsDdevLocation)
   186  		newSettingsIncludesSettingsDdev, err := fileutil.FgrepStringInFile(expectedSettingsLocation, settingsDdev)
   187  		assert.NoError(err)
   188  		assert.True(newSettingsIncludesSettingsDdev, "Failed to find %s in %s", settingsDdev, expectedSettingsLocation)
   189  
   190  		// Ensure that settings.ddev.php exists
   191  		assert.True(fileutil.FileExists(expectedSettingsDdevLocation))
   192  	}
   193  }
   194  
   195  // TestDrupalBackdropIncludeSettingsDdevInExistingSettingsFile verifies that when a settings.php file already exists,
   196  // it is modified to include settings.ddev.php
   197  func TestDrupalBackdropIncludeSettingsDdevInExistingSettingsFile(t *testing.T) {
   198  	assert := asrt.New(t)
   199  
   200  	dir := testcommon.CreateTmpDir(t.Name())
   201  
   202  	app, err := NewApp(dir, true)
   203  	assert.NoError(err)
   204  
   205  	err = os.MkdirAll(filepath.Join(dir, app.Docroot, "sites", "default"), 0777)
   206  	assert.NoError(err)
   207  
   208  	for appType, relativeSettingsLocations := range drupalBackdropSettingsLocations {
   209  		app.Type = appType
   210  
   211  		relativeSettingsLocation := relativeSettingsLocations.main
   212  		relativeSettingsDdevLocation := relativeSettingsLocations.local
   213  		expectedSettingsLocation := filepath.Join(dir, relativeSettingsLocation)
   214  		expectedSettingsDdevLocation := filepath.Join(dir, relativeSettingsDdevLocation)
   215  
   216  		// Ensure that no settings.php exists
   217  		_ = os.Remove(expectedSettingsLocation)
   218  
   219  		// Ensure that no settings.ddev.php file exists
   220  		_ = os.Remove(expectedSettingsDdevLocation)
   221  
   222  		// Create a settings.php that does not include settings.ddev.php
   223  		originalContents := "// this file is not empty\n"
   224  		err = os.WriteFile(expectedSettingsLocation, []byte(originalContents), 0644)
   225  		assert.NoError(err)
   226  
   227  		// Invoke the settings file creation process
   228  		_, err = app.CreateSettingsFile()
   229  		assert.NoError(err)
   230  
   231  		// Ensure that settings.php exists
   232  		assert.True(fileutil.FileExists(expectedSettingsLocation))
   233  
   234  		// Ensure that settings.ddev.php exists
   235  		assert.True(fileutil.FileExists(expectedSettingsDdevLocation))
   236  
   237  		// Ensure that settings.php references settings.ddev.php
   238  		settingsDdev := filepath.Base(relativeSettingsDdevLocation)
   239  		existingSettingsIncludesSettingsDdev, err := fileutil.FgrepStringInFile(expectedSettingsLocation, settingsDdev)
   240  		assert.NoError(err)
   241  		assert.True(existingSettingsIncludesSettingsDdev, "Failed to find %s in %s, apptype=%s", settingsDdev, expectedSettingsLocation, appType)
   242  
   243  		// Ensure that settings.php includes original contents
   244  		modifiedSettingsIncludesOriginalContents, err := fileutil.FgrepStringInFile(expectedSettingsLocation, originalContents)
   245  		assert.NoError(err)
   246  		assert.True(modifiedSettingsIncludesOriginalContents, "Failed to find %s in %s", originalContents, expectedSettingsLocation)
   247  	}
   248  }
   249  
   250  // TestDrupalBackdropCreateGitIgnoreIfNoneExists verifies that if no .gitignore file exists in the directory
   251  // containing settings.php and settings.ddev.php, a .gitignore is created that includes settings.ddev.php.
   252  func TestDrupalBackdropCreateGitIgnoreIfNoneExists(t *testing.T) {
   253  	assert := asrt.New(t)
   254  
   255  	dir := testcommon.CreateTmpDir(t.Name())
   256  
   257  	app, err := NewApp(dir, true)
   258  	assert.NoError(err)
   259  
   260  	err = os.MkdirAll(filepath.Join(dir, app.Docroot, "sites", "default"), 0777)
   261  	assert.NoError(err)
   262  
   263  	for appType, relativeSettingsLocations := range drupalBackdropSettingsLocations {
   264  		app.Type = appType
   265  
   266  		relativeSettingsDdevLocation := relativeSettingsLocations.local
   267  		expectedSettingsDdevLocation := filepath.Join(dir, relativeSettingsDdevLocation)
   268  		expectedGitIgnoreLocation := filepath.Join(filepath.Dir(expectedSettingsDdevLocation), ".gitignore")
   269  		fmt.Println(expectedGitIgnoreLocation)
   270  
   271  		// Ensure that no .gitignore exists
   272  		_ = os.Remove(expectedGitIgnoreLocation)
   273  
   274  		// Invoke the settings file creation process
   275  		_, err = app.CreateSettingsFile()
   276  		assert.NoError(err)
   277  
   278  		// Ensure that a .gitignore exists (except for backdrop, which has settings in project root)
   279  		if app.Type != nodeps.AppTypeBackdrop {
   280  			assert.True(fileutil.FileExists(expectedGitIgnoreLocation))
   281  
   282  			// Ensure that the new .gitignore includes settings.ddev.php
   283  			settingsDdev := filepath.Base(relativeSettingsDdevLocation)
   284  			newGitIgnoreIncludesSettingsDdev, err := fileutil.FgrepStringInFile(expectedGitIgnoreLocation, settingsDdev)
   285  			assert.NoError(err)
   286  			assert.True(newGitIgnoreIncludesSettingsDdev, "Failed to find %s in %s", settingsDdev, expectedGitIgnoreLocation)
   287  		}
   288  	}
   289  }
   290  
   291  // TestDrupalBackdropGitIgnoreAlreadyExists verifies that if a .gitignore already exists in the directory
   292  // containing settings.php and settings.ddev.php, it is not modified.
   293  func TestDrupalBackdropGitIgnoreAlreadyExists(t *testing.T) {
   294  	assert := asrt.New(t)
   295  
   296  	dir := testcommon.CreateTmpDir(t.Name())
   297  
   298  	app, err := NewApp(dir, true)
   299  	assert.NoError(err)
   300  
   301  	err = os.MkdirAll(filepath.Join(dir, app.Docroot, "sites", "default"), 0777)
   302  	assert.NoError(err)
   303  
   304  	for appType, relativeSettingsLocations := range drupalBackdropSettingsLocations {
   305  		app.Type = appType
   306  
   307  		relativeSettingsDdevLocation := relativeSettingsLocations.local
   308  		expectedSettingsDdevLocation := filepath.Join(dir, relativeSettingsDdevLocation)
   309  		expectedGitIgnoreLocation := filepath.Join(filepath.Dir(expectedSettingsDdevLocation), ".gitignore")
   310  		fmt.Println(expectedGitIgnoreLocation)
   311  
   312  		// Ensure that a .gitignore already exists and has some contents
   313  		originalContents := "not empty"
   314  		settingsFile, err := os.Create(expectedGitIgnoreLocation)
   315  		assert.NoError(err)
   316  		_, err = settingsFile.Write([]byte(originalContents))
   317  		assert.NoError(err)
   318  
   319  		// Invoke the settings file creation process
   320  		_, err = app.CreateSettingsFile()
   321  		assert.NoError(err)
   322  
   323  		// Ensure that .gitignore still exists
   324  		assert.True(fileutil.FileExists(expectedGitIgnoreLocation))
   325  
   326  		// Ensure that the new .gitignore has not been modified to include settings.ddev.php
   327  		settingsDdev := relativeSettingsDdevLocation
   328  		existingGitIgnoreIncludesSettingsDdev, err := fileutil.FgrepStringInFile(expectedGitIgnoreLocation, settingsDdev)
   329  		assert.NoError(err)
   330  		assert.False(existingGitIgnoreIncludesSettingsDdev, "Found unexpected %s in %s", settingsDdev, expectedGitIgnoreLocation)
   331  	}
   332  }
   333  
   334  // TestDrupalBackdropOverwriteDdevSettings ensures that if a settings.ddev.php file already exists, it is overwritten by the
   335  // settings creation process.
   336  func TestDrupalBackdropOverwriteDdevSettings(t *testing.T) {
   337  	assert := asrt.New(t)
   338  
   339  	dir := testcommon.CreateTmpDir(t.Name())
   340  
   341  	app, err := NewApp(dir, true)
   342  	assert.NoError(err)
   343  
   344  	err = os.MkdirAll(filepath.Join(dir, app.Docroot, "sites", "default"), 0777)
   345  	assert.NoError(err)
   346  
   347  	for appType, relativeSettingsLocations := range drupalBackdropSettingsLocations {
   348  		app.Type = appType
   349  
   350  		relativeSettingsDdevLocation := relativeSettingsLocations.local
   351  		expectedSettingsDdevLocation := filepath.Join(dir, relativeSettingsDdevLocation)
   352  
   353  		// Ensure that a settings.ddev.php file exists, WITH the #ddev-generated signature
   354  		originalContents := "not empty " + nodeps.DdevFileSignature
   355  		settingsFile, err := os.Create(expectedSettingsDdevLocation)
   356  		assert.NoError(err)
   357  		_, err = settingsFile.Write([]byte(originalContents))
   358  		assert.NoError(err)
   359  
   360  		// Invoke the settings file creation process
   361  		_, err = app.CreateSettingsFile()
   362  		assert.NoError(err)
   363  
   364  		// Ensure settings.ddev.php was overwritten; It had the signature in it
   365  		// so it was valid to overwrite. The original string should no longer be there.
   366  		containsOriginalString, err := fileutil.FgrepStringInFile(expectedSettingsDdevLocation, originalContents)
   367  		assert.NoError(err)
   368  		assert.False(containsOriginalString, "The file should not have contained the original string %s and it did not.", originalContents)
   369  
   370  		// Now do the whole thing again, but this time the settings.ddev.php does *not* have
   371  		// the #ddev-generated signature, so the file will be respected and not replaced
   372  		originalContents = "nearly empty "
   373  		settingsFile, err = os.Create(expectedSettingsDdevLocation)
   374  		assert.NoError(err)
   375  		_, err = settingsFile.Write([]byte(originalContents))
   376  		assert.NoError(err)
   377  
   378  		// Invoke the settings file creation process
   379  		_, err = app.CreateSettingsFile()
   380  		assert.NoError(err)
   381  
   382  		// Ensure settings.ddev.php was overwritten with new contents
   383  		containsOriginalString, err = fileutil.FgrepStringInFile(expectedSettingsDdevLocation, originalContents)
   384  		assert.NoError(err)
   385  		assert.True(containsOriginalString, "Did not find %s in the settings file; it should have still been there", originalContents)
   386  	}
   387  }