diff --git a/.changelog/46898.txt b/.changelog/46898.txt new file mode 100644 index 000000000000..4b093ec5ff70 --- /dev/null +++ b/.changelog/46898.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudfrontkeyvaluestore_key: Fix issue where values were incorrectly JSON-encoded, resulting in extra quotes being stored in AWS +``` diff --git a/internal/service/cloudfrontkeyvaluestore/key.go b/internal/service/cloudfrontkeyvaluestore/key.go index c0e16506fee0..f0c58cb1b291 100644 --- a/internal/service/cloudfrontkeyvaluestore/key.go +++ b/internal/service/cloudfrontkeyvaluestore/key.go @@ -113,6 +113,8 @@ func (r *keyResource) Create(ctx context.Context, request resource.CreateRequest // Additional fields. input.IfMatch = etag + // Manually set Value to avoid JSON encoding by AutoFlEx. + input.Value = data.Value.ValueStringPointer() output, err := conn.PutKey(ctx, input) @@ -159,6 +161,11 @@ func (r *keyResource) Read(ctx context.Context, request resource.ReadRequest, re return } + // Manually set Value to avoid JSON decoding by AutoFlEx. + if output.Value != nil { + data.Value = types.StringValue(*output.Value) + } + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -200,6 +207,8 @@ func (r *keyResource) Update(ctx context.Context, request resource.UpdateRequest // Additional fields. input.IfMatch = etag + // Manually set Value to avoid JSON encoding by AutoFlEx. + input.Value = new.Value.ValueStringPointer() output, err := conn.PutKey(ctx, input) diff --git a/internal/service/cloudfrontkeyvaluestore/key_test.go b/internal/service/cloudfrontkeyvaluestore/key_test.go index ced98ab0bb41..41127b909537 100644 --- a/internal/service/cloudfrontkeyvaluestore/key_test.go +++ b/internal/service/cloudfrontkeyvaluestore/key_test.go @@ -39,6 +39,7 @@ func TestAccCloudFrontKeyValueStoreKey_basic(t *testing.T) { Config: testAccKeyConfig_basic(rName, value), Check: resource.ComposeTestCheckFunc( testAccCheckKeyExists(ctx, t, resourceName), + testAccCheckKeyHasValue(ctx, t, resourceName, value), resource.TestCheckResourceAttr(resourceName, names.AttrKey, rName), resource.TestCheckResourceAttrPair(resourceName, "key_value_store_arn", "aws_cloudfront_key_value_store.test", names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, names.AttrID), @@ -113,6 +114,7 @@ func TestAccCloudFrontKeyValueStoreKey_value(t *testing.T) { Config: testAccKeyConfig_basic(rName, value1), Check: resource.ComposeTestCheckFunc( testAccCheckKeyExists(ctx, t, resourceName), + testAccCheckKeyHasValue(ctx, t, resourceName, value1), resource.TestCheckResourceAttr(resourceName, names.AttrKey, rName), resource.TestCheckResourceAttrPair(resourceName, "key_value_store_arn", "aws_cloudfront_key_value_store.test", names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, names.AttrID), @@ -129,6 +131,7 @@ func TestAccCloudFrontKeyValueStoreKey_value(t *testing.T) { Config: testAccKeyConfig_basic(rName, value2), Check: resource.ComposeTestCheckFunc( testAccCheckKeyExists(ctx, t, resourceName), + testAccCheckKeyHasValue(ctx, t, resourceName, value2), resource.TestCheckResourceAttr(resourceName, names.AttrKey, rName), resource.TestCheckResourceAttrPair(resourceName, "key_value_store_arn", "aws_cloudfront_key_value_store.test", names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, names.AttrID), @@ -140,6 +143,39 @@ func TestAccCloudFrontKeyValueStoreKey_value(t *testing.T) { }) } +func TestAccCloudFrontKeyValueStoreKey_specialCharacters(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + // Test value with special characters that would be affected by JSON encoding + value := `special "quoted" value with 'quotes' and {braces}` + resourceName := "aws_cloudfrontkeyvaluestore_key.test" + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.CloudFront) + }, + ErrorCheck: acctest.ErrorCheck(t, names.CloudFront), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKeyDestroy(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccKeyConfig_basic(rName, value), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeyExists(ctx, t, resourceName), + testAccCheckKeyHasValue(ctx, t, resourceName, value), + resource.TestCheckResourceAttr(resourceName, names.AttrValue, value), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccCloudFrontKeyValueStoreKey_disappears(t *testing.T) { ctx := acctest.Context(t) rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) @@ -208,6 +244,33 @@ func testAccCheckKeyExists(ctx context.Context, t *testing.T, n string) resource } } +func testAccCheckKeyHasValue(ctx context.Context, t *testing.T, n string, expectedValue string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.ProviderMeta(ctx, t).CloudFrontKeyValueStoreClient(ctx) + + output, err := tfcloudfrontkeyvaluestore.FindKeyByTwoPartKey(ctx, conn, rs.Primary.Attributes["key_value_store_arn"], rs.Primary.Attributes[names.AttrKey]) + if err != nil { + return err + } + + if output.Value == nil { + return fmt.Errorf("CloudFront KeyValueStore Key value is nil") + } + + actualValue := *output.Value + if actualValue != expectedValue { + return fmt.Errorf("CloudFront KeyValueStore Key value = %q, expected %q", actualValue, expectedValue) + } + + return nil + } +} + func testAccKeyConfig_basic(rName, value string) string { return fmt.Sprintf(` resource "aws_cloudfrontkeyvaluestore_key" "test" {