diff --git a/pkg/resource/select.go b/pkg/resource/select.go index 69f2e520..cb53c4db 100644 --- a/pkg/resource/select.go +++ b/pkg/resource/select.go @@ -38,17 +38,17 @@ func (f Filter) Apply(res []awsls.Resource) []awsls.Resource { func GetTags(r *awsls.Resource) (map[string]string, error) { if r == nil || r.UpdatableResource == nil { - return nil, fmt.Errorf("resource is nil") + return nil, fmt.Errorf("resource is nil: %+v", r) } state := r.State() - if state == nil { - return nil, fmt.Errorf("state is nil") + if state == nil || state.IsNull() { + return nil, fmt.Errorf("state is nil: %+v", state) } if !state.CanIterateElements() { - return nil, fmt.Errorf("cannot iterate: %s", *state) + return nil, fmt.Errorf("cannot iterate: %s", state.GoString()) } attrValue, ok := state.AsValueMap()["tags"] diff --git a/pkg/resource/select_test.go b/pkg/resource/select_test.go index 88de36c8..bfc9e371 100644 --- a/pkg/resource/select_test.go +++ b/pkg/resource/select_test.go @@ -1,12 +1,16 @@ package resource_test import ( + "reflect" "testing" "time" + "github.com/zclconf/go-cty/cty" + "github.com/aws/aws-sdk-go/aws" awsls "github.com/jckuester/awsls/aws" "github.com/jckuester/awsweeper/pkg/resource" + terradozerRes "github.com/jckuester/terradozer/pkg/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -409,3 +413,110 @@ func TestYamlFilter_Apply_NegatedStringFilter(t *testing.T) { require.Len(t, result, 1) assert.Equal(t, "select-this", result[0].ID) } + +func TestGetTags(t *testing.T) { + tests := []struct { + name string + arg *awsls.Resource + want map[string]string + wantErr string + }{ + { + name: "resource is nil", + wantErr: "resource is nil: ", + }, + { + name: "embedded updatable resource is nil", + arg: &awsls.Resource{}, + wantErr: "resource is nil: &{Type: ID: Region: Tags:map[] CreatedAt: UpdatableResource:}", + }, + { + name: "state is nil", + arg: &awsls.Resource{ + UpdatableResource: &terradozerRes.Resource{}, + }, + wantErr: "state is nil: ", + }, + { + name: "state is nil value", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", nil, &cty.NilVal), + }, + wantErr: "state is nil: &{ty:{typeImpl:} v:}", + }, + { + name: "null map", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.NullVal(cty.Map(cty.String)))), + }, + wantErr: "state is nil: &{ty:{typeImpl:{typeImplSigil:{} ElementTypeT:{typeImpl:{typeImplSigil:{} Kind:83}}}} v:}", + }, + { + name: "unhandled type", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.ObjectVal(map[string]cty.Value{ + "tags": cty.StringVal("foo"), + }))), + }, + wantErr: "currently unhandled type: string", + }, + { + name: "tags attribute not found", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.ObjectVal(map[string]cty.Value{ + "tag": cty.StringVal("foo"), + }))), + }, + wantErr: "attribute not found: tags", + }, + { + name: "cannot iterate element", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.StringVal("foo"))), + }, + wantErr: "cannot iterate: cty.StringVal(\"foo\")", + }, + { + name: "empty map of tags", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.ObjectVal(map[string]cty.Value{ + "tags": cty.MapValEmpty(cty.String), + }))), + }, + want: map[string]string{}, + }, + { + name: "some tags", + arg: &awsls.Resource{ + UpdatableResource: terradozerRes.NewWithState("aws_foo", "1234", + nil, ctyValuePtr(cty.ObjectVal(map[string]cty.Value{ + "tags": cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("bar")}), + }))), + }, + want: map[string]string{"foo": "bar"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := resource.GetTags(tt.arg) + + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetTags() got = %v, want %v", got, tt.want) + } + } + }) + } +} + +func ctyValuePtr(v cty.Value) *cty.Value { + return &v +}