Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Converting a test case to a migration test #2081

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,15 @@ 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),
},
})
testCase := mig.ConvertToMigrationTest(t, basicTestCase(t))
lantoli marked this conversation as resolved.
Show resolved Hide resolved
resource.ParallelTest(t, testCase)
}

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),
},
})
testCase := mig.ConvertToMigrationTest(t, basicTestCaseVector(t))
resource.ParallelTest(t, testCase)
}
26 changes: 19 additions & 7 deletions internal/service/searchindex/resource_search_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc"
)

func TestAccSearchIndex_basic(t *testing.T) {
func basicTestCase(t *testing.T) *resource.TestCase {
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
t.Helper()
var (
clusterInfo = acc.GetClusterInfo(t, nil)
indexName = acc.RandomName()
Expand All @@ -21,7 +22,7 @@ func TestAccSearchIndex_basic(t *testing.T) {
)
checks := commonChecks(indexName, indexType, mappingsDynamic, databaseName, clusterInfo)

resource.ParallelTest(t, resource.TestCase{
return &resource.TestCase{
PreCheck: func() { acc.PreCheckBasic(t) },
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
CheckDestroy: acc.CheckDestroySearchIndex,
Expand All @@ -38,7 +39,12 @@ func TestAccSearchIndex_basic(t *testing.T) {
ImportStateVerify: true,
},
},
})
}
}

func TestAccSearchIndex_basic(t *testing.T) {
basicCase := basicTestCase(t)
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
resource.ParallelTest(t, *basicCase)
}

func TestAccSearchIndex_withSearchType(t *testing.T) {
Expand Down Expand Up @@ -206,8 +212,8 @@ func TestAccSearchIndex_updatedToEmptyMappingsFields(t *testing.T) {
},
})
}

func TestAccSearchIndex_withVector(t *testing.T) {
func basicTestCaseVector(t *testing.T) *resource.TestCase {
t.Helper()
var (
clusterInfo = acc.GetClusterInfo(t, nil)
indexName = acc.RandomName()
Expand All @@ -225,7 +231,8 @@ 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{

return &resource.TestCase{
PreCheck: func() { acc.PreCheckBasic(t) },
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
CheckDestroy: acc.CheckDestroySearchIndex,
Expand All @@ -235,8 +242,13 @@ func TestAccSearchIndex_withVector(t *testing.T) {
Check: resource.ComposeTestCheckFunc(checks...),
},
},
})
}
}

func TestAccSearchIndex_withVector(t *testing.T) {
resource.ParallelTest(t, *basicTestCaseVector(t))
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
}

func commonChecks(indexName, indexType, mappingsDynamic, databaseName string, clusterInfo acc.ClusterInfo) []resource.TestCheckFunc {
attributes := map[string]string{
"name": indexName,
Expand Down
60 changes: 60 additions & 0 deletions internal/testutil/mig/test_case.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package mig

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/stretchr/testify/require"
)

// ConvertToMigrationTest returns an updated TestCase that reuses step 1 and adds a TestStepCheckEmptyPlan
// Requires: `MONGODB_ATLAS_LAST_VERSION` to be present
func ConvertToMigrationTest(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),
}
return reuseCase(test, steps)
}

// ConvertToMigrationTestUseExternalProvider returns an updated 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 ConvertToMigrationTestUseExternalProvider(t *testing.T, test *resource.TestCase, externalProviders, additionalProviders map[string]resource.ExternalProvider) resource.TestCase {
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
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(t *testing.T, test *resource.TestCase) {
t.Helper()
checkLastVersion(t)
require.GreaterOrEqual(t, len(test.Steps), 1, "Must have at least 1 test step.")
require.NotEmpty(t, 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 {
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
return resource.TestCase{
PreCheck: test.PreCheck,
CheckDestroy: test.CheckDestroy,
ErrorCheck: test.ErrorCheck,
Steps: steps,
}
}
115 changes: 115 additions & 0 deletions internal/testutil/mig/test_case_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
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.ConvertToMigrationTest(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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put both unit test for: ConvertToMigrationTest and ConvertToMigrationTestUseExternalProvider in the same test as they are reusing some internal functions.
However, would love to see suggestions of how to make this test cleaner

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's quite a big test, don't know if some nested tests could be extracted to functions, or if a table-based test would help here


t.Run("explicit ExternalProvider version an no additional providers", func(t *testing.T) {
test := mig.ConvertToMigrationTestUseExternalProvider(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.ConvertToMigrationTestUseExternalProvider(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)
// must be upgraded when the aws provider version is changed
EspenAlbert marked this conversation as resolved.
Show resolved Hide resolved
asserter.Equal("5.1.0", test.Steps[0].ExternalProviders["aws"].VersionConstraint)
asserter.Equal("5.1.0", test.Steps[1].ExternalProviders["aws"].VersionConstraint)
})
}