runner: add one-to-many error mapping for canonical error checking in BoGo tests
Associated Issue: https://github.com/golang/go/issues/71066
Change-Id: I6d8e35f03249bd0b612e54e6c00452f50f4cb4bf
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/75507
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 47fac16..8cbb46b 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -94,7 +94,7 @@
// string for the shim in question. For example, it might map
// “:NO_SHARED_CIPHER:” (a BoringSSL error string) to something
// like “SSL_ERROR_NO_CYPHER_OVERLAP”.
- ErrorMap map[string]string
+ ErrorMap map[string][]string
// HalfRTTTickets is the number of half-RTT tickets the client should
// expect before half-RTT data when testing 0-RTT.
@@ -1450,16 +1450,42 @@
return nil
}
-func translateExpectedError(errorStr string) string {
- if translated, ok := shimConfig.ErrorMap[errorStr]; ok {
+// translateExpectedError uses a canonical BoringSSL error to produce
+// a slice of expected canonical errors in bogo_shim_config.json.
+func translateExpectedError(canonical string) []string {
+ if translated, found := shimConfig.ErrorMap[canonical]; found {
return translated
}
- if *looseErrors {
- return ""
- }
+ // not specifying a canonical error will have the same effect as -loose-errors being true
+ // since the emptry string with match all error substrings.
+ return []string{canonical}
+}
- return errorStr
+// formatErrors takes the semantic mapping from translateExpectedError
+// and outputs human-readable digest of BoGo error state.
+func formatErrors(expectedErrors []string, stderr, local, child, stdout, expectedLocal, expectedCanonical string) (string, string) {
+ got := fmt.Sprintf("\tstderr:\n\t\t%s\n\tlocal: %q\n\tchild: %q\n\tstdout: %s", stderr, local, child, stdout)
+ want := fmt.Sprintf("\tlocal: %q\n\tremote: %q", expectedLocal, expectedCanonical)
+ if slices.Equal(expectedErrors, []string{expectedCanonical}) {
+ return got, want
+ }
+ if len(expectedErrors) == 0 || expectedErrors == nil {
+ return got, want + " (no specified mapping)"
+ }
+ return got, want + " mapped to one of:\n\t\t" + strings.Join(expectedErrors, "\n\t\t")
+}
+
+// matchError plucks the relevant canonical error from the provided
+// slice if found; if the slice is empty/nil, strict error checking
+// is presumed to be disabled.
+func matchError(expectedErrors []string, stderr string) bool {
+ for _, expectedError := range expectedErrors {
+ if strings.Contains(stderr, expectedError) {
+ return true
+ }
+ }
+ return false
}
// shimInitialWrite is the data we expect from the shim when the
@@ -1808,8 +1834,8 @@
}
failed := localErr != nil || childErr != nil
- expectedError := translateExpectedError(test.expectedError)
- correctFailure := len(expectedError) == 0 || strings.Contains(stderr, expectedError)
+ expectedErrors := translateExpectedError(test.expectedError)
+ correctFailure := *looseErrors || matchError(expectedErrors, stderr)
localErrString := "none"
if localErr != nil {
@@ -1825,21 +1851,25 @@
childErrString = childErr.Error()
}
+ got, want := formatErrors(expectedErrors,
+ stderr, localErrString, childErrString, stdout,
+ test.expectedLocalError, test.expectedError)
+
var msg string
switch {
case failed && !test.shouldFail:
msg = "unexpected failure"
case !failed && test.shouldFail:
- msg = fmt.Sprintf("unexpected success (wanted failure with %q / %q)", expectedError, test.expectedLocalError)
+ msg = fmt.Sprintf("unexpected success\nwant:\n%s\n", want)
case failed && !correctFailure:
- msg = fmt.Sprintf("bad error (wanted %q / %q)", expectedError, test.expectedLocalError)
+ msg = fmt.Sprintf("unexpected error\ngot:\n%s\n\nwant:\n%s\n", got, want)
case mustFail:
msg = "test failure"
default:
panic("internal error")
}
- return fmt.Errorf("%s: local error %q, child error %q, stdout:\n%s\nstderr:\n%s\n%s", msg, localErrString, childErrString, stdout, stderr, extraStderr)
+ return fmt.Errorf("%s\nextra stderr:\n%s", msg, extraStderr)
}
if len(extraStderr) > 0 || (!failed && len(stderr) > 0) {