Skip to content

Commit

Permalink
fix(parser): Select the correct AWS CloudFormation resource type base…
Browse files Browse the repository at this point in the history
…d on similarity (awslabs#183)

* [Fix] Select the correct polymorphic type
  • Loading branch information
Graham Jenson authored and PaulMaddox committed Mar 13, 2019
1 parent 776555d commit 5749b23
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 87 deletions.
15 changes: 9 additions & 6 deletions cloudformation/resources/awsserverlessapi_definitionuri.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package resources

import (
"encoding/json"
"sort"

"reflect"
"encoding/json"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -21,12 +21,15 @@ func (r AWSServerlessApi_DefinitionUri) value() interface{} {
return r.String
}

if r.S3Location != nil && !reflect.DeepEqual(r.S3Location, &AWSServerlessApi_S3Location{}) {
return r.S3Location
}
ret := []interface{}{}

if r.S3Location != nil {
return r.S3Location
ret = append(ret, *r.S3Location)
}

sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}

return nil
Expand Down
15 changes: 9 additions & 6 deletions cloudformation/resources/awsserverlessapplication_location.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package resources

import (
"encoding/json"
"sort"

"reflect"
"encoding/json"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -21,12 +21,15 @@ func (r AWSServerlessApplication_Location) value() interface{} {
return r.String
}

if r.ApplicationLocation != nil && !reflect.DeepEqual(r.ApplicationLocation, &AWSServerlessApplication_ApplicationLocation{}) {
return r.ApplicationLocation
}
ret := []interface{}{}

if r.ApplicationLocation != nil {
return r.ApplicationLocation
ret = append(ret, *r.ApplicationLocation)
}

sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}

return nil
Expand Down
15 changes: 9 additions & 6 deletions cloudformation/resources/awsserverlessfunction_codeuri.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package resources

import (
"encoding/json"
"sort"

"reflect"
"encoding/json"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -21,12 +21,15 @@ func (r AWSServerlessFunction_CodeUri) value() interface{} {
return r.String
}

if r.S3Location != nil && !reflect.DeepEqual(r.S3Location, &AWSServerlessFunction_S3Location{}) {
return r.S3Location
}
ret := []interface{}{}

if r.S3Location != nil {
return r.S3Location
ret = append(ret, *r.S3Location)
}

sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}

return nil
Expand Down
15 changes: 9 additions & 6 deletions cloudformation/resources/awsserverlessfunction_policies.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package resources

import (
"encoding/json"
"sort"

"reflect"
"encoding/json"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -29,12 +29,15 @@ func (r AWSServerlessFunction_Policies) value() interface{} {
return r.StringArray
}

if r.IAMPolicyDocument != nil && !reflect.DeepEqual(r.IAMPolicyDocument, &AWSServerlessFunction_IAMPolicyDocument{}) {
return r.IAMPolicyDocument
}
ret := []interface{}{}

if r.IAMPolicyDocument != nil {
return r.IAMPolicyDocument
ret = append(ret, *r.IAMPolicyDocument)
}

sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}

if r.IAMPolicyDocumentArray != nil {
Expand Down
69 changes: 18 additions & 51 deletions cloudformation/resources/awsserverlessfunction_properties.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package resources

import (
"encoding/json"
"sort"

"reflect"
"encoding/json"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -24,84 +24,51 @@ type AWSServerlessFunction_Properties struct {

func (r AWSServerlessFunction_Properties) value() interface{} {

if r.S3Event != nil && !reflect.DeepEqual(r.S3Event, &AWSServerlessFunction_S3Event{}) {
return r.S3Event
}

if r.SNSEvent != nil && !reflect.DeepEqual(r.SNSEvent, &AWSServerlessFunction_SNSEvent{}) {
return r.SNSEvent
}

if r.SQSEvent != nil && !reflect.DeepEqual(r.SQSEvent, &AWSServerlessFunction_SQSEvent{}) {
return r.SQSEvent
}

if r.KinesisEvent != nil && !reflect.DeepEqual(r.KinesisEvent, &AWSServerlessFunction_KinesisEvent{}) {
return r.KinesisEvent
}

if r.DynamoDBEvent != nil && !reflect.DeepEqual(r.DynamoDBEvent, &AWSServerlessFunction_DynamoDBEvent{}) {
return r.DynamoDBEvent
}

if r.ApiEvent != nil && !reflect.DeepEqual(r.ApiEvent, &AWSServerlessFunction_ApiEvent{}) {
return r.ApiEvent
}

if r.ScheduleEvent != nil && !reflect.DeepEqual(r.ScheduleEvent, &AWSServerlessFunction_ScheduleEvent{}) {
return r.ScheduleEvent
}

if r.CloudWatchEventEvent != nil && !reflect.DeepEqual(r.CloudWatchEventEvent, &AWSServerlessFunction_CloudWatchEventEvent{}) {
return r.CloudWatchEventEvent
}

if r.IoTRuleEvent != nil && !reflect.DeepEqual(r.IoTRuleEvent, &AWSServerlessFunction_IoTRuleEvent{}) {
return r.IoTRuleEvent
}

if r.AlexaSkillEvent != nil && !reflect.DeepEqual(r.AlexaSkillEvent, &AWSServerlessFunction_AlexaSkillEvent{}) {
return r.AlexaSkillEvent
}
ret := []interface{}{}

if r.S3Event != nil {
return r.S3Event
ret = append(ret, *r.S3Event)
}

if r.SNSEvent != nil {
return r.SNSEvent
ret = append(ret, *r.SNSEvent)
}

if r.SQSEvent != nil {
return r.SQSEvent
ret = append(ret, *r.SQSEvent)
}

if r.KinesisEvent != nil {
return r.KinesisEvent
ret = append(ret, *r.KinesisEvent)
}

if r.DynamoDBEvent != nil {
return r.DynamoDBEvent
ret = append(ret, *r.DynamoDBEvent)
}

if r.ApiEvent != nil {
return r.ApiEvent
ret = append(ret, *r.ApiEvent)
}

if r.ScheduleEvent != nil {
return r.ScheduleEvent
ret = append(ret, *r.ScheduleEvent)
}

if r.CloudWatchEventEvent != nil {
return r.CloudWatchEventEvent
ret = append(ret, *r.CloudWatchEventEvent)
}

if r.IoTRuleEvent != nil {
return r.IoTRuleEvent
ret = append(ret, *r.IoTRuleEvent)
}

if r.AlexaSkillEvent != nil {
return r.AlexaSkillEvent
ret = append(ret, *r.AlexaSkillEvent)
}

sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}

return nil
Expand Down
36 changes: 36 additions & 0 deletions cloudformation/resources/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package resources

import (
"encoding/json"
)

type byJSONLength []interface{}

func (s byJSONLength) Len() int {
return len(s)
}

func (s byJSONLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}

func (s byJSONLength) Less(i, j int) bool {
// Nil is always at the end
if s[i] == nil {
return false
}
if s[j] == nil {
return true
}
jsoni, _ := json.Marshal(s[i])
jsonj, _ := json.Marshal(s[j])

if jsoni == nil {
return false
}
if jsonj == nil {
return true
}

return len(jsoni) > len(jsonj)
}
37 changes: 37 additions & 0 deletions generate/property_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,43 @@ var _ = Describe("Goformation Code Generator", func() {

Context("with a polymorphic property", func() {

Context("with multiple types", func() {

Context("properly marshals and unmarshals values", func() {

property := []byte(`{"Properties":{"BatchSize":10,"StartingPosition":"LATEST","Stream":"arn"},"Type":"Kinesis"}`)

result := &resources.AWSServerlessFunction_EventSource{}
err := json.Unmarshal(property, result)
output, err2 := json.Marshal(result)

It("should marshal and unmarhal to same value", func() {
Expect(err).To(BeNil())
Expect(err2).To(BeNil())
Expect(output).To(Equal(property))
})

})

Context("properly Marshals best value", func() {
expected := []byte(`{"BatchSize":10,"Stream":"arn"}`)

result := &resources.AWSServerlessFunction_Properties{
SQSEvent: &resources.AWSServerlessFunction_SQSEvent{BatchSize: 10},
KinesisEvent: &resources.AWSServerlessFunction_KinesisEvent{BatchSize: 10, Stream: "arn"},
}

output, err := result.MarshalJSON()

It("should marshal and unmarhal to same value", func() {
Expect(err).To(BeNil())
Expect(output).To(Equal(expected))
})

})

})

Context("with a primitive value", func() {

Context("specified as a Go struct", func() {
Expand Down
24 changes: 12 additions & 12 deletions generate/templates/polymorphic-property.template
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package resources

import (
"encoding/json"
{{ if (.Property.Types) }}
"reflect"
"sort"
{{end}}
"encoding/json"
{{ if (or .Property.Types .Property.ItemTypes .Property.PrimitiveItemTypes)}}
"github.com/mitchellh/mapstructure"
{{end}}
)

// {{.Name}} is a helper struct that can hold either a {{.TypesJoined}} value
type {{.Name}} struct {

{{range $type := $.Property.PrimitiveTypes}}
{{$type}} *{{convertToGoType $type}}{{end}}

Expand Down Expand Up @@ -40,15 +39,16 @@ func (r {{.Name}}) value() interface{} {
}
{{end}}

{{range $type := $.Property.Types}}
if r.{{$type}} != nil && !reflect.DeepEqual(r.{{$type}}, &{{$.Basename}}_{{$type}}{}) {
return r.{{$type}}
}
{{end}}

{{range $type := $.Property.Types}}
if r.{{$type}} != nil {
return r.{{$type}}
{{ if (.Property.Types) }}
ret := []interface{}{}
{{range $type := $.Property.Types}}
if r.{{$type}} != nil {
ret = append(ret, *r.{{$type}})
}
{{end}}
sort.Sort(byJSONLength(ret))
if len(ret) > 0 {
return ret[0]
}
{{end}}

Expand Down

0 comments on commit 5749b23

Please sign in to comment.