Skip to content

Commit

Permalink
Merge pull request #32142 from hashicorp/b-custom-jsonmarshal
Browse files Browse the repository at this point in the history
Replace NormalizeJsonString with local helper func
  • Loading branch information
nam054 committed Jun 29, 2023
2 parents b600d30 + 4acc68c commit 6496f99
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 5 deletions.
39 changes: 34 additions & 5 deletions internal/service/events/rule.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package events

import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"time"
Expand All @@ -12,7 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
Expand Down Expand Up @@ -65,7 +66,7 @@ func ResourceRule() *schema.Resource {
ValidateFunc: validateEventPatternValue(),
AtLeastOneOf: []string{"schedule_expression", "event_pattern"},
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v.(string))
json, _ := RuleEventPatternJSONDecoder(v.(string))
return json
},
},
Expand Down Expand Up @@ -185,7 +186,7 @@ func resourceRuleRead(ctx context.Context, d *schema.ResourceData, meta interfac
d.Set("description", output.Description)
d.Set("event_bus_name", eventBusName) // Use event bus name from resource ID as API response may collapse any ARN.
if output.EventPattern != nil {
pattern, err := structure.NormalizeJsonString(aws.StringValue(output.EventPattern))
pattern, err := RuleEventPatternJSONDecoder(aws.StringValue(output.EventPattern))
if err != nil {
return sdkdiag.AppendErrorf(diags, "event pattern contains an invalid JSON: %s", err)
}
Expand Down Expand Up @@ -295,6 +296,34 @@ func FindRuleByTwoPartKey(ctx context.Context, conn *eventbridge.EventBridge, ev
return output, nil
}

// RuleEventPatternJSONDecoder decodes unicode translation of <,>,&
func RuleEventPatternJSONDecoder(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
}

b, err := json.Marshal(j)
if err != nil {
return "", err
}

if bytes.Contains(b, []byte("\\u003c")) || bytes.Contains(b, []byte("\\u003e")) || bytes.Contains(b, []byte("\\u0026")) {
b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
}
return string(b[:]), nil
}

func expandPutRuleInput(d *schema.ResourceData, name string) *eventbridge.PutRuleInput {
apiObject := &eventbridge.PutRuleInput{
Name: aws.String(name),
Expand All @@ -309,7 +338,7 @@ func expandPutRuleInput(d *schema.ResourceData, name string) *eventbridge.PutRul
}

if v, ok := d.GetOk("event_pattern"); ok {
json, _ := structure.NormalizeJsonString(v)
json, _ := RuleEventPatternJSONDecoder(v.(string))
apiObject.EventPattern = aws.String(json)
}

Expand All @@ -332,7 +361,7 @@ func expandPutRuleInput(d *schema.ResourceData, name string) *eventbridge.PutRul

func validateEventPatternValue() schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
json, err := structure.NormalizeJsonString(v)
json, err := RuleEventPatternJSONDecoder(v.(string))
if err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %w", k, err))

Expand Down
70 changes: 70 additions & 0 deletions internal/service/events/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/eventbridge"
"github.com/google/go-cmp/cmp"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
Expand All @@ -29,6 +30,41 @@ func testAccErrorCheckSkip(t *testing.T) resource.ErrorCheckFunc {
)
}

func TestRuleEventPatternJSONDecoder(t *testing.T) {
t.Parallel()

type testCase struct {
input string
expected string
}
tests := map[string]testCase{
"lessThanGreaterThan": {
input: `{"detail":{"count":[{"numeric":["\u003e",0,"\u003c",5]}]}}`,
expected: `{"detail":{"count":[{"numeric":[">",0,"<",5]}]}}`,
},
"ampersand": {
input: `{"detail":{"count":[{"numeric":["\u0026",0,"\u0026",5]}]}}`,
expected: `{"detail":{"count":[{"numeric":["&",0,"&",5]}]}}`,
},
}

for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()

got, err := tfevents.RuleEventPatternJSONDecoder(test.input)
if err != nil {
t.Fatal(err)
}

if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("unexpected diff (+wanted, -got): %s", diff)
}
})
}
}

func TestAccEventsRule_basic(t *testing.T) {
ctx := acctest.Context(t)
var v1, v2, v3 eventbridge.DescribeRuleOutput
Expand Down Expand Up @@ -256,6 +292,31 @@ func TestAccEventsRule_pattern(t *testing.T) {
})
}

func TestAccEventsRule_patternJSONEncoder(t *testing.T) {
ctx := acctest.Context(t)
var v1 eventbridge.DescribeRuleOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_cloudwatch_event_rule.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, eventbridge.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckRuleDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccRuleConfig_patternJSONEncoder(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckRuleExists(ctx, resourceName, &v1),
resource.TestCheckResourceAttr(resourceName, "name", rName),
resource.TestCheckResourceAttr(resourceName, "schedule_expression", ""),
acctest.CheckResourceAttrEquivalentJSON(resourceName, "event_pattern", `{"detail":{"count":[{"numeric":[">",0,"<",5]}]}}`),
),
},
},
})
}

func TestAccEventsRule_scheduleAndPattern(t *testing.T) {
ctx := acctest.Context(t)
var v eventbridge.DescribeRuleOutput
Expand Down Expand Up @@ -685,6 +746,15 @@ PATTERN
`, rName, pattern)
}

func testAccRuleConfig_patternJSONEncoder(rName string) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_event_rule" "test" {
name = %[1]q
event_pattern = jsonencode({ "detail" : { "count" : [{ "numeric" : [">", 0, "<", 5] }] } })
}
`, rName)
}

func testAccRuleConfig_scheduleAndPattern(rName, pattern string) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_event_rule" "test" {
Expand Down

0 comments on commit 6496f99

Please sign in to comment.