From 7e0fd48c8c62a9702a355cd8bf39446f287fafbc Mon Sep 17 00:00:00 2001 From: Alexandre Bruyelles Date: Fri, 17 Jul 2026 22:07:49 +0200 Subject: [PATCH 1/2] refactor(utils): improve the status code checker The responseCodeChecker method now takes raw parameters and does more work: convert them and check the values The resulting code is easier to use Signed-off-by: Alexandre Bruyelles --- internal/provider/curl_data_source.go | 9 +----- internal/provider/curl_ephemeral_resource.go | 29 ++------------------ internal/provider/curl_resource.go | 18 ++---------- internal/provider/utilities.go | 16 +++++++++-- internal/provider/utilities_test.go | 14 ++++++---- 5 files changed, 28 insertions(+), 58 deletions(-) diff --git a/internal/provider/curl_data_source.go b/internal/provider/curl_data_source.go index 52cd8d4..2fbfdd7 100644 --- a/internal/provider/curl_data_source.go +++ b/internal/provider/curl_data_source.go @@ -256,14 +256,7 @@ func (d *CurlDataSource) Read(ctx context.Context, req datasource.ReadRequest, r bodyString = "{}" } - var responseCodes []string - for _, v := range data.ResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - responseCodes = append(responseCodes, strVal.ValueString()) - } - } - - if responseCodeChecker(responseCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(data.ResponseCodes, statusCode) { break } diff --git a/internal/provider/curl_ephemeral_resource.go b/internal/provider/curl_ephemeral_resource.go index a15f18c..2e2309a 100644 --- a/internal/provider/curl_ephemeral_resource.go +++ b/internal/provider/curl_ephemeral_resource.go @@ -483,14 +483,7 @@ func (e *EphemeralCurlResource) Open(ctx context.Context, req ephemeral.OpenRequ bodyString = "{}" } - var responseCodes []string - for _, v := range data.ResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - responseCodes = append(responseCodes, strVal.ValueString()) - } - } - - if responseCodeChecker(responseCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(data.ResponseCodes, statusCode) { break } @@ -1143,14 +1136,7 @@ func (e *EphemeralCurlResource) Renew(ctx context.Context, req ephemeral.RenewRe bodyString = "{}" } - var responseCodes []string - for _, v := range privateData.RenewResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - responseCodes = append(responseCodes, strVal.ValueString()) - } - } - - if responseCodeChecker(responseCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(privateData.RenewResponseCodes, statusCode) { break } @@ -1497,19 +1483,10 @@ func (e *EphemeralCurlResource) Close(ctx context.Context, req ephemeral.CloseRe return } - var expectedCodes []string tflog.Debug(ctx, fmt.Sprintf("private data response code list: %v", privateData.CloseResponseCodes.Elements())) - for _, v := range privateData.CloseResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - expectedCodes = append(expectedCodes, strVal.ValueString()) - } - } - - tflog.Debug(ctx, fmt.Sprintf("response code received: %v", statusCode)) - tflog.Debug(ctx, fmt.Sprintf("expected response code received: %v", expectedCodes)) // Validate Response Code - if responseCodeChecker(expectedCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(privateData.CloseResponseCodes, statusCode) { tflog.Debug(ctx, "Close request completed successfully") break } else { diff --git a/internal/provider/curl_resource.go b/internal/provider/curl_resource.go index 1e4df5c..aa2149f 100644 --- a/internal/provider/curl_resource.go +++ b/internal/provider/curl_resource.go @@ -574,14 +574,7 @@ func (r *CurlResource) Create(ctx context.Context, req resource.CreateRequest, r bodyString = "{}" } - var responseCodes []string - for _, v := range data.ResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - responseCodes = append(responseCodes, strVal.ValueString()) - } - } - - if responseCodeChecker(responseCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(data.ResponseCodes, statusCode) { break } @@ -875,15 +868,8 @@ func (r *CurlResource) Delete(ctx context.Context, req resource.DeleteRequest, r return } - var expectedCodes []string - for _, v := range data.DestroyResponseCodes.Elements() { - if strVal, ok := v.(types.String); ok { - expectedCodes = append(expectedCodes, strVal.ValueString()) - } - } - // Validate Response Code - if responseCodeChecker(expectedCodes, strconv.Itoa(statusCode)) { + if responseCodeChecker(data.DestroyResponseCodes, statusCode) { tflog.Debug(ctx, "Destroy request completed successfully") break } else { diff --git a/internal/provider/utilities.go b/internal/provider/utilities.go index fea1dcc..4238f7a 100644 --- a/internal/provider/utilities.go +++ b/internal/provider/utilities.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "net/http" "os" + "strconv" "time" ) @@ -39,9 +40,18 @@ func sanitizeResponse(response string, fieldsToIgnore []string) (string, error) return string(filteredBytes), nil } -func responseCodeChecker(s []string, str string) bool { - for _, v := range s { - if v == str { +func responseCodeChecker(expectedStatusCodes types.List, receivedStatusCode int) bool { + var responseStatusCodes []string + for _, v := range expectedStatusCodes.Elements() { + if strVal, ok := v.(types.String); ok { + responseStatusCodes = append(responseStatusCodes, strVal.ValueString()) + } + } + + var receivedStatusCodeAsInt = strconv.Itoa(receivedStatusCode) + + for _, v := range responseStatusCodes { + if v == receivedStatusCodeAsInt { return true } } diff --git a/internal/provider/utilities_test.go b/internal/provider/utilities_test.go index 0320cef..c5b268a 100644 --- a/internal/provider/utilities_test.go +++ b/internal/provider/utilities_test.go @@ -1,6 +1,8 @@ package provider import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" "io" "net/http" "net/http/httptest" @@ -51,17 +53,19 @@ func TestSanitizeResponse(t *testing.T) { func TestResponseCodeChecker(t *testing.T) { tests := []struct { name string - codes []string - input string + codes []attr.Value + input int expected bool }{ - {"Value Present", []string{"200", "404", "500"}, "404", true}, - {"Value Absent", []string{"200", "500"}, "404", false}, + {"Value Present", []attr.Value{types.StringValue("200"), types.StringValue("404"), types.StringValue("500")}, 404, true}, + {"Value Absent", []attr.Value{types.StringValue("200"), types.StringValue("500")}, 404, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := responseCodeChecker(tt.codes, tt.input) + var listValue types.List + listValue, _ = types.ListValue(types.StringType, tt.codes) + result := responseCodeChecker(listValue, tt.input) if result != tt.expected { t.Errorf("Expected %v, got %v", tt.expected, result) } From a4b2a2cbc6943eb0ed158f1a402deab845286144 Mon Sep 17 00:00:00 2001 From: Alexandre Bruyelles Date: Fri, 17 Jul 2026 22:10:06 +0200 Subject: [PATCH 2/2] fix(read): implement read_response_codes and avoid post-creationg drift ReadResponseCodes was never actually used Also, improve the situation when oldSanitized is null (aka: we just created the object) Signed-off-by: Alexandre Bruyelles --- internal/provider/curl_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/curl_resource.go b/internal/provider/curl_resource.go index aa2149f..2ea20ae 100644 --- a/internal/provider/curl_resource.go +++ b/internal/provider/curl_resource.go @@ -721,7 +721,7 @@ func (r *CurlResource) Read(ctx context.Context, req resource.ReadRequest, resp } // Drift detection - if oldSanitized != sanitizedResponse { + if !responseCodeChecker(data.ReadResponseCodes, httpResp.StatusCode) || (oldSanitized != "null" && oldSanitized != sanitizedResponse) { tflog.Warn(ctx, "Drift detected: Response has changed, marking for recreation.") data.DriftMarker = types.StringValue(time.Now().Format(time.RFC3339Nano)) } else {