-
Notifications
You must be signed in to change notification settings - Fork 17
/
sleep.go
127 lines (110 loc) · 3.37 KB
/
sleep.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
package sleep
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/linuxboot/contest/pkg/event"
"github.com/linuxboot/contest/pkg/event/testevent"
"github.com/linuxboot/contest/pkg/logging"
"github.com/linuxboot/contest/pkg/signaling"
"github.com/linuxboot/contest/pkg/signals"
"github.com/linuxboot/contest/pkg/test"
"github.com/linuxboot/contest/plugins/teststeps"
)
// Name is the name used to look this plugin up.
var Name = "Sleep"
// Events defines the events that a TestStep is allow to emit
var Events = []event.Name{}
// sleepStep implements an echo-style printing plugin.
type sleepStep struct {
}
// New initializes and returns a new EchoStep. It implements the TestStepFactory
// interface.
func New() test.TestStep {
return &sleepStep{}
}
// Load returns the name, factory and events which are needed to register the step.
func Load() (string, test.TestStepFactory, []event.Name) {
return Name, New, Events
}
func getDuration(params test.TestStepParameters) (time.Duration, error) {
durP := params.GetOne("duration")
if durP.IsEmpty() {
return 0, errors.New("Missing 'duration' field in sleep parameters")
}
dur, err := time.ParseDuration(durP.String())
if err != nil {
return 0, fmt.Errorf("invalid duration %q: %w", durP.String(), err)
}
return dur, nil
}
// ValidateParameters validates the parameters that will be passed to the Run
// and Resume methods of the test step.
func (ss *sleepStep) ValidateParameters(_ context.Context, params test.TestStepParameters) error {
_, err := getDuration(params)
return err
}
// Name returns the name of the Step
func (ss *sleepStep) Name() string {
return Name
}
type sleepStepData struct {
DeadlineMS int64 `json:"D"`
}
// Run executes the step
func (ss *sleepStep) Run(
ctx context.Context,
ch test.TestStepChannels,
ev testevent.Emitter,
stepsVars test.StepsVariables,
params test.TestStepParameters,
resumeState json.RawMessage,
) (json.RawMessage, error) {
dur, err := getDuration(params)
if err != nil {
return nil, err
}
fn := func(ctx context.Context, target *teststeps.TargetWithData) error {
var deadline time.Time
// copy, can be different per target
var sleepTime = dur
// handle resume
if target.Data != nil {
ssd := sleepStepData{}
if err := json.Unmarshal(target.Data, &ssd); err != nil {
return fmt.Errorf("invalid resume state: %w", err)
}
deadline = time.Unix(ssd.DeadlineMS/1000, (ssd.DeadlineMS%1000)*1000000)
sleepTime = time.Until(deadline)
logging.Debugf(ctx, "restored with %v unix, in %s", ssd.DeadlineMS, time.Until(deadline))
} else {
deadline = time.Now().Add(dur)
}
// now sleep
select {
case <-time.After(sleepTime):
return nil
case <-signaling.Until(ctx, signals.Paused):
logging.Debugf(ctx, "%s: Paused with %s left", target.Target, time.Until(deadline))
ssd := &sleepStepData{
DeadlineMS: deadline.UnixNano() / 1000000,
}
var err error
target.Data, err = json.Marshal(ssd)
if err != nil {
return err
}
return signals.Paused
case <-ctx.Done():
logging.Debugf(ctx, "%s: Cancelled with %s left", target.Target, time.Until(deadline))
}
return nil
}
return teststeps.ForEachTargetWithResume(ctx, ch, resumeState, 1, fn)
}