github.com/apptainer/singularity@v3.1.1+incompatible/cmd/singularity/build_test.go (about) 1 // Copyright (c) 2018, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package main 7 8 import ( 9 "bytes" 10 "encoding/json" 11 "fmt" 12 "io/ioutil" 13 "log" 14 "os" 15 "os/exec" 16 "path" 17 "path/filepath" 18 "strings" 19 "testing" 20 21 "github.com/sylabs/singularity/internal/pkg/test" 22 ) 23 24 var testFileContent = "Test file content\n" 25 26 func imageVerify(t *testing.T, imagePath string, labels bool) { 27 type testSpec struct { 28 name string 29 execArgs []string 30 expectSuccess bool 31 } 32 tests := []testSpec{ 33 {"False", []string{"false"}, false}, 34 {"RunScript", []string{"test", "-f", "/.singularity.d/runscript"}, true}, 35 {"OneBase", []string{"test", "-f", "/.singularity.d/env/01-base.sh"}, true}, 36 {"ActionsShell", []string{"test", "-f", "/.singularity.d/actions/shell"}, true}, 37 {"ActionsExec", []string{"test", "-f", "/.singularity.d/actions/exec"}, true}, 38 {"ActionsRun", []string{"test", "-f", "/.singularity.d/actions/run"}, true}, 39 {"Environment", []string{"test", "-L", "/environment"}, true}, 40 {"Singularity", []string{"test", "-L", "/singularity"}, true}, 41 } 42 if labels && *runDisabled { // TODO 43 tests = append(tests, testSpec{"Labels", []string{"test", "-f", "/.singularity.d/labels.json"}, true}) 44 } 45 46 for _, tt := range tests { 47 t.Run(tt.name, test.WithoutPrivilege(func(t *testing.T) { 48 _, stderr, exitCode, err := imageExec(t, "exec", opts{}, imagePath, tt.execArgs) 49 if tt.expectSuccess && (exitCode != 0) { 50 t.Log(stderr) 51 t.Fatalf("unexpected failure running '%v': %v", strings.Join(tt.execArgs, " "), err) 52 } else if !tt.expectSuccess && (exitCode != 1) { 53 t.Log(stderr) 54 t.Fatalf("unexpected success running '%v'", strings.Join(tt.execArgs, " ")) 55 } 56 })) 57 } 58 } 59 60 type buildOpts struct { 61 force bool 62 sandbox bool 63 env []string 64 } 65 66 func imageBuild(opts buildOpts, imagePath, buildSpec string) ([]byte, error) { 67 var argv []string 68 argv = append(argv, "build") 69 if opts.force { 70 argv = append(argv, "--force") 71 } 72 if opts.sandbox { 73 argv = append(argv, "--sandbox") 74 } 75 argv = append(argv, imagePath, buildSpec) 76 77 cmd := exec.Command(cmdPath, argv...) 78 cmd.Env = opts.env 79 80 return cmd.CombinedOutput() 81 } 82 83 func TestBuild(t *testing.T) { 84 tests := []struct { 85 name string 86 dependency string 87 buildSpec string 88 sandbox bool 89 }{ 90 {"BusyBox", "", "../../examples/busybox/Singularity", false}, 91 {"BusyBoxSandbox", "", "../../examples/busybox/Singularity", true}, 92 {"Debootstrap", "debootstrap", "../../examples/debian/Singularity", true}, 93 {"DockerURI", "", "docker://busybox", true}, 94 {"DockerDefFile", "", "../../examples/docker/Singularity", true}, 95 {"SHubURI", "", "shub://GodloveD/busybox", true}, 96 {"SHubDefFile", "", "../../examples/shub/Singularity", true}, 97 {"LibraryDefFile", "", "../../examples/library/Singularity", true}, 98 {"Yum", "yum", "../../examples/centos/Singularity", true}, 99 {"Zypper", "zypper", "../../examples/opensuse/Singularity", true}, 100 } 101 102 for _, tt := range tests { 103 t.Run(tt.name, test.WithPrivilege(func(t *testing.T) { 104 if tt.dependency != "" { 105 if _, err := exec.LookPath(tt.dependency); err != nil { 106 t.Skipf("%v not found in path", tt.dependency) 107 } 108 } 109 110 opts := buildOpts{ 111 sandbox: tt.sandbox, 112 } 113 114 imagePath := path.Join(testDir, "container") 115 defer os.RemoveAll(imagePath) 116 117 if b, err := imageBuild(opts, imagePath, tt.buildSpec); err != nil { 118 t.Log(string(b)) 119 t.Fatalf("unexpected failure: %v", err) 120 } 121 imageVerify(t, imagePath, false) 122 })) 123 } 124 } 125 126 func TestBuildMultiStage(t *testing.T) { 127 imagePath1 := path.Join(testDir, "container1") 128 imagePath2 := path.Join(testDir, "container2") 129 imagePath3 := path.Join(testDir, "container3") 130 131 liDefFile := prepareDefFile(DefFileDetail{ 132 Bootstrap: "localimage", 133 From: imagePath1, 134 }) 135 defer os.Remove(liDefFile) 136 137 labels := make(map[string]string) 138 labels["FOO"] = "bar" 139 liLabelDefFile := prepareDefFile(DefFileDetail{ 140 Bootstrap: "localimage", 141 From: imagePath2, 142 Labels: labels, 143 }) 144 defer os.Remove(liLabelDefFile) 145 146 type testSpec struct { 147 name string 148 imagePath string 149 buildSpec string 150 force bool 151 sandbox bool 152 labels bool 153 } 154 155 tests := []struct { 156 name string 157 steps []testSpec 158 }{ 159 {"SIFToSIF", []testSpec{ 160 {"BusyBox", imagePath1, "../../examples/busybox/Singularity", false, false, false}, 161 {"SIF", imagePath2, imagePath1, false, false, false}, 162 }}, 163 {"SandboxToSIF", []testSpec{ 164 {"BusyBoxSandbox", imagePath1, "../../examples/busybox/Singularity", false, true, false}, 165 {"SIF", imagePath2, imagePath1, false, false, false}, 166 }}, 167 {"LocalImage", []testSpec{ 168 {"BusyBox", imagePath1, "../../examples/busybox/Singularity", false, false, false}, 169 {"LocalImage", imagePath2, liDefFile, false, false, false}, 170 {"LocalImageLabel", imagePath3, liLabelDefFile, false, false, true}, 171 }}, 172 {"LocalImageSandbox", []testSpec{ 173 {"BusyBoxSandbox", imagePath2, "../../examples/busybox/Singularity", true, true, false}, 174 {"LocalImageLabel", imagePath3, liLabelDefFile, false, false, true}, 175 }}, 176 } 177 178 for _, tt := range tests { 179 t.Run(tt.name, test.WithPrivilege(func(t *testing.T) { 180 for _, ts := range tt.steps { 181 defer os.RemoveAll(ts.imagePath) 182 } 183 184 for _, ts := range tt.steps { 185 t.Run(ts.name, test.WithPrivilege(func(t *testing.T) { 186 opts := buildOpts{ 187 force: ts.force, 188 sandbox: ts.sandbox, 189 } 190 191 if b, err := imageBuild(opts, ts.imagePath, ts.buildSpec); err != nil { 192 t.Log(string(b)) 193 t.Fatalf("unexpected failure: %v", err) 194 } 195 imageVerify(t, ts.imagePath, ts.labels) 196 })) 197 } 198 })) 199 } 200 } 201 202 func TestBadPath(t *testing.T) { 203 test.EnsurePrivilege(t) 204 205 imagePath := path.Join(testDir, "container") 206 defer os.RemoveAll(imagePath) 207 208 if b, err := imageBuild(buildOpts{}, imagePath, "/some/dumb/path"); err == nil { 209 t.Log(string(b)) 210 t.Fatal("unexpected success") 211 } 212 } 213 214 func TestBuildDefinition(t *testing.T) { 215 216 tmpfile, err := ioutil.TempFile(testDir, "testFile-") 217 if err != nil { 218 log.Fatal(err) 219 } 220 221 defer os.Remove(tmpfile.Name()) // clean up 222 223 if _, err := tmpfile.Write([]byte(testFileContent)); err != nil { 224 log.Fatal(err) 225 } 226 if err := tmpfile.Close(); err != nil { 227 log.Fatal(err) 228 } 229 230 tests := []struct { 231 name string 232 force bool 233 sandbox bool 234 dfd DefFileDetail 235 }{ 236 {"Empty", false, true, DefFileDetail{ 237 Bootstrap: "docker", 238 From: "alpine:latest", 239 }}, 240 {"Help", false, true, DefFileDetail{ 241 Bootstrap: "docker", 242 From: "alpine:latest", 243 Help: []string{ 244 "help info line 1", 245 "help info line 2", 246 "help info line 3", 247 }, 248 }}, 249 {"Files", false, true, DefFileDetail{ 250 Bootstrap: "docker", 251 From: "alpine:latest", 252 Files: []FilePair{ 253 FilePair{ 254 Src: tmpfile.Name(), 255 Dst: "NewName2.txt", 256 }, 257 FilePair{ 258 Src: tmpfile.Name(), 259 Dst: "NewName.txt", 260 }, 261 }, 262 }}, 263 {"Test", false, true, DefFileDetail{ 264 Bootstrap: "docker", 265 From: "alpine:latest", 266 Test: []string{ 267 "echo testscript line 1", 268 "echo testscript line 2", 269 "echo testscript line 3", 270 }, 271 }}, 272 {"Startscript", false, true, DefFileDetail{ 273 Bootstrap: "docker", 274 From: "alpine:latest", 275 StartScript: []string{ 276 "echo startscript line 1", 277 "echo startscript line 2", 278 "echo startscript line 3", 279 }, 280 }}, 281 {"Runscript", false, true, DefFileDetail{ 282 Bootstrap: "docker", 283 From: "alpine:latest", 284 RunScript: []string{ 285 "echo runscript line 1", 286 "echo runscript line 2", 287 "echo runscript line 3", 288 }, 289 }}, 290 {"Env", false, true, DefFileDetail{ 291 Bootstrap: "docker", 292 From: "alpine:latest", 293 Env: []string{ 294 "testvar1=one", 295 "testvar2=two", 296 "testvar3=three", 297 }, 298 }}, 299 {"Labels", false, true, DefFileDetail{ 300 Bootstrap: "docker", 301 From: "alpine:latest", 302 Labels: map[string]string{ 303 "customLabel1": "one", 304 "customLabel2": "two", 305 "customLabel3": "three", 306 }, 307 }}, 308 {"Pre", false, true, DefFileDetail{ 309 Bootstrap: "docker", 310 From: "alpine:latest", 311 Pre: []string{ 312 filepath.Join(testDir, "PreFile1"), 313 }, 314 }}, 315 {"Setup", false, true, DefFileDetail{ 316 Bootstrap: "docker", 317 From: "alpine:latest", 318 Setup: []string{ 319 filepath.Join(testDir, "SetupFile1"), 320 }, 321 }}, 322 {"Post", false, true, DefFileDetail{ 323 Bootstrap: "docker", 324 From: "alpine:latest", 325 Post: []string{ 326 "PostFile1", 327 }, 328 }}, 329 {"AppHelp", false, true, DefFileDetail{ 330 Bootstrap: "docker", 331 From: "alpine:latest", 332 Apps: []AppDetail{ 333 AppDetail{ 334 Name: "foo", 335 Help: []string{ 336 "foo help info line 1", 337 "foo help info line 2", 338 "foo help info line 3", 339 }, 340 }, 341 AppDetail{ 342 Name: "bar", 343 Help: []string{ 344 "bar help info line 1", 345 "bar help info line 2", 346 "bar help info line 3", 347 }, 348 }, 349 }, 350 }}, 351 {"AppEnv", false, true, DefFileDetail{ 352 Bootstrap: "docker", 353 From: "alpine:latest", 354 Apps: []AppDetail{ 355 AppDetail{ 356 Name: "foo", 357 Env: []string{ 358 "testvar1=fooOne", 359 "testvar2=fooTwo", 360 "testvar3=fooThree", 361 }, 362 }, 363 AppDetail{ 364 Name: "bar", 365 Env: []string{ 366 "testvar1=barOne", 367 "testvar2=barTwo", 368 "testvar3=barThree", 369 }, 370 }, 371 }, 372 }}, 373 {"AppLabels", false, true, DefFileDetail{ 374 Bootstrap: "docker", 375 From: "alpine:latest", 376 Apps: []AppDetail{ 377 AppDetail{ 378 Name: "foo", 379 Labels: map[string]string{ 380 "customLabel1": "fooOne", 381 "customLabel2": "fooTwo", 382 "customLabel3": "fooThree", 383 }, 384 }, 385 AppDetail{ 386 Name: "bar", 387 Labels: map[string]string{ 388 "customLabel1": "barOne", 389 "customLabel2": "barTwo", 390 "customLabel3": "barThree", 391 }, 392 }, 393 }, 394 }}, 395 {"AppFiles", false, true, DefFileDetail{ 396 Bootstrap: "docker", 397 From: "alpine:latest", 398 Apps: []AppDetail{ 399 AppDetail{ 400 Name: "foo", 401 Files: []FilePair{ 402 FilePair{ 403 Src: tmpfile.Name(), 404 Dst: "FooFile2.txt", 405 }, 406 FilePair{ 407 Src: tmpfile.Name(), 408 Dst: "FooFile.txt", 409 }, 410 }, 411 }, 412 AppDetail{ 413 Name: "bar", 414 Files: []FilePair{ 415 FilePair{ 416 Src: tmpfile.Name(), 417 Dst: "BarFile2.txt", 418 }, 419 FilePair{ 420 Src: tmpfile.Name(), 421 Dst: "BarFile.txt", 422 }, 423 }, 424 }, 425 }, 426 }}, 427 {"AppInstall", false, true, DefFileDetail{ 428 Bootstrap: "docker", 429 From: "alpine:latest", 430 Apps: []AppDetail{ 431 AppDetail{ 432 Name: "foo", 433 Install: []string{ 434 "FooInstallFile1", 435 }, 436 }, 437 AppDetail{ 438 Name: "bar", 439 Install: []string{ 440 "BarInstallFile1", 441 }, 442 }, 443 }, 444 }}, 445 {"AppRun", false, true, DefFileDetail{ 446 Bootstrap: "docker", 447 From: "alpine:latest", 448 Apps: []AppDetail{ 449 AppDetail{ 450 Name: "foo", 451 Run: []string{ 452 "echo foo runscript line 1", 453 "echo foo runscript line 2", 454 "echo foo runscript line 3", 455 }, 456 }, 457 AppDetail{ 458 Name: "bar", 459 Run: []string{ 460 "echo bar runscript line 1", 461 "echo bar runscript line 2", 462 "echo bar runscript line 3", 463 }, 464 }, 465 }, 466 }}, 467 {"AppTest", false, true, DefFileDetail{ 468 Bootstrap: "docker", 469 From: "alpine:latest", 470 Apps: []AppDetail{ 471 AppDetail{ 472 Name: "foo", 473 Test: []string{ 474 "echo foo testscript line 1", 475 "echo foo testscript line 2", 476 "echo foo testscript line 3", 477 }, 478 }, 479 AppDetail{ 480 Name: "bar", 481 Test: []string{ 482 "echo bar testscript line 1", 483 "echo bar testscript line 2", 484 "echo bar testscript line 3", 485 }, 486 }, 487 }, 488 }}, 489 } 490 491 for _, tt := range tests { 492 t.Run(tt.name, test.WithPrivilege(func(t *testing.T) { 493 494 defFile := prepareDefFile(tt.dfd) 495 defer os.Remove(defFile) 496 497 opts := buildOpts{ 498 sandbox: tt.sandbox, 499 } 500 501 imagePath := path.Join(testDir, "container") 502 defer os.RemoveAll(imagePath) 503 504 if b, err := imageBuild(opts, imagePath, defFile); err != nil { 505 t.Log(string(b)) 506 t.Fatalf("unexpected failure: %v", err) 507 } 508 definitionImageVerify(t, imagePath, tt.dfd) 509 })) 510 } 511 } 512 513 func definitionImageVerify(t *testing.T, imagePath string, dfd DefFileDetail) { 514 if dfd.Help != nil { 515 helpPath := filepath.Join(imagePath, `/.singularity.d/runscript.help`) 516 if !fileExists(t, helpPath) { 517 t.Fatalf("unexpected failure: Script %v does not exist in container", helpPath) 518 } 519 520 if err := verifyHelp(t, helpPath, dfd.Help); err != nil { 521 t.Fatalf("unexpected failure: help message: %v", err) 522 } 523 } 524 525 if dfd.Env != nil { 526 if err := verifyEnv(t, imagePath, dfd.Env, nil); err != nil { 527 t.Fatalf("unexpected failure: Env in container is incorrect: %v", err) 528 } 529 } 530 531 // always run this since we should at least have default build labels 532 if err := verifyLabels(t, imagePath, dfd.Labels); err != nil { 533 t.Fatalf("unexpected failure: Labels in the container are incorrect: %v", err) 534 } 535 536 // verify %files section works correctly 537 for _, p := range dfd.Files { 538 var file string 539 if p.Src == "" { 540 file = p.Src 541 } else { 542 file = p.Dst 543 } 544 545 if !fileExists(t, filepath.Join(imagePath, file)) { 546 t.Fatalf("unexpected failure: File %v does not exist in container", file) 547 } 548 549 if err := verifyFile(t, p.Src, filepath.Join(imagePath, file)); err != nil { 550 t.Fatalf("unexpected failure: File %v: %v", file, err) 551 } 552 } 553 554 if dfd.RunScript != nil { 555 scriptPath := filepath.Join(imagePath, `/.singularity.d/runscript`) 556 if !fileExists(t, scriptPath) { 557 t.Fatalf("unexpected failure: Script %v does not exist in container", scriptPath) 558 } 559 560 if err := verifyScript(t, scriptPath, dfd.RunScript); err != nil { 561 t.Fatalf("unexpected failure: runscript: %v", err) 562 } 563 } 564 565 if dfd.StartScript != nil { 566 scriptPath := filepath.Join(imagePath, `/.singularity.d/startscript`) 567 if !fileExists(t, scriptPath) { 568 t.Fatalf("unexpected failure: Script %v does not exist in container", scriptPath) 569 } 570 571 if err := verifyScript(t, scriptPath, dfd.StartScript); err != nil { 572 t.Fatalf("unexpected failure: startscript: %v", err) 573 } 574 } 575 576 if dfd.Test != nil { 577 scriptPath := filepath.Join(imagePath, `/.singularity.d/test`) 578 if !fileExists(t, scriptPath) { 579 t.Fatalf("unexpected failure: Script %v does not exist in container", scriptPath) 580 } 581 582 if err := verifyScript(t, scriptPath, dfd.Test); err != nil { 583 t.Fatalf("unexpected failure: test script: %v", err) 584 } 585 } 586 587 for _, file := range dfd.Pre { 588 if !fileExists(t, file) { 589 t.Fatalf("unexpected failure: %%Pre generated file %v does not exist on host", file) 590 } 591 } 592 593 for _, file := range dfd.Setup { 594 if !fileExists(t, file) { 595 t.Fatalf("unexpected failure: %%Setup generated file %v does not exist on host", file) 596 } 597 } 598 599 for _, file := range dfd.Post { 600 if !fileExists(t, filepath.Join(imagePath, file)) { 601 t.Fatalf("unexpected failure: %%Post generated file %v does not exist in container", file) 602 } 603 } 604 605 // Verify any apps 606 for _, app := range dfd.Apps { 607 // %apphelp 608 if app.Help != nil { 609 helpPath := filepath.Join(imagePath, `/scif/apps/`, app.Name, `/scif/runscript.help`) 610 if !fileExists(t, helpPath) { 611 t.Fatalf("unexpected failure in app %v: Script %v does not exist in app", app.Name, helpPath) 612 } 613 614 if err := verifyHelp(t, helpPath, app.Help); err != nil { 615 t.Fatalf("unexpected failure in app %v: app help message: %v", app.Name, err) 616 } 617 } 618 619 // %appenv 620 if app.Env != nil { 621 if err := verifyEnv(t, imagePath, app.Env, []string{"--app", app.Name}); err != nil { 622 t.Fatalf("unexpected failure in app %v: Env in app is incorrect: %v", app.Name, err) 623 } 624 } 625 626 // %applabels 627 if app.Labels != nil { 628 if err := verifyAppLabels(t, imagePath, app.Name, app.Labels); err != nil { 629 t.Fatalf("unexpected failure in app %v: Labels in app are incorrect: %v", app.Name, err) 630 } 631 } 632 633 // %appfiles 634 for _, p := range app.Files { 635 var file string 636 if p.Src == "" { 637 file = p.Src 638 } else { 639 file = p.Dst 640 } 641 642 if !fileExists(t, filepath.Join(imagePath, "/scif/apps/", app.Name, file)) { 643 t.Fatalf("unexpected failure in app %v: File %v does not exist in app", app.Name, file) 644 } 645 646 if err := verifyFile(t, p.Src, filepath.Join(imagePath, "/scif/apps/", app.Name, file)); err != nil { 647 t.Fatalf("unexpected failure in app %v: File %v: %v", app.Name, file, err) 648 } 649 } 650 651 // %appInstall 652 for _, file := range app.Install { 653 if !fileExists(t, filepath.Join(imagePath, "/scif/apps/", app.Name, file)) { 654 t.Fatalf("unexpected failure in app %v: %%Install generated file %v does not exist in container", app.Name, file) 655 } 656 } 657 658 // %appRun 659 if app.Run != nil { 660 scriptPath := filepath.Join(imagePath, "/scif/apps/", app.Name, "scif/runscript") 661 if !fileExists(t, scriptPath) { 662 t.Fatalf("unexpected failure in app %v: Script %v does not exist in app", app.Name, scriptPath) 663 } 664 665 if err := verifyScript(t, scriptPath, app.Run); err != nil { 666 t.Fatalf("unexpected failure in app %v: runscript: %v", app.Name, err) 667 } 668 } 669 670 // %appTest 671 if app.Test != nil { 672 scriptPath := filepath.Join(imagePath, "/scif/apps/", app.Name, "scif/test") 673 if !fileExists(t, scriptPath) { 674 t.Fatalf("unexpected failure in app %v: Script %v does not exist in app", app.Name, scriptPath) 675 } 676 677 if err := verifyScript(t, scriptPath, app.Test); err != nil { 678 t.Fatalf("unexpected failure in app %v: test script: %v", app.Name, err) 679 } 680 } 681 } 682 683 } 684 685 func fileExists(t *testing.T, path string) bool { 686 if _, err := os.Stat(path); os.IsNotExist(err) { 687 return false 688 } else if err != nil { 689 t.Fatalf("While stating file: %v", err) 690 } 691 692 return true 693 } 694 695 func verifyFile(t *testing.T, original, copy string) error { 696 ofi, err := os.Stat(original) 697 if err != nil { 698 t.Fatalf("While getting file info: %v", err) 699 } 700 701 cfi, err := os.Stat(copy) 702 if err != nil { 703 t.Fatalf("While getting file info: %v", err) 704 } 705 706 if ofi.Size() != cfi.Size() { 707 return fmt.Errorf("Incorrect file sizes. Original: %v, Copy: %v", ofi.Size(), cfi.Size()) 708 } 709 710 if ofi.Mode() != cfi.Mode() { 711 return fmt.Errorf("Incorrect file modes. Original: %v, Copy: %v", ofi.Mode(), cfi.Mode()) 712 } 713 714 o, err := ioutil.ReadFile(original) 715 if err != nil { 716 t.Fatalf("While reading file: %v", err) 717 } 718 719 c, err := ioutil.ReadFile(copy) 720 if err != nil { 721 t.Fatalf("While reading file: %v", err) 722 } 723 724 if bytes.Compare(o, c) != 0 { 725 return fmt.Errorf("Incorrect file content") 726 } 727 728 return nil 729 } 730 731 func verifyHelp(t *testing.T, fileName string, contents []string) error { 732 fi, err := os.Stat(fileName) 733 if err != nil { 734 t.Fatalf("While getting file info: %v", err) 735 } 736 737 // do perm check 738 if fi.Mode().Perm() != 0644 { 739 return fmt.Errorf("Incorrect help script perms: %v", fi.Mode().Perm()) 740 } 741 742 s, err := ioutil.ReadFile(fileName) 743 if err != nil { 744 t.Fatalf("While reading file: %v", err) 745 } 746 747 helpScript := string(s) 748 for _, c := range contents { 749 if !strings.Contains(helpScript, c) { 750 return fmt.Errorf("Missing help script content") 751 } 752 } 753 754 return nil 755 } 756 757 func verifyScript(t *testing.T, fileName string, contents []string) error { 758 fi, err := os.Stat(fileName) 759 if err != nil { 760 t.Fatalf("While getting file info: %v", err) 761 } 762 763 // do perm check 764 if fi.Mode().Perm() != 0755 { 765 return fmt.Errorf("Incorrect script perms: %v", fi.Mode().Perm()) 766 } 767 768 s, err := ioutil.ReadFile(fileName) 769 if err != nil { 770 t.Fatalf("While reading file: %v", err) 771 } 772 773 script := string(s) 774 for _, c := range contents { 775 if !strings.Contains(script, c) { 776 return fmt.Errorf("Missing script content") 777 } 778 } 779 780 return nil 781 } 782 783 func verifyEnv(t *testing.T, imagePath string, env []string, flags []string) error { 784 args := []string{"exec"} 785 if flags != nil { 786 args = append(args, flags...) 787 } 788 args = append(args, imagePath, "env") 789 790 cmd := exec.Command(cmdPath, args...) 791 b, err := cmd.CombinedOutput() 792 793 out := string(b) 794 795 if err != nil { 796 t.Fatalf("Error running command: %v", err) 797 } 798 799 for _, e := range env { 800 if !strings.Contains(out, e) { 801 return fmt.Errorf("Environment is missing: %v", e) 802 } 803 } 804 805 return nil 806 } 807 808 func verifyLabels(t *testing.T, imagePath string, labels map[string]string) error { 809 var fileLabels map[string]string 810 811 b, err := ioutil.ReadFile(filepath.Join(imagePath, "/.singularity.d/labels.json")) 812 if err != nil { 813 t.Fatalf("While reading file: %v", err) 814 } 815 816 if err := json.Unmarshal(b, &fileLabels); err != nil { 817 t.Fatalf("While unmarshaling labels.json into map: %v", err) 818 } 819 820 for k, v := range labels { 821 if l, ok := fileLabels[k]; !ok || v != l { 822 return fmt.Errorf("Missing label: %v:%v", k, v) 823 } 824 } 825 826 //check default labels that are always generated 827 defaultLabels := []string{ 828 "org.label-schema.schema-version", 829 "org.label-schema.build-date", 830 "org.label-schema.usage.singularity.version", 831 } 832 833 for _, l := range defaultLabels { 834 if _, ok := fileLabels[l]; !ok { 835 return fmt.Errorf("Missing label: %v", l) 836 } 837 } 838 839 return nil 840 } 841 842 func verifyAppLabels(t *testing.T, imagePath, appName string, labels map[string]string) error { 843 var fileLabels map[string]string 844 845 b, err := ioutil.ReadFile(filepath.Join(imagePath, "/scif/apps/", appName, "/scif/labels.json")) 846 if err != nil { 847 t.Fatalf("While reading file: %v", err) 848 } 849 850 if err := json.Unmarshal(b, &fileLabels); err != nil { 851 t.Fatalf("While unmarshaling labels.json into map: %v", err) 852 } 853 854 for k, v := range labels { 855 if l, ok := fileLabels[k]; !ok || v != l { 856 return fmt.Errorf("Missing label: %v:%v", k, v) 857 } 858 } 859 860 return nil 861 }