get.porter.sh/porter@v1.3.0/pkg/porter/lifecycle_test.go (about) 1 package porter 2 3 import ( 4 "context" 5 "io" 6 "runtime" 7 "sort" 8 "testing" 9 10 "get.porter.sh/porter/pkg" 11 "get.porter.sh/porter/pkg/cnab" 12 configadapter "get.porter.sh/porter/pkg/cnab/config-adapter" 13 cnabprovider "get.porter.sh/porter/pkg/cnab/provider" 14 "get.porter.sh/porter/pkg/config" 15 "get.porter.sh/porter/pkg/manifest" 16 "get.porter.sh/porter/pkg/secrets" 17 "get.porter.sh/porter/pkg/storage" 18 "get.porter.sh/porter/tests" 19 "github.com/cnabio/cnab-go/secrets/host" 20 "github.com/cnabio/cnab-to-oci/relocation" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 ) 24 25 var ( 26 kahnlatest = cnab.MustParseOCIReference("deislabs/kubekahn:latest") 27 ) 28 29 func TestInstallFromTagIgnoresCurrentBundle(t *testing.T) { 30 p := NewTestPorter(t) 31 defer p.Close() 32 33 err := p.Create() 34 require.NoError(t, err) 35 36 installOpts := NewInstallOptions() 37 installOpts.Reference = "mybun:1.0" 38 39 err = installOpts.Validate(context.Background(), []string{}, p.Porter) 40 require.NoError(t, err) 41 42 assert.Empty(t, installOpts.File, "The install should ignore the bundle in the current directory because we are installing from a tag") 43 } 44 45 func TestPorter_BuildActionArgs(t *testing.T) { 46 ctx := context.Background() 47 48 t.Run("no bundle set", func(t *testing.T) { 49 p := NewTestPorter(t) 50 defer p.Close() 51 opts := NewInstallOptions() 52 opts.Name = "mybuns" 53 54 err := opts.Validate(ctx, nil, p.Porter) 55 require.Error(t, err, "Validate should fail") 56 assert.Contains(t, err.Error(), "No bundle specified") 57 }) 58 59 t.Run("porter.yaml set", func(t *testing.T) { 60 p := NewTestPorter(t) 61 defer p.Close() 62 63 opts := NewInstallOptions() 64 opts.File = "porter.yaml" 65 p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", "porter.yaml") 66 p.TestConfig.TestContext.AddTestFile("testdata/bundle.json", ".cnab/bundle.json") 67 68 // pretend that we've resolved the parameters 69 opts.finalParams = map[string]interface{}{} 70 71 err := opts.Validate(ctx, nil, p.Porter) 72 require.NoError(t, err, "Validate failed") 73 args, err := p.BuildActionArgs(ctx, storage.Installation{}, opts) 74 require.NoError(t, err, "BuildActionArgs failed") 75 76 assert.NotEmpty(t, args.BundleReference.Definition) 77 }) 78 79 // Just do a quick check that things are populated correctly when a bundle.json is passed 80 t.Run("bundle.json set", func(t *testing.T) { 81 p := NewTestPorter(t) 82 opts := NewInstallOptions() 83 opts.CNABFile = "/bundle.json" 84 p.TestConfig.TestContext.AddTestFile("testdata/bundle.json", "/bundle.json") 85 86 // pretend that we've resolved the parameters 87 opts.finalParams = map[string]interface{}{} 88 89 err := opts.Validate(ctx, nil, p.Porter) 90 require.NoError(t, err, "Validate failed") 91 args, err := p.BuildActionArgs(ctx, storage.Installation{}, opts) 92 require.NoError(t, err, "BuildActionArgs failed") 93 94 assert.NotEmpty(t, args.BundleReference.Definition, "BundlePath was not populated correctly") 95 }) 96 97 t.Run("remaining fields", func(t *testing.T) { 98 p := NewTestPorter(t) 99 p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", "porter.yaml") 100 p.TestConfig.TestContext.AddTestFileFromRoot("pkg/runtime/testdata/relocation-mapping.json", "relocation-mapping.json") 101 p.TestCredentials.AddTestCredentials("testdata/test-creds/mycreds.yaml") 102 103 opts := InstallOptions{ 104 BundleExecutionOptions: &BundleExecutionOptions{ 105 AllowDockerHostAccess: true, 106 DebugMode: true, 107 Params: []string{ 108 "my-first-param=1", 109 }, 110 ParameterSets: []string{ 111 "porter-hello", 112 }, 113 CredentialIdentifiers: []string{ 114 "mycreds", 115 }, 116 Driver: "docker", 117 BundleReferenceOptions: &BundleReferenceOptions{ 118 installationOptions: installationOptions{ 119 BundleDefinitionOptions: BundleDefinitionOptions{ 120 RelocationMapping: "relocation-mapping.json", 121 File: config.Name, 122 }, 123 Name: "MyInstallation", 124 }, 125 }, 126 }, 127 } 128 p.TestParameters.AddSecret("PARAM2_SECRET", "VALUE2") 129 p.TestParameters.AddTestParameters("testdata/paramset2.json") 130 131 err := opts.Validate(ctx, nil, p.Porter) 132 require.NoError(t, err, "Validate failed") 133 existingInstall := storage.NewInstallation(opts.Namespace, opts.Name) 134 135 // resolve the parameters before building the action options to use for running the bundle 136 err = p.applyActionOptionsToInstallation(ctx, opts, &existingInstall) 137 require.NoError(t, err) 138 139 args, err := p.BuildActionArgs(ctx, existingInstall, opts) 140 require.NoError(t, err, "BuildActionArgs failed") 141 142 assert.Equal(t, opts.AllowDockerHostAccess, args.AllowDockerHostAccess, "AllowDockerHostAccess not populated correctly") 143 assert.Equal(t, opts.Driver, args.Driver, "Driver not populated correctly") 144 assert.NotEmpty(t, args.Installation, "Installation not populated") 145 wantReloMap := relocation.ImageRelocationMap{"gabrtv/microservice@sha256:cca460afa270d4c527981ef9ca4989346c56cf9b20217dcea37df1ece8120687": "my.registry/microservice@sha256:cca460afa270d4c527981ef9ca4989346c56cf9b20217dcea37df1ece8120687"} 146 assert.Equal(t, wantReloMap, args.BundleReference.RelocationMap, "RelocationMapping not populated correctly") 147 }) 148 } 149 150 func TestManifestIgnoredWithTag(t *testing.T) { 151 p := NewTestPorter(t) 152 defer p.Close() 153 154 t.Run("ignore manifest in cwd if tag present", func(t *testing.T) { 155 opts := BundleReferenceOptions{} 156 opts.Reference = "deislabs/kubekahn:latest" 157 158 // `path.Join(wd...` -> makes cnab.go#defaultBundleFiles#manifestExists `true` 159 // Only when `manifestExists` eq to `true`, default bundle logic will run 160 require.NoError(t, p.TestConfig.TestContext.AddTestFileContents([]byte(""), config.Name)) 161 // When execution reach to `readFromFile`, manifest file path will be lost. 162 // So, had to use root manifest file also for error simulation purpose 163 require.NoError(t, p.TestConfig.TestContext.AddTestFileContents([]byte(""), config.Name)) 164 165 err := opts.Validate(context.Background(), nil, p.Porter) 166 require.NoError(t, err, "Validate failed") 167 }) 168 } 169 170 func TestBundleActionOptions_Validate(t *testing.T) { 171 t.Run("driver flag unset", func(t *testing.T) { 172 p := NewTestPorter(t) 173 p.DataLoader = config.LoadFromEnvironment() 174 require.NoError(t, p.FileSystem.WriteFile("/home/myuser/.porter/config.yaml", []byte("runtime-driver: kubernetes"), pkg.FileModeWritable)) 175 ctx, err := p.Connect(context.Background()) 176 require.NoError(t, err) 177 178 opts := NewInstallOptions() 179 opts.Reference = "ghcr.io/getporter/examples/porter-hello:v0.2.0" 180 require.NoError(t, opts.Validate(ctx, nil, p.Porter)) 181 assert.Equal(t, "kubernetes", opts.Driver) 182 }) 183 t.Run("driver flag set", func(t *testing.T) { 184 p := NewTestPorter(t) 185 p.DataLoader = config.LoadFromEnvironment() 186 require.NoError(t, p.FileSystem.WriteFile("/home/myuser/.porter/config.yaml", []byte("driver: kubernetes"), pkg.FileModeWritable)) 187 ctx, err := p.Connect(context.Background()) 188 require.NoError(t, err) 189 190 opts := NewInstallOptions() 191 opts.Driver = "docker" 192 opts.Reference = "ghcr.io/getporter/examples/porter-hello:v0.2.0" 193 require.NoError(t, opts.Validate(ctx, nil, p.Porter)) 194 assert.Equal(t, "docker", opts.Driver) 195 }) 196 } 197 198 func TestBundleExecutionOptions_defaultDriver(t *testing.T) { 199 t.Run("no driver specified", func(t *testing.T) { 200 p := NewTestPorter(t) 201 defer p.Close() 202 203 opts := NewBundleExecutionOptions() 204 205 opts.defaultDriver(p.Porter) 206 207 assert.Equal(t, "docker", opts.Driver, "expected the driver value to default to docker") 208 }) 209 210 t.Run("driver flag set", func(t *testing.T) { 211 p := NewTestPorter(t) 212 defer p.Close() 213 214 opts := NewBundleExecutionOptions() 215 opts.Driver = "kubernetes" 216 217 opts.defaultDriver(p.Porter) 218 219 assert.Equal(t, "kubernetes", opts.Driver, "expected the --driver flag value to be used") 220 }) 221 222 t.Run("allow docker host access defaults to config", func(t *testing.T) { 223 p := NewTestPorter(t) 224 defer p.Close() 225 p.Config.Data.AllowDockerHostAccess = true 226 227 opts := NewBundleExecutionOptions() 228 229 opts.defaultDriver(p.Porter) 230 231 assert.True(t, opts.AllowDockerHostAccess, "expected allow-docker-host-access to inherit the value from the config file when the flag isn't specified") 232 }) 233 234 t.Run("allow docker host access flag set", func(t *testing.T) { 235 p := NewTestPorter(t) 236 defer p.Close() 237 p.Config.Data.AllowDockerHostAccess = false 238 239 opts := NewBundleExecutionOptions() 240 opts.AllowDockerHostAccess = true 241 242 opts.defaultDriver(p.Porter) 243 244 assert.True(t, opts.AllowDockerHostAccess, "expected allow-docker-host-access to use the flag value when specified") 245 }) 246 247 } 248 249 func TestBundleExecutionOptions_ParseParamSets(t *testing.T) { 250 p := NewTestPorter(t) 251 defer p.Close() 252 253 p.AddTestFile("testdata/porter.yaml", "porter.yaml") 254 p.TestParameters.AddSecret("foo_secret", "foo_value") 255 p.TestParameters.AddSecret("PARAM2_SECRET", "VALUE2") 256 p.TestParameters.AddTestParameters("testdata/paramset2.json") 257 258 ctx := context.Background() 259 m, err := manifest.LoadManifestFrom(ctx, p.Config, config.Name) 260 require.NoError(t, err) 261 bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m) 262 require.NoError(t, err) 263 264 opts := NewUpgradeOptions() 265 opts.ParameterSets = []string{"porter-hello"} 266 opts.bundleRef = &cnab.BundleReference{Definition: bun} 267 268 err = opts.Validate(ctx, []string{}, p.Porter) 269 assert.NoError(t, err) 270 271 inst := storage.NewInstallation("", "mybuns") 272 err = p.applyActionOptionsToInstallation(ctx, opts, &inst) 273 require.NoError(t, err) 274 275 wantParams := map[string]interface{}{ 276 "my-second-param": "VALUE2", 277 "porter-debug": false, 278 "porter-state": nil, 279 } 280 assert.Equal(t, wantParams, opts.GetParameters(), "resolved unexpected parameter values") 281 } 282 283 func TestBundleExecutionOptions_ParseParamSets_Failed(t *testing.T) { 284 p := NewTestPorter(t) 285 defer p.Close() 286 287 p.TestConfig.TestContext.AddTestFile("testdata/porter-with-file-param.yaml", config.Name) 288 p.TestConfig.TestContext.AddTestFile("testdata/paramset-with-file-param.json", "/paramset.json") 289 290 ctx := context.Background() 291 m, err := manifest.LoadManifestFrom(ctx, p.Config, config.Name) 292 require.NoError(t, err) 293 bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m) 294 require.NoError(t, err) 295 296 opts := NewInstallOptions() 297 opts.ParameterSets = []string{ 298 "/paramset.json", 299 } 300 opts.bundleRef = &cnab.BundleReference{Definition: bun} 301 302 err = opts.Validate(ctx, []string{}, p.Porter) 303 assert.NoError(t, err) 304 305 inst := storage.NewInstallation("myns", "mybuns") 306 307 err = p.applyActionOptionsToInstallation(ctx, opts, &inst) 308 tests.RequireErrorContains(t, err, "/paramset.json not found", "Porter no longer supports passing a parameter set file to the -p flag, validate that passing a file doesn't work") 309 } 310 311 // Validate that when an installation is run with a mix of overrides and parameter sets 312 // that it follows the rules for the paramter hierarchy 313 // highest -> lowest preceence 314 // - user override 315 // - previous value from last run 316 // - value resolved from a named parameter set 317 // - default value of the parameter 318 func TestPorter_applyActionOptionsToInstallation_FollowsParameterHierarchy(t *testing.T) { 319 t.Parallel() 320 321 p := NewTestPorter(t) 322 defer p.Close() 323 ctx := context.Background() 324 325 p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", config.Name) 326 m, err := manifest.LoadManifestFrom(context.Background(), p.Config, config.Name) 327 require.NoError(t, err) 328 bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m) 329 require.NoError(t, err) 330 331 err = p.TestParameters.InsertParameterSet(ctx, storage.NewParameterSet("", "myps", 332 storage.ValueStrategy("my-second-param", "via_paramset"))) 333 require.NoError(t, err, "Create my-second-param parameter set failed") 334 335 makeOpts := func() InstallOptions { 336 opts := NewInstallOptions() 337 opts.BundleReferenceOptions.bundleRef = &cnab.BundleReference{ 338 Reference: kahnlatest, 339 Definition: bun, 340 } 341 return opts 342 } 343 344 t.Run("no override present, no parameter set present", func(t *testing.T) { 345 i := storage.NewInstallation("", bun.Name) 346 opts := makeOpts() 347 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 348 require.NoError(t, err) 349 350 finalParams := opts.GetParameters() 351 wantParams := map[string]interface{}{ 352 "my-first-param": 9, 353 "my-second-param": "spring-music-demo", 354 "porter-debug": false, 355 "porter-state": nil, 356 } 357 assert.Equal(t, wantParams, finalParams, 358 "expected combined params to have the default parameter values from the bundle") 359 }) 360 361 t.Run("override present, no parameter set present", func(t *testing.T) { 362 i := storage.NewInstallation("", bun.Name) 363 opts := makeOpts() 364 opts.Params = []string{"my-second-param=cli_override"} 365 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 366 require.NoError(t, err) 367 368 finalParams := opts.GetParameters() 369 require.Contains(t, finalParams, "my-second-param", 370 "expected my-second-param to be a parameter") 371 require.Equal(t, "cli_override", finalParams["my-second-param"], 372 "expected param 'my-second-param' to be set with the override specified by the user") 373 }) 374 375 t.Run("no override present, parameter set present", func(t *testing.T) { 376 i := storage.NewInstallation("", bun.Name) 377 opts := makeOpts() 378 opts.ParameterSets = []string{"myps"} 379 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 380 require.NoError(t, err) 381 382 finalParams := opts.GetParameters() 383 require.Contains(t, finalParams, "my-second-param", 384 "expected my-second-param to be a parameter") 385 require.Equal(t, finalParams["my-second-param"], "via_paramset", 386 "expected param 'my-second-param' to be set with the value from the parameter set") 387 }) 388 389 t.Run("override present, parameter set present", func(t *testing.T) { 390 i := storage.NewInstallation("", bun.Name) 391 opts := makeOpts() 392 opts.Params = []string{"my-second-param=cli_override"} 393 opts.ParameterSets = []string{"myps"} 394 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 395 require.NoError(t, err) 396 397 finalParams := opts.GetParameters() 398 require.Contains(t, finalParams, "my-second-param", 399 "expected my-second-param to be a parameter") 400 require.Equal(t, finalParams["my-second-param"], "cli_override", 401 "expected param 'my-second-param' to be set with the value of the user override, which has precedence over the parameter set value") 402 }) 403 404 t.Run("debug mode on", func(t *testing.T) { 405 i := storage.NewInstallation("", bun.Name) 406 opts := makeOpts() 407 opts.DebugMode = true 408 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 409 require.NoError(t, err) 410 411 finalParams := opts.GetParameters() 412 debugParam, ok := finalParams["porter-debug"] 413 require.True(t, ok, "expected porter-debug to be set") 414 require.Equal(t, true, debugParam, "expected porter-debug to be true") 415 }) 416 } 417 418 // Validate that when we resolve parameters on an installation that sensitive parameters are 419 // not persisted on the installation record and instead are referenced by a secret 420 func TestPorter_applyActionOptionsToInstallation_sanitizesParameters(t *testing.T) { 421 p := NewTestPorter(t) 422 defer p.Close() 423 424 ctx := context.Background() 425 426 p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", config.Name) 427 m, err := manifest.LoadManifestFrom(context.Background(), p.Config, config.Name) 428 require.NoError(t, err) 429 bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m) 430 require.NoError(t, err) 431 432 sensitiveParamName := "my-second-param" 433 sensitiveParamValue := "2" 434 nonsensitiveParamName := "my-first-param" 435 nonsensitiveParamValue := "1" 436 opts := NewInstallOptions() 437 opts.BundleReferenceOptions.bundleRef = &cnab.BundleReference{ 438 Reference: kahnlatest, 439 Definition: bun, 440 } 441 opts.Params = []string{nonsensitiveParamName + "=" + nonsensitiveParamValue, sensitiveParamName + "=" + sensitiveParamValue} 442 443 i := storage.NewInstallation("", bun.Name) 444 445 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 446 require.NoError(t, err) 447 require.Len(t, i.Parameters.Parameters, 2) 448 449 // there should be no sensitive value on installation record 450 for _, param := range i.Parameters.Parameters { 451 if param.Name == sensitiveParamName { 452 require.Equal(t, param.Source.Strategy, secrets.SourceSecret) 453 require.NotEqual(t, param.Source.Hint, sensitiveParamValue) 454 continue 455 } 456 require.Equal(t, param.Source.Strategy, host.SourceValue) 457 require.Equal(t, param.Source.Hint, nonsensitiveParamValue) 458 } 459 460 // When no parameter override specified, installation record should be updated 461 // as well 462 opts = NewInstallOptions() 463 opts.BundleReferenceOptions.bundleRef = &cnab.BundleReference{ 464 Reference: kahnlatest, 465 Definition: bun, 466 } 467 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 468 require.NoError(t, err) 469 470 // Check that when no parameter overrides are specified, we use the originally specified parameters from the previous run 471 sort.Sort(i.Parameters.Parameters) 472 require.Len(t, i.Parameters.Parameters, 2) 473 require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name) 474 require.Equal(t, "1", i.Parameters.Parameters[0].Source.Hint) 475 require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name) 476 require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Strategy) 477 } 478 479 // When the installation has been used before with a parameter value 480 // the previous param value should be updated and the other previous values 481 // that were not set this time around should be re-used. 482 // i.e. you should be able to run 483 // porter install --param logLevel=debug --param featureA=enabled 484 // porter upgrade --param logLevel=info 485 // and when upgrade is run, the old value for featureA is kept 486 func TestPorter_applyActionOptionsToInstallation_PreservesExistingParams(t *testing.T) { 487 p := NewTestPorter(t) 488 defer p.Close() 489 490 ctx := context.Background() 491 492 p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", config.Name) 493 m, err := manifest.LoadManifestFrom(context.Background(), p.Config, config.Name) 494 require.NoError(t, err) 495 bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m) 496 require.NoError(t, err) 497 498 nonsensitiveParamName := "my-first-param" 499 nonsensitiveParamValue := "3" 500 opts := NewUpgradeOptions() 501 opts.BundleReferenceOptions.bundleRef = &cnab.BundleReference{ 502 Reference: kahnlatest, 503 Definition: bun, 504 } 505 opts.Params = []string{nonsensitiveParamName + "=" + nonsensitiveParamValue} 506 507 i := storage.NewInstallation("", bun.Name) 508 i.Parameters = storage.NewParameterSet("", "internal-ps", 509 storage.ValueStrategy("my-first-param", "1"), 510 storage.ValueStrategy("my-second-param", "2"), 511 ) 512 513 err = p.applyActionOptionsToInstallation(ctx, opts, &i) 514 require.NoError(t, err) 515 require.Len(t, i.Parameters.Parameters, 2) 516 517 // Check that overrides are applied on top of existing parameters 518 require.Len(t, i.Parameters.Parameters, 2) 519 require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name) 520 require.Equal(t, "value", i.Parameters.Parameters[0].Source.Strategy, "my-first-param isn't sensitive and can be stored in a hard-coded value") 521 require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name) 522 require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Strategy, "my-second-param should be stored on the installation using a secret since it's sensitive") 523 524 // Check the values stored are correct 525 params, err := p.Parameters.ResolveAll(ctx, i.Parameters, i.Parameters.Keys()) 526 require.NoError(t, err, "Failed to resolve the installation parameters") 527 require.Equal(t, secrets.Set{ 528 "my-first-param": "3", // Should have used the override 529 "my-second-param": "2", // Should have kept the existing value from the last run 530 }, params, "Incorrect parameter values were persisted on the installationß") 531 } 532 533 func Test_ensureVPrefix(t *testing.T) { 534 ref, err := cnab.ParseOCIReference("registry/bundle:1.2.3") 535 require.NoError(t, err) 536 537 testCases := []struct { 538 name string 539 reference string 540 ref *cnab.OCIReference 541 want string 542 wantRefTag string 543 }{ 544 { 545 name: "adds v prefix to semver reference", 546 reference: "registry/bundle:1.2.3", 547 ref: nil, 548 want: "registry/bundle:v1.2.3", 549 }, 550 { 551 name: "updates _ref if present", 552 reference: "registry/bundle:1.2.3", 553 ref: &ref, 554 want: "registry/bundle:v1.2.3", 555 wantRefTag: "v1.2.3", 556 }, 557 { 558 name: "is idempotent", 559 reference: "registry/bundle:v1.2.3", 560 ref: nil, 561 want: "registry/bundle:v1.2.3", 562 }, 563 { 564 name: "ignores non-semver references", 565 reference: "registry/bundle:latest", 566 ref: nil, 567 want: "registry/bundle:latest", 568 }, 569 { 570 name: "ignores references with no tag", 571 reference: "registry/bundle", 572 ref: nil, 573 want: "registry/bundle", 574 }, 575 } 576 577 for _, tc := range testCases { 578 t.Run(tc.name, func(t *testing.T) { 579 opts := BundleReferenceOptions{ 580 installationOptions: installationOptions{}, 581 BundlePullOptions: BundlePullOptions{ 582 Reference: tc.reference, 583 _ref: tc.ref, 584 InsecureRegistry: false, 585 Force: false, 586 }, 587 bundleRef: nil, 588 } 589 590 err = ensureVPrefix(&opts, io.Discard) 591 592 assert.Equal(t, tc.want, opts.BundlePullOptions.Reference) 593 assert.NoError(t, err) 594 if tc.wantRefTag == "" { 595 assert.Nil(t, opts.BundlePullOptions._ref) 596 } else { 597 require.NotNil(t, opts.BundlePullOptions._ref) 598 assert.Equal(t, tc.wantRefTag, opts.BundlePullOptions._ref.Tag()) 599 } 600 }) 601 } 602 } 603 604 func TestBundleExecutionOptions_GetHostVolumeMounts(t *testing.T) { 605 t.Run("valid host volume mounts", func(t *testing.T) { 606 opts := &BundleExecutionOptions{ 607 HostVolumeMounts: []string{ 608 "/host/path:/target/path:ro", 609 "/host/path:/target/path:rw", 610 "/host/path:/target/path", 611 }, 612 } 613 614 expected := []cnabprovider.HostVolumeMountSpec{ 615 { 616 Source: "/host/path", 617 Target: "/target/path", 618 ReadOnly: true, 619 }, 620 { 621 Source: "/host/path", 622 Target: "/target/path", 623 ReadOnly: false, 624 }, 625 { 626 Source: "/host/path", 627 Target: "/target/path", 628 ReadOnly: true, 629 }, 630 } 631 632 actual := opts.GetHostVolumeMounts() 633 634 if len(expected) != len(actual) { 635 t.Errorf("expected %v but got %v", expected, actual) 636 } 637 for i := range expected { 638 if expected[i].Source != actual[i].Source { 639 t.Errorf("expected %v but got %v", expected[i].Source, actual[i].Source) 640 } 641 if expected[i].Target != actual[i].Target { 642 t.Errorf("expected %v but got %v", expected[i].Target, actual[i].Target) 643 } 644 if expected[i].ReadOnly != actual[i].ReadOnly { 645 t.Errorf("expected %v but got %v", expected[i].ReadOnly, actual[i].ReadOnly) 646 } 647 } 648 }) 649 650 t.Run("invalid host volume mounts", func(t *testing.T) { 651 opts := &BundleExecutionOptions{ 652 HostVolumeMounts: []string{ 653 "1=", 654 "/host/path", 655 }, 656 } 657 658 actual := opts.GetHostVolumeMounts() 659 660 if len(actual) != 0 { 661 t.Errorf("expected no host volume mounts but got %v", actual) 662 } 663 664 }) 665 666 t.Run("invalid host volume mount r/w option value", func(t *testing.T) { 667 opts := &BundleExecutionOptions{ 668 HostVolumeMounts: []string{ 669 "/host/path:/target/path:invalid-option", 670 }, 671 } 672 673 actual := opts.GetHostVolumeMounts() 674 675 if !actual[0].ReadOnly { 676 t.Errorf("expected ReadOnly to be true but got %v", actual[0].ReadOnly) 677 } 678 679 }) 680 } 681 682 func TestBundleExecutionOptions_GetHostVolumeMountsWindows(t *testing.T) { 683 684 if runtime.GOOS != "windows" { 685 t.Skip("Skipping test on non-windows platform") 686 } 687 688 t.Run("valid host volume mounts", func(t *testing.T) { 689 opts := &BundleExecutionOptions{ 690 HostVolumeMounts: []string{ 691 "C:\\Users\\testuser\\folderpath:/target/path:rw", 692 "C:\\Users\\testuser\\folderpath:/target/path", 693 "C:\\Users\\Test User\\test path:/target/path", 694 }, 695 } 696 697 expected := []cnabprovider.HostVolumeMountSpec{ 698 { 699 Source: "C:\\Users\\testuser\\folderpath", 700 Target: "/target/path", 701 ReadOnly: false, 702 }, 703 { 704 Source: "C:\\Users\\testuser\\folderpath", 705 Target: "/target/path", 706 ReadOnly: true, 707 }, 708 { 709 Source: "C:\\Users\\Test User\\test path", 710 Target: "/target/path", 711 ReadOnly: true, 712 }, 713 } 714 715 actual := opts.GetHostVolumeMounts() 716 717 if len(expected) != len(actual) { 718 t.Errorf("expected %v but got %v", expected, actual) 719 } 720 for i := range expected { 721 if expected[i].Source != actual[i].Source { 722 t.Errorf("expected %v but got %v", expected[i].Source, actual[i].Source) 723 } 724 if expected[i].Target != actual[i].Target { 725 t.Errorf("expected %v but got %v", expected[i].Target, actual[i].Target) 726 } 727 if expected[i].ReadOnly != actual[i].ReadOnly { 728 t.Errorf("expected %v but got %v", expected[i].ReadOnly, actual[i].ReadOnly) 729 } 730 } 731 }) 732 733 }