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