@@ -5,9 +5,15 @@ import {
55 fetchClusterShardingData ,
66 createShardKey ,
77 type CreateShardKeyData ,
8+ type ShardKey ,
89} from './reducer' ;
910import sinon from 'sinon' ;
10- import type { ClusterDetailsApiResponse } from '../services/atlas-global-writes-service' ;
11+ import type {
12+ AutomationAgentDeploymentStatusApiResponse ,
13+ ClusterDetailsApiResponse ,
14+ ManagedNamespace ,
15+ ShardZoneMapping ,
16+ } from '../services/atlas-global-writes-service' ;
1117
1218const DB = 'test' ;
1319const COLL = 'coll' ;
@@ -22,7 +28,30 @@ const clusterDetails: ClusterDetailsApiResponse = {
2228 replicationSpecList : [ ] ,
2329} ;
2430
25- function createClusterDetailsResponse ( data : ClusterDetailsApiResponse ) {
31+ const managedNamespace : ManagedNamespace = {
32+ db : DB ,
33+ collection : COLL ,
34+ customShardKey : 'secondary' ,
35+ isCustomShardKeyHashed : false ,
36+ isShardKeyUnique : false ,
37+ numInitialChunks : null ,
38+ presplitHashedZones : false ,
39+ } ;
40+
41+ const shardKeyData : CreateShardKeyData = {
42+ customShardKey : 'test' ,
43+ isCustomShardKeyHashed : true ,
44+ isShardKeyUnique : false ,
45+ numInitialChunks : 1 ,
46+ presplitHashedZones : true ,
47+ } ;
48+
49+ function createAuthFetchResponse <
50+ TResponse extends
51+ | ClusterDetailsApiResponse
52+ | AutomationAgentDeploymentStatusApiResponse
53+ | Record < string , ShardZoneMapping >
54+ > ( data : TResponse ) {
2655 return {
2756 json : ( ) => Promise . resolve ( data ) ,
2857 } ;
@@ -46,106 +75,139 @@ describe('GlobalWritesStore Store', function () {
4675 expect ( store . getState ( ) . status ) . to . equal ( 'NOT_READY' ) ;
4776 } ) ;
4877
49- context ( 'actions' , function ( ) {
50- context ( 'fetchClusterShardingData' , function ( ) {
51- it ( 'when the namespace is not managed' , async function ( ) {
52- const store = createStore ( {
53- authenticatedFetch : ( ) =>
54- createClusterDetailsResponse ( clusterDetails ) ,
55- } ) ;
56- await store . dispatch ( fetchClusterShardingData ( ) ) ;
57- expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
58- expect ( store . getState ( ) . managedNamespace ) . to . equal ( undefined ) ;
78+ context ( 'scenarios' , function ( ) {
79+ it ( 'not managed -> sharding' , async function ( ) {
80+ const store = createStore ( {
81+ authenticatedFetch : ( ) => createAuthFetchResponse ( clusterDetails ) ,
5982 } ) ;
60-
61- // TODO (COMPASS-8277): Add more test for fetching shard key and process errors
83+ await store . dispatch ( fetchClusterShardingData ( ) ) ;
84+ expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
85+ expect ( store . getState ( ) . managedNamespace ) . to . equal ( undefined ) ;
86+
87+ const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
88+ expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
89+ await promise ;
90+ expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING' ) ;
6291 } ) ;
6392
64- context ( 'createShardKey' , function ( ) {
65- const shardKeyData : CreateShardKeyData = {
66- customShardKey : 'test' ,
67- isCustomShardKeyHashed : true ,
68- isShardKeyUnique : false ,
69- numInitialChunks : 1 ,
70- presplitHashedZones : true ,
71- } ;
72-
73- it ( 'sets SUBMITTING_FOR_SHARDING state when starting to create shard key and sets to SHARDING on success' , async function ( ) {
74- const store = createStore ( {
75- authenticatedFetch : ( ) =>
76- createClusterDetailsResponse ( clusterDetails ) ,
77- } ) ;
78-
79- const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
80- expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
81-
82- await promise ;
83- expect ( store . getState ( ) . status ) . to . equal ( 'SHARDING' ) ;
93+ it ( 'not managed -> failed sharding attempt' , async function ( ) {
94+ const store = createStore ( {
95+ authenticatedFetch : ( uri : string ) => {
96+ if ( uri . includes ( '/geoSharding' ) ) {
97+ return Promise . reject ( new Error ( 'Failed to shard' ) ) ;
98+ }
99+
100+ return createAuthFetchResponse ( clusterDetails ) ;
101+ } ,
84102 } ) ;
103+ await store . dispatch ( fetchClusterShardingData ( ) ) ;
104+ expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
105+ expect ( store . getState ( ) . managedNamespace ) . to . equal ( undefined ) ;
106+
107+ const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
108+ expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
109+ await promise ;
110+ expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
111+ } ) ;
85112
86- it ( 'sets SUBMITTING_FOR_SHARDING state when starting to create shard key and sets to UNSHARDED on failure' , async function ( ) {
87- const store = createStore ( {
88- authenticatedFetch : ( ) => Promise . reject ( new Error ( 'error' ) ) ,
89- } ) ;
113+ it ( 'when the namespace is managed' , async function ( ) {
114+ 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+ } ,
155+ } ) ;
156+ await store . dispatch ( fetchClusterShardingData ( ) ) ;
157+ // expect(store.getState().status).to.equal('SHARD_KEY_CORRECT'); // no idea why this does not work
158+ expect ( store . getState ( ) . managedNamespace ) . to . equal ( managedNamespace ) ;
159+ } ) ;
90160
91- const promise = store . dispatch ( createShardKey ( shardKeyData ) ) ;
92- expect ( store . getState ( ) . status ) . to . equal ( 'SUBMITTING_FOR_SHARDING' ) ;
161+ it ( 'sends correct data to the server when creating a shard key' , async function ( ) {
162+ const alreadyManagedNamespaces = [
163+ {
164+ db : 'test' ,
165+ collection : 'one' ,
166+ customShardKey : 'test' ,
167+ isCustomShardKeyHashed : true ,
168+ isShardKeyUnique : false ,
169+ numInitialChunks : 1 ,
170+ presplitHashedZones : true ,
171+ } ,
172+ ] ;
173+
174+ const getClusterInfoApiResponse = createAuthFetchResponse ( {
175+ ...clusterDetails ,
176+ geoSharding : {
177+ ...clusterDetails . geoSharding ,
178+ managedNamespaces : alreadyManagedNamespaces ,
179+ } ,
180+ } ) ;
93181
94- await promise ;
95- expect ( store . getState ( ) . status ) . to . equal ( 'UNSHARDED' ) ;
182+ // We call cluster API when store is activated to get the initial state.
183+ // When creating a shard key, we call the same API to fetch the latest list of
184+ // managed namespaces & then send it to the server along with the shard key data.
185+ // So, we mock first and second call with same data. And then third call
186+ // should be to create the shard key.
187+ const fetchStub = sinon
188+ . stub ( )
189+ . onFirstCall ( )
190+ . returns ( getClusterInfoApiResponse )
191+ . onSecondCall ( )
192+ . returns ( getClusterInfoApiResponse )
193+ . onThirdCall ( )
194+ . resolves ( ) ;
195+
196+ const store = createStore ( {
197+ authenticatedFetch : fetchStub ,
96198 } ) ;
97199
98- it ( 'sends correct data to the server when creating a shard key' , async function ( ) {
99- const alreadyManagedNamespaces = [
100- {
101- db : 'test' ,
102- collection : 'one' ,
103- customShardKey : 'test' ,
104- isCustomShardKeyHashed : true ,
105- isShardKeyUnique : false ,
106- numInitialChunks : 1 ,
107- presplitHashedZones : true ,
108- } ,
109- ] ;
110-
111- const getClusterInfoApiResponse = createClusterDetailsResponse ( {
112- ...clusterDetails ,
113- geoSharding : {
114- ...clusterDetails . geoSharding ,
115- managedNamespaces : alreadyManagedNamespaces ,
116- } ,
117- } ) ;
118-
119- // We call cluster API when store is activated to get the initial state.
120- // When creating a shard key, we call the same API to fetch the latest list of
121- // managed namespaces & then send it to the server along with the shard key data.
122- // So, we mock first and second call with same data. And then third call
123- // should be to create the shard key.
124- const fetchStub = sinon
125- . stub ( )
126- . onFirstCall ( )
127- . returns ( getClusterInfoApiResponse )
128- . onSecondCall ( )
129- . returns ( getClusterInfoApiResponse )
130- . onThirdCall ( )
131- . resolves ( ) ;
132-
133- const store = createStore ( {
134- authenticatedFetch : fetchStub ,
135- } ) ;
136-
137- await store . dispatch ( createShardKey ( shardKeyData ) ) ;
138-
139- const options = fetchStub . getCall ( 2 ) . args [ 1 ] ;
140- expect ( options . method ) . to . equal ( 'PATCH' ) ;
141- expect ( JSON . parse ( options . body ) ) . to . deep . equal ( {
142- customZoneMapping : { } ,
143- managedNamespaces : [
144- ...alreadyManagedNamespaces ,
145- { ...shardKeyData , db : DB , collection : COLL } ,
146- ] ,
147- selfManagedSharding : false ,
148- } ) ;
200+ await store . dispatch ( createShardKey ( shardKeyData ) ) ;
201+
202+ const options = fetchStub . getCall ( 2 ) . args [ 1 ] ;
203+ expect ( options . method ) . to . equal ( 'PATCH' ) ;
204+ expect ( JSON . parse ( options . body ) ) . to . deep . equal ( {
205+ customZoneMapping : { } ,
206+ managedNamespaces : [
207+ ...alreadyManagedNamespaces ,
208+ { ...shardKeyData , db : DB , collection : COLL } ,
209+ ] ,
210+ selfManagedSharding : false ,
149211 } ) ;
150212 } ) ;
151213 } ) ;
0 commit comments