@@ -3,6 +3,7 @@ package retry
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "strings"
6
7
7
8
"github.com/rs/zerolog/log"
8
9
"github.com/saucelabs/saucectl/internal/job"
@@ -39,22 +40,30 @@ func (b *JunitRetrier) retryFailedTests(reader job.Reader, jobOpts chan<- job.St
39
40
40
41
// setClassesToRetry sets the correct filtering flag when retrying.
41
42
// RDC API does not provide different endpoints (or identical values) for Espresso
42
- // and XCUITest. Thus, we need set the classes at the correct position depending the
43
- // framework that is being executed.
43
+ // and XCUITest. Thus, we need set the classes at the correct position depending
44
+ // on the framework that is being executed.
44
45
func setClassesToRetry (opt * job.StartOptions , testcases []junit.TestCase ) {
45
46
lg := log .Info ().
46
47
Str ("suite" , opt .DisplayName ).
47
48
Str ("attempt" , fmt .Sprintf ("%d of %d" , opt .Attempt + 1 , opt .Retries + 1 ))
48
49
50
+ if opt .TestOptions == nil {
51
+ opt .TestOptions = map [string ]interface {}{}
52
+ }
53
+
49
54
if opt .Framework == xcuitest .Kind {
50
- opt .TestsToRun = getFailedXCUITests (testcases )
51
- lg .Msgf (msg .RetryWithTests , opt .TestsToRun )
55
+ tests := getFailedXCUITests (testcases )
56
+
57
+ // RDC and VDC API filter use different fields for test filtering.
58
+ if opt .RealDevice {
59
+ opt .TestsToRun = tests
60
+ } else {
61
+ opt .TestOptions ["class" ] = tests
62
+ }
63
+ lg .Msgf (msg .RetryWithTests , tests )
52
64
return
53
65
}
54
66
55
- if opt .TestOptions == nil {
56
- opt .TestOptions = map [string ]interface {}{}
57
- }
58
67
tests := getFailedEspressoTests (testcases )
59
68
opt .TestOptions ["class" ] = tests
60
69
lg .Msgf (msg .RetryWithTests , tests )
@@ -84,16 +93,30 @@ func getFailedXCUITests(testCases []junit.TestCase) []string {
84
93
classes := map [string ]bool {}
85
94
for _ , tc := range testCases {
86
95
if tc .Error != nil || tc .Failure != nil {
96
+ className := normalizeXCUITestClassName (tc .ClassName )
87
97
if tc .Name != "" {
88
- classes [fmt .Sprintf ("%s/%s" , tc . ClassName , tc .Name )] = true
98
+ classes [fmt .Sprintf ("%s/%s" , className , tc .Name )] = true
89
99
} else {
90
- classes [tc . ClassName ] = true
100
+ classes [className ] = true
91
101
}
92
102
}
93
103
}
94
104
return maps .Keys (classes )
95
105
}
96
106
107
+ // normalizeXCUITestClassName normalizes the class name of an XCUITest. The
108
+ // class name within the platform generated JUnit XML file can be dot-separated,
109
+ // but our platform API expects a slash-separated class name. The platform is
110
+ // unfortunately not consistent in this regard and is not in full control of the
111
+ // generated JUnit XML file, hence we reconcile the two here.
112
+ func normalizeXCUITestClassName (name string ) string {
113
+ items := strings .Split (name , "." )
114
+ if len (items ) == 1 {
115
+ return name
116
+ }
117
+ return strings .Join (items , "/" )
118
+ }
119
+
97
120
// getFailedEspressoTests returns a list of failed Espresso tests from the given
98
121
// test cases. The format is "<className>#<testMethodName>", with the test
99
122
// method name being optional.
0 commit comments