github.com/nak3/source-to-image@v1.1.10-0.20180319140719-2ed55639898d/test/integration/integration_test.go (about) 1 // +build integration 2 3 package integration 4 5 import ( 6 "encoding/json" 7 "flag" 8 "fmt" 9 "io/ioutil" 10 "net" 11 "net/http" 12 "net/http/httptest" 13 "os" 14 "path/filepath" 15 "runtime" 16 "testing" 17 "time" 18 19 dockertypes "github.com/docker/docker/api/types" 20 dockercontainer "github.com/docker/docker/api/types/container" 21 dockerapi "github.com/docker/docker/client" 22 "github.com/golang/glog" 23 "github.com/openshift/source-to-image/pkg/api" 24 "github.com/openshift/source-to-image/pkg/build/strategies" 25 "github.com/openshift/source-to-image/pkg/docker" 26 dockerpkg "github.com/openshift/source-to-image/pkg/docker" 27 "github.com/openshift/source-to-image/pkg/scm/git" 28 "github.com/openshift/source-to-image/pkg/tar" 29 "github.com/openshift/source-to-image/pkg/util" 30 "github.com/openshift/source-to-image/pkg/util/fs" 31 "golang.org/x/net/context" 32 ) 33 34 const ( 35 DefaultDockerSocket = "unix:///var/run/docker.sock" 36 TestSource = "https://github.com/openshift/ruby-hello-world" 37 38 FakeBuilderImage = "sti_test/sti-fake" 39 FakeUserImage = "sti_test/sti-fake-user" 40 FakeImageScripts = "sti_test/sti-fake-scripts" 41 FakeImageScriptsNoSaveArtifacts = "sti_test/sti-fake-scripts-no-save-artifacts" 42 FakeImageNoTar = "sti_test/sti-fake-no-tar" 43 FakeImageOnBuild = "sti_test/sti-fake-onbuild" 44 FakeNumericUserImage = "sti_test/sti-fake-numericuser" 45 FakeImageOnBuildRootUser = "sti_test/sti-fake-onbuild-rootuser" 46 FakeImageOnBuildNumericUser = "sti_test/sti-fake-onbuild-numericuser" 47 48 TagCleanBuild = "test/sti-fake-app" 49 TagCleanBuildUser = "test/sti-fake-app-user" 50 TagIncrementalBuild = "test/sti-incremental-app" 51 TagIncrementalBuildUser = "test/sti-incremental-app-user" 52 TagCleanBuildScripts = "test/sti-fake-app-scripts" 53 TagIncrementalBuildScripts = "test/sti-incremental-app-scripts" 54 TagIncrementalBuildScriptsNoSaveArtifacts = "test/sti-incremental-app-scripts-no-save-artifacts" 55 TagCleanLayeredBuildNoTar = "test/sti-fake-no-tar" 56 TagCleanBuildOnBuild = "test/sti-fake-app-onbuild" 57 TagIncrementalBuildOnBuild = "test/sti-incremental-app-onbuild" 58 TagCleanBuildOnBuildNoName = "test/sti-fake-app-onbuild-noname" 59 TagCleanBuildNoName = "test/sti-fake-app-noname" 60 TagCleanLayeredBuildNoTarNoName = "test/sti-fake-no-tar-noname" 61 TagCleanBuildAllowedUIDsNamedUser = "test/sti-fake-alloweduids-nameduser" 62 TagCleanBuildAllowedUIDsNumericUser = "test/sti-fake-alloweduids-numericuser" 63 TagCleanBuildAllowedUIDsOnBuildRoot = "test/sti-fake-alloweduids-onbuildroot" 64 TagCleanBuildAllowedUIDsOnBuildNumericUser = "test/sti-fake-alloweduids-onbuildnumeric" 65 66 // Need to serve the scripts from local host so any potential changes to the 67 // scripts are made available for integration testing. 68 // 69 // Port 23456 must match the port used in the fake image Dockerfiles 70 FakeScriptsHTTPURL = "http://127.0.0.1:23456/.s2i/bin" 71 ) 72 73 var engineClient docker.Client 74 75 func init() { 76 var err error 77 engineClient, err = docker.NewEngineAPIClient(docker.GetDefaultDockerConfig()) 78 if err != nil { 79 panic(err) 80 } 81 82 // get the full path to this .go file so we can construct the file url 83 // using this file's dirname 84 _, filename, _, _ := runtime.Caller(0) 85 testImagesDir := filepath.Join(filepath.Dir(filename), "scripts") 86 87 l, err := net.Listen("tcp", ":23456") 88 if err != nil { 89 panic(err) 90 } 91 92 hs := http.Server{Handler: http.FileServer(http.Dir(testImagesDir))} 93 hs.SetKeepAlivesEnabled(false) 94 go hs.Serve(l) 95 } 96 97 func getDefaultContext() (context.Context, context.CancelFunc) { 98 return context.WithTimeout(context.Background(), 20*time.Second) 99 } 100 101 // TestInjectionBuild tests the build where we inject files to assemble script. 102 func TestInjectionBuild(t *testing.T) { 103 tempdir, err := ioutil.TempDir("", "s2i-test-dir") 104 if err != nil { 105 t.Errorf("Unable to create temporary directory: %v", err) 106 } 107 defer os.RemoveAll(tempdir) 108 109 err = ioutil.WriteFile(filepath.Join(tempdir, "secret"), []byte("secret"), 0666) 110 if err != nil { 111 t.Errorf("Unable to write content to temporary injection file: %v", err) 112 } 113 114 integration(t).exerciseInjectionBuild(TagCleanBuild, FakeBuilderImage, []string{ 115 tempdir + ":/tmp", 116 tempdir + ":", 117 }) 118 } 119 120 type integrationTest struct { 121 t *testing.T 122 setupComplete bool 123 } 124 125 func (i integrationTest) InspectImage(name string) (*dockertypes.ImageInspect, error) { 126 ctx, cancel := getDefaultContext() 127 defer cancel() 128 resp, _, err := engineClient.ImageInspectWithRaw(ctx, name) 129 if err != nil { 130 if dockerapi.IsErrImageNotFound(err) { 131 return nil, fmt.Errorf("no such image :%q", name) 132 } 133 return nil, err 134 } 135 return &resp, nil 136 } 137 138 var ( 139 FakeScriptsFileURL string 140 ) 141 142 func getLogLevel() (level int) { 143 for level = 5; level >= 0; level-- { 144 if glog.V(glog.Level(level)) == true { 145 break 146 } 147 } 148 return 149 } 150 151 // setup sets up integration tests 152 func (i *integrationTest) setup() { 153 if !i.setupComplete { 154 // get the full path to this .go file so we can construct the file url 155 // using this file's dirname 156 _, filename, _, _ := runtime.Caller(0) 157 testImagesDir := filepath.Join(filepath.Dir(filename), "scripts") 158 FakeScriptsFileURL = "file://" + filepath.ToSlash(filepath.Join(testImagesDir, ".s2i", "bin")) 159 160 for _, image := range []string{TagCleanBuild, TagCleanBuildUser, TagIncrementalBuild, TagIncrementalBuildUser} { 161 ctx, cancel := getDefaultContext() 162 engineClient.ImageRemove(ctx, image, dockertypes.ImageRemoveOptions{}) 163 cancel() 164 } 165 166 i.setupComplete = true 167 } 168 169 from := flag.CommandLine 170 if vflag := from.Lookup("v"); vflag != nil { 171 // the thing here is that we are looking for the bash -v passed into test-integration.sh (with no value), 172 // but for glog (https://github.com/golang/glog/blob/master/glog.go), one specifies 173 // the logging level with -v=# (i.e. -v=0 or -v=3 or -v=5). 174 // so, for the changes stemming from issue 133, we 'reuse' the bash -v, and set the highest glog level. 175 // (if you look at STI's main.go, and setupGlog, it essentially maps glog's -v to --loglevel for use by the sti command) 176 //NOTE - passing --loglevel or -v=5 into test-integration.sh does not work 177 if getLogLevel() != 5 { 178 vflag.Value.Set("5") 179 // FIXME currently glog has only option to redirect output to stderr 180 // the preferred for STI would be to redirect to stdout 181 flag.CommandLine.Set("logtostderr", "true") 182 } 183 } 184 } 185 186 func integration(t *testing.T) *integrationTest { 187 i := &integrationTest{t: t} 188 i.setup() 189 return i 190 } 191 192 // Test a clean build. The simplest case. 193 func TestCleanBuild(t *testing.T) { 194 integration(t).exerciseCleanBuild(TagCleanBuild, false, FakeBuilderImage, "", true, true, false) 195 } 196 197 // Test Labels 198 func TestCleanBuildLabel(t *testing.T) { 199 integration(t).exerciseCleanBuild(TagCleanBuild, false, FakeBuilderImage, "", true, true, true) 200 } 201 202 func TestCleanBuildUser(t *testing.T) { 203 integration(t).exerciseCleanBuild(TagCleanBuildUser, false, FakeUserImage, "", true, true, false) 204 } 205 206 func TestCleanBuildFileScriptsURL(t *testing.T) { 207 integration(t).exerciseCleanBuild(TagCleanBuild, false, FakeBuilderImage, FakeScriptsFileURL, true, true, false) 208 } 209 210 func TestCleanBuildHttpScriptsURL(t *testing.T) { 211 integration(t).exerciseCleanBuild(TagCleanBuild, false, FakeBuilderImage, FakeScriptsHTTPURL, true, true, false) 212 } 213 214 func TestCleanBuildScripts(t *testing.T) { 215 integration(t).exerciseCleanBuild(TagCleanBuildScripts, false, FakeImageScripts, "", true, true, false) 216 } 217 218 func TestLayeredBuildNoTar(t *testing.T) { 219 integration(t).exerciseCleanBuild(TagCleanLayeredBuildNoTar, false, FakeImageNoTar, FakeScriptsFileURL, false, true, false) 220 } 221 222 // Test that a build config with a callbackURL will invoke HTTP endpoint 223 func TestCleanBuildCallbackInvoked(t *testing.T) { 224 integration(t).exerciseCleanBuild(TagCleanBuild, true, FakeBuilderImage, "", true, true, false) 225 } 226 227 func TestCleanBuildOnBuild(t *testing.T) { 228 integration(t).exerciseCleanBuild(TagCleanBuildOnBuild, false, FakeImageOnBuild, "", true, true, false) 229 } 230 231 func TestCleanBuildOnBuildNoName(t *testing.T) { 232 integration(t).exerciseCleanBuild(TagCleanBuildOnBuildNoName, false, FakeImageOnBuild, "", false, false, false) 233 } 234 235 func TestCleanBuildNoName(t *testing.T) { 236 integration(t).exerciseCleanBuild(TagCleanBuildNoName, false, FakeBuilderImage, "", true, false, false) 237 } 238 239 func TestLayeredBuildNoTarNoName(t *testing.T) { 240 integration(t).exerciseCleanBuild(TagCleanLayeredBuildNoTarNoName, false, FakeImageNoTar, FakeScriptsFileURL, false, false, false) 241 } 242 243 func TestAllowedUIDsNamedUser(t *testing.T) { 244 integration(t).exerciseCleanAllowedUIDsBuild(TagCleanBuildAllowedUIDsNamedUser, FakeUserImage, true) 245 } 246 247 func TestAllowedUIDsNumericUser(t *testing.T) { 248 integration(t).exerciseCleanAllowedUIDsBuild(TagCleanBuildAllowedUIDsNumericUser, FakeNumericUserImage, false) 249 } 250 251 func TestAllowedUIDsOnBuildRootUser(t *testing.T) { 252 integration(t).exerciseCleanAllowedUIDsBuild(TagCleanBuildAllowedUIDsNamedUser, FakeImageOnBuildRootUser, true) 253 } 254 255 func TestAllowedUIDsOnBuildNumericUser(t *testing.T) { 256 integration(t).exerciseCleanAllowedUIDsBuild(TagCleanBuildAllowedUIDsNumericUser, FakeImageOnBuildNumericUser, false) 257 } 258 259 func (i *integrationTest) exerciseCleanAllowedUIDsBuild(tag, imageName string, expectError bool) { 260 t := i.t 261 config := &api.Config{ 262 DockerConfig: docker.GetDefaultDockerConfig(), 263 BuilderImage: imageName, 264 BuilderPullPolicy: api.DefaultBuilderPullPolicy, 265 Source: git.MustParse(TestSource), 266 Tag: tag, 267 Incremental: false, 268 ScriptsURL: "", 269 ExcludeRegExp: tar.DefaultExclusionPattern.String(), 270 } 271 config.AllowedUIDs.Set("1-") 272 _, _, err := strategies.GetStrategy(engineClient, config) 273 if err != nil && !expectError { 274 t.Fatalf("Cannot create a new builder: %v", err) 275 } 276 if err == nil && expectError { 277 t.Fatalf("Did not get an error and was expecting one.") 278 } 279 } 280 281 func (i *integrationTest) exerciseCleanBuild(tag string, verifyCallback bool, imageName string, scriptsURL string, expectImageName bool, setTag bool, checkLabel bool) { 282 t := i.t 283 callbackURL := "" 284 callbackInvoked := false 285 callbackHasValidJSON := false 286 if verifyCallback { 287 handler := func(w http.ResponseWriter, r *http.Request) { 288 // we got called 289 callbackInvoked = true 290 // the header is as expected 291 contentType := r.Header["Content-Type"][0] 292 callbackHasValidJSON = contentType == "application/json" 293 // the request body is as expected 294 if callbackHasValidJSON { 295 defer r.Body.Close() 296 body, _ := ioutil.ReadAll(r.Body) 297 type CallbackMessage struct { 298 Success bool 299 Labels map[string]string 300 } 301 var callbackMessage CallbackMessage 302 err := json.Unmarshal(body, &callbackMessage) 303 callbackHasValidJSON = (err == nil) && callbackMessage.Success && len(callbackMessage.Labels) > 0 304 } 305 } 306 ts := httptest.NewServer(http.HandlerFunc(handler)) 307 defer ts.Close() 308 callbackURL = ts.URL 309 } 310 311 var buildTag string 312 if setTag { 313 buildTag = tag 314 } else { 315 buildTag = "" 316 } 317 318 config := &api.Config{ 319 DockerConfig: docker.GetDefaultDockerConfig(), 320 BuilderImage: imageName, 321 BuilderPullPolicy: api.DefaultBuilderPullPolicy, 322 Source: git.MustParse(TestSource), 323 Tag: buildTag, 324 Incremental: false, 325 CallbackURL: callbackURL, 326 ScriptsURL: scriptsURL, 327 ExcludeRegExp: tar.DefaultExclusionPattern.String(), 328 } 329 330 b, _, err := strategies.GetStrategy(engineClient, config) 331 if err != nil { 332 t.Fatalf("Cannot create a new builder.") 333 } 334 resp, err := b.Build(config) 335 if err != nil { 336 t.Fatalf("An error occurred during the build: %v", err) 337 } else if !resp.Success { 338 t.Fatalf("The build failed.") 339 } 340 if callbackInvoked != verifyCallback { 341 t.Fatalf("S2I build did not invoke callback") 342 } 343 if callbackHasValidJSON != verifyCallback { 344 t.Fatalf("S2I build did not invoke callback with valid json message") 345 } 346 347 // We restrict this check to only when we are passing tag through the build config 348 // since we will not end up with an available tag by that name from build 349 if setTag { 350 i.checkForImage(tag) 351 containerID := i.createContainer(tag) 352 i.checkBasicBuildState(containerID, resp.WorkingDir) 353 354 if checkLabel { 355 i.checkForLabel(tag) 356 } 357 358 i.removeContainer(containerID) 359 } 360 361 // Check if we receive back an ImageID when we are expecting to 362 if expectImageName && len(resp.ImageID) == 0 { 363 t.Fatalf("S2I build did not receive an ImageID in response") 364 } 365 if !expectImageName && len(resp.ImageID) > 0 { 366 t.Fatalf("S2I build received an ImageID in response") 367 } 368 } 369 370 // Test an incremental build. 371 func TestIncrementalBuildAndRemovePreviousImage(t *testing.T) { 372 integration(t).exerciseIncrementalBuild(TagIncrementalBuild, FakeBuilderImage, true, false, false) 373 } 374 375 func TestIncrementalBuildAndKeepPreviousImage(t *testing.T) { 376 integration(t).exerciseIncrementalBuild(TagIncrementalBuild, FakeBuilderImage, false, false, false) 377 } 378 379 func TestIncrementalBuildUser(t *testing.T) { 380 integration(t).exerciseIncrementalBuild(TagIncrementalBuildUser, FakeBuilderImage, true, false, false) 381 } 382 383 func TestIncrementalBuildScripts(t *testing.T) { 384 integration(t).exerciseIncrementalBuild(TagIncrementalBuildScripts, FakeImageScripts, true, false, false) 385 } 386 387 func TestIncrementalBuildScriptsNoSaveArtifacts(t *testing.T) { 388 integration(t).exerciseIncrementalBuild(TagIncrementalBuildScriptsNoSaveArtifacts, FakeImageScriptsNoSaveArtifacts, true, true, false) 389 } 390 391 func TestIncrementalBuildOnBuild(t *testing.T) { 392 integration(t).exerciseIncrementalBuild(TagIncrementalBuildOnBuild, FakeImageOnBuild, false, true, true) 393 } 394 395 func (i *integrationTest) exerciseInjectionBuild(tag, imageName string, injections []string) { 396 t := i.t 397 398 injectionList := api.VolumeList{} 399 for _, i := range injections { 400 err := injectionList.Set(i) 401 if err != nil { 402 t.Errorf("injectionList.Set() failed with error %s\n", err) 403 } 404 } 405 config := &api.Config{ 406 DockerConfig: docker.GetDefaultDockerConfig(), 407 BuilderImage: imageName, 408 BuilderPullPolicy: api.DefaultBuilderPullPolicy, 409 Source: git.MustParse(TestSource), 410 Tag: tag, 411 Injections: injectionList, 412 ExcludeRegExp: tar.DefaultExclusionPattern.String(), 413 } 414 builder, _, err := strategies.GetStrategy(engineClient, config) 415 if err != nil { 416 t.Fatalf("Unable to create builder: %v", err) 417 } 418 resp, err := builder.Build(config) 419 if err != nil { 420 t.Fatalf("Unexpected error occurred during build: %v", err) 421 } 422 if !resp.Success { 423 t.Fatalf("S2I build failed.") 424 } 425 i.checkForImage(tag) 426 containerID := i.createContainer(tag) 427 defer i.removeContainer(containerID) 428 429 // Check that the injected file is delivered to assemble script 430 i.fileExists(containerID, "/sti-fake/secret-delivered") 431 i.fileExists(containerID, "/sti-fake/relative-secret-delivered") 432 433 // Make sure the injected file does not exists in resulting image 434 files, err := util.ExpandInjectedFiles(fs.NewFileSystem(), injectionList) 435 if err != nil { 436 t.Errorf("Unexpected error: %v", err) 437 } 438 for _, f := range files { 439 if exitCode := i.runInImage(tag, "test -s "+f); exitCode == 0 { 440 t.Errorf("The file %q must be empty", f) 441 } 442 } 443 } 444 445 func (i *integrationTest) exerciseIncrementalBuild(tag, imageName string, removePreviousImage bool, expectClean bool, checkOnBuild bool) { 446 t := i.t 447 start := time.Now() 448 config := &api.Config{ 449 DockerConfig: docker.GetDefaultDockerConfig(), 450 BuilderImage: imageName, 451 BuilderPullPolicy: api.DefaultBuilderPullPolicy, 452 Source: git.MustParse(TestSource), 453 Tag: tag, 454 Incremental: false, 455 RemovePreviousImage: removePreviousImage, 456 ExcludeRegExp: tar.DefaultExclusionPattern.String(), 457 } 458 459 builder, _, err := strategies.GetStrategy(engineClient, config) 460 if err != nil { 461 t.Fatalf("Unable to create builder: %v", err) 462 } 463 resp, err := builder.Build(config) 464 if err != nil { 465 t.Fatalf("Unexpected error occurred during build: %v", err) 466 } 467 if !resp.Success { 468 t.Fatalf("S2I build failed.") 469 } 470 471 previousImageID := resp.ImageID 472 config = &api.Config{ 473 DockerConfig: docker.GetDefaultDockerConfig(), 474 BuilderImage: imageName, 475 BuilderPullPolicy: api.DefaultBuilderPullPolicy, 476 Source: git.MustParse(TestSource), 477 Tag: tag, 478 Incremental: true, 479 RemovePreviousImage: removePreviousImage, 480 PreviousImagePullPolicy: api.PullIfNotPresent, 481 ExcludeRegExp: tar.DefaultExclusionPattern.String(), 482 } 483 484 builder, _, err = strategies.GetStrategy(engineClient, config) 485 if err != nil { 486 t.Fatalf("Unable to create incremental builder: %v", err) 487 } 488 resp, err = builder.Build(config) 489 if err != nil { 490 t.Fatalf("Unexpected error occurred during incremental build: %v", err) 491 } 492 if !resp.Success { 493 t.Fatalf("S2I incremental build failed.") 494 } 495 496 i.checkForImage(tag) 497 containerID := i.createContainer(tag) 498 defer i.removeContainer(containerID) 499 i.checkIncrementalBuildState(containerID, resp.WorkingDir, expectClean) 500 501 _, err = i.InspectImage(previousImageID) 502 if removePreviousImage { 503 if err == nil { 504 t.Errorf("Previous image %s not deleted", previousImageID) 505 } 506 } else { 507 if err != nil { 508 t.Errorf("Couldn't find previous image %s", previousImageID) 509 } 510 } 511 512 if checkOnBuild { 513 i.fileExists(containerID, "/sti-fake/src/onbuild") 514 } 515 516 if took := time.Since(start); took > docker.DefaultDockerTimeout { 517 // https://github.com/openshift/source-to-image/issues/301 is a 518 // case where incremental builds would get stuck until the 519 // timeout. 520 t.Errorf("Test took too long (%v), some operation may have gotten stuck waiting for the DefaultDockerTimeout (%v). Inspect the logs to find operations that took long.", took, docker.DefaultDockerTimeout) 521 } 522 } 523 524 // Support methods 525 func (i *integrationTest) checkForImage(tag string) { 526 _, err := i.InspectImage(tag) 527 if err != nil { 528 i.t.Errorf("Couldn't find image with tag: %s", tag) 529 } 530 } 531 532 func (i *integrationTest) createContainer(image string) string { 533 ctx, cancel := getDefaultContext() 534 defer cancel() 535 opts := dockertypes.ContainerCreateConfig{Name: "", Config: &dockercontainer.Config{Image: image}} 536 container, err := engineClient.ContainerCreate(ctx, opts.Config, opts.HostConfig, opts.NetworkingConfig, opts.Name) 537 if err != nil { 538 i.t.Errorf("Couldn't create container from image %s with error %+v", image, err) 539 return "" 540 } 541 542 ctx, cancel = getDefaultContext() 543 defer cancel() 544 err = engineClient.ContainerStart(ctx, container.ID, dockertypes.ContainerStartOptions{}) 545 if err != nil { 546 i.t.Errorf("Couldn't start container: %s with error %+v", container.ID, err) 547 return "" 548 } 549 550 ctx, cancel = getDefaultContext() 551 defer cancel() 552 waitC, errC := engineClient.ContainerWait(ctx, container.ID, dockercontainer.WaitConditionNextExit) 553 select { 554 case result := <-waitC: 555 if result.StatusCode != 0 { 556 i.t.Errorf("Bad exit code from container: %d", result.StatusCode) 557 return "" 558 } 559 case err := <-errC: 560 i.t.Errorf("Error waiting for container: %v", err) 561 return "" 562 } 563 return container.ID 564 } 565 566 func (i *integrationTest) runInContainer(image string, command []string) int { 567 ctx, cancel := getDefaultContext() 568 defer cancel() 569 opts := dockertypes.ContainerCreateConfig{Name: "", Config: &dockercontainer.Config{Image: image, AttachStdout: false, AttachStdin: false, Cmd: command}} 570 container, err := engineClient.ContainerCreate(ctx, opts.Config, opts.HostConfig, opts.NetworkingConfig, opts.Name) 571 if err != nil { 572 i.t.Errorf("Couldn't create container from image %s err %+v", image, err) 573 return -1 574 } 575 576 ctx, cancel = getDefaultContext() 577 defer cancel() 578 err = engineClient.ContainerStart(ctx, container.ID, dockertypes.ContainerStartOptions{}) 579 if err != nil { 580 i.t.Errorf("Couldn't start container: %s", container.ID) 581 } 582 ctx, cancel = getDefaultContext() 583 defer cancel() 584 waitC, errC := engineClient.ContainerWait(ctx, container.ID, dockercontainer.WaitConditionNextExit) 585 exitCode := -1 586 select { 587 case result := <-waitC: 588 exitCode = int(result.StatusCode) 589 case err := <-errC: 590 i.t.Errorf("Couldn't wait for container: %s: %v", container.ID, err) 591 } 592 ctx, cancel = getDefaultContext() 593 defer cancel() 594 err = engineClient.ContainerRemove(ctx, container.ID, dockertypes.ContainerRemoveOptions{}) 595 if err != nil { 596 i.t.Errorf("Couldn't remove container: %s", container.ID) 597 } 598 return exitCode 599 } 600 601 func (i *integrationTest) removeContainer(cID string) { 602 ctx, cancel := getDefaultContext() 603 defer cancel() 604 engineClient.ContainerKill(ctx, cID, "SIGKILL") 605 removeOpts := dockertypes.ContainerRemoveOptions{ 606 RemoveVolumes: true, 607 } 608 err := engineClient.ContainerRemove(ctx, cID, removeOpts) 609 if err != nil { 610 i.t.Errorf("Couldn't remove container %s: %s", cID, err) 611 } 612 } 613 614 func (i *integrationTest) fileExists(cID string, filePath string) { 615 res := i.fileExistsInContainer(cID, filePath) 616 617 if !res { 618 i.t.Errorf("Couldn't find file %s in container %s", filePath, cID) 619 } 620 } 621 622 func (i *integrationTest) fileNotExists(cID string, filePath string) { 623 res := i.fileExistsInContainer(cID, filePath) 624 625 if res { 626 i.t.Errorf("Unexpected file %s in container %s", filePath, cID) 627 } 628 } 629 630 func (i *integrationTest) runInImage(image string, cmd string) int { 631 return i.runInContainer(image, []string{"/bin/sh", "-c", cmd}) 632 } 633 634 func (i *integrationTest) checkBasicBuildState(cID string, workingDir string) { 635 i.fileExists(cID, "/sti-fake/assemble-invoked") 636 i.fileExists(cID, "/sti-fake/run-invoked") 637 i.fileExists(cID, "/sti-fake/src/Gemfile") 638 639 _, err := os.Stat(workingDir) 640 if !os.IsNotExist(err) { 641 i.t.Errorf("Unexpected error from stat check on %s", workingDir) 642 } 643 } 644 645 func (i *integrationTest) checkIncrementalBuildState(cID string, workingDir string, expectClean bool) { 646 i.checkBasicBuildState(cID, workingDir) 647 if expectClean { 648 i.fileNotExists(cID, "/sti-fake/save-artifacts-invoked") 649 } else { 650 i.fileExists(cID, "/sti-fake/save-artifacts-invoked") 651 } 652 } 653 654 func (i *integrationTest) fileExistsInContainer(cID string, filePath string) bool { 655 ctx, cancel := getDefaultContext() 656 defer cancel() 657 rdr, stats, err := engineClient.CopyFromContainer(ctx, cID, filePath) 658 if err != nil { 659 return false 660 } 661 defer rdr.Close() 662 return "" != stats.Name 663 } 664 665 func (i *integrationTest) checkForLabel(image string) { 666 docker := dockerpkg.New(engineClient, (&api.Config{}).PullAuthentication) 667 668 labelMap, err := docker.GetLabels(image) 669 if err != nil { 670 i.t.Fatalf("Unable to get labels from image %s: %v", image, err) 671 } 672 673 if labelMap["testLabel"] != "testLabel_value" { 674 i.t.Errorf("Unable to verify 'testLabel' for image '%s'", image) 675 } 676 }