@@ -24,6 +24,8 @@ import (
2424 "reflect"
2525 "testing"
2626
27+ "github.com/google/go-cmp/cmp"
28+ "github.com/google/go-cmp/cmp/cmpopts"
2729 "github.com/stretchr/testify/assert"
2830 "github.com/stretchr/testify/mock"
2931 "github.com/stretchr/testify/require"
@@ -1422,3 +1424,175 @@ func TestGetProjectFromKube(t *testing.T) {
14221424 })
14231425 }
14241426}
1427+
1428+ func TestChangeDeploymentType (t * testing.T ) {
1429+ tests := map [string ]struct {
1430+ deployment * akov2.AtlasDeployment
1431+ }{
1432+ "should fail when existing cluster is regular but manifest defines a serverless instance" : {
1433+ deployment : & akov2.AtlasDeployment {
1434+ ObjectMeta : metav1.ObjectMeta {
1435+ Name : "cluster0" ,
1436+ Namespace : "default" ,
1437+ },
1438+ Spec : akov2.AtlasDeploymentSpec {
1439+ Project : & common.ResourceRefNamespaced {
1440+ Name : "my-project" ,
1441+ Namespace : "default" ,
1442+ },
1443+ ServerlessSpec : & akov2.ServerlessSpec {
1444+ Name : "cluster0" ,
1445+ ProviderSettings : & akov2.ServerlessProviderSettingsSpec {
1446+ ProviderName : "SERVERLESS" ,
1447+ BackingProviderName : "AWS" ,
1448+ },
1449+ },
1450+ },
1451+ Status : status.AtlasDeploymentStatus {
1452+ StateName : "IDLE" ,
1453+ },
1454+ },
1455+ },
1456+ "should fail when existing cluster is serverless instance but manifest defines a regular deployment" : {
1457+ deployment : & akov2.AtlasDeployment {
1458+ ObjectMeta : metav1.ObjectMeta {
1459+ Name : "cluster0" ,
1460+ Namespace : "default" ,
1461+ },
1462+ Spec : akov2.AtlasDeploymentSpec {
1463+ Project : & common.ResourceRefNamespaced {
1464+ Name : "my-project" ,
1465+ Namespace : "default" ,
1466+ },
1467+ DeploymentSpec : & akov2.AdvancedDeploymentSpec {
1468+ Name : "cluster0" ,
1469+ },
1470+ },
1471+ Status : status.AtlasDeploymentStatus {
1472+ StateName : "IDLE" ,
1473+ },
1474+ },
1475+ },
1476+ }
1477+
1478+ for name , tt := range tests {
1479+ t .Run (name , func (t * testing.T ) {
1480+ secret := & corev1.Secret {
1481+ ObjectMeta : metav1.ObjectMeta {
1482+ Name : "api-secret" ,
1483+ Namespace : "default" ,
1484+ Labels : map [string ]string {
1485+ "atlas.mongodb.com/type" : "credentials" ,
1486+ },
1487+ },
1488+ Data : map [string ][]byte {
1489+ "orgId" : []byte ("1234567890" ),
1490+ "publicApiKey" : []byte ("a1b2c3" ),
1491+ "privateApiKey" : []byte ("abcdef123456" ),
1492+ },
1493+ Type : "Opaque" ,
1494+ }
1495+ project := & akov2.AtlasProject {
1496+ ObjectMeta : metav1.ObjectMeta {
1497+ Name : "my-project" ,
1498+ Namespace : "default" ,
1499+ },
1500+ Spec : akov2.AtlasProjectSpec {
1501+ Name : "MyProject" ,
1502+ ConnectionSecret : & common.ResourceRefNamespaced {
1503+ Name : secret .Name ,
1504+ Namespace : secret .Namespace ,
1505+ },
1506+ },
1507+ Status : status.AtlasProjectStatus {ID : "abc123" },
1508+ }
1509+
1510+ ctx := context .Background ()
1511+ logger := zaptest .NewLogger (t )
1512+
1513+ sch := runtime .NewScheme ()
1514+ require .NoError (t , akov2 .AddToScheme (sch ))
1515+ require .NoError (t , corev1 .AddToScheme (sch ))
1516+ dbUserProjectIndexer := indexer .NewAtlasDatabaseUserByProjectIndexer (ctx , nil , logger )
1517+ k8sClient := fake .NewClientBuilder ().
1518+ WithScheme (sch ).
1519+ WithObjects (secret , project , tt .deployment ).
1520+ WithStatusSubresource (project , tt .deployment ).
1521+ WithIndex (dbUserProjectIndexer .Object (), dbUserProjectIndexer .Name (), dbUserProjectIndexer .Keys ).
1522+ Build ()
1523+
1524+ atlasProvider := & atlasmock.TestProvider {
1525+ IsCloudGovFunc : func () bool {
1526+ return false
1527+ },
1528+ IsSupportedFunc : func () bool {
1529+ return true
1530+ },
1531+ ClientFunc : func (secretRef * client.ObjectKey , log * zap.SugaredLogger ) (* mongodbatlas.Client , string , error ) {
1532+ return & mongodbatlas.Client {}, "org-id" , nil
1533+ },
1534+ SdkClientFunc : func (secretRef * client.ObjectKey , log * zap.SugaredLogger ) (* admin.APIClient , string , error ) {
1535+ clusterAPI := mockadmin .NewClustersApi (t )
1536+ clusterAPI .EXPECT ().GetCluster (ctx , "abc123" , "cluster0" ).
1537+ Return (admin.GetClusterApiRequest {ApiService : clusterAPI })
1538+ clusterAPI .EXPECT ().GetClusterExecute (mock .AnythingOfType ("admin.GetClusterApiRequest" )).
1539+ RunAndReturn (
1540+ func (request admin.GetClusterApiRequest ) (* admin.AdvancedClusterDescription , * http.Response , error ) {
1541+ if ! tt .deployment .IsServerless () {
1542+ err := & admin.GenericOpenAPIError {}
1543+ err .SetModel (admin.ApiError {ErrorCode : pointer .MakePtr (atlas .ServerlessInstanceFromClusterAPI )})
1544+ return nil , nil , err
1545+ }
1546+ return & admin.AdvancedClusterDescription {Name : pointer .MakePtr ("cluster0" )}, nil , nil
1547+ },
1548+ )
1549+
1550+ serverlessAPI := mockadmin .NewServerlessInstancesApi (t )
1551+ if ! tt .deployment .IsServerless () {
1552+ serverlessAPI .EXPECT ().GetServerlessInstance (ctx , "abc123" , "cluster0" ).
1553+ Return (admin.GetServerlessInstanceApiRequest {ApiService : serverlessAPI })
1554+ serverlessAPI .EXPECT ().GetServerlessInstanceExecute (mock .AnythingOfType ("admin.GetServerlessInstanceApiRequest" )).
1555+ Return (& admin.ServerlessInstanceDescription {Name : pointer .MakePtr ("cluster0" )}, nil , nil )
1556+ }
1557+
1558+ return & admin.APIClient {ClustersApi : clusterAPI , ServerlessInstancesApi : serverlessAPI }, "org-id" , nil
1559+ },
1560+ }
1561+
1562+ r := & AtlasDeploymentReconciler {
1563+ Client : k8sClient ,
1564+ AtlasProvider : atlasProvider ,
1565+ Log : logger .Sugar (),
1566+ EventRecorder : record .NewFakeRecorder (1 ),
1567+ }
1568+ result , err := r .Reconcile (
1569+ ctx ,
1570+ ctrl.Request {
1571+ NamespacedName : types.NamespacedName {
1572+ Namespace : tt .deployment .Namespace ,
1573+ Name : tt .deployment .Name ,
1574+ },
1575+ },
1576+ )
1577+
1578+ assert .NoError (t , err )
1579+ assert .Equal (t , ctrl.Result {Requeue : false , RequeueAfter : workflow .DefaultRetry }, result )
1580+ assert .NoError (t , k8sClient .Get (ctx , client .ObjectKeyFromObject (tt .deployment ), tt .deployment ))
1581+ assert .True (
1582+ t ,
1583+ cmp .Equal (
1584+ []api.Condition {
1585+ api .FalseCondition (api .ReadyType ),
1586+ api .TrueCondition (api .ResourceVersionStatus ),
1587+ api .TrueCondition (api .ValidationSucceeded ),
1588+ api .FalseCondition (api .DeploymentReadyType ).
1589+ WithReason (string (workflow .Internal )).
1590+ WithMessageRegexp ("regular deployment cannot be converted into a serverless deployment and vice-versa" ),
1591+ },
1592+ tt .deployment .Status .Conditions ,
1593+ cmpopts .IgnoreFields (api.Condition {}, "LastTransitionTime" ),
1594+ ),
1595+ )
1596+ })
1597+ }
1598+ }
0 commit comments