Skip to content

Commit

Permalink
Basic runner and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchellh committed Jun 4, 2013
1 parent b44e610 commit 818eb85
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
22 changes: 22 additions & 0 deletions basic_runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package multistep

// BasicRunner is a Runner that just runs the given slice of steps.
type BasicRunner struct {
// Steps is a slice of steps to run. Once set, this should _not_ be
// modified.
Steps []Step
}

func (b *BasicRunner) Run(state map[string]interface{}) {
for _, step := range b.Steps {
action := step.Run(state)
defer step.Cleanup(state)

if action == ActionHalt {
break
}
}
}

func (b *BasicRunner) Cancel() {
}
29 changes: 29 additions & 0 deletions basic_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package multistep

import (
"reflect"
"testing"
)

func TestBasicRunner_ImplRunner(t *testing.T) {
var raw interface{}
raw = &BasicRunner{}
if _, ok := raw.(Runner); !ok {
t.Fatalf("BasicRunner must be a Runner")
}
}

func TestBasicRunner_Run(t *testing.T) {
data := make(map[string]interface{})
stepA := &TestStepAcc{"a"}
stepB := &TestStepAcc{"b"}

r := &BasicRunner{[]Step{stepA, stepB}}
r.Run(data)

expected := []string{"a", "b"}
results := data["data"].([]string)
if !reflect.DeepEqual(results, expected) {
t.Errorf("unexpected result: %#v", results)
}
}
39 changes: 39 additions & 0 deletions multistep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package multistep

// A StepAction determines the next step to take regarding multi-step actions.
type StepAction uint

const (
ActionContinue StepAction = iota
ActionHalt
)

// Step is a single step that is part of a potentially large sequence
// of other steps, responsible for performing some specific action.
type Step interface {
// Run is called to perform the action. The parameter is a "state bag"
// of untyped things. Please be very careful about type-checking the
// items in this bag.
//
// The return value determines whether multi-step sequences continue
// or should halt.
Run(map[string]interface{}) StepAction

// Cleanup is called in reverse order of the steps that have run
// and allow steps to clean up after themselves. Do not assume if this
// ran that the entire multi-step sequence completed successfully. This
// method can be ran in the face of errors and cancellations as well.
//
// The parameter is the same "state bag" as Run, and represents the
// state at the latest possible time prior to calling Cleanup.
Cleanup(map[string]interface{})
}

// Runner is a thing that runs one or more steps.
type Runner interface {
// Run runs the steps with the given initial state.
Run(map[string]interface{})

// Cancel cancels a potentially running stack of steps.
Cancel()
}
24 changes: 24 additions & 0 deletions multistep_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package multistep

// A step for testing that accumuluates data into a string slice in the
// the state bag. It always uses the "data" key in the state bag, and will
// initialize it.
type TestStepAcc struct {
// The data inserted into the state bag.
Data string
}

func (s TestStepAcc) Run(state map[string]interface{}) StepAction {
if _, ok := state["data"]; !ok {
state["data"] = make([]string, 0, 5)
}

data := state["data"].([]string)
data = append(data, s.Data)
state["data"] = data

return ActionContinue
}

func (s TestStepAcc) Cleanup(map[string]interface{}) {
}

0 comments on commit 818eb85

Please sign in to comment.