7
7
"regexp"
8
8
"sort"
9
9
"strings"
10
+ "text/template"
10
11
11
12
"github.com/spf13/cobra"
12
13
@@ -15,6 +16,21 @@ import (
15
16
"magician/provider"
16
17
"magician/source"
17
18
"magician/vcr"
19
+
20
+ _ "embed"
21
+ )
22
+
23
+ var (
24
+ //go:embed test_terraform_vcr_test_analytics.tmpl
25
+ testsAnalyticsTmplText string
26
+ //go:embed test_terraform_vcr_non_exercised_tests.tmpl
27
+ nonExercisedTestsTmplText string
28
+ //go:embed test_terraform_vcr_with_replay_failed_tests.tmpl
29
+ withReplayFailedTestsTmplText string
30
+ //go:embed test_terraform_vcr_without_replay_failed_tests.tmpl
31
+ withoutReplayFailedTestsTmplText string
32
+ //go:embed test_terraform_vcr_record_replay.tmpl
33
+ recordReplayTmplText string
18
34
)
19
35
20
36
var ttvEnvironmentVariables = [... ]string {
@@ -40,6 +56,37 @@ var ttvEnvironmentVariables = [...]string{
40
56
"USER" ,
41
57
}
42
58
59
+ type analytics struct {
60
+ ReplayingResult * vcr.Result
61
+ RunFullVCR bool
62
+ AffectedServices []string
63
+ }
64
+
65
+ type nonExercisedTests struct {
66
+ NotRunBetaTests []string
67
+ NotRunGATests []string
68
+ }
69
+
70
+ type withReplayFailedTests struct {
71
+ ReplayingResult * vcr.Result
72
+ }
73
+
74
+ type withoutReplayFailedTests struct {
75
+ ReplayingErr error
76
+ PRNumber string
77
+ BuildID string
78
+ }
79
+
80
+ type recordReplay struct {
81
+ RecordingResult * vcr.Result
82
+ ReplayingAfterRecordingResult * vcr.Result
83
+ HasTerminatedTests bool
84
+ RecordingErr error
85
+ AllRecordingPassed bool
86
+ PRNumber string
87
+ BuildID string
88
+ }
89
+
43
90
var testTerraformVCRCmd = & cobra.Command {
44
91
Use : "test-terraform-vcr" ,
45
92
Short : "Run vcr tests for affected packages" ,
@@ -143,7 +190,7 @@ func execTestTerraformVCR(prNumber, mmCommitSha, buildID, projectID, buildStep,
143
190
return fmt .Errorf ("error posting pending status: %w" , err )
144
191
}
145
192
146
- replayingResult , affectedServicesComment , testDirs , replayingErr := runReplaying (runFullVCR , services , vt )
193
+ replayingResult , testDirs , replayingErr := runReplaying (runFullVCR , services , vt )
147
194
testState := "success"
148
195
if replayingErr != nil {
149
196
testState = "failure"
@@ -159,55 +206,41 @@ func execTestTerraformVCR(prNumber, mmCommitSha, buildID, projectID, buildStep,
159
206
return nil
160
207
}
161
208
162
- failedTestsPattern := strings .Join (replayingResult .FailedTests , "|" )
163
-
164
- comment := `#### Tests analytics
165
- Total tests: ` + fmt .Sprintf ("`%d`" , len (replayingResult .PassedTests )+ len (replayingResult .SkippedTests )+ len (replayingResult .FailedTests )) + `
166
- Passed tests: ` + fmt .Sprintf ("`%d`" , len (replayingResult .PassedTests )) + `
167
- Skipped tests: ` + fmt .Sprintf ("`%d`" , len (replayingResult .SkippedTests )) + `
168
- Affected tests: ` + fmt .Sprintf ("`%d`" , len (replayingResult .FailedTests )) + `
169
-
170
- <details><summary>Click here to see the affected service packages</summary><blockquote>` + affectedServicesComment + `</blockquote></details>`
209
+ var servicesArr []string
210
+ for s := range services {
211
+ servicesArr = append (servicesArr , s )
212
+ }
213
+ analyticsData := analytics {
214
+ ReplayingResult : replayingResult ,
215
+ RunFullVCR : runFullVCR ,
216
+ AffectedServices : sort .StringSlice (servicesArr ),
217
+ }
218
+ testsAnalyticsComment , err := formatTestsAnalytics (analyticsData )
219
+ if err != nil {
220
+ return fmt .Errorf ("error formatting test_analytics comment: %w" , err )
221
+ }
171
222
172
223
notRunBeta , notRunGa := notRunTests (tpgRepo .UnifiedZeroDiff , tpgbRepo .UnifiedZeroDiff , replayingResult )
173
- if len (notRunBeta ) > 0 || len (notRunGa ) > 0 {
174
- comment += `
175
224
176
-
177
- #### Non-exercised tests`
178
-
179
- if len (notRunBeta ) > 0 {
180
- comment += `
181
-
182
- Tests were added that are skipped in VCR:
183
- `
184
- for _ , t := range notRunBeta {
185
- comment += `
186
- - ` + t
187
- }
188
- }
189
-
190
- if len (notRunGa ) > 0 {
191
- comment += `
192
-
193
- Tests were added that are GA-only additions and require manual runs:
194
- `
195
- for _ , t := range notRunGa {
196
- comment += `
197
- - ` + t
198
- }
199
- }
225
+ nonExercisedTestsData := nonExercisedTests {
226
+ NotRunBetaTests : notRunBeta ,
227
+ NotRunGATests : notRunGa ,
228
+ }
229
+ nonExercisedTestsComment , err := formatNonExercisedTests (nonExercisedTestsData )
230
+ if err != nil {
231
+ return fmt .Errorf ("error formatting non exercised tests comment: %w" , err )
200
232
}
201
233
202
234
if len (replayingResult .FailedTests ) > 0 {
203
- comment += fmt . Sprintf ( `
204
-
205
-
206
- #### Action taken
207
- <details> <summary>Found %d affected test(s) by replaying old test recordings. Starting RECORDING based on the most recent commit. Click here to see the affected tests</summary><blockquote>%s </blockquote></details>
208
-
209
- [Get to know how VCR tests work](https://googlecloudplatform.github.io/magic-modules/docs/getting-started/contributing/#general-contributing-steps)` , len ( replayingResult . FailedTests ), failedTestsPattern )
235
+ withReplayFailedTestsData := withReplayFailedTests {
236
+ ReplayingResult : replayingResult ,
237
+ }
238
+ withReplayFailedTestsComment , err := formatWithReplayFailedTests ( withReplayFailedTestsData )
239
+ if err != nil {
240
+ return fmt . Errorf ( "error formatting action taken comment: %w" , err )
241
+ }
210
242
243
+ comment := strings .Join ([]string {testsAnalyticsComment , nonExercisedTestsComment , withReplayFailedTestsComment }, "\n " )
211
244
if err := gh .PostComment (prNumber , comment ); err != nil {
212
245
return fmt .Errorf ("error posting comment: %w" , err )
213
246
}
@@ -233,77 +266,54 @@ Tests were added that are GA-only additions and require manual runs:
233
266
return nil
234
267
}
235
268
236
- comment = ""
269
+ var replayingAfterRecordingResult * vcr.Result
270
+ var replayingAfterRecordingErr error
237
271
if len (recordingResult .PassedTests ) > 0 {
238
- comment += "$\\ textcolor{green}{\\ textsf{Tests passed during RECORDING mode:}}$\n "
239
- for _ , passedTest := range recordingResult .PassedTests {
240
- comment += fmt .Sprintf ("`%s`[[Debug log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/recording/%s.log)]\n " , passedTest , prNumber , buildID , passedTest )
241
- }
242
- comment += "\n \n "
243
-
244
- replayingAfterRecordingResult , replayingAfterRecordingErr := vt .RunParallel (vcr .Replaying , provider .Beta , testDirs , recordingResult .PassedTests )
272
+ replayingAfterRecordingResult , replayingAfterRecordingErr = vt .RunParallel (vcr .Replaying , provider .Beta , testDirs , recordingResult .PassedTests )
245
273
if replayingAfterRecordingErr != nil {
246
274
testState = "failure"
247
275
}
248
276
249
277
if err := vt .UploadLogs ("ci-vcr-logs" , prNumber , buildID , true , true , vcr .Replaying , provider .Beta ); err != nil {
250
278
return fmt .Errorf ("error uploading recording logs: %w" , err )
251
279
}
252
-
253
- if len (replayingAfterRecordingResult .FailedTests ) > 0 {
254
- comment += "$\\ textcolor{red}{\\ textsf{Tests failed when rerunning REPLAYING mode:}}$\n "
255
- for _ , failedTest := range replayingAfterRecordingResult .FailedTests {
256
- comment += fmt .Sprintf ("`%s`[[Error message](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/build-log/replaying_build_after_recording/%s_replaying_test.log)] [[Debug log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/replaying_after_recording/%s.log)]\n " , failedTest , prNumber , buildID , failedTest , prNumber , buildID , failedTest )
257
- }
258
- comment += "\n \n "
259
- comment += `Tests failed due to non-determinism or randomness when the VCR replayed the response after the HTTP request was made.
260
-
261
- Please fix these to complete your PR. If you believe these test failures to be incorrect or unrelated to your change, or if you have any questions, please raise the concern with your reviewer.
262
- `
263
- } else {
264
- comment += "$\\ textcolor{green}{\\ textsf{No issues found for passed tests after REPLAYING rerun.}}$\n "
265
- }
266
- comment += "\n ---\n "
267
-
268
280
}
269
281
270
- if len (recordingResult .FailedTests ) > 0 {
271
- comment += "$\\ textcolor{red}{\\ textsf{Tests failed during RECORDING mode:}}$\n "
272
- for _ , failedTest := range recordingResult .FailedTests {
273
- comment += fmt .Sprintf ("`%s`[[Error message](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/build-log/recording_build/%s_recording_test.log)] [[Debug log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/recording/%s.log)]\n " , failedTest , prNumber , buildID , failedTest , prNumber , buildID , failedTest )
274
- }
275
- comment += "\n \n "
276
- if len (recordingResult .PassedTests )+ len (recordingResult .FailedTests ) < len (replayingResult .FailedTests ) {
277
- comment += "$\\ textcolor{red}{\\ textsf{Several tests got terminated during RECORDING mode.}}$\n "
278
- }
279
- comment += "$\\ textcolor{red}{\\ textsf{Please fix these to complete your PR.}}$\n "
280
- } else {
281
- if len (recordingResult .PassedTests )+ len (recordingResult .FailedTests ) < len (replayingResult .FailedTests ) {
282
- comment += "$\\ textcolor{red}{\\ textsf{Several tests got terminated during RECORDING mode.}}$\n "
283
- } else if recordingErr != nil {
284
- // Check for any uncaught errors in RECORDING mode.
285
- comment += "$\\ textcolor{red}{\\ textsf{Errors occurred during RECORDING mode. Please fix them to complete your PR.}}$\n "
286
- } else {
287
- comment += "$\\ textcolor{green}{\\ textsf{All tests passed!}}$\n "
288
- }
282
+ hasTerminatedTests := (len (recordingResult .PassedTests ) + len (recordingResult .FailedTests )) < len (replayingResult .FailedTests )
283
+ allRecordingPassed := len (recordingResult .FailedTests ) == 0 && ! hasTerminatedTests && recordingErr == nil
284
+
285
+ recordReplayData := recordReplay {
286
+ RecordingResult : recordingResult ,
287
+ ReplayingAfterRecordingResult : replayingAfterRecordingResult ,
288
+ RecordingErr : recordingErr ,
289
+ HasTerminatedTests : hasTerminatedTests ,
290
+ AllRecordingPassed : allRecordingPassed ,
291
+ PRNumber : prNumber ,
292
+ BuildID : buildID ,
293
+ }
294
+ recordReplayComment , err := formatRecordReplay (recordReplayData )
295
+ if err != nil {
296
+ return fmt .Errorf ("error formatting record replay comment: %w" , err )
297
+ }
298
+ if err := gh .PostComment (prNumber , recordReplayComment ); err != nil {
299
+ return fmt .Errorf ("error posting comment: %w" , err )
289
300
}
290
301
291
- comment += fmt .Sprintf ("View the [build log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/build-log/recording_test.log) or the [debug log](https://console.cloud.google.com/storage/browser/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/recording) for each test" , prNumber , buildID , prNumber , buildID )
292
- } else {
293
- // Add newlines so that the color formatting will work properly.
294
- comment += `
302
+ } else { // len(replayingResult.FailedTests) == 0
303
+ withoutReplayFailedTestsData := withoutReplayFailedTests {
304
+ ReplayingErr : replayingErr ,
305
+ PRNumber : prNumber ,
306
+ BuildID : buildID ,
307
+ }
308
+ withoutReplayFailedTestsComment , err := formatWithoutReplayFailedTests (withoutReplayFailedTestsData )
309
+ if err != nil {
310
+ return fmt .Errorf ("error formatting action taken comment: %w" , err )
311
+ }
295
312
296
- `
297
- if replayingErr != nil {
298
- // Check for any uncaught errors in REPLAYING mode.
299
- comment += "$\\ textcolor{red}{\\ textsf{Errors occurred during REPLAYING mode. Please fix them to complete your PR.}}$\n "
300
- } else {
301
- comment += "$\\ textcolor{green}{\\ textsf{All tests passed!}}$\n "
313
+ comment := strings .Join ([]string {testsAnalyticsComment , nonExercisedTestsComment , withoutReplayFailedTestsComment }, "\n " )
314
+ if err := gh .PostComment (prNumber , comment ); err != nil {
315
+ return fmt .Errorf ("error posting comment: %w" , err )
302
316
}
303
- comment += fmt .Sprintf ("View the [build log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/heads/auto-pr-%s/artifacts/%s/build-log/replaying_test.log)" , prNumber , buildID )
304
- }
305
- if err := gh .PostComment (prNumber , comment ); err != nil {
306
- return fmt .Errorf ("error posting comment: %w" , err )
307
317
}
308
318
309
319
if err := gh .PostBuildStatus (prNumber , "VCR-test" , testState , buildStatusTargetURL , mmCommitSha ); err != nil {
@@ -379,17 +389,14 @@ func modifiedPackages(changedFiles []string) (map[string]struct{}, bool) {
379
389
return services , runFullVCR
380
390
}
381
391
382
- func runReplaying (runFullVCR bool , services map [string ]struct {}, vt * vcr.Tester ) (* vcr.Result , string , []string , error ) {
392
+ func runReplaying (runFullVCR bool , services map [string ]struct {}, vt * vcr.Tester ) (* vcr.Result , []string , error ) {
383
393
var result * vcr.Result
384
- affectedServicesComment := "None"
385
394
var testDirs []string
386
395
var replayingErr error
387
396
if runFullVCR {
388
397
fmt .Println ("run full VCR tests" )
389
- affectedServicesComment = "all service packages are affected"
390
398
result , replayingErr = vt .Run (vcr .Replaying , provider .Beta , nil )
391
399
} else if len (services ) > 0 {
392
- affectedServicesComment = "<ul>"
393
400
result = & vcr.Result {}
394
401
for service := range services {
395
402
servicePath := "./" + filepath .Join ("google-beta" , "services" , service )
@@ -403,12 +410,10 @@ func runReplaying(runFullVCR bool, services map[string]struct{}, vt *vcr.Tester)
403
410
result .SkippedTests = append (result .SkippedTests , serviceResult .SkippedTests ... )
404
411
result .FailedTests = append (result .FailedTests , serviceResult .FailedTests ... )
405
412
result .Panics = append (result .Panics , serviceResult .Panics ... )
406
- affectedServicesComment += fmt .Sprintf ("<li>%s</li>" , service )
407
413
}
408
- affectedServicesComment += "</ul>"
409
414
}
410
415
411
- return result , affectedServicesComment , testDirs , replayingErr
416
+ return result , testDirs , replayingErr
412
417
}
413
418
414
419
func handlePanics (prNumber , buildID , buildStatusTargetURL , mmCommitSha string , result * vcr.Result , mode vcr.Mode , gh GithubClient ) (bool , error ) {
@@ -430,3 +435,40 @@ View the [build log](https://storage.cloud.google.com/ci-vcr-logs/beta/refs/head
430
435
func init () {
431
436
rootCmd .AddCommand (testTerraformVCRCmd )
432
437
}
438
+
439
+ func formatComment (fileName string , tmplText string , data any ) (string , error ) {
440
+ funcs := template.FuncMap {
441
+ "join" : strings .Join ,
442
+ "add" : func (i , j int ) int { return i + j },
443
+ }
444
+ tmpl , err := template .New (fileName ).Funcs (funcs ).Parse (tmplText )
445
+ if err != nil {
446
+ panic (fmt .Sprintf ("Unable to parse %s: %s" , fileName , err ))
447
+ }
448
+ sb := new (strings.Builder )
449
+ err = tmpl .Execute (sb , data )
450
+ if err != nil {
451
+ return "" , err
452
+ }
453
+ return strings .TrimSpace (sb .String ()), nil
454
+ }
455
+
456
+ func formatTestsAnalytics (data analytics ) (string , error ) {
457
+ return formatComment ("test_terraform_vcr_test_analytics.tmpl" , testsAnalyticsTmplText , data )
458
+ }
459
+
460
+ func formatNonExercisedTests (data nonExercisedTests ) (string , error ) {
461
+ return formatComment ("test_terraform_vcr_recording_mode_results.tmpl" , nonExercisedTestsTmplText , data )
462
+ }
463
+
464
+ func formatWithReplayFailedTests (data withReplayFailedTests ) (string , error ) {
465
+ return formatComment ("test_terraform_vcr_with_replay_failed_tests.tmpl" , withReplayFailedTestsTmplText , data )
466
+ }
467
+
468
+ func formatWithoutReplayFailedTests (data withoutReplayFailedTests ) (string , error ) {
469
+ return formatComment ("test_terraform_vcr_without_replay_failed_tests.tmpl" , withoutReplayFailedTestsTmplText , data )
470
+ }
471
+
472
+ func formatRecordReplay (data recordReplay ) (string , error ) {
473
+ return formatComment ("test_terraform_vcr_record_replay.tmpl" , recordReplayTmplText , data )
474
+ }
0 commit comments