diff --git a/.changes/unreleased/BUG FIXES-20230210-175832.yaml b/.changes/unreleased/BUG FIXES-20230210-175832.yaml new file mode 100644 index 0000000..b0c2dce --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20230210-175832.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'datasource/timeouts: Use default for null and unknown ([#35](https://github.com/hashicorp/terraform-plugin-framework-timeouts/pull/35)).' +time: 2023-02-10T17:58:32.928723089+01:00 +custom: + Issue: "35" diff --git a/.changes/unreleased/BUG FIXES-20230210-175852.yaml b/.changes/unreleased/BUG FIXES-20230210-175852.yaml new file mode 100644 index 0000000..e29acab --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20230210-175852.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'resource/timeouts: Use default for null and unknown ([#35](https://github.com/hashicorp/terraform-plugin-framework-timeouts/pull/35)).' +time: 2023-02-10T17:58:52.979389154+01:00 +custom: + Issue: "35" diff --git a/datasource/timeouts/timeouts.go b/datasource/timeouts/timeouts.go index 21f1caa..201d059 100644 --- a/datasource/timeouts/timeouts.go +++ b/datasource/timeouts/timeouts.go @@ -89,6 +89,12 @@ func (t Value) getTimeout(ctx context.Context, timeoutName string, defaultTimeou return defaultTimeout, diags } + if value.IsNull() || value.IsUnknown() { + tflog.Info(ctx, timeoutName+" timeout configuration is null or unknown, using provided default") + + return defaultTimeout, diags + } + // No type assertion check is required as the schema guarantees that the object attributes // are types.String. timeout, err := time.ParseDuration(value.(types.String).ValueString()) diff --git a/datasource/timeouts/timeouts_test.go b/datasource/timeouts/timeouts_test.go index ae683e7..4aabf1b 100644 --- a/datasource/timeouts/timeouts_test.go +++ b/datasource/timeouts/timeouts_test.go @@ -165,6 +165,32 @@ func TestTimeoutsValueRead(t *testing.T) { }, expectedTimeout: 20 * time.Minute, }, + "read-null": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "read": types.StringType, + }, + map[string]attr.Value{ + "read": types.StringNull(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, + "read-unknown": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "read": types.StringType, + }, + map[string]attr.Value{ + "read": types.StringUnknown(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, "read-not-parseable-as-time-duration": { timeoutsValue: timeouts.Value{ Object: types.ObjectValueMust( diff --git a/resource/timeouts/timeouts.go b/resource/timeouts/timeouts.go index d2b7cfa..b35c151 100644 --- a/resource/timeouts/timeouts.go +++ b/resource/timeouts/timeouts.go @@ -107,6 +107,12 @@ func (t Value) getTimeout(ctx context.Context, timeoutName string, defaultTimeou return defaultTimeout, diags } + if value.IsNull() || value.IsUnknown() { + tflog.Info(ctx, timeoutName+" timeout configuration is null or unknown, using provided default") + + return defaultTimeout, diags + } + // No type assertion check is required as the schema guarantees that the object attributes // are types.String. timeout, err := time.ParseDuration(value.(types.String).ValueString()) diff --git a/resource/timeouts/timeouts_test.go b/resource/timeouts/timeouts_test.go index f2b5d51..e41d74e 100644 --- a/resource/timeouts/timeouts_test.go +++ b/resource/timeouts/timeouts_test.go @@ -180,6 +180,32 @@ func TestTimeoutsValueCreate(t *testing.T) { }, expectedTimeout: 20 * time.Minute, }, + "create-null": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "create": types.StringType, + }, + map[string]attr.Value{ + "create": types.StringNull(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, + "create-unknown": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "create": types.StringType, + }, + map[string]attr.Value{ + "create": types.StringUnknown(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, "create-not-parseable-as-time-duration": { timeoutsValue: timeouts.Value{ Object: types.ObjectValueMust( @@ -248,6 +274,32 @@ func TestTimeoutsValueRead(t *testing.T) { }, expectedTimeout: 20 * time.Minute, }, + "read-null": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "read": types.StringType, + }, + map[string]attr.Value{ + "read": types.StringNull(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, + "read-unknown": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "read": types.StringType, + }, + map[string]attr.Value{ + "read": types.StringUnknown(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, "read-not-parseable-as-time-duration": { timeoutsValue: timeouts.Value{ Object: types.ObjectValueMust( @@ -316,6 +368,32 @@ func TestTimeoutsValueUpdate(t *testing.T) { }, expectedTimeout: 20 * time.Minute, }, + "update-null": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "update": types.StringType, + }, + map[string]attr.Value{ + "update": types.StringNull(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, + "update-unknown": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "update": types.StringType, + }, + map[string]attr.Value{ + "update": types.StringUnknown(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, "update-not-parseable-as-time-duration": { timeoutsValue: timeouts.Value{ Object: types.ObjectValueMust( @@ -384,6 +462,32 @@ func TestTimeoutsValueDelete(t *testing.T) { }, expectedTimeout: 20 * time.Minute, }, + "delete-null": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "delete": types.StringType, + }, + map[string]attr.Value{ + "delete": types.StringNull(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, + "delete-unknown": { + timeoutsValue: timeouts.Value{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "delete": types.StringType, + }, + map[string]attr.Value{ + "delete": types.StringUnknown(), + }, + ), + }, + expectedTimeout: 20 * time.Minute, + }, "delete-not-parseable-as-time-duration": { timeoutsValue: timeouts.Value{ Object: types.ObjectValueMust(