From 0fdb1ec505f56020c547b85e40906f1fecb4ff94 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Thu, 11 Aug 2022 09:37:55 -0500 Subject: [PATCH 01/15] Migrate happy path build test to new acceptance suite Signed-off-by: Javier Romero --- Makefile | 4 +- acceptance/acceptance_test.go | 147 +----------- acceptance/buildpacks/manager.go | 17 +- acceptance/config/asset_manager.go | 32 +-- acceptance/invoke/pack.go | 15 ++ acceptance/v2/build_test.go | 246 ++++++++++++++++++++ acceptance/v2/v2.go | 354 +++++++++++++++++++++++++++++ 7 files changed, 656 insertions(+), 159 deletions(-) create mode 100644 acceptance/v2/build_test.go create mode 100644 acceptance/v2/v2.go diff --git a/Makefile b/Makefile index 33b04baa1..651c65ecb 100644 --- a/Makefile +++ b/Makefile @@ -109,12 +109,12 @@ unit: out acceptance: out @echo "> Running acceptance tests..." - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/... acceptance-all: export ACCEPTANCE_SUITE_CONFIG:=$(shell $(CAT) .$/acceptance$/testconfig$/all.json) acceptance-all: @echo "> Running acceptance tests..." - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/... clean: @echo "> Cleaning workspace..." diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index ec32ad2c2..cbbb590f1 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -14,7 +14,6 @@ import ( "math/rand" "os" "path/filepath" - "regexp" "runtime" "strings" "testing" @@ -73,7 +72,7 @@ func TestAcceptance(t *testing.T) { inputConfigManager, err := config.NewInputConfigurationManager() assert.Nil(err) - assetsConfig := config.ConvergedAssetManager(t, assert, inputConfigManager) + assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, filepath.Join("testdata")) suiteManager = &SuiteManager{out: t.Logf} suite := spec.New("acceptance suite", spec.Report(report.Terminal{})) @@ -663,7 +662,7 @@ func testAcceptance( value, err := suiteManager.RunTaskOnceString("create-stack", func() (string, error) { runImageMirror := registryConfig.RepoName(runImage) - err := createStack(t, dockerCli, runImageMirror) + err := createStack(t, dockerCli, imageManager, runImageMirror) if err != nil { return "", err } @@ -694,7 +693,7 @@ func testAcceptance( )..., ) value, err := suiteManager.RunTaskOnceString(key, func() (string, error) { - return createBuilder(t, assert, createBuilderPack, lifecycle, buildpackManager, runImageMirror) + return createBuilder(t, assert, imageManager, dockerCli, createBuilderPack, lifecycle, buildpackManager, runImageMirror) }) assert.Nil(err) suiteManager.RegisterCleanUp("clean-"+key, func() error { @@ -794,6 +793,8 @@ func testAcceptance( untrustedBuilderName, err = createBuilder( t, assert, + imageManager, + dockerCli, createBuilderPack, lifecycle, buildpackManager, @@ -879,140 +880,6 @@ func testAcceptance( pack.JustRunSuccessfully("config", "trusted-builders", "add", builderName) }) - it("creates a runnable, rebuildable image on daemon from app dir", func() { - appPath := filepath.Join("testdata", "mock_app") - - output := pack.RunSuccessfully( - "build", repoName, - "-p", appPath, - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsUsingBuildCacheVolume() - assertOutput.ReportsSelectingRunImageMirror(runImageMirror) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("it uses the run image as a base image") - assertImage.HasBaseImage(repoName, runImage) - - t.Log("sets the run image metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImage, runImageMirror)) - - t.Log("sets the source metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) - - t.Log("registry is empty") - assertImage.NotExistsInRegistry(repo) - - t.Log("add a local mirror") - localRunImageMirror := registryConfig.RepoName("pack-test/run-mirror") - imageManager.TagImage(runImage, localRunImageMirror) - defer imageManager.CleanupImages(localRunImageMirror) - pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImage, "-m", localRunImageMirror) - - t.Log("rebuild") - output = pack.RunSuccessfully( - "build", repoName, - "-p", appPath, - ) - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) - cachedLaunchLayer := "simple/layers:cached-launch-layer" - - assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("rebuild with --clear-cache") - output = pack.RunSuccessfully("build", repoName, "-p", appPath, "--clear-cache") - - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) - - t.Log("cacher adds layers") - assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) - - t.Log("inspecting image") - inspectCmd := "inspect" - if !pack.Supports("inspect") { - inspectCmd = "inspect-image" - } - - var ( - webCommand string - helloCommand string - helloArgs []string - helloArgsPrefix string - imageWorkdir string - ) - if imageManager.HostOS() == "windows" { - webCommand = ".\\run" - helloCommand = "cmd" - helloArgs = []string{"/c", "echo hello world"} - helloArgsPrefix = " " - imageWorkdir = "c:\\workspace" - - } else { - webCommand = "./run" - helloCommand = "echo" - helloArgs = []string{"hello", "world"} - helloArgsPrefix = "" - imageWorkdir = "/workspace" - } - - formats := []compareFormat{ - { - extension: "json", - compareFunc: assert.EqualJSON, - outputArg: "json", - }, - { - extension: "yaml", - compareFunc: assert.EqualYAML, - outputArg: "yaml", - }, - { - extension: "toml", - compareFunc: assert.EqualTOML, - outputArg: "toml", - }, - } - for _, format := range formats { - t.Logf("inspecting image %s format", format.outputArg) - - output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) - expectedOutput := pack.FixtureManager().TemplateFixture( - fmt.Sprintf("inspect_image_local_output.%s", format.extension), - map[string]interface{}{ - "image_name": repoName, - "base_image_id": h.ImageID(t, runImageMirror), - "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), - "run_image_local_mirror": localRunImageMirror, - "run_image_mirror": runImageMirror, - "web_command": webCommand, - "hello_command": helloCommand, - "hello_args": helloArgs, - "hello_args_prefix": helloArgsPrefix, - "image_workdir": imageWorkdir, - }, - ) - - format.compareFunc(output, expectedOutput) - } - }) - when("--no-color", func() { it("doesn't have color", func() { appPath := filepath.Join("testdata", "mock_app") @@ -2699,6 +2566,8 @@ func createComplexBuilder(t *testing.T, func createBuilder( t *testing.T, assert h.AssertionManager, + imageManager managers.ImageManager, + dockerCli client.CommonAPIClient, pack *invoke.PackInvoker, lifecycle config.LifecycleAsset, buildpackManager buildpacks.BuildpackManager, @@ -2813,7 +2682,7 @@ func generatePackageTomlWithOS( return packageTomlFile.Name() } -func createStack(t *testing.T, dockerCli client.CommonAPIClient, runImageMirror string) error { +func createStack(t *testing.T, dockerCli client.CommonAPIClient, imageManager managers.ImageManager, runImageMirror string) error { t.Helper() t.Log("creating stack images...") diff --git a/acceptance/buildpacks/manager.go b/acceptance/buildpacks/manager.go index eafd80a88..1aa4f3154 100644 --- a/acceptance/buildpacks/manager.go +++ b/acceptance/buildpacks/manager.go @@ -8,21 +8,27 @@ import ( "testing" "github.com/buildpacks/pack/internal/builder" - "github.com/buildpacks/pack/testhelpers" ) type BuildpackManager struct { testObject *testing.T assert testhelpers.AssertionManager - sourceDir string + baseDir string + apiVersion string } type BuildpackManagerModifier func(b *BuildpackManager) +func WithBaseDir(baseDir string) func(b *BuildpackManager) { + return func(b *BuildpackManager) { + b.baseDir = baseDir + } +} + func WithBuildpackAPIVersion(apiVersion string) func(b *BuildpackManager) { return func(b *BuildpackManager) { - b.sourceDir = filepath.Join("testdata", "mock_buildpacks", apiVersion) + b.apiVersion = apiVersion } } @@ -30,7 +36,8 @@ func NewBuildpackManager(t *testing.T, assert testhelpers.AssertionManager, modi m := BuildpackManager{ testObject: t, assert: assert, - sourceDir: filepath.Join("testdata", "mock_buildpacks", builder.DefaultBuildpackAPIVersion), + baseDir: filepath.Join("testdata", "mock_buildpacks"), + apiVersion: builder.DefaultBuildpackAPIVersion, } for _, mod := range modifiers { @@ -48,7 +55,7 @@ func (b BuildpackManager) PrepareBuildpacks(destination string, buildpacks ...Te b.testObject.Helper() for _, buildpack := range buildpacks { - err := buildpack.Prepare(b.sourceDir, destination) + err := buildpack.Prepare(filepath.Join(b.baseDir, b.apiVersion), destination) b.assert.Nil(err) } } diff --git a/acceptance/config/asset_manager.go b/acceptance/config/asset_manager.go index 7a6ea0c4a..62ada8bb3 100644 --- a/acceptance/config/asset_manager.go +++ b/acceptance/config/asset_manager.go @@ -25,12 +25,11 @@ const ( ) var ( - currentPackFixturesDir = filepath.Join("testdata", "pack_fixtures") - previousPackFixturesOverridesDir = filepath.Join("testdata", "pack_previous_fixtures_overrides") - lifecycleTgzExp = regexp.MustCompile(`lifecycle-v\d+.\d+.\d+\+linux.x86-64.tgz`) + lifecycleTgzExp = regexp.MustCompile(`lifecycle-v\d+.\d+.\d+\+linux.x86-64.tgz`) ) type AssetManager struct { + testObject *testing.T packPath string packFixturesPath string previousPackPath string @@ -43,10 +42,9 @@ type AssetManager struct { previousLifecycleDescriptor builder.LifecycleDescriptor previousLifecycleImage string defaultLifecycleDescriptor builder.LifecycleDescriptor - testObject *testing.T } -func ConvergedAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputConfigurationManager) AssetManager { +func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputConfigurationManager, testDataDir string) AssetManager { t.Helper() var ( @@ -63,7 +61,7 @@ func ConvergedAssetManager(t *testing.T, assert h.AssertionManager, inputConfig ) githubAssetFetcher, err := NewGithubAssetFetcher(t, inputConfig.githubToken) - h.AssertNil(t, err) + assert.Nil(err) assetBuilder := assetManagerBuilder{ testObject: t, @@ -78,9 +76,10 @@ func ConvergedAssetManager(t *testing.T, assert h.AssertionManager, inputConfig if inputConfig.combinations.requiresPreviousPack() { convergedPreviousPackPath = assetBuilder.ensurePreviousPack() - convergedPreviousPackFixturesPath := assetBuilder.ensurePreviousPackFixtures() - - convergedPreviousPackFixturesPaths = []string{previousPackFixturesOverridesDir, convergedPreviousPackFixturesPath} + convergedPreviousPackFixturesPaths = []string{ + filepath.Join(testDataDir, "pack_previous_fixtures_overrides"), + assetBuilder.ensurePreviousPackFixtures(), + } } if inputConfig.combinations.requiresCurrentLifecycle() { @@ -97,7 +96,7 @@ func ConvergedAssetManager(t *testing.T, assert h.AssertionManager, inputConfig return AssetManager{ packPath: convergedCurrentPackPath, - packFixturesPath: currentPackFixturesDir, + packFixturesPath: filepath.Join(testDataDir, "pack_fixtures"), previousPackPath: convergedPreviousPackPath, previousPackFixturesPaths: convergedPreviousPackFixturesPaths, lifecyclePath: convergedCurrentLifecyclePath, @@ -359,12 +358,19 @@ func (b assetManagerBuilder) buildPack(compileVersion string) string { "-o", packPath, "./cmd/pack", ) - if filepath.Base(cwd) == "acceptance" { - cmd.Dir = filepath.Dir(cwd) + + cmd.Dir = cwd + if filepath.Base(cmd.Dir) == "v2" { + cmd.Dir = filepath.Dir(cmd.Dir) + } + + if filepath.Base(cmd.Dir) == "acceptance" { + cmd.Dir = filepath.Dir(cmd.Dir) } b.testObject.Logf("building pack: [CWD=%s] %s", cmd.Dir, cmd.Args) - _, err = cmd.CombinedOutput() + output, err := cmd.CombinedOutput() + b.testObject.Logf("output:\n%s", string(output)) b.assert.Nil(err) return packPath diff --git a/acceptance/invoke/pack.go b/acceptance/invoke/pack.go index 333dbb054..9b2b8c7da 100644 --- a/acceptance/invoke/pack.go +++ b/acceptance/invoke/pack.go @@ -5,6 +5,8 @@ package invoke import ( "bytes" + "crypto/sha256" + "encoding/hex" "fmt" "io/ioutil" "os" @@ -22,6 +24,7 @@ import ( ) type PackInvoker struct { + identifier string testObject *testing.T assert h.AssertionManager path string @@ -50,7 +53,15 @@ func NewPackInvoker( testObject.Fatalf("couldn't create home folder for pack: %s", err) } + hash := sha256.New() + hash.Write([]byte(packAssets.Path())) + for _, v := range packAssets.FixturePaths() { + hash.Write([]byte(v)) + } + identifier := hex.EncodeToString(hash.Sum(nil)) + return &PackInvoker{ + identifier: identifier, testObject: testObject, assert: assert, path: packAssets.Path(), @@ -94,6 +105,10 @@ func (i *PackInvoker) cmd(name string, args ...string) *exec.Cmd { return cmd } +func (i *PackInvoker) Identifier() string { + return i.identifier +} + func (i *PackInvoker) baseCmd(parts ...string) *exec.Cmd { return exec.Command(i.path, parts...) } diff --git a/acceptance/v2/build_test.go b/acceptance/v2/build_test.go new file mode 100644 index 000000000..d23e0a9c6 --- /dev/null +++ b/acceptance/v2/build_test.go @@ -0,0 +1,246 @@ +//go:build acceptance +// +build acceptance + +package acceptance_new + +import ( + "fmt" + "math/rand" + "path/filepath" + "regexp" + "testing" + "time" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/buildpacks" + "github.com/buildpacks/pack/acceptance/config" + "github.com/buildpacks/pack/acceptance/invoke" + "github.com/buildpacks/pack/acceptance/managers" + h "github.com/buildpacks/pack/testhelpers" + "github.com/docker/docker/client" +) + +func TestBuild(t *testing.T) { + h.RequireDocker(t) + rand.Seed(time.Now().UTC().UnixNano()) + + assert := h.NewAssertionManager(t) + + // docker cli + dockerCli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) + assert.Nil(err) + + imageManager := managers.NewImageManager(t, dockerCli) + + // run temp registry + registryConfig := h.RunRegistry(t) + defer registryConfig.RmRegistry(t) + + // image assert + assertImage := assertions.NewImageAssertionManager(t, imageManager, registryConfig) + + // gather config + inputConfigManager, err := config.NewInputConfigurationManager() + assert.Nil(err) + + assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, filepath.Join("..", "testdata")) + + // create stack + runImageName := "pack-test/run" + buildImageName := "pack-test/build" + + runImageMirror := registryConfig.RepoName(runImageName) + err = createStack(t, dockerCli, registryConfig, imageManager, runImageName, buildImageName, runImageMirror) + assert.Nil(err) + + stackBaseImages := map[string][]string{ + "linux": {"ubuntu:bionic"}, + "windows": {"mcr.microsoft.com/windows/nanoserver:1809", "golang:1.17-nanoserver-1809"}, + } + baseStackNames := stackBaseImages[imageManager.HostOS()] + defer imageManager.CleanupImages(baseStackNames...) + defer imageManager.CleanupImages(runImageName, buildImageName, runImageMirror) + + for _, combo := range inputConfigManager.Combinations() { + combo := combo + + t.Logf("Running combo: %s", combo) + + lifecycle := assetsConfig.NewLifecycleAsset(combo.Lifecycle) + + pack := invoke.NewPackInvoker(t, assert, assetsConfig.NewPackAsset(combo.Pack), registryConfig.DockerConfigDir) + pack.EnableExperimental() + pack.JustRunSuccessfully("config", "lifecycle-image", lifecycle.Image()) + + createBuilderPack := invoke.NewPackInvoker(t, assert, assetsConfig.NewPackAsset(combo.PackCreateBuilder), registryConfig.DockerConfigDir) + createBuilderPack.EnableExperimental() + + buildpackManager := buildpacks.NewBuildpackManager( + t, + assert, + buildpacks.WithBuildpackAPIVersion(lifecycle.EarliestBuildpackAPIVersion()), + buildpacks.WithBaseDir(filepath.Join("..", "testdata", "mock_buildpacks")), + ) + + repo := "some-org/" + h.RandString(10) + repoName := registryConfig.RepoName(repo) + + // create builder + builderName, err := createBuilder(t, assert, registryConfig, imageManager, dockerCli, createBuilderPack, lifecycle, buildpackManager, runImageMirror) + assert.Nil(err) + defer imageManager.CleanupImages(builderName) + + t.Run("creates a runnable, rebuildable image on daemon from app dir", func(t *testing.T) { + appPath := filepath.Join("..", "testdata", "mock_app") + + output := pack.RunSuccessfully( + "build", repoName, + "-B", builderName, + "-p", appPath, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsUsingBuildCacheVolume() + assertOutput.ReportsSelectingRunImageMirror(runImageMirror) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("it uses the run image as a base image") + assertImage.HasBaseImage(repoName, runImageName) + + t.Log("sets the run image metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImageName, runImageMirror)) + + t.Log("sets the source metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) + + t.Log("registry is empty") + assertImage.NotExistsInRegistry(repo) + + t.Log("add a local mirror") + localRunImageMirror := registryConfig.RepoName("pack-test/run-mirror") + imageManager.TagImage(runImageName, localRunImageMirror) + defer imageManager.CleanupImages(localRunImageMirror) + pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + + t.Log("rebuild") + output = pack.RunSuccessfully( + "build", repoName, + "-B", builderName, + "-p", appPath, + ) + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) + cachedLaunchLayer := "simple/layers:cached-launch-layer" + + assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("rebuild with --clear-cache") + output = pack.RunSuccessfully("build", + repoName, + "-B", builderName, + "-p", appPath, + "--clear-cache", + ) + + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) + + t.Log("cacher adds layers") + assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) + + t.Log("inspecting image") + inspectCmd := "inspect" + if !pack.Supports("inspect") { + inspectCmd = "inspect-image" + } + + var ( + webCommand string + helloCommand string + helloArgs []string + helloArgsPrefix string + imageWorkdir string + ) + if imageManager.HostOS() == "windows" { + webCommand = ".\\run" + helloCommand = "cmd" + helloArgs = []string{"/c", "echo hello world"} + helloArgsPrefix = " " + imageWorkdir = "c:\\workspace" + + } else { + webCommand = "./run" + helloCommand = "echo" + helloArgs = []string{"hello", "world"} + helloArgsPrefix = "" + imageWorkdir = "/workspace" + } + + formats := []compareFormat{ + { + extension: "json", + compareFunc: assert.EqualJSON, + outputArg: "json", + }, + { + extension: "yaml", + compareFunc: assert.EqualYAML, + outputArg: "yaml", + }, + { + extension: "toml", + compareFunc: assert.EqualTOML, + outputArg: "toml", + }, + } + for _, format := range formats { + t.Logf("inspecting image %s format", format.outputArg) + + output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) + expectedOutput := pack.FixtureManager().TemplateFixture( + fmt.Sprintf("inspect_image_local_output.%s", format.extension), + map[string]interface{}{ + "image_name": repoName, + "base_image_id": h.ImageID(t, runImageMirror), + "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), + "run_image_local_mirror": localRunImageMirror, + "run_image_mirror": runImageMirror, + "web_command": webCommand, + "hello_command": helloCommand, + "hello_args": helloArgs, + "hello_args_prefix": helloArgsPrefix, + "image_workdir": imageWorkdir, + }, + ) + + format.compareFunc(output, expectedOutput) + } + }) + } + + // suiteManager.CleanUp() + // imageManager.CleanupImages(repoName) + + // ref, err := name.ParseReference(repoName, name.WeakValidation) + // assert.Nil(err) + // cacheImage := cache.NewImageCache(ref, dockerCli) + // buildCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "build", dockerCli) + // launchCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "launch", dockerCli) + // cacheImage.Clear(context.TODO()) + // buildCacheVolume.Clear(context.TODO()) + // launchCacheVolume.Clear(context.TODO()) +} diff --git a/acceptance/v2/v2.go b/acceptance/v2/v2.go new file mode 100644 index 000000000..624727494 --- /dev/null +++ b/acceptance/v2/v2.go @@ -0,0 +1,354 @@ +//go:build acceptance +// +build acceptance + +package acceptance_new + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + dockertypes "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + + "github.com/buildpacks/pack/acceptance/buildpacks" + "github.com/buildpacks/pack/acceptance/config" + "github.com/buildpacks/pack/acceptance/invoke" + "github.com/buildpacks/pack/acceptance/managers" + "github.com/buildpacks/pack/pkg/archive" + h "github.com/buildpacks/pack/testhelpers" +) + +func buildpacksDir(bpAPIVersion string) string { + return filepath.Join("testdata", "mock_buildpacks", bpAPIVersion) +} + +func createComplexBuilder(t *testing.T, + assert h.AssertionManager, + registryConfig *h.TestRegistryConfig, + imageManager *managers.ImageManager, + dockerCli *client.Client, + pack *invoke.PackInvoker, + lifecycle config.LifecycleAsset, + buildpackManager buildpacks.BuildpackManager, + runImageMirror string, +) (string, error) { + + t.Log("creating complex builder image...") + + // CREATE TEMP WORKING DIR + tmpDir, err := ioutil.TempDir("", "create-complex-test-builder") + if err != nil { + return "", err + } + defer os.RemoveAll(tmpDir) + + // ARCHIVE BUILDPACKS + builderBuildpacks := []buildpacks.TestBuildpack{ + buildpacks.Noop, + buildpacks.Noop2, + buildpacks.OtherStack, + buildpacks.ReadEnv, + } + + templateMapping := map[string]interface{}{ + "run_image_mirror": runImageMirror, + } + + packageImageName := registryConfig.RepoName("nested-level-1-buildpack-" + h.RandString(8)) + nestedLevelTwoBuildpackName := registryConfig.RepoName("nested-level-2-buildpack-" + h.RandString(8)) + simpleLayersBuildpackName := registryConfig.RepoName("simple-layers-buildpack-" + h.RandString(8)) + simpleLayersBuildpackDifferentShaName := registryConfig.RepoName("simple-layers-buildpack-different-name-" + h.RandString(8)) + + templateMapping["package_id"] = "simple/nested-level-1" + templateMapping["package_image_name"] = packageImageName + templateMapping["nested_level_1_buildpack"] = packageImageName + templateMapping["nested_level_2_buildpack"] = nestedLevelTwoBuildpackName + templateMapping["simple_layers_buildpack"] = simpleLayersBuildpackName + templateMapping["simple_layers_buildpack_different_sha"] = simpleLayersBuildpackDifferentShaName + + fixtureManager := pack.FixtureManager() + + nestedLevelOneConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-1-package.toml") + assert.Nil(err) + fixtureManager.TemplateFixtureToFile( + "nested-level-1-buildpack_package.toml", + nestedLevelOneConfigFile, + templateMapping, + ) + err = nestedLevelOneConfigFile.Close() + assert.Nil(err) + + nestedLevelTwoConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-2-package.toml") + assert.Nil(err) + fixtureManager.TemplateFixtureToFile( + "nested-level-2-buildpack_package.toml", + nestedLevelTwoConfigFile, + templateMapping, + ) + + err = nestedLevelTwoConfigFile.Close() + assert.Nil(err) + + packageImageBuildpack := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + nestedLevelOneConfigFile.Name(), + buildpacks.WithRequiredBuildpacks( + buildpacks.NestedLevelOne, + buildpacks.NewPackageImage( + t, + pack, + nestedLevelTwoBuildpackName, + nestedLevelTwoConfigFile.Name(), + buildpacks.WithRequiredBuildpacks( + buildpacks.NestedLevelTwo, + buildpacks.NewPackageImage( + t, + pack, + simpleLayersBuildpackName, + fixtureManager.FixtureLocation("simple-layers-buildpack_package.toml"), + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), + ), + ), + ), + ), + ) + + simpleLayersDifferentShaBuildpack := buildpacks.NewPackageImage( + t, + pack, + simpleLayersBuildpackDifferentShaName, + fixtureManager.FixtureLocation("simple-layers-buildpack-different-sha_package.toml"), + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayersDifferentSha), + ) + + defer imageManager.CleanupImages(packageImageName, nestedLevelTwoBuildpackName, simpleLayersBuildpackName, simpleLayersBuildpackDifferentShaName) + + builderBuildpacks = append( + builderBuildpacks, + packageImageBuildpack, + simpleLayersDifferentShaBuildpack, + ) + + buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) + + // ADD lifecycle + if lifecycle.HasLocation() { + lifecycleURI := lifecycle.EscapedPath() + t.Logf("adding lifecycle path '%s' to builder config", lifecycleURI) + templateMapping["lifecycle_uri"] = lifecycleURI + } else { + lifecycleVersion := lifecycle.Version() + t.Logf("adding lifecycle version '%s' to builder config", lifecycleVersion) + templateMapping["lifecycle_version"] = lifecycleVersion + } + + // RENDER builder.toml + builderConfigFile, err := ioutil.TempFile(tmpDir, "nested_builder.toml") + if err != nil { + return "", err + } + + pack.FixtureManager().TemplateFixtureToFile("nested_builder.toml", builderConfigFile, templateMapping) + + err = builderConfigFile.Close() + if err != nil { + return "", err + } + + // NAME BUILDER + bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) + + // CREATE BUILDER + output := pack.RunSuccessfully( + "builder", "create", bldr, + "-c", builderConfigFile.Name(), + "--no-color", + ) + + assert.Contains(output, fmt.Sprintf("Successfully created builder image '%s'", bldr)) + assert.Succeeds(h.PushImage(dockerCli, bldr, registryConfig)) + + return bldr, nil +} + +func createBuilder( + t *testing.T, + assert h.AssertionManager, + registryConfig *h.TestRegistryConfig, + imageManager managers.ImageManager, + dockerCli client.CommonAPIClient, + pack *invoke.PackInvoker, + lifecycle config.LifecycleAsset, + buildpackManager buildpacks.BuildpackManager, + runImageMirror string, +) (string, error) { + t.Log("creating builder image...") + + // CREATE TEMP WORKING DIR + tmpDir, err := ioutil.TempDir("", "create-test-builder") + assert.Nil(err) + defer os.RemoveAll(tmpDir) + + templateMapping := map[string]interface{}{ + "run_image_mirror": runImageMirror, + } + + // ARCHIVE BUILDPACKS + builderBuildpacks := []buildpacks.TestBuildpack{ + buildpacks.Noop, + buildpacks.Noop2, + buildpacks.OtherStack, + buildpacks.ReadEnv, + } + + packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package.toml", imageManager.HostOS()) + packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) + + packageImageBuildpack := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + packageTomlPath, + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), + ) + + defer imageManager.CleanupImages(packageImageName) + + builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) + + templateMapping["package_image_name"] = packageImageName + templateMapping["package_id"] = "simple/layers" + + buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) + + // ADD lifecycle + var lifecycleURI string + var lifecycleVersion string + if lifecycle.HasLocation() { + lifecycleURI = lifecycle.EscapedPath() + t.Logf("adding lifecycle path '%s' to builder config", lifecycleURI) + templateMapping["lifecycle_uri"] = lifecycleURI + } else { + lifecycleVersion = lifecycle.Version() + t.Logf("adding lifecycle version '%s' to builder config", lifecycleVersion) + templateMapping["lifecycle_version"] = lifecycleVersion + } + + // RENDER builder.toml + configFileName := "builder.toml" + + builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") + assert.Nil(err) + + pack.FixtureManager().TemplateFixtureToFile( + configFileName, + builderConfigFile, + templateMapping, + ) + + err = builderConfigFile.Close() + assert.Nil(err) + + // NAME BUILDER + bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) + + // CREATE BUILDER + output := pack.RunSuccessfully( + "builder", "create", bldr, + "-c", builderConfigFile.Name(), + "--no-color", + ) + + assert.Contains(output, fmt.Sprintf("Successfully created builder image '%s'", bldr)) + assert.Succeeds(h.PushImage(dockerCli, bldr, registryConfig)) + + return bldr, nil +} + +func generatePackageTomlWithOS( + t *testing.T, + assert h.AssertionManager, + pack *invoke.PackInvoker, + tmpDir string, + fixtureName string, + platform_os string, +) string { + t.Helper() + + packageTomlFile, err := ioutil.TempFile(tmpDir, "package-*.toml") + assert.Nil(err) + + pack.FixtureManager().TemplateFixtureToFile( + fixtureName, + packageTomlFile, + map[string]interface{}{ + "OS": platform_os, + }, + ) + + assert.Nil(packageTomlFile.Close()) + + return packageTomlFile.Name() +} + +func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror string) error { + t.Helper() + t.Log("creating stack images...") + + stackBaseDir := filepath.Join("..", "testdata", "mock_stack", imageManager.HostOS()) + + _, err := os.Stat(stackBaseDir) + if err != nil { + return err + } + + if err := createStackImage(dockerCli, runImageName, filepath.Join(stackBaseDir, "run")); err != nil { + return err + } + if err := createStackImage(dockerCli, buildImageName, filepath.Join(stackBaseDir, "build")); err != nil { + return err + } + + imageManager.TagImage(runImageName, runImageMirror) + if err := h.PushImage(dockerCli, runImageMirror, registryConfig); err != nil { + return err + } + + return nil +} + +func createStackImage(dockerCli client.CommonAPIClient, repoName string, dir string) error { + defaultFilterFunc := func(file string) bool { return true } + + ctx := context.Background() + buildContext := archive.ReadDirAsTar(dir, "/", 0, 0, -1, true, false, defaultFilterFunc) + + return h.CheckImageBuildResult(dockerCli.ImageBuild(ctx, buildContext, dockertypes.ImageBuildOptions{ + Tags: []string{repoName}, + Remove: true, + ForceRemove: true, + })) +} + +// taskKey creates a key from the prefix and all arguments to be unique +func taskKey(prefix string, args ...string) string { + hash := sha256.New() + for _, v := range args { + hash.Write([]byte(v)) + } + return fmt.Sprintf("%s-%s", prefix, hex.EncodeToString(hash.Sum(nil))) +} + +type compareFormat struct { + extension string + compareFunc func(string, string) + outputArg string +} From c4d455d6b2d88567d8d90e2a1b05d1b222bddba6 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Thu, 11 Aug 2022 11:56:51 -0500 Subject: [PATCH 02/15] Simplify usage via builder harness Signed-off-by: Javier Romero --- acceptance/harness/builder_harness.go | 185 ++++++++++++++ acceptance/harness/harness.go | 182 +++++++++++++ acceptance/v2/build_test.go | 106 ++------ acceptance/v2/v2.go | 354 -------------------------- 4 files changed, 390 insertions(+), 437 deletions(-) create mode 100644 acceptance/harness/builder_harness.go create mode 100644 acceptance/harness/harness.go delete mode 100644 acceptance/v2/v2.go diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go new file mode 100644 index 000000000..3353bc3b0 --- /dev/null +++ b/acceptance/harness/builder_harness.go @@ -0,0 +1,185 @@ +//go:build acceptance +// +build acceptance + +package harness + +import ( + "fmt" + "math/rand" + "path/filepath" + "testing" + "time" + + "github.com/buildpacks/pack/acceptance/buildpacks" + "github.com/buildpacks/pack/acceptance/config" + "github.com/buildpacks/pack/acceptance/invoke" + "github.com/buildpacks/pack/acceptance/managers" + h "github.com/buildpacks/pack/testhelpers" + "github.com/docker/docker/client" +) + +type BuilderCombo struct { + builderName string + pack invoke.PackInvoker + lifecycle config.LifecycleAsset +} + +func (b *BuilderCombo) BuilderName() string { + return b.builderName +} + +func (b *BuilderCombo) Pack() invoke.PackInvoker { + return b.pack +} + +func (b *BuilderCombo) Lifecycle() config.LifecycleAsset { + return b.lifecycle +} + +func (b *BuilderCombo) String() string { + return fmt.Sprintf("builder=%s, lifecycle=%v, pack=%v", b.builderName, b.lifecycle, b.pack) +} + +type BuilderTestHarness struct { + t *testing.T + registryConfig h.TestRegistryConfig + imageManager managers.ImageManager + runImageName string + runImageMirror string + buildImageName string + combos []BuilderCombo + cleanups []func() +} + +func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { + h.RequireDocker(t) + rand.Seed(time.Now().UTC().UnixNano()) + + cleanups := []func(){} + + assert := h.NewAssertionManager(t) + + // docker cli + dockerCli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) + assert.Nil(err) + + imageManager := managers.NewImageManager(t, dockerCli) + + // run temp registry + registry := h.RunRegistry(t) + cleanups = append(cleanups, func() { + registry.RmRegistry(t) + }) + + // gather config + inputConfigManager, err := config.NewInputConfigurationManager() + assert.Nil(err) + + assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, testDataDir) + + // create stack + runImageName := "pack-test/run" + buildImageName := "pack-test/build" + + runImageMirror := registry.RepoName(runImageName) + err = createStack(t, dockerCli, registry, imageManager, runImageName, buildImageName, runImageMirror) + assert.Nil(err) + + stackBaseImages := map[string][]string{ + "linux": {"ubuntu:bionic"}, + "windows": {"mcr.microsoft.com/windows/nanoserver:1809", "golang:1.17-nanoserver-1809"}, + } + baseStackNames := stackBaseImages[imageManager.HostOS()] + cleanups = append(cleanups, func() { + imageManager.CleanupImages(baseStackNames...) + imageManager.CleanupImages(runImageName, buildImageName, runImageMirror) + }) + + combos := []BuilderCombo{} + for _, combo := range inputConfigManager.Combinations() { + lifecycle := assetsConfig.NewLifecycleAsset(combo.Lifecycle) + pack := invoke.NewPackInvoker( + t, + assert, + assetsConfig.NewPackAsset(combo.Pack), + registry.DockerConfigDir, + ) + pack.JustRunSuccessfully("config", "lifecycle-image", lifecycle.Image()) + pack.EnableExperimental() + + buildpackManager := buildpacks.NewBuildpackManager( + t, + assert, + buildpacks.WithBuildpackAPIVersion(lifecycle.EarliestBuildpackAPIVersion()), + buildpacks.WithBaseDir(filepath.Join(testDataDir, "mock_buildpacks")), + ) + + createBuilderPack := invoke.NewPackInvoker( + t, + assert, + assetsConfig.NewPackAsset(combo.PackCreateBuilder), + registry.DockerConfigDir, + ) + createBuilderPack.EnableExperimental() + + // create builder + builderName, err := createBuilder( + t, + assert, + registry, + imageManager, + dockerCli, + createBuilderPack, + lifecycle, + buildpackManager, + runImageMirror, + ) + assert.Nil(err) + cleanups = append(cleanups, func() { + imageManager.CleanupImages(builderName) + }) + + combos = append(combos, BuilderCombo{ + builderName: builderName, + lifecycle: lifecycle, + pack: *pack, + }) + } + + return BuilderTestHarness{ + t: t, + registryConfig: *registry, + imageManager: imageManager, + runImageName: runImageName, + runImageMirror: runImageMirror, + buildImageName: buildImageName, + combos: combos, + cleanups: cleanups, + } +} + +func (b *BuilderTestHarness) Combinations() []BuilderCombo { + return b.combos +} + +func (b *BuilderTestHarness) Registry() h.TestRegistryConfig { + return b.registryConfig +} + +func (b *BuilderTestHarness) ImageManager() managers.ImageManager { + return b.imageManager +} + +func (b *BuilderTestHarness) RunImageName() string { + return b.runImageName +} + +func (b *BuilderTestHarness) RunImageMirror() string { + return b.runImageMirror +} + +func (b *BuilderTestHarness) CleanUp() { + for _, fn := range b.cleanups { + fn() + } +} diff --git a/acceptance/harness/harness.go b/acceptance/harness/harness.go new file mode 100644 index 000000000..5472b71ac --- /dev/null +++ b/acceptance/harness/harness.go @@ -0,0 +1,182 @@ +//go:build acceptance +// +build acceptance + +package harness + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + dockertypes "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + + "github.com/buildpacks/pack/acceptance/buildpacks" + "github.com/buildpacks/pack/acceptance/config" + "github.com/buildpacks/pack/acceptance/invoke" + "github.com/buildpacks/pack/acceptance/managers" + "github.com/buildpacks/pack/pkg/archive" + h "github.com/buildpacks/pack/testhelpers" +) + +func createBuilder( + t *testing.T, + assert h.AssertionManager, + registryConfig *h.TestRegistryConfig, + imageManager managers.ImageManager, + dockerCli client.CommonAPIClient, + pack *invoke.PackInvoker, + lifecycle config.LifecycleAsset, + buildpackManager buildpacks.BuildpackManager, + runImageMirror string, +) (string, error) { + t.Log("creating builder image...") + + // CREATE TEMP WORKING DIR + tmpDir, err := ioutil.TempDir("", "create-test-builder") + assert.Nil(err) + defer os.RemoveAll(tmpDir) + + templateMapping := map[string]interface{}{ + "run_image_mirror": runImageMirror, + } + + // ARCHIVE BUILDPACKS + builderBuildpacks := []buildpacks.TestBuildpack{ + buildpacks.Noop, + buildpacks.Noop2, + buildpacks.OtherStack, + buildpacks.ReadEnv, + } + + packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package.toml", imageManager.HostOS()) + packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) + + packageImageBuildpack := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + packageTomlPath, + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), + ) + + defer imageManager.CleanupImages(packageImageName) + + builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) + + templateMapping["package_image_name"] = packageImageName + templateMapping["package_id"] = "simple/layers" + + buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) + + // ADD lifecycle + var lifecycleURI string + var lifecycleVersion string + if lifecycle.HasLocation() { + lifecycleURI = lifecycle.EscapedPath() + t.Logf("adding lifecycle path '%s' to builder config", lifecycleURI) + templateMapping["lifecycle_uri"] = lifecycleURI + } else { + lifecycleVersion = lifecycle.Version() + t.Logf("adding lifecycle version '%s' to builder config", lifecycleVersion) + templateMapping["lifecycle_version"] = lifecycleVersion + } + + // RENDER builder.toml + configFileName := "builder.toml" + + builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") + assert.Nil(err) + + pack.FixtureManager().TemplateFixtureToFile( + configFileName, + builderConfigFile, + templateMapping, + ) + + err = builderConfigFile.Close() + assert.Nil(err) + + // NAME BUILDER + bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) + + // CREATE BUILDER + output := pack.RunSuccessfully( + "builder", "create", bldr, + "-c", builderConfigFile.Name(), + "--no-color", + ) + + assert.Contains(output, fmt.Sprintf("Successfully created builder image '%s'", bldr)) + assert.Succeeds(h.PushImage(dockerCli, bldr, registryConfig)) + + return bldr, nil +} + +func generatePackageTomlWithOS( + t *testing.T, + assert h.AssertionManager, + pack *invoke.PackInvoker, + tmpDir string, + fixtureName string, + platform_os string, +) string { + t.Helper() + + packageTomlFile, err := ioutil.TempFile(tmpDir, "package-*.toml") + assert.Nil(err) + + pack.FixtureManager().TemplateFixtureToFile( + fixtureName, + packageTomlFile, + map[string]interface{}{ + "OS": platform_os, + }, + ) + + assert.Nil(packageTomlFile.Close()) + + return packageTomlFile.Name() +} + +func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror string) error { + t.Helper() + t.Log("creating stack images...") + + stackBaseDir := filepath.Join("..", "testdata", "mock_stack", imageManager.HostOS()) + + _, err := os.Stat(stackBaseDir) + if err != nil { + return err + } + + if err := createStackImage(dockerCli, runImageName, filepath.Join(stackBaseDir, "run")); err != nil { + return err + } + if err := createStackImage(dockerCli, buildImageName, filepath.Join(stackBaseDir, "build")); err != nil { + return err + } + + imageManager.TagImage(runImageName, runImageMirror) + if err := h.PushImage(dockerCli, runImageMirror, registryConfig); err != nil { + return err + } + + return nil +} + +func createStackImage(dockerCli client.CommonAPIClient, repoName string, dir string) error { + defaultFilterFunc := func(file string) bool { return true } + + ctx := context.Background() + buildContext := archive.ReadDirAsTar(dir, "/", 0, 0, -1, true, false, defaultFilterFunc) + + return h.CheckImageBuildResult(dockerCli.ImageBuild(ctx, buildContext, dockertypes.ImageBuildOptions{ + Tags: []string{repoName}, + Remove: true, + ForceRemove: true, + })) +} diff --git a/acceptance/v2/build_test.go b/acceptance/v2/build_test.go index d23e0a9c6..d31d47148 100644 --- a/acceptance/v2/build_test.go +++ b/acceptance/v2/build_test.go @@ -5,94 +5,39 @@ package acceptance_new import ( "fmt" - "math/rand" "path/filepath" "regexp" "testing" - "time" "github.com/buildpacks/pack/acceptance/assertions" - "github.com/buildpacks/pack/acceptance/buildpacks" - "github.com/buildpacks/pack/acceptance/config" - "github.com/buildpacks/pack/acceptance/invoke" - "github.com/buildpacks/pack/acceptance/managers" + "github.com/buildpacks/pack/acceptance/harness" h "github.com/buildpacks/pack/testhelpers" - "github.com/docker/docker/client" ) func TestBuild(t *testing.T) { - h.RequireDocker(t) - rand.Seed(time.Now().UTC().UnixNano()) - assert := h.NewAssertionManager(t) - - // docker cli - dockerCli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) - assert.Nil(err) - - imageManager := managers.NewImageManager(t, dockerCli) - - // run temp registry - registryConfig := h.RunRegistry(t) - defer registryConfig.RmRegistry(t) - - // image assert - assertImage := assertions.NewImageAssertionManager(t, imageManager, registryConfig) - - // gather config - inputConfigManager, err := config.NewInputConfigurationManager() - assert.Nil(err) - - assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, filepath.Join("..", "testdata")) - - // create stack - runImageName := "pack-test/run" - buildImageName := "pack-test/build" - - runImageMirror := registryConfig.RepoName(runImageName) - err = createStack(t, dockerCli, registryConfig, imageManager, runImageName, buildImageName, runImageMirror) - assert.Nil(err) - - stackBaseImages := map[string][]string{ - "linux": {"ubuntu:bionic"}, - "windows": {"mcr.microsoft.com/windows/nanoserver:1809", "golang:1.17-nanoserver-1809"}, - } - baseStackNames := stackBaseImages[imageManager.HostOS()] - defer imageManager.CleanupImages(baseStackNames...) - defer imageManager.CleanupImages(runImageName, buildImageName, runImageMirror) - - for _, combo := range inputConfigManager.Combinations() { - combo := combo - - t.Logf("Running combo: %s", combo) - - lifecycle := assetsConfig.NewLifecycleAsset(combo.Lifecycle) - - pack := invoke.NewPackInvoker(t, assert, assetsConfig.NewPackAsset(combo.Pack), registryConfig.DockerConfigDir) - pack.EnableExperimental() - pack.JustRunSuccessfully("config", "lifecycle-image", lifecycle.Image()) + testHarness := harness.ContainingBuilder(t, filepath.Join("..", "testdata")) - createBuilderPack := invoke.NewPackInvoker(t, assert, assetsConfig.NewPackAsset(combo.PackCreateBuilder), registryConfig.DockerConfigDir) - createBuilderPack.EnableExperimental() + registry := testHarness.Registry() + imageManager := testHarness.ImageManager() + runImageName := testHarness.RunImageName() + runImageMirror := testHarness.RunImageMirror() - buildpackManager := buildpacks.NewBuildpackManager( - t, - assert, - buildpacks.WithBuildpackAPIVersion(lifecycle.EarliestBuildpackAPIVersion()), - buildpacks.WithBaseDir(filepath.Join("..", "testdata", "mock_buildpacks")), - ) + assert := h.NewAssertionManager(t) + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - repo := "some-org/" + h.RandString(10) - repoName := registryConfig.RepoName(repo) + for _, combo := range testHarness.Combinations() { + t.Logf("Running combo: %s", combo.String()) - // create builder - builderName, err := createBuilder(t, assert, registryConfig, imageManager, dockerCli, createBuilderPack, lifecycle, buildpackManager, runImageMirror) - assert.Nil(err) - defer imageManager.CleanupImages(builderName) + builderName := combo.BuilderName() + pack := combo.Pack() t.Run("creates a runnable, rebuildable image on daemon from app dir", func(t *testing.T) { appPath := filepath.Join("..", "testdata", "mock_app") + repo := "some-org/" + h.RandString(10) + repoName := registry.RepoName(repo) + output := pack.RunSuccessfully( "build", repoName, "-B", builderName, @@ -121,7 +66,7 @@ func TestBuild(t *testing.T) { assertImage.NotExistsInRegistry(repo) t.Log("add a local mirror") - localRunImageMirror := registryConfig.RepoName("pack-test/run-mirror") + localRunImageMirror := registry.RepoName("pack-test/run-mirror") imageManager.TagImage(runImageName, localRunImageMirror) defer imageManager.CleanupImages(localRunImageMirror) pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) @@ -181,7 +126,6 @@ func TestBuild(t *testing.T) { helloArgs = []string{"/c", "echo hello world"} helloArgsPrefix = " " imageWorkdir = "c:\\workspace" - } else { webCommand = "./run" helloCommand = "echo" @@ -232,15 +176,11 @@ func TestBuild(t *testing.T) { }) } - // suiteManager.CleanUp() - // imageManager.CleanupImages(repoName) - - // ref, err := name.ParseReference(repoName, name.WeakValidation) - // assert.Nil(err) - // cacheImage := cache.NewImageCache(ref, dockerCli) - // buildCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "build", dockerCli) - // launchCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "launch", dockerCli) - // cacheImage.Clear(context.TODO()) - // buildCacheVolume.Clear(context.TODO()) - // launchCacheVolume.Clear(context.TODO()) + testHarness.CleanUp() +} + +type compareFormat struct { + extension string + compareFunc func(string, string) + outputArg string } diff --git a/acceptance/v2/v2.go b/acceptance/v2/v2.go deleted file mode 100644 index 624727494..000000000 --- a/acceptance/v2/v2.go +++ /dev/null @@ -1,354 +0,0 @@ -//go:build acceptance -// +build acceptance - -package acceptance_new - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - - dockertypes "github.com/docker/docker/api/types" - "github.com/docker/docker/client" - - "github.com/buildpacks/pack/acceptance/buildpacks" - "github.com/buildpacks/pack/acceptance/config" - "github.com/buildpacks/pack/acceptance/invoke" - "github.com/buildpacks/pack/acceptance/managers" - "github.com/buildpacks/pack/pkg/archive" - h "github.com/buildpacks/pack/testhelpers" -) - -func buildpacksDir(bpAPIVersion string) string { - return filepath.Join("testdata", "mock_buildpacks", bpAPIVersion) -} - -func createComplexBuilder(t *testing.T, - assert h.AssertionManager, - registryConfig *h.TestRegistryConfig, - imageManager *managers.ImageManager, - dockerCli *client.Client, - pack *invoke.PackInvoker, - lifecycle config.LifecycleAsset, - buildpackManager buildpacks.BuildpackManager, - runImageMirror string, -) (string, error) { - - t.Log("creating complex builder image...") - - // CREATE TEMP WORKING DIR - tmpDir, err := ioutil.TempDir("", "create-complex-test-builder") - if err != nil { - return "", err - } - defer os.RemoveAll(tmpDir) - - // ARCHIVE BUILDPACKS - builderBuildpacks := []buildpacks.TestBuildpack{ - buildpacks.Noop, - buildpacks.Noop2, - buildpacks.OtherStack, - buildpacks.ReadEnv, - } - - templateMapping := map[string]interface{}{ - "run_image_mirror": runImageMirror, - } - - packageImageName := registryConfig.RepoName("nested-level-1-buildpack-" + h.RandString(8)) - nestedLevelTwoBuildpackName := registryConfig.RepoName("nested-level-2-buildpack-" + h.RandString(8)) - simpleLayersBuildpackName := registryConfig.RepoName("simple-layers-buildpack-" + h.RandString(8)) - simpleLayersBuildpackDifferentShaName := registryConfig.RepoName("simple-layers-buildpack-different-name-" + h.RandString(8)) - - templateMapping["package_id"] = "simple/nested-level-1" - templateMapping["package_image_name"] = packageImageName - templateMapping["nested_level_1_buildpack"] = packageImageName - templateMapping["nested_level_2_buildpack"] = nestedLevelTwoBuildpackName - templateMapping["simple_layers_buildpack"] = simpleLayersBuildpackName - templateMapping["simple_layers_buildpack_different_sha"] = simpleLayersBuildpackDifferentShaName - - fixtureManager := pack.FixtureManager() - - nestedLevelOneConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-1-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( - "nested-level-1-buildpack_package.toml", - nestedLevelOneConfigFile, - templateMapping, - ) - err = nestedLevelOneConfigFile.Close() - assert.Nil(err) - - nestedLevelTwoConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-2-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( - "nested-level-2-buildpack_package.toml", - nestedLevelTwoConfigFile, - templateMapping, - ) - - err = nestedLevelTwoConfigFile.Close() - assert.Nil(err) - - packageImageBuildpack := buildpacks.NewPackageImage( - t, - pack, - packageImageName, - nestedLevelOneConfigFile.Name(), - buildpacks.WithRequiredBuildpacks( - buildpacks.NestedLevelOne, - buildpacks.NewPackageImage( - t, - pack, - nestedLevelTwoBuildpackName, - nestedLevelTwoConfigFile.Name(), - buildpacks.WithRequiredBuildpacks( - buildpacks.NestedLevelTwo, - buildpacks.NewPackageImage( - t, - pack, - simpleLayersBuildpackName, - fixtureManager.FixtureLocation("simple-layers-buildpack_package.toml"), - buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), - ), - ), - ), - ), - ) - - simpleLayersDifferentShaBuildpack := buildpacks.NewPackageImage( - t, - pack, - simpleLayersBuildpackDifferentShaName, - fixtureManager.FixtureLocation("simple-layers-buildpack-different-sha_package.toml"), - buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayersDifferentSha), - ) - - defer imageManager.CleanupImages(packageImageName, nestedLevelTwoBuildpackName, simpleLayersBuildpackName, simpleLayersBuildpackDifferentShaName) - - builderBuildpacks = append( - builderBuildpacks, - packageImageBuildpack, - simpleLayersDifferentShaBuildpack, - ) - - buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) - - // ADD lifecycle - if lifecycle.HasLocation() { - lifecycleURI := lifecycle.EscapedPath() - t.Logf("adding lifecycle path '%s' to builder config", lifecycleURI) - templateMapping["lifecycle_uri"] = lifecycleURI - } else { - lifecycleVersion := lifecycle.Version() - t.Logf("adding lifecycle version '%s' to builder config", lifecycleVersion) - templateMapping["lifecycle_version"] = lifecycleVersion - } - - // RENDER builder.toml - builderConfigFile, err := ioutil.TempFile(tmpDir, "nested_builder.toml") - if err != nil { - return "", err - } - - pack.FixtureManager().TemplateFixtureToFile("nested_builder.toml", builderConfigFile, templateMapping) - - err = builderConfigFile.Close() - if err != nil { - return "", err - } - - // NAME BUILDER - bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) - - // CREATE BUILDER - output := pack.RunSuccessfully( - "builder", "create", bldr, - "-c", builderConfigFile.Name(), - "--no-color", - ) - - assert.Contains(output, fmt.Sprintf("Successfully created builder image '%s'", bldr)) - assert.Succeeds(h.PushImage(dockerCli, bldr, registryConfig)) - - return bldr, nil -} - -func createBuilder( - t *testing.T, - assert h.AssertionManager, - registryConfig *h.TestRegistryConfig, - imageManager managers.ImageManager, - dockerCli client.CommonAPIClient, - pack *invoke.PackInvoker, - lifecycle config.LifecycleAsset, - buildpackManager buildpacks.BuildpackManager, - runImageMirror string, -) (string, error) { - t.Log("creating builder image...") - - // CREATE TEMP WORKING DIR - tmpDir, err := ioutil.TempDir("", "create-test-builder") - assert.Nil(err) - defer os.RemoveAll(tmpDir) - - templateMapping := map[string]interface{}{ - "run_image_mirror": runImageMirror, - } - - // ARCHIVE BUILDPACKS - builderBuildpacks := []buildpacks.TestBuildpack{ - buildpacks.Noop, - buildpacks.Noop2, - buildpacks.OtherStack, - buildpacks.ReadEnv, - } - - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package.toml", imageManager.HostOS()) - packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) - - packageImageBuildpack := buildpacks.NewPackageImage( - t, - pack, - packageImageName, - packageTomlPath, - buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), - ) - - defer imageManager.CleanupImages(packageImageName) - - builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) - - templateMapping["package_image_name"] = packageImageName - templateMapping["package_id"] = "simple/layers" - - buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) - - // ADD lifecycle - var lifecycleURI string - var lifecycleVersion string - if lifecycle.HasLocation() { - lifecycleURI = lifecycle.EscapedPath() - t.Logf("adding lifecycle path '%s' to builder config", lifecycleURI) - templateMapping["lifecycle_uri"] = lifecycleURI - } else { - lifecycleVersion = lifecycle.Version() - t.Logf("adding lifecycle version '%s' to builder config", lifecycleVersion) - templateMapping["lifecycle_version"] = lifecycleVersion - } - - // RENDER builder.toml - configFileName := "builder.toml" - - builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( - configFileName, - builderConfigFile, - templateMapping, - ) - - err = builderConfigFile.Close() - assert.Nil(err) - - // NAME BUILDER - bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) - - // CREATE BUILDER - output := pack.RunSuccessfully( - "builder", "create", bldr, - "-c", builderConfigFile.Name(), - "--no-color", - ) - - assert.Contains(output, fmt.Sprintf("Successfully created builder image '%s'", bldr)) - assert.Succeeds(h.PushImage(dockerCli, bldr, registryConfig)) - - return bldr, nil -} - -func generatePackageTomlWithOS( - t *testing.T, - assert h.AssertionManager, - pack *invoke.PackInvoker, - tmpDir string, - fixtureName string, - platform_os string, -) string { - t.Helper() - - packageTomlFile, err := ioutil.TempFile(tmpDir, "package-*.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( - fixtureName, - packageTomlFile, - map[string]interface{}{ - "OS": platform_os, - }, - ) - - assert.Nil(packageTomlFile.Close()) - - return packageTomlFile.Name() -} - -func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror string) error { - t.Helper() - t.Log("creating stack images...") - - stackBaseDir := filepath.Join("..", "testdata", "mock_stack", imageManager.HostOS()) - - _, err := os.Stat(stackBaseDir) - if err != nil { - return err - } - - if err := createStackImage(dockerCli, runImageName, filepath.Join(stackBaseDir, "run")); err != nil { - return err - } - if err := createStackImage(dockerCli, buildImageName, filepath.Join(stackBaseDir, "build")); err != nil { - return err - } - - imageManager.TagImage(runImageName, runImageMirror) - if err := h.PushImage(dockerCli, runImageMirror, registryConfig); err != nil { - return err - } - - return nil -} - -func createStackImage(dockerCli client.CommonAPIClient, repoName string, dir string) error { - defaultFilterFunc := func(file string) bool { return true } - - ctx := context.Background() - buildContext := archive.ReadDirAsTar(dir, "/", 0, 0, -1, true, false, defaultFilterFunc) - - return h.CheckImageBuildResult(dockerCli.ImageBuild(ctx, buildContext, dockertypes.ImageBuildOptions{ - Tags: []string{repoName}, - Remove: true, - ForceRemove: true, - })) -} - -// taskKey creates a key from the prefix and all arguments to be unique -func taskKey(prefix string, args ...string) string { - hash := sha256.New() - for _, v := range args { - hash.Write([]byte(v)) - } - return fmt.Sprintf("%s-%s", prefix, hex.EncodeToString(hash.Sum(nil))) -} - -type compareFormat struct { - extension string - compareFunc func(string, string) - outputArg string -} From 089d4fed85f9831d3ea526a5daaae91856b1cb83 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Thu, 11 Aug 2022 13:06:03 -0500 Subject: [PATCH 03/15] Further simplify usage of test harness, migrate more build tests Signed-off-by: Javier Romero --- acceptance/acceptance_test.go | 88 --------------------------- acceptance/harness/builder_harness.go | 27 +++++++- acceptance/v2/build_test.go | 83 ++++++++++++++++++++----- 3 files changed, 94 insertions(+), 104 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index cbbb590f1..d093dfda3 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -786,94 +786,6 @@ func testAcceptance( launchCacheVolume.Clear(context.TODO()) }) - when("builder is untrusted", func() { - var untrustedBuilderName string - it.Before(func() { - var err error - untrustedBuilderName, err = createBuilder( - t, - assert, - imageManager, - dockerCli, - createBuilderPack, - lifecycle, - buildpackManager, - runImageMirror, - ) - assert.Nil(err) - - suiteManager.RegisterCleanUp("remove-lifecycle-"+lifecycle.Image(), func() error { - img := imageManager.GetImageID(lifecycle.Image()) - imageManager.CleanupImages(img) - return nil - }) - }) - - it.After(func() { - imageManager.CleanupImages(untrustedBuilderName) - }) - - when("daemon", func() { - it("uses the 5 phases", func() { - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "-B", untrustedBuilderName, - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - - assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) - assertOutput.IncludesSeparatePhases() - }) - }) - - when("--publish", func() { - it("uses the 5 phases", func() { - buildArgs := []string{ - repoName, - "-p", filepath.Join("testdata", "mock_app"), - "-B", untrustedBuilderName, - "--publish", - } - if imageManager.HostOS() != "windows" { - buildArgs = append(buildArgs, "--network", "host") - } - - output := pack.RunSuccessfully("build", buildArgs...) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - - assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) - assertOutput.IncludesSeparatePhases() - }) - }) - - when("additional tags", func() { - var additionalRepoName string - - it.Before(func() { - additionalRepoName = fmt.Sprintf("%s_additional", repoName) - }) - it.After(func() { - imageManager.CleanupImages(additionalRepoName) - }) - it("pushes image to additional tags", func() { - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "-B", untrustedBuilderName, - "--tag", additionalRepoName, - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - assert.Contains(output, additionalRepoName) - }) - }) - }) - when("default builder is set", func() { it.Before(func() { pack.RunSuccessfully("config", "default-builder", builderName) diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index 3353bc3b0..c98b05935 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -10,12 +10,13 @@ import ( "testing" "time" + "github.com/docker/docker/client" + "github.com/buildpacks/pack/acceptance/buildpacks" "github.com/buildpacks/pack/acceptance/config" "github.com/buildpacks/pack/acceptance/invoke" "github.com/buildpacks/pack/acceptance/managers" h "github.com/buildpacks/pack/testhelpers" - "github.com/docker/docker/client" ) type BuilderCombo struct { @@ -68,6 +69,7 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { // run temp registry registry := h.RunRegistry(t) cleanups = append(cleanups, func() { + t.Log("stoping and deleting registry...") registry.RmRegistry(t) }) @@ -91,6 +93,7 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { } baseStackNames := stackBaseImages[imageManager.HostOS()] cleanups = append(cleanups, func() { + t.Log("cleaning up stack images...") imageManager.CleanupImages(baseStackNames...) imageManager.CleanupImages(runImageName, buildImageName, runImageMirror) }) @@ -136,6 +139,7 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { ) assert.Nil(err) cleanups = append(cleanups, func() { + t.Log("cleaning up builder image...") imageManager.CleanupImages(builderName) }) @@ -162,6 +166,27 @@ func (b *BuilderTestHarness) Combinations() []BuilderCombo { return b.combos } +func (b *BuilderTestHarness) RunA(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { + for _, combo := range b.combos { + combo := combo + b.t.Run(name, func(t *testing.T) { + test(t, b, combo) + }) + } +} + +func (b *BuilderTestHarness) RunT(name string, test func(t *testing.T, combo BuilderCombo)) { + b.RunA(name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + test(t, combo) + }) +} + +func (b *BuilderTestHarness) Run(name string, test func(combo BuilderCombo)) { + b.RunA(name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + test(combo) + }) +} + func (b *BuilderTestHarness) Registry() h.TestRegistryConfig { return b.registryConfig } diff --git a/acceptance/v2/build_test.go b/acceptance/v2/build_test.go index d31d47148..9cc238804 100644 --- a/acceptance/v2/build_test.go +++ b/acceptance/v2/build_test.go @@ -15,24 +15,23 @@ import ( ) func TestBuild(t *testing.T) { - testHarness := harness.ContainingBuilder(t, filepath.Join("..", "testdata")) + defer testHarness.CleanUp() - registry := testHarness.Registry() - imageManager := testHarness.ImageManager() - runImageName := testHarness.RunImageName() - runImageMirror := testHarness.RunImageMirror() - - assert := h.NewAssertionManager(t) - assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + testHarness.Run( + "creates a runnable, rebuildable, inspectable image", + func(combo harness.BuilderCombo) { + registry := testHarness.Registry() + imageManager := testHarness.ImageManager() + runImageName := testHarness.RunImageName() + runImageMirror := testHarness.RunImageMirror() - for _, combo := range testHarness.Combinations() { - t.Logf("Running combo: %s", combo.String()) + assert := h.NewAssertionManager(t) + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - builderName := combo.BuilderName() - pack := combo.Pack() + builderName := combo.BuilderName() + pack := combo.Pack() - t.Run("creates a runnable, rebuildable image on daemon from app dir", func(t *testing.T) { appPath := filepath.Join("..", "testdata", "mock_app") repo := "some-org/" + h.RandString(10) @@ -70,6 +69,7 @@ func TestBuild(t *testing.T) { imageManager.TagImage(runImageName, localRunImageMirror) defer imageManager.CleanupImages(localRunImageMirror) pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) t.Log("rebuild") output = pack.RunSuccessfully( @@ -174,9 +174,62 @@ func TestBuild(t *testing.T) { format.compareFunc(output, expectedOutput) } }) - } - testHarness.CleanUp() + testHarness.Run( + "an untrusted builder executes 5 phases (daemon)", + func(combo harness.BuilderCombo) { + builderName := combo.BuilderName() + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + registry := testHarness.Registry() + repoName := registry.RepoName("sample/" + h.RandString(3)) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "testdata", "mock_app"), + "-B", builderName, + ) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + + assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesSeparatePhases() + }, + ) + + testHarness.Run( + "an untrusted builder executes 5 phases (registry)", + func(combo harness.BuilderCombo) { + builderName := combo.BuilderName() + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + imageManager := testHarness.ImageManager() + registry := testHarness.Registry() + repoName := registry.RepoName("sample/" + h.RandString(3)) + + buildArgs := []string{ + repoName, + "-p", filepath.Join("..", "testdata", "mock_app"), + "-B", builderName, + "--publish", + } + + if imageManager.HostOS() != "windows" { + buildArgs = append(buildArgs, "--network", "host") + } + + output := pack.RunSuccessfully("build", buildArgs...) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + + assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesSeparatePhases() + }, + ) } type compareFormat struct { From 2ec73762c5252594aec0b5c34402af2c9b06f8c5 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Wed, 17 Aug 2022 14:49:06 -0500 Subject: [PATCH 04/15] Reorganize new acceptance suite package, migrate more build tests Signed-off-by: Javier Romero --- acceptance/acceptance_test.go | 88 --------- acceptance/config/asset_manager.go | 23 +-- acceptance/harness/builder_harness.go | 52 +++-- acceptance/harness/harness.go | 4 +- acceptance/tests/build/build_test.go | 184 +++++++++++++++++ acceptance/tests/build/color_test.go | 27 +++ acceptance/tests/build/env_vars_test.go | 87 +++++++++ acceptance/tests/build/init_test.go | 24 +++ acceptance/tests/build/untrusted_test.go | 59 ++++++ acceptance/v2/build_test.go | 239 ----------------------- testhelpers/registry.go | 2 +- 11 files changed, 426 insertions(+), 363 deletions(-) create mode 100644 acceptance/tests/build/build_test.go create mode 100644 acceptance/tests/build/color_test.go create mode 100644 acceptance/tests/build/env_vars_test.go create mode 100644 acceptance/tests/build/init_test.go create mode 100644 acceptance/tests/build/untrusted_test.go delete mode 100644 acceptance/v2/build_test.go diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index d093dfda3..8f7188953 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -787,22 +787,6 @@ func testAcceptance( }) when("default builder is set", func() { - it.Before(func() { - pack.RunSuccessfully("config", "default-builder", builderName) - pack.JustRunSuccessfully("config", "trusted-builders", "add", builderName) - }) - - when("--no-color", func() { - it("doesn't have color", func() { - appPath := filepath.Join("testdata", "mock_app") - - // --no-color is set as a default option in our tests, and doesn't need to be explicitly provided - output := pack.RunSuccessfully("build", repoName, "-p", appPath) - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.WithoutColors() - }) - }) when("--quiet", func() { it("only logs app name and sha", func() { @@ -817,12 +801,6 @@ func testAcceptance( }) }) - it("supports building app from a zip file", func() { - appPath := filepath.Join("testdata", "mock_app.zip") - output := pack.RunSuccessfully("build", repoName, "-p", appPath) - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - }) - when("--network", func() { var tmpDir string @@ -1209,72 +1187,6 @@ func testAcceptance( }) }) - when("--env-file", func() { - var envPath string - - it.Before(func() { - envfile, err := ioutil.TempFile("", "envfile") - assert.Nil(err) - defer envfile.Close() - - err = os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment") - assert.Nil(err) - envfile.WriteString(` - DETECT_ENV_BUILDPACK=true - ENV1_CONTENTS=Env1 Layer Contents From File - ENV2_CONTENTS - `) - envPath = envfile.Name() - }) - - it.After(func() { - assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) - assert.Succeeds(os.RemoveAll(envPath)) - }) - - it("provides the env vars to the build and detect steps", func() { - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--env-file", envPath, - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - assertImage.RunsWithOutput( - repoName, - "Env2 Layer Contents From Environment", - "Env1 Layer Contents From File", - ) - }) - }) - - when("--env", func() { - it.Before(func() { - assert.Succeeds(os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment")) - }) - - it.After(func() { - assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) - }) - - it("provides the env vars to the build and detect steps", func() { - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--env", "DETECT_ENV_BUILDPACK=true", - "--env", `ENV1_CONTENTS="Env1 Layer Contents From Command Line"`, - "--env", "ENV2_CONTENTS", - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - assertImage.RunsWithOutput( - repoName, - "Env2 Layer Contents From Environment", - "Env1 Layer Contents From Command Line", - ) - }) - }) - when("--run-image", func() { var runImageName string diff --git a/acceptance/config/asset_manager.go b/acceptance/config/asset_manager.go index 62ada8bb3..af6e802f9 100644 --- a/acceptance/config/asset_manager.go +++ b/acceptance/config/asset_manager.go @@ -6,7 +6,6 @@ package config import ( "fmt" "io/ioutil" - "os" "os/exec" "path/filepath" "regexp" @@ -44,7 +43,7 @@ type AssetManager struct { defaultLifecycleDescriptor builder.LifecycleDescriptor } -func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputConfigurationManager, testDataDir string) AssetManager { +func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputConfigurationManager, projectBaseDir string) AssetManager { t.Helper() var ( @@ -65,6 +64,7 @@ func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputC assetBuilder := assetManagerBuilder{ testObject: t, + projectBaseDir: projectBaseDir, assert: assert, inputConfig: inputConfig, githubAssetFetcher: githubAssetFetcher, @@ -77,7 +77,7 @@ func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputC if inputConfig.combinations.requiresPreviousPack() { convergedPreviousPackPath = assetBuilder.ensurePreviousPack() convergedPreviousPackFixturesPaths = []string{ - filepath.Join(testDataDir, "pack_previous_fixtures_overrides"), + filepath.Join(projectBaseDir, "acceptance", "testdata", "pack_previous_fixtures_overrides"), assetBuilder.ensurePreviousPackFixtures(), } } @@ -95,8 +95,9 @@ func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputC } return AssetManager{ + testObject: t, packPath: convergedCurrentPackPath, - packFixturesPath: filepath.Join(testDataDir, "pack_fixtures"), + packFixturesPath: filepath.Join(projectBaseDir, "acceptance", "testdata", "pack_fixtures"), previousPackPath: convergedPreviousPackPath, previousPackFixturesPaths: convergedPreviousPackFixturesPaths, lifecyclePath: convergedCurrentLifecyclePath, @@ -106,7 +107,6 @@ func NewAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputC previousLifecycleImage: convergedPreviousLifecycleImage, previousLifecycleDescriptor: convergedPreviousLifecycleDescriptor, defaultLifecycleDescriptor: convergedDefaultLifecycleDescriptor, - testObject: t, } } @@ -177,6 +177,7 @@ func (a AssetManager) LifecycleImage(kind ComboValue) string { type assetManagerBuilder struct { testObject *testing.T + projectBaseDir string assert h.AssertionManager inputConfig InputConfigurationManager githubAssetFetcher *GithubAssetFetcher @@ -350,23 +351,13 @@ func (b assetManagerBuilder) buildPack(compileVersion string) string { packPath := filepath.Join(packTmpDir, acceptanceOS.PackBinaryName) - cwd, err := os.Getwd() - b.assert.Nil(err) - cmd := exec.Command("go", "build", "-ldflags", fmt.Sprintf("-X 'github.com/buildpacks/pack/cmd.Version=%s'", compileVersion), "-o", packPath, "./cmd/pack", ) - cmd.Dir = cwd - if filepath.Base(cmd.Dir) == "v2" { - cmd.Dir = filepath.Dir(cmd.Dir) - } - - if filepath.Base(cmd.Dir) == "acceptance" { - cmd.Dir = filepath.Dir(cmd.Dir) - } + cmd.Dir = b.projectBaseDir b.testObject.Logf("building pack: [CWD=%s] %s", cmd.Dir, cmd.Args) output, err := cmd.CombinedOutput() diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index c98b05935..3f94f58ed 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -7,6 +7,8 @@ import ( "fmt" "math/rand" "path/filepath" + "reflect" + "runtime" "testing" "time" @@ -52,14 +54,20 @@ type BuilderTestHarness struct { cleanups []func() } -func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { +func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { + t.Helper() h.RequireDocker(t) rand.Seed(time.Now().UTC().UnixNano()) + var err error cleanups := []func(){} - assert := h.NewAssertionManager(t) + projectBaseDir, err = filepath.Abs(projectBaseDir) + assert.Nil(err) + + testDataDir := filepath.Join(projectBaseDir, "acceptance", "testdata") + // docker cli dockerCli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) assert.Nil(err) @@ -77,14 +85,14 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { inputConfigManager, err := config.NewInputConfigurationManager() assert.Nil(err) - assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, testDataDir) + assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, projectBaseDir) // create stack runImageName := "pack-test/run" buildImageName := "pack-test/build" runImageMirror := registry.RepoName(runImageName) - err = createStack(t, dockerCli, registry, imageManager, runImageName, buildImageName, runImageMirror) + err = createStack(t, dockerCli, registry, imageManager, runImageName, buildImageName, runImageMirror, testDataDir) assert.Nil(err) stackBaseImages := map[string][]string{ @@ -107,6 +115,7 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { assetsConfig.NewPackAsset(combo.Pack), registry.DockerConfigDir, ) + pack.JustRunSuccessfully("config", "lifecycle-image", lifecycle.Image()) pack.EnableExperimental() @@ -143,6 +152,8 @@ func ContainingBuilder(t *testing.T, testDataDir string) BuilderTestHarness { imageManager.CleanupImages(builderName) }) + pack.JustRunSuccessfully("config", "default-builder", builderName) + combos = append(combos, BuilderCombo{ builderName: builderName, lifecycle: lifecycle, @@ -166,25 +177,32 @@ func (b *BuilderTestHarness) Combinations() []BuilderCombo { return b.combos } -func (b *BuilderTestHarness) RunA(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { - for _, combo := range b.combos { - combo := combo - b.t.Run(name, func(t *testing.T) { - test(t, b, combo) - }) - } +func (b *BuilderTestHarness) Run(test func(combo BuilderCombo)) { + func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() + b.run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + test(combo) + }) } -func (b *BuilderTestHarness) RunT(name string, test func(t *testing.T, combo BuilderCombo)) { - b.RunA(name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { +func (b *BuilderTestHarness) RunT(test func(t *testing.T, combo BuilderCombo)) { + func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() + b.run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { test(t, combo) }) } -func (b *BuilderTestHarness) Run(name string, test func(combo BuilderCombo)) { - b.RunA(name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { - test(combo) - }) +func (b *BuilderTestHarness) RunA(test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { + func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() + b.run(func_name, test) +} + +func (b *BuilderTestHarness) run(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { + for _, combo := range b.combos { + combo := combo + b.t.Run(name, func(t *testing.T) { + test(t, b, combo) + }) + } } func (b *BuilderTestHarness) Registry() h.TestRegistryConfig { diff --git a/acceptance/harness/harness.go b/acceptance/harness/harness.go index 5472b71ac..df4830334 100644 --- a/acceptance/harness/harness.go +++ b/acceptance/harness/harness.go @@ -142,11 +142,11 @@ func generatePackageTomlWithOS( return packageTomlFile.Name() } -func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror string) error { +func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror, testDataDir string) error { t.Helper() t.Log("creating stack images...") - stackBaseDir := filepath.Join("..", "testdata", "mock_stack", imageManager.HostOS()) + stackBaseDir := filepath.Join(testDataDir, "mock_stack", imageManager.HostOS()) _, err := os.Stat(stackBaseDir) if err != nil { diff --git a/acceptance/tests/build/build_test.go b/acceptance/tests/build/build_test.go new file mode 100644 index 000000000..71ab9219b --- /dev/null +++ b/acceptance/tests/build/build_test.go @@ -0,0 +1,184 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_runnable_rebuildable_inspectable(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + registry := th.Registry() + imageManager := th.ImageManager() + runImageName := th.RunImageName() + runImageMirror := th.RunImageMirror() + + assert := h.NewAssertionManager(t) + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + + repo := "some-org/" + h.RandString(10) + repoName := registry.RepoName(repo) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsUsingBuildCacheVolume() + assertOutput.ReportsSelectingRunImageMirror(runImageMirror) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("it uses the run image as a base image") + assertImage.HasBaseImage(repoName, runImageName) + + t.Log("sets the run image metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImageName, runImageMirror)) + + t.Log("sets the source metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) + + t.Log("registry is empty") + assertImage.NotExistsInRegistry(repo) + + t.Log("add a local mirror") + localRunImageMirror := registry.RepoName("pack-test/run-mirror") + imageManager.TagImage(runImageName, localRunImageMirror) + defer imageManager.CleanupImages(localRunImageMirror) + + pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) + + t.Log("rebuild") + output = pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) + cachedLaunchLayer := "simple/layers:cached-launch-layer" + + assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("rebuild with --clear-cache") + output = pack.RunSuccessfully("build", + repoName, + "-p", appPath, + "--clear-cache", + ) + + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) + + t.Log("cacher adds layers") + assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) + + t.Log("inspecting image") + inspectCmd := "inspect" + if !pack.Supports("inspect") { + inspectCmd = "inspect-image" + } + + var ( + webCommand string + helloCommand string + helloArgs []string + helloArgsPrefix string + imageWorkdir string + ) + if imageManager.HostOS() == "windows" { + webCommand = ".\\run" + helloCommand = "cmd" + helloArgs = []string{"/c", "echo hello world"} + helloArgsPrefix = " " + imageWorkdir = "c:\\workspace" + } else { + webCommand = "./run" + helloCommand = "echo" + helloArgs = []string{"hello", "world"} + helloArgsPrefix = "" + imageWorkdir = "/workspace" + } + + formats := []compareFormat{ + { + extension: "json", + compareFunc: assert.EqualJSON, + outputArg: "json", + }, + { + extension: "yaml", + compareFunc: assert.EqualYAML, + outputArg: "yaml", + }, + { + extension: "toml", + compareFunc: assert.EqualTOML, + outputArg: "toml", + }, + } + for _, format := range formats { + t.Logf("inspecting image %s format", format.outputArg) + + output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) + expectedOutput := pack.FixtureManager().TemplateFixture( + fmt.Sprintf("inspect_image_local_output.%s", format.extension), + map[string]interface{}{ + "image_name": repoName, + "base_image_id": h.ImageID(t, runImageMirror), + "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), + "run_image_local_mirror": localRunImageMirror, + "run_image_mirror": runImageMirror, + "web_command": webCommand, + "hello_command": helloCommand, + "hello_args": helloArgs, + "hello_args_prefix": helloArgsPrefix, + "image_workdir": imageWorkdir, + }, + ) + + format.compareFunc(output, expectedOutput) + } +} + +func test_app_zipfile(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + registry := th.Registry() + + pack := combo.Pack() + + repoName := registry.RepoName("sample/" + h.RandString(10)) + appPath := filepath.Join("..", "..", "testdata", "mock_app.zip") + output := pack.RunSuccessfully("build", repoName, "-p", appPath) + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) +} + +type compareFormat struct { + extension string + compareFunc func(string, string) + outputArg string +} diff --git a/acceptance/tests/build/color_test.go b/acceptance/tests/build/color_test.go new file mode 100644 index 000000000..d2335e0a7 --- /dev/null +++ b/acceptance/tests/build/color_test.go @@ -0,0 +1,27 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_no_color(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + pack := combo.Pack() + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + + registry := th.Registry() + repoName := registry.RepoName("sample/" + h.RandString(3)) + + output := pack.RunSuccessfully("build", repoName, "-p", appPath, "--no-color") + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.WithoutColors() +} diff --git a/acceptance/tests/build/env_vars_test.go b/acceptance/tests/build/env_vars_test.go new file mode 100644 index 000000000..455dff8a3 --- /dev/null +++ b/acceptance/tests/build/env_vars_test.go @@ -0,0 +1,87 @@ +package build_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_env_file(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + assert := h.NewAssertionManager(t) + registry := th.Registry() + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + + envfile, err := ioutil.TempFile("", "envfile") + assert.Nil(err) + defer envfile.Close() + + err = os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment") + assert.Nil(err) + + _, err = envfile.WriteString(` +DETECT_ENV_BUILDPACK=true +ENV1_CONTENTS=Env1 Layer Contents From File +ENV2_CONTENTS +`) + assert.Nil(err) + err = envfile.Close() + assert.Nil(err) + + envPath := envfile.Name() + t.Cleanup(func() { + assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) + assert.Succeeds(os.RemoveAll(envPath)) + }) + + repoName := registry.RepoName("some-org/" + h.RandString(10)) + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--env-file", envPath, + ) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + assertImage.RunsWithOutput( + repoName, + "Env2 Layer Contents From Environment", + "Env1 Layer Contents From File", + ) +} + +func test_env_vars(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + assert := h.NewAssertionManager(t) + registry := th.Registry() + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + + assert.Succeeds(os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment")) + t.Cleanup(func() { + assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) + }) + + repoName := registry.RepoName("some-org/" + h.RandString(10)) + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--env", "DETECT_ENV_BUILDPACK=true", + "--env", `ENV1_CONTENTS="Env1 Layer Contents From Command Line"`, + "--env", "ENV2_CONTENTS", + ) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + assertImage.RunsWithOutput( + repoName, + "Env2 Layer Contents From Environment", + "Env1 Layer Contents From Command Line", + ) +} diff --git a/acceptance/tests/build/init_test.go b/acceptance/tests/build/init_test.go new file mode 100644 index 000000000..cabb9c259 --- /dev/null +++ b/acceptance/tests/build/init_test.go @@ -0,0 +1,24 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/harness" +) + +func TestBuild(t *testing.T) { + testHarness := harness.ContainingBuilder(t, filepath.Join("..", "..", "..")) + t.Cleanup(testHarness.CleanUp) + + // testHarness.RunA(test_runnable_rebuildable_inspectable) + // testHarness.RunA(test_untrusted_daemon) + // testHarness.RunA(test_untrusted_registry) + // testHarness.RunA(test_no_color) + // testHarness.RunA(test_app_zipfile) + // testHarness.RunA(test_env_file) + testHarness.RunA(test_env_vars) +} diff --git a/acceptance/tests/build/untrusted_test.go b/acceptance/tests/build/untrusted_test.go new file mode 100644 index 000000000..6109f3a70 --- /dev/null +++ b/acceptance/tests/build/untrusted_test.go @@ -0,0 +1,59 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + "github.com/buildpacks/pack/testhelpers" +) + +func test_untrusted_daemon(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + registry := th.Registry() + repoName := registry.RepoName("sample/" + testhelpers.RandString(3)) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + ) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + + assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesSeparatePhases() +} + +func test_untrusted_registry(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + imageManager := th.ImageManager() + registry := th.Registry() + repoName := registry.RepoName("sample/" + testhelpers.RandString(3)) + + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + buildArgs := []string{ + repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--publish", + } + + if imageManager.HostOS() != "windows" { + buildArgs = append(buildArgs, "--network", "host") + } + + output := pack.RunSuccessfully("build", buildArgs...) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + + assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesSeparatePhases() +} diff --git a/acceptance/v2/build_test.go b/acceptance/v2/build_test.go deleted file mode 100644 index 9cc238804..000000000 --- a/acceptance/v2/build_test.go +++ /dev/null @@ -1,239 +0,0 @@ -//go:build acceptance -// +build acceptance - -package acceptance_new - -import ( - "fmt" - "path/filepath" - "regexp" - "testing" - - "github.com/buildpacks/pack/acceptance/assertions" - "github.com/buildpacks/pack/acceptance/harness" - h "github.com/buildpacks/pack/testhelpers" -) - -func TestBuild(t *testing.T) { - testHarness := harness.ContainingBuilder(t, filepath.Join("..", "testdata")) - defer testHarness.CleanUp() - - testHarness.Run( - "creates a runnable, rebuildable, inspectable image", - func(combo harness.BuilderCombo) { - registry := testHarness.Registry() - imageManager := testHarness.ImageManager() - runImageName := testHarness.RunImageName() - runImageMirror := testHarness.RunImageMirror() - - assert := h.NewAssertionManager(t) - assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - - builderName := combo.BuilderName() - pack := combo.Pack() - - appPath := filepath.Join("..", "testdata", "mock_app") - - repo := "some-org/" + h.RandString(10) - repoName := registry.RepoName(repo) - - output := pack.RunSuccessfully( - "build", repoName, - "-B", builderName, - "-p", appPath, - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsUsingBuildCacheVolume() - assertOutput.ReportsSelectingRunImageMirror(runImageMirror) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("it uses the run image as a base image") - assertImage.HasBaseImage(repoName, runImageName) - - t.Log("sets the run image metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImageName, runImageMirror)) - - t.Log("sets the source metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) - - t.Log("registry is empty") - assertImage.NotExistsInRegistry(repo) - - t.Log("add a local mirror") - localRunImageMirror := registry.RepoName("pack-test/run-mirror") - imageManager.TagImage(runImageName, localRunImageMirror) - defer imageManager.CleanupImages(localRunImageMirror) - pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) - defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) - - t.Log("rebuild") - output = pack.RunSuccessfully( - "build", repoName, - "-B", builderName, - "-p", appPath, - ) - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) - cachedLaunchLayer := "simple/layers:cached-launch-layer" - - assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("rebuild with --clear-cache") - output = pack.RunSuccessfully("build", - repoName, - "-B", builderName, - "-p", appPath, - "--clear-cache", - ) - - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) - - t.Log("cacher adds layers") - assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) - - t.Log("inspecting image") - inspectCmd := "inspect" - if !pack.Supports("inspect") { - inspectCmd = "inspect-image" - } - - var ( - webCommand string - helloCommand string - helloArgs []string - helloArgsPrefix string - imageWorkdir string - ) - if imageManager.HostOS() == "windows" { - webCommand = ".\\run" - helloCommand = "cmd" - helloArgs = []string{"/c", "echo hello world"} - helloArgsPrefix = " " - imageWorkdir = "c:\\workspace" - } else { - webCommand = "./run" - helloCommand = "echo" - helloArgs = []string{"hello", "world"} - helloArgsPrefix = "" - imageWorkdir = "/workspace" - } - - formats := []compareFormat{ - { - extension: "json", - compareFunc: assert.EqualJSON, - outputArg: "json", - }, - { - extension: "yaml", - compareFunc: assert.EqualYAML, - outputArg: "yaml", - }, - { - extension: "toml", - compareFunc: assert.EqualTOML, - outputArg: "toml", - }, - } - for _, format := range formats { - t.Logf("inspecting image %s format", format.outputArg) - - output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) - expectedOutput := pack.FixtureManager().TemplateFixture( - fmt.Sprintf("inspect_image_local_output.%s", format.extension), - map[string]interface{}{ - "image_name": repoName, - "base_image_id": h.ImageID(t, runImageMirror), - "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), - "run_image_local_mirror": localRunImageMirror, - "run_image_mirror": runImageMirror, - "web_command": webCommand, - "hello_command": helloCommand, - "hello_args": helloArgs, - "hello_args_prefix": helloArgsPrefix, - "image_workdir": imageWorkdir, - }, - ) - - format.compareFunc(output, expectedOutput) - } - }) - - testHarness.Run( - "an untrusted builder executes 5 phases (daemon)", - func(combo harness.BuilderCombo) { - builderName := combo.BuilderName() - pack := combo.Pack() - lifecycle := combo.Lifecycle() - - registry := testHarness.Registry() - repoName := registry.RepoName("sample/" + h.RandString(3)) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("..", "testdata", "mock_app"), - "-B", builderName, - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - - assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) - assertOutput.IncludesSeparatePhases() - }, - ) - - testHarness.Run( - "an untrusted builder executes 5 phases (registry)", - func(combo harness.BuilderCombo) { - builderName := combo.BuilderName() - pack := combo.Pack() - lifecycle := combo.Lifecycle() - - imageManager := testHarness.ImageManager() - registry := testHarness.Registry() - repoName := registry.RepoName("sample/" + h.RandString(3)) - - buildArgs := []string{ - repoName, - "-p", filepath.Join("..", "testdata", "mock_app"), - "-B", builderName, - "--publish", - } - - if imageManager.HostOS() != "windows" { - buildArgs = append(buildArgs, "--network", "host") - } - - output := pack.RunSuccessfully("build", buildArgs...) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - - assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) - assertOutput.IncludesSeparatePhases() - }, - ) -} - -type compareFormat struct { - extension string - compareFunc func(string, string) - outputArg string -} diff --git a/testhelpers/registry.go b/testhelpers/registry.go index ec3d6af4b..fab29059e 100644 --- a/testhelpers/registry.go +++ b/testhelpers/registry.go @@ -77,8 +77,8 @@ func CreateRegistryFixture(t *testing.T, tmpDir, fixturePath string) string { } func RunRegistry(t *testing.T) *TestRegistryConfig { - t.Log("run registry") t.Helper() + t.Log("run registry") runRegistryName := "test-registry-" + RandString(10) username := RandString(10) From 2c20968d5e2a5c79879fdc46c5f46ab37a2124f5 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Fri, 19 Aug 2022 19:39:18 -0500 Subject: [PATCH 05/15] Acceptance: Fix feature detection in pack Signed-off-by: Javier Romero --- acceptance/invoke/pack.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acceptance/invoke/pack.go b/acceptance/invoke/pack.go index 9b2b8c7da..993f26593 100644 --- a/acceptance/invoke/pack.go +++ b/acceptance/invoke/pack.go @@ -226,11 +226,19 @@ func (i *PackInvoker) Supports(command string) bool { search = command } - re := regexp.MustCompile(fmt.Sprint(`\b%s\b`, search)) output, err := i.baseCmd(cmdParts...).CombinedOutput() i.assert.Nil(err) - return re.MatchString(string(output)) && !strings.Contains(string(output), "Unknown help topic") + pattern := fmt.Sprintf(`\b%s\b`, search) + if search[0:1] == "-" { + // flags cannot match word boundary (`\b`) at the begining + // due to them starting with a dash (`-`) + pattern = fmt.Sprintf(`%s\b`, search) + } + + re := regexp.MustCompile(pattern) + help := string(output) + return re.MatchString(help) && !strings.Contains(help, "Unknown help topic") } type Feature int From 99a1671696605f5515dc8bab9a1d542a2014a616 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Fri, 19 Aug 2022 19:41:25 -0500 Subject: [PATCH 06/15] Migrate additional build acceptance tests Signed-off-by: Javier Romero --- acceptance/acceptance_test.go | 388 ++---------------- .../buildpacks/package_file_buildpack.go | 4 +- .../buildpacks/package_image_buildpack.go | 4 +- acceptance/harness/builder_harness.go | 2 +- acceptance/harness/{harness.go => util.go} | 50 +-- acceptance/invoke/pack_fixtures.go | 8 +- acceptance/tests/build/arg_app_test.go | 24 ++ acceptance/tests/build/arg_buildpack_test.go | 231 +++++++++++ .../tests/build/arg_creation_time_test.go | 64 +++ ...{env_vars_test.go => arg_env_file_test.go} | 32 +- acceptance/tests/build/arg_env_test.go | 41 ++ .../{color_test.go => arg_no_color_test.go} | 2 +- acceptance/tests/build/build_test.go | 185 +-------- acceptance/tests/build/init_test.go | 24 -- acceptance/tests/build/inspectable_test.go | 111 +++++ acceptance/tests/build/rebuild_test.go | 100 +++++ 16 files changed, 656 insertions(+), 614 deletions(-) rename acceptance/harness/{harness.go => util.go} (83%) create mode 100644 acceptance/tests/build/arg_app_test.go create mode 100644 acceptance/tests/build/arg_buildpack_test.go create mode 100644 acceptance/tests/build/arg_creation_time_test.go rename acceptance/tests/build/{env_vars_test.go => arg_env_file_test.go} (55%) create mode 100644 acceptance/tests/build/arg_env_test.go rename acceptance/tests/build/{color_test.go => arg_no_color_test.go} (86%) delete mode 100644 acceptance/tests/build/init_test.go create mode 100644 acceptance/tests/build/inspectable_test.go create mode 100644 acceptance/tests/build/rebuild_test.go diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 8f7188953..425a81e5a 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -188,29 +188,21 @@ func testWithoutSpecificBuilderRequirement( }) generateAggregatePackageToml := func(buildpackURI, nestedPackageName, os string) string { - t.Helper() - packageTomlFile, err := ioutil.TempFile(tmpDir, "package_aggregate-*.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( + return pack.FixtureManager().TemplateFixtureToFile( + tmpDir, "package_aggregate.toml", - packageTomlFile, map[string]interface{}{ "BuildpackURI": buildpackURI, "PackageName": nestedPackageName, "OS": os, }, ) - - assert.Nil(packageTomlFile.Close()) - - return packageTomlFile.Name() } when("no --format is provided", func() { it("creates the package as image", func() { packageName := "test/package-" + h.RandString(10) - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) output := pack.RunSuccessfully("buildpack", "package", packageName, "-c", packageTomlPath) assertions.NewOutputAssertionManager(t, output).ReportsPackageCreation(packageName) @@ -226,19 +218,19 @@ func testWithoutSpecificBuilderRequirement( nestedPackageName := "test/package-" + h.RandString(10) packageName := "test/package-" + h.RandString(10) - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) aggregatePackageToml := generateAggregatePackageToml("simple-layers-parent-buildpack.tgz", nestedPackageName, imageManager.HostOS()) packageBuildpack := buildpacks.NewPackageImage( t, - pack, + *pack, packageName, aggregatePackageToml, buildpacks.WithRequiredBuildpacks( buildpacks.SimpleLayersParent, buildpacks.NewPackageImage( t, - pack, + *pack, nestedPackageName, packageTomlPath, buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), @@ -254,12 +246,12 @@ func testWithoutSpecificBuilderRequirement( when("--publish", func() { it("publishes image to registry", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) nestedPackageName := registryConfig.RepoName("test/package-" + h.RandString(10)) nestedPackage := buildpacks.NewPackageImage( t, - pack, + *pack, nestedPackageName, packageTomlPath, buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), @@ -286,11 +278,11 @@ func testWithoutSpecificBuilderRequirement( when("--pull-policy=never", func() { it("should use local image", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) nestedPackageName := "test/package-" + h.RandString(10) nestedPackage := buildpacks.NewPackageImage( t, - pack, + *pack, nestedPackageName, packageTomlPath, buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), @@ -310,11 +302,11 @@ func testWithoutSpecificBuilderRequirement( }) it("should not pull image from registry", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) nestedPackageName := registryConfig.RepoName("test/package-" + h.RandString(10)) nestedPackage := buildpacks.NewPackageImage( t, - pack, + *pack, nestedPackageName, packageTomlPath, buildpacks.WithPublish(), @@ -340,7 +332,7 @@ func testWithoutSpecificBuilderRequirement( when("--format file", func() { when("the file extension is .cnb", func() { it("creates the package with the same extension", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) destinationFile := filepath.Join(tmpDir, "package.cnb") output := pack.RunSuccessfully( "buildpack", "package", destinationFile, @@ -353,7 +345,7 @@ func testWithoutSpecificBuilderRequirement( }) when("the file extension is empty", func() { it("creates the package with a .cnb extension", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) destinationFile := filepath.Join(tmpDir, "package") expectedFile := filepath.Join(tmpDir, "package.cnb") output := pack.RunSuccessfully( @@ -367,7 +359,7 @@ func testWithoutSpecificBuilderRequirement( }) when("the file extension is not .cnb", func() { it("creates the package with the given extension but shows a warning", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, simplePackageConfigFixtureName, imageManager.HostOS()) destinationFile := filepath.Join(tmpDir, "package.tar.gz") output := pack.RunSuccessfully( "buildpack", "package", destinationFile, @@ -417,11 +409,11 @@ func testWithoutSpecificBuilderRequirement( fmt.Sprintf("buildpack-%s.cnb", h.RandString(8)), ) - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) packageFile := buildpacks.NewPackageFile( t, - pack, + *pack, packageFileLocation, packageTomlPath, buildpacks.WithRequiredBuildpacks( @@ -448,12 +440,12 @@ func testWithoutSpecificBuilderRequirement( when("buildpack image", func() { when("inspect", func() { it("succeeds", func() { - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) packageImageName := registryConfig.RepoName("buildpack-" + h.RandString(8)) packageImage := buildpacks.NewPackageImage( t, - pack, + *pack, packageImageName, packageTomlPath, buildpacks.WithRequiredBuildpacks( @@ -972,221 +964,6 @@ func testAcceptance( }) }) - when("--buildpack", func() { - when("the argument is an ID", func() { - it("adds the buildpacks to the builder if necessary and runs them", func() { - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", "simple/layers", // can omit version if only one - "--buildpack", "noop.buildpack@noop.buildpack.version", - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - - assertTestAppOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) - assertTestAppOutput.ReportsBuildStep("Simple Layers Buildpack") - assertTestAppOutput.ReportsBuildStep("NOOP Buildpack") - assertOutput.ReportsSuccessfulImageBuild(repoName) - - t.Log("app is runnable") - assertImage.RunsWithOutput( - repoName, - "Launch Dep Contents", - "Cached Dep Contents", - ) - }) - }) - - when("the argument is an archive", func() { - var tmpDir string - - it.Before(func() { - var err error - tmpDir, err = ioutil.TempDir("", "archive-buildpack-tests-") - assert.Nil(err) - }) - - it.After(func() { - assert.Succeeds(os.RemoveAll(tmpDir)) - }) - - it("adds the buildpack to the builder and runs it", func() { - buildpackManager.PrepareBuildpacks(tmpDir, buildpacks.ArchiveNotInBuilder) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", buildpacks.ArchiveNotInBuilder.FullPathIn(tmpDir), - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsAddingBuildpack("local/bp", "local-bp-version") - assertOutput.ReportsSuccessfulImageBuild(repoName) - - assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) - assertBuildpackOutput.ReportsBuildStep("Local Buildpack") - }) - }) - - when("the argument is directory", func() { - var tmpDir string - - it.Before(func() { - var err error - tmpDir, err = ioutil.TempDir("", "folder-buildpack-tests-") - assert.Nil(err) - }) - - it.After(func() { - _ = os.RemoveAll(tmpDir) - }) - - it("adds the buildpacks to the builder and runs it", func() { - h.SkipIf(t, runtime.GOOS == "windows", "buildpack directories not supported on windows") - - buildpackManager.PrepareBuildpacks(tmpDir, buildpacks.FolderNotInBuilder) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", buildpacks.FolderNotInBuilder.FullPathIn(tmpDir), - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsAddingBuildpack("local/bp", "local-bp-version") - assertOutput.ReportsSuccessfulImageBuild(repoName) - - assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) - assertBuildpackOutput.ReportsBuildStep("Local Buildpack") - }) - }) - - when("the argument is a buildpackage image", func() { - var ( - tmpDir string - packageImageName string - ) - - it.After(func() { - imageManager.CleanupImages(packageImageName) - _ = os.RemoveAll(tmpDir) - }) - - it("adds the buildpacks to the builder and runs them", func() { - packageImageName = registryConfig.RepoName("buildpack-" + h.RandString(8)) - - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) - packageImage := buildpacks.NewPackageImage( - t, - pack, - packageImageName, - packageTomlPath, - buildpacks.WithRequiredBuildpacks( - buildpacks.FolderSimpleLayersParent, - buildpacks.FolderSimpleLayers, - ), - ) - - buildpackManager.PrepareBuildpacks(tmpDir, packageImage) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", packageImageName, - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsAddingBuildpack( - "simple/layers/parent", - "simple-layers-parent-version", - ) - assertOutput.ReportsAddingBuildpack("simple/layers", "simple-layers-version") - assertOutput.ReportsSuccessfulImageBuild(repoName) - - assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) - assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") - }) - }) - - when("the argument is a buildpackage file", func() { - var tmpDir string - - it.Before(func() { - var err error - tmpDir, err = ioutil.TempDir("", "package-file") - assert.Nil(err) - }) - - it.After(func() { - assert.Succeeds(os.RemoveAll(tmpDir)) - }) - - it("adds the buildpacks to the builder and runs them", func() { - packageFileLocation := filepath.Join( - tmpDir, - fmt.Sprintf("buildpack-%s.cnb", h.RandString(8)), - ) - - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) - packageFile := buildpacks.NewPackageFile( - t, - pack, - packageFileLocation, - packageTomlPath, - buildpacks.WithRequiredBuildpacks( - buildpacks.FolderSimpleLayersParent, - buildpacks.FolderSimpleLayers, - ), - ) - - buildpackManager.PrepareBuildpacks(tmpDir, packageFile) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", packageFileLocation, - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsAddingBuildpack( - "simple/layers/parent", - "simple-layers-parent-version", - ) - assertOutput.ReportsAddingBuildpack("simple/layers", "simple-layers-version") - assertOutput.ReportsSuccessfulImageBuild(repoName) - - assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) - assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") - }) - }) - - when("the buildpack stack doesn't match the builder", func() { - var otherStackBuilderTgz string - - it.Before(func() { - otherStackBuilderTgz = h.CreateTGZ(t, filepath.Join(bpDir, "other-stack-buildpack"), "./", 0755) - }) - - it.After(func() { - assert.Succeeds(os.Remove(otherStackBuilderTgz)) - }) - - it("errors", func() { - output, err := pack.Run( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--buildpack", otherStackBuilderTgz, - ) - - assert.NotNil(err) - assert.Contains(output, "other/stack/bp") - assert.Contains(output, "other-stack-version") - assert.Contains(output, "does not support stack 'pack.test.stack'") - }) - }) - }) - when("--run-image", func() { var runImageName string @@ -1703,50 +1480,6 @@ include = [ "*.jar", "media/mountain.jpg", "/media/person.png", ] }) }) }) - - when("--creation-time", func() { - it.Before(func() { - h.SkipIf(t, !pack.SupportsFeature(invoke.CreationTime), "") - h.SkipIf(t, !lifecycle.SupportsFeature(config.CreationTime), "") - }) - - when("provided as 'now'", func() { - it("image has create time of the current time", func() { - expectedTime := time.Now() - pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--creation-time", "now", - ) - assertImage.HasCreateTime(repoName, expectedTime) - }) - }) - - when("provided as unix timestamp", func() { - it("image has create time of the time that was provided", func() { - pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--creation-time", "1566172801", - ) - expectedTime, err := time.Parse("2006-01-02T03:04:05Z", "2019-08-19T00:00:01Z") - h.AssertNil(t, err) - assertImage.HasCreateTime(repoName, expectedTime) - }) - }) - - when("not provided", func() { - it("image has create time of Jan 1, 1980", func() { - pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - ) - expectedTime, err := time.Parse("2006-01-02T03:04:05Z", "1980-01-01T00:00:01Z") - h.AssertNil(t, err) - assertImage.HasCreateTime(repoName, expectedTime) - }) - }) - }) }) }) @@ -2282,44 +2015,35 @@ func createComplexBuilder(t *testing.T, fixtureManager := pack.FixtureManager() - nestedLevelOneConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-1-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( + nestedLevelOneConfig := fixtureManager.TemplateFixtureToFile( + tmpDir, "nested-level-1-buildpack_package.toml", - nestedLevelOneConfigFile, templateMapping, ) - err = nestedLevelOneConfigFile.Close() - assert.Nil(err) - nestedLevelTwoConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-2-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( + nestedLevelTwoConfig := fixtureManager.TemplateFixtureToFile( + tmpDir, "nested-level-2-buildpack_package.toml", - nestedLevelTwoConfigFile, templateMapping, ) - err = nestedLevelTwoConfigFile.Close() - assert.Nil(err) - packageImageBuildpack := buildpacks.NewPackageImage( t, - pack, + *pack, packageImageName, - nestedLevelOneConfigFile.Name(), + nestedLevelOneConfig, buildpacks.WithRequiredBuildpacks( buildpacks.NestedLevelOne, buildpacks.NewPackageImage( t, - pack, + *pack, nestedLevelTwoBuildpackName, - nestedLevelTwoConfigFile.Name(), + nestedLevelTwoConfig, buildpacks.WithRequiredBuildpacks( buildpacks.NestedLevelTwo, buildpacks.NewPackageImage( t, - pack, + *pack, simpleLayersBuildpackName, fixtureManager.FixtureLocation("simple-layers-buildpack_package.toml"), buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), @@ -2331,7 +2055,7 @@ func createComplexBuilder(t *testing.T, simpleLayersDifferentShaBuildpack := buildpacks.NewPackageImage( t, - pack, + *pack, simpleLayersBuildpackDifferentShaName, fixtureManager.FixtureLocation("simple-layers-buildpack-different-sha_package.toml"), buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayersDifferentSha), @@ -2359,17 +2083,11 @@ func createComplexBuilder(t *testing.T, } // RENDER builder.toml - builderConfigFile, err := ioutil.TempFile(tmpDir, "nested_builder.toml") - if err != nil { - return "", err - } - - pack.FixtureManager().TemplateFixtureToFile("nested_builder.toml", builderConfigFile, templateMapping) - - err = builderConfigFile.Close() - if err != nil { - return "", err - } + builderConfig := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, + "nested_builder.toml", + templateMapping, + ) // NAME BUILDER bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) @@ -2377,7 +2095,7 @@ func createComplexBuilder(t *testing.T, // CREATE BUILDER output := pack.RunSuccessfully( "builder", "create", bldr, - "-c", builderConfigFile.Name(), + "-c", builderConfig, "--no-color", ) @@ -2416,12 +2134,12 @@ func createBuilder( buildpacks.ReadEnv, } - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package.toml", imageManager.HostOS()) + packageTomlPath := generatePackageTomlWithOS(t, pack, tmpDir, "package.toml", imageManager.HostOS()) packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) packageImageBuildpack := buildpacks.NewPackageImage( t, - pack, + *pack, packageImageName, packageTomlPath, buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), @@ -2450,27 +2168,19 @@ func createBuilder( } // RENDER builder.toml - configFileName := "builder.toml" - - builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( - configFileName, - builderConfigFile, + builderConfig := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, + "builder.toml", templateMapping, ) - err = builderConfigFile.Close() - assert.Nil(err) - // NAME BUILDER bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) // CREATE BUILDER output := pack.RunSuccessfully( "builder", "create", bldr, - "-c", builderConfigFile.Name(), + "-c", builderConfig, "--no-color", ) @@ -2482,28 +2192,20 @@ func createBuilder( func generatePackageTomlWithOS( t *testing.T, - assert h.AssertionManager, pack *invoke.PackInvoker, tmpDir string, fixtureName string, - platform_os string, + platformOS string, ) string { t.Helper() - packageTomlFile, err := ioutil.TempFile(tmpDir, "package-*.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( + return pack.FixtureManager().TemplateFixtureToFile( + tmpDir, fixtureName, - packageTomlFile, map[string]interface{}{ - "OS": platform_os, + "OS": platformOS, }, ) - - assert.Nil(packageTomlFile.Close()) - - return packageTomlFile.Name() } func createStack(t *testing.T, dockerCli client.CommonAPIClient, imageManager managers.ImageManager, runImageMirror string) error { diff --git a/acceptance/buildpacks/package_file_buildpack.go b/acceptance/buildpacks/package_file_buildpack.go index ce9d29112..e0e8236bf 100644 --- a/acceptance/buildpacks/package_file_buildpack.go +++ b/acceptance/buildpacks/package_file_buildpack.go @@ -18,7 +18,7 @@ import ( type PackageFile struct { testObject *testing.T - pack *invoke.PackInvoker + pack invoke.PackInvoker destination string sourceConfigLocation string buildpacks []TestBuildpack @@ -32,7 +32,7 @@ func (p *PackageFile) SetPublish() {} func NewPackageFile( t *testing.T, - pack *invoke.PackInvoker, + pack invoke.PackInvoker, destination, configLocation string, modifiers ...PackageModifier, ) PackageFile { diff --git a/acceptance/buildpacks/package_image_buildpack.go b/acceptance/buildpacks/package_image_buildpack.go index a924e9bc6..00c7900b5 100644 --- a/acceptance/buildpacks/package_image_buildpack.go +++ b/acceptance/buildpacks/package_image_buildpack.go @@ -19,7 +19,7 @@ import ( type PackageImage struct { testObject *testing.T - pack *invoke.PackInvoker + pack invoke.PackInvoker name string sourceConfigLocation string buildpacks []TestBuildpack @@ -36,7 +36,7 @@ func (p *PackageImage) SetPublish() { func NewPackageImage( t *testing.T, - pack *invoke.PackInvoker, + pack invoke.PackInvoker, name, configLocation string, modifiers ...PackageModifier, ) PackageImage { diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index 3f94f58ed..8260827f4 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -141,7 +141,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { registry, imageManager, dockerCli, - createBuilderPack, + *createBuilderPack, lifecycle, buildpackManager, runImageMirror, diff --git a/acceptance/harness/harness.go b/acceptance/harness/util.go similarity index 83% rename from acceptance/harness/harness.go rename to acceptance/harness/util.go index df4830334..e81c21578 100644 --- a/acceptance/harness/harness.go +++ b/acceptance/harness/util.go @@ -28,7 +28,7 @@ func createBuilder( registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, dockerCli client.CommonAPIClient, - pack *invoke.PackInvoker, + pack invoke.PackInvoker, lifecycle config.LifecycleAsset, buildpackManager buildpacks.BuildpackManager, runImageMirror string, @@ -52,7 +52,15 @@ func createBuilder( buildpacks.ReadEnv, } - packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package.toml", imageManager.HostOS()) + packageTomlPath := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, + "package.toml", + map[string]interface{}{ + "OS": imageManager.HostOS(), + }, + ) + defer os.RemoveAll(packageTomlPath) + packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) packageImageBuildpack := buildpacks.NewPackageImage( @@ -88,25 +96,19 @@ func createBuilder( // RENDER builder.toml configFileName := "builder.toml" - builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( + builderConfig := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, configFileName, - builderConfigFile, templateMapping, ) - err = builderConfigFile.Close() - assert.Nil(err) - // NAME BUILDER bldr := registryConfig.RepoName("test/builder-" + h.RandString(10)) // CREATE BUILDER output := pack.RunSuccessfully( "builder", "create", bldr, - "-c", builderConfigFile.Name(), + "-c", builderConfig, "--no-color", ) @@ -116,32 +118,6 @@ func createBuilder( return bldr, nil } -func generatePackageTomlWithOS( - t *testing.T, - assert h.AssertionManager, - pack *invoke.PackInvoker, - tmpDir string, - fixtureName string, - platform_os string, -) string { - t.Helper() - - packageTomlFile, err := ioutil.TempFile(tmpDir, "package-*.toml") - assert.Nil(err) - - pack.FixtureManager().TemplateFixtureToFile( - fixtureName, - packageTomlFile, - map[string]interface{}{ - "OS": platform_os, - }, - ) - - assert.Nil(packageTomlFile.Close()) - - return packageTomlFile.Name() -} - func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror, testDataDir string) error { t.Helper() t.Log("creating stack images...") diff --git a/acceptance/invoke/pack_fixtures.go b/acceptance/invoke/pack_fixtures.go index 367ebd390..9cd876578 100644 --- a/acceptance/invoke/pack_fixtures.go +++ b/acceptance/invoke/pack_fixtures.go @@ -75,9 +75,13 @@ func (m PackFixtureManager) TemplateVersionedFixture( return m.fillTemplate(outputTemplate, templateData) } -func (m PackFixtureManager) TemplateFixtureToFile(name string, destination *os.File, data map[string]interface{}) { - _, err := io.WriteString(destination, m.TemplateFixture(name, data)) +func (m PackFixtureManager) TemplateFixtureToFile(tmpDir string, fixture string, data map[string]interface{}) string { + packageTomlFile, err := ioutil.TempFile(tmpDir, fixture+"-*") + defer packageTomlFile.Close() + + _, err = io.WriteString(packageTomlFile, m.TemplateFixture(fixture, data)) m.assert.Nil(err) + return packageTomlFile.Name() } func (m PackFixtureManager) fillTemplate(templateContents []byte, data map[string]interface{}) string { diff --git a/acceptance/tests/build/arg_app_test.go b/acceptance/tests/build/arg_app_test.go new file mode 100644 index 000000000..a72e0f80b --- /dev/null +++ b/acceptance/tests/build/arg_app_test.go @@ -0,0 +1,24 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_arg_app_zipfile(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + registry := th.Registry() + + pack := combo.Pack() + + repoName := registry.RepoName("sample/" + h.RandString(10)) + appPath := filepath.Join("..", "..", "testdata", "mock_app.zip") + output := pack.RunSuccessfully("build", repoName, "-p", appPath) + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) +} diff --git a/acceptance/tests/build/arg_buildpack_test.go b/acceptance/tests/build/arg_buildpack_test.go new file mode 100644 index 000000000..13c0e5c58 --- /dev/null +++ b/acceptance/tests/build/arg_buildpack_test.go @@ -0,0 +1,231 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/buildpacks" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_arg_buildpack(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + assert := h.NewAssertionManager(t) + registry := th.Registry() + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + repoName := registry.RepoName("test/" + h.RandString(10)) + + buildpackManager := buildpacks.NewBuildpackManager( + t, + assert, + buildpacks.WithBuildpackAPIVersion(lifecycle.EarliestBuildpackAPIVersion()), + buildpacks.WithBaseDir(filepath.Join("..", "..", "testdata", "mock_buildpacks")), + ) + + t.Run("the argument is an ID", func(t *testing.T) { + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--buildpack", "simple/layers", // can omit version if only one + "--buildpack", "noop.buildpack@noop.buildpack.version", + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + + assertTestAppOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertTestAppOutput.ReportsBuildStep("Simple Layers Buildpack") + assertTestAppOutput.ReportsBuildStep("NOOP Buildpack") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + t.Log("app is runnable") + assertImage.RunsWithOutput( + repoName, + "Launch Dep Contents", + "Cached Dep Contents", + ) + }) + + t.Run("the argument is an archive", func(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "archive-buildpack-tests-") + assert.Nil(err) + t.Cleanup(func() { + assert.Succeeds(os.RemoveAll(tmpDir)) + }) + + buildpackManager.PrepareBuildpacks(tmpDir, buildpacks.ArchiveNotInBuilder) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--buildpack", buildpacks.ArchiveNotInBuilder.FullPathIn(tmpDir), + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsAddingBuildpack("local/bp", "local-bp-version") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertBuildpackOutput.ReportsBuildStep("Local Buildpack") + }) + + t.Run("the argument is a directory", func(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "folder-buildpack-tests-") + assert.Nil(err) + t.Cleanup(func() { + assert.Succeeds(os.RemoveAll(tmpDir)) + }) + + h.SkipIf(t, runtime.GOOS == "windows", "buildpack directories not supported on windows") + + buildpackManager.PrepareBuildpacks(tmpDir, buildpacks.FolderNotInBuilder) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--buildpack", buildpacks.FolderNotInBuilder.FullPathIn(tmpDir), + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsAddingBuildpack("local/bp", "local-bp-version") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertBuildpackOutput.ReportsBuildStep("Local Buildpack") + }) + + t.Run("the argument is a buildpackage image", func(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "test-buildpackages-") + assert.Nil(err) + + packageImageName := registry.RepoName("buildpack-" + h.RandString(8)) + + t.Cleanup(func() { + imageManager.CleanupImages(packageImageName) + assert.Succeeds(os.RemoveAll(tmpDir)) + }) + + packageTomlPath := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, + "package_for_build_cmd.toml", + map[string]interface{}{ + "OS": imageManager.HostOS(), + }, + ) + + packageImage := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + packageTomlPath, + buildpacks.WithRequiredBuildpacks( + buildpacks.FolderSimpleLayersParent, + buildpacks.FolderSimpleLayers, + ), + ) + + buildpackManager.PrepareBuildpacks(tmpDir, packageImage) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--buildpack", packageImageName, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsAddingBuildpack( + "simple/layers/parent", + "simple-layers-parent-version", + ) + assertOutput.ReportsAddingBuildpack("simple/layers", "simple-layers-version") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") + }) + + t.Run("the argument is a buildpackage file", func(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "package-file") + assert.Nil(err) + + t.Cleanup(func() { + assert.Succeeds(os.RemoveAll(tmpDir)) + }) + + packageFileLocation := filepath.Join( + tmpDir, + fmt.Sprintf("buildpack-%s.cnb", h.RandString(8)), + ) + + packageTomlPath := pack.FixtureManager().TemplateFixtureToFile( + tmpDir, + "package_for_build_cmd.toml", + map[string]interface{}{ + "OS": imageManager.HostOS(), + }, + ) + + packageFile := buildpacks.NewPackageFile( + t, + pack, + packageFileLocation, + packageTomlPath, + buildpacks.WithRequiredBuildpacks( + buildpacks.FolderSimpleLayersParent, + buildpacks.FolderSimpleLayers, + ), + ) + + buildpackManager.PrepareBuildpacks(tmpDir, packageFile) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--buildpack", packageFileLocation, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsAddingBuildpack( + "simple/layers/parent", + "simple-layers-parent-version", + ) + assertOutput.ReportsAddingBuildpack("simple/layers", "simple-layers-version") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") + }) + + t.Run("the buildpack stack doesn't match the builder", func(t *testing.T) { + bpDir := filepath.Join("..", "..", "testdata", "mock_buildpacks", lifecycle.EarliestBuildpackAPIVersion()) + otherStackBuilderTgz := h.CreateTGZ(t, filepath.Join(bpDir, "other-stack-buildpack"), "./", 0755) + + t.Cleanup(func() { + assert.Succeeds(os.Remove(otherStackBuilderTgz)) + }) + + output, err := pack.Run( + "build", repoName, + "-p", appPath, + "--buildpack", otherStackBuilderTgz, + ) + + assert.NotNil(err) + assert.Contains(output, "other/stack/bp") + assert.Contains(output, "other-stack-version") + assert.Contains(output, "does not support stack 'pack.test.stack'") + }) +} diff --git a/acceptance/tests/build/arg_creation_time_test.go b/acceptance/tests/build/arg_creation_time_test.go new file mode 100644 index 000000000..f4ee6bc5e --- /dev/null +++ b/acceptance/tests/build/arg_creation_time_test.go @@ -0,0 +1,64 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/config" + "github.com/buildpacks/pack/acceptance/harness" + "github.com/buildpacks/pack/acceptance/invoke" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_arg_creation_time(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + registry := th.Registry() + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + lifecycle := combo.Lifecycle() + + h.SkipIf(t, !pack.SupportsFeature(invoke.CreationTime), "pack doesn't support creation time") + h.SkipIf(t, !lifecycle.SupportsFeature(config.CreationTime), "lifecycle doesn't support creation time") + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + + t.Run("provided as 'now'", func(t *testing.T) { + repoName := registry.RepoName("sample/" + h.RandString(10)) + expectedTime := time.Now() + pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--creation-time", "now", + ) + assertImage.HasCreateTime(repoName, expectedTime) + }) + + t.Run("provided as unix timestamp", func(t *testing.T) { + repoName := registry.RepoName("sample/" + h.RandString(10)) + pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + "--creation-time", "1566172801", + ) + expectedTime, err := time.Parse("2006-01-02T03:04:05Z", "2019-08-19T00:00:01Z") + h.AssertNil(t, err) + assertImage.HasCreateTime(repoName, expectedTime) + }) + + t.Run("not provided", func(t *testing.T) { + repoName := registry.RepoName("sample/" + h.RandString(10)) + pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + expectedTime, err := time.Parse("2006-01-02T03:04:05Z", "1980-01-01T00:00:01Z") + h.AssertNil(t, err) + assertImage.HasCreateTime(repoName, expectedTime) + }) +} diff --git a/acceptance/tests/build/env_vars_test.go b/acceptance/tests/build/arg_env_file_test.go similarity index 55% rename from acceptance/tests/build/env_vars_test.go rename to acceptance/tests/build/arg_env_file_test.go index 455dff8a3..c16875858 100644 --- a/acceptance/tests/build/env_vars_test.go +++ b/acceptance/tests/build/arg_env_file_test.go @@ -11,7 +11,7 @@ import ( h "github.com/buildpacks/pack/testhelpers" ) -func test_env_file(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { +func test_arg_env_file(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { assert := h.NewAssertionManager(t) registry := th.Registry() imageManager := th.ImageManager() @@ -55,33 +55,3 @@ ENV2_CONTENTS "Env1 Layer Contents From File", ) } - -func test_env_vars(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { - assert := h.NewAssertionManager(t) - registry := th.Registry() - imageManager := th.ImageManager() - assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - - pack := combo.Pack() - - assert.Succeeds(os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment")) - t.Cleanup(func() { - assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) - }) - - repoName := registry.RepoName("some-org/" + h.RandString(10)) - output := pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("..", "..", "testdata", "mock_app"), - "--env", "DETECT_ENV_BUILDPACK=true", - "--env", `ENV1_CONTENTS="Env1 Layer Contents From Command Line"`, - "--env", "ENV2_CONTENTS", - ) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) - assertImage.RunsWithOutput( - repoName, - "Env2 Layer Contents From Environment", - "Env1 Layer Contents From Command Line", - ) -} diff --git a/acceptance/tests/build/arg_env_test.go b/acceptance/tests/build/arg_env_test.go new file mode 100644 index 000000000..d171ddcc3 --- /dev/null +++ b/acceptance/tests/build/arg_env_test.go @@ -0,0 +1,41 @@ +package build_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_arg_env_vars(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + assert := h.NewAssertionManager(t) + registry := th.Registry() + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + + assert.Succeeds(os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment")) + t.Cleanup(func() { + assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) + }) + + repoName := registry.RepoName("some-org/" + h.RandString(10)) + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--env", "DETECT_ENV_BUILDPACK=true", + "--env", `ENV1_CONTENTS="Env1 Layer Contents From Command Line"`, + "--env", "ENV2_CONTENTS", + ) + + assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) + assertImage.RunsWithOutput( + repoName, + "Env2 Layer Contents From Environment", + "Env1 Layer Contents From Command Line", + ) +} diff --git a/acceptance/tests/build/color_test.go b/acceptance/tests/build/arg_no_color_test.go similarity index 86% rename from acceptance/tests/build/color_test.go rename to acceptance/tests/build/arg_no_color_test.go index d2335e0a7..fd861ecf8 100644 --- a/acceptance/tests/build/color_test.go +++ b/acceptance/tests/build/arg_no_color_test.go @@ -12,7 +12,7 @@ import ( h "github.com/buildpacks/pack/testhelpers" ) -func test_no_color(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { +func test_arg_no_color(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { pack := combo.Pack() appPath := filepath.Join("..", "..", "testdata", "mock_app") diff --git a/acceptance/tests/build/build_test.go b/acceptance/tests/build/build_test.go index 71ab9219b..3bfcc2601 100644 --- a/acceptance/tests/build/build_test.go +++ b/acceptance/tests/build/build_test.go @@ -4,181 +4,24 @@ package build_test import ( - "fmt" "path/filepath" - "regexp" "testing" - "github.com/buildpacks/pack/acceptance/assertions" "github.com/buildpacks/pack/acceptance/harness" - h "github.com/buildpacks/pack/testhelpers" ) -func test_runnable_rebuildable_inspectable(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { - registry := th.Registry() - imageManager := th.ImageManager() - runImageName := th.RunImageName() - runImageMirror := th.RunImageMirror() - - assert := h.NewAssertionManager(t) - assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - - pack := combo.Pack() - - appPath := filepath.Join("..", "..", "testdata", "mock_app") - - repo := "some-org/" + h.RandString(10) - repoName := registry.RepoName(repo) - - output := pack.RunSuccessfully( - "build", repoName, - "-p", appPath, - ) - - assertOutput := assertions.NewOutputAssertionManager(t, output) - - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsUsingBuildCacheVolume() - assertOutput.ReportsSelectingRunImageMirror(runImageMirror) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("it uses the run image as a base image") - assertImage.HasBaseImage(repoName, runImageName) - - t.Log("sets the run image metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImageName, runImageMirror)) - - t.Log("sets the source metadata") - assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) - - t.Log("registry is empty") - assertImage.NotExistsInRegistry(repo) - - t.Log("add a local mirror") - localRunImageMirror := registry.RepoName("pack-test/run-mirror") - imageManager.TagImage(runImageName, localRunImageMirror) - defer imageManager.CleanupImages(localRunImageMirror) - - pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) - defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) - - t.Log("rebuild") - output = pack.RunSuccessfully( - "build", repoName, - "-p", appPath, - ) - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) - cachedLaunchLayer := "simple/layers:cached-launch-layer" - - assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) - - t.Log("app is runnable") - assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") - - t.Log("rebuild with --clear-cache") - output = pack.RunSuccessfully("build", - repoName, - "-p", appPath, - "--clear-cache", - ) - - assertOutput = assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSuccessfulImageBuild(repoName) - assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) - assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) - assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) - - t.Log("cacher adds layers") - assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) - - t.Log("inspecting image") - inspectCmd := "inspect" - if !pack.Supports("inspect") { - inspectCmd = "inspect-image" - } - - var ( - webCommand string - helloCommand string - helloArgs []string - helloArgsPrefix string - imageWorkdir string - ) - if imageManager.HostOS() == "windows" { - webCommand = ".\\run" - helloCommand = "cmd" - helloArgs = []string{"/c", "echo hello world"} - helloArgsPrefix = " " - imageWorkdir = "c:\\workspace" - } else { - webCommand = "./run" - helloCommand = "echo" - helloArgs = []string{"hello", "world"} - helloArgsPrefix = "" - imageWorkdir = "/workspace" - } - - formats := []compareFormat{ - { - extension: "json", - compareFunc: assert.EqualJSON, - outputArg: "json", - }, - { - extension: "yaml", - compareFunc: assert.EqualYAML, - outputArg: "yaml", - }, - { - extension: "toml", - compareFunc: assert.EqualTOML, - outputArg: "toml", - }, - } - for _, format := range formats { - t.Logf("inspecting image %s format", format.outputArg) - - output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) - expectedOutput := pack.FixtureManager().TemplateFixture( - fmt.Sprintf("inspect_image_local_output.%s", format.extension), - map[string]interface{}{ - "image_name": repoName, - "base_image_id": h.ImageID(t, runImageMirror), - "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), - "run_image_local_mirror": localRunImageMirror, - "run_image_mirror": runImageMirror, - "web_command": webCommand, - "hello_command": helloCommand, - "hello_args": helloArgs, - "hello_args_prefix": helloArgsPrefix, - "image_workdir": imageWorkdir, - }, - ) - - format.compareFunc(output, expectedOutput) - } -} - -func test_app_zipfile(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { - registry := th.Registry() - - pack := combo.Pack() - - repoName := registry.RepoName("sample/" + h.RandString(10)) - appPath := filepath.Join("..", "..", "testdata", "mock_app.zip") - output := pack.RunSuccessfully("build", repoName, "-p", appPath) - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) -} - -type compareFormat struct { - extension string - compareFunc func(string, string) - outputArg string +func TestBuild(t *testing.T) { + testHarness := harness.ContainingBuilder(t, filepath.Join("..", "..", "..")) + t.Cleanup(testHarness.CleanUp) + + testHarness.RunA(test_app_image_is_runnable_and_rebuildable) + testHarness.RunA(test_app_image_is_inspectable) + testHarness.RunA(test_untrusted_daemon) + testHarness.RunA(test_untrusted_registry) + testHarness.RunA(test_arg_app_zipfile) + testHarness.RunA(test_arg_creation_time) + testHarness.RunA(test_arg_env_file) + testHarness.RunA(test_arg_env_vars) + testHarness.RunA(test_arg_no_color) + testHarness.RunA(test_arg_buildpack) } diff --git a/acceptance/tests/build/init_test.go b/acceptance/tests/build/init_test.go deleted file mode 100644 index cabb9c259..000000000 --- a/acceptance/tests/build/init_test.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build acceptance -// +build acceptance - -package build_test - -import ( - "path/filepath" - "testing" - - "github.com/buildpacks/pack/acceptance/harness" -) - -func TestBuild(t *testing.T) { - testHarness := harness.ContainingBuilder(t, filepath.Join("..", "..", "..")) - t.Cleanup(testHarness.CleanUp) - - // testHarness.RunA(test_runnable_rebuildable_inspectable) - // testHarness.RunA(test_untrusted_daemon) - // testHarness.RunA(test_untrusted_registry) - // testHarness.RunA(test_no_color) - // testHarness.RunA(test_app_zipfile) - // testHarness.RunA(test_env_file) - testHarness.RunA(test_env_vars) -} diff --git a/acceptance/tests/build/inspectable_test.go b/acceptance/tests/build/inspectable_test.go new file mode 100644 index 000000000..80e055242 --- /dev/null +++ b/acceptance/tests/build/inspectable_test.go @@ -0,0 +1,111 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_app_image_is_inspectable(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + assert := h.NewAssertionManager(t) + + registry := th.Registry() + imageManager := th.ImageManager() + runImageName := th.RunImageName() + runImageMirror := th.RunImageMirror() + + pack := combo.Pack() + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + repoName := registry.RepoName("some-org/" + h.RandString(10)) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + + localRunImageMirror := registry.RepoName("pack-test/run-mirror") + imageManager.TagImage(runImageName, localRunImageMirror) + defer imageManager.CleanupImages(localRunImageMirror) + + pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) + + inspectCmd := "inspect" + if !pack.Supports("inspect") { + inspectCmd = "inspect-image" + } + + var ( + webCommand string + helloCommand string + helloArgs []string + helloArgsPrefix string + imageWorkdir string + ) + if imageManager.HostOS() == "windows" { + webCommand = ".\\run" + helloCommand = "cmd" + helloArgs = []string{"/c", "echo hello world"} + helloArgsPrefix = " " + imageWorkdir = "c:\\workspace" + } else { + webCommand = "./run" + helloCommand = "echo" + helloArgs = []string{"hello", "world"} + helloArgsPrefix = "" + imageWorkdir = "/workspace" + } + + formats := []compareFormat{ + { + extension: "json", + compareFunc: assert.EqualJSON, + outputArg: "json", + }, + { + extension: "yaml", + compareFunc: assert.EqualYAML, + outputArg: "yaml", + }, + { + extension: "toml", + compareFunc: assert.EqualTOML, + outputArg: "toml", + }, + } + for _, format := range formats { + t.Logf("inspecting image %s format", format.outputArg) + + output = pack.RunSuccessfully(inspectCmd, repoName, "--output", format.outputArg) + expectedOutput := pack.FixtureManager().TemplateFixture( + fmt.Sprintf("inspect_image_local_output.%s", format.extension), + map[string]interface{}{ + "image_name": repoName, + "base_image_id": h.ImageID(t, runImageMirror), + "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), + "run_image_local_mirror": localRunImageMirror, + "run_image_mirror": runImageMirror, + "web_command": webCommand, + "hello_command": helloCommand, + "hello_args": helloArgs, + "hello_args_prefix": helloArgsPrefix, + "image_workdir": imageWorkdir, + }, + ) + + format.compareFunc(output, expectedOutput) + } +} + +type compareFormat struct { + extension string + compareFunc func(string, string) + outputArg string +} diff --git a/acceptance/tests/build/rebuild_test.go b/acceptance/tests/build/rebuild_test.go new file mode 100644 index 000000000..320ba0aea --- /dev/null +++ b/acceptance/tests/build/rebuild_test.go @@ -0,0 +1,100 @@ +//go:build acceptance +// +build acceptance + +package build_test + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func test_app_image_is_runnable_and_rebuildable(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + registry := th.Registry() + imageManager := th.ImageManager() + runImageName := th.RunImageName() + runImageMirror := th.RunImageMirror() + + assert := h.NewAssertionManager(t) + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack := combo.Pack() + + appPath := filepath.Join("..", "..", "testdata", "mock_app") + + repo := "some-org/" + h.RandString(10) + repoName := registry.RepoName(repo) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsUsingBuildCacheVolume() + assertOutput.ReportsSelectingRunImageMirror(runImageMirror) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("it uses the run image as a base image") + assertImage.HasBaseImage(repoName, runImageName) + + t.Log("sets the run image metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.lifecycle.metadata", fmt.Sprintf(`"stack":{"runImage":{"image":"%s","mirrors":["%s"]}}}`, runImageName, runImageMirror)) + + t.Log("sets the source metadata") + assertImage.HasLabelWithData(repoName, "io.buildpacks.project.metadata", (`{"source":{"type":"project","version":{"declared":"1.0.2"},"metadata":{"url":"https://github.com/buildpacks/pack"}}}`)) + + t.Log("registry is empty") + assertImage.NotExistsInRegistry(repo) + + t.Log("add a local mirror") + localRunImageMirror := registry.RepoName("pack-test/run-mirror") + imageManager.TagImage(runImageName, localRunImageMirror) + defer imageManager.CleanupImages(localRunImageMirror) + + pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + defer pack.JustRunSuccessfully("config", "run-image-mirrors", "remove", runImageName) + + t.Log("rebuild") + output = pack.RunSuccessfully( + "build", repoName, + "-p", appPath, + ) + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) + cachedLaunchLayer := "simple/layers:cached-launch-layer" + + assertLifecycleOutput := assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsRestoresCachedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheReuse(cachedLaunchLayer) + + t.Log("app is runnable") + assertImage.RunsWithOutput(repoName, "Launch Dep Contents", "Cached Dep Contents") + + t.Log("rebuild with --clear-cache") + output = pack.RunSuccessfully("build", + repoName, + "-p", appPath, + "--clear-cache", + ) + + assertOutput = assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSuccessfulImageBuild(repoName) + assertLifecycleOutput = assertions.NewLifecycleOutputAssertionManager(t, output) + assertLifecycleOutput.ReportsExporterReusingUnchangedLayer(cachedLaunchLayer) + assertLifecycleOutput.ReportsCacheCreation(cachedLaunchLayer) + + t.Log("cacher adds layers") + assert.Matches(output, regexp.MustCompile(`(?i)Adding cache layer 'simple/layers:cached-launch-layer'`)) +} From 34a1b619b06e12f23cf09dba9274d425df2dde06 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Fri, 19 Aug 2022 19:56:19 -0500 Subject: [PATCH 07/15] Fix legacy acceptance tests Signed-off-by: Javier Romero --- acceptance/acceptance_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 425a81e5a..890a3844a 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -72,7 +72,7 @@ func TestAcceptance(t *testing.T) { inputConfigManager, err := config.NewInputConfigurationManager() assert.Nil(err) - assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, filepath.Join("testdata")) + assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, "..") suiteManager = &SuiteManager{out: t.Logf} suite := spec.New("acceptance suite", spec.Report(report.Terminal{})) @@ -780,6 +780,15 @@ func testAcceptance( when("default builder is set", func() { + it.Before(func() { + pack.RunSuccessfully("config", "default-builder", builderName) + pack.JustRunSuccessfully("config", "trusted-builders", "add", builderName) + }) + + it.After(func() { + pack.RunSuccessfully("config", "default-builder", "--unset") + }) + when("--quiet", func() { it("only logs app name and sha", func() { appPath := filepath.Join("testdata", "mock_app") From d0188e85f89c1e760de13765bc8e13a98055498a Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Mon, 22 Aug 2022 11:12:35 -0500 Subject: [PATCH 08/15] Migrate rebase tests Signed-off-by: Javier Romero --- acceptance/config/stack.go | 14 ++ acceptance/harness/builder_harness.go | 62 +++---- acceptance/harness/util.go | 27 ++- acceptance/managers/image_manager.go | 4 + .../testdata/pack_fixtures/builder.toml | 8 + .../inspect_image_local_output.json | 2 +- .../inspect_image_local_output.toml | 2 +- .../inspect_image_local_output.yaml | 2 +- .../inspect_image_published_output.json | 2 +- .../inspect_image_published_output.toml | 2 +- .../inspect_image_published_output.yaml | 2 +- acceptance/tests/build/arg_env_file_test.go | 3 + acceptance/tests/build/arg_env_test.go | 3 + acceptance/tests/build/inspectable_test.go | 5 +- acceptance/tests/build/rebuild_test.go | 4 +- acceptance/tests/rebase/rebase_test.go | 172 ++++++++++++++++++ 16 files changed, 262 insertions(+), 52 deletions(-) create mode 100644 acceptance/config/stack.go create mode 100644 acceptance/tests/rebase/rebase_test.go diff --git a/acceptance/config/stack.go b/acceptance/config/stack.go new file mode 100644 index 000000000..ea446cb6b --- /dev/null +++ b/acceptance/config/stack.go @@ -0,0 +1,14 @@ +//go:build acceptance +// +build acceptance + +package config + +type Stack struct { + RunImage RunImage + BuildImageName string +} + +type RunImage struct { + Name string + MirrorName string +} diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index 8260827f4..473f1a822 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -47,9 +47,7 @@ type BuilderTestHarness struct { t *testing.T registryConfig h.TestRegistryConfig imageManager managers.ImageManager - runImageName string - runImageMirror string - buildImageName string + stack config.Stack combos []BuilderCombo cleanups []func() } @@ -88,11 +86,15 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { assetsConfig := config.NewAssetManager(t, assert, inputConfigManager, projectBaseDir) // create stack - runImageName := "pack-test/run" - buildImageName := "pack-test/build" - - runImageMirror := registry.RepoName(runImageName) - err = createStack(t, dockerCli, registry, imageManager, runImageName, buildImageName, runImageMirror, testDataDir) + stack, err := createStack( + t, + dockerCli, + registry, + imageManager, + "pack-test/run:"+h.RandString(6), + "pack-test/build:"+h.RandString(6), + testDataDir, + ) assert.Nil(err) stackBaseImages := map[string][]string{ @@ -103,7 +105,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { cleanups = append(cleanups, func() { t.Log("cleaning up stack images...") imageManager.CleanupImages(baseStackNames...) - imageManager.CleanupImages(runImageName, buildImageName, runImageMirror) + imageManager.CleanupImages(stack.RunImage.Name, stack.BuildImageName, stack.RunImage.MirrorName) }) combos := []BuilderCombo{} @@ -144,7 +146,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { *createBuilderPack, lifecycle, buildpackManager, - runImageMirror, + stack, ) assert.Nil(err) cleanups = append(cleanups, func() { @@ -165,9 +167,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { t: t, registryConfig: *registry, imageManager: imageManager, - runImageName: runImageName, - runImageMirror: runImageMirror, - buildImageName: buildImageName, + stack: stack, combos: combos, cleanups: cleanups, } @@ -177,32 +177,32 @@ func (b *BuilderTestHarness) Combinations() []BuilderCombo { return b.combos } -func (b *BuilderTestHarness) Run(test func(combo BuilderCombo)) { +func (b *BuilderTestHarness) Run(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { + for _, combo := range b.combos { + combo := combo + b.t.Run(name, func(t *testing.T) { + test(t, b, combo) + }) + } +} + +func (b *BuilderTestHarness) RunC(test func(combo BuilderCombo)) { func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + b.Run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { test(combo) }) } -func (b *BuilderTestHarness) RunT(test func(t *testing.T, combo BuilderCombo)) { +func (b *BuilderTestHarness) RunTC(test func(t *testing.T, combo BuilderCombo)) { func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + b.Run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { test(t, combo) }) } func (b *BuilderTestHarness) RunA(test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.run(func_name, test) -} - -func (b *BuilderTestHarness) run(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { - for _, combo := range b.combos { - combo := combo - b.t.Run(name, func(t *testing.T) { - test(t, b, combo) - }) - } + b.Run(func_name, test) } func (b *BuilderTestHarness) Registry() h.TestRegistryConfig { @@ -213,12 +213,8 @@ func (b *BuilderTestHarness) ImageManager() managers.ImageManager { return b.imageManager } -func (b *BuilderTestHarness) RunImageName() string { - return b.runImageName -} - -func (b *BuilderTestHarness) RunImageMirror() string { - return b.runImageMirror +func (b *BuilderTestHarness) Stack() config.Stack { + return b.stack } func (b *BuilderTestHarness) CleanUp() { diff --git a/acceptance/harness/util.go b/acceptance/harness/util.go index e81c21578..2189125d5 100644 --- a/acceptance/harness/util.go +++ b/acceptance/harness/util.go @@ -31,7 +31,7 @@ func createBuilder( pack invoke.PackInvoker, lifecycle config.LifecycleAsset, buildpackManager buildpacks.BuildpackManager, - runImageMirror string, + stack config.Stack, ) (string, error) { t.Log("creating builder image...") @@ -41,7 +41,9 @@ func createBuilder( defer os.RemoveAll(tmpDir) templateMapping := map[string]interface{}{ - "run_image_mirror": runImageMirror, + "build_image": stack.BuildImageName, + "run_image": stack.RunImage.Name, + "run_image_mirror": stack.RunImage.MirrorName, } // ARCHIVE BUILDPACKS @@ -118,7 +120,7 @@ func createBuilder( return bldr, nil } -func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, runImageMirror, testDataDir string) error { +func createStack(t *testing.T, dockerCli client.CommonAPIClient, registry *h.TestRegistryConfig, imageManager managers.ImageManager, runImageName, buildImageName, testDataDir string) (config.Stack, error) { t.Helper() t.Log("creating stack images...") @@ -126,22 +128,29 @@ func createStack(t *testing.T, dockerCli client.CommonAPIClient, registryConfig _, err := os.Stat(stackBaseDir) if err != nil { - return err + return config.Stack{}, err } if err := createStackImage(dockerCli, runImageName, filepath.Join(stackBaseDir, "run")); err != nil { - return err + return config.Stack{}, err } if err := createStackImage(dockerCli, buildImageName, filepath.Join(stackBaseDir, "build")); err != nil { - return err + return config.Stack{}, err } + runImageMirror := registry.RepoName(runImageName) imageManager.TagImage(runImageName, runImageMirror) - if err := h.PushImage(dockerCli, runImageMirror, registryConfig); err != nil { - return err + if err := h.PushImage(dockerCli, runImageMirror, registry); err != nil { + return config.Stack{}, err } - return nil + return config.Stack{ + RunImage: config.RunImage{ + Name: runImageName, + MirrorName: runImageMirror, + }, + BuildImageName: buildImageName, + }, nil } func createStackImage(dockerCli client.CommonAPIClient, repoName string, dir string) error { diff --git a/acceptance/managers/image_manager.go b/acceptance/managers/image_manager.go index e3976ba13..a4e24fbe5 100644 --- a/acceptance/managers/image_manager.go +++ b/acceptance/managers/image_manager.go @@ -42,6 +42,10 @@ func (im ImageManager) CleanupImages(imageNames ...string) { } } +func (im ImageManager) CreateImage(name string, dockerfile string) { + h.CreateImage(im.testObject, im.dockerCli, name, dockerfile) +} + func (im ImageManager) InspectLocal(image string) (dockertypes.ImageInspect, error) { im.testObject.Helper() inspect, _, err := im.dockerCli.ImageInspectWithRaw(context.Background(), image) diff --git a/acceptance/testdata/pack_fixtures/builder.toml b/acceptance/testdata/pack_fixtures/builder.toml index afd2e7d03..de251b765 100644 --- a/acceptance/testdata/pack_fixtures/builder.toml +++ b/acceptance/testdata/pack_fixtures/builder.toml @@ -30,8 +30,16 @@ [stack] id = "pack.test.stack" +{{- if .build_image}} + build-image = "{{.build_image}}" +{{- else -}} build-image = "pack-test/build" +{{- end}} +{{- if .run_image}} + run-image = "{{.run_image}}" +{{- else -}} run-image = "pack-test/run" +{{- end}} run-image-mirrors = ["{{.run_image_mirror}}"] [lifecycle] diff --git a/acceptance/testdata/pack_fixtures/inspect_image_local_output.json b/acceptance/testdata/pack_fixtures/inspect_image_local_output.json index 83cbc9b12..7cb053e5d 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_local_output.json +++ b/acceptance/testdata/pack_fixtures/inspect_image_local_output.json @@ -13,7 +13,7 @@ "user_configured": true }, { - "name": "pack-test/run" + "name": "{{.run_image}}" }, { "name": "{{.run_image_mirror}}" diff --git a/acceptance/testdata/pack_fixtures/inspect_image_local_output.toml b/acceptance/testdata/pack_fixtures/inspect_image_local_output.toml index 97be50630..e10b49eb8 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_local_output.toml +++ b/acceptance/testdata/pack_fixtures/inspect_image_local_output.toml @@ -12,7 +12,7 @@ stack = "pack.test.stack" user_configured = true [[local_info.run_images]] - name = "pack-test/run" + name = "{{.run_image}}" [[local_info.run_images]] name = "{{.run_image_mirror}}" diff --git a/acceptance/testdata/pack_fixtures/inspect_image_local_output.yaml b/acceptance/testdata/pack_fixtures/inspect_image_local_output.yaml index 465ef5263..7fad7e313 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_local_output.yaml +++ b/acceptance/testdata/pack_fixtures/inspect_image_local_output.yaml @@ -9,7 +9,7 @@ local_info: run_images: - name: "{{.run_image_local_mirror}}" user_configured: true - - name: pack-test/run + - name: "{{.run_image}}" - name: "{{.run_image_mirror}}" buildpacks: - id: simple/layers diff --git a/acceptance/testdata/pack_fixtures/inspect_image_published_output.json b/acceptance/testdata/pack_fixtures/inspect_image_published_output.json index 691b8d17d..331fcf770 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_published_output.json +++ b/acceptance/testdata/pack_fixtures/inspect_image_published_output.json @@ -9,7 +9,7 @@ }, "run_images": [ { - "name": "pack-test/run" + "name": "{{.run_image}}" }, { "name": "{{.run_image_mirror}}" diff --git a/acceptance/testdata/pack_fixtures/inspect_image_published_output.toml b/acceptance/testdata/pack_fixtures/inspect_image_published_output.toml index 734eaad21..c144e8ae1 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_published_output.toml +++ b/acceptance/testdata/pack_fixtures/inspect_image_published_output.toml @@ -8,7 +8,7 @@ stack = "pack.test.stack" reference = "{{.base_image_ref}}" [[remote_info.run_images]] - name = "pack-test/run" + name = "{{.run_image}}" [[remote_info.run_images]] name = "{{.run_image_mirror}}" diff --git a/acceptance/testdata/pack_fixtures/inspect_image_published_output.yaml b/acceptance/testdata/pack_fixtures/inspect_image_published_output.yaml index 189c3c3e3..5bc966107 100644 --- a/acceptance/testdata/pack_fixtures/inspect_image_published_output.yaml +++ b/acceptance/testdata/pack_fixtures/inspect_image_published_output.yaml @@ -7,7 +7,7 @@ remote_info: top_layer: "{{.base_image_top_layer}}" reference: "{{.base_image_ref}}" run_images: - - name: pack-test/run + - name: "{{.run_image}}" - name: "{{.run_image_mirror}}" buildpacks: - id: simple/layers diff --git a/acceptance/tests/build/arg_env_file_test.go b/acceptance/tests/build/arg_env_file_test.go index c16875858..a6e48da24 100644 --- a/acceptance/tests/build/arg_env_file_test.go +++ b/acceptance/tests/build/arg_env_file_test.go @@ -1,3 +1,6 @@ +//go:build acceptance +// +build acceptance + package build_test import ( diff --git a/acceptance/tests/build/arg_env_test.go b/acceptance/tests/build/arg_env_test.go index d171ddcc3..a5d17d575 100644 --- a/acceptance/tests/build/arg_env_test.go +++ b/acceptance/tests/build/arg_env_test.go @@ -1,3 +1,6 @@ +//go:build acceptance +// +build acceptance + package build_test import ( diff --git a/acceptance/tests/build/inspectable_test.go b/acceptance/tests/build/inspectable_test.go index 80e055242..028daab34 100644 --- a/acceptance/tests/build/inspectable_test.go +++ b/acceptance/tests/build/inspectable_test.go @@ -17,8 +17,8 @@ func test_app_image_is_inspectable(t *testing.T, th *harness.BuilderTestHarness, registry := th.Registry() imageManager := th.ImageManager() - runImageName := th.RunImageName() - runImageMirror := th.RunImageMirror() + runImageName := th.Stack().RunImage.Name + runImageMirror := th.Stack().RunImage.MirrorName pack := combo.Pack() @@ -91,6 +91,7 @@ func test_app_image_is_inspectable(t *testing.T, th *harness.BuilderTestHarness, "base_image_id": h.ImageID(t, runImageMirror), "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), "run_image_local_mirror": localRunImageMirror, + "run_image": runImageName, "run_image_mirror": runImageMirror, "web_command": webCommand, "hello_command": helloCommand, diff --git a/acceptance/tests/build/rebuild_test.go b/acceptance/tests/build/rebuild_test.go index 320ba0aea..bc5b93f96 100644 --- a/acceptance/tests/build/rebuild_test.go +++ b/acceptance/tests/build/rebuild_test.go @@ -17,8 +17,8 @@ import ( func test_app_image_is_runnable_and_rebuildable(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { registry := th.Registry() imageManager := th.ImageManager() - runImageName := th.RunImageName() - runImageMirror := th.RunImageMirror() + runImageName := th.Stack().RunImage.Name + runImageMirror := th.Stack().RunImage.MirrorName assert := h.NewAssertionManager(t) assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) diff --git a/acceptance/tests/rebase/rebase_test.go b/acceptance/tests/rebase/rebase_test.go new file mode 100644 index 000000000..28e8299f6 --- /dev/null +++ b/acceptance/tests/rebase/rebase_test.go @@ -0,0 +1,172 @@ +//go:build acceptance +// +build acceptance + +package rebase_test + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/buildpacks/pack/acceptance/assertions" + "github.com/buildpacks/pack/acceptance/harness" + h "github.com/buildpacks/pack/testhelpers" +) + +func TestRebase(t *testing.T) { + testHarness := harness.ContainingBuilder(t, filepath.Join("..", "..", "..")) + t.Cleanup(testHarness.CleanUp) + + testHarness.RunA(test_run_image_flag) + testHarness.RunA(test_local_config_mirror) + testHarness.RunA(test_stack_config_mirror) +} + +func test_run_image_flag(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + assert := h.NewAssertionManager(t) + + pack := combo.Pack() + builderName := combo.BuilderName() + + registry := th.Registry() + runImageName := th.Stack().RunImage.Name + imageManager := th.ImageManager() + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + pack.JustRunSuccessfully("config", "trusted-builders", "add", builderName) + + repoName := registry.RepoName("some-org/" + h.RandString(10)) + originalRunImage := registry.RepoName("acceptance/run-image:original" + h.RandString(10)) + + th.ImageManager().CreateImage( + originalRunImage, + runImageDockerfile(runImageName, "root", "contents-original-1", "contents-original-2"), + ) + + pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--builder", builderName, + "--run-image", originalRunImage, + "--pull-policy", "never", + ) + + originalID := h.ImageID(t, repoName) + + assertImage.RunsWithOutput( + repoName, + "contents-original-1", + "contents-original-2", + ) + + t.Cleanup(func() { + imageManager.CleanupImages(originalID, repoName, originalRunImage) + }) + + updatedRunImage := registry.RepoName("acceptance/run-image:updated" + h.RandString(10)) + imageManager.CreateImage(updatedRunImage, runImageDockerfile(runImageName, "root", "contents-updated-1", "contents-updated-2")) + t.Cleanup(func() { + imageManager.CleanupImages(updatedRunImage) + }) + + output := pack.RunSuccessfully( + "rebase", repoName, + "--run-image", updatedRunImage, + "--pull-policy", "never", + ) + + assert.Contains(output, fmt.Sprintf("Successfully rebased image '%s'", repoName)) + assertImage.RunsWithOutput( + repoName, + "contents-updated-1", + "contents-updated-2", + ) +} + +func test_local_config_mirror(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + builderName := combo.BuilderName() + pack := combo.Pack() + + registry := th.Registry() + runImageName := th.Stack().RunImage.Name + imageManager := th.ImageManager() + + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + localRunImageMirror := "run-after/" + h.RandString(10) + th.ImageManager().CreateImage(localRunImageMirror, runImageDockerfile(runImageName, "root", "local-mirror-after-1", "local-mirror-after-2")) + + output := pack.RunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) + t.Log(output) + + t.Cleanup(func() { + imageManager.CleanupImages(localRunImageMirror) + }) + + repoName := "pack-test/rebase-local-config-mirror:app" + h.RandString(6) + + pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--builder", builderName, + "--pull-policy", "never", + ) + + output = pack.RunSuccessfully("rebase", repoName, "--pull-policy", "never") + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) + assertOutput.ReportsSuccessfulRebase(repoName) + assertImage.RunsWithOutput( + repoName, + "local-mirror-after-1", + "local-mirror-after-2", + ) +} + +func test_stack_config_mirror(t *testing.T, th *harness.BuilderTestHarness, combo harness.BuilderCombo) { + builderName := combo.BuilderName() + pack := combo.Pack() + + registry := th.Registry() + runImageName := th.Stack().RunImage.Name + runImageMirror := th.Stack().RunImage.MirrorName + imageManager := th.ImageManager() + + assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) + + // override image + th.ImageManager().CreateImage(runImageMirror, runImageDockerfile(runImageName, "root", "mirror-after-1", "mirror-after-2")) + + t.Cleanup(func() { + imageManager.CleanupImages(runImageMirror) + }) + + repoName := registry.RepoName("pack-test/stack-config-run-image:app" + h.RandString(6)) + + pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("..", "..", "testdata", "mock_app"), + "--builder", builderName, + "--pull-policy", "never", + ) + + output := pack.RunSuccessfully("rebase", repoName, "--pull-policy", "never") + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsSelectingRunImageMirror(runImageMirror) + assertOutput.ReportsSuccessfulRebase(repoName) + assertImage.RunsWithOutput( + repoName, + "mirror-after-1", + "mirror-after-2", + ) +} + +func runImageDockerfile(baseRunImage, user, contents1, contents2 string) string { + return fmt.Sprintf(`FROM %s +USER %s +RUN echo %s > /contents1.txt +RUN echo %s > /contents2.txt +USER pack`, baseRunImage, user, contents1, contents2) +} From 4ba458ad529ddaf8bd30c41b1afce39808839956 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Mon, 22 Aug 2022 13:41:24 -0500 Subject: [PATCH 09/15] Update legacy acceptance tests to pass Signed-off-by: Javier Romero --- acceptance/acceptance_test.go | 181 +++------------------------------- 1 file changed, 12 insertions(+), 169 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 890a3844a..e67e2dd8e 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -685,7 +685,13 @@ func testAcceptance( )..., ) value, err := suiteManager.RunTaskOnceString(key, func() (string, error) { - return createBuilder(t, assert, imageManager, dockerCli, createBuilderPack, lifecycle, buildpackManager, runImageMirror) + return createBuilder(t, assert, imageManager, dockerCli, createBuilderPack, lifecycle, buildpackManager, config.Stack{ + RunImage: config.RunImage{ + Name: runImage, + MirrorName: runImageMirror, + }, + BuildImageName: buildImage, + }) }) assert.Nil(err) suiteManager.RegisterCleanUp("clean-"+key, func() error { @@ -1123,6 +1129,7 @@ func testAcceptance( "image_name": repoName, "base_image_ref": strings.Join([]string{runImageMirror, h.Digest(t, runImageMirror)}, "@"), "base_image_top_layer": h.TopLayerDiffID(t, runImageMirror), + "run_image": runImage, "run_image_mirror": runImageMirror, "web_command": webCommand, "hello_command": helloCommand, @@ -1807,172 +1814,6 @@ include = [ "*.jar", "media/mountain.jpg", "/media/person.png", ] assert.TrimmedEq(output, expectedOutput) }) }) - - when("rebase", func() { - var repoName, runBefore, origID string - var buildRunImage func(string, string, string) - - it.Before(func() { - pack.JustRunSuccessfully("config", "trusted-builders", "add", builderName) - - repoName = registryConfig.RepoName("some-org/" + h.RandString(10)) - runBefore = registryConfig.RepoName("run-before/" + h.RandString(10)) - - buildRunImage = func(newRunImage, contents1, contents2 string) { - user := func() string { - if imageManager.HostOS() == "windows" { - return "ContainerAdministrator" - } - - return "root" - } - - h.CreateImage(t, dockerCli, newRunImage, fmt.Sprintf(` - FROM %s - USER %s - RUN echo %s > /contents1.txt - RUN echo %s > /contents2.txt - USER pack - `, runImage, user(), contents1, contents2)) - } - - buildRunImage(runBefore, "contents-before-1", "contents-before-2") - pack.RunSuccessfully( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--builder", builderName, - "--run-image", runBefore, - "--pull-policy", "never", - ) - origID = h.ImageID(t, repoName) - assertImage.RunsWithOutput( - repoName, - "contents-before-1", - "contents-before-2", - ) - }) - - it.After(func() { - imageManager.CleanupImages(origID, repoName, runBefore) - ref, err := name.ParseReference(repoName, name.WeakValidation) - assert.Nil(err) - buildCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "build", dockerCli) - launchCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "launch", dockerCli) - assert.Succeeds(buildCacheVolume.Clear(context.TODO())) - assert.Succeeds(launchCacheVolume.Clear(context.TODO())) - }) - - when("daemon", func() { - when("--run-image", func() { - var runAfter string - - it.Before(func() { - runAfter = registryConfig.RepoName("run-after/" + h.RandString(10)) - buildRunImage(runAfter, "contents-after-1", "contents-after-2") - }) - - it.After(func() { - imageManager.CleanupImages(runAfter) - }) - - it("uses provided run image", func() { - output := pack.RunSuccessfully( - "rebase", repoName, - "--run-image", runAfter, - "--pull-policy", "never", - ) - - assert.Contains(output, fmt.Sprintf("Successfully rebased image '%s'", repoName)) - assertImage.RunsWithOutput( - repoName, - "contents-after-1", - "contents-after-2", - ) - }) - }) - - when("local config has a mirror", func() { - var localRunImageMirror string - - it.Before(func() { - localRunImageMirror = registryConfig.RepoName("run-after/" + h.RandString(10)) - buildRunImage(localRunImageMirror, "local-mirror-after-1", "local-mirror-after-2") - pack.JustRunSuccessfully("config", "run-image-mirrors", "add", runImage, "-m", localRunImageMirror) - }) - - it.After(func() { - imageManager.CleanupImages(localRunImageMirror) - }) - - it("prefers the local mirror", func() { - output := pack.RunSuccessfully("rebase", repoName, "--pull-policy", "never") - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) - assertOutput.ReportsSuccessfulRebase(repoName) - assertImage.RunsWithOutput( - repoName, - "local-mirror-after-1", - "local-mirror-after-2", - ) - }) - }) - - when("image metadata has a mirror", func() { - it.Before(func() { - // clean up existing mirror first to avoid leaking images - imageManager.CleanupImages(runImageMirror) - - buildRunImage(runImageMirror, "mirror-after-1", "mirror-after-2") - }) - - it("selects the best mirror", func() { - output := pack.RunSuccessfully("rebase", repoName, "--pull-policy", "never") - - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsSelectingRunImageMirror(runImageMirror) - assertOutput.ReportsSuccessfulRebase(repoName) - assertImage.RunsWithOutput( - repoName, - "mirror-after-1", - "mirror-after-2", - ) - }) - }) - }) - - when("--publish", func() { - it.Before(func() { - assert.Succeeds(h.PushImage(dockerCli, repoName, registryConfig)) - }) - - when("--run-image", func() { - var runAfter string - - it.Before(func() { - runAfter = registryConfig.RepoName("run-after/" + h.RandString(10)) - buildRunImage(runAfter, "contents-after-1", "contents-after-2") - assert.Succeeds(h.PushImage(dockerCli, runAfter, registryConfig)) - }) - - it.After(func() { - imageManager.CleanupImages(runAfter) - }) - - it("uses provided run image", func() { - output := pack.RunSuccessfully("rebase", repoName, "--publish", "--run-image", runAfter) - - assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulRebase(repoName) - assertImage.CanBePulledFromRegistry(repoName) - assertImage.RunsWithOutput( - repoName, - "contents-after-1", - "contents-after-2", - ) - }) - }) - }) - }) }) }) } @@ -2122,7 +1963,7 @@ func createBuilder( pack *invoke.PackInvoker, lifecycle config.LifecycleAsset, buildpackManager buildpacks.BuildpackManager, - runImageMirror string, + stack config.Stack, ) (string, error) { t.Log("creating builder image...") @@ -2132,7 +1973,9 @@ func createBuilder( defer os.RemoveAll(tmpDir) templateMapping := map[string]interface{}{ - "run_image_mirror": runImageMirror, + "build_image": stack.BuildImageName, + "run_image": stack.RunImage.Name, + "run_image_mirror": stack.RunImage.MirrorName, } // ARCHIVE BUILDPACKS From 6a02bc9e67be460949d4a6c9aff58d52edc18153 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Tue, 23 Aug 2022 08:33:28 -0500 Subject: [PATCH 10/15] make rebase tests windows compatible Signed-off-by: Javier Romero --- acceptance/tests/rebase/rebase_test.go | 42 +++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/acceptance/tests/rebase/rebase_test.go b/acceptance/tests/rebase/rebase_test.go index 28e8299f6..cf332d739 100644 --- a/acceptance/tests/rebase/rebase_test.go +++ b/acceptance/tests/rebase/rebase_test.go @@ -40,7 +40,12 @@ func test_run_image_flag(t *testing.T, th *harness.BuilderTestHarness, combo har th.ImageManager().CreateImage( originalRunImage, - runImageDockerfile(runImageName, "root", "contents-original-1", "contents-original-2"), + runImageDockerfile( + runImageName, + hostRootUser(imageManager.HostOS()), + "contents-original-1", + "contents-original-2", + ), ) pack.RunSuccessfully( @@ -64,7 +69,14 @@ func test_run_image_flag(t *testing.T, th *harness.BuilderTestHarness, combo har }) updatedRunImage := registry.RepoName("acceptance/run-image:updated" + h.RandString(10)) - imageManager.CreateImage(updatedRunImage, runImageDockerfile(runImageName, "root", "contents-updated-1", "contents-updated-2")) + imageManager.CreateImage( + updatedRunImage, + runImageDockerfile( + runImageName, + hostRootUser(imageManager.HostOS()), + "contents-updated-1", + "contents-updated-2", + )) t.Cleanup(func() { imageManager.CleanupImages(updatedRunImage) }) @@ -94,7 +106,14 @@ func test_local_config_mirror(t *testing.T, th *harness.BuilderTestHarness, comb assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) localRunImageMirror := "run-after/" + h.RandString(10) - th.ImageManager().CreateImage(localRunImageMirror, runImageDockerfile(runImageName, "root", "local-mirror-after-1", "local-mirror-after-2")) + imageManager.CreateImage( + localRunImageMirror, + runImageDockerfile( + runImageName, + hostRootUser(imageManager.HostOS()), + "local-mirror-after-1", + "local-mirror-after-2", + )) output := pack.RunSuccessfully("config", "run-image-mirrors", "add", runImageName, "-m", localRunImageMirror) t.Log(output) @@ -135,8 +154,13 @@ func test_stack_config_mirror(t *testing.T, th *harness.BuilderTestHarness, comb assertImage := assertions.NewImageAssertionManager(t, imageManager, ®istry) - // override image - th.ImageManager().CreateImage(runImageMirror, runImageDockerfile(runImageName, "root", "mirror-after-1", "mirror-after-2")) + // FIXME: we should not be overriding suite level test asset + th.ImageManager().CreateImage(runImageMirror, + runImageDockerfile(runImageName, + hostRootUser(imageManager.HostOS()), + "mirror-after-1", + "mirror-after-2", + )) t.Cleanup(func() { imageManager.CleanupImages(runImageMirror) @@ -170,3 +194,11 @@ RUN echo %s > /contents1.txt RUN echo %s > /contents2.txt USER pack`, baseRunImage, user, contents1, contents2) } + +func hostRootUser(hostOS string) string { + if hostOS == "windows" { + return "ContainerAdministrator" + } + + return "root" +} From da00a5e3c24ebff0f04c735407cfb69c94a84ac4 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Tue, 23 Aug 2022 09:52:17 -0500 Subject: [PATCH 11/15] Improve test output by including combo in test path Signed-off-by: Javier Romero --- acceptance/harness/builder_harness.go | 43 ++++++++++++++++++++------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index 473f1a822..6fc551dd0 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -22,11 +22,16 @@ import ( ) type BuilderCombo struct { + comboConfig config.RunCombo builderName string pack invoke.PackInvoker lifecycle config.LifecycleAsset } +func (b *BuilderCombo) Config() config.RunCombo { + return b.comboConfig +} + func (b *BuilderCombo) BuilderName() string { return b.builderName } @@ -39,10 +44,6 @@ func (b *BuilderCombo) Lifecycle() config.LifecycleAsset { return b.lifecycle } -func (b *BuilderCombo) String() string { - return fmt.Sprintf("builder=%s, lifecycle=%v, pack=%v", b.builderName, b.lifecycle, b.pack) -} - type BuilderTestHarness struct { t *testing.T registryConfig h.TestRegistryConfig @@ -110,6 +111,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { combos := []BuilderCombo{} for _, combo := range inputConfigManager.Combinations() { + t.Logf("creating assets for combo: %v", combo) lifecycle := assetsConfig.NewLifecycleAsset(combo.Lifecycle) pack := invoke.NewPackInvoker( t, @@ -157,6 +159,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { pack.JustRunSuccessfully("config", "default-builder", builderName) combos = append(combos, BuilderCombo{ + comboConfig: *combo, builderName: builderName, lifecycle: lifecycle, pack: *pack, @@ -180,29 +183,26 @@ func (b *BuilderTestHarness) Combinations() []BuilderCombo { func (b *BuilderTestHarness) Run(name string, test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { for _, combo := range b.combos { combo := combo - b.t.Run(name, func(t *testing.T) { + b.t.Run(runComboToPath(&combo.comboConfig)+name, func(t *testing.T) { test(t, b, combo) }) } } func (b *BuilderTestHarness) RunC(test func(combo BuilderCombo)) { - func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.Run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + b.Run(funcName(test), func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { test(combo) }) } func (b *BuilderTestHarness) RunTC(test func(t *testing.T, combo BuilderCombo)) { - func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.Run(func_name, func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { + b.Run(funcName(test), func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo) { test(t, combo) }) } func (b *BuilderTestHarness) RunA(test func(t *testing.T, th *BuilderTestHarness, combo BuilderCombo)) { - func_name := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name() - b.Run(func_name, test) + b.Run(funcName(test), test) } func (b *BuilderTestHarness) Registry() h.TestRegistryConfig { @@ -222,3 +222,24 @@ func (b *BuilderTestHarness) CleanUp() { fn() } } + +// funcName gathers the name of the given function and +// formats it to be used as part of the test path +func funcName(fn interface{}) string { + funcName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() + funcName = filepath.Base(funcName) + return funcName +} + +// runComboToPath creates a `go test` path string to use for identifying +// combination tests in test output +// +// ie: "builder:previous/lifecyle:previous/pack:current/" +func runComboToPath(combo *config.RunCombo) string { + return fmt.Sprintf( + "builder:%s/lifecyle:%s/pack:%s/", + combo.PackCreateBuilder, + combo.Lifecycle, + combo.Pack, + ) +} From f676f3dade9f040bd232c59d5df9e183e453b65f Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Wed, 24 Aug 2022 08:32:46 -0500 Subject: [PATCH 12/15] Update Makefile to execute legacy and new acceptance tests Signed-off-by: Javier Romero --- DEVELOPMENT.md | 2 +- Makefile | 14 ++--- acceptance/config/github_asset_fetcher.go | 22 ++++++-- acceptance/harness/builder_harness.go | 3 +- acceptance/harness/util.go | 23 ++++----- acceptance/invoke/pack_fixtures.go | 28 ++++++++-- acceptance/testconfig/all.json | 10 ++-- .../builder.toml | 8 +++ .../inspect_image_local_output.json | 51 +++++++++++++++++++ .../inspect_image_local_output.toml | 38 ++++++++++++++ .../inspect_image_local_output.yaml | 30 +++++++++++ 11 files changed, 197 insertions(+), 32 deletions(-) create mode 100644 acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.json create mode 100644 acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.toml create mode 100644 acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.yaml diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 61bb2c380..5df44c18f 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -68,7 +68,7 @@ make test To run our full acceptance suite (including cross-compatibility for n-1 `pack` and `lifecycle`): ```shell -make acceptance-all +make compatibility ``` ### Tidy diff --git a/Makefile b/Makefile index 651c65ecb..34d503525 100644 --- a/Makefile +++ b/Makefile @@ -109,12 +109,14 @@ unit: out acceptance: out @echo "> Running acceptance tests..." - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/... - -acceptance-all: export ACCEPTANCE_SUITE_CONFIG:=$(shell $(CAT) .$/acceptance$/testconfig$/all.json) -acceptance-all: - @echo "> Running acceptance tests..." - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/... + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/tests/build + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/tests/rebase + +compatibility: export ACCEPTANCE_SUITE_CONFIG:=$(shell $(CAT) .$/acceptance$/testconfig$/all.json) +compatibility: + @echo "> Configured acceptance tests to test compatibility..." + make acceptance clean: @echo "> Cleaning workspace..." diff --git a/acceptance/config/github_asset_fetcher.go b/acceptance/config/github_asset_fetcher.go index 3b490178e..227fc5ec5 100644 --- a/acceptance/config/github_asset_fetcher.go +++ b/acceptance/config/github_asset_fetcher.go @@ -28,7 +28,6 @@ import ( "golang.org/x/oauth2" "github.com/buildpacks/pack/pkg/blob" - "github.com/buildpacks/pack/pkg/logging" ) const ( @@ -377,7 +376,7 @@ func (f *GithubAssetFetcher) writeCacheManifest(owner, repo string, op func(cach func (f *GithubAssetFetcher) downloadAndSave(assetURI, destPath string) error { f.testObject.Helper() - downloader := blob.NewDownloader(logging.NewSimpleLogger(&testWriter{t: f.testObject}), f.cacheDir) + downloader := blob.NewDownloader(&testLogger{t: f.testObject}, f.cacheDir) assetBlob, err := downloader.Download(f.ctx, assetURI) if err != nil { @@ -406,7 +405,7 @@ func (f *GithubAssetFetcher) downloadAndSave(assetURI, destPath string) error { func (f *GithubAssetFetcher) downloadAndExtractTgz(assetURI, destDir string) error { f.testObject.Helper() - downloader := blob.NewDownloader(logging.NewSimpleLogger(&testWriter{t: f.testObject}), f.cacheDir) + downloader := blob.NewDownloader(&testLogger{t: f.testObject}, f.cacheDir) assetBlob, err := downloader.Download(f.ctx, assetURI) if err != nil { @@ -528,3 +527,20 @@ func (w *testWriter) Write(p []byte) (n int, err error) { w.t.Log(string(p)) return len(p), nil } + +// testLogger implements the logger interface for testing purposes. +type testLogger struct { + t *testing.T +} + +func (l *testLogger) Debugf(format string, args ...interface{}) { + l.t.Logf(format, args...) +} + +func (l *testLogger) Infof(format string, args ...interface{}) { + l.t.Logf(format, args...) +} + +func (l *testLogger) Writer() io.Writer { + return &testWriter{t: l.t} +} diff --git a/acceptance/harness/builder_harness.go b/acceptance/harness/builder_harness.go index 6fc551dd0..e241f87d0 100644 --- a/acceptance/harness/builder_harness.go +++ b/acceptance/harness/builder_harness.go @@ -18,6 +18,7 @@ import ( "github.com/buildpacks/pack/acceptance/config" "github.com/buildpacks/pack/acceptance/invoke" "github.com/buildpacks/pack/acceptance/managers" + "github.com/buildpacks/pack/internal/style" h "github.com/buildpacks/pack/testhelpers" ) @@ -152,7 +153,7 @@ func ContainingBuilder(t *testing.T, projectBaseDir string) BuilderTestHarness { ) assert.Nil(err) cleanups = append(cleanups, func() { - t.Log("cleaning up builder image...") + t.Logf("cleaning up builder: %s", style.Symbol(builderName)) imageManager.CleanupImages(builderName) }) diff --git a/acceptance/harness/util.go b/acceptance/harness/util.go index 2189125d5..20262097b 100644 --- a/acceptance/harness/util.go +++ b/acceptance/harness/util.go @@ -40,12 +40,6 @@ func createBuilder( assert.Nil(err) defer os.RemoveAll(tmpDir) - templateMapping := map[string]interface{}{ - "build_image": stack.BuildImageName, - "run_image": stack.RunImage.Name, - "run_image_mirror": stack.RunImage.MirrorName, - } - // ARCHIVE BUILDPACKS builderBuildpacks := []buildpacks.TestBuildpack{ buildpacks.Noop, @@ -77,8 +71,13 @@ func createBuilder( builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) - templateMapping["package_image_name"] = packageImageName - templateMapping["package_id"] = "simple/layers" + templateMapping := map[string]interface{}{ + "build_image": stack.BuildImageName, + "run_image": stack.RunImage.Name, + "run_image_mirror": stack.RunImage.MirrorName, + "package_image_name": packageImageName, + "package_id": "simple/layers", + } buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) @@ -96,11 +95,11 @@ func createBuilder( } // RENDER builder.toml - configFileName := "builder.toml" - - builderConfig := pack.FixtureManager().TemplateFixtureToFile( + builderConfig := pack.FixtureManager().TemplateVersionedFixtureToFile( tmpDir, - configFileName, + filepath.Join("%s", "builder.toml"), + pack.SanitizedVersion(), + "builder.toml", templateMapping, ) diff --git a/acceptance/invoke/pack_fixtures.go b/acceptance/invoke/pack_fixtures.go index 9cd876578..84064ce21 100644 --- a/acceptance/invoke/pack_fixtures.go +++ b/acceptance/invoke/pack_fixtures.go @@ -46,6 +46,7 @@ func (m PackFixtureManager) VersionedFixtureOrFallbackLocation(pattern, version, for _, dir := range m.locations { fixtureLocation := filepath.Join(dir, versionedName) + m.testObject.Logf("looking up possible fixture at: %s", fixtureLocation) _, err := os.Stat(fixtureLocation) if !os.IsNotExist(err) { return fixtureLocation @@ -75,13 +76,32 @@ func (m PackFixtureManager) TemplateVersionedFixture( return m.fillTemplate(outputTemplate, templateData) } +func (m PackFixtureManager) TemplateVersionedFixtureToFile( + tmpDir, versionedPattern, version, fallback string, + templateData map[string]interface{}, +) string { + m.testObject.Helper() + fixturePath := m.VersionedFixtureOrFallbackLocation(versionedPattern, version, fallback) + m.testObject.Logf("using %s for fixture %s", fixturePath, fallback) + + outputTemplate, err := ioutil.ReadFile(fixturePath) + m.assert.Nil(err) + + tmpFile, err := ioutil.TempFile(tmpDir, "*-"+fallback) + defer tmpFile.Close() + + _, err = io.WriteString(tmpFile, m.fillTemplate(outputTemplate, templateData)) + m.assert.Nil(err) + return tmpFile.Name() +} + func (m PackFixtureManager) TemplateFixtureToFile(tmpDir string, fixture string, data map[string]interface{}) string { - packageTomlFile, err := ioutil.TempFile(tmpDir, fixture+"-*") - defer packageTomlFile.Close() + tmpFile, err := ioutil.TempFile(tmpDir, fixture+"-*") + defer tmpFile.Close() - _, err = io.WriteString(packageTomlFile, m.TemplateFixture(fixture, data)) + _, err = io.WriteString(tmpFile, m.TemplateFixture(fixture, data)) m.assert.Nil(err) - return packageTomlFile.Name() + return tmpFile.Name() } func (m PackFixtureManager) fillTemplate(templateContents []byte, data map[string]interface{}) string { diff --git a/acceptance/testconfig/all.json b/acceptance/testconfig/all.json index 0238d7d02..8be5ed95e 100644 --- a/acceptance/testconfig/all.json +++ b/acceptance/testconfig/all.json @@ -1,7 +1,7 @@ [ - {"pack": "current", "pack_create_builder": "current", "lifecycle": "current"}, - {"pack": "current", "pack_create_builder": "current", "lifecycle": "previous"}, - {"pack": "current", "pack_create_builder": "previous", "lifecycle": "previous"}, - {"pack": "previous", "pack_create_builder": "current", "lifecycle": "current"}, - {"pack": "previous", "pack_create_builder": "current", "lifecycle": "previous"} + {"pack_create_builder": "current", "lifecycle": "current", "pack": "current"}, + {"pack_create_builder": "current", "lifecycle": "previous", "pack": "current"}, + {"pack_create_builder": "previous", "lifecycle": "previous", "pack": "current"}, + {"pack_create_builder": "current", "lifecycle": "current", "pack": "previous"}, + {"pack_create_builder": "current", "lifecycle": "previous", "pack": "previous"} ] \ No newline at end of file diff --git a/acceptance/testdata/pack_previous_fixtures_overrides/builder.toml b/acceptance/testdata/pack_previous_fixtures_overrides/builder.toml index afd2e7d03..de251b765 100644 --- a/acceptance/testdata/pack_previous_fixtures_overrides/builder.toml +++ b/acceptance/testdata/pack_previous_fixtures_overrides/builder.toml @@ -30,8 +30,16 @@ [stack] id = "pack.test.stack" +{{- if .build_image}} + build-image = "{{.build_image}}" +{{- else -}} build-image = "pack-test/build" +{{- end}} +{{- if .run_image}} + run-image = "{{.run_image}}" +{{- else -}} run-image = "pack-test/run" +{{- end}} run-image-mirrors = ["{{.run_image_mirror}}"] [lifecycle] diff --git a/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.json b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.json new file mode 100644 index 000000000..7cb053e5d --- /dev/null +++ b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.json @@ -0,0 +1,51 @@ +{ + "image_name": "{{.image_name}}", + "remote_info": null, + "local_info": { + "stack": "pack.test.stack", + "base_image": { + "top_layer": "{{.base_image_top_layer}}", + "reference": "{{.base_image_id}}" + }, + "run_images": [ + { + "name": "{{.run_image_local_mirror}}", + "user_configured": true + }, + { + "name": "{{.run_image}}" + }, + { + "name": "{{.run_image_mirror}}" + } + ], + "buildpacks": [ + { + "id": "simple/layers", + "version": "simple-layers-version" + } + ], + "processes": [ + { + "type": "web", + "shell": "bash", + "command": "{{ ( StringsEscapeBackslash .web_command ) }}", + "default": true, + "args": [ + "8080" + ], + "working-dir": "{{ ( StringsEscapeBackslash .image_workdir ) }}" + }, + { + "type": "hello", + "shell": "", + "command": "{{.hello_command}}", + "default": false, + "args": [ + {{ ( StringsJoin (StringsDoubleQuote .hello_args) "," ) }} + ], + "working-dir": "{{ ( StringsEscapeBackslash .image_workdir ) }}" + } + ] + } +} \ No newline at end of file diff --git a/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.toml b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.toml new file mode 100644 index 000000000..e10b49eb8 --- /dev/null +++ b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.toml @@ -0,0 +1,38 @@ +image_name = "{{.image_name}}" + +[local_info] +stack = "pack.test.stack" + + [local_info.base_image] + top_layer = "{{.base_image_top_layer}}" + reference = "{{.base_image_id}}" + + [[local_info.run_images]] + name = "{{.run_image_local_mirror}}" + user_configured = true + + [[local_info.run_images]] + name = "{{.run_image}}" + + [[local_info.run_images]] + name = "{{.run_image_mirror}}" + + [[local_info.buildpacks]] + id = "simple/layers" + version = "simple-layers-version" + + [[local_info.processes]] + type = "web" + shell = "bash" + command = "{{ ( StringsEscapeBackslash .web_command ) }}" + default = true + args = [ "8080" ] + working-dir = "{{ ( StringsEscapeBackslash .image_workdir ) }}" + + [[local_info.processes]] + type = "hello" + shell = "" + command = "{{.hello_command}}" + default = false + args = [ {{ ( StringsJoin (StringsDoubleQuote .hello_args) ",") }} ] + working-dir = "{{ ( StringsEscapeBackslash .image_workdir ) }}" diff --git a/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.yaml b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.yaml new file mode 100644 index 000000000..7fad7e313 --- /dev/null +++ b/acceptance/testdata/pack_previous_fixtures_overrides/inspect_image_local_output.yaml @@ -0,0 +1,30 @@ +--- +image_name: "{{.image_name}}" +remote_info: +local_info: + stack: pack.test.stack + base_image: + top_layer: "{{.base_image_top_layer}}" + reference: "{{.base_image_id}}" + run_images: + - name: "{{.run_image_local_mirror}}" + user_configured: true + - name: "{{.run_image}}" + - name: "{{.run_image_mirror}}" + buildpacks: + - id: simple/layers + version: simple-layers-version + processes: + - type: web + shell: bash + command: "{{ ( StringsEscapeBackslash .web_command ) }}" + default: true + args: + - '8080' + working-dir: "{{ ( StringsEscapeBackslash .image_workdir ) }}" + - type: hello + shell: '' + command: "{{.hello_command}}" + default: false + args: [ {{ ( StringsJoin (StringsDoubleQuote .hello_args) ",") }} ] + working-dir: "{{ ( StringsEscapeBackslash .image_workdir ) }}" \ No newline at end of file From 8542f6383d5c0f5b8b8ddd97b88f6bd2ca6f38e9 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Wed, 24 Aug 2022 13:15:33 -0700 Subject: [PATCH 13/15] Attempt to fix Windows CI issue Signed-off-by: Javier Romero --- acceptance/tests/build/arg_env_file_test.go | 5 +++++ acceptance/tests/build/arg_env_test.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/acceptance/tests/build/arg_env_file_test.go b/acceptance/tests/build/arg_env_file_test.go index a6e48da24..a8e54a281 100644 --- a/acceptance/tests/build/arg_env_file_test.go +++ b/acceptance/tests/build/arg_env_file_test.go @@ -22,6 +22,11 @@ func test_arg_env_file(t *testing.T, th *harness.BuilderTestHarness, combo harne pack := combo.Pack() + // mark builder as trusted + // TODO: Windows fails with "Access is denied" when builder is not trusted + pack.JustRunSuccessfully("config", "trusted-builders", "add", combo.BuilderName()) + defer pack.JustRunSuccessfully("config", "trusted-builders", "remove", combo.BuilderName()) + envfile, err := ioutil.TempFile("", "envfile") assert.Nil(err) defer envfile.Close() diff --git a/acceptance/tests/build/arg_env_test.go b/acceptance/tests/build/arg_env_test.go index a5d17d575..a2b140cf7 100644 --- a/acceptance/tests/build/arg_env_test.go +++ b/acceptance/tests/build/arg_env_test.go @@ -21,6 +21,11 @@ func test_arg_env_vars(t *testing.T, th *harness.BuilderTestHarness, combo harne pack := combo.Pack() + // mark builder as trusted + // TODO: Windows fails with "Access is denied" when builder is not trusted + pack.JustRunSuccessfully("config", "trusted-builders", "add", combo.BuilderName()) + defer pack.JustRunSuccessfully("config", "trusted-builders", "remove", combo.BuilderName()) + assert.Succeeds(os.Setenv("ENV2_CONTENTS", "Env2 Layer Contents From Environment")) t.Cleanup(func() { assert.Succeeds(os.Unsetenv("ENV2_CONTENTS")) From 4352bb68d3b026eb7499d2f147d01aab33e2a109 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Tue, 30 Aug 2022 20:28:00 -0500 Subject: [PATCH 14/15] Fix pack command detection in acceptance tests Signed-off-by: Javier Romero --- acceptance/invoke/pack.go | 39 ++++++++-- acceptance/invoke/pack_test.go | 41 +++++++++++ .../invoke/testdata/pack_build_help.txt | 73 +++++++++++++++++++ acceptance/invoke/testdata/pack_help.txt | 28 +++++++ 4 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 acceptance/invoke/pack_test.go create mode 100644 acceptance/invoke/testdata/pack_build_help.txt create mode 100644 acceptance/invoke/testdata/pack_help.txt diff --git a/acceptance/invoke/pack.go b/acceptance/invoke/pack.go index 993f26593..611780b2e 100644 --- a/acceptance/invoke/pack.go +++ b/acceptance/invoke/pack.go @@ -229,16 +229,41 @@ func (i *PackInvoker) Supports(command string) bool { output, err := i.baseCmd(cmdParts...).CombinedOutput() i.assert.Nil(err) - pattern := fmt.Sprintf(`\b%s\b`, search) + helpOutput := string(output) + if strings.Contains(helpOutput, "Unknown help topic") { + return false + } + if search[0:1] == "-" { - // flags cannot match word boundary (`\b`) at the begining - // due to them starting with a dash (`-`) - pattern = fmt.Sprintf(`%s\b`, search) + return hasFlag(helpOutput, search) + } + + return hasCommand(helpOutput, search) +} + +func hasCommand(helpOutput string, command string) bool { + + commandsSection := "" + if parts := strings.Split(helpOutput, "Available Commands:"); len(parts) > 1 { + commandsSection = parts[1] } - re := regexp.MustCompile(pattern) - help := string(output) - return re.MatchString(help) && !strings.Contains(help, "Unknown help topic") + if parts := strings.Split(commandsSection, "Flags:"); len(parts) > 1 { + commandsSection = parts[0] + } + + if commandsSection == "" { + return false + } + + expression := regexp.MustCompile(fmt.Sprintf(`\t\b%s\b`, command)) + return expression.MatchString(commandsSection) +} + +func hasFlag(helpOutput string, flag string) bool { + pattern := fmt.Sprintf(`\s%s\s`, flag) + expression := regexp.MustCompile(pattern) + return expression.MatchString(helpOutput) } type Feature int diff --git a/acceptance/invoke/pack_test.go b/acceptance/invoke/pack_test.go new file mode 100644 index 000000000..e9915be89 --- /dev/null +++ b/acceptance/invoke/pack_test.go @@ -0,0 +1,41 @@ +//go:build acceptance +// +build acceptance + +package invoke + +import ( + "io/ioutil" + "testing" + + "github.com/buildpacks/pack/testhelpers" +) + +func TestPack(t *testing.T) { + assert := testhelpers.NewAssertionManager(t) + + t.Run("hasFlag:exists", func(t *testing.T) { + packBuildHelp, err := ioutil.ReadFile("testdata/pack_build_help.txt") + assert.Nil(err) + assert.Equal(hasFlag(string(packBuildHelp), "--quiet"), true) + }) + + t.Run("hasFlag:non-existent", func(t *testing.T) { + packBuildHelp, err := ioutil.ReadFile("testdata/pack_build_help.txt") + assert.Nil(err) + assert.Equal(hasFlag(string(packBuildHelp), "--non-existent"), false) + }) + + t.Run("hasCommand:exists", func(t *testing.T) { + packHelp, err := ioutil.ReadFile("testdata/pack_help.txt") + assert.Nil(err) + assert.Equal(hasCommand(string(packHelp), "build"), true) + }) + + t.Run("hasCommand:non-existent", func(t *testing.T) { + packHelp, err := ioutil.ReadFile("testdata/pack_help.txt") + assert.Nil(err) + // we use a word that is not in the help text to + // make sure we're not just getting lucky + assert.Equal(hasCommand(string(packHelp), "building"), false) + }) +} diff --git a/acceptance/invoke/testdata/pack_build_help.txt b/acceptance/invoke/testdata/pack_build_help.txt new file mode 100644 index 000000000..c6090544e --- /dev/null +++ b/acceptance/invoke/testdata/pack_build_help.txt @@ -0,0 +1,73 @@ +Pack Build uses Cloud Native Buildpacks to create a runnable app image from source code. + +Pack Build requires an image name, which will be generated from the source code. Build defaults to the current directory, but you can use '--path' to specify another source code directory. Build requires a 'builder', which can either be provided directly to build using '--builder', or can be set using the 'set-default-builder' command. For more on how to use 'pack build', see: https://buildpacks.io/docs/app-developer-guide/build-an-app/. + +Usage: + pack build [flags] + +Examples: +pack build test_img --path apps/test-app --builder cnbs/sample-builder:bionic + +Flags: + -B, --builder string Builder image (default "paketobuildpacks/builder:tiny") + -b, --buildpack strings Buildpack to use. One of: + a buildpack by id and version in the form of '@', + path to a buildpack directory (not supported on Windows), + path/URL to a buildpack .tar or .tgz file, or + a packaged buildpack image name in the form of '/[:]' + Repeat for each buildpack in order, or supply once by comma-separated list + -r, --buildpack-registry string Buildpack Registry by name + --cache-image string Cache build layers in remote registry. Requires --publish + --clear-cache Clear image's associated cache before building + --creation-time string Desired create time in the output image config. Accepted values are Unix timestamps (e.g., '1641013200'), or 'now'. Platform API version must be at least 0.9 to use this feature. + -D, --default-process string Set the default process type. (default "web") + -d, --descriptor string Path to the project descriptor file + --docker-host string Address to docker daemon that will be exposed to the build container. + If not set (or set to empty string) the standard socket location will be used. + Special value 'inherit' may be used in which case DOCKER_HOST environment variable will be used. + This option may set DOCKER_HOST environment variable for the build container if needed. + + -e, --env stringArray Build-time environment variable, in the form 'VAR=VALUE' or 'VAR'. + When using latter value-less form, value will be taken from current + environment at the time this command is executed. + This flag may be specified multiple times and will override + individual values defined by --env-file. + Repeat for each env in order (comma-separated lists not accepted) + NOTE: These are NOT available at image runtime. + --env-file stringArray Build-time environment variables file + One variable per line, of the form 'VAR=VALUE' or 'VAR' + When using latter value-less form, value will be taken from current + environment at the time this command is executed + NOTE: These are NOT available at image runtime." + --gid int Override GID of user's group in the stack's build and run images. The provided value must be a positive number + -h, --help Help for 'build' + --interactive Launch a terminal UI to depict the build process + --lifecycle-image string Custom lifecycle image to use for analysis, restore, and export when builder is untrusted. + --network string Connect detect and build containers to network + -p, --path string Path to app dir or zip-formatted file (defaults to current working directory) + --previous-image string Set previous image to a particular tag reference, digest reference, or (when performing a daemon build) image ID + --publish Publish to registry + --pull-policy string Pull policy to use. Accepted values are always, never, and if-not-present. (default "always") + --run-image string Run image (defaults to default stack's run image) + --sbom-output-dir string Path to export SBoM contents. + Omitting the flag will yield no SBoM content. + -t, --tag strings Additional tags to push the output image to. + Tags should be in the format 'image:tag' or 'repository/image:tag'. + Repeat for each tag in order, or supply once by comma-separated list + --trust-builder Trust the provided builder + All lifecycle phases will be run in a single container (if supported by the lifecycle). + --volume stringArray Mount host volume into the build container, in the form ':[:]'. + - 'host path': Name of the volume or absolute directory path to mount. + - 'target path': The path where the file or directory is available in the container. + - 'options' (default "ro"): An optional comma separated list of mount options. + - "ro", volume contents are read-only. + - "rw", volume contents are readable and writeable. + - "volume-opt==", can be specified more than once, takes a key-value pair consisting of the option name and its value. + Repeat for each volume in order (comma-separated lists not accepted) + --workspace string Location at which to mount the app dir in the build image + +Global Flags: + --no-color Disable color output + -q, --quiet Show less output + --timestamps Enable timestamps in output + -v, --verbose Show more output \ No newline at end of file diff --git a/acceptance/invoke/testdata/pack_help.txt b/acceptance/invoke/testdata/pack_help.txt new file mode 100644 index 000000000..b2821851f --- /dev/null +++ b/acceptance/invoke/testdata/pack_help.txt @@ -0,0 +1,28 @@ +CLI for building apps using Cloud Native Buildpacks + +Usage: + pack [command] + +Available Commands: + build Generate app image from source code + builder Interact with builders + buildpack Interact with buildpacks + config Interact with your local pack config file + inspect Show information about a built app image + stack Interact with stacks + rebase Rebase app image with latest run image + sbom Interact with SBoM + completion Outputs completion script location + report Display useful information for reporting an issue + version Show current 'pack' version + help Help about any command + +Flags: + -h, --help Help for 'pack' + --no-color Disable color output + -q, --quiet Show less output + --timestamps Enable timestamps in output + -v, --verbose Show more output + --version Show current 'pack' version + +Use "pack [command] --help" for more information about a command. From 712d3379ec4e686c5f02599e4cc852f730b301c8 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Fri, 9 Sep 2022 10:29:34 -0500 Subject: [PATCH 15/15] Tests: Increase docker client timeout to enable running all acceptance tests in sequence Signed-off-by: Javier Romero --- Makefile | 4 +--- testhelpers/testhelpers.go | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 34d503525..cad6b9959 100644 --- a/Makefile +++ b/Makefile @@ -109,9 +109,7 @@ unit: out acceptance: out @echo "> Running acceptance tests..." - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/tests/build - $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/tests/rebase + $(GOCMD) test $(GOTESTFLAGS) -timeout=$(ACCEPTANCE_TIMEOUT) -tags=acceptance ./acceptance/... compatibility: export ACCEPTANCE_SUITE_CONFIG:=$(shell $(CAT) .$/acceptance$/testconfig$/all.json) compatibility: diff --git a/testhelpers/testhelpers.go b/testhelpers/testhelpers.go index 964274686..28f3ac902 100644 --- a/testhelpers/testhelpers.go +++ b/testhelpers/testhelpers.go @@ -309,7 +309,11 @@ var dockerCliErr error func dockerCli(t *testing.T) client.CommonAPIClient { dockerCliOnce.Do(func() { - dockerCliVal, dockerCliErr = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) + dockerCliVal, dockerCliErr = client.NewClientWithOpts( + client.FromEnv, + client.WithVersion("1.38"), + client.WithTimeout(60*time.Second), + ) }) AssertNil(t, dockerCliErr) return dockerCliVal