internal/worker: add hermetic test for analysis scan
Add a test that covers nearly all of the analysis scan code,
but does not touch the network.
- Use the proxytest package (copied from pkgsite a while ago
but never used here) to get a fake proxy.
- Pass an openFileFunc to copy the binary from the local disk
instead of GCS.
Change-Id: I357a9a6b6bffa689bbf1185c1c5a758c84078796
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/474545
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/worker/analysis_test.go b/internal/worker/analysis_test.go
index 39ea342..1b06ac2 100644
--- a/internal/worker/analysis_test.go
+++ b/internal/worker/analysis_test.go
@@ -5,12 +5,20 @@
package worker
import (
+ "context"
+ "errors"
+ "io"
+ "os"
"path/filepath"
+ "strings"
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/pkgsite-metrics/internal/analysis"
"golang.org/x/pkgsite-metrics/internal/buildtest"
+ "golang.org/x/pkgsite-metrics/internal/config"
+ "golang.org/x/pkgsite-metrics/internal/proxy/proxytest"
"golang.org/x/pkgsite-metrics/internal/queue"
"golang.org/x/pkgsite-metrics/internal/scan"
)
@@ -85,3 +93,96 @@
t.Errorf("mismatch (-want +got):\n%s", diff)
}
}
+
+func TestAnalysisScan(t *testing.T) {
+ const (
+ binary = "./analyzer"
+ modulePath = "a.com/m"
+ version = "v1.2.3"
+ )
+ binaryPath, cleanup := buildtest.GoBuild(t, "testdata/analyzer", "")
+ defer cleanup()
+ proxyClient, cleanup2 := proxytest.SetupTestClient(t, []*proxytest.Module{
+ {
+ ModulePath: modulePath,
+ Version: version,
+ Files: map[string]string{
+ "go.mod": `module ` + modulePath,
+ "a.go": `
+package p
+func F() { G() }
+func G() {}
+`},
+ },
+ })
+ defer cleanup2()
+
+ diff := func(want, got *analysis.Result) {
+ t.Helper()
+ d := cmp.Diff(want, got,
+ cmpopts.IgnoreFields(analysis.WorkVersion{}, "BinaryVersion", "SchemaVersion"),
+ cmpopts.IgnoreFields(analysis.Diagnostic{}, "Position"))
+ if d != "" {
+ t.Errorf("mismatch (-want, +got)\n%s", d)
+ }
+ }
+
+ s := &analysisServer{
+ Server: &Server{
+ proxyClient: proxyClient,
+ cfg: &config.Config{
+ BinaryBucket: "unused",
+ },
+ },
+ openFile: func(name string) (io.ReadCloser, error) {
+ if name == "analysis-binaries/analyzer" {
+ return os.Open(binaryPath)
+ }
+ return nil, errors.New("bad name")
+ },
+ }
+ req := &analysis.ScanRequest{
+ ModuleURLPath: scan.ModuleURLPath{Module: modulePath, Version: version},
+ ScanParams: analysis.ScanParams{
+ Binary: "analyzer",
+ Args: "-name G",
+ Insecure: true,
+ },
+ }
+ got := s.scan(context.Background(), req)
+ want := &analysis.Result{
+ ModulePath: modulePath,
+ Version: version,
+ SortVersion: "1,2,3~",
+ CommitTime: proxytest.CommitTime,
+ BinaryName: "analyzer",
+ WorkVersion: analysis.WorkVersion{BinaryArgs: "-name G"},
+ Error: "",
+ ErrorCategory: "",
+ Diagnostics: []*analysis.Diagnostic{
+ {
+ PackageID: "a.com/m",
+ AnalyzerName: "findcall",
+ Message: "call of G(...)",
+ },
+ },
+ }
+ diff(want, got)
+
+ // Test that errors are put into the Result.
+ req.Binary = "bad"
+ got = s.scan(context.Background(), req)
+ // Trim varying part of error.
+ if i := strings.LastIndexByte(got.Error, ':'); i > 0 {
+ got.Error = got.Error[i+2:]
+ }
+ want = &analysis.Result{
+ ModulePath: modulePath,
+ Version: version,
+ SortVersion: "1,2,3~",
+ BinaryName: "bad",
+ WorkVersion: analysis.WorkVersion{BinaryArgs: "-name G"},
+ Error: "bad name",
+ }
+ diff(want, got)
+}