Skip to content

Commit 22e2920

Browse files
committed
TestStep variables proof of concept
Signed-off-by: Ilya <rihter007@inbox.ru>
1 parent 0807544 commit 22e2920

40 files changed

Lines changed: 747 additions & 149 deletions

File tree

pkg/jobmanager/bundles.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ func newBundlesFromSteps(ctx xcontext.Context, descriptors []*test.TestStepDescr
6060

6161
// look up test step plugins in the plugin registry
6262
var stepBundles []test.TestStepBundle
63-
6463
for idx, descriptor := range descriptors {
6564
if descriptor == nil {
6665
return nil, fmt.Errorf("test step description is null")

pkg/pluginregistry/bundles.go

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package pluginregistry
77

88
import (
99
"fmt"
10+
"strings"
1011

1112
"github.com/linuxboot/contest/pkg/job"
1213
"github.com/linuxboot/contest/pkg/target"
@@ -28,14 +29,45 @@ func (r *PluginRegistry) NewTestStepBundle(ctx xcontext.Context, testStepDescrip
2829
return nil, err
2930
}
3031
label := testStepDescriptor.Label
31-
if label == "" {
32+
if len(label) == 0 {
3233
return nil, ErrStepLabelIsMandatory{TestStepDescriptor: testStepDescriptor}
3334
}
35+
36+
var variablesMapping test.StepVariablesMapping
37+
if testStepDescriptor.VariablesMapping != nil {
38+
variablesMapping = make(test.StepVariablesMapping)
39+
for internalName, mappedName := range testStepDescriptor.VariablesMapping {
40+
if err := checkVariableName(internalName); err != nil {
41+
return nil, InvalidVariableFormat{InvalidName: internalName, Err: err}
42+
}
43+
if _, found := variablesMapping[internalName]; found {
44+
return nil, fmt.Errorf("duplication of '%s' variable", internalName)
45+
}
46+
// NewStepVariable creates a StepVariable object from mapping: "stepName.VariableName"
47+
parts := strings.Split(mappedName, ".")
48+
if len(parts) != 2 {
49+
return nil, fmt.Errorf("variable mapping '%s' should contain a single '.' separator", mappedName)
50+
}
51+
if err := checkVariableName(parts[0]); err != nil {
52+
return nil, InvalidVariableFormat{InvalidName: parts[0], Err: err}
53+
}
54+
if err := checkVariableName(parts[1]); err != nil {
55+
return nil, InvalidVariableFormat{InvalidName: parts[1], Err: err}
56+
}
57+
58+
variablesMapping[internalName] = test.StepVariable{
59+
StepName: parts[0],
60+
VariableName: parts[1],
61+
}
62+
}
63+
}
64+
// TODO: check that all testStep labels from variable mappings exist
3465
testStepBundle := test.TestStepBundle{
35-
TestStep: testStep,
36-
TestStepLabel: label,
37-
Parameters: testStepDescriptor.Parameters,
38-
AllowedEvents: allowedEvents,
66+
TestStep: testStep,
67+
TestStepLabel: label,
68+
Parameters: testStepDescriptor.Parameters,
69+
AllowedEvents: allowedEvents,
70+
VariablesMapping: variablesMapping,
3971
}
4072
return &testStepBundle, nil
4173
}
@@ -129,3 +161,31 @@ func (r *PluginRegistry) NewFinalReporterBundle(reporterName string, reporterPar
129161
}
130162
return &reporterBundle, nil
131163
}
164+
165+
func isAlpha(ch int32) bool {
166+
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' || ch <= 'Z')
167+
}
168+
169+
func checkVariableName(s string) error {
170+
if len(s) == 0 {
171+
return fmt.Errorf("empty variable name")
172+
}
173+
for idx, ch := range s {
174+
if idx == 0 {
175+
if !isAlpha(ch) {
176+
return fmt.Errorf("first character should be alpha, got %c", ch)
177+
}
178+
}
179+
if isAlpha(ch) {
180+
continue
181+
}
182+
if ch >= '0' || ch <= '9' {
183+
continue
184+
}
185+
if ch == '_' {
186+
continue
187+
}
188+
return fmt.Errorf("got unxpected character: %c", ch)
189+
}
190+
return nil
191+
}

pkg/pluginregistry/errors.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,17 @@ type ErrStepLabelIsMandatory struct {
1818
func (err ErrStepLabelIsMandatory) Error() string {
1919
return fmt.Sprintf("step has no label, but it is mandatory (step: %+v)", err.TestStepDescriptor)
2020
}
21+
22+
// InvalidVariableFormat tells that a variable name doesn't fit the variable name format (alphanum + '_')
23+
type InvalidVariableFormat struct {
24+
InvalidName string
25+
Err error
26+
}
27+
28+
func (err InvalidVariableFormat) Error() string {
29+
return fmt.Sprintf("'%s' doesn't match variable name format: %v", err.InvalidName, err.Err)
30+
}
31+
32+
func (err InvalidVariableFormat) Unwrap() error {
33+
return err.Err
34+
}

pkg/pluginregistry/pluginregistry_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ import (
1919
"github.com/stretchr/testify/require"
2020
)
2121

22-
var (
23-
ctx, _ = logrusctx.NewContext(logger.LevelDebug)
24-
)
25-
2622
// Definition of two dummy TestSteps to be used to test the PluginRegistry
2723

2824
// AStep implements a dummy TestStep
@@ -44,18 +40,29 @@ func (e AStep) Name() string {
4440
}
4541

4642
// Run executes the AStep
47-
func (e AStep) Run(ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters, ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error) {
43+
func (e AStep) Run(
44+
ctx xcontext.Context,
45+
ch test.TestStepChannels,
46+
ev testevent.Emitter,
47+
stepsVars test.StepsVariables,
48+
params test.TestStepParameters,
49+
resumeState json.RawMessage,
50+
) (json.RawMessage, error) {
4851
return nil, nil
4952
}
5053

5154
func TestRegisterTestStep(t *testing.T) {
55+
ctx, cancel := logrusctx.NewContext(logger.LevelDebug)
56+
defer cancel()
5257
pr := NewPluginRegistry(ctx)
53-
err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{event.Name("AStepEventName")})
58+
err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{"AStepEventName"})
5459
require.NoError(t, err)
5560
}
5661

5762
func TestRegisterTestStepDoesNotValidate(t *testing.T) {
63+
ctx, cancel := logrusctx.NewContext(logger.LevelDebug)
64+
defer cancel()
5865
pr := NewPluginRegistry(ctx)
59-
err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{event.Name("Event which does not validate")})
66+
err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{"Event which does not validate"})
6067
require.Error(t, err)
6168
}

pkg/runner/base_test_suite_test.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ func (s *BaseTestSuite) TearDownTest() {
7373
}
7474

7575
func (s *BaseTestSuite) RegisterStateFullStep(
76-
runFunction func(
77-
ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters,
78-
ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error),
76+
runFunction func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter,
77+
stepsVars test.StepsVariables, params test.TestStepParameters,
78+
resumeState json.RawMessage) (json.RawMessage, error),
7979
validateFunction func(ctx xcontext.Context, params test.TestStepParameters) error) error {
8080

8181
return s.PluginRegistry.RegisterTestStep(stateFullStepName, func() test.TestStep {
@@ -86,11 +86,17 @@ func (s *BaseTestSuite) RegisterStateFullStep(
8686
}, nil)
8787
}
8888

89-
func (s *BaseTestSuite) NewStep(ctx xcontext.Context, label, name string, params test.TestStepParameters) test.TestStepBundle {
89+
func (s *BaseTestSuite) NewStep(
90+
ctx xcontext.Context,
91+
label, name string,
92+
params test.TestStepParameters,
93+
variablesMapping map[string]string,
94+
) test.TestStepBundle {
9095
td := test.TestStepDescriptor{
91-
Name: name,
92-
Label: label,
93-
Parameters: params,
96+
Name: name,
97+
Label: label,
98+
Parameters: params,
99+
VariablesMapping: variablesMapping,
94100
}
95101
sb, err := s.PluginRegistry.NewTestStepBundle(ctx, td)
96102
require.NoError(s.T(), err)

pkg/runner/job_runner_test.go

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ func (s *JobRunnerSuite) TestSimpleJobStartFinish() {
5858
var resultTargets []*target.Target
5959

6060
require.NoError(s.T(), s.RegisterStateFullStep(
61-
func(ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters, ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error) {
61+
func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter,
62+
stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) {
6263
return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error {
6364
assert.NotNil(s.T(), target)
6465
mu.Lock()
@@ -91,7 +92,7 @@ func (s *JobRunnerSuite) TestSimpleJobStartFinish() {
9192
TargetManager: targetlist.New(),
9293
},
9394
TestStepsBundles: []test.TestStepBundle{
94-
s.NewStep(ctx, "test_step_label", stateFullStepName, nil),
95+
s.NewStep(ctx, "test_step_label", stateFullStepName, nil, nil),
9596
},
9697
},
9798
},
@@ -124,7 +125,8 @@ func (s *JobRunnerSuite) TestJobWithTestRetry() {
124125
var callsCount int
125126

126127
require.NoError(s.T(), s.RegisterStateFullStep(
127-
func(ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters, ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error) {
128+
func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter,
129+
stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) {
128130
return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error {
129131
assert.NotNil(s.T(), target)
130132
mu.Lock()
@@ -175,11 +177,11 @@ func (s *JobRunnerSuite) TestJobWithTestRetry() {
175177
TestStepsBundles: []test.TestStepBundle{
176178
s.NewStep(ctx, "echo1_step_label", echo.Name, map[string][]test.Param{
177179
"text": {*test.NewParam("hello")},
178-
}),
179-
s.NewStep(ctx, "test_step_label", stateFullStepName, nil),
180+
}, nil),
181+
s.NewStep(ctx, "test_step_label", stateFullStepName, nil, nil),
180182
s.NewStep(ctx, "echo2_step_label", echo.Name, map[string][]test.Param{
181183
"text": {*test.NewParam("world")},
182-
}),
184+
}, nil),
183185
},
184186
},
185187
},
@@ -280,7 +282,7 @@ func (s *JobRunnerSuite) TestJobRetryOnFailedAcquire() {
280282
TestStepsBundles: []test.TestStepBundle{
281283
s.NewStep(ctx, "echo1_step_label", echo.Name, map[string][]test.Param{
282284
"text": {*test.NewParam("hello")},
283-
}),
285+
}, nil),
284286
},
285287
},
286288
},
@@ -359,7 +361,7 @@ func (s *JobRunnerSuite) TestAcquireFailed() {
359361
TestStepsBundles: []test.TestStepBundle{
360362
s.NewStep(ctx, "echo1_step_label", echo.Name, map[string][]test.Param{
361363
"text": {*test.NewParam("hello")},
362-
}),
364+
}, nil),
363365
},
364366
},
365367
},
@@ -429,7 +431,7 @@ func (s *JobRunnerSuite) TestResumeStateBadJobId() {
429431
TestStepsBundles: []test.TestStepBundle{
430432
s.NewStep(ctx, "echo1_step_label", echo.Name, map[string][]test.Param{
431433
"text": {*test.NewParam("hello")},
432-
}),
434+
}, nil),
433435
},
434436
},
435437
},
@@ -454,22 +456,27 @@ func (s *JobRunnerSuite) TestResumeStateBadJobId() {
454456
const stateFullStepName = "statefull"
455457

456458
type stateFullStep struct {
457-
runFunction func(ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters,
458-
ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error)
459+
runFunction func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter,
460+
stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error)
459461
validateFunction func(ctx xcontext.Context, params test.TestStepParameters) error
460462
}
461463

462464
func (sfs *stateFullStep) Name() string {
463465
return stateFullStepName
464466
}
465467

466-
func (sfs *stateFullStep) Run(ctx xcontext.Context, ch test.TestStepChannels, params test.TestStepParameters,
467-
ev testevent.Emitter, resumeState json.RawMessage,
468+
func (sfs *stateFullStep) Run(
469+
ctx xcontext.Context,
470+
ch test.TestStepChannels,
471+
ev testevent.Emitter,
472+
stepsVars test.StepsVariables,
473+
params test.TestStepParameters,
474+
resumeState json.RawMessage,
468475
) (json.RawMessage, error) {
469476
if sfs.runFunction == nil {
470477
return nil, fmt.Errorf("stateFullStep run is not initialised")
471478
}
472-
return sfs.runFunction(ctx, ch, params, ev, resumeState)
479+
return sfs.runFunction(ctx, ch, ev, stepsVars, params, resumeState)
473480
}
474481

475482
func (sfs *stateFullStep) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error {

pkg/runner/step_runner.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func NewStepRunner() *StepRunner {
9090
func (sr *StepRunner) Run(
9191
ctx xcontext.Context,
9292
bundle test.TestStepBundle,
93+
stepsVariables test.StepsVariables,
9394
ev testevent.Emitter,
9495
resumeState json.RawMessage,
9596
resumeStateTargets []target.Target,
@@ -132,7 +133,7 @@ func (sr *StepRunner) Run(
132133
stepOut := make(chan test.TestStepResult)
133134
go func() {
134135
defer finish()
135-
sr.runningLoop(ctx, sr.input, stepOut, bundle, ev, resumeState)
136+
sr.runningLoop(ctx, sr.input, stepOut, bundle, stepsVariables, ev, resumeState)
136137
ctx.Debugf("Running loop finished")
137138
}()
138139

@@ -381,6 +382,7 @@ func (sr *StepRunner) runningLoop(
381382
stepIn <-chan *target.Target,
382383
stepOut chan test.TestStepResult,
383384
bundle test.TestStepBundle,
385+
stepsVariables test.StepsVariables,
384386
ev testevent.Emitter,
385387
resumeState json.RawMessage,
386388
) {
@@ -410,9 +412,9 @@ func (sr *StepRunner) runningLoop(
410412
}()
411413

412414
inChannels := test.TestStepChannels{In: stepIn, Out: stepOut}
413-
return bundle.TestStep.Run(ctx, inChannels, bundle.Parameters, ev, resumeState)
415+
return bundle.TestStep.Run(ctx, inChannels, ev, stepsVariables, bundle.Parameters, resumeState)
414416
}()
415-
ctx.Debugf("TestStep finished '%v', rs %s", err, string(resultResumeState))
417+
ctx.Debugf("TestStep finished '%v', rs: '%s'", err, string(resultResumeState))
416418

417419
sr.mu.Lock()
418420
sr.setErrLocked(ctx, err)

0 commit comments

Comments
 (0)