@@ -30,23 +30,24 @@ type StepResult struct {
30
30
type StepRunner struct {
31
31
mu sync.Mutex
32
32
33
- stepIn chan * target.Target
34
- reportedTargets map [string ]struct {}
35
-
36
- started bool
37
- runningLoopActive bool
33
+ input chan * target.Target
38
34
stopOnce sync.Once
35
+ resultsChan chan <- StepRunnerEvent
36
+ runningLoopActive bool
39
37
finishedCh chan struct {}
40
38
41
39
resultErr error
42
40
resultResumeState json.RawMessage
43
41
notifyStoppedOnce sync.Once
44
- resultsChan chan <- StepRunnerEvent
45
42
}
46
43
47
44
func (sr * StepRunner ) AddTarget (ctx xcontext.Context , tgt * target.Target ) error {
45
+ if tgt == nil {
46
+ return fmt .Errorf ("target should not be nil" )
47
+ }
48
+
48
49
select {
49
- case sr .stepIn <- tgt :
50
+ case sr .input <- tgt :
50
51
case <- ctx .Until (xcontext .ErrPaused ):
51
52
return xcontext .ErrPaused
52
53
case <- ctx .Done ():
@@ -61,20 +62,15 @@ func (sr *StepRunner) Run(
61
62
ev testevent.Emitter ,
62
63
resumeState json.RawMessage ,
63
64
) (<- chan StepRunnerEvent , error ) {
64
- err := func () error {
65
- sr .mu .Lock ()
66
- defer sr .mu .Unlock ()
67
- if sr .started {
68
- return & cerrors.ErrAlreadyDone {}
69
- }
70
- sr .started = true
71
- return nil
72
- }()
73
- if err != nil {
74
- return nil , err
65
+ sr .mu .Lock ()
66
+ defer sr .mu .Unlock ()
67
+
68
+ if sr .resultsChan != nil {
69
+ return nil , & cerrors.ErrAlreadyDone {}
75
70
}
76
71
77
- sr .finishedCh = make (chan struct {})
72
+ finishedCh := make (chan struct {})
73
+ sr .finishedCh = finishedCh
78
74
resultsChan := make (chan StepRunnerEvent , 1 )
79
75
sr .resultsChan = resultsChan
80
76
@@ -95,10 +91,11 @@ func (sr *StepRunner) Run(
95
91
ctx .Debugf ("StepRunner finished" )
96
92
}
97
93
94
+ stepIn := sr .input
98
95
stepOut := make (chan test.TestStepResult )
99
96
go func () {
100
97
defer finish ()
101
- sr .runningLoop (ctx , stepOut , bundle , ev , resumeState )
98
+ sr .runningLoop (ctx , stepIn , stepOut , bundle , ev , resumeState )
102
99
ctx .Debugf ("Running loop finished" )
103
100
}()
104
101
@@ -107,21 +104,22 @@ func (sr *StepRunner) Run(
107
104
sr .readingLoop (ctx , stepOut , bundle .TestStepLabel )
108
105
ctx .Debugf ("Reading loop finished" )
109
106
}()
107
+
110
108
return resultsChan , nil
111
109
}
112
110
113
111
func (sr * StepRunner ) Started () bool {
114
112
sr .mu .Lock ()
115
113
defer sr .mu .Unlock ()
116
114
117
- return sr .started
115
+ return sr .resultsChan != nil
118
116
}
119
117
120
118
func (sr * StepRunner ) Running () bool {
121
119
sr .mu .Lock ()
122
120
defer sr .mu .Unlock ()
123
121
124
- return sr .started && sr .finishedCh != nil
122
+ return sr .resultsChan != nil && sr .finishedCh != nil
125
123
}
126
124
127
125
// WaitResults returns TestStep.Run() output
@@ -161,7 +159,7 @@ func (sr *StepRunner) WaitResults(ctx context.Context) (stepResult StepResult, e
161
159
// Stop triggers TestStep to stop running by closing input channel
162
160
func (sr * StepRunner ) Stop () {
163
161
sr .stopOnce .Do (func () {
164
- close (sr .stepIn )
162
+ close (sr .input )
165
163
})
166
164
}
167
165
@@ -170,6 +168,7 @@ func (sr *StepRunner) readingLoop(
170
168
stepOut chan test.TestStepResult ,
171
169
testStepLabel string ,
172
170
) {
171
+ reportedTargets := make (map [string ]struct {})
173
172
for {
174
173
select {
175
174
case res , ok := <- stepOut :
@@ -191,10 +190,8 @@ func (sr *StepRunner) readingLoop(
191
190
}
192
191
ctx .Infof ("Obtained '%v' for target '%s'" , res , res .Target .ID )
193
192
194
- sr .mu .Lock ()
195
- _ , found := sr .reportedTargets [res .Target .ID ]
196
- sr .reportedTargets [res .Target .ID ] = struct {}{}
197
- sr .mu .Unlock ()
193
+ _ , found := reportedTargets [res .Target .ID ]
194
+ reportedTargets [res .Target .ID ] = struct {}{}
198
195
199
196
if found {
200
197
sr .setErr (ctx , & cerrors.ErrTestStepReturnedDuplicateResult {StepName : testStepLabel , Target : res .Target .ID })
@@ -219,6 +216,7 @@ func (sr *StepRunner) readingLoop(
219
216
220
217
func (sr * StepRunner ) runningLoop (
221
218
ctx xcontext.Context ,
219
+ stepIn <- chan * target.Target ,
222
220
stepOut chan test.TestStepResult ,
223
221
bundle test.TestStepBundle ,
224
222
ev testevent.Emitter ,
@@ -249,7 +247,7 @@ func (sr *StepRunner) runningLoop(
249
247
}
250
248
}()
251
249
252
- inChannels := test.TestStepChannels {In : sr . stepIn , Out : stepOut }
250
+ inChannels := test.TestStepChannels {In : stepIn , Out : stepOut }
253
251
return bundle .TestStep .Run (ctx , inChannels , bundle .Parameters , ev , resumeState )
254
252
}()
255
253
ctx .Debugf ("TestStep finished '%v', rs %s" , err , string (resultResumeState ))
@@ -273,7 +271,11 @@ func (sr *StepRunner) setErrLocked(ctx xcontext.Context, err error) {
273
271
}
274
272
ctx .Errorf ("err: %v" , err )
275
273
sr .resultErr = err
276
- sr .notifyStopped (sr .resultErr )
274
+
275
+ // notifyStopped is a blocking operation: should release the lock
276
+ sr .mu .Unlock ()
277
+ sr .notifyStopped (err )
278
+ sr .mu .Lock ()
277
279
}
278
280
279
281
func (sr * StepRunner ) notifyStopped (err error ) {
@@ -296,7 +298,6 @@ func safeCloseOutCh(ch chan test.TestStepResult) (recoverOccurred bool) {
296
298
// NewStepRunner creates a new StepRunner object
297
299
func NewStepRunner () * StepRunner {
298
300
return & StepRunner {
299
- stepIn : make (chan * target.Target ),
300
- reportedTargets : make (map [string ]struct {}),
301
+ input : make (chan * target.Target ),
301
302
}
302
303
}
0 commit comments