Skip to content

Commit c4aaf26

Browse files
authored
Make VCR correctly handle compound tests (#13941)
1 parent 9d90550 commit c4aaf26

File tree

4 files changed

+138
-16
lines changed

4 files changed

+138
-16
lines changed

.ci/magician/cmd/templates/vcr/record_replay.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
{{color "red" "Tests failed when rerunning REPLAYING mode:"}}
1212
{{range .ReplayingAfterRecordingResult.FailedTests -}}
1313
`{{.}}` {{/* remove trailing whitespace */ -}}
14-
[[Error message](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/build-log/replaying_build_after_recording/{{.}}_replaying_test.log)] {{/* remove trailing whitespace */ -}}
14+
[[Error message](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/build-log/replaying_build_after_recording/{{compoundTest .}}_replaying_test.log)] {{/* remove trailing whitespace */ -}}
1515
[[Debug log](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/replaying_after_recording/{{.}}.log)]
1616
{{/* remove trailing whitespace */ -}}
1717
{{end}}
@@ -30,7 +30,7 @@ Please fix these to complete your PR. If you believe these test failures to be i
3030
{{color "red" "Tests failed during RECORDING mode:"}}
3131
{{range .RecordingResult.FailedTests -}}
3232
`{{.}}` {{/* remove trailing whitespace */ -}}
33-
[[Error message](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/build-log/recording_build/{{.}}_recording_test.log)] {{/* remove trailing whitespace */ -}}
33+
[[Error message](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/build-log/recording_build/{{compoundTest .}}_recording_test.log)] {{/* remove trailing whitespace */ -}}
3434
[[Debug log](https://storage.cloud.google.com/{{$.LogBucket}}/{{$.Version}}/refs/heads/{{$.Head}}/artifacts/{{$.BuildID}}/recording/{{.}}.log)]
3535
{{/* remove trailing whitespace */ -}}
3636
{{end}}

.ci/magician/cmd/test_terraform_vcr.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,13 @@ func execTestTerraformVCR(prNumber, mmCommitSha, buildID, projectID, buildStep,
235235
}
236236

237237
notRunBeta, notRunGa := notRunTests(tpgRepo.UnifiedZeroDiff, tpgbRepo.UnifiedZeroDiff, replayingResult)
238+
238239
postReplayData := postReplay{
239240
RunFullVCR: runFullVCR,
240241
AffectedServices: sort.StringSlice(servicesArr),
241242
NotRunBetaTests: notRunBeta,
242243
NotRunGATests: notRunGa,
243-
ReplayingResult: replayingResult,
244+
ReplayingResult: subtestResult(replayingResult),
244245
ReplayingErr: replayingErr,
245246
LogBucket: "ci-vcr-logs",
246247
Version: provider.Beta.String(),
@@ -318,8 +319,8 @@ func execTestTerraformVCR(prNumber, mmCommitSha, buildID, projectID, buildStep,
318319
allRecordingPassed := len(recordingResult.FailedTests) == 0 && !hasTerminatedTests && recordingErr == nil
319320

320321
recordReplayData := recordReplay{
321-
RecordingResult: recordingResult,
322-
ReplayingAfterRecordingResult: replayingAfterRecordingResult,
322+
RecordingResult: subtestResult(recordingResult),
323+
ReplayingAfterRecordingResult: subtestResult(replayingAfterRecordingResult),
323324
RecordingErr: recordingErr,
324325
HasTerminatedTests: hasTerminatedTests,
325326
AllRecordingPassed: allRecordingPassed,
@@ -386,6 +387,43 @@ func notRunTests(gaDiff, betaDiff string, result vcr.Result) ([]string, []string
386387
return notRunBeta, notRunGa
387388
}
388389

390+
func subtestResult(original vcr.Result) vcr.Result {
391+
return vcr.Result{
392+
PassedTests: excludeCompoundTests(original.PassedTests, original.PassedSubtests),
393+
FailedTests: excludeCompoundTests(original.FailedTests, original.FailedSubtests),
394+
SkippedTests: excludeCompoundTests(original.SkippedTests, original.SkippedSubtests),
395+
Panics: original.Panics,
396+
}
397+
}
398+
399+
// Returns the name of the compound test that the given subtest belongs to.
400+
func compoundTest(subtest string) string {
401+
parts := strings.Split(subtest, "__")
402+
if len(parts) != 2 {
403+
return subtest
404+
}
405+
return parts[0]
406+
}
407+
408+
// Returns subtests and tests that are not compound tests.
409+
func excludeCompoundTests(allTests, subtests []string) []string {
410+
res := make([]string, 0, len(allTests)+len(subtests))
411+
compoundTests := make(map[string]struct{}, len(subtests))
412+
for _, subtest := range subtests {
413+
if compound := compoundTest(subtest); compound != subtest {
414+
compoundTests[compound] = struct{}{}
415+
res = append(res, subtest)
416+
}
417+
}
418+
for _, test := range allTests {
419+
if _, ok := compoundTests[test]; !ok {
420+
res = append(res, test)
421+
}
422+
}
423+
sort.Strings(res)
424+
return res
425+
}
426+
389427
func modifiedPackages(changedFiles []string, version provider.Version) (map[string]struct{}, bool) {
390428
var goFiles []string
391429
for _, line := range changedFiles {
@@ -468,9 +506,10 @@ func init() {
468506

469507
func formatComment(fileName string, tmplText string, data any) (string, error) {
470508
funcs := template.FuncMap{
471-
"join": strings.Join,
472-
"add": func(i, j int) int { return i + j },
473-
"color": color,
509+
"join": strings.Join,
510+
"add": func(i, j int) int { return i + j },
511+
"color": color,
512+
"compoundTest": compoundTest,
474513
}
475514
tmpl, err := template.New(fileName).Funcs(funcs).Parse(tmplText)
476515
if err != nil {

.ci/magician/vcr/tester.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ import (
1313
)
1414

1515
type Result struct {
16-
PassedTests []string
17-
SkippedTests []string
18-
FailedTests []string
19-
Panics []string
16+
PassedTests []string
17+
SkippedTests []string
18+
FailedTests []string
19+
PassedSubtests []string
20+
SkippedSubtests []string
21+
FailedSubtests []string
22+
Panics []string
2023
}
2124

2225
type Mode int
@@ -66,6 +69,8 @@ const replayingTimeout = "240m"
6669

6770
var testResultsExpression = regexp.MustCompile(`(?m:^--- (PASS|FAIL|SKIP): (TestAcc\w+))`)
6871

72+
var subtestResultsExpression = regexp.MustCompile(`(?m:^ --- (PASS|FAIL|SKIP): (TestAcc\w+)/(\w+))`)
73+
6974
var testPanicExpression = regexp.MustCompile(`^panic: .*`)
7075

7176
var safeToLog = map[string]bool{
@@ -603,19 +608,39 @@ func collectResult(output string) Result {
603608
}
604609
resultSets[submatches[1]][submatches[2]] = struct{}{}
605610
}
611+
matches = subtestResultsExpression.FindAllStringSubmatch(output, -1)
612+
subtestResultSets := make(map[string]map[string]struct{}, 4)
613+
for _, submatches := range matches {
614+
if len(submatches) != 4 {
615+
fmt.Printf("Warning: unexpected regex match found in test output: %v", submatches)
616+
continue
617+
}
618+
if _, ok := subtestResultSets[submatches[1]]; !ok {
619+
subtestResultSets[submatches[1]] = make(map[string]struct{})
620+
}
621+
subtestResultSets[submatches[1]][fmt.Sprintf("%s__%s", submatches[2], submatches[3])] = struct{}{}
622+
}
606623
results := make(map[string][]string, 4)
607624
results["PANIC"] = testPanicExpression.FindAllString(output, -1)
608625
sort.Strings(results["PANIC"])
626+
subtestResults := make(map[string][]string, 3)
609627
for _, kind := range []string{"FAIL", "PASS", "SKIP"} {
610628
for test := range resultSets[kind] {
611629
results[kind] = append(results[kind], test)
612630
}
613631
sort.Strings(results[kind])
632+
for subtest := range subtestResultSets[kind] {
633+
subtestResults[kind] = append(subtestResults[kind], subtest)
634+
}
635+
sort.Strings(subtestResults[kind])
614636
}
615637
return Result{
616-
FailedTests: results["FAIL"],
617-
PassedTests: results["PASS"],
618-
SkippedTests: results["SKIP"],
619-
Panics: results["PANIC"],
638+
FailedTests: results["FAIL"],
639+
PassedTests: results["PASS"],
640+
SkippedTests: results["SKIP"],
641+
FailedSubtests: subtestResults["FAIL"],
642+
PassedSubtests: subtestResults["PASS"],
643+
SkippedSubtests: subtestResults["SKIP"],
644+
Panics: results["PANIC"],
620645
}
621646
}

.ci/magician/vcr/tester_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package vcr
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
)
8+
9+
func TestCollectResults(t *testing.T) {
10+
for _, test := range []struct {
11+
name string
12+
output string
13+
expected Result
14+
}{
15+
{
16+
name: "no compound tests",
17+
output: `--- FAIL: TestAccServiceOneResourceOne (100.00s)
18+
--- PASS: TestAccServiceOneResourceTwo (100.00s)
19+
--- PASS: TestAccServiceTwoResourceOne (100.00s)
20+
--- PASS: TestAccServiceTwoResourceTwo (100.00s)
21+
`,
22+
expected: Result{
23+
PassedTests: []string{"TestAccServiceOneResourceTwo", "TestAccServiceTwoResourceOne", "TestAccServiceTwoResourceTwo"},
24+
FailedTests: []string{"TestAccServiceOneResourceOne"},
25+
},
26+
},
27+
{
28+
name: "compound tests",
29+
output: `--- FAIL: TestAccServiceOneResourceOne (100.00s)
30+
--- FAIL: TestAccServiceOneResourceTwo (100.00s)
31+
--- PASS: TestAccServiceOneResourceTwo/test_one (100.00s)
32+
--- FAIL: TestAccServiceOneResourceTwo/test_two (100.00s)
33+
--- PASS: TestAccServiceTwoResourceOne (100.00s)
34+
--- PASS: TestAccServiceTwoResourceOne/test_one (100.00s)
35+
--- PASS: TestAccServiceTwoResourceOne/test_two (100.00s)
36+
--- PASS: TestAccServiceTwoResourceTwo (100.00s)
37+
`,
38+
expected: Result{
39+
PassedTests: []string{
40+
"TestAccServiceTwoResourceOne",
41+
"TestAccServiceTwoResourceTwo",
42+
},
43+
FailedTests: []string{"TestAccServiceOneResourceOne", "TestAccServiceOneResourceTwo"},
44+
PassedSubtests: []string{
45+
"TestAccServiceOneResourceTwo__test_one",
46+
"TestAccServiceTwoResourceOne__test_one",
47+
"TestAccServiceTwoResourceOne__test_two",
48+
},
49+
FailedSubtests: []string{"TestAccServiceOneResourceTwo__test_two"},
50+
},
51+
},
52+
} {
53+
if diff := cmp.Diff(test.expected, collectResult(test.output)); diff != "" {
54+
t.Errorf("collectResult(%q) got unexpected diff (-want +got):\n%s", test.output, diff)
55+
}
56+
}
57+
58+
}

0 commit comments

Comments
 (0)