github.com/apptainer/singularity@v3.1.1+incompatible/pkg/image/image_test.go (about) 1 // Copyright (c) 2019, 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 image 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "testing" 17 18 "github.com/sylabs/singularity/internal/pkg/util/fs" 19 20 imageSpecs "github.com/opencontainers/image-spec/specs-go/v1" 21 "github.com/sylabs/singularity/pkg/image/unpacker" 22 ) 23 24 func downloadImage(t *testing.T) string { 25 sexec, err := exec.LookPath("singularity") 26 if err != nil { 27 t.SkipNow() 28 } 29 f, err := ioutil.TempFile("", "image-") 30 if err != nil { 31 t.Fatal(err) 32 } 33 name := f.Name() 34 f.Close() 35 36 cmd := exec.Command(sexec, "build", "-F", name, "docker://busybox") 37 if err := cmd.Run(); err != nil { 38 t.Fatal(err) 39 } 40 return name 41 } 42 43 func checkPartition(reader io.Reader) error { 44 extracted := "/bin/busybox" 45 dir, err := ioutil.TempDir("", "extract-") 46 if err != nil { 47 return err 48 } 49 defer os.RemoveAll(dir) 50 51 s := unpacker.NewSquashfs() 52 if s.HasUnsquashfs() { 53 if err := s.ExtractFiles([]string{extracted}, reader, dir); err != nil { 54 return fmt.Errorf("extraction failed: %s", err) 55 } 56 if !fs.IsExec(filepath.Join(dir, extracted)) { 57 return fmt.Errorf("%s extraction failed", extracted) 58 } 59 } 60 return nil 61 } 62 63 func checkSection(reader io.Reader) error { 64 dec := json.NewDecoder(reader) 65 imgSpec := &imageSpecs.ImageConfig{} 66 if err := dec.Decode(imgSpec); err != nil { 67 return fmt.Errorf("failed to decode oci image config") 68 } 69 if len(imgSpec.Cmd) == 0 { 70 return fmt.Errorf("no command found") 71 } 72 if imgSpec.Cmd[0] != "sh" { 73 return fmt.Errorf("unexpected value: %s instead of sh", imgSpec.Cmd[0]) 74 } 75 return nil 76 } 77 78 func TestReader(t *testing.T) { 79 filename := downloadImage(t) 80 defer os.Remove(filename) 81 82 for _, e := range []struct { 83 fn func(*Image, string, int) (io.Reader, error) 84 fnCheck func(io.Reader) error 85 errCheck error 86 name string 87 index int 88 }{ 89 { 90 fn: NewPartitionReader, 91 fnCheck: checkPartition, 92 errCheck: ErrNoPartition, 93 name: RootFs, 94 index: -1, 95 }, 96 { 97 fn: NewPartitionReader, 98 fnCheck: checkPartition, 99 errCheck: ErrNoPartition, 100 index: 0, 101 }, 102 { 103 fn: NewSectionReader, 104 fnCheck: checkSection, 105 errCheck: ErrNoSection, 106 name: "oci-config.json", 107 index: -1, 108 }, 109 } { 110 // test with nil image parameter 111 if _, err := e.fn(nil, "", -1); err == nil { 112 t.Errorf("unexpected success with nil image parameter") 113 } 114 // test with non opened file 115 if _, err := e.fn(&Image{}, "", -1); err == nil { 116 t.Errorf("unexpected success with non opened file") 117 } 118 119 img, err := Init(filename, false) 120 if err != nil { 121 t.Fatal(err) 122 } 123 124 if img.Type != SIF { 125 t.Errorf("unexpected image format: %v", img.Type) 126 } 127 // test without match criteria 128 if _, err := e.fn(img, "", -1); err == nil { 129 t.Errorf("unexpected success without match criteria") 130 } 131 // test with large index 132 if _, err := e.fn(img, "", 999999); err == nil { 133 t.Errorf("unexpected success with large index") 134 } 135 // test with unknown name 136 if _, err := e.fn(img, "fakefile.name", -1); err != e.errCheck { 137 t.Errorf("unexpected error with unknown name") 138 } 139 // test with match criteria 140 if r, err := e.fn(img, e.name, e.index); err == e.errCheck { 141 t.Error(err) 142 } else { 143 if err := e.fnCheck(r); err != nil { 144 t.Error(err) 145 } 146 } 147 img.File.Close() 148 } 149 }