github.com/YousefHaggyHeroku/pack@v1.5.5/internal/build/lifecycle_execution_test.go (about) 1 package build_test 2 3 import ( 4 "bytes" 5 "context" 6 "io/ioutil" 7 "math/rand" 8 "os" 9 "testing" 10 "time" 11 12 "github.com/google/go-containerregistry/pkg/name" 13 14 "github.com/apex/log" 15 "github.com/buildpacks/lifecycle/api" 16 "github.com/docker/docker/api/types/container" 17 "github.com/docker/docker/client" 18 "github.com/heroku/color" 19 "github.com/sclevine/spec" 20 "github.com/sclevine/spec/report" 21 22 "github.com/YousefHaggyHeroku/pack/internal/build" 23 "github.com/YousefHaggyHeroku/pack/internal/build/fakes" 24 ilogging "github.com/YousefHaggyHeroku/pack/internal/logging" 25 h "github.com/YousefHaggyHeroku/pack/testhelpers" 26 ) 27 28 // TestLifecycleExecution are unit tests that test each possible phase to ensure they are executed with the proper parameters 29 func TestLifecycleExecution(t *testing.T) { 30 rand.Seed(time.Now().UTC().UnixNano()) 31 32 color.Disable(true) 33 defer color.Disable(false) 34 35 spec.Run(t, "phases", testLifecycleExecution, spec.Report(report.Terminal{}), spec.Sequential()) 36 } 37 38 func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { 39 // Avoid contaminating tests with existing docker configuration. 40 // GGCR resolves the default keychain by inspecting DOCKER_CONFIG - this is used by the Analyze step 41 // when constructing the auth config (see `auth.BuildEnvVar` in phases.go). 42 var dockerConfigDir string 43 it.Before(func() { 44 var err error 45 dockerConfigDir, err = ioutil.TempDir("", "empty-docker-config-dir") 46 h.AssertNil(t, err) 47 48 h.AssertNil(t, os.Setenv("DOCKER_CONFIG", dockerConfigDir)) 49 }) 50 51 it.After(func() { 52 h.AssertNil(t, os.Unsetenv("DOCKER_CONFIG")) 53 h.AssertNil(t, os.RemoveAll(dockerConfigDir)) 54 }) 55 56 when("#NewLifecycleExecution", func() { 57 when("lifecycle supports multiple platform APIs", func() { 58 it("select the latest supported version", func() { 59 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{ 60 api.MustParse("0.2"), 61 api.MustParse("0.3"), 62 api.MustParse("0.4"), 63 api.MustParse("0.5"), 64 })) 65 h.AssertNil(t, err) 66 67 lifecycleExec := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 68 h.AssertEq(t, lifecycleExec.PlatformAPI().String(), "0.4") 69 }) 70 }) 71 72 when("supported platform API is deprecated", func() { 73 it("select the deprecated version", func() { 74 fakeBuilder, err := fakes.NewFakeBuilder( 75 fakes.WithDeprecatedPlatformAPIs([]*api.Version{api.MustParse("0.4")}), 76 fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("1.2")}), 77 ) 78 h.AssertNil(t, err) 79 80 lifecycleExec := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 81 h.AssertEq(t, lifecycleExec.PlatformAPI().String(), "0.4") 82 }) 83 }) 84 85 when("pack doesn't support any lifecycle supported platform API", func() { 86 it("errors", func() { 87 fakeBuilder, err := fakes.NewFakeBuilder( 88 fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("1.2")}), 89 ) 90 h.AssertNil(t, err) 91 92 _, err = newTestLifecycleExecErr(t, false, fakes.WithBuilder(fakeBuilder)) 93 h.AssertError(t, err, "unable to find a supported Platform API version") 94 }) 95 }) 96 }) 97 98 when("Run", func() { 99 var ( 100 imageName name.Tag 101 fakeBuilder *fakes.FakeBuilder 102 outBuf bytes.Buffer 103 logger *ilogging.LogWithWriters 104 docker *client.Client 105 fakePhaseFactory *fakes.FakePhaseFactory 106 ) 107 108 it.Before(func() { 109 var err error 110 imageName, err = name.NewTag("/some/image", name.WeakValidation) 111 h.AssertNil(t, err) 112 113 fakeBuilder, err = fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.3")})) 114 h.AssertNil(t, err) 115 logger = ilogging.NewLogWithWriters(&outBuf, &outBuf) 116 docker, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) 117 h.AssertNil(t, err) 118 fakePhaseFactory = fakes.NewFakePhaseFactory() 119 }) 120 121 when("Run using creator", func() { 122 it("succeeds", func() { 123 opts := build.LifecycleOptions{ 124 Publish: false, 125 ClearCache: false, 126 RunImage: "test", 127 Image: imageName, 128 Builder: fakeBuilder, 129 TrustBuilder: false, 130 UseCreator: true, 131 } 132 133 lifecycle, err := build.NewLifecycleExecution(logger, docker, opts) 134 h.AssertNil(t, err) 135 136 err = lifecycle.Run(context.Background(), func(execution *build.LifecycleExecution) build.PhaseFactory { 137 return fakePhaseFactory 138 }) 139 h.AssertNil(t, err) 140 141 h.AssertEq(t, len(fakePhaseFactory.NewCalledWithProvider), 1) 142 143 for _, entry := range fakePhaseFactory.NewCalledWithProvider { 144 if entry.Name() == "creator" { 145 h.AssertSliceContains(t, entry.ContainerConfig().Cmd, "/some/image") 146 } 147 } 148 }) 149 }) 150 when("Run without using creator", func() { 151 it("succeeds", func() { 152 opts := build.LifecycleOptions{ 153 Publish: false, 154 ClearCache: false, 155 RunImage: "test", 156 Image: imageName, 157 Builder: fakeBuilder, 158 TrustBuilder: false, 159 UseCreator: false, 160 } 161 162 lifecycle, err := build.NewLifecycleExecution(logger, docker, opts) 163 h.AssertNil(t, err) 164 165 err = lifecycle.Run(context.Background(), func(execution *build.LifecycleExecution) build.PhaseFactory { 166 return fakePhaseFactory 167 }) 168 h.AssertNil(t, err) 169 170 h.AssertEq(t, len(fakePhaseFactory.NewCalledWithProvider), 5) 171 172 for _, entry := range fakePhaseFactory.NewCalledWithProvider { 173 switch entry.Name() { 174 case "exporter": 175 h.AssertSliceContains(t, entry.ContainerConfig().Cmd, "/some/image") 176 case "analyzer": 177 h.AssertSliceContains(t, entry.ContainerConfig().Cmd, "/some/image") 178 } 179 } 180 }) 181 }) 182 }) 183 184 when("#Create", func() { 185 it("creates a phase and then run it", func() { 186 lifecycle := newTestLifecycleExec(t, false) 187 fakePhase := &fakes.FakePhase{} 188 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 189 190 err := lifecycle.Create( 191 context.Background(), 192 false, 193 false, 194 "test", 195 "test", 196 "test", 197 "test", 198 "test", 199 []string{}, 200 fakePhaseFactory, 201 ) 202 h.AssertNil(t, err) 203 204 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 205 h.AssertEq(t, fakePhase.RunCallCount, 1) 206 }) 207 208 it("configures the phase with the expected arguments", func() { 209 verboseLifecycle := newTestLifecycleExec(t, true) 210 fakePhaseFactory := fakes.NewFakePhaseFactory() 211 expectedRepoName := "some-repo-name" 212 expectedRunImage := "some-run-image" 213 214 err := verboseLifecycle.Create( 215 context.Background(), 216 false, 217 false, 218 expectedRunImage, 219 "test", 220 "test", 221 expectedRepoName, 222 "test", 223 []string{}, 224 fakePhaseFactory, 225 ) 226 h.AssertNil(t, err) 227 228 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 229 h.AssertNotEq(t, lastCallIndex, -1) 230 231 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 232 h.AssertEq(t, configProvider.Name(), "creator") 233 h.AssertIncludeAllExpectedPatterns(t, 234 configProvider.ContainerConfig().Cmd, 235 []string{"-log-level", "debug"}, 236 []string{"-run-image", expectedRunImage}, 237 []string{expectedRepoName}, 238 ) 239 }) 240 241 it("configures the phase with the expected network mode", func() { 242 lifecycle := newTestLifecycleExec(t, false) 243 fakePhaseFactory := fakes.NewFakePhaseFactory() 244 expectedNetworkMode := "some-network-mode" 245 246 err := lifecycle.Create( 247 context.Background(), 248 false, 249 false, 250 "test", 251 "test", 252 "test", 253 "test", 254 expectedNetworkMode, 255 []string{}, 256 fakePhaseFactory, 257 ) 258 h.AssertNil(t, err) 259 260 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 261 h.AssertNotEq(t, lastCallIndex, -1) 262 263 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 264 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 265 }) 266 267 when("clear cache", func() { 268 it("configures the phase with the expected arguments", func() { 269 verboseLifecycle := newTestLifecycleExec(t, true) 270 fakePhaseFactory := fakes.NewFakePhaseFactory() 271 272 err := verboseLifecycle.Create( 273 context.Background(), 274 false, 275 true, 276 "test", 277 "test", 278 "test", 279 "test", 280 "test", 281 []string{}, 282 fakePhaseFactory, 283 ) 284 h.AssertNil(t, err) 285 286 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 287 h.AssertNotEq(t, lastCallIndex, -1) 288 289 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 290 h.AssertEq(t, configProvider.Name(), "creator") 291 h.AssertIncludeAllExpectedPatterns(t, 292 configProvider.ContainerConfig().Cmd, 293 []string{"-skip-restore"}, 294 ) 295 }) 296 }) 297 298 when("clear cache is false", func() { 299 it("configures the phase with the expected arguments", func() { 300 verboseLifecycle := newTestLifecycleExec(t, true) 301 fakePhaseFactory := fakes.NewFakePhaseFactory() 302 303 err := verboseLifecycle.Create( 304 context.Background(), 305 false, 306 false, 307 "test", 308 "test", 309 "test", 310 "test", 311 "test", 312 []string{}, 313 fakePhaseFactory, 314 ) 315 h.AssertNil(t, err) 316 317 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 318 h.AssertNotEq(t, lastCallIndex, -1) 319 320 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 321 h.AssertEq(t, configProvider.Name(), "creator") 322 h.AssertIncludeAllExpectedPatterns(t, 323 configProvider.ContainerConfig().Cmd, 324 []string{"-cache-dir", "/cache"}, 325 ) 326 }) 327 }) 328 329 when("publish", func() { 330 it("configures the phase with binds", func() { 331 lifecycle := newTestLifecycleExec(t, false) 332 fakePhaseFactory := fakes.NewFakePhaseFactory() 333 volumeMount := "custom-mount-source:/custom-mount-target" 334 expectedBinds := []string{volumeMount, "some-cache:/cache"} 335 336 err := lifecycle.Create( 337 context.Background(), 338 true, 339 false, 340 "test", 341 "test", 342 "some-cache", 343 "test", 344 "test", 345 []string{volumeMount}, 346 fakePhaseFactory, 347 ) 348 h.AssertNil(t, err) 349 350 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 351 h.AssertNotEq(t, lastCallIndex, -1) 352 353 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 354 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBinds...) 355 }) 356 357 it("configures the phase with root", func() { 358 lifecycle := newTestLifecycleExec(t, false) 359 fakePhaseFactory := fakes.NewFakePhaseFactory() 360 361 err := lifecycle.Create( 362 context.Background(), 363 true, 364 false, 365 "test", 366 "test", 367 "test", 368 "test", 369 "test", 370 []string{}, 371 fakePhaseFactory, 372 ) 373 h.AssertNil(t, err) 374 375 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 376 h.AssertNotEq(t, lastCallIndex, -1) 377 378 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 379 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 380 }) 381 382 it("configures the phase with registry access", func() { 383 lifecycle := newTestLifecycleExec(t, false) 384 fakePhaseFactory := fakes.NewFakePhaseFactory() 385 expectedRepos := "some-repo-name" 386 387 err := lifecycle.Create( 388 context.Background(), 389 true, 390 false, 391 "test", 392 "test", 393 "test", 394 expectedRepos, 395 "test", 396 []string{}, 397 fakePhaseFactory, 398 ) 399 h.AssertNil(t, err) 400 401 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 402 h.AssertNotEq(t, lastCallIndex, -1) 403 404 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 405 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_REGISTRY_AUTH={}") 406 }) 407 408 when("platform 0.3", func() { 409 it("doesn't hint at default process type", func() { 410 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.3")})) 411 h.AssertNil(t, err) 412 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 413 fakePhaseFactory := fakes.NewFakePhaseFactory() 414 415 err = lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 416 h.AssertNil(t, err) 417 418 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 419 h.AssertNotEq(t, lastCallIndex, -1) 420 421 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 422 h.AssertSliceNotContains(t, configProvider.ContainerConfig().Cmd, "-process-type") 423 }) 424 }) 425 426 when("platform 0.4", func() { 427 it("hints at default process type", func() { 428 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.4")})) 429 h.AssertNil(t, err) 430 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 431 fakePhaseFactory := fakes.NewFakePhaseFactory() 432 433 err = lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 434 h.AssertNil(t, err) 435 436 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 437 h.AssertNotEq(t, lastCallIndex, -1) 438 439 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 440 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, []string{"-process-type", "web"}) 441 }) 442 }) 443 }) 444 445 when("publish is false", func() { 446 it("configures the phase with the expected arguments", func() { 447 verboseLifecycle := newTestLifecycleExec(t, true) 448 fakePhaseFactory := fakes.NewFakePhaseFactory() 449 450 err := verboseLifecycle.Create( 451 context.Background(), 452 false, 453 false, 454 "test", 455 "test", 456 "test", 457 "test", 458 "test", 459 []string{}, 460 fakePhaseFactory, 461 ) 462 h.AssertNil(t, err) 463 464 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 465 h.AssertNotEq(t, lastCallIndex, -1) 466 467 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 468 h.AssertEq(t, configProvider.Name(), "creator") 469 h.AssertIncludeAllExpectedPatterns(t, 470 configProvider.ContainerConfig().Cmd, 471 []string{"-daemon"}, 472 []string{"-launch-cache", "/launch-cache"}, 473 ) 474 }) 475 476 it("configures the phase with daemon access", func() { 477 lifecycle := newTestLifecycleExec(t, false) 478 fakePhaseFactory := fakes.NewFakePhaseFactory() 479 480 err := lifecycle.Create( 481 context.Background(), 482 false, 483 false, 484 "test", 485 "some-launch-cache", 486 "some-cache", 487 "test", 488 "test", 489 []string{}, 490 fakePhaseFactory, 491 ) 492 h.AssertNil(t, err) 493 494 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 495 h.AssertNotEq(t, lastCallIndex, -1) 496 497 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 498 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 499 h.AssertSliceContains(t, configProvider.HostConfig().Binds, "/var/run/docker.sock:/var/run/docker.sock") 500 }) 501 502 it("configures the phase with binds", func() { 503 lifecycle := newTestLifecycleExec(t, false) 504 fakePhaseFactory := fakes.NewFakePhaseFactory() 505 volumeMount := "custom-mount-source:/custom-mount-target" 506 expectedBinds := []string{volumeMount, "some-cache:/cache", "some-launch-cache:/launch-cache"} 507 508 err := lifecycle.Create( 509 context.Background(), 510 false, 511 false, 512 "test", 513 "some-launch-cache", 514 "some-cache", 515 "test", 516 "test", 517 []string{volumeMount}, 518 fakePhaseFactory, 519 ) 520 h.AssertNil(t, err) 521 522 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 523 h.AssertNotEq(t, lastCallIndex, -1) 524 525 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 526 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBinds...) 527 }) 528 529 when("platform 0.3", func() { 530 it("doesn't hint at default process type", func() { 531 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.3")})) 532 h.AssertNil(t, err) 533 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 534 fakePhaseFactory := fakes.NewFakePhaseFactory() 535 536 err = lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 537 h.AssertNil(t, err) 538 539 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 540 h.AssertNotEq(t, lastCallIndex, -1) 541 542 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 543 h.AssertSliceNotContains(t, configProvider.ContainerConfig().Cmd, "-process-type") 544 }) 545 }) 546 547 when("platform 0.4", func() { 548 it("hints at default process type", func() { 549 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.4")})) 550 h.AssertNil(t, err) 551 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 552 fakePhaseFactory := fakes.NewFakePhaseFactory() 553 554 err = lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 555 h.AssertNil(t, err) 556 557 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 558 h.AssertNotEq(t, lastCallIndex, -1) 559 560 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 561 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, []string{"-process-type", "web"}) 562 }) 563 }) 564 }) 565 }) 566 567 when("#Detect", func() { 568 it("creates a phase and then runs it", func() { 569 lifecycle := newTestLifecycleExec(t, false) 570 fakePhase := &fakes.FakePhase{} 571 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 572 573 err := lifecycle.Detect(context.Background(), "test", []string{}, fakePhaseFactory) 574 h.AssertNil(t, err) 575 576 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 577 h.AssertEq(t, fakePhase.RunCallCount, 1) 578 }) 579 580 it("configures the phase with the expected arguments", func() { 581 verboseLifecycle := newTestLifecycleExec(t, true) 582 fakePhaseFactory := fakes.NewFakePhaseFactory() 583 584 err := verboseLifecycle.Detect(context.Background(), "test", []string{"test"}, fakePhaseFactory) 585 h.AssertNil(t, err) 586 587 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 588 h.AssertNotEq(t, lastCallIndex, -1) 589 590 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 591 h.AssertEq(t, configProvider.Name(), "detector") 592 h.AssertIncludeAllExpectedPatterns(t, 593 configProvider.ContainerConfig().Cmd, 594 []string{"-log-level", "debug"}, 595 []string{"-app", "/workspace"}, 596 []string{"-platform", "/platform"}, 597 ) 598 }) 599 600 it("configures the phase with the expected network mode", func() { 601 lifecycle := newTestLifecycleExec(t, false) 602 fakePhaseFactory := fakes.NewFakePhaseFactory() 603 expectedNetworkMode := "some-network-mode" 604 605 err := lifecycle.Detect(context.Background(), expectedNetworkMode, []string{}, fakePhaseFactory) 606 h.AssertNil(t, err) 607 608 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 609 h.AssertNotEq(t, lastCallIndex, -1) 610 611 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 612 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 613 }) 614 615 it("configures the phase to copy app dir", func() { 616 lifecycle := newTestLifecycleExec(t, false) 617 fakePhaseFactory := fakes.NewFakePhaseFactory() 618 expectedBind := "some-mount-source:/some-mount-target" 619 620 err := lifecycle.Detect(context.Background(), "test", []string{expectedBind}, fakePhaseFactory) 621 h.AssertNil(t, err) 622 623 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 624 h.AssertNotEq(t, lastCallIndex, -1) 625 626 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 627 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 628 629 h.AssertEq(t, len(configProvider.ContainerOps()), 2) 630 h.AssertFunctionName(t, configProvider.ContainerOps()[0], "EnsureVolumeAccess") 631 h.AssertFunctionName(t, configProvider.ContainerOps()[1], "CopyDir") 632 }) 633 }) 634 635 when("#Analyze", func() { 636 it("creates a phase and then runs it", func() { 637 lifecycle := newTestLifecycleExec(t, false) 638 fakePhase := &fakes.FakePhase{} 639 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 640 641 err := lifecycle.Analyze(context.Background(), "test", "test", "test", false, false, fakePhaseFactory) 642 h.AssertNil(t, err) 643 644 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 645 h.AssertEq(t, fakePhase.RunCallCount, 1) 646 }) 647 648 when("clear cache", func() { 649 it("configures the phase with the expected arguments", func() { 650 lifecycle := newTestLifecycleExec(t, false) 651 fakePhaseFactory := fakes.NewFakePhaseFactory() 652 expectedRepoName := "some-repo-name" 653 654 err := lifecycle.Analyze(context.Background(), expectedRepoName, "test", "test", false, true, fakePhaseFactory) 655 h.AssertNil(t, err) 656 657 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 658 h.AssertNotEq(t, lastCallIndex, -1) 659 660 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 661 h.AssertEq(t, configProvider.Name(), "analyzer") 662 h.AssertSliceContains(t, configProvider.ContainerConfig().Cmd, "-skip-layers") 663 }) 664 }) 665 666 when("clear cache is false", func() { 667 it("configures the phase with the expected arguments", func() { 668 lifecycle := newTestLifecycleExec(t, false) 669 fakePhaseFactory := fakes.NewFakePhaseFactory() 670 expectedRepoName := "some-repo-name" 671 672 err := lifecycle.Analyze(context.Background(), expectedRepoName, "test", "test", false, false, fakePhaseFactory) 673 h.AssertNil(t, err) 674 675 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 676 h.AssertNotEq(t, lastCallIndex, -1) 677 678 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 679 h.AssertEq(t, configProvider.Name(), "analyzer") 680 h.AssertIncludeAllExpectedPatterns(t, 681 configProvider.ContainerConfig().Cmd, 682 []string{"-cache-dir", "/cache"}, 683 ) 684 }) 685 }) 686 687 when("publish", func() { 688 it("runs the phase with the lifecycle image", func() { 689 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 690 options.LifecycleImage = "some-lifecycle-image" 691 }) 692 fakePhaseFactory := fakes.NewFakePhaseFactory() 693 694 err := lifecycle.Analyze(context.Background(), "test", "test", "test", true, false, fakePhaseFactory) 695 h.AssertNil(t, err) 696 697 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 698 h.AssertNotEq(t, lastCallIndex, -1) 699 700 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 701 h.AssertEq(t, configProvider.ContainerConfig().Image, "some-lifecycle-image") 702 }) 703 704 it("sets the CNB_USER_ID and CNB_GROUP_ID in the environment", func() { 705 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithUID(2222), fakes.WithGID(3333)) 706 h.AssertNil(t, err) 707 lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 708 fakePhaseFactory := fakes.NewFakePhaseFactory() 709 710 err = lifecycle.Analyze(context.Background(), "test", "test", "test", true, false, fakePhaseFactory) 711 h.AssertNil(t, err) 712 713 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 714 h.AssertNotEq(t, lastCallIndex, -1) 715 716 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 717 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_USER_ID=2222") 718 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_GROUP_ID=3333") 719 }) 720 721 it("configures the phase with registry access", func() { 722 lifecycle := newTestLifecycleExec(t, false) 723 fakePhaseFactory := fakes.NewFakePhaseFactory() 724 expectedRepos := "some-repo-name" 725 expectedNetworkMode := "some-network-mode" 726 727 err := lifecycle.Analyze(context.Background(), expectedRepos, "test", expectedNetworkMode, true, false, fakePhaseFactory) 728 h.AssertNil(t, err) 729 730 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 731 h.AssertNotEq(t, lastCallIndex, -1) 732 733 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 734 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_REGISTRY_AUTH={}") 735 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 736 }) 737 738 it("configures the phase with root", func() { 739 lifecycle := newTestLifecycleExec(t, false) 740 fakePhaseFactory := fakes.NewFakePhaseFactory() 741 742 err := lifecycle.Analyze(context.Background(), "test", "test", "test", true, false, fakePhaseFactory) 743 h.AssertNil(t, err) 744 745 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 746 h.AssertNotEq(t, lastCallIndex, -1) 747 748 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 749 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 750 }) 751 752 it("configures the phase with the expected arguments", func() { 753 verboseLifecycle := newTestLifecycleExec(t, true) 754 fakePhaseFactory := fakes.NewFakePhaseFactory() 755 expectedRepoName := "some-repo-name" 756 757 err := verboseLifecycle.Analyze(context.Background(), expectedRepoName, "test", "test", true, false, fakePhaseFactory) 758 h.AssertNil(t, err) 759 760 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 761 h.AssertNotEq(t, lastCallIndex, -1) 762 763 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 764 h.AssertEq(t, configProvider.Name(), "analyzer") 765 h.AssertIncludeAllExpectedPatterns(t, 766 configProvider.ContainerConfig().Cmd, 767 []string{"-log-level", "debug"}, 768 []string{"-layers", "/layers"}, 769 []string{expectedRepoName}, 770 ) 771 }) 772 773 it("configures the phase with binds", func() { 774 lifecycle := newTestLifecycleExec(t, false) 775 fakePhaseFactory := fakes.NewFakePhaseFactory() 776 expectedBind := "some-cache:/cache" 777 778 err := lifecycle.Analyze(context.Background(), "test", "some-cache", "test", true, false, fakePhaseFactory) 779 h.AssertNil(t, err) 780 781 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 782 h.AssertNotEq(t, lastCallIndex, -1) 783 784 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 785 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 786 }) 787 }) 788 789 when("publish is false", func() { 790 it("runs the phase with the lifecycle image", func() { 791 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 792 options.LifecycleImage = "some-lifecycle-image" 793 }) 794 fakePhaseFactory := fakes.NewFakePhaseFactory() 795 796 err := lifecycle.Analyze(context.Background(), "test", "test", "test", false, false, fakePhaseFactory) 797 h.AssertNil(t, err) 798 799 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 800 h.AssertNotEq(t, lastCallIndex, -1) 801 802 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 803 h.AssertEq(t, configProvider.ContainerConfig().Image, "some-lifecycle-image") 804 }) 805 806 it("sets the CNB_USER_ID and CNB_GROUP_ID in the environment", func() { 807 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithUID(2222), fakes.WithGID(3333)) 808 h.AssertNil(t, err) 809 lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 810 fakePhaseFactory := fakes.NewFakePhaseFactory() 811 812 err = lifecycle.Analyze(context.Background(), "test", "test", "test", false, false, fakePhaseFactory) 813 h.AssertNil(t, err) 814 815 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 816 h.AssertNotEq(t, lastCallIndex, -1) 817 818 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 819 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_USER_ID=2222") 820 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_GROUP_ID=3333") 821 }) 822 823 it("configures the phase with daemon access", func() { 824 lifecycle := newTestLifecycleExec(t, false) 825 fakePhaseFactory := fakes.NewFakePhaseFactory() 826 827 err := lifecycle.Analyze(context.Background(), "test", "test", "test", false, false, fakePhaseFactory) 828 h.AssertNil(t, err) 829 830 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 831 h.AssertNotEq(t, lastCallIndex, -1) 832 833 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 834 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 835 h.AssertSliceContains(t, configProvider.HostConfig().Binds, "/var/run/docker.sock:/var/run/docker.sock") 836 }) 837 838 it("configures the phase with the expected arguments", func() { 839 verboseLifecycle := newTestLifecycleExec(t, true) 840 fakePhaseFactory := fakes.NewFakePhaseFactory() 841 expectedRepoName := "some-repo-name" 842 843 err := verboseLifecycle.Analyze(context.Background(), expectedRepoName, "test", "test", false, true, fakePhaseFactory) 844 h.AssertNil(t, err) 845 846 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 847 h.AssertNotEq(t, lastCallIndex, -1) 848 849 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 850 h.AssertEq(t, configProvider.Name(), "analyzer") 851 h.AssertIncludeAllExpectedPatterns(t, 852 configProvider.ContainerConfig().Cmd, 853 []string{"-log-level", "debug"}, 854 []string{"-daemon"}, 855 []string{"-layers", "/layers"}, 856 []string{expectedRepoName}, 857 ) 858 }) 859 860 it("configures the phase with the expected network mode", func() { 861 lifecycle := newTestLifecycleExec(t, false) 862 fakePhaseFactory := fakes.NewFakePhaseFactory() 863 expectedNetworkMode := "some-network-mode" 864 865 err := lifecycle.Analyze(context.Background(), "test", "test", expectedNetworkMode, false, false, fakePhaseFactory) 866 h.AssertNil(t, err) 867 868 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 869 h.AssertNotEq(t, lastCallIndex, -1) 870 871 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 872 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 873 }) 874 875 it("configures the phase with binds", func() { 876 lifecycle := newTestLifecycleExec(t, false) 877 fakePhaseFactory := fakes.NewFakePhaseFactory() 878 expectedBind := "some-cache:/cache" 879 880 err := lifecycle.Analyze(context.Background(), "test", "some-cache", "test", false, true, fakePhaseFactory) 881 h.AssertNil(t, err) 882 883 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 884 h.AssertNotEq(t, lastCallIndex, -1) 885 886 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 887 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 888 }) 889 }) 890 }) 891 892 when("#Restore", func() { 893 it("runs the phase with the lifecycle image", func() { 894 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 895 options.LifecycleImage = "some-lifecycle-image" 896 }) 897 fakePhaseFactory := fakes.NewFakePhaseFactory() 898 899 err := lifecycle.Restore(context.Background(), "test", "test", fakePhaseFactory) 900 h.AssertNil(t, err) 901 902 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 903 h.AssertNotEq(t, lastCallIndex, -1) 904 905 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 906 h.AssertEq(t, configProvider.ContainerConfig().Image, "some-lifecycle-image") 907 }) 908 909 it("sets the CNB_USER_ID and CNB_GROUP_ID in the environment", func() { 910 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithUID(2222), fakes.WithGID(3333)) 911 h.AssertNil(t, err) 912 lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 913 fakePhaseFactory := fakes.NewFakePhaseFactory() 914 915 err = lifecycle.Restore(context.Background(), "test", "test", fakePhaseFactory) 916 h.AssertNil(t, err) 917 918 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 919 h.AssertNotEq(t, lastCallIndex, -1) 920 921 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 922 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_USER_ID=2222") 923 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_GROUP_ID=3333") 924 }) 925 926 it("creates a phase and then runs it", func() { 927 lifecycle := newTestLifecycleExec(t, false) 928 fakePhase := &fakes.FakePhase{} 929 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 930 931 err := lifecycle.Restore(context.Background(), "test", "test", fakePhaseFactory) 932 h.AssertNil(t, err) 933 934 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 935 h.AssertEq(t, fakePhase.RunCallCount, 1) 936 }) 937 938 it("configures the phase with root access", func() { 939 lifecycle := newTestLifecycleExec(t, false) 940 fakePhaseFactory := fakes.NewFakePhaseFactory() 941 942 err := lifecycle.Restore(context.Background(), "test", "test", fakePhaseFactory) 943 h.AssertNil(t, err) 944 945 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 946 h.AssertNotEq(t, lastCallIndex, -1) 947 948 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 949 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 950 }) 951 952 it("configures the phase with the expected arguments", func() { 953 verboseLifecycle := newTestLifecycleExec(t, true) 954 fakePhaseFactory := fakes.NewFakePhaseFactory() 955 956 err := verboseLifecycle.Restore(context.Background(), "test", "test", fakePhaseFactory) 957 h.AssertNil(t, err) 958 959 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 960 h.AssertNotEq(t, lastCallIndex, -1) 961 962 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 963 h.AssertEq(t, configProvider.Name(), "restorer") 964 h.AssertIncludeAllExpectedPatterns(t, 965 configProvider.ContainerConfig().Cmd, 966 []string{"-log-level", "debug"}, 967 []string{"-cache-dir", "/cache"}, 968 []string{"-layers", "/layers"}, 969 ) 970 }) 971 972 it("configures the phase with the expected network mode", func() { 973 lifecycle := newTestLifecycleExec(t, false) 974 fakePhaseFactory := fakes.NewFakePhaseFactory() 975 expectedNetworkMode := "some-network-mode" 976 977 err := lifecycle.Restore(context.Background(), "test", expectedNetworkMode, fakePhaseFactory) 978 h.AssertNil(t, err) 979 980 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 981 h.AssertNotEq(t, lastCallIndex, -1) 982 983 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 984 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 985 }) 986 987 it("configures the phase with binds", func() { 988 lifecycle := newTestLifecycleExec(t, false) 989 fakePhaseFactory := fakes.NewFakePhaseFactory() 990 expectedBind := "some-cache:/cache" 991 992 err := lifecycle.Restore(context.Background(), "some-cache", "test", fakePhaseFactory) 993 h.AssertNil(t, err) 994 995 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 996 h.AssertNotEq(t, lastCallIndex, -1) 997 998 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 999 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 1000 }) 1001 }) 1002 1003 when("#Build", func() { 1004 it("creates a phase and then runs it", func() { 1005 lifecycle := newTestLifecycleExec(t, false) 1006 fakePhase := &fakes.FakePhase{} 1007 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 1008 1009 err := lifecycle.Build(context.Background(), "test", []string{}, fakePhaseFactory) 1010 h.AssertNil(t, err) 1011 1012 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 1013 h.AssertEq(t, fakePhase.RunCallCount, 1) 1014 }) 1015 1016 it("configures the phase with the expected arguments", func() { 1017 fakeBuilder, err := fakes.NewFakeBuilder() 1018 h.AssertNil(t, err) 1019 verboseLifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 1020 fakePhaseFactory := fakes.NewFakePhaseFactory() 1021 1022 err = verboseLifecycle.Build(context.Background(), "test", []string{}, fakePhaseFactory) 1023 h.AssertNil(t, err) 1024 1025 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1026 h.AssertNotEq(t, lastCallIndex, -1) 1027 1028 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1029 h.AssertEq(t, configProvider.Name(), "builder") 1030 h.AssertIncludeAllExpectedPatterns(t, 1031 configProvider.ContainerConfig().Cmd, 1032 []string{"-log-level", "debug"}, 1033 []string{"-layers", "/layers"}, 1034 []string{"-app", "/workspace"}, 1035 []string{"-platform", "/platform"}, 1036 ) 1037 }) 1038 1039 it("configures the phase with the expected network mode", func() { 1040 lifecycle := newTestLifecycleExec(t, false) 1041 fakePhaseFactory := fakes.NewFakePhaseFactory() 1042 expectedNetworkMode := "some-network-mode" 1043 1044 err := lifecycle.Build(context.Background(), expectedNetworkMode, []string{}, fakePhaseFactory) 1045 h.AssertNil(t, err) 1046 1047 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1048 h.AssertNotEq(t, lastCallIndex, -1) 1049 1050 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1051 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 1052 }) 1053 1054 it("configures the phase with binds", func() { 1055 lifecycle := newTestLifecycleExec(t, false) 1056 fakePhaseFactory := fakes.NewFakePhaseFactory() 1057 expectedBind := "some-mount-source:/some-mount-target" 1058 1059 err := lifecycle.Build(context.Background(), "test", []string{expectedBind}, fakePhaseFactory) 1060 h.AssertNil(t, err) 1061 1062 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1063 h.AssertNotEq(t, lastCallIndex, -1) 1064 1065 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1066 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 1067 }) 1068 }) 1069 1070 when("#Export", func() { 1071 it("creates a phase and then runs it", func() { 1072 lifecycle := newTestLifecycleExec(t, false) 1073 fakePhase := &fakes.FakePhase{} 1074 fakePhaseFactory := fakes.NewFakePhaseFactory(fakes.WhichReturnsForNew(fakePhase)) 1075 1076 err := lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1077 h.AssertNil(t, err) 1078 1079 h.AssertEq(t, fakePhase.CleanupCallCount, 1) 1080 h.AssertEq(t, fakePhase.RunCallCount, 1) 1081 }) 1082 1083 it("configures the phase with the expected arguments", func() { 1084 verboseLifecycle := newTestLifecycleExec(t, true) 1085 fakePhaseFactory := fakes.NewFakePhaseFactory() 1086 expectedRepoName := "some-repo-name" 1087 expectedRunImage := "some-run-image" 1088 1089 err := verboseLifecycle.Export(context.Background(), expectedRepoName, expectedRunImage, false, "test", "test", "test", fakePhaseFactory) 1090 h.AssertNil(t, err) 1091 1092 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1093 h.AssertNotEq(t, lastCallIndex, -1) 1094 1095 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1096 h.AssertEq(t, configProvider.Name(), "exporter") 1097 h.AssertIncludeAllExpectedPatterns(t, 1098 configProvider.ContainerConfig().Cmd, 1099 []string{"-log-level", "debug"}, 1100 []string{"-cache-dir", "/cache"}, 1101 []string{"-layers", "/layers"}, 1102 []string{"-app", "/workspace"}, 1103 []string{"-run-image", expectedRunImage}, 1104 []string{expectedRepoName}, 1105 ) 1106 }) 1107 1108 when("publish", func() { 1109 it("runs the phase with the lifecycle image", func() { 1110 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 1111 options.LifecycleImage = "some-lifecycle-image" 1112 }) 1113 fakePhaseFactory := fakes.NewFakePhaseFactory() 1114 1115 err := lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1116 h.AssertNil(t, err) 1117 1118 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1119 h.AssertNotEq(t, lastCallIndex, -1) 1120 1121 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1122 h.AssertEq(t, configProvider.ContainerConfig().Image, "some-lifecycle-image") 1123 }) 1124 1125 it("sets the CNB_USER_ID and CNB_GROUP_ID in the environment", func() { 1126 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithUID(2222), fakes.WithGID(3333)) 1127 h.AssertNil(t, err) 1128 lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 1129 fakePhaseFactory := fakes.NewFakePhaseFactory() 1130 1131 err = lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1132 h.AssertNil(t, err) 1133 1134 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1135 h.AssertNotEq(t, lastCallIndex, -1) 1136 1137 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1138 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_USER_ID=2222") 1139 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_GROUP_ID=3333") 1140 }) 1141 1142 it("configures the phase with registry access", func() { 1143 lifecycle := newTestLifecycleExec(t, false) 1144 fakePhaseFactory := fakes.NewFakePhaseFactory() 1145 expectedRepos := []string{"some-repo-name", "some-run-image"} 1146 1147 err := lifecycle.Export(context.Background(), expectedRepos[0], expectedRepos[1], true, "test", "test", "test", fakePhaseFactory) 1148 h.AssertNil(t, err) 1149 1150 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1151 h.AssertNotEq(t, lastCallIndex, -1) 1152 1153 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1154 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_REGISTRY_AUTH={}") 1155 }) 1156 1157 it("configures the phase with root", func() { 1158 lifecycle := newTestLifecycleExec(t, false) 1159 fakePhaseFactory := fakes.NewFakePhaseFactory() 1160 1161 err := lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1162 h.AssertNil(t, err) 1163 1164 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1165 h.AssertNotEq(t, lastCallIndex, -1) 1166 1167 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1168 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 1169 }) 1170 1171 it("configures the phase with the expected network mode", func() { 1172 lifecycle := newTestLifecycleExec(t, false) 1173 fakePhaseFactory := fakes.NewFakePhaseFactory() 1174 expectedNetworkMode := "some-network-mode" 1175 1176 err := lifecycle.Export(context.Background(), "test", "test", true, "test", "test", expectedNetworkMode, fakePhaseFactory) 1177 h.AssertNil(t, err) 1178 1179 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1180 h.AssertNotEq(t, lastCallIndex, -1) 1181 1182 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1183 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 1184 }) 1185 1186 it("configures the phase with binds", func() { 1187 lifecycle := newTestLifecycleExec(t, false) 1188 fakePhaseFactory := fakes.NewFakePhaseFactory() 1189 expectedBind := "some-cache:/cache" 1190 1191 err := lifecycle.Export(context.Background(), "test", "test", true, "test", "some-cache", "test", fakePhaseFactory) 1192 h.AssertNil(t, err) 1193 1194 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1195 h.AssertNotEq(t, lastCallIndex, -1) 1196 1197 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1198 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBind) 1199 }) 1200 1201 it("configures the phase to write stack toml", func() { 1202 lifecycle := newTestLifecycleExec(t, false) 1203 fakePhaseFactory := fakes.NewFakePhaseFactory() 1204 expectedBinds := []string{"some-cache:/cache", "some-launch-cache:/launch-cache"} 1205 1206 err := lifecycle.Export(context.Background(), "test", "test", false, "some-launch-cache", "some-cache", "test", fakePhaseFactory) 1207 h.AssertNil(t, err) 1208 1209 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1210 h.AssertNotEq(t, lastCallIndex, -1) 1211 1212 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1213 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBinds...) 1214 1215 h.AssertEq(t, len(configProvider.ContainerOps()), 1) 1216 h.AssertFunctionName(t, configProvider.ContainerOps()[0], "WriteStackToml") 1217 }) 1218 1219 it("configures the phase with default process type", func() { 1220 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 1221 options.DefaultProcessType = "test-process" 1222 }) 1223 fakePhaseFactory := fakes.NewFakePhaseFactory() 1224 expectedDefaultProc := []string{"-process-type", "test-process"} 1225 1226 err := lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1227 h.AssertNil(t, err) 1228 1229 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1230 h.AssertNotEq(t, lastCallIndex, -1) 1231 1232 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1233 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, expectedDefaultProc) 1234 }) 1235 1236 when("platform 0.3", func() { 1237 it("doesn't hint at default process type", func() { 1238 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.3")})) 1239 h.AssertNil(t, err) 1240 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 1241 fakePhaseFactory := fakes.NewFakePhaseFactory() 1242 1243 err = lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1244 h.AssertNil(t, err) 1245 1246 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1247 h.AssertNotEq(t, lastCallIndex, -1) 1248 1249 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1250 h.AssertSliceNotContains(t, configProvider.ContainerConfig().Cmd, "-process-type") 1251 }) 1252 }) 1253 1254 when("platform 0.4", func() { 1255 it("hints at default process type", func() { 1256 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.4")})) 1257 h.AssertNil(t, err) 1258 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 1259 fakePhaseFactory := fakes.NewFakePhaseFactory() 1260 1261 err = lifecycle.Export(context.Background(), "test", "test", true, "test", "test", "test", fakePhaseFactory) 1262 h.AssertNil(t, err) 1263 1264 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1265 h.AssertNotEq(t, lastCallIndex, -1) 1266 1267 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1268 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, []string{"-process-type", "web"}) 1269 }) 1270 }) 1271 }) 1272 1273 when("publish is false", func() { 1274 it("runs the phase with the lifecycle image", func() { 1275 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 1276 options.LifecycleImage = "some-lifecycle-image" 1277 }) 1278 fakePhaseFactory := fakes.NewFakePhaseFactory() 1279 1280 err := lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1281 h.AssertNil(t, err) 1282 1283 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1284 h.AssertNotEq(t, lastCallIndex, -1) 1285 1286 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1287 h.AssertEq(t, configProvider.ContainerConfig().Image, "some-lifecycle-image") 1288 }) 1289 1290 it("sets the CNB_USER_ID and CNB_GROUP_ID in the environment", func() { 1291 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithUID(2222), fakes.WithGID(3333)) 1292 h.AssertNil(t, err) 1293 lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) 1294 fakePhaseFactory := fakes.NewFakePhaseFactory() 1295 1296 err = lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1297 h.AssertNil(t, err) 1298 1299 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1300 h.AssertNotEq(t, lastCallIndex, -1) 1301 1302 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1303 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_USER_ID=2222") 1304 h.AssertSliceContains(t, configProvider.ContainerConfig().Env, "CNB_GROUP_ID=3333") 1305 }) 1306 1307 it("configures the phase with daemon access", func() { 1308 lifecycle := newTestLifecycleExec(t, false) 1309 fakePhaseFactory := fakes.NewFakePhaseFactory() 1310 1311 err := lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1312 h.AssertNil(t, err) 1313 1314 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1315 h.AssertNotEq(t, lastCallIndex, -1) 1316 1317 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1318 h.AssertEq(t, configProvider.ContainerConfig().User, "root") 1319 h.AssertSliceContains(t, configProvider.HostConfig().Binds, "/var/run/docker.sock:/var/run/docker.sock") 1320 }) 1321 1322 it("configures the phase with the expected arguments", func() { 1323 verboseLifecycle := newTestLifecycleExec(t, true) 1324 fakePhaseFactory := fakes.NewFakePhaseFactory() 1325 1326 err := verboseLifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1327 h.AssertNil(t, err) 1328 1329 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1330 h.AssertNotEq(t, lastCallIndex, -1) 1331 1332 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1333 h.AssertEq(t, configProvider.Name(), "exporter") 1334 h.AssertIncludeAllExpectedPatterns(t, 1335 configProvider.ContainerConfig().Cmd, 1336 []string{"-daemon"}, 1337 []string{"-launch-cache", "/launch-cache"}, 1338 ) 1339 }) 1340 1341 it("configures the phase with the expected network mode", func() { 1342 lifecycle := newTestLifecycleExec(t, false) 1343 fakePhaseFactory := fakes.NewFakePhaseFactory() 1344 expectedNetworkMode := "some-network-mode" 1345 1346 err := lifecycle.Export(context.Background(), "test", "test", false, "test", "test", expectedNetworkMode, fakePhaseFactory) 1347 h.AssertNil(t, err) 1348 1349 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1350 h.AssertNotEq(t, lastCallIndex, -1) 1351 1352 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1353 h.AssertEq(t, configProvider.HostConfig().NetworkMode, container.NetworkMode(expectedNetworkMode)) 1354 }) 1355 1356 it("configures the phase with binds", func() { 1357 lifecycle := newTestLifecycleExec(t, false) 1358 fakePhaseFactory := fakes.NewFakePhaseFactory() 1359 expectedBinds := []string{"some-cache:/cache", "some-launch-cache:/launch-cache"} 1360 1361 err := lifecycle.Export(context.Background(), "test", "test", false, "some-launch-cache", "some-cache", "test", fakePhaseFactory) 1362 h.AssertNil(t, err) 1363 1364 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1365 h.AssertNotEq(t, lastCallIndex, -1) 1366 1367 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1368 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBinds...) 1369 }) 1370 1371 it("configures the phase to write stack toml", func() { 1372 lifecycle := newTestLifecycleExec(t, false) 1373 fakePhaseFactory := fakes.NewFakePhaseFactory() 1374 expectedBinds := []string{"some-cache:/cache", "some-launch-cache:/launch-cache"} 1375 1376 err := lifecycle.Export(context.Background(), "test", "test", false, "some-launch-cache", "some-cache", "test", fakePhaseFactory) 1377 h.AssertNil(t, err) 1378 1379 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1380 h.AssertNotEq(t, lastCallIndex, -1) 1381 1382 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1383 h.AssertSliceContains(t, configProvider.HostConfig().Binds, expectedBinds...) 1384 1385 h.AssertEq(t, len(configProvider.ContainerOps()), 1) 1386 h.AssertFunctionName(t, configProvider.ContainerOps()[0], "WriteStackToml") 1387 }) 1388 1389 it("configures the phase with default process type", func() { 1390 lifecycle := newTestLifecycleExec(t, true, func(options *build.LifecycleOptions) { 1391 options.DefaultProcessType = "test-process" 1392 }) 1393 fakePhaseFactory := fakes.NewFakePhaseFactory() 1394 expectedDefaultProc := []string{"-process-type", "test-process"} 1395 1396 err := lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1397 h.AssertNil(t, err) 1398 1399 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1400 h.AssertNotEq(t, lastCallIndex, -1) 1401 1402 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1403 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, expectedDefaultProc) 1404 }) 1405 1406 when("platform 0.3", func() { 1407 it("doesn't hint at default process type", func() { 1408 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.3")})) 1409 h.AssertNil(t, err) 1410 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 1411 fakePhaseFactory := fakes.NewFakePhaseFactory() 1412 1413 err = lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1414 h.AssertNil(t, err) 1415 1416 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1417 h.AssertNotEq(t, lastCallIndex, -1) 1418 1419 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1420 h.AssertSliceNotContains(t, configProvider.ContainerConfig().Cmd, "-process-type") 1421 }) 1422 }) 1423 1424 when("platform 0.4", func() { 1425 it("hints at default process type", func() { 1426 fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithSupportedPlatformAPIs([]*api.Version{api.MustParse("0.4")})) 1427 h.AssertNil(t, err) 1428 lifecycle := newTestLifecycleExec(t, true, fakes.WithBuilder(fakeBuilder)) 1429 fakePhaseFactory := fakes.NewFakePhaseFactory() 1430 1431 err = lifecycle.Export(context.Background(), "test", "test", false, "test", "test", "test", fakePhaseFactory) 1432 h.AssertNil(t, err) 1433 1434 lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 1435 h.AssertNotEq(t, lastCallIndex, -1) 1436 1437 configProvider := fakePhaseFactory.NewCalledWithProvider[lastCallIndex] 1438 h.AssertIncludeAllExpectedPatterns(t, configProvider.ContainerConfig().Cmd, []string{"-process-type", "web"}) 1439 }) 1440 }) 1441 }) 1442 }) 1443 } 1444 1445 func newTestLifecycleExecErr(t *testing.T, logVerbose bool, ops ...func(*build.LifecycleOptions)) (*build.LifecycleExecution, error) { 1446 docker, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) 1447 h.AssertNil(t, err) 1448 1449 var outBuf bytes.Buffer 1450 logger := ilogging.NewLogWithWriters(&outBuf, &outBuf) 1451 if logVerbose { 1452 logger.Level = log.DebugLevel 1453 } 1454 1455 defaultBuilder, err := fakes.NewFakeBuilder() 1456 h.AssertNil(t, err) 1457 1458 opts := build.LifecycleOptions{ 1459 AppPath: "some-app-path", 1460 Builder: defaultBuilder, 1461 HTTPProxy: "some-http-proxy", 1462 HTTPSProxy: "some-https-proxy", 1463 NoProxy: "some-no-proxy", 1464 } 1465 1466 for _, op := range ops { 1467 op(&opts) 1468 } 1469 1470 return build.NewLifecycleExecution(logger, docker, opts) 1471 } 1472 1473 func newTestLifecycleExec(t *testing.T, logVerbose bool, ops ...func(*build.LifecycleOptions)) *build.LifecycleExecution { 1474 t.Helper() 1475 1476 lifecycleExec, err := newTestLifecycleExecErr(t, logVerbose, ops...) 1477 h.AssertNil(t, err) 1478 return lifecycleExec 1479 }