github.com/quay/claircore@v1.5.28/gobin/gobin_test.go (about) 1 package gobin 2 3 import ( 4 "archive/tar" 5 "context" 6 "io" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "regexp" 11 "strings" 12 "testing" 13 14 "github.com/quay/zlog" 15 16 "github.com/quay/claircore" 17 "github.com/quay/claircore/test" 18 ) 19 20 func TestEmptyFile(t *testing.T) { 21 ctx := zlog.Test(context.Background(), t) 22 23 mod := test.Modtime(t, "gobin_test.go") // Needs to be the name of this file. 24 p := test.GenerateFixture(t, "nothing.tar", mod, func(t testing.TB, tf *os.File) { 25 tmpdir := t.TempDir() 26 f, err := os.Create(filepath.Join(tmpdir, "nothing")) 27 if err != nil { 28 t.Fatal(err) 29 } 30 defer f.Close() 31 fi, err := f.Stat() 32 if err != nil { 33 t.Fatal(err) 34 } 35 // Create the tar stuff 36 tw := tar.NewWriter(tf) 37 defer tw.Close() 38 hdr, err := tar.FileInfoHeader(fi, "") 39 if err != nil { 40 t.Fatal(err) 41 } 42 hdr.Name = "./bin/nothing" 43 if err := tw.WriteHeader(hdr); err != nil { 44 t.Error(err) 45 } 46 if _, err := io.Copy(tw, f); err != nil { 47 t.Error(err) 48 } 49 }) 50 f, err := os.Open(p) 51 if err != nil { 52 t.Fatal(err) 53 } 54 t.Cleanup(func() { 55 if err := f.Close(); err != nil { 56 t.Error(err) 57 } 58 }) 59 60 var l claircore.Layer 61 if err := l.Init(ctx, &test.AnyDescription, f); err != nil { 62 t.Error(err) 63 } 64 var s Detector 65 _, err = s.Scan(ctx, &l) 66 if err != nil { 67 t.Error(err) 68 } 69 } 70 71 func TestScanner(t *testing.T) { 72 ctx := zlog.Test(context.Background(), t) 73 74 mod := test.Modtime(t, "gobin_test.go") // Needs to be the name of this file. 75 p := test.GenerateFixture(t, t.Name()+".tar", mod, func(t testing.TB, tf *os.File) { 76 tmpdir := t.TempDir() 77 78 // Build a go binary. 79 outname := filepath.Join(tmpdir, "bisect") 80 cmd := exec.CommandContext(ctx, "go", "build", "-o", outname, "github.com/quay/claircore/test/bisect") 81 cmd.Env = append(cmd.Environ(), "GOOS=linux", "GOARCH=amd64") // build a Linux amd64 ELF exe, supported by clair. Unit tests may be running on another architecture 82 out, err := cmd.CombinedOutput() 83 if len(out) != 0 { 84 t.Logf("%q", string(out)) 85 } 86 if err != nil { 87 t.Fatal(err) 88 } 89 inf, err := os.Open(outname) 90 if err != nil { 91 t.Fatal(err) 92 } 93 defer inf.Close() 94 fi, err := inf.Stat() 95 if err != nil { 96 t.Fatal(err) 97 } 98 t.Logf("wrote binary to: %s", inf.Name()) 99 t.Cleanup(func() { 100 if !t.Failed() { 101 return 102 } 103 cmd := exec.CommandContext(ctx, "go", "version", "-m", inf.Name()) 104 out, err := cmd.CombinedOutput() 105 if err != nil { 106 t.Logf("error looking at toolchain reporting: %v", err) 107 return 108 } 109 t.Logf("version information reported by toolchain:\n%s", string(out)) 110 }) 111 112 // Write a tarball with the binary. 113 tw := tar.NewWriter(tf) 114 defer tw.Close() 115 hdr, err := tar.FileInfoHeader(fi, "") 116 if err != nil { 117 t.Fatal(err) 118 } 119 hdr.Name = "./bin/bisect" 120 if err := tw.WriteHeader(hdr); err != nil { 121 t.Error(err) 122 } 123 if _, err := io.Copy(tw, inf); err != nil { 124 t.Error(err) 125 } 126 }) 127 f, err := os.Open(p) 128 if err != nil { 129 t.Fatal(err) 130 } 131 t.Cleanup(func() { 132 if err := f.Close(); err != nil { 133 t.Error(err) 134 } 135 }) 136 137 var l claircore.Layer 138 if err := l.Init(ctx, &test.AnyDescription, f); err != nil { 139 t.Error(err) 140 } 141 142 // Run the scanner on the fake layer. 143 var s Detector 144 vs, err := s.Scan(ctx, &l) 145 if err != nil { 146 t.Error(err) 147 } 148 if len(vs) == 0 { 149 t.Error("no results returned") 150 } 151 // Why not just have a list? It'd change on every dependency update, which 152 // would be annoying. 153 for _, v := range vs { 154 switch { 155 case v.Name == "stdlib": 156 continue 157 case strings.HasPrefix(v.Version, "(devel)"): 158 continue 159 case v.Kind != claircore.BINARY: 160 case v.PackageDB != "go:bin/bisect": 161 t.Errorf("unexpected package DB: %s: %q", v.Name, v.PackageDB) 162 case !verRegexp.MatchString(v.Version): 163 t.Errorf("unexpected version: %s: %q", v.Name, v.Version) 164 case !strings.Contains(v.Name, "/"): 165 t.Errorf("unexpected module name: %q", v.Name) 166 default: 167 continue 168 } 169 t.Errorf("unexpected entry: %v", v) 170 } 171 } 172 173 var verRegexp = regexp.MustCompile(`^v([0-9]+\.){2}[0-9]+(-[.0-9]+-[0-9a-f]+)?(\+incompatible)?$`)