From 5697a52b4f1b6c87870f862c25eb0e44d24eb403 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczynski Date: Sat, 17 Sep 2016 19:50:38 +0100 Subject: [PATCH] [WIP] provider/aws: Add normalizeJsonString and validateJsonString functions. (#8028) * Add normalizeJsonString and validateJsonString functions. Signed-off-by: Krzysztof Wilczynski * Add unit test for the normalizeJsonString helper function. Signed-off-by: Krzysztof Wilczynski * Fix. Remove incrrect format string. Signed-off-by: Krzysztof Wilczynski * Remove surplus type assertion. Signed-off-by: Krzysztof Wilczynski * Add unit test for the validateJsonStringhelper function. Signed-off-by: Krzysztof Wilczynski * Remove surplus whitespaces. Signed-off-by: Krzysztof Wilczynski --- .../providers/aws/resource_aws_s3_bucket.go | 1 + builtin/providers/aws/structure.go | 21 +++++++ builtin/providers/aws/structure_test.go | 52 ++++++++++++++++++ builtin/providers/aws/validators.go | 7 +++ builtin/providers/aws/validators_test.go | 55 +++++++++++++++++++ 5 files changed, 136 insertions(+) diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index 09c8ddb3e..6c9e7fca6 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -1399,6 +1399,7 @@ func removeNil(data map[string]interface{}) map[string]interface{} { return withoutNil } +// DEPRECATED. Please consider using `normalizeJsonString` function instead. func normalizeJson(jsonString interface{}) string { if jsonString == nil || jsonString == "" { return "" diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 69e372351..925abf8f4 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -1567,3 +1567,24 @@ func flattenPolicyAttributes(list []*elb.PolicyAttributeDescription) []interface return attributes } + +// Takes a value containing JSON string and passes it through +// the JSON parser to normalize it, returns either a parsing +// error or normalized JSON string. +func normalizeJsonString(jsonString interface{}) (string, error) { + var j interface{} + + if jsonString == nil || jsonString.(string) == "" { + return "", nil + } + + s := jsonString.(string) + + err := json.Unmarshal([]byte(s), &j) + if err != nil { + return s, err + } + + bytes, _ := json.Marshal(j) + return string(bytes[:]), nil +} diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go index 981e199c2..e74348291 100644 --- a/builtin/providers/aws/structure_test.go +++ b/builtin/providers/aws/structure_test.go @@ -1116,3 +1116,55 @@ func TestFlattenPolicyAttributes(t *testing.T) { } } } + +func TestNormalizeJsonString(t *testing.T) { + var err error + var actual string + + // Well formatted and valid. + validJson := `{ + "abc": { + "def": 123, + "xyz": [ + { + "a": "ホリネズミ" + }, + { + "b": "1\\n2" + } + ] + } +}` + expected := `{"abc":{"def":123,"xyz":[{"a":"ホリネズミ"},{"b":"1\\n2"}]}}` + + actual, err = normalizeJsonString(validJson) + if err != nil { + t.Fatalf("Expected not to throw an error while parsing JSON, but got: %s", err) + } + + if actual != expected { + t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, expected) + } + + // Well formatted but not valid, + // missing closing squre bracket. + invalidJson := `{ + "abc": { + "def": 123, + "xyz": [ + { + "a": "1" + } + } + } +}` + actual, err = normalizeJsonString(invalidJson) + if err == nil { + t.Fatalf("Expected to throw an error while parsing JSON, but got: %s", err) + } + + // We expect the invalid JSON to be shown back to us again. + if actual != invalidJson { + t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", expected, invalidJson) + } +} diff --git a/builtin/providers/aws/validators.go b/builtin/providers/aws/validators.go index 75dd0d1d7..bb65870f5 100644 --- a/builtin/providers/aws/validators.go +++ b/builtin/providers/aws/validators.go @@ -460,3 +460,10 @@ func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) ( } return } + +func validateJsonString(v interface{}, k string) (ws []string, errors []error) { + if _, err := normalizeJsonString(v); err != nil { + errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) + } + return +} diff --git a/builtin/providers/aws/validators_test.go b/builtin/providers/aws/validators_test.go index fdf1d3e28..613d21be7 100644 --- a/builtin/providers/aws/validators_test.go +++ b/builtin/providers/aws/validators_test.go @@ -553,3 +553,58 @@ func TestValidateDbEventSubscriptionName(t *testing.T) { } } } + +func TestValidateJsonString(t *testing.T) { + type testCases struct { + Value string + ErrCount int + } + + invalidCases := []testCases{ + { + Value: `{0:"1"}`, + ErrCount: 1, + }, + { + Value: `{'abc':1}`, + ErrCount: 1, + }, + { + Value: `{"def":}`, + ErrCount: 1, + }, + { + Value: `{"xyz":[}}`, + ErrCount: 1, + }, + } + + for _, tc := range invalidCases { + _, errors := validateJsonString(tc.Value, "json") + if len(errors) != tc.ErrCount { + t.Fatalf("Expected %q to trigger a validation error.", tc.Value) + } + } + + validCases := []testCases{ + { + Value: ``, + ErrCount: 0, + }, + { + Value: `{}`, + ErrCount: 0, + }, + { + Value: `{"abc":["1","2"]}`, + ErrCount: 0, + }, + } + + for _, tc := range validCases { + _, errors := validateJsonString(tc.Value, "json") + if len(errors) != tc.ErrCount { + t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) + } + } +}