diff --git a/.changes/unreleased/ENHANCEMENTS-20240223-162424.yaml b/.changes/unreleased/ENHANCEMENTS-20240223-162424.yaml new file mode 100644 index 00000000..9d0b2475 --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20240223-162424.yaml @@ -0,0 +1,6 @@ +kind: ENHANCEMENTS +body: 'resource/time_static: If the `rfc3339` value is set in config and known at + plan-time, all other attributes will also be known during plan.' +time: 2024-02-23T16:24:24.067014-05:00 +custom: + Issue: "255" diff --git a/go.mod b/go.mod index 9cbb2c0e..73169379 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.21 toolchain go1.21.6 require ( + github.com/google/go-cmp v0.6.0 + github.com/hashicorp/terraform-json v0.22.1 github.com/hashicorp/terraform-plugin-framework v1.10.0 github.com/hashicorp/terraform-plugin-framework-timetypes v0.4.0 github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 @@ -20,7 +22,6 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/fatih/color v1.16.0 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -34,7 +35,6 @@ require ( github.com/hashicorp/hcl/v2 v2.21.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.21.0 // indirect - github.com/hashicorp/terraform-json v0.22.1 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 64ef92a6..d245f120 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -4,15 +4,11 @@ package provider import ( - "fmt" - "time" - "github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" ) func protoV5ProviderFactories() map[string]func() (tfprotov5.ProviderServer, error) { @@ -29,62 +25,3 @@ func providerVersion080() map[string]resource.ExternalProvider { }, } } - -func testCheckAttributeValuesDiffer(i *string, j *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if testStringValue(i) == testStringValue(j) { - return fmt.Errorf("attribute values are the same") - } - - return nil - } -} - -func testCheckAttributeValuesSame(i *string, j *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if testStringValue(i) != testStringValue(j) { - return fmt.Errorf("attribute values are different") - } - - return nil - } -} - -//nolint:unparam -func testExtractResourceAttr(resourceName string, attributeName string, attributeValue *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] - - if !ok { - return fmt.Errorf("resource name %s not found in state", resourceName) - } - - attrValue, ok := rs.Primary.Attributes[attributeName] - - if !ok { - return fmt.Errorf("attribute %s not found in resource %s state", attributeName, resourceName) - } - - *attributeValue = attrValue - - return nil - } -} - -// Certain testing requires time differences that are too fast for unit testing. -// Sleeping for a second or two seems pragmatic in our testing. -func testSleep(seconds int) resource.TestCheckFunc { - return func(s *terraform.State) error { - time.Sleep(time.Duration(seconds) * time.Second) - - return nil - } -} - -func testStringValue(sPtr *string) string { - if sPtr == nil { - return "" - } - - return *sPtr -} diff --git a/internal/provider/resource_time_offset_test.go b/internal/provider/resource_time_offset_test.go index e273c8ca..c3c9e897 100644 --- a/internal/provider/resource_time_offset_test.go +++ b/internal/provider/resource_time_offset_test.go @@ -6,12 +6,14 @@ package provider import ( "fmt" "regexp" - "strconv" "testing" "time" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccTimeOffset_Triggers(t *testing.T) { @@ -23,17 +25,16 @@ func TestAccTimeOffset_Triggers(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetTriggers1("key1", "value1"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1"), - resource.TestCheckResourceAttr(resourceName, "offset_days", "1"), - resource.TestCheckNoResourceAttr(resourceName, "offset_months"), - resource.TestCheckNoResourceAttr(resourceName, "offset_hours"), - resource.TestCheckNoResourceAttr(resourceName, "offset_minutes"), - resource.TestCheckNoResourceAttr(resourceName, "offset_seconds"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - testSleep(1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_days"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_seconds"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -43,17 +44,21 @@ func TestAccTimeOffset_Triggers(t *testing.T) { ImportStateVerifyIgnore: []string{"triggers"}, }, { + // Ensures a time difference when running unit tests in CI + PreConfig: func() { + time.Sleep(time.Duration(1) * time.Second) + }, Config: testAccConfigTimeOffsetTriggers1("key1", "value1updated"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "offset_days", "1"), - resource.TestCheckNoResourceAttr(resourceName, "offset_months"), - resource.TestCheckNoResourceAttr(resourceName, "offset_hours"), - resource.TestCheckNoResourceAttr(resourceName, "offset_minutes"), - resource.TestCheckNoResourceAttr(resourceName, "offset_seconds"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1updated")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_days"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_seconds"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, }, }) @@ -71,18 +76,18 @@ func TestAccTimeOffset_OffsetDays(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetDays(timestamp.Format(time.RFC3339), 7), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_days", "7"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_days"), knownvalue.Int64Exact(7)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -92,18 +97,18 @@ func TestAccTimeOffset_OffsetDays(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetDays(timestamp.Format(time.RFC3339), 8), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_days", "8"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_days"), knownvalue.Int64Exact(8)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -121,18 +126,18 @@ func TestAccTimeOffset_OffsetHours(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetHours(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_hours", "1"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_hours"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -142,18 +147,18 @@ func TestAccTimeOffset_OffsetHours(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetHours(timestamp.Format(time.RFC3339), 2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_hours", "2"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_hours"), knownvalue.Int64Exact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -171,18 +176,18 @@ func TestAccTimeOffset_OffsetMinutes(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetMinutes(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_minutes", "1"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_minutes"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -192,18 +197,18 @@ func TestAccTimeOffset_OffsetMinutes(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetMinutes(timestamp.Format(time.RFC3339), 2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_minutes", "2"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_minutes"), knownvalue.Int64Exact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -221,18 +226,18 @@ func TestAccTimeOffset_OffsetMonths(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetMonths(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_months", "3"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -242,18 +247,18 @@ func TestAccTimeOffset_OffsetMonths(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetMonths(timestamp.Format(time.RFC3339), 4), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_months", "4"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Int64Exact(4)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -271,18 +276,18 @@ func TestAccTimeOffset_OffsetSeconds(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetSeconds(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_seconds", "1"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_seconds"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -292,18 +297,18 @@ func TestAccTimeOffset_OffsetSeconds(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetSeconds(timestamp.Format(time.RFC3339), 2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_seconds", "2"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_seconds"), knownvalue.Int64Exact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -321,18 +326,18 @@ func TestAccTimeOffset_OffsetYears(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -342,18 +347,18 @@ func TestAccTimeOffset_OffsetYears(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetYears(timestamp.Format(time.RFC3339), 4), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "4"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(4)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -371,19 +376,19 @@ func TestAccTimeOffset_OffsetYearsAndMonths(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeOffsetOffsetYearsAndMonths(timestamp.Format(time.RFC3339), 3, 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "3"), - resource.TestCheckResourceAttr(resourceName, "offset_months", "3"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ResourceName: resourceName, @@ -393,19 +398,19 @@ func TestAccTimeOffset_OffsetYearsAndMonths(t *testing.T) { }, { Config: testAccConfigTimeOffsetOffsetYearsAndMonths(timestamp.Format(time.RFC3339), 4, 4), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestampUpdated.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestampUpdated.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestampUpdated.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestampUpdated.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "4"), - resource.TestCheckResourceAttr(resourceName, "offset_months", "4"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestampUpdated.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestampUpdated.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestampUpdated.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestampUpdated.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(4)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_months"), knownvalue.Int64Exact(4)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestampUpdated.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestampUpdated.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestampUpdated.Year()))), + }, }, }, }) @@ -422,18 +427,18 @@ func TestAccTimeOffset_Upgrade(t *testing.T) { { ExternalProviders: providerVersion080(), Config: testAccConfigTimeOffsetOffsetYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -443,18 +448,18 @@ func TestAccTimeOffset_Upgrade(t *testing.T) { { ProtoV5ProviderFactories: protoV5ProviderFactories(), Config: testAccConfigTimeOffsetOffsetYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "base_rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "day", strconv.Itoa(offsetTimestamp.Day())), - resource.TestCheckResourceAttr(resourceName, "hour", strconv.Itoa(offsetTimestamp.Hour())), - resource.TestCheckResourceAttr(resourceName, "minute", strconv.Itoa(offsetTimestamp.Minute())), - resource.TestCheckResourceAttr(resourceName, "month", strconv.Itoa(int(offsetTimestamp.Month()))), - resource.TestCheckResourceAttr(resourceName, "offset_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rfc3339", offsetTimestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", strconv.Itoa(offsetTimestamp.Second())), - resource.TestCheckResourceAttr(resourceName, "unix", strconv.Itoa(int(offsetTimestamp.Unix()))), - resource.TestCheckResourceAttr(resourceName, "year", strconv.Itoa(offsetTimestamp.Year())), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("base_rfc3339"), knownvalue.StringExact(timestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), knownvalue.Int64Exact(int64(offsetTimestamp.Day()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), knownvalue.Int64Exact(int64(offsetTimestamp.Hour()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), knownvalue.Int64Exact(int64(offsetTimestamp.Minute()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), knownvalue.Int64Exact(int64(offsetTimestamp.Month()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("offset_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringExact(offsetTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), knownvalue.Int64Exact(int64(offsetTimestamp.Second()))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), knownvalue.Int64Exact(offsetTimestamp.Unix())), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), knownvalue.Int64Exact(int64(offsetTimestamp.Year()))), + }, }, }, }) diff --git a/internal/provider/resource_time_rotating_test.go b/internal/provider/resource_time_rotating_test.go index f1eae128..cee0b53b 100644 --- a/internal/provider/resource_time_rotating_test.go +++ b/internal/provider/resource_time_rotating_test.go @@ -10,7 +10,10 @@ import ( "time" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccTimeRotating_Triggers(t *testing.T) { @@ -22,18 +25,17 @@ func TestAccTimeRotating_Triggers(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingTriggers1("key1", "value1"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1"), - resource.TestCheckResourceAttr(resourceName, "rotation_days", "1"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rotation_rfc3339"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - testSleep(1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -43,18 +45,22 @@ func TestAccTimeRotating_Triggers(t *testing.T) { ImportStateVerifyIgnore: []string{"triggers"}, }, { + // Ensures a time difference when running unit tests in CI + PreConfig: func() { + time.Sleep(time.Duration(1) * time.Second) + }, Config: testAccConfigTimeRotatingTriggers1("key1", "value1updated"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "rotation_days", "1"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rotation_rfc3339"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1updated")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, }, }) @@ -70,15 +76,15 @@ func TestAccTimeRotating_RotationDays_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationDays(timestamp.Format(time.RFC3339), 7), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_days", "7"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 0, 7).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Int64Exact(7)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 0, 7).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -100,15 +106,15 @@ func TestAccTimeRotating_RotationDays_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationDays(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_days", "1"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 0, 1).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 0, 1).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -125,15 +131,15 @@ func TestAccTimeRotating_RotationHours_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationHours(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_hours", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.Add(3*time.Hour).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.Add(3*time.Hour).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -155,15 +161,15 @@ func TestAccTimeRotating_RotationHours_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationHours(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_hours", "1"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.Add(1*time.Hour).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.Add(1*time.Hour).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -180,15 +186,15 @@ func TestAccTimeRotating_RotationMinutes_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationMinutes(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_minutes", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.Add(3*time.Minute).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.Add(3*time.Minute).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -210,15 +216,15 @@ func TestAccTimeRotating_RotationMinutes_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationMinutes(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_minutes", "1"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.Add(1*time.Minute).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.Add(1*time.Minute).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -235,15 +241,15 @@ func TestAccTimeRotating_RotationMonths_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationMonths(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_months", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 3, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 3, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -265,15 +271,15 @@ func TestAccTimeRotating_RotationMonths_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationMonths(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_months", "1"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 1, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 1, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -291,15 +297,15 @@ func TestAccTimeRotating_RotationRfc3339_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationRfc3339(timestamp.Format(time.RFC3339), rotationTimestamp.Format(time.RFC3339)), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", rotationTimestamp.Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(rotationTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -322,15 +328,15 @@ func TestAccTimeRotating_RotationRfc3339_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationRfc3339(timestamp.Format(time.RFC3339), rotationTimestamp.Format(time.RFC3339)), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", rotationTimestamp.Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(rotationTimestamp.Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -347,15 +353,15 @@ func TestAccTimeRotating_RotationYears_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(3, 0, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(3, 0, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -377,15 +383,15 @@ func TestAccTimeRotating_RotationYears_expired(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationYears(timestamp.Format(time.RFC3339), 1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_years", "1"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(1, 0, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Int64Exact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(1, 0, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, ExpectNonEmptyPlan: true, }, }, @@ -402,27 +408,27 @@ func TestAccTimeRotating_RotationDays_ToRotationMonths(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeRotatingRotationDays(timestamp.Format(time.RFC3339), 7), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_days", "7"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 0, 7).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Int64Exact(7)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 0, 7).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { Config: testAccConfigTimeRotatingRotationMonths(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_months", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(0, 3, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_years"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(0, 3, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, }, }) @@ -439,15 +445,15 @@ func TestAccTimeRotation_Upgrade(t *testing.T) { { ExternalProviders: providerVersion080(), Config: testAccConfigTimeRotatingRotationYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(3, 0, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(3, 0, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -457,15 +463,15 @@ func TestAccTimeRotation_Upgrade(t *testing.T) { { ProtoV5ProviderFactories: protoV5ProviderFactories(), Config: testAccConfigTimeRotatingRotationYears(timestamp.Format(time.RFC3339), 3), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "rotation_years", "3"), - resource.TestCheckResourceAttr(resourceName, "rotation_rfc3339", timestamp.AddDate(3, 0, 0).Format(time.RFC3339)), - resource.TestCheckNoResourceAttr(resourceName, "rotation_months"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_days"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_hours"), - resource.TestCheckNoResourceAttr(resourceName, "rotation_minutes"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_years"), knownvalue.Int64Exact(3)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_rfc3339"), knownvalue.StringExact(timestamp.AddDate(3, 0, 0).Format(time.RFC3339))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_months"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_days"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_hours"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rotation_minutes"), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), diff --git a/internal/provider/resource_time_sleep_test.go b/internal/provider/resource_time_sleep_test.go index 4908c214..02ebb99b 100644 --- a/internal/provider/resource_time_sleep_test.go +++ b/internal/provider/resource_time_sleep_test.go @@ -14,6 +14,10 @@ import ( "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tftypes" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) // Since the acceptance testing framework can introduce uncontrollable time delays, @@ -155,20 +159,24 @@ func TestResourceTimeSleepDelete(t *testing.T) { } func TestAccTimeSleep_CreateDuration(t *testing.T) { - var time1, time2 string resourceName := "time_sleep.test" + // These ID comparisons can eventually be replaced by the multiple value checks once released + // in terraform-plugin-testing: https://github.com/hashicorp/terraform-plugin-testing/issues/295 + captureTimeState1 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + captureTimeState2 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + resource.UnitTest(t, resource.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), CheckDestroy: nil, Steps: []resource.TestStep{ { Config: testAccConfigTimeSleepCreateDuration("1ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "create_duration", "1ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - testExtractResourceAttr(resourceName, "id", &time1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.StringExact("1ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + captureTimeState1, + }, }, // This test may work in local execution but typically does not work in CI because of its reliance // on the current time stamp in the ID. We will also need to revisit this test later once TF core allows @@ -181,32 +189,40 @@ func TestAccTimeSleep_CreateDuration(t *testing.T) { //}, { Config: testAccConfigTimeSleepCreateDuration("2ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "create_duration", "2ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - testExtractResourceAttr(resourceName, "id", &time2), - testCheckAttributeValuesSame(&time1, &time2), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.StringExact("2ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + captureTimeState2, + }, }, }, }) + + // Ensure the id time value is different due to the sleep + if captureTimeState1.Value == captureTimeState2.Value { + t.Fatal("attribute values are the same") + } } func TestAccTimeSleep_DestroyDuration(t *testing.T) { - var time1, time2 string resourceName := "time_sleep.test" + // These ID comparisons can eventually be replaced by the multiple value checks once released + // in terraform-plugin-testing: https://github.com/hashicorp/terraform-plugin-testing/issues/295 + captureTimeState1 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + captureTimeState2 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + resource.UnitTest(t, resource.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), CheckDestroy: nil, Steps: []resource.TestStep{ { Config: testAccConfigTimeSleepDestroyDuration("1ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "destroy_duration", "1ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - testExtractResourceAttr(resourceName, "id", &time1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("destroy_duration"), knownvalue.StringExact("1ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + captureTimeState1, + }, }, // This test may work in local execution but typically does not work in CI because of its reliance // on the current time stamp in the ID. We will also need to revisit this test later once TF core allows @@ -219,34 +235,42 @@ func TestAccTimeSleep_DestroyDuration(t *testing.T) { //}, { Config: testAccConfigTimeSleepDestroyDuration("2ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "destroy_duration", "2ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - testExtractResourceAttr(resourceName, "id", &time2), - testCheckAttributeValuesSame(&time1, &time2), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("destroy_duration"), knownvalue.StringExact("2ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + captureTimeState2, + }, }, }, }) + + // Ensure the id time value is different due to the sleep + if captureTimeState1.Value == captureTimeState2.Value { + t.Fatal("attribute values are the same") + } } func TestAccTimeSleep_Triggers(t *testing.T) { - var time1, time2 string resourceName := "time_sleep.test" + // These ID comparisons can eventually be replaced by the multiple value checks once released + // in terraform-plugin-testing: https://github.com/hashicorp/terraform-plugin-testing/issues/295 + captureTimeState1 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + captureTimeState2 := timetesting.NewExtractState(resourceName, tfjsonpath.New("id")) + resource.UnitTest(t, resource.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), CheckDestroy: nil, Steps: []resource.TestStep{ { Config: testAccConfigTimeSleepTriggers1("key1", "value1"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - resource.TestCheckResourceAttrSet(resourceName, "create_duration"), - testExtractResourceAttr(resourceName, "id", &time1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.NotNull()), + captureTimeState1, + }, }, // This test may work in local execution but typically does not work in CI because of its reliance // on the current time stamp in the ID. We will also need to revisit this test later once TF core allows @@ -260,17 +284,21 @@ func TestAccTimeSleep_Triggers(t *testing.T) { //}, { Config: testAccConfigTimeSleepTriggers1("key1", "value1updated"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1updated"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - resource.TestCheckResourceAttrSet(resourceName, "create_duration"), - testExtractResourceAttr(resourceName, "id", &time2), - testCheckAttributeValuesDiffer(&time1, &time2), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1updated")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.NotNull()), + captureTimeState2, + }, }, }, }) + + // Ensure the id time value is different due to the sleep + if captureTimeState1.Value == captureTimeState2.Value { + t.Fatal("attribute values are the same") + } } func TestAccTimeSleep_Upgrade(t *testing.T) { @@ -282,10 +310,10 @@ func TestAccTimeSleep_Upgrade(t *testing.T) { { ExternalProviders: providerVersion080(), Config: testAccConfigTimeSleepCreateDuration("1ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "create_duration", "1ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.StringExact("1ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -295,10 +323,10 @@ func TestAccTimeSleep_Upgrade(t *testing.T) { { ProtoV5ProviderFactories: protoV5ProviderFactories(), Config: testAccConfigTimeSleepCreateDuration("1ms"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "create_duration", "1ms"), - resource.TestCheckResourceAttrSet(resourceName, "id"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("create_duration"), knownvalue.StringExact("1ms")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), knownvalue.NotNull()), + }, }, }, }) diff --git a/internal/provider/resource_time_static.go b/internal/provider/resource_time_static.go index b8c84320..abad07c3 100644 --- a/internal/provider/resource_time_static.go +++ b/internal/provider/resource_time_static.go @@ -20,6 +20,7 @@ import ( var ( _ resource.Resource = (*timeStaticResource)(nil) + _ resource.ResourceWithModifyPlan = (*timeStaticResource)(nil) _ resource.ResourceWithImportState = (*timeStaticResource)(nil) ) @@ -29,6 +30,53 @@ func NewTimeStaticResource() resource.Resource { type timeStaticResource struct{} +func (t timeStaticResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // Skip plan modification unless it's a create operation + if req.Plan.Raw.IsNull() || !req.State.Raw.IsNull() { + return + } + + var plan timeStaticModelV0 + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // Currently, it is only possible to enhance the plan when the rfc3339 value is defined in configuration (i.e. value is not null and known in plan). + // + // Terraform calls the PlanResourceChange RPC twice (initial planned state and final planned state) and currently has no mechanism for sharing information between + // the initial plan call and final plan call. This means that we can't create a final plan that matches the initial plan using something like time.Now() + // which will differ between the two calls and result in a "Provider produced inconsistent final plan" error from Terraform. + // + // If functionality is introduced in the future that allows us to create consistent final and initial plans, we'd likely want to introduce a new managed resource that + // always determines its results at plan time. Changing this resource to adopt that behavior would be a breaking change for practitioners who are relying on the time being + // determined at apply time. + // + // There is no time provider feature request currently for this behavior, but a similar long-standing issue exists on the random provider: + // - https://github.com/hashicorp/terraform-provider-random/issues/121 + if plan.RFC3339.IsNull() || plan.RFC3339.IsUnknown() { + return + } + + rfc3339, diags := plan.RFC3339.ValueRFC3339Time() + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + plan.Year = types.Int64Value(int64(rfc3339.Year())) + plan.Month = types.Int64Value(int64(rfc3339.Month())) + plan.Day = types.Int64Value(int64(rfc3339.Day())) + plan.Hour = types.Int64Value(int64(rfc3339.Hour())) + plan.Minute = types.Int64Value(int64(rfc3339.Minute())) + plan.Second = types.Int64Value(int64(rfc3339.Second())) + plan.Unix = types.Int64Value(rfc3339.Unix()) + plan.ID = plan.RFC3339 + + resp.Diagnostics.Append(resp.Plan.Set(ctx, &plan)...) +} + func (t timeStaticResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_static" } @@ -139,7 +187,7 @@ func (t timeStaticResource) Create(ctx context.Context, req resource.CreateReque timestamp := time.Now().UTC() - if plan.RFC3339.ValueString() != "" { + if !plan.RFC3339.IsNull() && !plan.RFC3339.IsUnknown() { rfc3339, diags := plan.RFC3339.ValueRFC3339Time() resp.Diagnostics.Append(diags...) diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index a56260b6..370a3fa8 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -5,12 +5,17 @@ package provider import ( "fmt" + "math" "regexp" - "strconv" "testing" "time" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeStatic_basic(t *testing.T) { @@ -22,16 +27,16 @@ func TestAccTimeStatic_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeStatic(), - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "day", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "hour", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "minute", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "month", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "rfc3339", regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`)), - resource.TestMatchResourceAttr(resourceName, "second", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "unix", regexp.MustCompile(`^\d+$`)), - resource.TestMatchResourceAttr(resourceName, "year", regexp.MustCompile(`^\d{4}$`)), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.Int64Between(1, 31)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.Int64Between(0, 23)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.Int64Between(1, 12)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegexp(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.Int64Between(1, math.MaxInt64)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.Int64Between(1, 9999)), + }, }, { ResourceName: resourceName, @@ -43,22 +48,26 @@ func TestAccTimeStatic_basic(t *testing.T) { } func TestAccTimeStatic_Triggers(t *testing.T) { - var time1, time2 string + resourceName := "time_static.test" + // These ID comparisons can eventually be replaced by the multiple value checks once released + // in terraform-plugin-testing: https://github.com/hashicorp/terraform-plugin-testing/issues/295 + captureTimeState1 := timetesting.NewExtractState(resourceName, tfjsonpath.New("rfc3339")) + captureTimeState2 := timetesting.NewExtractState(resourceName, tfjsonpath.New("rfc3339")) + resource.UnitTest(t, resource.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), CheckDestroy: nil, Steps: []resource.TestStep{ { Config: testAccConfigTimeStaticTriggers1("key1", "value1"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - testExtractResourceAttr(resourceName, "rfc3339", &time1), - testSleep(1), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + captureTimeState1, + }, }, { ResourceName: resourceName, @@ -67,29 +76,39 @@ func TestAccTimeStatic_Triggers(t *testing.T) { ImportStateVerifyIgnore: []string{"triggers"}, }, { + // Ensures a time difference when running unit tests in CI + PreConfig: func() { + time.Sleep(time.Duration(1) * time.Second) + }, Config: testAccConfigTimeStaticTriggers1("key1", "value1updated"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "triggers.%", "1"), - resource.TestCheckResourceAttr(resourceName, "triggers.key1", "value1updated"), - resource.TestCheckResourceAttrSet(resourceName, "rfc3339"), - testExtractResourceAttr(resourceName, "rfc3339", &time2), - testCheckAttributeValuesDiffer(&time1, &time2), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1updated")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), + captureTimeState2, + }, }, }, }) + + // Ensure the rfc3339 time value is different due to the sleep + if captureTimeState1.Value == captureTimeState2.Value { + t.Fatal("attribute values are the same") + } } func TestAccTimeStatic_Rfc3339(t *testing.T) { resourceName := "time_static.test" timestamp := time.Now().UTC() - day := strconv.Itoa(timestamp.Day()) - hour := strconv.Itoa(timestamp.Hour()) - minute := strconv.Itoa(timestamp.Minute()) - month := strconv.Itoa(int(timestamp.Month())) - second := strconv.Itoa(timestamp.Second()) - unix := strconv.Itoa(int(timestamp.Unix())) - year := strconv.Itoa(timestamp.Year()) + + rfc3339 := knownvalue.StringExact(timestamp.Format(time.RFC3339)) + year := knownvalue.Int64Exact(int64(timestamp.Year())) + month := knownvalue.Int64Exact(int64(timestamp.Month())) + day := knownvalue.Int64Exact(int64(timestamp.Day())) + hour := knownvalue.Int64Exact(int64(timestamp.Hour())) + minute := knownvalue.Int64Exact(int64(timestamp.Minute())) + second := knownvalue.Int64Exact(int64(timestamp.Second())) + unix := knownvalue.Int64Exact(timestamp.Unix()) resource.UnitTest(t, resource.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -97,16 +116,31 @@ func TestAccTimeStatic_Rfc3339(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConfigTimeStaticRfc3339(timestamp.Format(time.RFC3339)), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "day", day), - resource.TestCheckResourceAttr(resourceName, "hour", hour), - resource.TestCheckResourceAttr(resourceName, "minute", minute), - resource.TestCheckResourceAttr(resourceName, "month", month), - resource.TestCheckResourceAttr(resourceName, "rfc3339", timestamp.Format(time.RFC3339)), - resource.TestCheckResourceAttr(resourceName, "second", second), - resource.TestCheckResourceAttr(resourceName, "unix", unix), - resource.TestCheckResourceAttr(resourceName, "year", year), - ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), year), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), month), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), day), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), hour), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), minute), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), second), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), unix), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), rfc3339), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), rfc3339), + }, + }, + + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), year), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), month), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), day), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), hour), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), minute), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), second), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), unix), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), rfc3339), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("id"), rfc3339), + }, }, { ResourceName: resourceName, @@ -126,16 +160,16 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { { ExternalProviders: providerVersion080(), Config: testAccConfigTimeStatic(), - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "day", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "hour", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "minute", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "month", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "rfc3339", regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`)), - resource.TestMatchResourceAttr(resourceName, "second", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "unix", regexp.MustCompile(`^\d+$`)), - resource.TestMatchResourceAttr(resourceName, "year", regexp.MustCompile(`^\d{4}$`)), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.Int64Between(1, 31)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.Int64Between(0, 23)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.Int64Between(1, 12)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegexp(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.Int64Between(1, math.MaxInt64)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.Int64Between(1, 9999)), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -145,16 +179,16 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { { ExternalProviders: providerVersion080(), Config: testAccConfigTimeStatic(), - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "day", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "hour", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "minute", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "month", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "rfc3339", regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`)), - resource.TestMatchResourceAttr(resourceName, "second", regexp.MustCompile(`^\d{1,2}$`)), - resource.TestMatchResourceAttr(resourceName, "unix", regexp.MustCompile(`^\d+$`)), - resource.TestMatchResourceAttr(resourceName, "year", regexp.MustCompile(`^\d{4}$`)), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.Int64Between(1, 31)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.Int64Between(0, 23)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.Int64Between(1, 12)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegexp(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.Int64Between(0, 59)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.Int64Between(1, math.MaxInt64)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.Int64Between(1, 9999)), + }, }, }, }) diff --git a/internal/timetesting/extract_state_check.go b/internal/timetesting/extract_state_check.go new file mode 100644 index 00000000..a38227c4 --- /dev/null +++ b/internal/timetesting/extract_state_check.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package timetesting + +import ( + "context" + "fmt" + + tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +var _ statecheck.StateCheck = &ExtractState{} + +type ExtractState struct { + resourceAddress string + attributePath tfjsonpath.Path + + // Value contains the string state value after the check has run. + Value *string +} + +func (e *ExtractState) CheckState(ctx context.Context, req statecheck.CheckStateRequest, resp *statecheck.CheckStateResponse) { + var resource *tfjson.StateResource + + if req.State == nil { + resp.Error = fmt.Errorf("state is nil") + + return + } + + if req.State.Values == nil { + resp.Error = fmt.Errorf("state does not contain any state values") + + return + } + + if req.State.Values.RootModule == nil { + resp.Error = fmt.Errorf("state does not contain a root module") + + return + } + + for _, r := range req.State.Values.RootModule.Resources { + if e.resourceAddress == r.Address { + resource = r + + break + } + } + + if resource == nil { + resp.Error = fmt.Errorf("%s - Resource not found in state", e.resourceAddress) + + return + } + + result, err := tfjsonpath.Traverse(resource.AttributeValues, e.attributePath) + + if err != nil { + resp.Error = err + + return + } + + strValue, ok := result.(string) + if !ok { + resp.Error = fmt.Errorf("error checking value for attribute at path: %s.%s, expected a string value, receieved %T", e.resourceAddress, e.attributePath.String(), result) + + return + } + + e.Value = &strValue +} + +// NewExtractState returns a state check that will extract a state value into an accessible string pointer `(*ExtractState).Value`. +func NewExtractState(resourceAddress string, attributePath tfjsonpath.Path) *ExtractState { + return &ExtractState{ + resourceAddress: resourceAddress, + attributePath: attributePath, + } +} diff --git a/internal/timetesting/int64_between_knownvalue.go b/internal/timetesting/int64_between_knownvalue.go new file mode 100644 index 00000000..6cd759f1 --- /dev/null +++ b/internal/timetesting/int64_between_knownvalue.go @@ -0,0 +1,57 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package timetesting + +import ( + "encoding/json" + "fmt" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +var _ knownvalue.Check = int64Between{} + +type int64Between struct { + min int64 + max int64 +} + +// CheckValue determines whether the passed value is of type json.Number, converts that to an int64, and then +// checks if the value is between the min and max int64 values (inclusive). +func (v int64Between) CheckValue(other any) error { + jsonNum, ok := other.(json.Number) + + if !ok { + return fmt.Errorf("expected json.Number value for Int64Between check, got: %T", other) + } + + otherVal, err := jsonNum.Int64() + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Between check: %s", err) + } + + if otherVal < v.min { + return fmt.Errorf("received value: %d, which is less than the minimum value: %d", otherVal, v.min) + } + + if otherVal > v.max { + return fmt.Errorf("received value: %d, which is greater than the maximum value: %d", otherVal, v.max) + } + + return nil +} + +// String returns the string representation of the value. +func (v int64Between) String() string { + return fmt.Sprintf("%d ≤ x ≤ %d", v.min, v.max) +} + +// Int64Between returns a Check for asserting that a value is between the supplied min and max int64 values (inclusive). +func Int64Between(min, max int64) int64Between { + return int64Between{ + min: min, + max: max, + } +} diff --git a/internal/timetesting/int64_between_knownvalue_test.go b/internal/timetesting/int64_between_knownvalue_test.go new file mode 100644 index 00000000..5035438b --- /dev/null +++ b/internal/timetesting/int64_between_knownvalue_test.go @@ -0,0 +1,93 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package timetesting_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" +) + +func TestInt64Between_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.Check + other any + expectedError error + }{ + "zero-other": { + self: timetesting.Int64Between(0, 0), + other: json.Number("0"), // checking against the underlying value field zero-value + }, + "nil": { + self: timetesting.Int64Between(0, 100), + expectedError: fmt.Errorf("expected json.Number value for Int64Between check, got: "), + }, + "wrong-type": { + self: timetesting.Int64Between(0, 100), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as int64 value for Int64Between check: strconv.ParseInt: parsing \"str\": invalid syntax"), + }, + "less-than-min": { + self: timetesting.Int64Between(1, 50), + other: json.Number("0"), + expectedError: fmt.Errorf("received value: 0, which is less than the minimum value: 1"), + }, + "greater-than-max": { + self: timetesting.Int64Between(1, 50), + other: json.Number("51"), + expectedError: fmt.Errorf("received value: 51, which is greater than the maximum value: 50"), + }, + "between": { + self: timetesting.Int64Between(1, 50), + other: json.Number("35"), + }, + "between-equal-to-min": { + self: timetesting.Int64Between(1, 50), + other: json.Number("1"), + }, + "between-equal-to-max": { + self: timetesting.Int64Between(1, 50), + other: json.Number("50"), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestInt64Between_String(t *testing.T) { + t.Parallel() + + got := timetesting.Int64Between(0, 100).String() + + if diff := cmp.Diff(got, `0 ≤ x ≤ 100`); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} + +// equateErrorMessage reports errors to be equal if both are nil +// or both have the same message. +var equateErrorMessage = cmp.Comparer(func(x, y error) bool { + if x == nil || y == nil { + return x == nil && y == nil + } + return x.Error() == y.Error() +})