github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/internal/inspectimage/writer/toml_test.go (about) 1 package writer_test 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/buildpacks/lifecycle/buildpack" 8 "github.com/buildpacks/lifecycle/launch" 9 "github.com/buildpacks/lifecycle/platform/files" 10 "github.com/heroku/color" 11 "github.com/sclevine/spec" 12 "github.com/sclevine/spec/report" 13 14 "github.com/buildpacks/pack/internal/config" 15 "github.com/buildpacks/pack/internal/inspectimage" 16 "github.com/buildpacks/pack/internal/inspectimage/writer" 17 "github.com/buildpacks/pack/pkg/client" 18 "github.com/buildpacks/pack/pkg/logging" 19 h "github.com/buildpacks/pack/testhelpers" 20 ) 21 22 func TestTOML(t *testing.T) { 23 color.Disable(true) 24 defer color.Disable(false) 25 spec.Run(t, "TOML Writer", testTOML, spec.Parallel(), spec.Report(report.Terminal{})) 26 } 27 28 func testTOML(t *testing.T, when spec.G, it spec.S) { 29 var ( 30 assert = h.NewAssertionManager(t) 31 outBuf bytes.Buffer 32 33 remoteInfo *client.ImageInfo 34 remoteInfoNoRebasable *client.ImageInfo 35 localInfo *client.ImageInfo 36 localInfoNoRebasable *client.ImageInfo 37 38 expectedLocalOutput = `[local_info] 39 stack = 'test.stack.id.local' 40 rebasable = true 41 42 [local_info.base_image] 43 top_layer = 'some-local-top-layer' 44 reference = 'some-local-run-image-reference' 45 46 [[local_info.run_images]] 47 name = 'user-configured-mirror-for-local' 48 user_configured = true 49 50 [[local_info.run_images]] 51 name = 'some-local-run-image' 52 53 [[local_info.run_images]] 54 name = 'some-local-mirror' 55 56 [[local_info.run_images]] 57 name = 'other-local-mirror' 58 59 [[local_info.buildpacks]] 60 id = 'test.bp.one.local' 61 version = '1.0.0' 62 homepage = 'https://some-homepage-one' 63 64 [[local_info.buildpacks]] 65 id = 'test.bp.two.local' 66 version = '2.0.0' 67 homepage = 'https://some-homepage-two' 68 69 [[local_info.processes]] 70 type = 'some-local-type' 71 shell = 'bash' 72 command = '/some/local command' 73 default = true 74 args = [ 75 'some', 76 'local', 77 'args', 78 ] 79 working-dir = "/some-test-work-dir" 80 81 [[local_info.processes]] 82 type = 'other-local-type' 83 shell = '' 84 command = '/other/local/command' 85 default = false 86 args = [ 87 'other', 88 'local', 89 'args', 90 ] 91 working-dir = "/other-test-work-dir" 92 ` 93 expectedLocalNoRebasableOutput = `[local_info] 94 stack = 'test.stack.id.local' 95 rebasable = false 96 97 [local_info.base_image] 98 top_layer = 'some-local-top-layer' 99 reference = 'some-local-run-image-reference' 100 101 [[local_info.run_images]] 102 name = 'user-configured-mirror-for-local' 103 user_configured = true 104 105 [[local_info.run_images]] 106 name = 'some-local-run-image' 107 108 [[local_info.run_images]] 109 name = 'some-local-mirror' 110 111 [[local_info.run_images]] 112 name = 'other-local-mirror' 113 114 [[local_info.buildpacks]] 115 id = 'test.bp.one.local' 116 version = '1.0.0' 117 homepage = 'https://some-homepage-one' 118 119 [[local_info.buildpacks]] 120 id = 'test.bp.two.local' 121 version = '2.0.0' 122 homepage = 'https://some-homepage-two' 123 124 [[local_info.processes]] 125 type = 'some-local-type' 126 shell = 'bash' 127 command = '/some/local command' 128 default = true 129 args = [ 130 'some', 131 'local', 132 'args', 133 ] 134 working-dir = "/some-test-work-dir" 135 136 [[local_info.processes]] 137 type = 'other-local-type' 138 shell = '' 139 command = '/other/local/command' 140 default = false 141 args = [ 142 'other', 143 'local', 144 'args', 145 ] 146 working-dir = "/other-test-work-dir" 147 ` 148 149 expectedRemoteOutput = ` 150 [remote_info] 151 stack = 'test.stack.id.remote' 152 rebasable = true 153 154 [remote_info.base_image] 155 top_layer = 'some-remote-top-layer' 156 reference = 'some-remote-run-image-reference' 157 158 [[remote_info.run_images]] 159 name = 'user-configured-mirror-for-remote' 160 user_configured = true 161 162 [[remote_info.run_images]] 163 name = 'some-remote-run-image' 164 165 [[remote_info.run_images]] 166 name = 'some-remote-mirror' 167 168 [[remote_info.run_images]] 169 name = 'other-remote-mirror' 170 171 [[remote_info.buildpacks]] 172 id = 'test.bp.one.remote' 173 version = '1.0.0' 174 homepage = 'https://some-homepage-one' 175 176 [[remote_info.buildpacks]] 177 id = 'test.bp.two.remote' 178 version = '2.0.0' 179 homepage = 'https://some-homepage-two' 180 181 [[remote_info.processes]] 182 type = 'some-remote-type' 183 shell = 'bash' 184 command = '/some/remote command' 185 default = true 186 args = [ 187 'some', 188 'remote', 189 'args', 190 ] 191 working-dir = "/some-test-work-dir" 192 193 [[remote_info.processes]] 194 type = 'other-remote-type' 195 shell = '' 196 command = '/other/remote/command' 197 default = false 198 args = [ 199 'other', 200 'remote', 201 'args', 202 ] 203 working-dir = "/other-test-work-dir" 204 ` 205 expectedRemoteNoRebasableOutput = ` 206 [remote_info] 207 stack = 'test.stack.id.remote' 208 rebasable = false 209 210 [remote_info.base_image] 211 top_layer = 'some-remote-top-layer' 212 reference = 'some-remote-run-image-reference' 213 214 [[remote_info.run_images]] 215 name = 'user-configured-mirror-for-remote' 216 user_configured = true 217 218 [[remote_info.run_images]] 219 name = 'some-remote-run-image' 220 221 [[remote_info.run_images]] 222 name = 'some-remote-mirror' 223 224 [[remote_info.run_images]] 225 name = 'other-remote-mirror' 226 227 [[remote_info.buildpacks]] 228 id = 'test.bp.one.remote' 229 version = '1.0.0' 230 homepage = 'https://some-homepage-one' 231 232 [[remote_info.buildpacks]] 233 id = 'test.bp.two.remote' 234 version = '2.0.0' 235 homepage = 'https://some-homepage-two' 236 237 [[remote_info.processes]] 238 type = 'some-remote-type' 239 shell = 'bash' 240 command = '/some/remote command' 241 default = true 242 args = [ 243 'some', 244 'remote', 245 'args', 246 ] 247 working-dir = "/some-test-work-dir" 248 249 [[remote_info.processes]] 250 type = 'other-remote-type' 251 shell = '' 252 command = '/other/remote/command' 253 default = false 254 args = [ 255 'other', 256 'remote', 257 'args', 258 ] 259 working-dir = "/other-test-work-dir" 260 ` 261 ) 262 263 when("Print", func() { 264 it.Before(func() { 265 type someData struct { 266 String string 267 Bool bool 268 Int int 269 Nested struct { 270 String string 271 } 272 } 273 274 remoteInfo = &client.ImageInfo{ 275 StackID: "test.stack.id.remote", 276 Buildpacks: []buildpack.GroupElement{ 277 {ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 278 {ID: "test.bp.two.remote", Version: "2.0.0", Homepage: "https://some-homepage-two"}, 279 }, 280 Base: files.RunImageForRebase{ 281 TopLayer: "some-remote-top-layer", 282 Reference: "some-remote-run-image-reference", 283 }, 284 Stack: files.Stack{ 285 RunImage: files.RunImageForExport{ 286 Image: "some-remote-run-image", 287 Mirrors: []string{"some-remote-mirror", "other-remote-mirror"}, 288 }, 289 }, 290 BOM: []buildpack.BOMEntry{{ 291 Require: buildpack.Require{ 292 Name: "name-1", 293 Version: "version-1", 294 Metadata: map[string]interface{}{ 295 "RemoteData": someData{ 296 String: "aString", 297 Bool: true, 298 Int: 123, 299 Nested: struct { 300 String string 301 }{ 302 String: "anotherString", 303 }, 304 }, 305 }, 306 }, 307 Buildpack: buildpack.GroupElement{ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 308 }}, 309 Processes: client.ProcessDetails{ 310 DefaultProcess: &launch.Process{ 311 Type: "some-remote-type", 312 Command: launch.RawCommand{Entries: []string{"/some/remote command"}}, 313 Args: []string{"some", "remote", "args"}, 314 Direct: false, 315 WorkingDirectory: "/some-test-work-dir", 316 }, 317 OtherProcesses: []launch.Process{ 318 { 319 Type: "other-remote-type", 320 Command: launch.RawCommand{Entries: []string{"/other/remote/command"}}, 321 Args: []string{"other", "remote", "args"}, 322 Direct: true, 323 WorkingDirectory: "/other-test-work-dir", 324 }, 325 }, 326 }, 327 Rebasable: true, 328 } 329 remoteInfoNoRebasable = &client.ImageInfo{ 330 StackID: "test.stack.id.remote", 331 Buildpacks: []buildpack.GroupElement{ 332 {ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 333 {ID: "test.bp.two.remote", Version: "2.0.0", Homepage: "https://some-homepage-two"}, 334 }, 335 Base: files.RunImageForRebase{ 336 TopLayer: "some-remote-top-layer", 337 Reference: "some-remote-run-image-reference", 338 }, 339 Stack: files.Stack{ 340 RunImage: files.RunImageForExport{ 341 Image: "some-remote-run-image", 342 Mirrors: []string{"some-remote-mirror", "other-remote-mirror"}, 343 }, 344 }, 345 BOM: []buildpack.BOMEntry{{ 346 Require: buildpack.Require{ 347 Name: "name-1", 348 Version: "version-1", 349 Metadata: map[string]interface{}{ 350 "RemoteData": someData{ 351 String: "aString", 352 Bool: true, 353 Int: 123, 354 Nested: struct { 355 String string 356 }{ 357 String: "anotherString", 358 }, 359 }, 360 }, 361 }, 362 Buildpack: buildpack.GroupElement{ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 363 }}, 364 Processes: client.ProcessDetails{ 365 DefaultProcess: &launch.Process{ 366 Type: "some-remote-type", 367 Command: launch.RawCommand{Entries: []string{"/some/remote command"}}, 368 Args: []string{"some", "remote", "args"}, 369 Direct: false, 370 WorkingDirectory: "/some-test-work-dir", 371 }, 372 OtherProcesses: []launch.Process{ 373 { 374 Type: "other-remote-type", 375 Command: launch.RawCommand{Entries: []string{"/other/remote/command"}}, 376 Args: []string{"other", "remote", "args"}, 377 Direct: true, 378 WorkingDirectory: "/other-test-work-dir", 379 }, 380 }, 381 }, 382 Rebasable: false, 383 } 384 385 localInfo = &client.ImageInfo{ 386 StackID: "test.stack.id.local", 387 Buildpacks: []buildpack.GroupElement{ 388 {ID: "test.bp.one.local", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 389 {ID: "test.bp.two.local", Version: "2.0.0", Homepage: "https://some-homepage-two"}, 390 }, 391 Base: files.RunImageForRebase{ 392 TopLayer: "some-local-top-layer", 393 Reference: "some-local-run-image-reference", 394 }, 395 Stack: files.Stack{ 396 RunImage: files.RunImageForExport{ 397 Image: "some-local-run-image", 398 Mirrors: []string{"some-local-mirror", "other-local-mirror"}, 399 }, 400 }, 401 BOM: []buildpack.BOMEntry{{ 402 Require: buildpack.Require{ 403 Name: "name-1", 404 Version: "version-1", 405 Metadata: map[string]interface{}{ 406 "LocalData": someData{ 407 Bool: false, 408 Int: 456, 409 }, 410 }, 411 }, 412 Buildpack: buildpack.GroupElement{ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 413 }}, 414 Processes: client.ProcessDetails{ 415 DefaultProcess: &launch.Process{ 416 Type: "some-local-type", 417 Command: launch.RawCommand{Entries: []string{"/some/local command"}}, 418 Args: []string{"some", "local", "args"}, 419 Direct: false, 420 WorkingDirectory: "/some-test-work-dir", 421 }, 422 OtherProcesses: []launch.Process{ 423 { 424 Type: "other-local-type", 425 Command: launch.RawCommand{Entries: []string{"/other/local/command"}}, 426 Args: []string{"other", "local", "args"}, 427 Direct: true, 428 WorkingDirectory: "/other-test-work-dir", 429 }, 430 }, 431 }, 432 Rebasable: true, 433 } 434 localInfoNoRebasable = &client.ImageInfo{ 435 StackID: "test.stack.id.local", 436 Buildpacks: []buildpack.GroupElement{ 437 {ID: "test.bp.one.local", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 438 {ID: "test.bp.two.local", Version: "2.0.0", Homepage: "https://some-homepage-two"}, 439 }, 440 Base: files.RunImageForRebase{ 441 TopLayer: "some-local-top-layer", 442 Reference: "some-local-run-image-reference", 443 }, 444 Stack: files.Stack{ 445 RunImage: files.RunImageForExport{ 446 Image: "some-local-run-image", 447 Mirrors: []string{"some-local-mirror", "other-local-mirror"}, 448 }, 449 }, 450 BOM: []buildpack.BOMEntry{{ 451 Require: buildpack.Require{ 452 Name: "name-1", 453 Version: "version-1", 454 Metadata: map[string]interface{}{ 455 "LocalData": someData{ 456 Bool: false, 457 Int: 456, 458 }, 459 }, 460 }, 461 Buildpack: buildpack.GroupElement{ID: "test.bp.one.remote", Version: "1.0.0", Homepage: "https://some-homepage-one"}, 462 }}, 463 Processes: client.ProcessDetails{ 464 DefaultProcess: &launch.Process{ 465 Type: "some-local-type", 466 Command: launch.RawCommand{Entries: []string{"/some/local command"}}, 467 Args: []string{"some", "local", "args"}, 468 Direct: false, 469 WorkingDirectory: "/some-test-work-dir", 470 }, 471 OtherProcesses: []launch.Process{ 472 { 473 Type: "other-local-type", 474 Command: launch.RawCommand{Entries: []string{"/other/local/command"}}, 475 Args: []string{"other", "local", "args"}, 476 Direct: true, 477 WorkingDirectory: "/other-test-work-dir", 478 }, 479 }, 480 }, 481 Rebasable: false, 482 } 483 484 outBuf = bytes.Buffer{} 485 }) 486 487 when("local and remote image exits", func() { 488 it("prints both local and remote image info in a TOML format", func() { 489 runImageMirrors := []config.RunImage{ 490 { 491 Image: "un-used-run-image", 492 Mirrors: []string{"un-used"}, 493 }, 494 { 495 Image: "some-local-run-image", 496 Mirrors: []string{"user-configured-mirror-for-local"}, 497 }, 498 { 499 Image: "some-remote-run-image", 500 Mirrors: []string{"user-configured-mirror-for-remote"}, 501 }, 502 } 503 sharedImageInfo := inspectimage.GeneralInfo{ 504 Name: "test-image", 505 RunImageMirrors: runImageMirrors, 506 } 507 tomlWriter := writer.NewTOML() 508 509 logger := logging.NewLogWithWriters(&outBuf, &outBuf) 510 err := tomlWriter.Print(logger, sharedImageInfo, localInfo, remoteInfo, nil, nil) 511 assert.Nil(err) 512 513 assert.ContainsTOML(outBuf.String(), `image_name = "test-image"`) 514 assert.ContainsTOML(outBuf.String(), expectedLocalOutput) 515 assert.ContainsTOML(outBuf.String(), expectedRemoteOutput) 516 }) 517 it("prints both local and remote no rebasable images info in a TOML format", func() { 518 runImageMirrors := []config.RunImage{ 519 { 520 Image: "un-used-run-image", 521 Mirrors: []string{"un-used"}, 522 }, 523 { 524 Image: "some-local-run-image", 525 Mirrors: []string{"user-configured-mirror-for-local"}, 526 }, 527 { 528 Image: "some-remote-run-image", 529 Mirrors: []string{"user-configured-mirror-for-remote"}, 530 }, 531 } 532 sharedImageInfo := inspectimage.GeneralInfo{ 533 Name: "test-image", 534 RunImageMirrors: runImageMirrors, 535 } 536 tomlWriter := writer.NewTOML() 537 538 logger := logging.NewLogWithWriters(&outBuf, &outBuf) 539 err := tomlWriter.Print(logger, sharedImageInfo, localInfoNoRebasable, remoteInfoNoRebasable, nil, nil) 540 assert.Nil(err) 541 542 assert.ContainsTOML(outBuf.String(), `image_name = "test-image"`) 543 assert.ContainsTOML(outBuf.String(), expectedLocalNoRebasableOutput) 544 assert.ContainsTOML(outBuf.String(), expectedRemoteNoRebasableOutput) 545 }) 546 }) 547 548 when("only local image exists", func() { 549 it("prints local image info in TOML format", func() { 550 runImageMirrors := []config.RunImage{ 551 { 552 Image: "un-used-run-image", 553 Mirrors: []string{"un-used"}, 554 }, 555 { 556 Image: "some-local-run-image", 557 Mirrors: []string{"user-configured-mirror-for-local"}, 558 }, 559 { 560 Image: "some-remote-run-image", 561 Mirrors: []string{"user-configured-mirror-for-remote"}, 562 }, 563 } 564 sharedImageInfo := inspectimage.GeneralInfo{ 565 Name: "test-image", 566 RunImageMirrors: runImageMirrors, 567 } 568 tomlWriter := writer.NewTOML() 569 570 logger := logging.NewLogWithWriters(&outBuf, &outBuf) 571 err := tomlWriter.Print(logger, sharedImageInfo, localInfo, nil, nil, nil) 572 assert.Nil(err) 573 574 assert.ContainsTOML(outBuf.String(), `image_name = "test-image"`) 575 assert.NotContains(outBuf.String(), "test.stack.id.remote") 576 assert.ContainsTOML(outBuf.String(), expectedLocalOutput) 577 }) 578 }) 579 580 when("only remote image exists", func() { 581 it("prints remote image info in TOML format", func() { 582 runImageMirrors := []config.RunImage{ 583 { 584 Image: "un-used-run-image", 585 Mirrors: []string{"un-used"}, 586 }, 587 { 588 Image: "some-local-run-image", 589 Mirrors: []string{"user-configured-mirror-for-local"}, 590 }, 591 { 592 Image: "some-remote-run-image", 593 Mirrors: []string{"user-configured-mirror-for-remote"}, 594 }, 595 } 596 sharedImageInfo := inspectimage.GeneralInfo{ 597 Name: "test-image", 598 RunImageMirrors: runImageMirrors, 599 } 600 tomlWriter := writer.NewTOML() 601 602 logger := logging.NewLogWithWriters(&outBuf, &outBuf) 603 err := tomlWriter.Print(logger, sharedImageInfo, nil, remoteInfo, nil, nil) 604 assert.Nil(err) 605 606 assert.ContainsTOML(outBuf.String(), `image_name = "test-image"`) 607 assert.NotContains(outBuf.String(), "test.stack.id.local") 608 assert.ContainsTOML(outBuf.String(), expectedRemoteOutput) 609 }) 610 }) 611 }) 612 }