[goldctl] Add extra logging surrounding empty expectations
Bug: skia:13621, angleproject:7550
Change-Id: I9cce68560b7bd7504699c385dfcd654ff6edb2df
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/565501
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
diff --git a/gold-client/cmd/goldctl/cmd_imgtest_test.go b/gold-client/cmd/goldctl/cmd_imgtest_test.go
index b6a2478..77810b3 100644
--- a/gold-client/cmd/goldctl/cmd_imgtest_test.go
+++ b/gold-client/cmd/goldctl/cmd_imgtest_test.go
@@ -63,7 +63,7 @@
Known("11111111111111111111111111111111").Build()
// Call imgtest init with the following flags. We expect it to load the baseline expectations
- // and the known hashes (both empty).
+ // (with two images triaged) and the known hashes (one entry).
ctx, output, exit := testContext(nil, mh, nil, nil)
env := imgTest{
gitHash: "1234567890123456789012345678901234567890",
@@ -101,7 +101,7 @@
Known("11111111111111111111111111111111").Build()
// Call imgtest init with the following flags. We expect it to load the baseline expectations
- // and the known hashes (both empty).
+ // (with two images triaged) and the known hashes (one entry).
ctx, output, exit := testContext(nil, mh, nil, nil)
env := imgTest{
commitID: "92.103234.1.123456",
@@ -195,6 +195,71 @@
assert.Contains(t, outStr, `invalid configuration: field "gitHash", "commit_id", or "change_list_id" must be set`)
}
+func TestImgTest_Init_EmptyExpectationsReturned_EmitsWarning(t *testing.T) {
+ unittest.MediumTest(t)
+
+ workDir := t.TempDir()
+ setupAuthWithGSUtil(t, workDir)
+
+ keysFile := filepath.Join(workDir, "keys.json")
+ require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+
+ mh := mockRPCResponses("https://my-instance-gold.skia.org").
+ Known("11111111111111111111111111111111").Build()
+
+ ctx, output, exit := testContext(nil, mh, nil, nil)
+ env := imgTest{
+ gitHash: "1234567890123456789012345678901234567890",
+ corpus: "my_corpus",
+ instanceID: "my-instance",
+ keysFile: keysFile,
+ passFailStep: true,
+ workDir: workDir,
+ }
+ runUntilExit(t, func() {
+ env.Init(ctx)
+ })
+ logs := output.String()
+ exit.AssertWasCalledWithCode(t, 0, logs)
+ assert.Contains(t, logs, "warning: got empty expectations when querying https://my-instance-gold.skia.org/json/v2/expectations\n")
+}
+
+func TestImgTest_InitCheck_EmptyExpectationsReturned_ReturnsNonzeroExitCode(t *testing.T) {
+ unittest.MediumTest(t)
+
+ workDir := t.TempDir()
+ setupAuthWithGSUtil(t, workDir)
+
+ keysFile := filepath.Join(workDir, "keys.json")
+ require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+
+ mh := mockRPCResponses("https://my-instance-gold.skia.org").
+ Known("11111111111111111111111111111111").Build()
+
+ ctx, output, exit := testContext(nil, mh, nil, nil)
+ env := imgTest{
+ gitHash: "1234567890123456789012345678901234567890",
+ corpus: "my_corpus",
+ instanceID: "my-instance",
+ keysFile: keysFile,
+ passFailStep: true,
+ workDir: workDir,
+ }
+ runUntilExit(t, func() {
+ env.Init(ctx)
+ })
+ exit.AssertWasCalledWithCode(t, 0, output.String())
+
+ output.buf.Reset()
+ runUntilExit(t, func() {
+ env.Check(ctx)
+ })
+ logs := output.String()
+ exit.AssertWasCalledWithCode(t, 1, logs)
+ assert.Contains(t, logs, "Expectations are empty, despite re-loading them from Gold")
+ assert.Contains(t, logs, `raw expectation response "{}"`)
+}
+
func TestImgTest_InitAdd_StreamingPassFail_DoesNotMatchExpectations_NonzeroExitCode(t *testing.T) {
unittest.MediumTest(t)
diff --git a/gold-client/cmd/goldctl/cmd_whoami_test.go b/gold-client/cmd/goldctl/cmd_whoami_test.go
index 9a51c74..8afcaed 100644
--- a/gold-client/cmd/goldctl/cmd_whoami_test.go
+++ b/gold-client/cmd/goldctl/cmd_whoami_test.go
@@ -64,10 +64,15 @@
assert.Contains(t, output.String(), `Logged in as ""`)
}
-func httpResponse(body, status string, statusCode int) *http.Response {
- return &http.Response{
- Body: ioutil.NopCloser(strings.NewReader(body)),
- Status: status,
- StatusCode: statusCode,
+// This returns a function that returns a fresh response. Returning a static response works for
+// the first mocked call to this function, but subsequent ones read nothing (because the string
+// reader has already read all its bytes).
+func httpResponse(body, status string, statusCode int) func(string) *http.Response {
+ return func(_ string) *http.Response {
+ return &http.Response{
+ Body: ioutil.NopCloser(strings.NewReader(body)),
+ Status: status,
+ StatusCode: statusCode,
+ }
}
}
diff --git a/gold-client/go/goldclient/goldclient.go b/gold-client/go/goldclient/goldclient.go
index ce01758..d754a36 100644
--- a/gold-client/go/goldclient/goldclient.go
+++ b/gold-client/go/goldclient/goldclient.go
@@ -400,6 +400,9 @@
return false, skerr.Wrapf(err, "writing the expectations to disk")
}
}
+ if len(c.resultState.Expectations) == 0 {
+ return false, skerr.Fmt("Expectations are empty, despite re-loading them from Gold")
+ }
// Load the PNG from disk and hash it.
imgBytes, imgHash, err := c.loadAndHashImage(imgFileName)
@@ -574,14 +577,14 @@
func (c *CloudClient) downloadHashesAndBaselineFromGold(ctx context.Context) error {
// What hashes have we seen already (to avoid uploading them again).
if err := c.resultState.loadKnownHashes(ctx); err != nil {
- return err
+ return skerr.Wrap(err)
}
infof(ctx, "Loaded %d known hashes\n", len(c.resultState.KnownHashes))
- // Fetch the baseline (may be empty but should not fail).
+ // Fetch the baseline
if err := c.resultState.loadExpectations(ctx); err != nil {
- return err
+ return skerr.Wrap(err)
}
infof(ctx, "Loaded %d tests from the baseline\n", len(c.resultState.Expectations))
diff --git a/gold-client/go/goldclient/resultstate.go b/gold-client/go/goldclient/resultstate.go
index abc1cfd..d185501 100644
--- a/gold-client/go/goldclient/resultstate.go
+++ b/gold-client/go/goldclient/resultstate.go
@@ -137,10 +137,14 @@
if len(jsonBytes) > 200 {
infof(ctx, `Invalid JSON: "%s..."`, string(jsonBytes[0:200]))
} else {
- infof(ctx, `Invalid JSON: "%s"`, string(jsonBytes))
+ infof(ctx, `Invalid JSON: %q`, string(jsonBytes))
}
return skerr.Wrapf(err, "parsing JSON; this sometimes means auth issues")
}
+ if len(exp.Expectations) == 0 {
+ errorf(ctx, "warning: got empty expectations when querying %s\n", u)
+ errorf(ctx, "raw expectation response %q\n", string(jsonBytes))
+ }
r.Expectations = exp.Expectations
return nil