Skip to content

Commit ccf7526

Browse files
committed
internal/{proxy,genericosv}: add mock proxy framework and use in TestToReport
Adds a framework to more easily store proxy responses for testing and create mock proxy clients. TestToReport is now hermetic by default, as it reads mock proxy responses from a JSON file. If the -proxy flag set, the test contacts the real module proxy and re-writes the JSON file. (In most cases, there should be no need to use this flag). For golang/go#61769 Change-Id: I7cfcea44b94ee57105bedcaf2f4d514ad2436688 Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/522835 Run-TryBot: Tatiana Bradley <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 7fdbb06 commit ccf7526

File tree

5 files changed

+596
-74
lines changed

5 files changed

+596
-74
lines changed

internal/genericosv/report_test.go

Lines changed: 93 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,88 @@
55
package genericosv
66

77
import (
8+
"encoding/json"
89
"flag"
910
"io/fs"
11+
"os"
1012
"path/filepath"
1113
"strings"
1214
"testing"
1315

1416
"github.com/google/go-cmp/cmp"
1517
osvschema "github.com/google/osv-scanner/pkg/models"
18+
"golang.org/x/vulndb/internal/proxy"
1619
"golang.org/x/vulndb/internal/report"
1720
)
1821

19-
var update = flag.Bool("update", false, "if true, update test cases")
22+
var (
23+
realProxy = flag.Bool("proxy", false, "if true, contact the real module proxy and update expected responses")
24+
update = flag.Bool("update", false, "if true, update test YAML reports to reflect new expected behavior")
25+
)
2026

2127
var (
22-
testdataDir = "testdata"
23-
testOSVDir = filepath.Join(testdataDir, "osv")
24-
testYAMLDir = filepath.Join(testdataDir, "yaml")
28+
testdataDir = "testdata"
29+
testOSVDir = filepath.Join(testdataDir, "osv")
30+
testYAMLDir = filepath.Join(testdataDir, "yaml")
31+
proxyResponsesFile = filepath.Join(testdataDir, "proxy.json")
2532
)
2633

2734
// To update test cases to reflect new expected behavior:
2835
// go test ./internal/genericosv/... -update -run TestToReport
29-
//
30-
// TODO(https://go.dev/issues/61769): mock out proxy calls in the non-update
31-
// case so that this test is hermetic.
3236
func TestToReport(t *testing.T) {
33-
t.Skip("need to mock out proxy calls")
34-
if err := filepath.WalkDir(testOSVDir, func(path string, f fs.DirEntry, err error) error {
35-
if err != nil {
36-
return err
37-
}
38-
if f.IsDir() || filepath.Ext(path) != ".json" {
39-
return nil
40-
}
41-
ghsaID := strings.TrimSuffix(f.Name(), ".json")
42-
t.Run(ghsaID, func(t *testing.T) {
43-
t.Parallel()
44-
osv := Entry{}
45-
if err := report.UnmarshalFromFile(path, &osv); err != nil {
37+
if *realProxy {
38+
defer func() {
39+
err := updateProxyResponses()
40+
if err != nil {
4641
t.Fatal(err)
4742
}
48-
got := osv.ToReport("GO-TEST-ID")
49-
yamlFile := filepath.Join(testYAMLDir, ghsaID+".yaml")
50-
if *update {
51-
if err := got.Write(yamlFile); err != nil {
52-
t.Fatal(err)
53-
}
54-
}
55-
want, err := report.Read(yamlFile)
43+
}()
44+
} else {
45+
err := setupMockProxy(t)
46+
if err != nil {
47+
t.Fatal(err)
48+
}
49+
}
50+
51+
// The outer test run forces the test to wait for all parallel tests
52+
// to finish before tearing down test.
53+
t.Run("run", func(t *testing.T) {
54+
if err := filepath.WalkDir(testOSVDir, func(path string, f fs.DirEntry, err error) error {
5655
if err != nil {
57-
t.Fatal(err)
56+
return err
5857
}
59-
if diff := cmp.Diff(want, got); diff != "" {
60-
t.Errorf("ToReport() mismatch (-want +got)\n%s", diff)
58+
if f.IsDir() || filepath.Ext(path) != ".json" {
59+
return nil
6160
}
62-
})
63-
return nil
64-
}); err != nil {
65-
t.Fatal(err)
66-
}
61+
ghsaID := strings.TrimSuffix(f.Name(), ".json")
62+
t.Run(ghsaID, func(t *testing.T) {
63+
t.Parallel()
64+
65+
osv := Entry{}
66+
if err := report.UnmarshalFromFile(path, &osv); err != nil {
67+
t.Fatal(err)
68+
}
69+
70+
got := osv.ToReport("GO-TEST-ID")
71+
yamlFile := filepath.Join(testYAMLDir, ghsaID+".yaml")
72+
if *update {
73+
if err := got.Write(yamlFile); err != nil {
74+
t.Fatal(err)
75+
}
76+
}
77+
want, err := report.Read(yamlFile)
78+
if err != nil {
79+
t.Fatal(err)
80+
}
81+
if diff := cmp.Diff(want, got); diff != "" {
82+
t.Errorf("ToReport() mismatch (-want +got)\n%s", diff)
83+
}
84+
})
85+
return nil
86+
}); err != nil {
87+
t.Fatal(err)
88+
}
89+
})
6790
}
6891

6992
// TODO(https://go.dev/issues/61769): unskip test cases as we add features.
@@ -260,3 +283,37 @@ func TestAffectedToModules(t *testing.T) {
260283

261284
}
262285
}
286+
287+
// Use saved responses from testdata/proxy.json instead of real proxy calls.
288+
func setupMockProxy(t *testing.T) error {
289+
t.Helper()
290+
291+
b, err := os.ReadFile(proxyResponsesFile)
292+
if err != nil {
293+
return err
294+
}
295+
var responses map[string]*proxy.Response
296+
err = json.Unmarshal(b, &responses)
297+
if err != nil {
298+
return err
299+
}
300+
301+
defaultProxyClient := proxy.DefaultClient
302+
testClient, cleanup := proxy.NewTestClient(responses)
303+
proxy.DefaultClient = testClient
304+
t.Cleanup(cleanup)
305+
t.Cleanup(func() {
306+
proxy.DefaultClient = defaultProxyClient
307+
})
308+
309+
return nil
310+
}
311+
312+
// Write proxy responses for this run to testdata/proxy.json.
313+
func updateProxyResponses() error {
314+
responses, err := json.MarshalIndent(proxy.Responses(), "", "\t")
315+
if err != nil {
316+
return err
317+
}
318+
return os.WriteFile(proxyResponsesFile, responses, 0644)
319+
}

0 commit comments

Comments
 (0)