Skip to content

Commit

Permalink
test: Add unit tests to advanced_cluster (#1809)
Browse files Browse the repository at this point in the history
* add tests for refresh functions of advanced cluster

* use mockery
  • Loading branch information
oarbusi authored Jan 5, 2024
1 parent 5182510 commit 7681b35
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ packages:
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/searchdeployment
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/project
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/advancedcluster
: interfaces:
DeploymentService:
EarService:
GroupProjectService:
ClusterService:
10 changes: 5 additions & 5 deletions internal/service/advancedcluster/common_advanced_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func UpgradeCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cl
stateConf := &retry.StateChangeConf{
Pending: []string{"CREATING", "UPDATING", "REPAIRING"},
Target: []string{"IDLE"},
Refresh: ResourceClusterRefreshFunc(ctx, name, projectID, conn),
Refresh: ResourceClusterRefreshFunc(ctx, name, projectID, ServiceFromClient(conn)),
Timeout: timeout,
MinTimeout: 30 * time.Second,
Delay: 1 * time.Minute,
Expand All @@ -144,9 +144,9 @@ func UpgradeCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cl
return cluster, resp, nil
}

func ResourceClusterRefreshFunc(ctx context.Context, name, projectID string, client *matlas.Client) retry.StateRefreshFunc {
func ResourceClusterRefreshFunc(ctx context.Context, name, projectID string, client ClusterService) retry.StateRefreshFunc {
return func() (any, string, error) {
c, resp, err := client.Clusters.Get(ctx, projectID, name)
c, resp, err := client.Get(ctx, projectID, name)

if err != nil && strings.Contains(err.Error(), "reset by peer") {
return nil, "REPEATING", nil
Expand All @@ -172,9 +172,9 @@ func ResourceClusterRefreshFunc(ctx context.Context, name, projectID string, cli
}
}

func ResourceClusterListAdvancedRefreshFunc(ctx context.Context, projectID string, client *matlas.Client) retry.StateRefreshFunc {
func ResourceClusterListAdvancedRefreshFunc(ctx context.Context, projectID string, client ClusterService) retry.StateRefreshFunc {
return func() (any, string, error) {
clusters, resp, err := client.AdvancedClusters.List(ctx, projectID, nil)
clusters, resp, err := client.List(ctx, projectID, nil)

if err != nil && strings.Contains(err.Error(), "reset by peer") {
return nil, "REPEATING", nil
Expand Down
215 changes: 215 additions & 0 deletions internal/service/advancedcluster/common_advanced_cluster_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
package advancedcluster_test

import (
"context"
"net/http"
"testing"

"github.com/go-test/deep"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/advancedcluster"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/mocksvc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
matlas "go.mongodb.org/atlas/mongodbatlas"
)

var (
dummyClusterName = "clusterName"
dummyProjectID = "projectId"
genericError = matlas.NewArgError("error", "generic")
advancedClusters = []*matlas.AdvancedCluster{{StateName: "NOT IDLE"}}
)

type Result struct {
response any
error error
state string
}

func TestRemoveLabel(t *testing.T) {
toRemove := matlas.Label{Key: "To Remove", Value: "To remove value"}

Expand All @@ -30,3 +48,200 @@ func TestRemoveLabel(t *testing.T) {
t.Fatalf("Bad removeLabel return \n got = %#v\nwant = %#v \ndiff = %#v", got, expected, diff)
}
}

func TestResourceClusterRefreshFunc(t *testing.T) {
testCases := []struct {
mockCluster *matlas.Cluster
mockResponse *matlas.Response
expectedResult Result
mockError error
name string
expectedError bool
}{
{
name: "Error in the API call: reset by peer",
mockError: matlas.NewArgError("error", "reset by peer"),
expectedError: false,
expectedResult: Result{
response: nil,
state: "REPEATING",
error: nil,
},
},
{
name: "Generic error in the API call",
mockError: genericError,
expectedError: true,
expectedResult: Result{
response: nil,
state: "",
error: genericError,
},
},
{
name: "Error in the API call: HTTP 404",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 404}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: "",
state: "DELETED",
error: nil,
},
},
{
name: "Error in the API call: HTTP 503",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 503}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: "",
state: "PENDING",
error: nil,
},
},
{
name: "Error in the API call: Neither HTTP 503 or 404",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 400}, Links: nil, Raw: nil},
expectedError: true,
expectedResult: Result{
response: nil,
state: "",
error: genericError,
},
},
{
name: "Successful",
mockCluster: &matlas.Cluster{StateName: "stateName"},
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 200}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: &matlas.Cluster{StateName: "stateName"},
state: "stateName",
error: nil,
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
testObject := mocksvc.NewClusterService(t)

testObject.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(tc.mockCluster, tc.mockResponse, tc.mockError)

result, stateName, err := advancedcluster.ResourceClusterRefreshFunc(context.Background(), dummyClusterName, dummyProjectID, testObject)()
if (err != nil) != tc.expectedError {
t.Errorf("Case %s: Received unexpected error: %v", tc.name, err)
}

assert.Equal(t, tc.expectedResult.error, err)
assert.Equal(t, tc.expectedResult.response, result)
assert.Equal(t, tc.expectedResult.state, stateName)
})
}
}

func TestResourceListAdvancedRefreshFunc(t *testing.T) {
testCases := []struct {
mockCluster *matlas.AdvancedClustersResponse
mockResponse *matlas.Response
expectedResult Result
mockError error
name string
expectedError bool
}{
{
name: "Error in the API call: reset by peer",
mockError: matlas.NewArgError("error", "reset by peer"),
expectedError: false,
expectedResult: Result{
response: nil,
state: "REPEATING",
error: nil,
},
},
{
name: "Generic error in the API call",
mockError: genericError,
expectedError: true,
expectedResult: Result{
response: nil,
state: "",
error: genericError,
},
},
{
name: "Error in the API call: HTTP 404",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 404}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: "",
state: "DELETED",
error: nil,
},
},
{
name: "Error in the API call: HTTP 503",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 503}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: "",
state: "PENDING",
error: nil,
},
},
{
name: "Error in the API call: Neither HTTP 503 or 404",
mockError: genericError,
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 400}, Links: nil, Raw: nil},
expectedError: true,
expectedResult: Result{
response: nil,
state: "",
error: genericError,
},
},
{
name: "Successful but with at least one cluster not idle",
mockCluster: &matlas.AdvancedClustersResponse{Results: advancedClusters},
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 200}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: advancedClusters[0],
state: "PENDING",
error: nil,
},
},
{
name: "Successful",
mockCluster: &matlas.AdvancedClustersResponse{},
mockResponse: &matlas.Response{Response: &http.Response{StatusCode: 200}, Links: nil, Raw: nil},
expectedError: false,
expectedResult: Result{
response: &matlas.AdvancedClustersResponse{},
state: "IDLE",
error: nil,
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
testObject := mocksvc.NewClusterService(t)

testObject.On("List", mock.Anything, mock.Anything, mock.Anything).Return(tc.mockCluster, tc.mockResponse, tc.mockError)

result, stateName, err := advancedcluster.ResourceClusterListAdvancedRefreshFunc(context.Background(), dummyProjectID, testObject)()
if (err != nil) != tc.expectedError {
t.Errorf("Case %s: Received unexpected error: %v", tc.name, err)
}

assert.Equal(t, tc.expectedResult.error, err)
assert.Equal(t, tc.expectedResult.response, result)
assert.Equal(t, tc.expectedResult.state, stateName)
})
}
}
35 changes: 35 additions & 0 deletions internal/service/advancedcluster/service_advanced_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package advancedcluster

import (
"context"

matlas "go.mongodb.org/atlas/mongodbatlas"
)

type ClusterService interface {
Get(ctx context.Context, groupID, clusterName string) (*matlas.Cluster, *matlas.Response, error)
List(ctx context.Context, groupID string, options *matlas.ListOptions) (*matlas.AdvancedClustersResponse, *matlas.Response, error)
GetAdvancedCluster(ctx context.Context, groupID, clusterName string) (*matlas.AdvancedCluster, *matlas.Response, error)
}

type ClusterServiceFromClient struct {
client *matlas.Client
}

func (a *ClusterServiceFromClient) Get(ctx context.Context, groupID, clusterName string) (*matlas.Cluster, *matlas.Response, error) {
return a.client.Clusters.Get(ctx, groupID, clusterName)
}

func (a *ClusterServiceFromClient) GetAdvancedCluster(ctx context.Context, groupID, clusterName string) (*matlas.AdvancedCluster, *matlas.Response, error) {
return a.client.AdvancedClusters.Get(ctx, groupID, clusterName)
}

func (a *ClusterServiceFromClient) List(ctx context.Context, groupID string, options *matlas.ListOptions) (*matlas.AdvancedClustersResponse, *matlas.Response, error) {
return a.client.AdvancedClusters.List(ctx, groupID, options)
}

func ServiceFromClient(client *matlas.Client) ClusterService {
return &ClusterServiceFromClient{
client: client,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func resourceMongoDBAtlasCloudBackupSnapshotCreate(ctx context.Context, d *schem
stateConf := &retry.StateChangeConf{
Pending: []string{"CREATING", "UPDATING", "REPAIRING", "REPEATING"},
Target: []string{"IDLE"},
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, d.Get("cluster_name").(string), d.Get("project_id").(string), conn),
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, d.Get("cluster_name").(string), d.Get("project_id").(string), advancedcluster.ServiceFromClient(conn)),
Timeout: 10 * time.Minute,
MinTimeout: 10 * time.Second,
Delay: 3 * time.Minute,
Expand Down
6 changes: 3 additions & 3 deletions internal/service/cluster/resource_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ func resourceMongoDBAtlasClusterCreate(ctx context.Context, d *schema.ResourceDa
stateConf := &retry.StateChangeConf{
Pending: []string{"CREATING", "UPDATING", "REPAIRING", "REPEATING", "PENDING"},
Target: []string{"IDLE"},
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, d.Get("name").(string), projectID, conn),
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, d.Get("name").(string), projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: timeout,
MinTimeout: 1 * time.Minute,
Delay: 3 * time.Minute,
Expand Down Expand Up @@ -1001,7 +1001,7 @@ func resourceMongoDBAtlasClusterDelete(ctx context.Context, d *schema.ResourceDa
stateConf := &retry.StateChangeConf{
Pending: []string{"IDLE", "CREATING", "UPDATING", "REPAIRING", "DELETING"},
Target: []string{"DELETED"},
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, clusterName, projectID, conn),
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, clusterName, projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: d.Timeout(schema.TimeoutDelete),
MinTimeout: 30 * time.Second,
Delay: 1 * time.Minute, // Wait 30 secs before starting
Expand Down Expand Up @@ -1375,7 +1375,7 @@ func updateCluster(ctx context.Context, conn *matlas.Client, request *matlas.Clu
stateConf := &retry.StateChangeConf{
Pending: []string{"CREATING", "UPDATING", "REPAIRING"},
Target: []string{"IDLE"},
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, name, projectID, conn),
Refresh: advancedcluster.ResourceClusterRefreshFunc(ctx, name, projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: timeout,
MinTimeout: 30 * time.Second,
Delay: 1 * time.Minute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func resourceMongoDBAtlasPrivateEndpointRegionalModeUpdate(ctx context.Context,
stateConf := &retry.StateChangeConf{
Pending: []string{"REPEATING", "PENDING"},
Target: []string{"IDLE", "DELETED"},
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, conn),
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: d.Timeout(timeoutKey.(string)),
MinTimeout: 5 * time.Second,
Delay: 3 * time.Second,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func resourceMongoDBAtlasPrivateEndpointServiceLinkCreate(ctx context.Context, d
clusterConf := &retry.StateChangeConf{
Pending: []string{"REPEATING", "PENDING"},
Target: []string{"IDLE", "DELETED"},
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, conn),
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: d.Timeout(schema.TimeoutCreate),
MinTimeout: 5 * time.Second,
Delay: 5 * time.Minute,
Expand Down Expand Up @@ -316,7 +316,7 @@ func resourceMongoDBAtlasPrivateEndpointServiceLinkDelete(ctx context.Context, d
clusterConf := &retry.StateChangeConf{
Pending: []string{"REPEATING", "PENDING"},
Target: []string{"IDLE", "DELETED"},
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, conn),
Refresh: advancedcluster.ResourceClusterListAdvancedRefreshFunc(ctx, projectID, advancedcluster.ServiceFromClient(conn)),
Timeout: d.Timeout(schema.TimeoutDelete),
MinTimeout: 5 * time.Second,
Delay: 5 * time.Minute,
Expand Down
Loading

0 comments on commit 7681b35

Please sign in to comment.