From cc777da32d5d655900400b867632697f1b14c01e Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 12:17:40 -0500 Subject: [PATCH 01/13] added plan enhancment for static rfc3339 strings --- internal/provider/resource_time_static.go | 39 ++++++++++++- .../provider/resource_time_static_test.go | 56 +++++++++++++------ 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/internal/provider/resource_time_static.go b/internal/provider/resource_time_static.go index b8c84320..622270d0 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,42 @@ 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 + } + + // We can't enhance the plan unless the rfc3339 attribute is known + 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 +176,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..38751294 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -6,11 +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/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccTimeStatic_basic(t *testing.T) { @@ -83,13 +86,15 @@ func TestAccTimeStatic_Triggers(t *testing.T) { 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 +102,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, From 0e7629df5960ce77affd5c339919d27f6689774a Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 14:59:18 -0500 Subject: [PATCH 02/13] add number regexp for now --- go.mod | 31 ++++--- go.sum | 80 +++++++---------- .../provider/resource_time_static_test.go | 21 ++--- internal/testing/knownvalue/number_regexp.go | 47 ++++++++++ .../testing/knownvalue/number_regexp_test.go | 85 +++++++++++++++++++ 5 files changed, 188 insertions(+), 76 deletions(-) create mode 100644 internal/testing/knownvalue/number_regexp.go create mode 100644 internal/testing/knownvalue/number_regexp_test.go diff --git a/go.mod b/go.mod index 3dc15fa0..f802982f 100644 --- a/go.mod +++ b/go.mod @@ -3,43 +3,43 @@ module github.com/hashicorp/terraform-provider-time go 1.20 require ( + github.com/google/go-cmp v0.6.0 github.com/hashicorp/terraform-plugin-framework v1.5.0 github.com/hashicorp/terraform-plugin-framework-timetypes v0.3.0 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 github.com/hashicorp/terraform-plugin-go v0.21.0 - github.com/hashicorp/terraform-plugin-testing v1.6.0 + github.com/hashicorp/terraform-plugin-testing v1.6.1-0.20240223192018-a3a403807cb6 ) require ( - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/ProtonMail/go-crypto v1.1.0-alpha.0 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/golang/protobuf v1.5.3 // 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 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.6.0 // indirect - github.com/hashicorp/hc-install v0.6.1 // indirect + github.com/hashicorp/hc-install v0.6.3 // indirect github.com/hashicorp/hcl/v2 v2.19.1 // indirect github.com/hashicorp/logutils v1.0.0 // indirect - github.com/hashicorp/terraform-exec v0.19.0 // indirect - github.com/hashicorp/terraform-json v0.18.0 // indirect + github.com/hashicorp/terraform-exec v0.20.0 // indirect + github.com/hashicorp/terraform-json v0.21.0 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect - github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect @@ -49,12 +49,11 @@ require ( github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/zclconf/go-cty v1.14.1 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/sys v0.15.0 // indirect + github.com/zclconf/go-cty v1.14.2 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/go.sum b/go.sum index 5e808d23..9029e36c 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,13 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0= +github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -19,11 +16,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -45,8 +43,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= @@ -56,16 +54,16 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hc-install v0.6.1 h1:IGxShH7AVhPaSuSJpKtVi/EFORNjO+OYVJJrAtGG2mY= -github.com/hashicorp/hc-install v0.6.1/go.mod h1:0fW3jpg+wraYSnFDJ6Rlie3RvLf1bIqVIkzoon4KoVE= +github.com/hashicorp/hc-install v0.6.3 h1:yE/r1yJvWbtrJ0STwScgEnCanb0U9v7zp0Gbkmcoxqs= +github.com/hashicorp/hc-install v0.6.3/go.mod h1:KamGdbodYzlufbWh4r9NRo8y6GLHWZP2GBtdnms1Ln0= github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM= -github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg= -github.com/hashicorp/terraform-json v0.18.0 h1:pCjgJEqqDESv4y0Tzdqfxr/edOIGkjs8keY42xfNBwU= -github.com/hashicorp/terraform-json v0.18.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= +github.com/hashicorp/terraform-exec v0.20.0 h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8JyYF3vpnuEo= +github.com/hashicorp/terraform-exec v0.20.0/go.mod h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw= +github.com/hashicorp/terraform-json v0.21.0 h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRyRNd+zTI05U= +github.com/hashicorp/terraform-json v0.21.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= github.com/hashicorp/terraform-plugin-framework v1.5.0 h1:8kcvqJs/x6QyOFSdeAyEgsenVOUeC/IyKpi2ul4fjTg= github.com/hashicorp/terraform-plugin-framework v1.5.0/go.mod h1:6waavirukIlFpVpthbGd2PUNYaFedB0RwW3MDzJ/rtc= github.com/hashicorp/terraform-plugin-framework-timetypes v0.3.0 h1:egR4InfakWkgepZNUATWGwkrPhaAYOTEybPfEol+G/I= @@ -76,10 +74,10 @@ github.com/hashicorp/terraform-plugin-go v0.21.0 h1:VSjdVQYNDKR0l2pi3vsFK1PdMQrw github.com/hashicorp/terraform-plugin-go v0.21.0/go.mod h1:piJp8UmO1uupCvC9/H74l2C6IyKG0rW4FDedIpwW5RQ= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 h1:X7vB6vn5tON2b49ILa4W7mFAsndeqJ7bZFOGbVO+0Cc= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0/go.mod h1:ydFcxbdj6klCqYEPkPvdvFKiNGKZLUs+896ODUXCyao= -github.com/hashicorp/terraform-plugin-testing v1.6.0 h1:Wsnfh+7XSVRfwcr2jZYHsnLOnZl7UeaOBvsx6dl/608= -github.com/hashicorp/terraform-plugin-testing v1.6.0/go.mod h1:cJGG0/8j9XhHaJZRC+0sXFI4uzqQZ9Az4vh6C4GJpFE= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0 h1:7xdO9aOXVmhvMxNAq8UloyyqW0EEzyAY37llSTHJgjo= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0/go.mod h1:LxQzs7AQl/5JE1IGFd6LX8E4A0InRJ/7s245gOmsejA= +github.com/hashicorp/terraform-plugin-testing v1.6.1-0.20240223192018-a3a403807cb6 h1:cflzyn2cRFCR+OPbjrG13oPRtfPRPN5PcO5JImvW86M= +github.com/hashicorp/terraform-plugin-testing v1.6.1-0.20240223192018-a3a403807cb6/go.mod h1:xAOy259zW/cGnyRnkZhFfnrVwmBwCNOeal0wN3epJ9I= github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= @@ -103,8 +101,9 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= @@ -123,7 +122,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -136,33 +135,24 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= -github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.14.2 h1:kTG7lqmBou0Zkx35r6HJHUQTvaRPr5bIAf3AoHS0izI= +github.com/zclconf/go-cty v1.14.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U= -golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -174,31 +164,21 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index 38751294..b16b5b84 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + time_knownvalue "github.com/hashicorp/terraform-provider-time/internal/testing/knownvalue" ) func TestAccTimeStatic_basic(t *testing.T) { @@ -25,16 +26,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"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + }, }, { ResourceName: resourceName, diff --git a/internal/testing/knownvalue/number_regexp.go b/internal/testing/knownvalue/number_regexp.go new file mode 100644 index 00000000..ee8b70ad --- /dev/null +++ b/internal/testing/knownvalue/number_regexp.go @@ -0,0 +1,47 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "encoding/json" + "fmt" + "regexp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +var _ knownvalue.Check = numberRegularExpression{} + +type numberRegularExpression struct { + regex *regexp.Regexp +} + +// CheckValue determines whether the passed value is of type json.Number, converts that to a string, and then +// checks if it contains a sequence of bytes that match the regular expression supplied to NumberRegularExpression. +func (v numberRegularExpression) CheckValue(other any) error { + otherVal, ok := other.(json.Number) + + if !ok { + return fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: %T", other) + } + + if !v.regex.MatchString(otherVal.String()) { + return fmt.Errorf("expected regex match %s for NumberRegularExpression check, got: %s", v.regex.String(), otherVal) + } + + return nil +} + +// String returns the string representation of the value. +func (v numberRegularExpression) String() string { + return v.regex.String() +} + +// NumberRegularExpression returns a Check for asserting equality between the +// supplied regular expression and a value passed to the CheckValue method. +func NumberRegularExpression(regex *regexp.Regexp) numberRegularExpression { + return numberRegularExpression{ + regex: regex, + } +} diff --git a/internal/testing/knownvalue/number_regexp_test.go b/internal/testing/knownvalue/number_regexp_test.go new file mode 100644 index 00000000..5448787a --- /dev/null +++ b/internal/testing/knownvalue/number_regexp_test.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "encoding/json" + "fmt" + "regexp" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + time_knownvalue "github.com/hashicorp/terraform-provider-time/internal/testing/knownvalue" +) + +func TestNumberRegularExpression_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.Check + other any + expectedError error + }{ + "zero-nil": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("")), + expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), + }, + "zero-other": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("")), + other: json.Number(""), // checking against the underlying value field zero-value + }, + "nil": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), + }, + "wrong-type": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + other: "1.23", + expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: string"), + }, + "not-equal": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + other: json.Number("1.24"), + expectedError: fmt.Errorf("expected regex match 1.23 for NumberRegularExpression check, got: 1.24"), + }, + "equal": { + self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + other: json.Number("1.23"), + }, + } + + 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 TestNumberRegularExpression_String(t *testing.T) { + t.Parallel() + + got := time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`)).String() + + if diff := cmp.Diff(got, `^\d{1,2}$`); 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() +}) From d00f7aa081d7dd7ecb6cdbcd5f2d55e97bbd5c2c Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 15:44:32 -0500 Subject: [PATCH 03/13] add new state checks and replace all of the time static testing --- go.mod | 2 +- .../provider/resource_time_static_test.go | 92 ++++++++++--------- internal/timetesting/extract_state_check.go | 82 +++++++++++++++++ .../number_regexp_knownvalue.go} | 2 +- .../number_regexp_knownvalue_test.go} | 18 ++-- internal/timetesting/sleep_state_check.go | 26 ++++++ 6 files changed, 168 insertions(+), 54 deletions(-) create mode 100644 internal/timetesting/extract_state_check.go rename internal/{testing/knownvalue/number_regexp.go => timetesting/number_regexp_knownvalue.go} (98%) rename internal/{testing/knownvalue/number_regexp_test.go => timetesting/number_regexp_knownvalue_test.go} (72%) create mode 100644 internal/timetesting/sleep_state_check.go diff --git a/go.mod b/go.mod index f802982f..1f9703f1 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/google/go-cmp v0.6.0 + github.com/hashicorp/terraform-json v0.21.0 github.com/hashicorp/terraform-plugin-framework v1.5.0 github.com/hashicorp/terraform-plugin-framework-timetypes v0.3.0 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 @@ -31,7 +32,6 @@ require ( github.com/hashicorp/hcl/v2 v2.19.1 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.20.0 // indirect - github.com/hashicorp/terraform-json v0.21.0 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index b16b5b84..509ec747 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" - time_knownvalue "github.com/hashicorp/terraform-provider-time/internal/testing/knownvalue" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeStatic_basic(t *testing.T) { @@ -27,14 +27,14 @@ func TestAccTimeStatic_basic(t *testing.T) { { Config: testAccConfigTimeStatic(), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), }, }, { @@ -47,22 +47,25 @@ func TestAccTimeStatic_basic(t *testing.T) { } func TestAccTimeStatic_Triggers(t *testing.T) { - var time1, time2 string + resourceName := "time_static.test" + 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, + timetesting.Sleep(2), + }, }, { ResourceName: resourceName, @@ -72,16 +75,19 @@ func TestAccTimeStatic_Triggers(t *testing.T) { }, { 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, + }, }, }, }) + + if captureTimeState1.Value == captureTimeState2.Value { + t.Fatal("attribute values are the same") + } } func TestAccTimeStatic_Rfc3339(t *testing.T) { @@ -147,16 +153,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.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + }, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), @@ -166,16 +172,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.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + }, }, }, }) diff --git a/internal/timetesting/extract_state_check.go b/internal/timetesting/extract_state_check.go new file mode 100644 index 00000000..61555ff6 --- /dev/null +++ b/internal/timetesting/extract_state_check.go @@ -0,0 +1,82 @@ +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 +} + +// CheckState implements the state check logic. +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/testing/knownvalue/number_regexp.go b/internal/timetesting/number_regexp_knownvalue.go similarity index 98% rename from internal/testing/knownvalue/number_regexp.go rename to internal/timetesting/number_regexp_knownvalue.go index ee8b70ad..b06517d4 100644 --- a/internal/testing/knownvalue/number_regexp.go +++ b/internal/timetesting/number_regexp_knownvalue.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package knownvalue +package timetesting import ( "encoding/json" diff --git a/internal/testing/knownvalue/number_regexp_test.go b/internal/timetesting/number_regexp_knownvalue_test.go similarity index 72% rename from internal/testing/knownvalue/number_regexp_test.go rename to internal/timetesting/number_regexp_knownvalue_test.go index 5448787a..dff77eed 100644 --- a/internal/testing/knownvalue/number_regexp_test.go +++ b/internal/timetesting/number_regexp_knownvalue_test.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package knownvalue_test +package timetesting_test import ( "encoding/json" @@ -11,7 +11,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-testing/knownvalue" - time_knownvalue "github.com/hashicorp/terraform-provider-time/internal/testing/knownvalue" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestNumberRegularExpression_CheckValue(t *testing.T) { @@ -23,29 +23,29 @@ func TestNumberRegularExpression_CheckValue(t *testing.T) { expectedError error }{ "zero-nil": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("")), expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), }, "zero-other": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("")), other: json.Number(""), // checking against the underlying value field zero-value }, "nil": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), }, "wrong-type": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), other: "1.23", expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: string"), }, "not-equal": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), other: json.Number("1.24"), expectedError: fmt.Errorf("expected regex match 1.23 for NumberRegularExpression check, got: 1.24"), }, "equal": { - self: time_knownvalue.NumberRegularExpression(regexp.MustCompile("1.23")), + self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), other: json.Number("1.23"), }, } @@ -68,7 +68,7 @@ func TestNumberRegularExpression_CheckValue(t *testing.T) { func TestNumberRegularExpression_String(t *testing.T) { t.Parallel() - got := time_knownvalue.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`)).String() + got := timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`)).String() if diff := cmp.Diff(got, `^\d{1,2}$`); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/timetesting/sleep_state_check.go b/internal/timetesting/sleep_state_check.go new file mode 100644 index 00000000..e15df413 --- /dev/null +++ b/internal/timetesting/sleep_state_check.go @@ -0,0 +1,26 @@ +package timetesting + +import ( + "context" + "time" + + "github.com/hashicorp/terraform-plugin-testing/statecheck" +) + +var _ statecheck.StateCheck = &sleep{} + +type sleep struct { + seconds int +} + +func (s *sleep) CheckState(ctx context.Context, req statecheck.CheckStateRequest, resp *statecheck.CheckStateResponse) { + time.Sleep(time.Duration(s.seconds) * time.Second) +} + +// Sleep returns a state check that sleep for the given number of seconds. +// - Certain testing requires time differences that are too fast for unit testing :) +func Sleep(seconds int) statecheck.StateCheck { + return &sleep{ + seconds: seconds, + } +} From 24d396596927e82aaaefe68ee1ba3db979dc003b Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 16:02:07 -0500 Subject: [PATCH 04/13] update comments --- internal/provider/resource_time_static_test.go | 1 + internal/timetesting/extract_state_check.go | 1 - internal/timetesting/sleep_state_check.go | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index 509ec747..848b855a 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -85,6 +85,7 @@ func TestAccTimeStatic_Triggers(t *testing.T) { }, }) + // Ensure the rfc3339 time value is different due to the sleep if captureTimeState1.Value == captureTimeState2.Value { t.Fatal("attribute values are the same") } diff --git a/internal/timetesting/extract_state_check.go b/internal/timetesting/extract_state_check.go index 61555ff6..f927efe3 100644 --- a/internal/timetesting/extract_state_check.go +++ b/internal/timetesting/extract_state_check.go @@ -19,7 +19,6 @@ type ExtractState struct { Value *string } -// CheckState implements the state check logic. func (e *ExtractState) CheckState(ctx context.Context, req statecheck.CheckStateRequest, resp *statecheck.CheckStateResponse) { var resource *tfjson.StateResource diff --git a/internal/timetesting/sleep_state_check.go b/internal/timetesting/sleep_state_check.go index e15df413..62736a1e 100644 --- a/internal/timetesting/sleep_state_check.go +++ b/internal/timetesting/sleep_state_check.go @@ -17,8 +17,8 @@ func (s *sleep) CheckState(ctx context.Context, req statecheck.CheckStateRequest time.Sleep(time.Duration(s.seconds) * time.Second) } -// Sleep returns a state check that sleep for the given number of seconds. -// - Certain testing requires time differences that are too fast for unit testing :) +// Sleep returns a state check that sleep for the given number of seconds. This state check can be used +// for certain tests that require time differences that are too fast for unit testing. func Sleep(seconds int) statecheck.StateCheck { return &sleep{ seconds: seconds, From 2106a004e1b54092fd48c94776607988caab9db7 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 16:19:43 -0500 Subject: [PATCH 05/13] add license headers --- internal/timetesting/extract_state_check.go | 3 +++ internal/timetesting/sleep_state_check.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/internal/timetesting/extract_state_check.go b/internal/timetesting/extract_state_check.go index f927efe3..a38227c4 100644 --- a/internal/timetesting/extract_state_check.go +++ b/internal/timetesting/extract_state_check.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package timetesting import ( diff --git a/internal/timetesting/sleep_state_check.go b/internal/timetesting/sleep_state_check.go index 62736a1e..b6c5421f 100644 --- a/internal/timetesting/sleep_state_check.go +++ b/internal/timetesting/sleep_state_check.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package timetesting import ( From 2b04347466b6ee620c1f5066cec111b21e84c4aa Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 16:24:41 -0500 Subject: [PATCH 06/13] add changelog --- .changes/unreleased/ENHANCEMENTS-20240223-162424.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/unreleased/ENHANCEMENTS-20240223-162424.yaml 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" From 19bf0bd1a27cc99589f22eff2bf43e88675ce0f3 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 17:09:49 -0500 Subject: [PATCH 07/13] update the remaining tests to fix the lints --- internal/provider/provider_test.go | 63 --- .../provider/resource_time_offset_test.go | 435 +++++++++--------- .../provider/resource_time_rotating_test.go | 338 +++++++------- internal/provider/resource_time_sleep_test.go | 118 +++-- 4 files changed, 460 insertions(+), 494 deletions(-) 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..b6027333 100644 --- a/internal/provider/resource_time_offset_test.go +++ b/internal/provider/resource_time_offset_test.go @@ -6,12 +6,15 @@ 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" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeOffset_Triggers(t *testing.T) { @@ -23,17 +26,17 @@ 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()), + timetesting.Sleep(2), + }, }, { ResourceName: resourceName, @@ -44,16 +47,16 @@ func TestAccTimeOffset_Triggers(t *testing.T) { }, { 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 +74,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 +95,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 +124,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 +145,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 +174,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 +195,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 +224,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 +245,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 +274,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 +295,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 +324,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 +345,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 +374,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 +396,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 +425,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 +446,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..f9b58e7f 100644 --- a/internal/provider/resource_time_rotating_test.go +++ b/internal/provider/resource_time_rotating_test.go @@ -10,7 +10,11 @@ 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" + "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeRotating_Triggers(t *testing.T) { @@ -22,18 +26,18 @@ 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()), + timetesting.Sleep(2), + }, }, { ResourceName: resourceName, @@ -44,17 +48,17 @@ func TestAccTimeRotating_Triggers(t *testing.T) { }, { 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 +74,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 +104,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 +129,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 +159,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 +184,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 +214,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 +239,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 +269,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 +295,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 +326,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 +351,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 +381,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 +406,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 +443,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 +461,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..afc6539b 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,22 @@ func TestResourceTimeSleepDelete(t *testing.T) { } func TestAccTimeSleep_CreateDuration(t *testing.T) { - var time1, time2 string resourceName := "time_sleep.test" + 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 +187,38 @@ 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" + 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 +231,40 @@ 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" + 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 +278,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 +304,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 +317,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()), + }, }, }, }) From 3c5cf6bffa58371123d70da81d5c0d0b63ef3871 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Fri, 23 Feb 2024 17:26:52 -0500 Subject: [PATCH 08/13] grammar --- internal/timetesting/sleep_state_check.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/timetesting/sleep_state_check.go b/internal/timetesting/sleep_state_check.go index b6c5421f..7c99d2e5 100644 --- a/internal/timetesting/sleep_state_check.go +++ b/internal/timetesting/sleep_state_check.go @@ -20,7 +20,7 @@ func (s *sleep) CheckState(ctx context.Context, req statecheck.CheckStateRequest time.Sleep(time.Duration(s.seconds) * time.Second) } -// Sleep returns a state check that sleep for the given number of seconds. This state check can be used +// Sleep returns a state check that sleeps for the given number of seconds. This state check can be used // for certain tests that require time differences that are too fast for unit testing. func Sleep(seconds int) statecheck.StateCheck { return &sleep{ From e78df2ab9364b353a74a1542deae2d5e5b5b101e Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Mon, 26 Feb 2024 07:28:48 -0500 Subject: [PATCH 09/13] move sleep into preconfig --- .../provider/resource_time_offset_test.go | 6 ++-- .../provider/resource_time_rotating_test.go | 6 ++-- .../provider/resource_time_static_test.go | 5 +++- internal/timetesting/sleep_state_check.go | 29 ------------------- 4 files changed, 12 insertions(+), 34 deletions(-) delete mode 100644 internal/timetesting/sleep_state_check.go diff --git a/internal/provider/resource_time_offset_test.go b/internal/provider/resource_time_offset_test.go index b6027333..c3c9e897 100644 --- a/internal/provider/resource_time_offset_test.go +++ b/internal/provider/resource_time_offset_test.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" - "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeOffset_Triggers(t *testing.T) { @@ -35,7 +34,6 @@ func TestAccTimeOffset_Triggers(t *testing.T) { 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()), - timetesting.Sleep(2), }, }, { @@ -46,6 +44,10 @@ 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"), ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), diff --git a/internal/provider/resource_time_rotating_test.go b/internal/provider/resource_time_rotating_test.go index f9b58e7f..cee0b53b 100644 --- a/internal/provider/resource_time_rotating_test.go +++ b/internal/provider/resource_time_rotating_test.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" - "github.com/hashicorp/terraform-provider-time/internal/timetesting" ) func TestAccTimeRotating_Triggers(t *testing.T) { @@ -36,7 +35,6 @@ func TestAccTimeRotating_Triggers(t *testing.T) { 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()), - timetesting.Sleep(2), }, }, { @@ -47,6 +45,10 @@ 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"), ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index 848b855a..d2e4617c 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -64,7 +64,6 @@ func TestAccTimeStatic_Triggers(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers").AtMapKey("key1"), knownvalue.StringExact("value1")), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rfc3339"), knownvalue.NotNull()), captureTimeState1, - timetesting.Sleep(2), }, }, { @@ -74,6 +73,10 @@ 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"), ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("triggers"), knownvalue.MapSizeExact(1)), diff --git a/internal/timetesting/sleep_state_check.go b/internal/timetesting/sleep_state_check.go deleted file mode 100644 index 7c99d2e5..00000000 --- a/internal/timetesting/sleep_state_check.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package timetesting - -import ( - "context" - "time" - - "github.com/hashicorp/terraform-plugin-testing/statecheck" -) - -var _ statecheck.StateCheck = &sleep{} - -type sleep struct { - seconds int -} - -func (s *sleep) CheckState(ctx context.Context, req statecheck.CheckStateRequest, resp *statecheck.CheckStateResponse) { - time.Sleep(time.Duration(s.seconds) * time.Second) -} - -// Sleep returns a state check that sleeps for the given number of seconds. This state check can be used -// for certain tests that require time differences that are too fast for unit testing. -func Sleep(seconds int) statecheck.StateCheck { - return &sleep{ - seconds: seconds, - } -} From 25eed4b1e2b8111a9c0d7b581bf073ea4b4f6c0d Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Mon, 26 Feb 2024 07:50:07 -0500 Subject: [PATCH 10/13] add a better comment --- internal/provider/resource_time_static.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/provider/resource_time_static.go b/internal/provider/resource_time_static.go index 622270d0..abad07c3 100644 --- a/internal/provider/resource_time_static.go +++ b/internal/provider/resource_time_static.go @@ -43,7 +43,18 @@ func (t timeStaticResource) ModifyPlan(ctx context.Context, req resource.ModifyP return } - // We can't enhance the plan unless the rfc3339 attribute is known + // 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 } From d73f9a9168e7dd1554fe1fbe2cb8f4f676405852 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Mon, 26 Feb 2024 08:51:33 -0500 Subject: [PATCH 11/13] remove number regex --- .../provider/resource_time_static_test.go | 43 ++++----- .../timetesting/int64_between_knownvalue.go | 57 ++++++++++++ .../int64_between_knownvalue_test.go | 93 +++++++++++++++++++ .../timetesting/number_regexp_knownvalue.go | 47 ---------- .../number_regexp_knownvalue_test.go | 85 ----------------- 5 files changed, 172 insertions(+), 153 deletions(-) create mode 100644 internal/timetesting/int64_between_knownvalue.go create mode 100644 internal/timetesting/int64_between_knownvalue_test.go delete mode 100644 internal/timetesting/number_regexp_knownvalue.go delete mode 100644 internal/timetesting/number_regexp_knownvalue_test.go diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index d2e4617c..755af726 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -5,6 +5,7 @@ package provider import ( "fmt" + "math" "regexp" "testing" "time" @@ -27,14 +28,14 @@ func TestAccTimeStatic_basic(t *testing.T) { { Config: testAccConfigTimeStatic(), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + 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)), }, }, { @@ -158,14 +159,14 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { ExternalProviders: providerVersion080(), Config: testAccConfigTimeStatic(), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + 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)), }, }, { @@ -177,14 +178,14 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { ExternalProviders: providerVersion080(), Config: testAccConfigTimeStatic(), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("day"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("hour"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("minute"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("month"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), + 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("second"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("unix"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d+$`))), - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("year"), timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{4}$`))), + 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/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() +}) diff --git a/internal/timetesting/number_regexp_knownvalue.go b/internal/timetesting/number_regexp_knownvalue.go deleted file mode 100644 index b06517d4..00000000 --- a/internal/timetesting/number_regexp_knownvalue.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package timetesting - -import ( - "encoding/json" - "fmt" - "regexp" - - "github.com/hashicorp/terraform-plugin-testing/knownvalue" -) - -var _ knownvalue.Check = numberRegularExpression{} - -type numberRegularExpression struct { - regex *regexp.Regexp -} - -// CheckValue determines whether the passed value is of type json.Number, converts that to a string, and then -// checks if it contains a sequence of bytes that match the regular expression supplied to NumberRegularExpression. -func (v numberRegularExpression) CheckValue(other any) error { - otherVal, ok := other.(json.Number) - - if !ok { - return fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: %T", other) - } - - if !v.regex.MatchString(otherVal.String()) { - return fmt.Errorf("expected regex match %s for NumberRegularExpression check, got: %s", v.regex.String(), otherVal) - } - - return nil -} - -// String returns the string representation of the value. -func (v numberRegularExpression) String() string { - return v.regex.String() -} - -// NumberRegularExpression returns a Check for asserting equality between the -// supplied regular expression and a value passed to the CheckValue method. -func NumberRegularExpression(regex *regexp.Regexp) numberRegularExpression { - return numberRegularExpression{ - regex: regex, - } -} diff --git a/internal/timetesting/number_regexp_knownvalue_test.go b/internal/timetesting/number_regexp_knownvalue_test.go deleted file mode 100644 index dff77eed..00000000 --- a/internal/timetesting/number_regexp_knownvalue_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package timetesting_test - -import ( - "encoding/json" - "fmt" - "regexp" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-testing/knownvalue" - "github.com/hashicorp/terraform-provider-time/internal/timetesting" -) - -func TestNumberRegularExpression_CheckValue(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - self knownvalue.Check - other any - expectedError error - }{ - "zero-nil": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("")), - expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), - }, - "zero-other": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("")), - other: json.Number(""), // checking against the underlying value field zero-value - }, - "nil": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), - expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: "), - }, - "wrong-type": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), - other: "1.23", - expectedError: fmt.Errorf("expected json.Number value for NumberRegularExpression check, got: string"), - }, - "not-equal": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), - other: json.Number("1.24"), - expectedError: fmt.Errorf("expected regex match 1.23 for NumberRegularExpression check, got: 1.24"), - }, - "equal": { - self: timetesting.NumberRegularExpression(regexp.MustCompile("1.23")), - other: json.Number("1.23"), - }, - } - - 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 TestNumberRegularExpression_String(t *testing.T) { - t.Parallel() - - got := timetesting.NumberRegularExpression(regexp.MustCompile(`^\d{1,2}$`)).String() - - if diff := cmp.Diff(got, `^\d{1,2}$`); 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() -}) From 6dd30b0afb26fb077629f6b34191600b230c7e19 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Mon, 15 Jul 2024 17:23:09 -0400 Subject: [PATCH 12/13] fix deps --- go.mod | 4 ++-- internal/provider/resource_time_static_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) 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/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index 755af726..707b2d48 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -32,7 +32,7 @@ func TestAccTimeStatic_basic(t *testing.T) { 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + 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)), @@ -163,7 +163,7 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + 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)), @@ -182,7 +182,7 @@ func TestAccTimeStatic_Upgrade(t *testing.T) { 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.StringRegularExpression(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`))), + 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)), From c79753df2e960c112a33f0b221a52574454fd83c Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Tue, 16 Jul 2024 14:14:57 -0400 Subject: [PATCH 13/13] add links to value comparer PR --- internal/provider/resource_time_sleep_test.go | 6 ++++++ internal/provider/resource_time_static_test.go | 2 ++ 2 files changed, 8 insertions(+) diff --git a/internal/provider/resource_time_sleep_test.go b/internal/provider/resource_time_sleep_test.go index afc6539b..02ebb99b 100644 --- a/internal/provider/resource_time_sleep_test.go +++ b/internal/provider/resource_time_sleep_test.go @@ -161,6 +161,8 @@ func TestResourceTimeSleepDelete(t *testing.T) { func TestAccTimeSleep_CreateDuration(t *testing.T) { 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")) @@ -205,6 +207,8 @@ func TestAccTimeSleep_CreateDuration(t *testing.T) { func TestAccTimeSleep_DestroyDuration(t *testing.T) { 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")) @@ -249,6 +253,8 @@ func TestAccTimeSleep_DestroyDuration(t *testing.T) { func TestAccTimeSleep_Triggers(t *testing.T) { 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")) diff --git a/internal/provider/resource_time_static_test.go b/internal/provider/resource_time_static_test.go index 707b2d48..370a3fa8 100644 --- a/internal/provider/resource_time_static_test.go +++ b/internal/provider/resource_time_static_test.go @@ -51,6 +51,8 @@ func TestAccTimeStatic_Triggers(t *testing.T) { 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"))