From 096aaf9edbc0a59a25ef2eb2f734a225a12207b7 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 28 Aug 2023 11:51:13 -0400 Subject: [PATCH] helper/resource: Refactor various unit testing to use inline providers Reference: https://github.com/hashicorp/terraform-plugin-testing/issues/151 This will reduce CI time and dependency on networking/registry calls. --- helper/resource/testing_new_config_test.go | 298 +++++++++++++--- .../resource/testing_new_import_state_test.go | 333 ++++++++++++------ .../testing_new_refresh_state_test.go | 89 ++++- helper/resource/teststep_providers_test.go | 111 ++++-- 4 files changed, 612 insertions(+), 219 deletions(-) diff --git a/helper/resource/testing_new_config_test.go b/helper/resource/testing_new_config_test.go index d6ea46be9..965b357e3 100644 --- a/helper/resource/testing_new_config_test.go +++ b/helper/resource/testing_new_config_test.go @@ -8,24 +8,52 @@ import ( "regexp" "testing" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource" "github.com/hashicorp/terraform-plugin-testing/plancheck" ) func TestTest_TestStep_ExpectError_NewConfig(t *testing.T) { t.Parallel() - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - VersionConstraint: "3.4.3", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Required: true, + }, + }, + }, + }, + }, + ValidateConfigResponse: &resource.ValidateConfigResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Invalid Attribute Value", + Detail: "Diagnostic details", + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 2 - min_upper = 4 + Config: `resource "test_resource" "test" { + id = "invalid-value" }`, ExpectError: regexp.MustCompile(`Error: Invalid Attribute Value`), }, @@ -38,17 +66,43 @@ func Test_ConfigPlanChecks_PreApply_Called(t *testing.T) { spy1 := &planCheckSpy{} spy2 := &planCheckSpy{} - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ spy1, @@ -78,17 +132,43 @@ func Test_ConfigPlanChecks_PreApply_Errors(t *testing.T) { spy3 := &planCheckSpy{ err: errors.New("spy3 check failed"), } - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ spy1, @@ -107,17 +187,43 @@ func Test_ConfigPlanChecks_PostApplyPreRefresh_Called(t *testing.T) { spy1 := &planCheckSpy{} spy2 := &planCheckSpy{} - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PostApplyPreRefresh: []plancheck.PlanCheck{ spy1, @@ -147,17 +253,43 @@ func Test_ConfigPlanChecks_PostApplyPreRefresh_Errors(t *testing.T) { spy3 := &planCheckSpy{ err: errors.New("spy3 check failed"), } - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PostApplyPreRefresh: []plancheck.PlanCheck{ spy1, @@ -176,17 +308,43 @@ func Test_ConfigPlanChecks_PostApplyPostRefresh_Called(t *testing.T) { spy1 := &planCheckSpy{} spy2 := &planCheckSpy{} - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PostApplyPostRefresh: []plancheck.PlanCheck{ spy1, @@ -216,17 +374,43 @@ func Test_ConfigPlanChecks_PostApplyPostRefresh_Errors(t *testing.T) { spy3 := &planCheckSpy{ err: errors.New("spy3 check failed"), } - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, ConfigPlanChecks: ConfigPlanChecks{ PostApplyPostRefresh: []plancheck.PlanCheck{ spy1, diff --git a/helper/resource/testing_new_import_state_test.go b/helper/resource/testing_new_import_state_test.go index f864792ff..fea261cb0 100644 --- a/helper/resource/testing_new_import_state_test.go +++ b/helper/resource/testing_new_import_state_test.go @@ -4,14 +4,17 @@ package resource import ( - "context" "fmt" "regexp" "testing" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/datasource" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" ) @@ -19,50 +22,79 @@ func TestTest_TestStep_ImportStateCheck_SkipDataSourceState(t *testing.T) { t.Parallel() UnitTest(t, TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "examplecloud": func() (*schema.Provider, error) { //nolint:unparam // required signature - return &schema.Provider{ - DataSourcesMap: map[string]*schema.Resource{ - "examplecloud_thing": { - ReadContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - d.SetId("datasource-test") - - return nil - }, - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "examplecloud": providerserver.NewProviderServer(testprovider.Provider{ + DataSources: map[string]testprovider.DataSource{ + "examplecloud_thing": { + ReadResponse: &datasource.ReadResponse{ + State: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "datasource-test"), + }, + ), + }, + SchemaResponse: &datasource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, }, }, }, }, - ResourcesMap: map[string]*schema.Resource{ - "examplecloud_thing": { - CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - d.SetId("resource-test") - - return nil - }, - DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - ReadContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - Schema: map[string]*schema.Schema{ - "id": { - Computed: true, - Type: schema.TypeString, + }, + Resources: map[string]testprovider.Resource{ + "examplecloud_thing": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + }, + ), + }, + ImportStateResponse: &resource.ImportStateResponse{ + State: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, }, - }, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, }, }, }, - }, nil - }, + }, + }), }, Steps: []TestStep{ { @@ -90,41 +122,59 @@ func TestTest_TestStep_ImportStateVerify(t *testing.T) { t.Parallel() UnitTest(t, TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "examplecloud": func() (*schema.Provider, error) { //nolint:unparam // required signature - return &schema.Provider{ - ResourcesMap: map[string]*schema.Resource{ - "examplecloud_thing": { - CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - d.SetId("resource-test") - - return nil - }, - DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - ReadContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - _ = d.Set("other", "testvalue") - - return nil - }, - Schema: map[string]*schema.Schema{ - "other": { - Computed: true, - Type: schema.TypeString, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "examplecloud": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "examplecloud_thing": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "other": tftypes.String, + }, }, - "id": { - Computed: true, - Type: schema.TypeString, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + "other": tftypes.NewValue(tftypes.String, "testvalue"), + }, + ), + }, + ImportStateResponse: &resource.ImportStateResponse{ + State: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "other": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + "other": tftypes.NewValue(tftypes.String, "testvalue"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + { + Name: "other", + Type: tftypes.String, + Computed: true, + }, + }, }, - }, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, }, }, }, - }, nil - }, + }, + }), }, Steps: []TestStep{ { @@ -143,47 +193,68 @@ func TestTest_TestStep_ImportStateVerifyIgnore(t *testing.T) { t.Parallel() UnitTest(t, TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "examplecloud": func() (*schema.Provider, error) { //nolint:unparam // required signature - return &schema.Provider{ - ResourcesMap: map[string]*schema.Resource{ - "examplecloud_thing": { - CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - d.SetId("resource-test") - - _ = d.Set("create_only", "testvalue") - - return nil - }, - DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - ReadContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - _ = d.Set("read_only", "testvalue") - - return nil - }, - Schema: map[string]*schema.Schema{ - "create_only": { - Computed: true, - Type: schema.TypeString, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "examplecloud": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "examplecloud_thing": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "create_only": tftypes.String, + "read_only": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + "create_only": tftypes.NewValue(tftypes.String, "testvalue"), + "read_only": tftypes.NewValue(tftypes.String, "testvalue"), }, - "read_only": { - Computed: true, - Type: schema.TypeString, + ), + }, + ImportStateResponse: &resource.ImportStateResponse{ + State: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "create_only": tftypes.String, + "read_only": tftypes.String, + }, }, - "id": { - Computed: true, - Type: schema.TypeString, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + "create_only": tftypes.NewValue(tftypes.String, nil), // intentional + "read_only": tftypes.NewValue(tftypes.String, "testvalue"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "create_only", + Type: tftypes.String, + Computed: true, + }, + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + { + Name: "read_only", + Type: tftypes.String, + Computed: true, + }, + }, }, - }, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, }, }, }, - }, nil - }, + }, + }), }, Steps: []TestStep{ { @@ -202,20 +273,56 @@ func TestTest_TestStep_ImportStateVerifyIgnore(t *testing.T) { func TestTest_TestStep_ExpectError_ImportState(t *testing.T) { t.Parallel() - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/time", - VersionConstraint: "0.9.1", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "resource-test"), + }, + ), + }, + ImportStateResponse: &resource.ImportStateResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Invalid Import ID", + Detail: "Diagnostic details", + }, + }, + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "time_static" "one" {}`, + Config: `resource "test_resource" "test" {}`, ImportStateId: "invalid time string", - ResourceName: "time_static.one", + ResourceName: "test_resource.test", ImportState: true, - ExpectError: regexp.MustCompile(`Error: Import time static error`), + ExpectError: regexp.MustCompile(`Error: Invalid Import ID`), }, }, }) diff --git a/helper/resource/testing_new_refresh_state_test.go b/helper/resource/testing_new_refresh_state_test.go index f82622a56..5c1000e19 100644 --- a/helper/resource/testing_new_refresh_state_test.go +++ b/helper/resource/testing_new_refresh_state_test.go @@ -8,6 +8,11 @@ import ( "regexp" "testing" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource" "github.com/hashicorp/terraform-plugin-testing/plancheck" ) @@ -16,17 +21,43 @@ func Test_RefreshPlanChecks_PostRefresh_Called(t *testing.T) { spy1 := &planCheckSpy{} spy2 := &planCheckSpy{} - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, }, { RefreshState: true, @@ -59,17 +90,43 @@ func Test_RefreshPlanChecks_PostRefresh_Errors(t *testing.T) { spy3 := &planCheckSpy{ err: errors.New("spy3 check failed"), } - Test(t, TestCase{ - ExternalProviders: map[string]ExternalProvider{ - "random": { - Source: "registry.terraform.io/hashicorp/random", - }, + UnitTest(t, TestCase{ + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), }, Steps: []TestStep{ { - Config: `resource "random_string" "one" { - length = 16 - }`, + Config: `resource "test_resource" "test" {}`, }, { RefreshState: true, diff --git a/helper/resource/teststep_providers_test.go b/helper/resource/teststep_providers_test.go index 8c96ea509..a2b1f5a82 100644 --- a/helper/resource/teststep_providers_test.go +++ b/helper/resource/teststep_providers_test.go @@ -1320,41 +1320,86 @@ func TestTest_TestStep_Taint(t *testing.T) { var idOne, idTwo string - Test(t, TestCase{ - ProviderFactories: map[string]func() (*schema.Provider, error){ - "random": func() (*schema.Provider, error) { //nolint:unparam // required signature - return &schema.Provider{ - ResourcesMap: map[string]*schema.Resource{ - "random_id": { - CreateContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics { - d.SetId(time.Now().String()) - return nil - }, - DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - ReadContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { - return nil - }, - Schema: map[string]*schema.Schema{}, - }, - }, - }, nil - }, - }, + UnitTest(t, TestCase{ Steps: []TestStep{ { - Config: `resource "random_id" "test" {}`, + Config: `resource "test_resource" "test" {}`, Check: ComposeAggregateTestCheckFunc( - extractResourceAttr("random_id.test", "id", &idOne), + extractResourceAttr("test_resource.test", "id", &idOne), ), + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-value1"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), + }, }, { - Taint: []string{"random_id.test"}, - Config: `resource "random_id" "test" {}`, + Taint: []string{"test_resource.test"}, + Config: `resource "test_resource" "test" {}`, Check: ComposeAggregateTestCheckFunc( - extractResourceAttr("random_id.test", "id", &idTwo), + extractResourceAttr("test_resource.test", "id", &idTwo), ), + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "test": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "test_resource": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-value2"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }), + }, }, }, }) @@ -1388,7 +1433,7 @@ func extractResourceAttr(resourceName string, attributeName string, attributeVal func TestTest_TestStep_ProtoV5ProviderFactories(t *testing.T) { t.Parallel() - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty", @@ -1406,7 +1451,7 @@ func TestTest_TestStep_ProtoV5ProviderFactories_Error(t *testing.T) { t.Parallel() plugintest.TestExpectTFatal(t, func() { - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty", @@ -1424,7 +1469,7 @@ func TestTest_TestStep_ProtoV5ProviderFactories_Error(t *testing.T) { func TestTest_TestStep_ProtoV6ProviderFactories(t *testing.T) { t.Parallel() - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty", @@ -1442,7 +1487,7 @@ func TestTest_TestStep_ProtoV6ProviderFactories_Error(t *testing.T) { t.Parallel() plugintest.TestExpectTFatal(t, func() { - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty", @@ -1520,7 +1565,7 @@ func TestTest_TestStep_ProtoV6ProviderFactories_To_ExternalProviders(t *testing. func TestTest_TestStep_ProviderFactories(t *testing.T) { t.Parallel() - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty", @@ -1538,7 +1583,7 @@ func TestTest_TestStep_ProviderFactories_Error(t *testing.T) { t.Parallel() plugintest.TestExpectTFatal(t, func() { - Test(&mockT{}, TestCase{ + UnitTest(&mockT{}, TestCase{ Steps: []TestStep{ { Config: "# not empty",