Skip to content

Commit

Permalink
chore: slightly reorganize namings
Browse files Browse the repository at this point in the history
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
  • Loading branch information
hiddeco committed Aug 29, 2024
1 parent bedbd35 commit 367ad99
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 119 deletions.
2 changes: 1 addition & 1 deletion internal/directives/copy_directive.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

func init() {
// Register the copy directive with the builtins registry.
builtins.RegisterStep(&copyDirective{})
builtins.RegisterDirective(&copyDirective{})
}

// copyDirective is a directive that copies a file or directory.
Expand Down
20 changes: 10 additions & 10 deletions internal/directives/step.go → internal/directives/directive.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,24 @@ func (c Config) DeepCopy() Config {
return runtime.DeepCopyJSON(c)
}

// Result is a type that represents the result of a step.
// Result is a type that represents the result of a Directive.
type Result string

const (
// ResultSuccess is the result of a successful step.
// ResultSuccess is the result of a successful directive.
ResultSuccess Result = "Success"
// ResultFailure is the result of a failed step.
// ResultFailure is the result of a failed directive.
ResultFailure Result = "Failure"
)

// Step is an interface that represents a single step in a list of directives
// that should be executed in sequence. Each step is responsible for executing
// a specific action, and may modify the provided context to allow subsequent
// steps to access the results of its execution.
type Step interface {
// Name returns the name of the step.
// Directive is an interface that a directive must implement. A directive is
// a responsible for executing a specific action, and may modify the provided
// context to allow subsequent directives to access the results of its
// execution.
type Directive interface {
// Name returns the name of the directive.
Name() string
// Run executes the step using the provided context and configuration.
// Run executes the directive using the provided context and configuration.
Run(ctx context.Context, stepCtx *StepContext) (Result, error)
}

Expand Down
File renamed without changes.
26 changes: 13 additions & 13 deletions internal/directives/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"os"
)

// Directive is a single directive that should be executed by the Engine.
type Directive struct {
// Step is the name of the step to execute.
Step string
// Step is a single step that should be executed by the Engine.
type Step struct {
// Directive is the name of the directive to execute for this step.
Directive string
// Alias is an optional alias for the step, which can be used to
// refer to its results in subsequent steps.
Alias string
Expand All @@ -19,20 +19,20 @@ type Directive struct {

// Engine is a simple engine that executes a list of directives in sequence.
type Engine struct {
registry StepRegistry
registry DirectiveRegistry
}

// NewEngine returns a new Engine with the provided StepRegistry.
func NewEngine(registry StepRegistry) *Engine {
// NewEngine returns a new Engine with the provided DirectiveRegistry.
func NewEngine(registry DirectiveRegistry) *Engine {
return &Engine{
registry: registry,
}
}

// Execute runs the provided list of directives in sequence.
func (e *Engine) Execute(ctx context.Context, directives []Directive) (Result, error) {
func (e *Engine) Execute(ctx context.Context, steps []Step) (Result, error) {
// TODO(hidde): allow the workDir to be restored from a previous execution.
workDir, err := os.CreateTemp("", "directives-")
workDir, err := os.CreateTemp("", "run-")
if err != nil {
return ResultFailure, fmt.Errorf("temporary working directory creation failed: %w", err)
}
Expand All @@ -41,14 +41,14 @@ func (e *Engine) Execute(ctx context.Context, directives []Directive) (Result, e
// Initialize the shared state that will be passed to each step.
state := make(State)

for _, d := range directives {
for _, d := range steps {
select {
case <-ctx.Done():
return ResultFailure, ctx.Err()
default:
step, err := e.registry.GetStep(d.Step)
step, err := e.registry.GetDirective(d.Directive)
if err != nil {
return ResultFailure, fmt.Errorf("failed to get step %q: %w", d.Step, err)
return ResultFailure, fmt.Errorf("failed to get step %q: %w", d.Directive, err)
}

if result, err := step.Run(ctx, &StepContext{
Expand All @@ -57,7 +57,7 @@ func (e *Engine) Execute(ctx context.Context, directives []Directive) (Result, e
Alias: d.Alias,
Config: d.Config.DeepCopy(),
}); err != nil {
return result, fmt.Errorf("failed to run step %q: %w", d.Step, err)
return result, fmt.Errorf("failed to run step %q: %w", d.Directive, err)
}
}
}
Expand Down
62 changes: 31 additions & 31 deletions internal/directives/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import (
func TestEngine_Execute(t *testing.T) {
tests := []struct {
name string
directives []Directive
initRegistry func() StepRegistry
directives []Step
initRegistry func() DirectiveRegistry
ctx context.Context
assertions func(t *testing.T, result Result, err error)
}{
{
name: "success: single directive",
directives: []Directive{
{Step: "mock"},
directives: []Step{
{Directive: "mock"},
},
initRegistry: func() StepRegistry {
registry := make(StepRegistry)
registry.RegisterStep(&mockStep{
initRegistry: func() DirectiveRegistry {
registry := make(DirectiveRegistry)
registry.RegisterDirective(&mockDirective{
name: "mock",
runResult: ResultSuccess,
})
Expand All @@ -38,17 +38,17 @@ func TestEngine_Execute(t *testing.T) {
},
{
name: "success: multiple directives",
directives: []Directive{
{Step: "mock1"},
{Step: "mock2"},
directives: []Step{
{Directive: "mock1"},
{Directive: "mock2"},
},
initRegistry: func() StepRegistry {
registry := make(StepRegistry)
registry.RegisterStep(&mockStep{
initRegistry: func() DirectiveRegistry {
registry := make(DirectiveRegistry)
registry.RegisterDirective(&mockDirective{
name: "mock1",
runResult: ResultSuccess,
})
registry.RegisterStep(&mockStep{
registry.RegisterDirective(&mockDirective{
name: "mock2",
runResult: ResultSuccess,
})
Expand All @@ -61,12 +61,12 @@ func TestEngine_Execute(t *testing.T) {
},
},
{
name: "failure: step not found",
directives: []Directive{
{Step: "unknown"},
name: "failure: directive not found",
directives: []Step{
{Directive: "unknown"},
},
initRegistry: func() StepRegistry {
return make(StepRegistry)
initRegistry: func() DirectiveRegistry {
return make(DirectiveRegistry)
},
ctx: context.Background(),
assertions: func(t *testing.T, result Result, err error) {
Expand All @@ -75,13 +75,13 @@ func TestEngine_Execute(t *testing.T) {
},
},
{
name: "failure: step returns error",
directives: []Directive{
{Step: "failing", Alias: "alias1", Config: map[string]any{"key": "value"}},
name: "failure: directive returns error",
directives: []Step{
{Directive: "failing", Alias: "alias1", Config: map[string]any{"key": "value"}},
},
initRegistry: func() StepRegistry {
registry := make(StepRegistry)
registry.RegisterStep(&mockStep{
initRegistry: func() DirectiveRegistry {
registry := make(DirectiveRegistry)
registry.RegisterDirective(&mockDirective{
name: "failing",
runResult: ResultFailure,
runErr: errors.New("something went wrong"),
Expand All @@ -96,13 +96,13 @@ func TestEngine_Execute(t *testing.T) {
},
{
name: "failure: context canceled",
directives: []Directive{
{Step: "mock"},
{Step: "mock"}, // This step should not be executed
directives: []Step{
{Directive: "mock"},
{Directive: "mock"}, // This directive should not be executed
},
initRegistry: func() StepRegistry {
registry := make(StepRegistry)
registry.RegisterStep(&mockStep{
initRegistry: func() DirectiveRegistry {
registry := make(DirectiveRegistry)
registry.RegisterDirective(&mockDirective{
name: "mock",
runFunc: func(ctx context.Context, _ *StepContext) (Result, error) {
<-ctx.Done() // Wait for context to be canceled
Expand Down
30 changes: 30 additions & 0 deletions internal/directives/mock_directive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package directives

import "context"

// mockDirective is a mock implementation of the Directive interface, which can be
// used for testing.
type mockDirective struct {
// name is the name of the Directive.
name string
// runFunc is the function that the step should call when Run is called.
// If set, this function will be called instead of returning runResult
// and runErr.
runFunc func(context.Context, *StepContext) (Result, error)
// runResult is the result that the Directive should return when Run is
// called.
runResult Result
// runErr is the error that the Directive should return when Run is called.
runErr error
}

func (d *mockDirective) Name() string {
return d.name
}

func (d *mockDirective) Run(ctx context.Context, stepCtx *StepContext) (Result, error) {
if d.runFunc != nil {
return d.runFunc(ctx, stepCtx)
}
return d.runResult, d.runErr
}
29 changes: 0 additions & 29 deletions internal/directives/mock_step_test.go

This file was deleted.

31 changes: 16 additions & 15 deletions internal/directives/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,31 @@ import (
"maps"
)

// builtins is the registry of built-in steps.
var builtins = StepRegistry{}
// builtins is the registry of built-in directives.
var builtins = DirectiveRegistry{}

// BuiltinsRegistry returns a registry of built-in steps.
func BuiltinsRegistry() StepRegistry {
// BuiltinsRegistry returns a registry of built-in directives.
func BuiltinsRegistry() DirectiveRegistry {
return maps.Clone(builtins)
}

// StepRegistry is a map of step names to steps. It is used to register and
// retrieve steps by name.
type StepRegistry map[string]Step
// DirectiveRegistry is a map of directive names to directives. It is used to
// register and retrieve directives by name.
type DirectiveRegistry map[string]Directive

// RegisterStep registers a step with the given name. If a step with the same
// name has already been registered, it will be overwritten.
func (r StepRegistry) RegisterStep(step Step) {
r[step.Name()] = step

// RegisterDirective registers a Directive with the given name. If a Directive
// with the same name has already been registered, it will be overwritten.
func (r DirectiveRegistry) RegisterDirective(directive Directive) {
r[directive.Name()] = directive
}

// GetStep returns the step with the given name, or an error if no such step
// exists.
func (r StepRegistry) GetStep(name string) (Step, error) {
// GetDirective returns the Directive with the given name, or an error if no
// such Directive exists.
func (r DirectiveRegistry) GetDirective(name string) (Directive, error) {
step, ok := r[name]
if !ok {
return nil, fmt.Errorf("step %q not found", name)
return nil, fmt.Errorf("directive %q not found", name)
}
return step, nil
}
40 changes: 20 additions & 20 deletions internal/directives/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,43 @@ import (
"github.com/stretchr/testify/assert"
)

func TestStepRegistry_RegisterStep(t *testing.T) {
t.Run("registers step", func(t *testing.T) {
r := make(StepRegistry)
s := &mockStep{}
r.RegisterStep(s)
func TestDirectiveRegistry_RegisterDirective(t *testing.T) {
t.Run("registers directive", func(t *testing.T) {
r := make(DirectiveRegistry)
s := &mockDirective{}
r.RegisterDirective(s)

assert.Equal(t, s, r[s.Name()])
})

t.Run("overwrites step", func(t *testing.T) {
r := make(StepRegistry)
s := &mockStep{}
r.RegisterStep(s)
s2 := &mockStep{
t.Run("overwrites directive", func(t *testing.T) {
r := make(DirectiveRegistry)
s := &mockDirective{}
r.RegisterDirective(s)
s2 := &mockDirective{
runErr: fmt.Errorf("error"),
}
r.RegisterStep(s2)
r.RegisterDirective(s2)

assert.NotEqual(t, s, r[s2.Name()])
assert.Equal(t, s2, r[s2.Name()])
})
}

func TestStepRegistry_GetStep(t *testing.T) {
t.Run("step exists", func(t *testing.T) {
r := make(StepRegistry)
s := &mockStep{}
r.RegisterStep(s)
func TestDirectiveRegistry_GetDirective(t *testing.T) {
t.Run("directive exists", func(t *testing.T) {
r := make(DirectiveRegistry)
s := &mockDirective{}
r.RegisterDirective(s)

step, err := r.GetStep(s.Name())
step, err := r.GetDirective(s.Name())
assert.NoError(t, err)
assert.Equal(t, s, step)
})

t.Run("step does not exist", func(t *testing.T) {
r := make(StepRegistry)
_, err := r.GetStep("nonexistent")
t.Run("directive does not exist", func(t *testing.T) {
r := make(DirectiveRegistry)
_, err := r.GetDirective("nonexistent")
assert.ErrorContains(t, err, "not found")
})
}

0 comments on commit 367ad99

Please sign in to comment.