github.com/sbuss/deis@v1.6.1/tests/utils/itutils.go (about) 1 package utils 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "math/rand" 10 "net/http" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "strings" 15 "testing" 16 "text/template" 17 "time" 18 19 "github.com/ThomasRooney/gexpect" 20 ) 21 22 // Deis points to the CLI used to run tests. 23 var Deis = "deis " 24 25 // DeisTestConfig allows tests to be repeated against different 26 // targets, with different example apps, using specific credentials, and so on. 27 type DeisTestConfig struct { 28 AuthKey string 29 Hosts string 30 Domain string 31 SSHKey string 32 ClusterName string 33 UserName string 34 Password string 35 Email string 36 ExampleApp string 37 AppDomain string 38 AppName string 39 ProcessNum string 40 ImageID string 41 Version string 42 AppUser string 43 SSLCertificatePath string 44 SSLKeyPath string 45 } 46 47 // randomApp is used for the test run if DEIS_TEST_APP isn't set 48 var randomApp = GetRandomApp() 49 50 // GetGlobalConfig returns a test configuration object. 51 func GetGlobalConfig() *DeisTestConfig { 52 authKey := os.Getenv("DEIS_TEST_AUTH_KEY") 53 if authKey == "" { 54 authKey = "deis" 55 } 56 hosts := os.Getenv("DEIS_TEST_HOSTS") 57 if hosts == "" { 58 hosts = "172.17.8.100" 59 } 60 domain := os.Getenv("DEIS_TEST_DOMAIN") 61 if domain == "" { 62 domain = "local.deisapp.com" 63 } 64 sshKey := os.Getenv("DEIS_TEST_SSH_KEY") 65 if sshKey == "" { 66 sshKey = "~/.vagrant.d/insecure_private_key" 67 } 68 exampleApp := os.Getenv("DEIS_TEST_APP") 69 if exampleApp == "" { 70 exampleApp = randomApp 71 } 72 appDomain := os.Getenv("DEIS_TEST_APP_DOMAIN") 73 if appDomain == "" { 74 appDomain = fmt.Sprintf("test.%s", domain) 75 } 76 77 // generate a self-signed certifcate for the app domain 78 keyOut, err := filepath.Abs(appDomain + ".key") 79 if err != nil { 80 log.Fatal(err) 81 } 82 certOut, err := filepath.Abs(appDomain + ".cert") 83 if err != nil { 84 log.Fatal(err) 85 } 86 cmd := exec.Command("openssl", "req", "-new", "-newkey", "rsa:4096", "-nodes", "-x509", 87 "-days", "1", 88 "-subj", fmt.Sprintf("/C=US/ST=Colorado/L=Boulder/CN=%s", appDomain), 89 "-keyout", keyOut, 90 "-out", certOut) 91 if err := cmd.Start(); err != nil { 92 log.Fatal(err) 93 } 94 if err := cmd.Wait(); err != nil { 95 log.Fatal(err) 96 } 97 98 var envCfg = DeisTestConfig{ 99 AuthKey: authKey, 100 Hosts: hosts, 101 Domain: domain, 102 SSHKey: sshKey, 103 ClusterName: "dev", 104 UserName: "test", 105 Password: "asdf1234", 106 Email: "test@test.co.nz", 107 ExampleApp: exampleApp, 108 AppDomain: appDomain, 109 AppName: "sample", 110 ProcessNum: "2", 111 ImageID: "buildtest", 112 Version: "2", 113 AppUser: "test1", 114 SSLCertificatePath: certOut, 115 SSLKeyPath: keyOut, 116 } 117 return &envCfg 118 } 119 120 func doCurl(url string) ([]byte, error) { 121 // disable security check for self-signed certificates 122 tr := &http.Transport{ 123 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 124 } 125 client := &http.Client{Transport: tr} 126 response, err := client.Get(url) 127 if err != nil { 128 return nil, err 129 } 130 defer response.Body.Close() 131 body, err := ioutil.ReadAll(response.Body) 132 133 if !strings.Contains(string(body), "Powered by") { 134 return nil, fmt.Errorf("App not started (%d)\nBody: (%s)", response.StatusCode, string(body)) 135 } 136 137 return body, nil 138 } 139 140 // Curl connects to an endpoint to see if the endpoint is responding. 141 func Curl(t *testing.T, url string) { 142 CurlWithFail(t, url, false, "") 143 } 144 145 // CurlApp is a convenience function to see if the example app is running. 146 func CurlApp(t *testing.T, cfg DeisTestConfig) { 147 CurlWithFail(t, fmt.Sprintf("http://%s.%s", cfg.AppName, cfg.Domain), false, "") 148 } 149 150 // CurlWithFail connects to a Deis endpoint to see if the example app is running. 151 func CurlWithFail(t *testing.T, url string, failFlag bool, expect string) { 152 // FIXME: try the curl a few times 153 for i := 0; i < 20; i++ { 154 body, err := doCurl(url) 155 if err == nil { 156 fmt.Println(string(body)) 157 return 158 } 159 time.Sleep(1 * time.Second) 160 } 161 162 // once more to fail with an error 163 body, err := doCurl(url) 164 165 switch failFlag { 166 case true: 167 if err != nil { 168 if strings.Contains(string(err.Error()), expect) { 169 fmt.Println("(Error expected...ok) " + expect) 170 } else { 171 t.Fatal(err) 172 } 173 } else { 174 if strings.Contains(string(body), expect) { 175 fmt.Println("(Error expected...ok) " + expect) 176 } else { 177 t.Fatal(err) 178 } 179 } 180 case false: 181 if err != nil { 182 t.Fatal(err) 183 } else { 184 fmt.Println(string(body)) 185 } 186 } 187 } 188 189 // AuthPasswd tests whether `deis auth:passwd` updates a user's password. 190 func AuthPasswd(t *testing.T, params *DeisTestConfig, password string) { 191 fmt.Println("deis auth:passwd") 192 child, err := gexpect.Spawn(Deis + " auth:passwd") 193 if err != nil { 194 t.Fatalf("command not started\n%v", err) 195 } 196 fmt.Println("current password:") 197 err = child.Expect("current password: ") 198 if err != nil { 199 t.Fatalf("expect password failed\n%v", err) 200 } 201 child.SendLine(params.Password) 202 fmt.Println("new password:") 203 err = child.Expect("new password: ") 204 if err != nil { 205 t.Fatalf("expect password failed\n%v", err) 206 } 207 child.SendLine(password) 208 fmt.Println("new password (confirm):") 209 err = child.Expect("new password (confirm): ") 210 if err != nil { 211 t.Fatalf("expect password failed\n%v", err) 212 } 213 child.SendLine(password) 214 err = child.Expect("Password change succeeded") 215 if err != nil { 216 t.Fatalf("command executiuon failed\n%v", err) 217 } 218 child.Close() 219 } 220 221 // CheckList executes a command and optionally tests whether its output does 222 // or does not contain a given string. 223 func CheckList( 224 t *testing.T, cmd string, params interface{}, contain string, notflag bool) { 225 var cmdBuf bytes.Buffer 226 tmpl := template.Must(template.New("cmd").Parse(cmd)) 227 if err := tmpl.Execute(&cmdBuf, params); err != nil { 228 t.Fatal(err) 229 } 230 cmdString := cmdBuf.String() 231 fmt.Println(cmdString) 232 var cmdl *exec.Cmd 233 if strings.Contains(cmd, "cat") { 234 cmdl = exec.Command("sh", "-c", cmdString) 235 } else { 236 cmdl = exec.Command("sh", "-c", Deis+cmdString) 237 } 238 stdout, _, err := RunCommandWithStdoutStderr(cmdl) 239 if err != nil { 240 t.Fatal(err) 241 } 242 if notflag && strings.Contains(stdout.String(), contain) { 243 t.Fatalf("Didn't expect '%s' in command output:\n%v", contain, stdout) 244 } 245 if !notflag && !strings.Contains(stdout.String(), contain) { 246 t.Fatalf("Expected '%s' in command output:\n%v", contain, stdout) 247 } 248 } 249 250 // Execute takes command string and parameters required to execute the command, 251 // a failflag to check whether the command is expected to fail, and an expect 252 // string to check whether the command has failed according to failflag. 253 // 254 // If failflag is true and the command failed, check the stdout and stderr for 255 // the expect string. 256 func Execute(t *testing.T, cmd string, params interface{}, failFlag bool, expect string) { 257 var cmdBuf bytes.Buffer 258 tmpl := template.Must(template.New("cmd").Parse(cmd)) 259 if err := tmpl.Execute(&cmdBuf, params); err != nil { 260 t.Fatal(err) 261 } 262 cmdString := cmdBuf.String() 263 fmt.Println(cmdString) 264 var cmdl *exec.Cmd 265 if strings.Contains(cmd, "git ") { 266 cmdl = exec.Command("sh", "-c", cmdString) 267 } else { 268 cmdl = exec.Command("sh", "-c", Deis+cmdString) 269 } 270 271 switch failFlag { 272 case true: 273 if stdout, stderr, err := RunCommandWithStdoutStderr(cmdl); err != nil { 274 if strings.Contains(stdout.String(), expect) || strings.Contains(stderr.String(), expect) { 275 fmt.Println("(Error expected...ok)") 276 } else { 277 t.Fatal(err) 278 } 279 } else { 280 if strings.Contains(stdout.String(), expect) || strings.Contains(stderr.String(), expect) { 281 fmt.Println("(Error expected...ok)" + expect) 282 } else { 283 t.Fatal(err) 284 } 285 } 286 case false: 287 if _, _, err := RunCommandWithStdoutStderr(cmdl); err != nil { 288 t.Fatal(err) 289 } else { 290 fmt.Println("ok") 291 } 292 } 293 } 294 295 // AppsDestroyTest destroys a Deis app and checks that it was successful. 296 func AppsDestroyTest(t *testing.T, params *DeisTestConfig) { 297 cmd := "apps:destroy --app={{.AppName}} --confirm={{.AppName}}" 298 if err := Chdir(params.ExampleApp); err != nil { 299 t.Fatal(err) 300 } 301 Execute(t, cmd, params, false, "") 302 if err := Chdir(".."); err != nil { 303 t.Fatal(err) 304 } 305 if err := Rmdir(params.ExampleApp); err != nil { 306 t.Fatal(err) 307 } 308 } 309 310 // GetRandomApp returns a known working example app at random for testing. 311 func GetRandomApp() string { 312 rand.Seed(int64(time.Now().Unix())) 313 apps := []string{ 314 "example-clojure-ring", 315 // "example-dart", 316 "example-dockerfile-python", 317 "example-go", 318 "example-java-jetty", 319 "example-nodejs-express", 320 // "example-php", 321 "example-play", 322 "example-python-django", 323 "example-python-flask", 324 "example-ruby-sinatra", 325 "example-scala", 326 "example-dockerfile-http", 327 } 328 return apps[rand.Intn(len(apps))] 329 }