github.com/ddev/ddev@v1.23.2-0.20240519125000-d824ffe36ff3/pkg/ddevapp/config_merge_test.go (about) 1 package ddevapp_test 2 3 import ( 4 "github.com/ddev/ddev/pkg/ddevapp" 5 "github.com/ddev/ddev/pkg/fileutil" 6 "github.com/ddev/ddev/pkg/testcommon" 7 asrt "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 "os" 10 "path/filepath" 11 "sort" 12 "testing" 13 ) 14 15 // TestConfigMerge takes a variety of test expectations and checks to see if they work out 16 func TestConfigMerge(t *testing.T) { 17 assert := asrt.New(t) 18 19 // Each item here has a set of config.*.yaml to be composed, and a config.yaml that should reflect the result 20 for _, c := range []string{"envtest", "fulloverridetest", "hookstest", "overridetest", "scalartest"} { 21 composedApp := SetupTestTempDir(t, filepath.Join(c, "components")) 22 expectedApp := SetupTestTempDir(t, filepath.Join(c, "expected")) 23 composedApp.Name = "" 24 composedApp.AppRoot = "" 25 composedApp.ConfigPath = "" 26 expectedApp.Name = "" 27 expectedApp.AppRoot = "" 28 expectedApp.ConfigPath = "" 29 // We don't know in advance the ordering of the WebEnvironment for testing purposes, 30 // and it doesn't matter in reality, so sort both for testing before comparison 31 sort.Strings(expectedApp.WebEnvironment) 32 sort.Strings(composedApp.WebEnvironment) 33 34 assert.Equal(expectedApp, composedApp, "%s failed", c) 35 } 36 } 37 38 // TestConfigMergeStringList verifies that scalar string merges update w/o clobber 39 func TestConfigMergeStringList(t *testing.T) { 40 assert := asrt.New(t) 41 app := SetupTestTempDir(t, "") 42 43 // test matches allowing for delete syntax (a prefixed !) 44 assertSimpleMatch := func(expected bool, match string, setting []string) { 45 test := assert.True 46 if !expected { 47 test = assert.False 48 } 49 50 for _, val := range setting { 51 if val == match { 52 test(true, match) 53 return 54 } 55 } 56 test(false, match) 57 } 58 // no clobber of old setting 59 assertSimpleMatch(true, "somename", app.AdditionalHostnames) 60 // successful merge 61 assertSimpleMatch(true, "somename-new", app.AdditionalHostnames) 62 } 63 64 // TestConfigMergeEnvItems verifies that config overrides web_environment 65 // and do not destroy (but may update) config.yaml stuff 66 func TestConfigMergeEnvItems(t *testing.T) { 67 assert := asrt.New(t) 68 app := SetupTestTempDir(t, "") 69 70 // check the config file w/o overrides 71 noOverridesApp, err := ddevapp.NewApp(app.AppRoot, false) 72 require.NoError(t, err) 73 assert.IsType([]string{}, noOverridesApp.WebEnvironment) 74 75 // The app loaded without overrides should get the original values expected here 76 for _, v := range []string{`LARRY=l`, `MOE=m`, `CURLEY=c`} { 77 assert.Contains(noOverridesApp.WebEnvironment, v, "the app without overrides should have had %v but it didn't, webEnvironment=%v", v, noOverridesApp.WebEnvironment) 78 } 79 80 // With overrides we should have different values with the config.override.yaml values added 81 withOverridesApp, err := ddevapp.NewApp(app.AppRoot, true) 82 require.NoError(t, err) 83 84 for _, v := range []string{`LARRY=lz`, `MOE=mz`, `CURLEY=c`, `SHEMP=s`} { 85 assert.Contains(withOverridesApp.WebEnvironment, v, "the app without overrides should have had %v but it didn't, webEnvironment=%v", v, noOverridesApp.WebEnvironment) 86 } 87 88 } 89 90 // TestConfigHooksMerge makes sure that hooks get merged with additional config.*.yaml 91 func TestConfigHooksMerge(t *testing.T) { 92 app := SetupTestTempDir(t, "") 93 94 // some helpers 95 getHookTasks := func(hooks map[string][]ddevapp.YAMLTask, hook string) []ddevapp.YAMLTask { 96 tasks, ok := hooks[hook] 97 if !ok { 98 return nil 99 } 100 return tasks 101 } 102 103 // the fields we want are private! 104 hasTask := func(hooks map[string][]ddevapp.YAMLTask, hook, taskKey, desc string) bool { 105 tasks := getHookTasks(hooks, hook) 106 if tasks == nil { 107 return false 108 } 109 found := false 110 for _, task := range tasks { 111 taskDesc := "" 112 taskInterface, ok := task[taskKey] 113 if !ok { 114 // we guessed the key wrong 115 continue 116 } 117 118 taskDesc, ok = taskInterface.(string) 119 if !ok { 120 // we expected the command to be a string, but WTF? 121 continue 122 } 123 124 //t.Logf("key %s as %s", taskKey, taskDesc) 125 126 if taskDesc == desc { 127 found = true 128 } 129 130 } 131 return found 132 } 133 134 assertTask := func(expected bool, hook, taskKey, desc string) { 135 tasks := getHookTasks(app.Hooks, hook) 136 if tasks == nil { 137 if expected { 138 t.Errorf("did not found tasks for %s", hook) 139 } else { 140 return 141 } 142 } else { 143 found := hasTask(app.Hooks, hook, taskKey, desc) 144 if found != expected { 145 msg := "Expected " 146 if !expected { 147 msg = "Did not expect " 148 } 149 t.Errorf("%s Hook %s with %s", msg, hook, desc) 150 } 151 } 152 } 153 154 assertTask(true, "post-start", "exec", "simple random expression") 155 assertTask(true, "post-start", "exec-host", "simple host command") 156 assertTask(true, "post-start", "exec", "simple web command") 157 assertTask(true, "post-import-db", "exec", "drush uli") 158 159 } 160 161 // SetupTestTempDir creates the test directory and related objects. 162 func SetupTestTempDir(t *testing.T, subDir string) *ddevapp.DdevApp { 163 164 projDir, err := filepath.Abs(testcommon.CreateTmpDir(t.Name())) 165 require.NoError(t, err) 166 167 testConfig := filepath.Join("./testdata/", t.Name(), subDir, "/.ddev") 168 err = fileutil.CopyDir(testConfig, filepath.Join(projDir, ".ddev")) 169 require.NoError(t, err) 170 171 app, err := ddevapp.NewApp(projDir, true) 172 require.NoError(t, err) 173 174 t.Cleanup(func() { 175 _ = os.RemoveAll(projDir) 176 }) 177 178 return app 179 } 180 181 // TestEnvToUniqueEnv tests EnvToUniqueEnv 182 func TestEnvToUniqueEnv(t *testing.T) { 183 assert := asrt.New(t) 184 185 testBedSources := [][]string{ 186 {"ONE=one", "ONE=two", "ONE=three", "TWO=two", "TWO=three", "TWO=four"}, 187 } 188 189 testBedExpectations := [][]string{ 190 {"ONE=three", "TWO=four"}, 191 } 192 193 for i := 0; i < len(testBedSources); i++ { 194 res := ddevapp.EnvToUniqueEnv(&testBedSources[i]) 195 sort.Strings(res) 196 assert.Equal(testBedExpectations[i], res) 197 } 198 }