Skip to content

Commit

Permalink
fix(types): universal improvement to metadata decoding (#40)
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Meier <[email protected]>
  • Loading branch information
astromechza authored May 20, 2024
1 parent 27be95b commit 7032922
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 19 deletions.
19 changes: 0 additions & 19 deletions framework/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,6 @@ func (s *State[StateExtras, WorkloadExtras, ResourceExtras]) WithWorkload(spec *
out.Workloads = maps.Clone(s.Workloads)
}

spec.Metadata = coerceAnnotationsType(spec.Metadata)
for resName, resource := range spec.Resources {
resource.Metadata = coerceAnnotationsType(resource.Metadata)
spec.Resources[resName] = resource
}

name, ok := spec.Metadata["name"].(string)
if !ok {
return nil, fmt.Errorf("metadata: name: is missing or is not a string")
Expand Down Expand Up @@ -182,19 +176,6 @@ func (s *State[StateExtras, WorkloadExtras, ResourceExtras]) WithPrimedResources
return &out, nil
}

// The metadata maps (workload metadata and resource metadata) decode in a weird way in yaml.v3 which causes type
// coercions elsewhere in the software to fail. We have to rewrite the type to be clear.
func coerceAnnotationsType(in map[string]interface{}) map[string]interface{} {
if a, ok := in["annotations"].(score.WorkloadMetadata); ok {
in = maps.Clone(in)
in["annotations"] = map[string]interface{}(a)
} else if a, ok := in["annotations"].(score.ResourceMetadata); ok {
in = maps.Clone(in)
in["annotations"] = map[string]interface{}(a)
}
return in
}

func (s *State[StateExtras, WorkloadExtras, ResourceExtras]) getResourceDependencies(workloadName, resName string) (map[ResourceUid]bool, error) {
outMap := make(map[ResourceUid]bool)
res := s.Workloads[workloadName].Spec.Resources[resName]
Expand Down
69 changes: 69 additions & 0 deletions framework/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package framework

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -190,15 +191,25 @@ resources:
id: elephant
metadata:
x: a
annotations:
acme.org/x: y
two:
type: thing
id: elephant
metadata:
x: a
annotations:
acme.org/x: y
`)
next, err := next.WithPrimedResources()
assert.NoError(t, err)
assert.Len(t, next.Resources, 1)
assert.Equal(t, map[string]interface{}{
"annotations": map[string]interface{}{
"acme.org/x": "y",
},
"x": "a",
}, next.Resources["thing.default#elephant"].Metadata)
})

t.Run("one workload - same resource - diff metadata", func(t *testing.T) {
Expand Down Expand Up @@ -291,6 +302,64 @@ resources:

}

func TestEncodeDecodeMetadata_yaml(t *testing.T) {
state := new(State[NoExtras, NoExtras, NoExtras])
state = mustAddWorkload(t, state, `
apiVersion: score.dev/v1b1
metadata:
name: example
annotations:
acme.org/x: a
containers:
main:
image: nginx
resources:
eg:
type: example
metadata:
annotations:
acme.org/x: b
`)
raw, err := yaml.Marshal(state)
assert.NoError(t, err)
state = new(State[NoExtras, NoExtras, NoExtras])
assert.NoError(t, yaml.Unmarshal(raw, &state))
assert.Equal(t, score.WorkloadMetadata{"name": "example", "annotations": map[string]interface{}{"acme.org/x": "a"}}, state.Workloads["example"].Spec.Metadata)
assert.Equal(t, score.ResourceMetadata{"annotations": map[string]interface{}{"acme.org/x": "b"}}, state.Workloads["example"].Spec.Resources["eg"].Metadata)

state, err = state.WithPrimedResources()
assert.NoError(t, err)
assert.Equal(t, score.WorkloadMetadata{"name": "example", "annotations": map[string]interface{}{"acme.org/x": "a"}}, state.Workloads["example"].Spec.Metadata)
assert.Equal(t, score.ResourceMetadata{"annotations": map[string]interface{}{"acme.org/x": "b"}}, state.Workloads["example"].Spec.Resources["eg"].Metadata)
assert.Equal(t, map[string]interface{}{"annotations": map[string]interface{}{"acme.org/x": "b"}}, state.Resources["example.default#example.eg"].Metadata)
}

func TestEncodeDecodeMetadata_json(t *testing.T) {
state := new(State[NoExtras, NoExtras, NoExtras])
state = mustAddWorkload(t, state, `
apiVersion: score.dev/v1b1
metadata:
name: example
annotations:
acme.org/x: a
containers:
main:
image: nginx
resources:
eg:
type: example
metadata:
annotations:
acme.org/x: b
`)
raw, err := json.Marshal(state)
assert.NoError(t, err)
state = new(State[NoExtras, NoExtras, NoExtras])
assert.NoError(t, json.Unmarshal(raw, &state))
assert.Equal(t, score.WorkloadMetadata{"name": "example", "annotations": map[string]interface{}{"acme.org/x": "a"}}, state.Workloads["example"].Spec.Metadata)
assert.Equal(t, score.ResourceMetadata{"annotations": map[string]interface{}{"acme.org/x": "b"}}, state.Workloads["example"].Spec.Resources["eg"].Metadata)
}

func TestGetSortedResourceUids(t *testing.T) {

t.Run("empty", func(t *testing.T) {
Expand Down
18 changes: 18 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,21 @@
package types

//go:generate go run github.com/atombender/[email protected] -v --schema-output=https://score.dev/schemas/score=types.gen.go --schema-package=https://score.dev/schemas/score=types --schema-root-type=https://score.dev/schemas/score=Workload ../schema/files/score-v1b1.json.modified

func (m *ResourceMetadata) UnmarshalYAML(unmarshal func(interface{}) error) error {
var out map[string]interface{}
if err := unmarshal(&out); err != nil {
return err
}
*m = ResourceMetadata(out)
return nil
}

func (m *WorkloadMetadata) UnmarshalYAML(unmarshal func(interface{}) error) error {
var out map[string]interface{}
if err := unmarshal(&out); err != nil {
return err
}
*m = WorkloadMetadata(out)
return nil
}

0 comments on commit 7032922

Please sign in to comment.