Skip to content

Commit

Permalink
Variables plugin: creates variables from its parameters
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya <[email protected]>
  • Loading branch information
rihter007 committed Jun 27, 2022
1 parent c087b84 commit f79f6ef
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 6 deletions.
4 changes: 4 additions & 0 deletions pkg/runner/step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ type stepsVariablesMock struct {
get func(tgtID string, name string, value interface{}) error
}

func (sm *stepsVariablesMock) AddRaw(tgtID string, name string, value json.RawMessage) error {
return sm.add(tgtID, name, value)
}

func (sm *stepsVariablesMock) Add(tgtID string, name string, value interface{}) error {
return sm.add(tgtID, name, value)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/test/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func getFuncMap() map[string]interface{} {
return mapCopy
}

func registerStepVariableAccessor(fm map[string]interface{}, tgtID string, vars StepsVariables) {
func registerStepVariableAccessor(fm map[string]interface{}, tgtID string, vars StepsVariablesReader) {
fm["StringVar"] = func(varName string) (string, error) {
var s string
if err := vars.Get(tgtID, varName, &s); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/test/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (p Param) JSON() json.RawMessage {

// Expand evaluates the raw expression and applies the necessary manipulation,
// if any.
func (p *Param) Expand(target *target.Target, vars StepsVariables) (string, error) {
func (p *Param) Expand(target *target.Target, vars StepsVariablesReader) (string, error) {
if p == nil {
return "", errors.New("parameter cannot be nil")
}
Expand Down
8 changes: 5 additions & 3 deletions pkg/test/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,15 @@ type TestStepChannels struct {
Out chan<- TestStepResult
}

type StepsVariablesReader interface {
// Get obtains existing variable by a mappedName which should be specified in variables mapping
Get(tgtID string, mappedName string, out interface{}) error
}

// StepsVariables represents a read/write access for step variables
type StepsVariables interface {
// Add adds a new or replaces existing variable associated with current test step and target
Add(tgtID string, name string, in interface{}) error

// Get obtains existing variable by a mappedName which should be specified in variables mapping
Get(tgtID string, mappedName string, out interface{}) error
}

// TestStep is the interface that all steps need to implement to be executed
Expand Down
78 changes: 78 additions & 0 deletions plugins/teststeps/variables/variables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package variables

import (
"encoding/json"
"fmt"
"github.com/linuxboot/contest/pkg/event"
"github.com/linuxboot/contest/pkg/event/testevent"
"github.com/linuxboot/contest/pkg/target"
"github.com/linuxboot/contest/pkg/test"
"github.com/linuxboot/contest/pkg/xcontext"
"github.com/linuxboot/contest/plugins/teststeps"
)

// Name is the name used to look this plugin up.
const Name = "variables"

// Events defines the events that a TestStep is allowed to emit
var Events []event.Name

// Variables creates variables that can be used by other test steps
type Variables struct {
}

// Name returns the plugin name.
func (ts *Variables) Name() string {
return Name
}

// Run executes the cmd step.
func (ts *Variables) Run(
ctx xcontext.Context,
ch test.TestStepChannels,
ev testevent.Emitter,
stepsVars test.StepsVariables,
inputParams test.TestStepParameters,
resumeState json.RawMessage,
) (json.RawMessage, error) {
if err := ts.ValidateParameters(ctx, inputParams); err != nil {
return nil, err
}
return teststeps.ForEachTarget(Name, ctx, ch, func(ctx xcontext.Context, target *target.Target) error {
for name, ps := range inputParams {
ctx.Debugf("add variable %s, value: %s", name, ps[0])
if err := stepsVars.AddRaw(target.ID, name, ps[0].RawMessage); err != nil {
return err
}
}
return nil
})
}

// ValidateParameters validates the parameters associated to the TestStep
func (ts *Variables) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error {
for name, ps := range params {
if err := test.CheckVariableName(name); err != nil {
return fmt.Errorf("invalid variable name: '%s': %w", name, err)
}
if len(ps) != 1 {
return fmt.Errorf("invalid number of parameter '%s' values: %d (expected 1)", name, len(ps))
}

var res interface{}
if err := json.Unmarshal(ps[0].RawMessage, &res); err != nil {
return fmt.Errorf("invalid json '%s': %w", ps[0].RawMessage, err)
}
}
return nil
}

// New initializes and returns a new Variables test step.
func New() test.TestStep {
return &Variables{}
}

// 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
}
171 changes: 171 additions & 0 deletions plugins/teststeps/variables/variables_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package variables

import (
"encoding/json"
"fmt"
"github.com/linuxboot/contest/pkg/event/testevent"
"github.com/linuxboot/contest/pkg/storage"
"github.com/linuxboot/contest/pkg/target"
"github.com/linuxboot/contest/plugins/storage/memory"
"sync"
"testing"

"github.com/linuxboot/contest/pkg/test"
"github.com/linuxboot/contest/pkg/xcontext"
"github.com/stretchr/testify/require"
)

func TestCreation(t *testing.T) {
obj := New()
require.NotNil(t, obj)
require.Equal(t, Name, obj.Name())
}

func TestValidateParameters(t *testing.T) {
obj := New()
require.NotNil(t, obj)

require.NoError(t, obj.ValidateParameters(xcontext.Background(), nil))
require.NoError(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{
"var1": []test.Param{
{
json.RawMessage("123"),
},
},
}))
// invalid variable name
require.Error(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{
"var var": []test.Param{
{
json.RawMessage("123"),
},
},
}))
// invalid value
require.Error(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{
"var1": []test.Param{
{
json.RawMessage("ALALALALA[}"),
},
},
}))
}

func TestVariablesEmission(t *testing.T) {
ctx, cancel := xcontext.WithCancel(xcontext.Background())
defer cancel()

obj := New()
require.NotNil(t, obj)

in := make(chan *target.Target, 1)
out := make(chan test.TestStepResult, 1)

m, err := memory.New()
if err != nil {
t.Fatalf("could not initialize memory storage: '%v'", err)
}
storageEngineVault := storage.NewSimpleEngineVault()
if err := storageEngineVault.StoreEngine(m, storage.SyncEngine); err != nil {
t.Fatalf("Failed to set memory storage: '%v'", err)
}
ev := storage.NewTestEventEmitterFetcher(storageEngineVault, testevent.Header{
JobID: 12345,
TestName: "variables_tests",
TestStepLabel: "variables",
})

svm := newStepsVariablesMock()

tgt := target.Target{ID: "id1"}
in <- &tgt
close(in)

state, err := obj.Run(ctx, test.TestStepChannels{In: in, Out: out}, ev, svm, test.TestStepParameters{
"str_variable": []test.Param{
{
json.RawMessage("\"dummy\""),
},
},
"int_variable": []test.Param{
{
json.RawMessage("123"),
},
},
"complex_variable": []test.Param{
{
json.RawMessage("{\"name\":\"value\"}"),
},
},
}, nil)
require.NoError(t, err)
require.Empty(t, state)

stepResult := <-out
require.Equal(t, tgt, *stepResult.Target)
require.NoError(t, stepResult.Err)

var strVar string
require.NoError(t, svm.Get(tgt.ID, "str_variable", &strVar))
require.Equal(t, "dummy", strVar)

var intVar int
require.NoError(t, svm.Get(tgt.ID, "int_variable", &intVar))
require.Equal(t, 123, intVar)

var complexVar dummyStruct
require.NoError(t, svm.Get(tgt.ID, "complex_variable", &complexVar))
require.Equal(t, dummyStruct{Name: "value"}, complexVar)
}

type dummyStruct struct {
Name string `json:"name"`
}

type stepsVariablesMock struct {
mu sync.Mutex
variables map[string]map[string]json.RawMessage
}

func newStepsVariablesMock() *stepsVariablesMock {
return &stepsVariablesMock{
variables: make(map[string]map[string]json.RawMessage),
}
}

func (svm *stepsVariablesMock) AddRaw(tgtID string, name string, b json.RawMessage) error {
svm.mu.Lock()
defer svm.mu.Unlock()

targetVars := svm.variables[tgtID]
if targetVars == nil {
targetVars = make(map[string]json.RawMessage)
svm.variables[tgtID] = targetVars
}
targetVars[name] = b
return nil
}

func (svm *stepsVariablesMock) Add(tgtID string, name string, v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
return err
}

return svm.AddRaw(tgtID, name, b)
}

func (svm *stepsVariablesMock) Get(tgtID string, name string, out interface{}) error {
svm.mu.Lock()
defer svm.mu.Unlock()

targetVars := svm.variables[tgtID]
if targetVars == nil {
return fmt.Errorf("no target: %s", tgtID)
}
b, found := targetVars[name]
if !found {
return fmt.Errorf("no variable: %s", name)
}
return json.Unmarshal(b, out)
}
3 changes: 2 additions & 1 deletion tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"github.com/linuxboot/contest/plugins/testfetchers/literal"
"github.com/linuxboot/contest/plugins/teststeps/cmd"
"github.com/linuxboot/contest/plugins/teststeps/sleep"
"github.com/linuxboot/contest/plugins/teststeps/variables"
"github.com/linuxboot/contest/plugins/teststeps/waitport"
testsCommon "github.com/linuxboot/contest/tests/common"
"github.com/linuxboot/contest/tests/common/goroutine_leak_check"
Expand Down Expand Up @@ -122,7 +123,7 @@ func (ts *E2ETestSuite) startServer(extraArgs ...string) {
targetlist_with_state.Load,
},
TestFetcherLoaders: []test.TestFetcherLoader{literal.Load},
TestStepLoaders: []test.TestStepLoader{cmd.Load, sleep.Load, waitport.Load},
TestStepLoaders: []test.TestStepLoader{cmd.Load, sleep.Load, waitport.Load, variables.Load},
ReporterLoaders: []job.ReporterLoader{targetsuccess.Load, noop.Load},
}
err := server.Main(&pc, "contest", args, serverSigs)
Expand Down

0 comments on commit f79f6ef

Please sign in to comment.