blob: ec4800b4a8203e66051ccd0223158046665f9bf6 [file] [log] [blame]
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"encoding/json"
"errors"
"os"
"os/exec"
"runtime"
"strings"
"testing"
"golang.org/x/exp/slices"
"golang.org/x/pkgsite-metrics/internal/derrors"
"golang.org/x/pkgsite-metrics/internal/worker"
"golang.org/x/vuln/vulncheck"
)
func Test(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("cannot run on Windows")
}
checkVuln := func(t *testing.T, res *vulncheck.Result) {
wantID := "GO-2021-0113"
i := slices.IndexFunc(res.Vulns, func(v *vulncheck.Vuln) bool {
return v.OSV.ID == wantID
})
if i < 0 {
t.Fatalf("no vuln with ID %s. Result:\n%+v", wantID, res)
}
}
t.Run("source", func(t *testing.T) {
res, err := runTest([]string{worker.ModeImports, "testdata/module"}, "testdata/vulndb")
if err != nil {
t.Fatal(err)
}
checkVuln(t, res)
})
t.Run("binary", func(t *testing.T) {
t.Skip("vulncheck.Binary may not support the Go version")
const binary = "testdata/module/vuln"
cmd := exec.Command("go build")
cmd.Dir = "testdata/module"
if _, err := cmd.Output(); err != nil {
t.Fatal(derrors.IncludeStderr(err))
}
defer os.Remove(binary)
res, err := runTest([]string{worker.ModeBinary, binary}, "testdata/vulndb")
if err != nil {
t.Fatal(err)
}
checkVuln(t, res)
})
// Errors
for _, test := range []struct {
name string
args []string
vulndb string
want string
}{
{
name: "too few args",
args: []string{"testdata/module"},
vulndb: "testdata/vulndb",
want: "need two args",
},
{
name: "no vulndb",
args: []string{worker.ModeImports, "testdata/module"},
vulndb: "does not exist",
want: "no such file",
},
{
name: "no mode",
args: []string{"MODE", "testdata/module"},
vulndb: "testdata/vulndb",
want: "not a valid mode",
},
{
name: "no module",
args: []string{worker.ModeImports, "testdata/nosuchmodule"},
vulndb: "testdata/vulndb",
want: "no such file",
},
} {
t.Run(test.name, func(t *testing.T) {
_, err := runTest(test.args, test.vulndb)
if err == nil {
t.Fatal("got nil, want error")
}
if g, w := err.Error(), test.want; !strings.Contains(g, w) {
t.Fatalf("error %q does not contain %q", g, w)
}
})
}
}
func runTest(args []string, vulndbDir string) (*vulncheck.Result, error) {
var buf bytes.Buffer
run(&buf, args, vulndbDir)
return unmarshalVulncheckOutput(buf.Bytes())
}
func unmarshalVulncheckOutput(output []byte) (*vulncheck.Result, error) {
var e struct {
Error string
}
if err := json.Unmarshal(output, &e); err != nil {
return nil, err
}
if e.Error != "" {
return nil, errors.New(e.Error)
}
var res vulncheck.Result
if err := json.Unmarshal(output, &res); err != nil {
return nil, err
}
return &res, nil
}