get.porter.sh/porter@v1.3.0/tests/integration/build_integration_test.go (about) 1 //go:build integration 2 3 package integration 4 5 import ( 6 "context" 7 "encoding/json" 8 "io/fs" 9 "testing" 10 11 "get.porter.sh/porter/pkg" 12 "get.porter.sh/porter/pkg/build" 13 configadapter "get.porter.sh/porter/pkg/cnab/config-adapter" 14 "get.porter.sh/porter/pkg/config" 15 "get.porter.sh/porter/pkg/linter" 16 "get.porter.sh/porter/pkg/manifest" 17 "get.porter.sh/porter/pkg/mixin" 18 "get.porter.sh/porter/pkg/porter" 19 "get.porter.sh/porter/pkg/schema" 20 "get.porter.sh/porter/pkg/yaml" 21 "get.porter.sh/porter/tests" 22 "github.com/cnabio/cnab-go/bundle" 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func TestPorter_Build(t *testing.T) { 28 p := porter.NewTestPorter(t) 29 defer p.Close() 30 31 configTpl, err := p.Templates.GetManifest() 32 require.Nil(t, err) 33 p.TestConfig.TestContext.AddTestFileContents(configTpl, config.Name) 34 35 // Create some junk in the previous .cnab directory, build should clean it up and not copy it into the bundle 36 junkDir := ".cnab/test/junk" 37 require.NoError(t, p.FileSystem.MkdirAll(junkDir, pkg.FileModeDirectory), "could not create test junk files") 38 junkExists, _ := p.FileSystem.DirExists(junkDir) 39 assert.True(t, junkExists, "failed to create junk files for the test") 40 41 opts := porter.BuildOptions{} 42 require.NoError(t, opts.Validate(p.Porter), "Validate failed") 43 44 err = p.Build(context.Background(), opts) 45 require.NoError(t, err) 46 47 // Check file permissions on .cnab contents 48 bundleJSONStats, err := p.FileSystem.Stat(build.LOCAL_BUNDLE) 49 require.NoError(t, err) 50 tests.AssertFilePermissionsEqual(t, build.LOCAL_BUNDLE, pkg.FileModeWritable, bundleJSONStats.Mode()) 51 52 runStats, err := p.FileSystem.Stat(build.LOCAL_RUN) 53 require.NoError(t, err) 54 tests.AssertFilePermissionsEqual(t, build.LOCAL_RUN, pkg.FileModeExecutable, runStats.Mode()) 55 56 manifestStats, err := p.FileSystem.Stat(build.LOCAL_MANIFEST) 57 require.NoError(t, err) 58 tests.AssertFilePermissionsEqual(t, build.LOCAL_MANIFEST, pkg.FileModeWritable, manifestStats.Mode()) 59 60 err = p.FileSystem.Walk(build.LOCAL_MIXINS, func(path string, info fs.FileInfo, err error) error { 61 if err != nil { 62 return err 63 } 64 if info.IsDir() { 65 return nil 66 } 67 68 tests.AssertFilePermissionsEqual(t, path, pkg.FileModeExecutable, runStats.Mode()) 69 return nil 70 }) 71 require.NoError(t, err) 72 73 // Check that the junk files were cleaned up 74 junkExists, _ = p.FileSystem.DirExists(junkDir) 75 assert.False(t, junkExists, "junk files were not cleaned up before building") 76 77 bun, err := p.CNAB.LoadBundle(build.LOCAL_BUNDLE) 78 require.NoError(t, err) 79 80 assert.Equal(t, "porter-hello", bun.Name) 81 assert.Equal(t, "1.2.0", string(bun.SchemaVersion)) 82 assert.Equal(t, "0.1.0", bun.Version) 83 assert.Equal(t, "An example Porter configuration", bun.Description) 84 85 stamp, err := configadapter.LoadStamp(bun) 86 require.NoError(t, err) 87 assert.NotEmpty(t, stamp.ManifestDigest) 88 89 debugParam, ok := bun.Parameters["porter-debug"] 90 require.True(t, ok, "porter-debug parameter was not defined") 91 assert.Equal(t, "PORTER_DEBUG", debugParam.Destination.EnvironmentVariable) 92 debugDef, ok := bun.Definitions[debugParam.Definition] 93 require.True(t, ok, "porter-debug definition was not defined") 94 assert.Equal(t, "boolean", debugDef.Type) 95 assert.Equal(t, false, debugDef.Default) 96 } 97 98 func TestPorter_Build_ChecksManifestSchemaVersion(t *testing.T) { 99 testcases := []struct { 100 name string 101 schemaVersion string 102 wantErr string 103 }{ 104 {name: "current version", schemaVersion: manifest.DefaultSchemaVersion.String()}, 105 {name: "its an older code but it checks out", schemaVersion: "1.0.0-alpha.1"}, 106 {name: "invalid version", schemaVersion: "", wantErr: schema.ErrInvalidSchemaVersion.Error()}, 107 } 108 for _, tc := range testcases { 109 t.Run(tc.name, func(t *testing.T) { 110 p := porter.NewTestPorter(t) 111 defer p.Close() 112 113 // Make a bundle with the specified schemaVersion 114 p.TestConfig.TestContext.AddTestDirectoryFromRoot("tests/testdata/mybuns", "/") 115 e := yaml.NewEditor(p.FileSystem) 116 require.NoError(t, e.ReadFile("porter.yaml")) 117 require.NoError(t, e.SetValue("schemaVersion", tc.schemaVersion)) 118 require.NoError(t, e.WriteFile("porter.yaml")) 119 120 opts := porter.BuildOptions{} 121 opts.File = "porter.yaml" 122 err := p.Build(context.Background(), opts) 123 if tc.wantErr == "" { 124 require.NoError(t, err) 125 } else { 126 require.ErrorIs(t, err, schema.ErrInvalidSchemaVersion) 127 tests.RequireErrorContains(t, err, tc.wantErr) 128 } 129 }) 130 } 131 } 132 133 func TestPorter_LintDuringBuild(t *testing.T) { 134 lintResults := linter.Results{ 135 { 136 Level: linter.LevelError, 137 Code: "exec-100", 138 }, 139 } 140 141 t.Run("failing lint should stop build", func(t *testing.T) { 142 p := porter.NewTestPorter(t) 143 defer p.Close() 144 145 testMixins := p.Mixins.(*mixin.TestMixinProvider) 146 testMixins.LintResults = lintResults 147 148 err := p.Create() 149 require.NoError(t, err, "Create failed") 150 151 opts := porter.BuildOptions{NoLint: false} 152 err = opts.Validate(p.Porter) 153 require.NoError(t, err) 154 155 err = p.Build(context.Background(), opts) 156 require.Errorf(t, err, "Build should have been aborted with lint errors") 157 assert.Contains(t, err.Error(), "lint errors were detected") 158 }) 159 160 t.Run("ignores lint error with --no-lint", func(t *testing.T) { 161 p := porter.NewTestPorter(t) 162 defer p.Close() 163 164 testMixins := p.Mixins.(*mixin.TestMixinProvider) 165 testMixins.LintResults = lintResults 166 167 err := p.Create() 168 require.NoError(t, err, "Create failed") 169 170 opts := porter.BuildOptions{NoLint: true} 171 err = opts.Validate(p.Porter) 172 require.NoError(t, err) 173 174 err = p.Build(context.Background(), opts) 175 require.NoError(t, err, "Build failed but should have not run lint") 176 }) 177 178 } 179 180 func TestPorter_paramRequired(t *testing.T) { 181 p := porter.NewTestPorter(t) 182 defer p.Close() 183 184 p.TestConfig.TestContext.AddTestFile("./testdata/paramafest.yaml", config.Name) 185 186 ctx := context.Background() 187 opts := porter.BuildOptions{} 188 require.NoError(t, opts.Validate(p.Porter), "Validate failed") 189 190 err := p.Build(ctx, opts) 191 192 bundleBytes, err := p.FileSystem.ReadFile(build.LOCAL_BUNDLE) 193 require.NoError(t, err) 194 195 var bundle bundle.Bundle 196 err = json.Unmarshal(bundleBytes, &bundle) 197 require.NoError(t, err) 198 199 require.False(t, bundle.Parameters["command"].Required, "expected command param to not be required") 200 require.True(t, bundle.Parameters["command2"].Required, "expected command2 param to be required") 201 } 202 203 func TestBuildOptions_Validate(t *testing.T) { 204 p := porter.NewTestPorter(t) 205 defer p.Close() 206 207 p.TestConfig.TestContext.AddTestFile("./testdata/porter.yaml", config.Name) 208 209 testcases := []struct { 210 name string 211 opts porter.BuildOptions 212 wantDriver string 213 wantError string 214 }{{ 215 name: "no opts", 216 opts: porter.BuildOptions{}, 217 wantDriver: config.BuildDriverBuildkit, 218 }, { 219 name: "invalid version set - latest", 220 opts: porter.BuildOptions{MetadataOpts: porter.MetadataOpts{Version: "latest"}}, 221 wantError: `invalid bundle version: "latest" is not a valid semantic version`, 222 }, { 223 name: "valid version - v prefix", 224 opts: porter.BuildOptions{MetadataOpts: porter.MetadataOpts{Version: "v1.0.0"}}, 225 }, { 226 name: "valid version - with hash", 227 opts: porter.BuildOptions{MetadataOpts: porter.MetadataOpts{Version: "v0.1.7+58d98af56c3a4c40c69535654216bd4a1fa701e7"}}, 228 }, { 229 name: "valid name and value set", 230 opts: porter.BuildOptions{MetadataOpts: porter.MetadataOpts{Name: "newname", Version: "1.0.0"}}, 231 }, { 232 name: "deprecated driver: docker", 233 opts: porter.BuildOptions{Driver: config.BuildDriverDocker}, 234 wantError: `invalid --driver value docker`, 235 }, { 236 name: "valid driver: buildkit", 237 opts: porter.BuildOptions{Driver: config.BuildDriverBuildkit}, 238 wantDriver: config.BuildDriverBuildkit, 239 }, { 240 name: "invalid driver", 241 opts: porter.BuildOptions{Driver: "missing-driver"}, 242 wantError: `invalid --driver value missing-driver`, 243 }} 244 245 for _, tc := range testcases { 246 t.Run(tc.name, func(t *testing.T) { 247 err := tc.opts.Validate(p.Porter) 248 if tc.wantError != "" { 249 require.EqualError(t, err, tc.wantError) 250 } else { 251 require.NoError(t, err) 252 253 if tc.wantDriver != "" { 254 assert.Equal(t, tc.wantDriver, p.Data.BuildDriver) 255 } 256 } 257 }) 258 } 259 } 260 261 func TestBuildOptions_Defaults(t *testing.T) { 262 p := porter.NewTestPorter(t) 263 defer p.Close() 264 265 p.TestConfig.TestContext.AddTestFile("./testdata/porter.yaml", config.Name) 266 267 t.Run("default driver", func(t *testing.T) { 268 opts := porter.BuildOptions{} 269 err := opts.Validate(p.Porter) 270 require.NoError(t, err, "Validate failed") 271 assert.Equal(t, config.BuildDriverBuildkit, opts.Driver) 272 }) 273 } 274 275 func TestPorter_BuildWithCustomValues(t *testing.T) { 276 p := porter.NewTestPorter(t) 277 defer p.Close() 278 279 p.TestConfig.TestContext.AddTestFile("./testdata/porter.yaml", config.Name) 280 281 ctx := context.Background() 282 283 opts := porter.BuildOptions{Customs: []string{"customKey1=editedCustomValue1"}} 284 require.NoError(t, opts.Validate(p.Porter), "Validate failed") 285 286 err := p.Build(ctx, opts) 287 require.NoError(t, err) 288 289 bun, err := p.CNAB.LoadBundle(build.LOCAL_BUNDLE) 290 require.NoError(t, err) 291 292 assert.Equal(t, bun.Custom["customKey1"], "editedCustomValue1") 293 } 294 295 func TestPorter_BuildWithPreserveTags(t *testing.T) { 296 p := porter.NewTestPorter(t) 297 defer p.Close() 298 299 p.TestConfig.TestContext.AddTestFile("./testdata/porter-with-image-tag.yaml", config.Name) 300 301 ctx := context.Background() 302 opts := porter.BuildOptions{ 303 BundleDefinitionOptions: porter.BundleDefinitionOptions{ 304 PreserveTags: true, 305 }, 306 } 307 require.NoError(t, opts.Validate(p.Porter), "Validate failed") 308 309 err := p.Build(ctx, opts) 310 require.NoError(t, err) 311 312 bun, err := p.CNAB.LoadBundle(build.LOCAL_BUNDLE) 313 require.NoError(t, err) 314 315 stamp, err := configadapter.LoadStamp(bun) 316 require.NoError(t, err) 317 assert.Equal(t, stamp.PreserveTags, true) 318 assert.Empty(t, bun.Images["something"].Digest) 319 }