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)?$`)