1919package org .apache .fineract .commands .service ;
2020
2121import static org .mockito .ArgumentMatchers .anyString ;
22- import static org .mockito .ArgumentMatchers .contains ;
23- import static org .mockito .ArgumentMatchers .eq ;
2422import static org .mockito .Mockito .mock ;
2523import static org .mockito .Mockito .never ;
2624import static org .mockito .Mockito .verify ;
@@ -77,31 +75,18 @@ public void testIPKResolveFromRequest() {
7775 }
7876
7977 @ Test
80- void shouldGenerateKeyUsingContextWhenHeaderMissing () {
81- CommandWrapper wrapper = mock (CommandWrapper .class );
82-
83- when (wrapper .getIdempotencyKey ()).thenReturn (null );
84- when (wrapper .getJson ()).thenReturn ("{\" a\" :1}" );
85- when (wrapper .getActionName ()).thenReturn ("action" );
86- when (wrapper .getEntityName ()).thenReturn ("entity" );
87- when (wrapper .getHref ()).thenReturn ("/endpoint" );
88- when (wrapper .getClientId ()).thenReturn (1L );
89- when (wrapper .getEntityId ()).thenReturn (null );
90- when (wrapper .getJobName ()).thenReturn (null );
91-
92- when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("generated-key" );
93-
94- String result = underTest .resolve (wrapper );
95-
96- verify (deterministicIdempotencyKeyGenerator ).generate (eq ("{\" a\" :1}" ), contains ("action:entity:/endpoint:1:" ));
97- Assertions .assertEquals ("generated-key" , result );
98-
78+ public void testIPKResolveFromWrapper () {
79+ String idk = "idk" ;
80+ CommandWrapper wrapper = new CommandWrapper (null , null , null , null , null , null , null , null , null , null , null , null , null , null ,
81+ null , null , null , idk , null , null );
82+ String resolvedIdk = underTest .resolve (wrapper );
83+ Assertions .assertEquals (idk , resolvedIdk );
84+ verifyNoInteractions (deterministicIdempotencyKeyGenerator );
9985 }
10086
10187 @ Test
10288 void shouldUseHeaderIdempotencyKeyWhenPresent () {
10389 CommandWrapper wrapper = mock (CommandWrapper .class );
104-
10590 when (wrapper .getIdempotencyKey ()).thenReturn ("header-key" );
10691
10792 String result = underTest .resolve (wrapper );
@@ -113,22 +98,20 @@ void shouldUseHeaderIdempotencyKeyWhenPresent() {
11398 @ Test
11499 void shouldFallbackToRandomWhenJsonMissing () {
115100 CommandWrapper wrapper = mock (CommandWrapper .class );
116-
117101 when (wrapper .getIdempotencyKey ()).thenReturn (null );
118102 when (wrapper .getJson ()).thenReturn (null );
119103 when (wrapper .getClientId ()).thenReturn (1L );
120104 when (wrapper .getEntityId ()).thenReturn (1L );
121105
122106 String result = underTest .resolve (wrapper );
123107
124- Assertions .assertNotNull ( result );
108+ Assertions .assertEquals ( "random-key" , result );
125109 verifyNoInteractions (deterministicIdempotencyKeyGenerator );
126110 }
127111
128112 @ Test
129113 void shouldFallbackToRandomWhenNoClientAndEntity () {
130114 CommandWrapper wrapper = mock (CommandWrapper .class );
131-
132115 when (wrapper .getIdempotencyKey ()).thenReturn (null );
133116 when (wrapper .getJson ()).thenReturn ("{\" a\" :1}" );
134117 when (wrapper .getClientId ()).thenReturn (null );
@@ -137,14 +120,13 @@ void shouldFallbackToRandomWhenNoClientAndEntity() {
137120
138121 String result = underTest .resolve (wrapper );
139122
140- Assertions .assertNotNull ( result );
123+ Assertions .assertEquals ( "random-key" , result );
141124 verifyNoInteractions (deterministicIdempotencyKeyGenerator );
142125 }
143126
144127 @ Test
145128 void shouldFallbackToRandomForConfigurationsEndpoint () {
146129 CommandWrapper wrapper = mock (CommandWrapper .class );
147-
148130 when (wrapper .getIdempotencyKey ()).thenReturn (null );
149131 when (wrapper .getJson ()).thenReturn ("{\" a\" :1}" );
150132 when (wrapper .getClientId ()).thenReturn (1L );
@@ -153,34 +135,67 @@ void shouldFallbackToRandomForConfigurationsEndpoint() {
153135
154136 String result = underTest .resolve (wrapper );
155137
156- Assertions .assertNotNull ( result );
138+ Assertions .assertEquals ( "random-key" , result );
157139 verifyNoInteractions (deterministicIdempotencyKeyGenerator );
158140 }
159141
160142 @ Test
161- void shouldMarkDeterministicTrueWhenGenerated () {
143+ void shouldFallbackToRandomForJobCommands () {
162144 CommandWrapper wrapper = mock (CommandWrapper .class );
145+ when (wrapper .getIdempotencyKey ()).thenReturn (null );
146+ when (wrapper .getJson ()).thenReturn ("{\" a\" :1}" );
147+ when (wrapper .getClientId ()).thenReturn (null );
148+ when (wrapper .getEntityId ()).thenReturn (null );
149+ when (wrapper .getJobName ()).thenReturn ("LOAN_CLOSE_OF_BUSINESS" );
150+
151+ IdempotencyKeyResolver .ResolvedKey result = underTest .resolveWithMeta (wrapper );
163152
153+ Assertions .assertEquals ("random-key" , result .key ());
154+ Assertions .assertFalse (result .isDeterministic ());
155+ verifyNoInteractions (deterministicIdempotencyKeyGenerator );
156+ }
157+
158+ @ Test
159+ void shouldFallbackToRandomForNonTransferCreate () {
160+ CommandWrapper wrapper = mock (CommandWrapper .class );
161+ when (wrapper .getIdempotencyKey ()).thenReturn (null );
162+ when (wrapper .getJson ()).thenReturn ("{\" name\" :\" Test\" }" );
163+ when (wrapper .getClientId ()).thenReturn (1L );
164+ when (wrapper .getEntityId ()).thenReturn (null );
165+ when (wrapper .getActionName ()).thenReturn ("CREATE" );
166+ when (wrapper .getEntityName ()).thenReturn ("CLIENT" );
167+ when (wrapper .getHref ()).thenReturn ("/clients" );
168+ when (wrapper .getJobName ()).thenReturn (null );
169+
170+ IdempotencyKeyResolver .ResolvedKey result = underTest .resolveWithMeta (wrapper );
171+
172+ Assertions .assertEquals ("random-key" , result .key ());
173+ Assertions .assertFalse (result .isDeterministic ());
174+ verifyNoInteractions (deterministicIdempotencyKeyGenerator );
175+ }
176+
177+ @ Test
178+ void shouldFallbackToRandomForNonCreateOperation () {
179+ CommandWrapper wrapper = mock (CommandWrapper .class );
164180 when (wrapper .getIdempotencyKey ()).thenReturn (null );
165181 when (wrapper .getJson ()).thenReturn ("{\" a\" :1}" );
166182 when (wrapper .getClientId ()).thenReturn (1L );
167183 when (wrapper .getEntityId ()).thenReturn (1L );
168- when (wrapper .getActionName ()).thenReturn ("act" );
169- when (wrapper .getEntityName ()).thenReturn ("ent" );
170- when (wrapper .getHref ()).thenReturn ("/test" );
171-
172- when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("det-key" );
184+ when (wrapper .getActionName ()).thenReturn ("UPDATE" );
185+ when (wrapper .getEntityName ()).thenReturn ("ACCOUNTTRANSFER" );
186+ when (wrapper .getHref ()).thenReturn ("/accounttransfers/1" );
187+ when (wrapper .getJobName ()).thenReturn (null );
173188
174189 IdempotencyKeyResolver .ResolvedKey result = underTest .resolveWithMeta (wrapper );
175190
176- Assertions .assertEquals ("det-key" , result .key ());
177- Assertions .assertTrue (result .isDeterministic ());
191+ Assertions .assertEquals ("random-key" , result .key ());
192+ Assertions .assertFalse (result .isDeterministic ());
193+ verifyNoInteractions (deterministicIdempotencyKeyGenerator );
178194 }
179195
180196 @ Test
181197 void shouldMarkDeterministicFalseForRandomFallback () {
182198 CommandWrapper wrapper = mock (CommandWrapper .class );
183-
184199 when (wrapper .getIdempotencyKey ()).thenReturn (null );
185200 when (wrapper .getJson ()).thenReturn (null );
186201
@@ -190,38 +205,61 @@ void shouldMarkDeterministicFalseForRandomFallback() {
190205 }
191206
192207 @ Test
193- void shouldUseDeterministicKeyWhenJobNamePresentEvenWithoutClientOrEntity () {
208+ void shouldUseDeterministicKeyForAccountTransfer () {
194209 CommandWrapper wrapper = mock (CommandWrapper .class );
195-
196210 when (wrapper .getIdempotencyKey ()).thenReturn (null );
197- when (wrapper .getJson ()).thenReturn ("{\" a \" :1 }" );
198- when (wrapper .getClientId ()).thenReturn (null );
211+ when (wrapper .getJson ()).thenReturn ("{\" fromAccountId \" :\" 1 \" , \" toAccountId \" : \" 2 \" , \" transferAmount \" : \" 500 \" }" );
212+ when (wrapper .getClientId ()).thenReturn (1L );
199213 when (wrapper .getEntityId ()).thenReturn (null );
200- when (wrapper .getJobName ()).thenReturn ("LOAN_CLOSE_OF_BUSINESS" );
201- when (wrapper .getActionName ()).thenReturn ("UPDATE" );
202- when (wrapper .getEntityName ()).thenReturn ("BATCH_BUSINESS_STEP" );
203- when (wrapper .getHref ()).thenReturn ("/jobs/LOAN_CLOSE_OF_BUSINESS/steps" );
204-
205- when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("job-key" );
214+ when (wrapper .getActionName ()).thenReturn ("CREATE" );
215+ when (wrapper .getEntityName ()).thenReturn ("ACCOUNTTRANSFER" );
216+ when (wrapper .getHref ()).thenReturn ("/accounttransfers" );
217+ when (wrapper .getJobName ()).thenReturn (null );
218+ when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("transfer-det-key" );
206219
207220 IdempotencyKeyResolver .ResolvedKey result = underTest .resolveWithMeta (wrapper );
208221
209- Assertions .assertEquals ("job -key" , result .key ());
222+ Assertions .assertEquals ("transfer-det -key" , result .key ());
210223 Assertions .assertTrue (result .isDeterministic ());
211- verify (deterministicIdempotencyKeyGenerator ).generate (anyString (), contains ("LOAN_CLOSE_OF_BUSINESS" ));
212- // Verify the key is stored in context for internal retry reuse
213- Assertions .assertEquals ("job-key" ,
214- fineractRequestContextHolder .getAttribute (SynchronousCommandProcessingService .IDEMPOTENCY_KEY_ATTRIBUTE ));
224+ verify (deterministicIdempotencyKeyGenerator ).generate (anyString (), anyString ());
225+ }
226+
227+ @ Test
228+ void shouldMarkDeterministicTrueForAccountTransfer () {
229+ CommandWrapper wrapper = mock (CommandWrapper .class );
230+ when (wrapper .getIdempotencyKey ()).thenReturn (null );
231+ when (wrapper .getJson ()).thenReturn ("{\" fromAccountId\" :\" 1\" ,\" toAccountId\" :\" 2\" ,\" transferAmount\" :\" 100\" }" );
232+ when (wrapper .getClientId ()).thenReturn (1L );
233+ when (wrapper .getEntityId ()).thenReturn (null );
234+ when (wrapper .getActionName ()).thenReturn ("CREATE" );
235+ when (wrapper .getEntityName ()).thenReturn ("ACCOUNTTRANSFER" );
236+ when (wrapper .getHref ()).thenReturn ("/accounttransfers" );
237+ when (wrapper .getJobName ()).thenReturn (null );
238+ when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("det-key" );
239+
240+ IdempotencyKeyResolver .ResolvedKey result = underTest .resolveWithMeta (wrapper );
215241
242+ Assertions .assertEquals ("det-key" , result .key ());
243+ Assertions .assertTrue (result .isDeterministic ());
216244 }
217245
218246 @ Test
219- public void testIPKResolveFromWrapper () {
220- String idk = "idk" ;
221- CommandWrapper wrapper = new CommandWrapper (null , null , null , null , null , null , null , null , null , null , null , null , null , null ,
222- null , null , null , idk , null , null );
223- String resolvedIdk = underTest .resolve (wrapper );
224- Assertions .assertEquals (idk , resolvedIdk );
225- verifyNoInteractions (deterministicIdempotencyKeyGenerator );
247+ void shouldReturnSameDeterministicKeyForRetryOfSameTransfer () {
248+ CommandWrapper wrapper = mock (CommandWrapper .class );
249+ when (wrapper .getIdempotencyKey ()).thenReturn (null );
250+ when (wrapper .getJson ()).thenReturn ("{\" fromAccountId\" :\" 1\" ,\" toAccountId\" :\" 2\" ,\" transferAmount\" :\" 500\" }" );
251+ when (wrapper .getClientId ()).thenReturn (1L );
252+ when (wrapper .getEntityId ()).thenReturn (null );
253+ when (wrapper .getActionName ()).thenReturn ("CREATE" );
254+ when (wrapper .getEntityName ()).thenReturn ("ACCOUNTTRANSFER" );
255+ when (wrapper .getHref ()).thenReturn ("/accounttransfers" );
256+ when (wrapper .getJobName ()).thenReturn (null );
257+ when (deterministicIdempotencyKeyGenerator .generate (anyString (), anyString ())).thenReturn ("same-key" );
258+
259+ String key1 = underTest .resolve (wrapper );
260+ fineractRequestContextHolder .setAttribute (SynchronousCommandProcessingService .IDEMPOTENCY_KEY_ATTRIBUTE , null );
261+ String key2 = underTest .resolve (wrapper );
262+
263+ Assertions .assertEquals (key1 , key2 );
226264 }
227265}
0 commit comments