From 66b1087a2be8397e4c94002ebcdaea26a33b801e Mon Sep 17 00:00:00 2001 From: Lukas Jarosch Date: Tue, 12 Mar 2024 00:11:21 +0100 Subject: [PATCH] feat: undefined detection --- inventory.go | 31 ++++++++++++----- inventory_test.go | 34 ++++++++++++++++--- testdata/compile/data/undefined.yaml | 2 ++ .../targets/not_overwritten_undefined.yaml | 2 ++ .../targets/overwritten_undefined.yaml | 2 ++ 5 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 testdata/compile/data/undefined.yaml create mode 100644 testdata/compile/targets/not_overwritten_undefined.yaml create mode 100644 testdata/compile/targets/overwritten_undefined.yaml diff --git a/inventory.go b/inventory.go index ea1fcd0..298bad3 100644 --- a/inventory.go +++ b/inventory.go @@ -2,8 +2,7 @@ package skipper import ( "fmt" - - "github.com/davecgh/go-spew/spew" + "strings" "github.com/lukasjarosch/skipper/data" ) @@ -14,14 +13,20 @@ type Scope string var ( DataScope Scope = "data" TargetsScope Scope = "targets" + + // UndefinedValue is a value which must be defined during compilation + // To ensure all values which can only be set within the target are actually set, + // one can use this value. + UndefinedValue = data.NewValue("__undefined__") ) var ( - ErrEmptyScope = fmt.Errorf("scope is empty") - ErrNilRegistry = fmt.Errorf("registry is nil") - ErrScopeDoesNotExist = fmt.Errorf("scope does not exist") - ErrScopeAlreadyRegistered = fmt.Errorf("scope already registered") - ErrTargetCannotIntroducePaths = fmt.Errorf("target cannot introduce new paths") + ErrEmptyScope = fmt.Errorf("scope is empty") + ErrNilRegistry = fmt.Errorf("registry is nil") + ErrScopeDoesNotExist = fmt.Errorf("scope does not exist") + ErrScopeAlreadyRegistered = fmt.Errorf("scope already registered") + ErrTargetCannotIntroducePaths = fmt.Errorf("target cannot introduce new paths") + ErrUndefinedValueNotOverwritten = fmt.Errorf("undefined value was not overwritten by target") ) // Inventory is the top-level abstraction which represents all data. @@ -122,7 +127,6 @@ func (inv *Inventory) Compile(target data.Path) error { } // The path exists within the inventory, overwrite it with the value from the target. - spew.Println("OVERWRITTEN", pathWithoutClassName) err = inv.SetPath(pathWithoutClassName, v.Raw) if err != nil { return fmt.Errorf("failed to overwrite path %s: %w", pathWithoutClassName, err) @@ -133,6 +137,17 @@ func (inv *Inventory) Compile(target data.Path) error { return err } + // undefined value detection, go through all paths to ensure all values are no 'UndefinedValue' + err = inv.WalkValues(func(p data.Path, v data.Value) error { + if strings.ToLower(strings.TrimSpace(v.String())) == UndefinedValue.String() { + return fmt.Errorf("%w: %s", ErrUndefinedValueNotOverwritten, p) + } + return nil + }) + if err != nil { + return err + } + return nil } diff --git a/inventory_test.go b/inventory_test.go index f810aa7..cfcb7a5 100644 --- a/inventory_test.go +++ b/inventory_test.go @@ -160,8 +160,8 @@ func TestInventoryAbsolutePath(t *testing.T) { } func TestInventory_Compile(t *testing.T) { - dataRegistry := func() *Registry { - commonClass, err := NewClass("testdata/compile/data/common.yaml", codec.NewYamlCodec(), data.NewPath("common")) + dataRegistry := func(class string) *Registry { + commonClass, err := NewClass(fmt.Sprintf("testdata/compile/data/%s.yaml", class), codec.NewYamlCodec(), data.NewPath(class)) assert.NoError(t, err) dataRegistry := NewRegistry() err = dataRegistry.RegisterClass(commonClass) @@ -182,7 +182,7 @@ func TestInventory_Compile(t *testing.T) { t.Run("valid target", func(t *testing.T) { inventory, _ := NewInventory() - err := inventory.RegisterScope(DataScope, dataRegistry()) + err := inventory.RegisterScope(DataScope, dataRegistry("common")) assert.NoError(t, err) err = inventory.RegisterScope(TargetsScope, targetRegistry("valid")) assert.NoError(t, err) @@ -204,7 +204,7 @@ func TestInventory_Compile(t *testing.T) { t.Run("target cannot introduce paths in the inventory", func(t *testing.T) { inventory, _ := NewInventory() - err := inventory.RegisterScope(DataScope, dataRegistry()) + err := inventory.RegisterScope(DataScope, dataRegistry("common")) assert.NoError(t, err) err = inventory.RegisterScope(TargetsScope, targetRegistry("introduce_paths")) assert.NoError(t, err) @@ -212,4 +212,30 @@ func TestInventory_Compile(t *testing.T) { err = inventory.Compile(data.NewPath("targets.introduce_paths")) assert.ErrorIs(t, err, ErrTargetCannotIntroducePaths) }) + + t.Run("error if undefined value is not overwritten", func(t *testing.T) { + inventory, _ := NewInventory() + err := inventory.RegisterScope(DataScope, dataRegistry("undefined")) + assert.NoError(t, err) + err = inventory.RegisterScope(TargetsScope, targetRegistry("not_overwritten_undefined")) + assert.NoError(t, err) + + err = inventory.Compile(data.NewPath("targets.not_overwritten_undefined")) + assert.ErrorIs(t, err, ErrUndefinedValueNotOverwritten) + }) + + t.Run("no error if undefined value is overwritten", func(t *testing.T) { + inventory, _ := NewInventory() + err := inventory.RegisterScope(DataScope, dataRegistry("undefined")) + assert.NoError(t, err) + err = inventory.RegisterScope(TargetsScope, targetRegistry("overwritten_undefined")) + assert.NoError(t, err) + + err = inventory.Compile(data.NewPath("targets.overwritten_undefined")) + assert.NoError(t, err) + + val, err := inventory.Get("data.undefined.network_cidr") + assert.NoError(t, err) + assert.Equal(t, "10.0.0.0/8", val.String()) + }) } diff --git a/testdata/compile/data/undefined.yaml b/testdata/compile/data/undefined.yaml new file mode 100644 index 0000000..f0a3a51 --- /dev/null +++ b/testdata/compile/data/undefined.yaml @@ -0,0 +1,2 @@ +undefined: + network_cidr: __undefined__ diff --git a/testdata/compile/targets/not_overwritten_undefined.yaml b/testdata/compile/targets/not_overwritten_undefined.yaml new file mode 100644 index 0000000..ea2183d --- /dev/null +++ b/testdata/compile/targets/not_overwritten_undefined.yaml @@ -0,0 +1,2 @@ +not_overwritten_undefined: + lol: nothing diff --git a/testdata/compile/targets/overwritten_undefined.yaml b/testdata/compile/targets/overwritten_undefined.yaml new file mode 100644 index 0000000..2680060 --- /dev/null +++ b/testdata/compile/targets/overwritten_undefined.yaml @@ -0,0 +1,2 @@ +overwritten_undefined: + data.undefined.network_cidr: 10.0.0.0/8