From d515f8b80534124011bc7e784a90be7c387dedb1 Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:44:18 +0100 Subject: [PATCH 1/6] execution project --- ...ice_data_federation_online_archive_test.go | 2 +- ...ce_data_federation_online_archives_test.go | 2 +- ...ederation_online_archive_migration_test.go | 2 +- ...ice_data_federation_online_archive_test.go | 10 +- internal/testutil/acc/atlas.go | 116 ++++++++++++++++++ internal/testutil/acc/name.go | 17 --- internal/testutil/acc/skip.go | 6 +- 7 files changed, 131 insertions(+), 24 deletions(-) create mode 100644 internal/testutil/acc/atlas.go diff --git a/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archive_test.go b/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archive_test.go index d4e7c705f6..c1f5c70fc1 100644 --- a/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archive_test.go +++ b/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archive_test.go @@ -15,7 +15,7 @@ var ( func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchiveDS_basic(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") customerEndpointDNSName = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_DNS_NAME") ) diff --git a/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archives_test.go b/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archives_test.go index 79ed6d5c94..6c2433308c 100644 --- a/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archives_test.go +++ b/internal/service/privatelinkendpointservicedatafederationonlinearchive/data_source_privatelink_endpoint_service_data_federation_online_archives_test.go @@ -15,7 +15,7 @@ var ( func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchivesDSPlural_basic(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") ) diff --git a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_migration_test.go b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_migration_test.go index 7829bfb736..33616a5427 100644 --- a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_migration_test.go +++ b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_migration_test.go @@ -11,7 +11,7 @@ import ( func TestAccMigrationNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_basic(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") config = resourceConfigBasic(projectID, endpointID, comment) ) diff --git a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go index 1d9c553b61..34ead6fbca 100644 --- a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go +++ b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go @@ -18,9 +18,13 @@ var ( atlasRegion = "US_EAST_1" ) +func TestMain(m *testing.M) { + acc.TestMainExecution(m) +} + func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_basic(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") ) @@ -51,7 +55,7 @@ func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_basic(t } func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_updateComment(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") commentUpdated = "Terraform Acceptance Test Updated" ) @@ -98,7 +102,7 @@ func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_updateC func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_basicWithRegionDnsName(t *testing.T) { var ( - projectID = acc.ProjectIDGlobal(t) + projectID = acc.ProjectIDExecution(t) endpointID = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_ID") customerEndpointDNSName = os.Getenv("MONGODB_ATLAS_PRIVATE_ENDPOINT_DNS_NAME") ) diff --git a/internal/testutil/acc/atlas.go b/internal/testutil/acc/atlas.go new file mode 100644 index 0000000000..545e233c92 --- /dev/null +++ b/internal/testutil/acc/atlas.go @@ -0,0 +1,116 @@ +package acc + +import ( + "context" + "fmt" + "os" + "regexp" + "runtime" + "sync" + "testing" + + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20231115007/admin" +) + +// TestMainExecution must be called from TestMain in the test package if ProjectIDExecution is going to be used. +func TestMainExecution(m *testing.M) { + if !InUnitTest() { + atlasInfo.init = true + atlasInfo.resourceName = resourceName() + } + + exitCode := m.Run() + + if !InUnitTest() && atlasInfo.needsDeletion { + fmt.Printf("Deleting execution project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) + deleteProject(atlasInfo.projectID) + atlasInfo.projectID = "" + atlasInfo.projectName = "" + } + + os.Exit(exitCode) +} + +// ProjectIDExecution returns a project id created for the execution of the resource tests. +func ProjectIDExecution(tb testing.TB) string { + tb.Helper() + SkipInUnitTest(tb) + require.True(tb, atlasInfo.init, "TestMainExecution must called to be able to use ProjectIDExecution") + + atlasInfo.mu.Lock() + defer atlasInfo.mu.Unlock() + + // lazy creation so it's only done if really needed + if atlasInfo.projectName == "" { + var globalName, globalID string + if atlasInfo.resourceName != "" { + globalName = (prefixProjectKeep + "-" + atlasInfo.resourceName)[:projectNameMaxLen] + globalID = projectID(globalName) + } + + if globalID == "" { + atlasInfo.projectName = RandomProjectName() + tb.Logf("Creating execution project: %s, resource: %s, global project (not found): %s\n", atlasInfo.projectName, atlasInfo.resourceName, globalName) + atlasInfo.projectID = createProject(tb, atlasInfo.projectName) + atlasInfo.needsDeletion = true + } else { + atlasInfo.projectName = globalName + tb.Logf("Reusing global project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) + atlasInfo.projectID = globalID + } + } + + return atlasInfo.projectID +} + +var atlasInfo = struct { + projectID string + projectName string + resourceName string + mu sync.Mutex + init bool + needsDeletion bool +}{} + +const ( + projectNameMaxLen = 64 +) + +func resourceName() string { + pc, _, _, ok := runtime.Caller(2) + if !ok { + return "" + } + pattern := `([^/]+)_test\.TestMain$` + re := regexp.MustCompile(pattern) + matches := re.FindStringSubmatch(runtime.FuncForPC(pc).Name()) + if len(matches) <= 1 { + return "" + } + return matches[1] +} + +func createProject(tb testing.TB, name string) string { + tb.Helper() + orgID := os.Getenv("MONGODB_ATLAS_ORG_ID") + require.NotNil(tb, "Project creation failed: %s, org not set", name) + params := &admin.Group{Name: name, OrgId: orgID} + resp, _, err := ConnV2().ProjectsApi.CreateProject(context.Background(), params).Execute() + require.NoError(tb, err, "Project creation failed: %s, err: %s", name, err) + id := resp.GetId() + require.NotEmpty(tb, id, "Project creation failed: %s", name) + return id +} + +func deleteProject(id string) { + _, _, err := ConnV2().ProjectsApi.DeleteProject(context.Background(), id).Execute() + if err != nil { + fmt.Printf("Project deletion failed: %s, error: %s", id, err) + } +} + +func projectID(name string) string { + resp, _, _ := ConnV2().ProjectsApi.GetProjectByName(context.Background(), name).Execute() + return resp.GetId() +} diff --git a/internal/testutil/acc/name.go b/internal/testutil/acc/name.go index e739efd4e1..95054c6e40 100644 --- a/internal/testutil/acc/name.go +++ b/internal/testutil/acc/name.go @@ -1,12 +1,9 @@ package acc import ( - "context" "fmt" - "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/stretchr/testify/require" ) const ( @@ -40,17 +37,3 @@ func RandomIP(a, b, c byte) string { func RandomEmail() string { return fmt.Sprintf("%s-%s@mongodb.com", prefixName, acctest.RandString(10)) } - -func ProjectIDGlobal(tb testing.TB) string { - tb.Helper() - return projectID(tb, prefixProjectKeep+"-global") -} - -func projectID(tb testing.TB, name string) string { - tb.Helper() - SkipInUnitTest(tb) - resp, _, _ := ConnV2().ProjectsApi.GetProjectByName(context.Background(), name).Execute() - id := resp.GetId() - require.NotEmpty(tb, id, "Project name not found: %s", name) - return id -} diff --git a/internal/testutil/acc/skip.go b/internal/testutil/acc/skip.go index 86c413da33..62bd7aea27 100644 --- a/internal/testutil/acc/skip.go +++ b/internal/testutil/acc/skip.go @@ -18,7 +18,11 @@ func SkipTestForCI(tb testing.TB) { // This can be useful for acceptance tests that define logic prior to resource.Test/resource.ParallelTest functions as this code would always be run. func SkipInUnitTest(tb testing.TB) { tb.Helper() - if os.Getenv("TF_ACC") == "" { + if InUnitTest() { tb.Skip() } } + +func InUnitTest() bool { + return os.Getenv("TF_ACC") == "" +} From 68030d6c568e6403181009d3dcbeba860bdef82f Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:38:53 +0100 Subject: [PATCH 2/6] no need to empty these values --- internal/testutil/acc/atlas.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/testutil/acc/atlas.go b/internal/testutil/acc/atlas.go index 545e233c92..45e546a56d 100644 --- a/internal/testutil/acc/atlas.go +++ b/internal/testutil/acc/atlas.go @@ -25,8 +25,6 @@ func TestMainExecution(m *testing.M) { if !InUnitTest() && atlasInfo.needsDeletion { fmt.Printf("Deleting execution project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) deleteProject(atlasInfo.projectID) - atlasInfo.projectID = "" - atlasInfo.projectName = "" } os.Exit(exitCode) From 1d0fe097a34c4eb4e723cce823fd5b12c7c20d5d Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Wed, 13 Mar 2024 03:43:31 +0100 Subject: [PATCH 3/6] simplify TestMainExecution conditions --- internal/testutil/acc/atlas.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/internal/testutil/acc/atlas.go b/internal/testutil/acc/atlas.go index 45e546a56d..c388521290 100644 --- a/internal/testutil/acc/atlas.go +++ b/internal/testutil/acc/atlas.go @@ -15,14 +15,12 @@ import ( // TestMainExecution must be called from TestMain in the test package if ProjectIDExecution is going to be used. func TestMainExecution(m *testing.M) { - if !InUnitTest() { - atlasInfo.init = true - atlasInfo.resourceName = resourceName() - } + atlasInfo.init = true + atlasInfo.resourceName = resourceName() exitCode := m.Run() - if !InUnitTest() && atlasInfo.needsDeletion { + if atlasInfo.needsDeletion { fmt.Printf("Deleting execution project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) deleteProject(atlasInfo.projectID) } From c29b2cee4b5f87016c0d9c93a5e9fe9953f5cfe4 Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:41:14 +0100 Subject: [PATCH 4/6] address feedback --- ...ice_data_federation_online_archive_test.go | 5 +- internal/testutil/acc/atlas.go | 85 ++----------------- internal/testutil/acc/name.go | 6 ++ internal/testutil/acc/shared_resource.go | 46 ++++++++++ 4 files changed, 62 insertions(+), 80 deletions(-) create mode 100644 internal/testutil/acc/shared_resource.go diff --git a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go index 34ead6fbca..ca1457ebcb 100644 --- a/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go +++ b/internal/service/privatelinkendpointservicedatafederationonlinearchive/resource_privatelink_endpoint_service_data_federation_online_archive_test.go @@ -19,7 +19,10 @@ var ( ) func TestMain(m *testing.M) { - acc.TestMainExecution(m) + acc.SetupSharedResources() + exitCode := m.Run() + acc.CleanupSharedResources() + os.Exit(exitCode) } func TestAccNetworkPrivatelinkEndpointServiceDataFederationOnlineArchive_basic(t *testing.T) { diff --git a/internal/testutil/acc/atlas.go b/internal/testutil/acc/atlas.go index c388521290..1024910500 100644 --- a/internal/testutil/acc/atlas.go +++ b/internal/testutil/acc/atlas.go @@ -4,89 +4,12 @@ import ( "context" "fmt" "os" - "regexp" - "runtime" - "sync" "testing" "github.com/stretchr/testify/require" "go.mongodb.org/atlas-sdk/v20231115007/admin" ) -// TestMainExecution must be called from TestMain in the test package if ProjectIDExecution is going to be used. -func TestMainExecution(m *testing.M) { - atlasInfo.init = true - atlasInfo.resourceName = resourceName() - - exitCode := m.Run() - - if atlasInfo.needsDeletion { - fmt.Printf("Deleting execution project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) - deleteProject(atlasInfo.projectID) - } - - os.Exit(exitCode) -} - -// ProjectIDExecution returns a project id created for the execution of the resource tests. -func ProjectIDExecution(tb testing.TB) string { - tb.Helper() - SkipInUnitTest(tb) - require.True(tb, atlasInfo.init, "TestMainExecution must called to be able to use ProjectIDExecution") - - atlasInfo.mu.Lock() - defer atlasInfo.mu.Unlock() - - // lazy creation so it's only done if really needed - if atlasInfo.projectName == "" { - var globalName, globalID string - if atlasInfo.resourceName != "" { - globalName = (prefixProjectKeep + "-" + atlasInfo.resourceName)[:projectNameMaxLen] - globalID = projectID(globalName) - } - - if globalID == "" { - atlasInfo.projectName = RandomProjectName() - tb.Logf("Creating execution project: %s, resource: %s, global project (not found): %s\n", atlasInfo.projectName, atlasInfo.resourceName, globalName) - atlasInfo.projectID = createProject(tb, atlasInfo.projectName) - atlasInfo.needsDeletion = true - } else { - atlasInfo.projectName = globalName - tb.Logf("Reusing global project: %s, resource: %s\n", atlasInfo.projectName, atlasInfo.resourceName) - atlasInfo.projectID = globalID - } - } - - return atlasInfo.projectID -} - -var atlasInfo = struct { - projectID string - projectName string - resourceName string - mu sync.Mutex - init bool - needsDeletion bool -}{} - -const ( - projectNameMaxLen = 64 -) - -func resourceName() string { - pc, _, _, ok := runtime.Caller(2) - if !ok { - return "" - } - pattern := `([^/]+)_test\.TestMain$` - re := regexp.MustCompile(pattern) - matches := re.FindStringSubmatch(runtime.FuncForPC(pc).Name()) - if len(matches) <= 1 { - return "" - } - return matches[1] -} - func createProject(tb testing.TB, name string) string { tb.Helper() orgID := os.Getenv("MONGODB_ATLAS_ORG_ID") @@ -106,7 +29,11 @@ func deleteProject(id string) { } } -func projectID(name string) string { +func projectID(tb testing.TB, name string) string { + tb.Helper() + SkipInUnitTest(tb) resp, _, _ := ConnV2().ProjectsApi.GetProjectByName(context.Background(), name).Execute() - return resp.GetId() + id := resp.GetId() + require.NotEmpty(tb, id, "Project name not found: %s", name) + return id } diff --git a/internal/testutil/acc/name.go b/internal/testutil/acc/name.go index 95054c6e40..36a5d3a71c 100644 --- a/internal/testutil/acc/name.go +++ b/internal/testutil/acc/name.go @@ -2,6 +2,7 @@ package acc import ( "fmt" + "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" ) @@ -37,3 +38,8 @@ func RandomIP(a, b, c byte) string { func RandomEmail() string { return fmt.Sprintf("%s-%s@mongodb.com", prefixName, acctest.RandString(10)) } + +func ProjectIDGlobal(tb testing.TB) string { + tb.Helper() + return projectID(tb, prefixProjectKeep+"-global") +} diff --git a/internal/testutil/acc/shared_resource.go b/internal/testutil/acc/shared_resource.go new file mode 100644 index 0000000000..f008fb22ef --- /dev/null +++ b/internal/testutil/acc/shared_resource.go @@ -0,0 +1,46 @@ +package acc + +import ( + "fmt" + "sync" + "testing" + + "github.com/stretchr/testify/require" +) + +func SetupSharedResources() { + sharedInfo.init = true +} + +func CleanupSharedResources() { + if sharedInfo.projectID != "" { + fmt.Printf("Deleting execution project: %s, id: %s\n", sharedInfo.projectName, sharedInfo.projectID) + deleteProject(sharedInfo.projectID) + } +} + +// ProjectIDExecution returns a project id created for the execution of the tests in the resource package. +func ProjectIDExecution(tb testing.TB) string { + tb.Helper() + SkipInUnitTest(tb) + require.True(tb, sharedInfo.init, "SetupSharedResources must called from TestMain test package") + + sharedInfo.mu.Lock() + defer sharedInfo.mu.Unlock() + + // lazy creation so it's only done if really needed + if sharedInfo.projectID == "" { + sharedInfo.projectName = RandomProjectName() + tb.Logf("Creating execution project: %s, id: %s\n", sharedInfo.projectName, sharedInfo.projectID) + sharedInfo.projectID = createProject(tb, sharedInfo.projectName) + } + + return sharedInfo.projectID +} + +var sharedInfo = struct { + projectID string + projectName string + mu sync.Mutex + init bool +}{} From 1a1f21c1a5947fad9412797b6f093f404efc1bd8 Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:11:24 +0100 Subject: [PATCH 5/6] add comments --- internal/testutil/acc/shared_resource.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/testutil/acc/shared_resource.go b/internal/testutil/acc/shared_resource.go index f008fb22ef..d18edefe1b 100644 --- a/internal/testutil/acc/shared_resource.go +++ b/internal/testutil/acc/shared_resource.go @@ -8,10 +8,12 @@ import ( "github.com/stretchr/testify/require" ) +// SetupSharedResources must be called from TestMain test package in order to use ProjectIDExecution. func SetupSharedResources() { sharedInfo.init = true } +// CleanupSharedResources must be called from TestMain test package in order to use ProjectIDExecution. func CleanupSharedResources() { if sharedInfo.projectID != "" { fmt.Printf("Deleting execution project: %s, id: %s\n", sharedInfo.projectName, sharedInfo.projectID) @@ -31,7 +33,7 @@ func ProjectIDExecution(tb testing.TB) string { // lazy creation so it's only done if really needed if sharedInfo.projectID == "" { sharedInfo.projectName = RandomProjectName() - tb.Logf("Creating execution project: %s, id: %s\n", sharedInfo.projectName, sharedInfo.projectID) + tb.Logf("Creating execution project: %s\n", sharedInfo.projectName) sharedInfo.projectID = createProject(tb, sharedInfo.projectName) } From d6bb0d6592d070639c1735333dd35fbfbb1a3b86 Mon Sep 17 00:00:00 2001 From: Leo Antoli <430982+lantoli@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:52:55 +0100 Subject: [PATCH 6/6] clarify ProjectIDExecution behavior --- internal/testutil/acc/shared_resource.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/testutil/acc/shared_resource.go b/internal/testutil/acc/shared_resource.go index d18edefe1b..21d8005591 100644 --- a/internal/testutil/acc/shared_resource.go +++ b/internal/testutil/acc/shared_resource.go @@ -22,6 +22,7 @@ func CleanupSharedResources() { } // ProjectIDExecution returns a project id created for the execution of the tests in the resource package. +// Even if a GH test group is run, every resource/package will create its own project, not a shared project for all the test group. func ProjectIDExecution(tb testing.TB) string { tb.Helper() SkipInUnitTest(tb)