@@ -14,8 +14,8 @@ import (
14
14
"time"
15
15
16
16
"github.com/peterbourgon/ff/v3/ffcli"
17
- "moul.io/godev"
18
17
"moul.io/motd"
18
+ "moul.io/u"
19
19
)
20
20
21
21
var opts Opts
@@ -34,8 +34,8 @@ func run(args []string) error {
34
34
testFlags := flag .NewFlagSet ("testman test" , flag .ExitOnError )
35
35
testFlags .BoolVar (& opts .Verbose , "v" , false , "verbose" )
36
36
testFlags .StringVar (& opts .Run , "run" , "^(Test|Example)" , "regex to filter out tests and examples" )
37
- // testFlags.IntVar(&opts.Retry, "retry", 0, "fail after N retries")
38
- // testFlags.DurationVar(&opts.Timeout, "timeout", opts.Timeout, "max duration allowed to run the whole suite")
37
+ testFlags .IntVar (& opts .Retry , "retry" , 0 , "fail after N retries" )
38
+ testFlags .DurationVar (& opts .Timeout , "timeout" , opts .Timeout , "max duration allowed to run the whole suite" )
39
39
listFlags := flag .NewFlagSet ("testman list" , flag .ExitOnError )
40
40
listFlags .BoolVar (& opts .Verbose , "v" , false , "verbose" )
41
41
listFlags .StringVar (& opts .Run , "run" , "^(Test|Example)" , "regex to filter out tests and examples" )
@@ -53,14 +53,14 @@ func run(args []string) error {
53
53
FlagSet : testFlags ,
54
54
ShortHelp : "advanced go test workflows" ,
55
55
ShortUsage : "testman test [flags] [packages]" ,
56
- LongHelp : "EXAMPLES \n testman test -v ./..." ,
56
+ LongHelp : testLongHelp ,
57
57
Exec : runTest ,
58
58
}, {
59
59
Name : "list" ,
60
60
FlagSet : listFlags ,
61
61
ShortHelp : "list available tests" ,
62
62
ShortUsage : "testman list [packages]" ,
63
- LongHelp : "EXAMPLE \n testman list ./..." ,
63
+ LongHelp : listLongHelp ,
64
64
Exec : runList ,
65
65
},
66
66
},
@@ -69,11 +69,26 @@ func run(args []string) error {
69
69
return root .ParseAndRun (context .Background (), args [1 :])
70
70
}
71
71
72
+ const (
73
+ testLongHelp = `EXAMPLES
74
+ testman test ./...
75
+ testman test -v ./...
76
+ testman test -run ^TestUnstable -timeout=300s -retry=50 ./...`
77
+ listLongHelp = `EXAMPLES
78
+ testman list ./...
79
+ testman list -v ./...
80
+ testman list -run ^TestStable ./...`
81
+ )
82
+
72
83
func runList (ctx context.Context , args []string ) error {
73
84
if len (args ) == 0 {
74
85
return flag .ErrHelp
75
86
}
76
- preRun ()
87
+ cleanup , err := preRun ()
88
+ if err != nil {
89
+ return err
90
+ }
91
+ defer cleanup ()
77
92
78
93
// list packages
79
94
pkgs , err := listPackagesWithTests (args )
@@ -103,22 +118,28 @@ func runTest(ctx context.Context, args []string) error {
103
118
if len (args ) == 0 {
104
119
return flag .ErrHelp
105
120
}
106
- preRun ()
107
- log .Printf ("runTest opts=%s args=%s" , godev .JSON (opts ), godev .JSON (args ))
108
- start := time .Now ()
109
-
110
- // list packages
111
- pkgs , err := listPackagesWithTests (args )
121
+ cleanup , err := preRun ()
112
122
if err != nil {
113
123
return err
114
124
}
125
+ defer cleanup ()
115
126
116
- // create temp dir
117
- tmpdir , err := ioutil .TempDir ("" , "testman" )
127
+ log .Printf ("runTest opts=%s args=%s" , u .JSON (opts ), u .JSON (args ))
128
+ start := time .Now ()
129
+
130
+ if opts .Timeout > 0 {
131
+ go func () {
132
+ <- time .After (opts .Timeout )
133
+ fmt .Printf ("FAIL: timed out after %s\n " , time .Since (start ))
134
+ os .Exit (1 )
135
+ }()
136
+ }
137
+
138
+ // list packages
139
+ pkgs , err := listPackagesWithTests (args )
118
140
if err != nil {
119
141
return err
120
142
}
121
- defer os .RemoveAll (tmpdir )
122
143
123
144
atLeastOneFailure := false
124
145
// list tests
@@ -133,7 +154,7 @@ func runTest(ctx context.Context, args []string) error {
133
154
134
155
pkgStart := time .Now ()
135
156
// compile test binary
136
- bin , err := compileTestBin (pkg , tmpdir )
157
+ bin , err := compileTestBin (pkg , opts . TmpDir )
137
158
if err != nil {
138
159
fmt .Printf ("FAIL\t %s\t [compile error: %v]\n " , pkg .ImportPath , err )
139
160
return err
@@ -144,40 +165,61 @@ func runTest(ctx context.Context, args []string) error {
144
165
// FIXME: check if matches run regex
145
166
args := []string {
146
167
"-test.count=1" ,
147
- "-test.timeout=300s" ,
168
+ fmt . Sprintf ( "-test.timeout=%s" , opts . Timeout ) ,
148
169
}
149
170
if opts .Verbose {
150
171
args = append (args , "-test.v" )
151
172
}
152
173
args = append (args , "-test.run" , fmt .Sprintf ("^%s$" , test ))
153
- cmd := exec .Command (bin , args ... )
154
- log .Println (cmd .String ())
155
- out , err := cmd .CombinedOutput ()
156
- if err != nil {
157
- fmt .Printf ("FAIL\t %s.%s\t [compile error: %v]\n " , pkg .ImportPath , test , err )
158
- if opts .Verbose {
159
- fmt .Println (string (out ))
174
+ for i := opts .Retry ; i >= 0 ; i -- {
175
+ cmd := exec .Command (bin , args ... )
176
+ log .Println (cmd .String ())
177
+ out , err := cmd .CombinedOutput ()
178
+ if err != nil {
179
+ if i == 0 {
180
+ fmt .Printf ("FAIL\t %s.%s\t [test error: %v]\n " , pkg .ImportPath , test , err )
181
+ isPackageOK = false
182
+ atLeastOneFailure = true
183
+ } else if opts .Verbose {
184
+ fmt .Printf ("RETRY\t %s.%s\t [test error: %v]\n " , pkg .ImportPath , test , err )
185
+ }
186
+ if opts .Verbose {
187
+ fmt .Println (string (out ))
188
+ }
189
+ } else {
190
+ fmt .Printf ("ok\t %s.%s\n " , pkg .ImportPath , test )
191
+ break
160
192
}
161
- isPackageOK = false
162
- atLeastOneFailure = true
163
193
}
164
194
}
165
195
if isPackageOK {
166
196
fmt .Printf ("ok\t %s\t %s\n " , pkg .ImportPath , time .Since (pkgStart ))
167
197
}
168
198
}
169
199
170
- fmt .Printf ("total: %s\n " , time .Since (start ))
200
+ log .Printf ("total: %s\n " , time .Since (start ))
171
201
if atLeastOneFailure {
172
202
os .Exit (1 )
173
203
}
174
204
return nil
175
205
}
176
206
177
- func preRun () {
207
+ func preRun () ( func (), error ) {
178
208
if ! opts .Verbose {
179
209
log .SetOutput (ioutil .Discard )
180
210
}
211
+
212
+ // create temp dir
213
+ var err error
214
+ opts .TmpDir , err = ioutil .TempDir ("" , "testman" )
215
+ if err != nil {
216
+ return nil , err
217
+ }
218
+
219
+ cleanup := func () {
220
+ os .RemoveAll (opts .TmpDir )
221
+ }
222
+ return cleanup , nil
181
223
}
182
224
183
225
func compileTestBin (pkg Package , tempdir string ) (string , error ) {
@@ -258,8 +300,9 @@ type Package struct {
258
300
type Opts struct {
259
301
Verbose bool
260
302
Run string
261
- // Timeout time.Duration
262
- // Retry int
303
+ Timeout time.Duration
304
+ Retry int
305
+ TmpDir string
263
306
// c
264
307
// debug
265
308
// continueOnFailure vs failFast
0 commit comments