@@ -5,15 +5,18 @@ import {
55 fetchClusterShardingData ,
66 createShardKey ,
77 type CreateShardKeyData ,
8+ TEST_POLLING_INTERVAL ,
89} from './reducer' ;
910import sinon from 'sinon' ;
1011import type {
1112 AutomationAgentDeploymentStatusApiResponse ,
13+ AutomationAgentProcess ,
1214 ClusterDetailsApiResponse ,
1315 ManagedNamespace ,
1416 ShardZoneMapping ,
1517} from '../services/atlas-global-writes-service' ;
16- import { waitFor } from '@mongodb-js/testing-library-compass' ;
18+ import { wait , waitFor } from '@mongodb-js/testing-library-compass' ;
19+ import Sinon from 'sinon' ;
1720
1821const DB = 'test' ;
1922const COLL = 'coll' ;
@@ -28,22 +31,24 @@ const clusterDetails: ClusterDetailsApiResponse = {
2831 replicationSpecList : [ ] ,
2932} ;
3033
34+ const shardKeyData : CreateShardKeyData = {
35+ customShardKey : 'secondary' ,
36+ isCustomShardKeyHashed : true ,
37+ isShardKeyUnique : true ,
38+ numInitialChunks : 1 ,
39+ presplitHashedZones : true ,
40+ } ;
41+
3142const managedNamespace : ManagedNamespace = {
3243 db : DB ,
3344 collection : COLL ,
34- customShardKey : 'secondary' ,
35- isCustomShardKeyHashed : false ,
36- isShardKeyUnique : false ,
37- numInitialChunks : null ,
38- presplitHashedZones : false ,
45+ ...shardKeyData ,
3946} ;
4047
41- const shardKeyData : CreateShardKeyData = {
42- customShardKey : 'test' ,
43- isCustomShardKeyHashed : true ,
44- isShardKeyUnique : false ,
45- numInitialChunks : 1 ,
46- presplitHashedZones : true ,
48+ const failedShardingProcess : AutomationAgentProcess = {
49+ statusType : 'ERROR' ,
50+ workingOnShort : 'ShardingCollections' ,
51+ errorText : `Failed to shard ${ NS } ` ,
4752} ;
4853
4954function createAuthFetchResponse <
@@ -57,7 +62,81 @@ function createAuthFetchResponse<
5762 } ;
5863}
5964
60- function createStore ( atlasService : any = { } ) : GlobalWritesStore {
65+ function createStore ( {
66+ isNamespaceManaged = ( ) => false ,
67+ hasShardingError = ( ) => false ,
68+ hasShardKey = ( ) => false ,
69+ failsOnShardingRequest = ( ) => false ,
70+ authenticatedFetchStub,
71+ } :
72+ | {
73+ isNamespaceManaged ?: ( ) => boolean ;
74+ hasShardingError ?: ( ) => boolean ;
75+ hasShardKey ?: ( ) => boolean ;
76+ failsOnShardingRequest ?: ( ) => boolean ;
77+ authenticatedFetchStub ?: never ;
78+ }
79+ | {
80+ isNamespaceManaged ?: never ;
81+ hasShardingError ?: never ;
82+ hasShardKey ?: ( ) => boolean ;
83+ failsOnShardingRequest ?: never ;
84+ authenticatedFetchStub ?: ( ) => void ;
85+ } = { } ) : GlobalWritesStore {
86+ const atlasService = {
87+ authenticatedFetch : ( uri : string ) => {
88+ if ( uri . includes ( `/geoSharding` ) && failsOnShardingRequest ( ) ) {
89+ return Promise . reject ( new Error ( 'Failed to shard' ) ) ;
90+ }
91+
92+ if ( uri . includes ( '/clusters/' ) ) {
93+ return createAuthFetchResponse ( {
94+ ...clusterDetails ,
95+ geoSharding : {
96+ ...clusterDetails . geoSharding ,
97+ managedNamespaces : isNamespaceManaged ( ) ? [ managedNamespace ] : [ ] ,
98+ } ,
99+ } ) ;
100+ }
101+
102+ if ( uri . includes ( '/deploymentStatus/' ) ) {
103+ return createAuthFetchResponse ( {
104+ automationStatus : {
105+ processes : hasShardingError ( ) ? [ failedShardingProcess ] : [ ] ,
106+ } ,
107+ } ) ;
108+ }
109+
110+ return createAuthFetchResponse ( { } ) ;
111+ } ,
112+ automationAgentRequest : ( _meta : unknown , type : string ) => ( {
113+ _id : '123' ,
114+ requestType : type ,
115+ } ) ,
116+ automationAgentAwait : ( _meta : unknown , type : string ) => {
117+ if ( type === 'getShardKey' ) {
118+ return {
119+ response : hasShardKey ( )
120+ ? [
121+ {
122+ key : {
123+ location : 'range' ,
124+ secondary : shardKeyData . isCustomShardKeyHashed
125+ ? 'hashed'
126+ : 'range' ,
127+ } ,
128+ unique : true ,
129+ } ,
130+ ]
131+ : [ ] ,
132+ } ;
133+ }
134+ } ,
135+ } as any ;
136+
137+ if ( authenticatedFetchStub )
138+ atlasService . authenticatedFetch = authenticatedFetchStub ;
139+
61140 return setupStore (
62141 {
63142 namespace : NS ,
@@ -76,29 +155,59 @@ describe('GlobalWritesStore Store', function () {
76155 } ) ;
77156
78157 context ( 'scenarios' , function ( ) {
79- it ( 'not managed -> sharding' , async function ( ) {
158+ it ( 'not managed -> sharding -> success' , async function ( ) {
159+ let mockShardKey = false ;
160+ const hasShardKey = Sinon . fake ( ( ) => mockShardKey ) ;
161+ // initial state === unsharded
80162 const store = createStore ( {
81- authenticatedFetch : ( ) => createAuthFetchResponse ( clusterDetails ) ,
163+ hasShardKey ,
82164 } ) ;
83165 await store . dispatch ( fetchClusterShardingData ( ) ) ;
84166 expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
85167 expect ( store . getState ( ) . managedNamespace ) . to . equal ( undefined ) ;
86168
169+ // user requests sharding
87170 const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
88171 expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
89172 await promise ;
90173 expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING' ) ;
174+
175+ // sharding ends with a shardKey
176+ mockShardKey = true ;
177+ await wait ( TEST_POLLING_INTERVAL ) ;
178+ await waitFor ( ( ) => {
179+ expect ( store . getState ( ) . status ) . to . equal ( 'SHARD_KEY_CORRECT' ) ;
180+ } ) ;
91181 } ) ;
92182
93- it ( 'not managed -> failed sharding attempt' , async function ( ) {
183+ it ( 'not managed -> sharding -> sharding error' , async function ( ) {
184+ let mockFailure = false ;
185+ const hasShardingError = Sinon . fake ( ( ) => mockFailure ) ;
186+ // initial state === unsharded
94187 const store = createStore ( {
95- authenticatedFetch : ( uri : string ) => {
96- if ( uri . includes ( '/geoSharding' ) ) {
97- return Promise . reject ( new Error ( 'Failed to shard' ) ) ;
98- }
188+ hasShardingError,
189+ } ) ;
190+ await store . dispatch ( fetchClusterShardingData ( ) ) ;
191+ expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
192+ expect ( store . getState ( ) . managedNamespace ) . to . equal ( undefined ) ;
99193
100- return createAuthFetchResponse ( clusterDetails ) ;
101- } ,
194+ // user requests sharding
195+ const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
196+ expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
197+ await promise ;
198+ expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING' ) ;
199+
200+ // sharding ends with an error
201+ mockFailure = true ;
202+ await wait ( TEST_POLLING_INTERVAL ) ;
203+ await waitFor ( ( ) => {
204+ expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING_ERROR' ) ;
205+ } ) ;
206+ } ) ;
207+
208+ it ( 'not managed -> failed sharding attempt' , async function ( ) {
209+ const store = createStore ( {
210+ failsOnShardingRequest : ( ) => true ,
102211 } ) ;
103212 await store . dispatch ( fetchClusterShardingData ( ) ) ;
104213 expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
@@ -110,48 +219,10 @@ describe('GlobalWritesStore Store', function () {
110219 expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
111220 } ) ;
112221
113- it ( 'when the namespace is managed' , async function ( ) {
222+ it ( 'when the namespace is managed and has a valid shard key ' , async function ( ) {
114223 const store = createStore ( {
115- authenticatedFetch : ( uri : string ) => {
116- if ( uri . includes ( '/clusters/' ) ) {
117- return createAuthFetchResponse ( {
118- ...clusterDetails ,
119- geoSharding : {
120- ...clusterDetails . geoSharding ,
121- managedNamespaces : [ managedNamespace ] ,
122- } ,
123- } ) ;
124- }
125-
126- if ( uri . includes ( '/deploymentStatus/' ) ) {
127- return createAuthFetchResponse ( {
128- automationStatus : {
129- processes : [ ] ,
130- } ,
131- } ) ;
132- }
133-
134- return createAuthFetchResponse ( { } ) ;
135- } ,
136- automationAgentRequest : ( _meta : unknown , type : string ) => ( {
137- _id : '123' ,
138- requestType : type ,
139- } ) ,
140- automationAgentAwait : ( _meta : unknown , type : string ) => {
141- if ( type === 'getShardKey' ) {
142- return {
143- response : [
144- {
145- key : {
146- location : 'HASHED' ,
147- secondary : 'HASHED' ,
148- } ,
149- unique : false ,
150- } ,
151- ] ,
152- } ;
153- }
154- } ,
224+ isNamespaceManaged : ( ) => true ,
225+ hasShardKey : ( ) => true ,
155226 } ) ;
156227 await store . dispatch ( fetchClusterShardingData ( ) ) ;
157228 await waitFor ( ( ) => {
@@ -160,12 +231,24 @@ describe('GlobalWritesStore Store', function () {
160231 } ) ;
161232 } ) ;
162233
234+ it ( 'when the namespace is managed but has a sharding error' , async function ( ) {
235+ const store = createStore ( {
236+ isNamespaceManaged : ( ) => true ,
237+ hasShardingError : ( ) => true ,
238+ } ) ;
239+ await store . dispatch ( fetchClusterShardingData ( ) ) ;
240+ await waitFor ( ( ) => {
241+ expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING_ERROR' ) ;
242+ expect ( store . getState ( ) . managedNamespace ) . to . equal ( managedNamespace ) ;
243+ } ) ;
244+ } ) ;
245+
163246 it ( 'sends correct data to the server when creating a shard key' , async function ( ) {
164247 const alreadyManagedNamespaces = [
165248 {
166249 db : 'test' ,
167250 collection : 'one' ,
168- customShardKey : 'test ' ,
251+ customShardKey : 'secondary ' ,
169252 isCustomShardKeyHashed : true ,
170253 isShardKeyUnique : false ,
171254 numInitialChunks : 1 ,
@@ -196,7 +279,7 @@ describe('GlobalWritesStore Store', function () {
196279 . resolves ( ) ;
197280
198281 const store = createStore ( {
199- authenticatedFetch : fetchStub ,
282+ authenticatedFetchStub : fetchStub ,
200283 } ) ;
201284
202285 await store . dispatch ( createShardKey ( shardKeyData ) ) ;
0 commit comments