get.porter.sh/porter@v1.3.0/tests/integration/build_test.go (about)

     1  //go:build integration
     2  
     3  package integration
     4  
     5  import (
     6  	"encoding/json"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  	"testing"
    11  
    12  	"get.porter.sh/porter/pkg"
    13  	"get.porter.sh/porter/pkg/build"
    14  	"get.porter.sh/porter/pkg/cnab"
    15  	"get.porter.sh/porter/pkg/yaml"
    16  	"get.porter.sh/porter/tests"
    17  	"get.porter.sh/porter/tests/tester"
    18  	"github.com/Masterminds/semver/v3"
    19  	"github.com/stretchr/testify/require"
    20  	"github.com/uwu-tools/magex/shx"
    21  )
    22  
    23  func TestBuild(t *testing.T) {
    24  	test, err := tester.NewTest(t)
    25  	defer test.Close()
    26  	require.NoError(t, err, "test setup failed")
    27  
    28  	bunPath := filepath.Join(test.RepoRoot, "tests/testdata/mybuns/*")
    29  	require.NoError(t, shx.Copy(bunPath, test.TestDir, shx.CopyRecursive))
    30  	test.Chdir(test.TestDir)
    31  
    32  	// build the bundle
    33  	_, output := test.RequirePorter("build", "--custom", "customKey1=editedCustomValue1", "--no-lint", "--name=porter-test-build")
    34  
    35  	// Validate that the custom value defined in porter.yaml was injected into the build as a build argument
    36  	tests.RequireOutputContains(t, output, "CUSTOM_APP_VERSION=1.2.3")
    37  
    38  	// Validate that the bundle metadata contains the custom key specified by the user with --custom
    39  	bun, err := cnab.LoadBundle(test.TestContext.Context, build.LOCAL_BUNDLE)
    40  	require.NoError(t, err)
    41  	require.Equal(t, bun.Custom["customKey1"], "editedCustomValue1")
    42  
    43  }
    44  
    45  // This test uses build and the --no-lint flag, which is not a global flag defined on config.DataStore,
    46  // to validate that when a flag value is set via the configuration file, environment variable or directly with the flag
    47  // that the value binds properly to the variable.
    48  // It is a regression test for our cobra+viper configuration setup and was created in response to this regression
    49  // https://github.com/getporter/porter/issues/2735
    50  func TestBuild_ConfigureNoLintThreeWays(t *testing.T) {
    51  	test, err := tester.NewTest(t)
    52  	defer test.Close()
    53  	require.NoError(t, err, "test setup failed")
    54  
    55  	// Use a bundle that will trigger a lint error, it can only be successfully built when --no-lint is set
    56  	require.NoError(t, shx.Copy("testdata/bundles/bundle-with-lint-error/porter.yaml", test.TestDir))
    57  	test.Chdir(test.TestDir)
    58  
    59  	// Attempt to build the bundle, it should fail with a lint error
    60  	_, _, err = test.RunPorter("build")
    61  	require.ErrorContains(t, err, "lint errors were detected")
    62  
    63  	// Build the bundle and disable the linter with --no-lint
    64  	test.RequirePorter("build", "--no-lint")
    65  
    66  	// Build the bundle and disable the linter with PORTER_NO_LINT
    67  	_, _, err = test.RunPorterWith(func(cmd *shx.PreparedCommand) {
    68  		cmd.Args("build").Env("PORTER_NO_LINT=true")
    69  	})
    70  	require.NoError(t, err, "expected the build to pass when PORTER_NO_LINT=true is specified")
    71  
    72  	// Build the bundle and disable the linter with the configuration file
    73  	disableAutoBuildCfg := []byte(`no-lint: true`)
    74  	err = os.WriteFile(filepath.Join(test.PorterHomeDir, "config.yaml"), disableAutoBuildCfg, pkg.FileModeWritable)
    75  	require.NoError(t, err, "Failed to write out the porter configuration file")
    76  	test.RequirePorter("build")
    77  }
    78  
    79  func TestRebuild(t *testing.T) {
    80  	test, err := tester.NewTest(t)
    81  	defer test.Close()
    82  	require.NoError(t, err, "test setup failed")
    83  
    84  	// Create a bundle
    85  	test.Chdir(test.TestDir)
    86  	test.RequirePorter("create")
    87  
    88  	// Edit the bundle to use more than one mixin
    89  	// This helps us test that when we calculate the manifestDigest that it consistently sorts used mixins
    90  	test.EditYaml("porter.yaml", func(yq *yaml.Editor) error {
    91  		n, err := yq.GetNode("mixins")
    92  		require.NoError(t, err, "could not get mixins node for porter.yaml")
    93  		testMixin := *n.Content[0]
    94  		testMixin.Value = "testmixin"
    95  		n.Content = append(n.Content, &testMixin)
    96  		return nil
    97  	})
    98  
    99  	// Use a unique name with it so that if other tests install a newly created hello
   100  	// world bundle, they don't conflict
   101  	installationName := t.Name()
   102  
   103  	// Modify the porter.yaml to trigger a rebuild
   104  	bumpBundle := func() {
   105  		test.EditYaml("porter.yaml", func(yq *yaml.Editor) error {
   106  			orig, err := yq.GetValue("version")
   107  			require.NoError(t, err, "unable to read the bundle version from porter.yaml in order to bump it")
   108  
   109  			v, err := semver.NewVersion(orig)
   110  			require.NoErrorf(t, err, "error reading %s as a semver version", orig)
   111  
   112  			return yq.SetValue("version", v.IncPatch().String())
   113  		})
   114  	}
   115  
   116  	// Try to explain the bundle without building first, it should fail
   117  	_, output, err := test.RunPorter("explain", "--autobuild-disabled")
   118  	require.ErrorContains(t, err, "Attempted to use a bundle from source without building it first when --autobuild-disabled is set. Build the bundle and try again")
   119  	require.NotContains(t, output, "Building bundle ===>")
   120  
   121  	// Explain the bundle
   122  	_, output = test.RequirePorter("explain")
   123  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a build before explain")
   124  
   125  	// Explain the bundle a bunch more times, it should not rebuild again.
   126  	// This is a regression test for a bug where the manifest would be considered out-of-date when nothing had changed
   127  	// caused by us using a go map when comparing the mixins used in the bundle, which has inconsistent sort order...
   128  
   129  	for i := 0; i < 10; i++ {
   130  		_, output = test.RequirePorter("explain")
   131  		tests.RequireOutputContains(t, output, "Bundle is up-to-date!", "expected the previous build to be reused")
   132  	}
   133  
   134  	bumpBundle()
   135  
   136  	// Explain the bundle, with --autobuild-disabled. It should work since the bundle has been built
   137  	explainJson, output := test.RequirePorter("explain", "--autobuild-disabled", "-o=json", "--verbosity=warn")
   138  	tests.RequireOutputContains(t, output, "WARNING: The bundle is out-of-date. Skipping autobuild because --autobuild-disabled was specified")
   139  	require.NotContains(t, output, "Building bundle ===>")
   140  	// todo(kichristensen): in the future this should be improved
   141  	explainJson = strings.ReplaceAll(explainJson, "WARNING: The bundle is out-of-date. Skipping autobuild because --autobuild-disabled was specified", "")
   142  	var explainResult map[string]interface{}
   143  	err = json.Unmarshal([]byte(explainJson), &explainResult)
   144  	require.NoError(t, err, "could not marshal explain output as json")
   145  	require.Equal(t, "0.1.0", explainResult["version"], "explain should show stale output because we used --autobuild-disabled")
   146  
   147  	// Inspect the bundle
   148  	_, output = test.RequirePorter("inspect")
   149  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a build before inspect")
   150  
   151  	bumpBundle()
   152  
   153  	// Generate credentials for the bundle
   154  	_, output = test.RequirePorter("credentials", "generate", installationName)
   155  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a build before credentials generate")
   156  
   157  	bumpBundle()
   158  
   159  	// Generate parameters for the bundle
   160  	_, output = test.RequirePorter("parameters", "generate", installationName)
   161  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a build before parameters generate")
   162  
   163  	bumpBundle()
   164  
   165  	// Install the bundle
   166  	_, output = test.RequirePorter("install", installationName)
   167  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a build before install")
   168  
   169  	bumpBundle()
   170  
   171  	// Upgrade the bundle
   172  	_, output = test.RequirePorter("upgrade", installationName)
   173  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a rebuild before upgrade")
   174  
   175  	// Upgrade again, should not trigger a rebuild
   176  	_, output = test.RequirePorter("upgrade", installationName)
   177  	require.NotContains(t, output, "Building bundle ===>", "the second upgrade should not rebuild because the bundle wasn't changed")
   178  
   179  	bumpBundle()
   180  
   181  	// Uninstall the bundle
   182  	_, output = test.RequirePorter("uninstall", installationName)
   183  	tests.RequireOutputContains(t, output, "Building bundle ===>", "expected a rebuild before uninstall")
   184  }