diff --git a/stackit/internal/services/alb/applicationloadbalancer/resource.go b/stackit/internal/services/alb/applicationloadbalancer/resource.go index c65da6e28..d86250ebd 100644 --- a/stackit/internal/services/alb/applicationloadbalancer/resource.go +++ b/stackit/internal/services/alb/applicationloadbalancer/resource.go @@ -41,6 +41,11 @@ import ( "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" ) +// healthCheckDurationRegex accepts only durations in the form the API returns them: whole seconds +// ("1s") or exactly three non-zero decimals ("0.100s"), so the value in state matches the config +// and does not drift. The alternatives are grouped so that both are anchored at both ends. +var healthCheckDurationRegex = regexp.MustCompile(`^(?:[0-9]{1,3}s|[0-9]{1,3}\.(?:[0-9]{2}[1-9]|[0-9][1-9][0-9]|[1-9][0-9]{2})s)$`) + // Ensure the implementation satisfies the expected interfaces. var ( _ resource.Resource = &applicationLoadBalancerResource{} @@ -984,7 +989,7 @@ The example below creates the supporting infrastructure using the STACKIT Terraf Required: true, Validators: []validator.String{ stringvalidator.RegexMatches( - regexp.MustCompile(`^[0-9]{1,3}s|[0-9]{1,3}\.(?:[0-9]{2}[1-9]|[0-9][1-9][0-9]|[1-9][0-9]{2})s$`), + healthCheckDurationRegex, "The duration must be between 0s and 999.999s (e.g.: 1s or 0.100s or 12.345s)", ), }, @@ -994,7 +999,7 @@ The example below creates the supporting infrastructure using the STACKIT Terraf Required: true, Validators: []validator.String{ stringvalidator.RegexMatches( - regexp.MustCompile(`^[0-9]{1,3}s|[0-9]{1,3}\.(?:[0-9]{2}[1-9]|[0-9][1-9][0-9]|[1-9][0-9]{2})s$`), + healthCheckDurationRegex, "The duration must be between 0s and 999.999s (e.g.: 1s or 0.100s or 12.345s)", ), }, @@ -1004,7 +1009,7 @@ The example below creates the supporting infrastructure using the STACKIT Terraf Required: true, Validators: []validator.String{ stringvalidator.RegexMatches( - regexp.MustCompile(`^[0-9]{1,3}s|[0-9]{1,3}\.(?:[0-9]{2}[1-9]|[0-9][1-9][0-9]|[1-9][0-9]{2})s$`), + healthCheckDurationRegex, "The duration must be between 0s and 999.999s (e.g.: 1s or 0.100s or 12.345s)", ), }, diff --git a/stackit/internal/services/alb/applicationloadbalancer/resource_test.go b/stackit/internal/services/alb/applicationloadbalancer/resource_test.go index 32d1013fa..922e37530 100644 --- a/stackit/internal/services/alb/applicationloadbalancer/resource_test.go +++ b/stackit/internal/services/alb/applicationloadbalancer/resource_test.go @@ -1679,3 +1679,40 @@ func Test_toPathPayload(t *testing.T) { }) } } + +func TestHealthCheckDurationRegex(t *testing.T) { + tests := []struct { + value string + valid bool + }{ + {"0s", true}, + {"1s", true}, + {"999s", true}, + {"0.100s", true}, + {"1.500s", true}, + {"12.345s", true}, + {"999.999s", true}, + // Returned by the API as "0.100s", "1s" and "0s", which would drift. + {"0.1s", false}, + {"1.000s", false}, + {"0.000s", false}, + {"", false}, + {"s", false}, + {"1000s", false}, + {"1.0000s", false}, + {"1.s", false}, + {"-1s", false}, + {"1", false}, + {"1ms", false}, + {"5sGARBAGE", false}, + {"GARBAGE1.500s", false}, + {"5s1.500s", false}, + } + for _, tt := range tests { + t.Run(tt.value, func(t *testing.T) { + if got := healthCheckDurationRegex.MatchString(tt.value); got != tt.valid { + t.Errorf("healthCheckDurationRegex.MatchString(%q) = %v, want %v", tt.value, got, tt.valid) + } + }) + } +}