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