diff --git a/internal/service/searchindex/resource_search_index_migration_test.go b/internal/service/searchindex/resource_search_index_migration_test.go index 789962cf41..0cc1138662 100644 --- a/internal/service/searchindex/resource_search_index_migration_test.go +++ b/internal/service/searchindex/resource_search_index_migration_test.go @@ -3,69 +3,13 @@ package searchindex_test import ( "testing" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/mig" ) func TestMigSearchIndex_basic(t *testing.T) { - var ( - clusterInfo = acc.GetClusterInfo(t, nil) - indexName = acc.RandomName() - databaseName = acc.RandomName() - config = configBasic(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr, false) - ) - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { mig.PreCheckBasic(t) }, - CheckDestroy: acc.CheckDestroySearchIndex, - Steps: []resource.TestStep{ - { - Config: config, - ExternalProviders: mig.ExternalProviders(), - Check: resource.ComposeTestCheckFunc( - checkExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", indexName), - resource.TestCheckResourceAttrSet(resourceName, "project_id"), - resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.ClusterName), - resource.TestCheckResourceAttr(resourceName, "database", databaseName), - resource.TestCheckResourceAttr(resourceName, "collection_name", collectionName), - resource.TestCheckResourceAttr(resourceName, "search_analyzer", searchAnalyzer), - resource.TestCheckResourceAttr(resourceName, "type", ""), - ), - }, - mig.TestStepCheckEmptyPlan(config), - }, - }) + mig.CreateAndRunTest(t, basicTestCase(t)) } func TestMigSearchIndex_withVector(t *testing.T) { - var ( - clusterInfo = acc.GetClusterInfo(t, nil) - indexName = acc.RandomName() - databaseName = acc.RandomName() - config = configVector(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr) - ) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { mig.PreCheckBasic(t) }, - CheckDestroy: acc.CheckDestroySearchIndex, - Steps: []resource.TestStep{ - { - Config: config, - ExternalProviders: mig.ExternalProviders(), - Check: resource.ComposeTestCheckFunc( - checkExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", indexName), - resource.TestCheckResourceAttrSet(resourceName, "project_id"), - resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.ClusterName), - resource.TestCheckResourceAttr(resourceName, "database", databaseName), - resource.TestCheckResourceAttr(resourceName, "collection_name", collectionName), - resource.TestCheckResourceAttr(resourceName, "type", "vectorSearch"), - resource.TestCheckResourceAttrSet(resourceName, "fields"), - resource.TestCheckResourceAttrWith(resourceName, "fields", acc.JSONEquals(fieldsJSON)), - ), - }, - mig.TestStepCheckEmptyPlan(config), - }, - }) + mig.CreateAndRunTest(t, basicVectorTestCase(t)) } diff --git a/internal/service/searchindex/resource_search_index_test.go b/internal/service/searchindex/resource_search_index_test.go index c4e41ed532..230c059075 100644 --- a/internal/service/searchindex/resource_search_index_test.go +++ b/internal/service/searchindex/resource_search_index_test.go @@ -12,33 +12,7 @@ import ( ) func TestAccSearchIndex_basic(t *testing.T) { - var ( - clusterInfo = acc.GetClusterInfo(t, nil) - indexName = acc.RandomName() - databaseName = acc.RandomName() - indexType = "" - mappingsDynamic = "true" - ) - checks := commonChecks(indexName, indexType, mappingsDynamic, databaseName, clusterInfo) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.PreCheckBasic(t) }, - ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - CheckDestroy: acc.CheckDestroySearchIndex, - Steps: []resource.TestStep{ - { - Config: configBasic(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr, false), - Check: resource.ComposeTestCheckFunc(checks...), - }, - { - Config: configBasic(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr, false), - ResourceName: resourceName, - ImportStateIdFunc: importStateIDFunc(resourceName), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) + resource.ParallelTest(t, *basicTestCase(t)) } func TestAccSearchIndex_withSearchType(t *testing.T) { @@ -208,8 +182,44 @@ func TestAccSearchIndex_updatedToEmptyMappingsFields(t *testing.T) { } func TestAccSearchIndex_withVector(t *testing.T) { + resource.ParallelTest(t, *basicVectorTestCase(t)) +} + +func basicTestCase(tb testing.TB) *resource.TestCase { + tb.Helper() var ( - clusterInfo = acc.GetClusterInfo(t, nil) + clusterInfo = acc.GetClusterInfo(tb, nil) + indexName = acc.RandomName() + databaseName = acc.RandomName() + indexType = "" + mappingsDynamic = "true" + ) + checks := commonChecks(indexName, indexType, mappingsDynamic, databaseName, clusterInfo) + + return &resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(tb) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: acc.CheckDestroySearchIndex, + Steps: []resource.TestStep{ + { + Config: configBasic(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr, false), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: configBasic(clusterInfo.ProjectIDStr, indexName, databaseName, clusterInfo.ClusterNameStr, clusterInfo.ClusterTerraformStr, false), + ResourceName: resourceName, + ImportStateIdFunc: importStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + } +} + +func basicVectorTestCase(tb testing.TB) *resource.TestCase { + tb.Helper() + var ( + clusterInfo = acc.GetClusterInfo(tb, nil) indexName = acc.RandomName() indexType = "vectorSearch" databaseName = acc.RandomName() @@ -225,8 +235,9 @@ func TestAccSearchIndex_withVector(t *testing.T) { checks = acc.AddAttrSetChecks(resourceName, checks, "project_id") checks = acc.AddAttrSetChecks(datasourceName, checks, "project_id", "index_id") checks = append(checks, resource.TestCheckResourceAttrWith(datasourceName, "fields", acc.JSONEquals(fieldsJSON))) - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.PreCheckBasic(t) }, + + return &resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(tb) }, ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, CheckDestroy: acc.CheckDestroySearchIndex, Steps: []resource.TestStep{ @@ -235,8 +246,9 @@ func TestAccSearchIndex_withVector(t *testing.T) { Check: resource.ComposeTestCheckFunc(checks...), }, }, - }) + } } + func commonChecks(indexName, indexType, mappingsDynamic, databaseName string, clusterInfo acc.ClusterInfo) []resource.TestCheckFunc { attributes := map[string]string{ "name": indexName, diff --git a/internal/testutil/acc/provider.go b/internal/testutil/acc/provider.go index 2abd09551d..948b913e77 100644 --- a/internal/testutil/acc/provider.go +++ b/internal/testutil/acc/provider.go @@ -4,6 +4,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) +const AwsProviderVersion = "5.1.0" + func ExternalProviders(versionAtlasProvider string) map[string]resource.ExternalProvider { return map[string]resource.ExternalProvider{ "mongodbatlas": *providerAtlas(versionAtlasProvider), @@ -32,7 +34,7 @@ func providerAtlas(versionAtlasProvider string) *resource.ExternalProvider { func providerAWS() *resource.ExternalProvider { return &resource.ExternalProvider{ - VersionConstraint: "5.1.0", + VersionConstraint: AwsProviderVersion, Source: "hashicorp/aws", } } diff --git a/internal/testutil/mig/test_case.go b/internal/testutil/mig/test_case.go new file mode 100644 index 0000000000..6d63dcb688 --- /dev/null +++ b/internal/testutil/mig/test_case.go @@ -0,0 +1,71 @@ +package mig + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/stretchr/testify/require" +) + +func CreateAndRunTest(t *testing.T, test *resource.TestCase) { + t.Helper() + resource.ParallelTest(t, CreateTest(t, test)) +} + +func CreateTestAndRunUseExternalProvider(t *testing.T, test *resource.TestCase, externalProviders, additionalProviders map[string]resource.ExternalProvider) { + t.Helper() + resource.ParallelTest(t, CreateTestUseExternalProvider(t, test, externalProviders, additionalProviders)) +} + +// CreateTest returns a new TestCase that reuses step 1 and adds a TestStepCheckEmptyPlan. +// Requires: `MONGODB_ATLAS_LAST_VERSION` to be present. +func CreateTest(t *testing.T, test *resource.TestCase) resource.TestCase { + t.Helper() + validateReusableCase(t, test) + firstStep := test.Steps[0] + steps := []resource.TestStep{ + useExternalProvider(&firstStep, ExternalProviders()), + TestStepCheckEmptyPlan(firstStep.Config), + } + newTest := reuseCase(test, steps) + return newTest +} + +// CreateTestUseExternalProvider returns a new TestCase that reuses step 1 and adds a TestStepCheckEmptyPlan with the additionalProviders. +// Requires: `MONGODB_ATLAS_LAST_VERSION` to be present. +// externalProviders: e.g., ExternalProvidersWithAWS() or ExternalProviders("specific_sem_ver"). +// additionalProviders: e.g., acc.ExternalProvidersOnlyAWS(), can also be nil. +func CreateTestUseExternalProvider(t *testing.T, test *resource.TestCase, externalProviders, additionalProviders map[string]resource.ExternalProvider) resource.TestCase { + t.Helper() + validateReusableCase(t, test) + firstStep := test.Steps[0] + require.NotContains(t, additionalProviders, "mongodbatlas", "Will use the local provider, cannot specify mongodbatlas provider") + emptyPlanStep := TestStepCheckEmptyPlan(firstStep.Config) + steps := []resource.TestStep{ + useExternalProvider(&firstStep, externalProviders), + useExternalProvider(&emptyPlanStep, additionalProviders), + } + return reuseCase(test, steps) +} + +func validateReusableCase(tb testing.TB, test *resource.TestCase) { + tb.Helper() + checkLastVersion(tb) + require.GreaterOrEqual(tb, len(test.Steps), 1, "Must have at least 1 test step.") + require.NotEmpty(tb, test.Steps[0].Config, "First step of migration test must use Config") +} + +func useExternalProvider(step *resource.TestStep, provider map[string]resource.ExternalProvider) resource.TestStep { + step.ExternalProviders = provider + return *step +} + +// Note how we don't set ProtoV6ProviderFactories and instead specify providers on each step. +func reuseCase(test *resource.TestCase, steps []resource.TestStep) resource.TestCase { + return resource.TestCase{ + PreCheck: test.PreCheck, + CheckDestroy: test.CheckDestroy, + ErrorCheck: test.ErrorCheck, + Steps: steps, + } +} diff --git a/internal/testutil/mig/test_case_test.go b/internal/testutil/mig/test_case_test.go new file mode 100644 index 0000000000..1e30407bed --- /dev/null +++ b/internal/testutil/mig/test_case_test.go @@ -0,0 +1,114 @@ +package mig_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/mig" + "github.com/stretchr/testify/assert" +) + +func TestConvertToMigration(t *testing.T) { + t.Setenv("MONGODB_ATLAS_LAST_VERSION", "1.2.3") + var ( + preCheckCalled = false + checkDestroyCalled = false + config = "someTerraformConfig" + ) + preCheck := func() { + preCheckCalled = true + } + firstStep := resource.TestStep{ + Config: config, + Check: resource.TestCheckResourceAttrSet("someTarget", "someAttribute"), + } + + asserter := assert.New(t) + + convertAndCall := func(test resource.TestCase) resource.TestCase { + newTest := mig.CreateTest(t, &test) + newTest.PreCheck() + if newTest.CheckDestroy != nil { + asserter.NoError(newTest.CheckDestroy(nil)) + } + return newTest + } + defaultAssertions := func(test resource.TestCase) { + t.Helper() + asserter.Len(test.Steps, 2, "Expected 2 steps (one extra test step)") + newFirstStep := test.Steps[0] + asserter.Equal(config, newFirstStep.Config) + + planStep := test.Steps[1] + asserter.Equal(mig.TestStepCheckEmptyPlan(config), planStep) + } + + t.Run("normal call with check and destroy", func(t *testing.T) { + checkDestroy := func(*terraform.State) error { + checkDestroyCalled = true + return nil + } + test := convertAndCall(resource.TestCase{ + PreCheck: preCheck, + CheckDestroy: checkDestroy, + Steps: []resource.TestStep{ + firstStep, + }, + }) + asserter.True(preCheckCalled) + asserter.True(checkDestroyCalled) + defaultAssertions(test) + }) + + t.Run("checkDestroy=nil has no panic", func(t *testing.T) { + test := convertAndCall(resource.TestCase{ + PreCheck: preCheck, + Steps: []resource.TestStep{ + firstStep, + }, + }) + defaultAssertions(test) + }) + + t.Run("more than 1 step uses only 1 step", func(t *testing.T) { + test := convertAndCall(resource.TestCase{ + PreCheck: preCheck, + Steps: []resource.TestStep{ + firstStep, + { + Config: "differentConfig", + Check: resource.TestCheckResourceAttrSet("target", "attribute"), + }, + }, + }) + defaultAssertions(test) + }) + // ConvertToMigrationTestUseExternalProvider + + t.Run("explicit ExternalProvider version an no additional providers", func(t *testing.T) { + test := mig.CreateTestUseExternalProvider(t, &resource.TestCase{ + PreCheck: preCheck, + Steps: []resource.TestStep{firstStep}, + }, acc.ExternalProviders("1.2.3"), nil) + asserter.Len(test.Steps, 2, "Expected 2 steps (one extra test step)") + newFirstStep := test.Steps[0] + asserter.Equal(config, newFirstStep.Config) + asserter.Equal("1.2.3", test.Steps[0].ExternalProviders["mongodbatlas"].VersionConstraint) + }) + + t.Run("explicit ExternalProviders and additional providers", func(t *testing.T) { + test := mig.CreateTestUseExternalProvider(t, &resource.TestCase{ + PreCheck: preCheck, + Steps: []resource.TestStep{firstStep}, + }, acc.ExternalProvidersWithAWS("1.2.3"), acc.ExternalProvidersOnlyAWS()) + asserter.Len(test.Steps, 2, "Expected 2 steps (one extra test step)") + newFirstStep := test.Steps[0] + asserter.Equal(config, newFirstStep.Config) + + asserter.Equal("1.2.3", test.Steps[0].ExternalProviders["mongodbatlas"].VersionConstraint) + asserter.Equal(acc.AwsProviderVersion, test.Steps[0].ExternalProviders["aws"].VersionConstraint) + asserter.Equal(acc.AwsProviderVersion, test.Steps[1].ExternalProviders["aws"].VersionConstraint) + }) +}