github.com/drud/ddev@v1.21.5-alpha1.0.20230226034409-94fcc4b94453/pkg/ddevapp/providerAcquia_test.go (about) 1 package ddevapp_test 2 3 import ( 4 "fmt" 5 "github.com/drud/ddev/pkg/exec" 6 "github.com/drud/ddev/pkg/globalconfig" 7 "github.com/drud/ddev/pkg/nodeps" 8 "github.com/stretchr/testify/require" 9 "io" 10 "net/http" 11 "os" 12 "path" 13 "path/filepath" 14 "strings" 15 "testing" 16 17 . "github.com/drud/ddev/pkg/ddevapp" 18 "github.com/drud/ddev/pkg/testcommon" 19 asrt "github.com/stretchr/testify/assert" 20 ) 21 22 /** 23 * A valid site (with backups) must be present which matches the test site and environment name 24 * defined in the constants below. 25 */ 26 const acquiaPullTestSite = "ddevdemo.dev" 27 const acquiaPullDatabase = "ddevdemo" 28 const acquiaPushTestSite = "ddevdemo.test" 29 30 const acquiaPullSiteURL = "http://ddevdemodev.prod.acquia-sites.com/" 31 const acquiaSiteExpectation = "Super easy vegetarian pasta" 32 33 // Note that these tests won't run with GitHub actions on a forked PR. 34 // Thie is a security feature, but means that PRs intended to test this 35 // must be done in the ddev repo. 36 37 // TestAcquiaPull ensures we can pull backups from Acquia 38 func TestAcquiaPull(t *testing.T) { 39 acquiaKey := "" 40 acquiaSecret := "" 41 sshkey := "" 42 if acquiaKey = os.Getenv("DDEV_ACQUIA_API_KEY"); acquiaKey == "" { 43 t.Skipf("No DDEV_ACQUIA_API_KEY env var has been set. Skipping %v", t.Name()) 44 } 45 if acquiaSecret = os.Getenv("DDEV_ACQUIA_API_SECRET"); acquiaSecret == "" { 46 t.Skipf("No DDEV_ACQUIA_SECRET env var has been set. Skipping %v", t.Name()) 47 } 48 if sshkey = os.Getenv("DDEV_ACQUIA_SSH_KEY"); sshkey == "" { 49 t.Skipf("No DDEV_ACQUIA_SSH_KEY env var has been set. Skipping %v", t.Name()) 50 } 51 sshkey = strings.Replace(sshkey, "<SPLIT>", "\n", -1) 52 53 require.True(t, isPullSiteValid(acquiaPullSiteURL, acquiaSiteExpectation), "acquiaPullSiteURL %s isn't working right", acquiaPullSiteURL) 54 // Set up tests and give ourselves a working directory. 55 assert := asrt.New(t) 56 origDir, _ := os.Getwd() 57 58 webEnvSave := globalconfig.DdevGlobalConfig.WebEnvironment 59 60 globalconfig.DdevGlobalConfig.WebEnvironment = []string{"ACQUIA_API_KEY=" + acquiaKey, "ACQUIA_API_SECRET=" + acquiaSecret} 61 err := globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig) 62 assert.NoError(err) 63 64 siteDir := testcommon.CreateTmpDir(t.Name()) 65 err = os.MkdirAll(filepath.Join(siteDir, "docroot/sites/default"), 0777) 66 assert.NoError(err) 67 err = os.Chdir(siteDir) 68 assert.NoError(err) 69 70 err = setupSSHKey(t, sshkey, filepath.Join(origDir, "testdata", t.Name())) 71 require.NoError(t, err) 72 73 app, err := NewApp(siteDir, true) 74 assert.NoError(err) 75 app.PHPVersion = "8.0" 76 77 t.Cleanup(func() { 78 err = app.Stop(true, false) 79 assert.NoError(err) 80 81 globalconfig.DdevGlobalConfig.WebEnvironment = webEnvSave 82 err = globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig) 83 assert.NoError(err) 84 85 _ = os.Chdir(origDir) 86 err = os.RemoveAll(siteDir) 87 assert.NoError(err) 88 }) 89 90 app.Name = t.Name() 91 app.Type = nodeps.AppTypeDrupal9 92 93 _ = app.Stop(true, false) 94 err = app.WriteConfig() 95 assert.NoError(err) 96 97 testcommon.ClearDockerEnv() 98 99 err = PopulateExamplesCommandsHomeadditions(app.Name) 100 require.NoError(t, err) 101 102 err = app.Start() 103 require.NoError(t, err) 104 105 // Make sure we have drush 106 _, _, err = app.Exec(&ExecOpts{ 107 Cmd: "composer require --no-interaction drush/drush symfony/http-kernel>/dev/null 2>/dev/null", 108 }) 109 require.NoError(t, err) 110 111 // Build our acquia.yaml from the example file 112 s, err := os.ReadFile(app.GetConfigPath("providers/acquia.yaml.example")) 113 require.NoError(t, err) 114 115 // Replace the project_id and database_name 116 x := strings.Replace(string(s), "project_id:", fmt.Sprintf("project_id: %s\n#project_id:", acquiaPullTestSite), -1) 117 x = strings.Replace(x, "database_name: ", fmt.Sprintf("database_name: %s\n#database_name:", acquiaPullDatabase), -1) 118 119 err = os.WriteFile(app.GetConfigPath("providers/acquia.yaml"), []byte(x), 0666) 120 assert.NoError(err) 121 err = app.WriteConfig() 122 require.NoError(t, err) 123 err = app.MutagenSyncFlush() 124 require.NoError(t, err) 125 126 provider, err := app.GetProvider("acquia") 127 require.NoError(t, err) 128 err = app.Pull(provider, false, false, false) 129 require.NoError(t, err) 130 131 assert.FileExists(filepath.Join(app.GetHostUploadDirFullPath(), "chocolate-brownie-umami.jpg")) 132 out, err := exec.RunCommand("bash", []string{"-c", fmt.Sprintf(`echo 'select COUNT(*) from users_field_data where mail="randy@example.com";' | %s mysql -N`, DdevBin)}) 133 assert.NoError(err) 134 assert.True(strings.HasPrefix(out, "1\n")) 135 } 136 137 // TestAcquiaPush ensures we can push to acquia for a configured environment. 138 func TestAcquiaPush(t *testing.T) { 139 acquiaKey := "" 140 acquiaSecret := "" 141 sshkey := "" 142 if os.Getenv("DDEV_ALLOW_ACQUIA_PUSH") != "true" { 143 t.Skip("TestAcquiaPush is currently embargoed by DDEV_ALLOW_ACQUIA_PUSH not set to true") 144 } 145 if acquiaKey = os.Getenv("DDEV_ACQUIA_API_KEY"); acquiaKey == "" { 146 t.Skipf("No DDEV_ACQUIA_API_KEY env var has been set. Skipping %v", t.Name()) 147 } 148 if acquiaSecret = os.Getenv("DDEV_ACQUIA_API_SECRET"); acquiaSecret == "" { 149 t.Skipf("No DDEV_ACQUIA_API_SECRET env var has been set. Skipping %v", t.Name()) 150 } 151 if sshkey = os.Getenv("DDEV_ACQUIA_SSH_KEY"); sshkey == "" { 152 t.Skipf("No DDEV_ACQUIA_SSH_KEY env var has been set. Skipping %v", t.Name()) 153 } 154 sshkey = strings.Replace(sshkey, "<SPLIT>", "\n", -1) 155 156 // Set up tests and give ourselves a working directory. 157 assert := asrt.New(t) 158 origDir, _ := os.Getwd() 159 160 webEnvSave := globalconfig.DdevGlobalConfig.WebEnvironment 161 162 globalconfig.DdevGlobalConfig.WebEnvironment = []string{"ACQUIA_API_KEY=" + acquiaKey, "ACQUIA_API_SECRET=" + acquiaSecret} 163 err := globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig) 164 assert.NoError(err) 165 166 // Use a D9 codebase for drush to work right 167 d9code := FullTestSites[8] 168 d9code.Name = t.Name() 169 err = globalconfig.RemoveProjectInfo(t.Name()) 170 require.NoError(t, err) 171 err = d9code.Prepare() 172 require.NoError(t, err) 173 app, err := NewApp(d9code.Dir, false) 174 require.NoError(t, err) 175 _ = app.Stop(true, false) 176 177 err = os.Chdir(d9code.Dir) 178 require.NoError(t, err) 179 180 err = setupSSHKey(t, sshkey, filepath.Join(origDir, "testdata", t.Name())) 181 require.NoError(t, err) 182 183 t.Cleanup(func() { 184 err = app.Stop(true, false) 185 assert.NoError(err) 186 187 globalconfig.DdevGlobalConfig.WebEnvironment = webEnvSave 188 err = globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig) 189 assert.NoError(err) 190 191 _ = os.Chdir(origDir) 192 err = os.RemoveAll(d9code.Dir) 193 assert.NoError(err) 194 }) 195 196 app.Hooks = map[string][]YAMLTask{"post-push": {{"exec-host": "touch hello-post-push-" + app.Name}}, "pre-push": {{"exec-host": "touch hello-pre-push-" + app.Name}}} 197 _ = app.Stop(true, false) 198 199 err = app.WriteConfig() 200 require.NoError(t, err) 201 202 testcommon.ClearDockerEnv() 203 204 err = PopulateExamplesCommandsHomeadditions(app.Name) 205 require.NoError(t, err) 206 207 // Create the uploaddir and a file; it won't have existed in our download 208 tval := nodeps.RandomString(10) 209 fName := tval + ".txt" 210 fContent := []byte(tval) 211 err = os.MkdirAll(filepath.Join(app.AppRoot, app.Docroot, "sites/default/files"), 0777) 212 require.NoError(t, err) 213 err = os.WriteFile(filepath.Join(app.AppRoot, app.Docroot, "sites/default/files", fName), fContent, 0644) 214 require.NoError(t, err) 215 216 err = app.Start() 217 require.NoError(t, err) 218 219 // Since allow-plugins isn't there and you can't even set it with composer... 220 _, _, err = app.Exec(&ExecOpts{ 221 Cmd: `composer config --no-plugins allow-plugins true`, 222 }) 223 require.NoError(t, err) 224 // Make sure we have drush 225 _, _, err = app.Exec(&ExecOpts{ 226 Cmd: "composer require --no-interaction drush/drush >/dev/null 2>/dev/null", 227 }) 228 require.NoError(t, err) 229 230 _, _, err = app.Exec(&ExecOpts{ 231 Cmd: "time drush si -y minimal", 232 }) 233 require.NoError(t, err) 234 235 // Create database and files entries that we can verify after push 236 writeQuery := fmt.Sprintf(`mysql -e 'CREATE TABLE IF NOT EXISTS %s ( title VARCHAR(255) NOT NULL ); INSERT INTO %s VALUES("%s");'`, t.Name(), t.Name(), tval) 237 _, _, err = app.Exec(&ExecOpts{ 238 Cmd: writeQuery, 239 }) 240 require.NoError(t, err) 241 242 // Make sure that the file we created exists in the container 243 _, _, err = app.Exec(&ExecOpts{ 244 Cmd: fmt.Sprintf("ls %s", path.Join("/var/www/html", app.Docroot, "sites/default/files", fName)), 245 }) 246 require.NoError(t, err) 247 248 // Build our PUSH acquia.yaml from the example file 249 s, err := os.ReadFile(app.GetConfigPath("providers/acquia.yaml.example")) 250 require.NoError(t, err) 251 x := strings.Replace(string(s), "project_id:", fmt.Sprintf("project_id: %s\n#project_id:", acquiaPushTestSite), -1) 252 err = os.WriteFile(app.GetConfigPath("providers/acquia.yaml"), []byte(x), 0666) 253 assert.NoError(err) 254 err = app.WriteConfig() 255 require.NoError(t, err) 256 257 provider, err := app.GetProvider("acquia") 258 require.NoError(t, err) 259 260 err = app.Push(provider, false, false) 261 require.NoError(t, err) 262 263 // Test that the database row was added 264 readQuery := fmt.Sprintf(`echo 'SELECT title FROM %s WHERE title="%s"' | drush @%s --alias-path=~/.drush sql-cli --extra=-N`, t.Name(), tval, acquiaPushTestSite) 265 out, _, err := app.Exec(&ExecOpts{ 266 Cmd: readQuery, 267 }) 268 require.NoError(t, err) 269 assert.Contains(out, tval) 270 271 // Test that the file arrived there (by rsyncing it back) 272 out, _, err = app.Exec(&ExecOpts{ 273 Cmd: fmt.Sprintf("drush --alias-path=~/.drush rsync -y @%s:%%files/%s /tmp && cat /tmp/%s", acquiaPushTestSite, fName, fName), 274 }) 275 require.NoError(t, err) 276 assert.Contains(out, tval) 277 278 err = app.MutagenSyncFlush() 279 assert.NoError(err) 280 281 assert.FileExists("hello-pre-push-" + app.Name) 282 assert.FileExists("hello-post-push-" + app.Name) 283 err = os.Remove("hello-pre-push-" + app.Name) 284 assert.NoError(err) 285 err = os.Remove("hello-post-push-" + app.Name) 286 assert.NoError(err) 287 } 288 289 // isPullSiteValid just checks to make sure the site we're testing against is OK 290 func isPullSiteValid(siteURL string, siteExpectation string) bool { 291 resp, err := http.Get(siteURL) 292 if err != nil { 293 return false 294 } 295 //nolint: errcheck 296 defer resp.Body.Close() 297 if resp.StatusCode != 200 { 298 return false 299 } 300 body, err := io.ReadAll(resp.Body) 301 if err != nil { 302 return false 303 } 304 return strings.Contains(string(body), siteExpectation) 305 }