11/*
2- * Copyright 2013-2017 the original author or authors.
2+ * Copyright 2013-2020 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1919import java .util .Collections ;
2020import java .util .List ;
2121
22+ import org .bson .Document ;
2223import org .junit .Before ;
2324import org .junit .Test ;
2425import org .mockito .Mock ;
2526import org .mockito .MockitoAnnotations ;
2627
2728import org .springframework .batch .support .transaction .ResourcelessTransactionManager ;
29+ import org .springframework .data .mongodb .core .BulkOperations ;
2830import org .springframework .data .mongodb .core .MongoOperations ;
31+ import org .springframework .data .mongodb .core .convert .MongoConverter ;
32+ import org .springframework .data .mongodb .core .query .Query ;
2933import org .springframework .transaction .PlatformTransactionManager ;
3034import org .springframework .transaction .support .TransactionCallback ;
3135import org .springframework .transaction .support .TransactionTemplate ;
3236
3337import static org .junit .Assert .assertEquals ;
3438import static org .junit .Assert .fail ;
3539import static org .mockito .ArgumentMatchers .any ;
40+ import static org .mockito .ArgumentMatchers .anyString ;
41+ import static org .mockito .Mockito .when ;
3642import static org .mockito .Mockito .doAnswer ;
3743import static org .mockito .Mockito .mock ;
3844import static org .mockito .Mockito .verify ;
45+ import static org .mockito .Mockito .times ;
3946import static org .mockito .Mockito .verifyZeroInteractions ;
4047
48+ /**
49+ * @author Michael Minella
50+ * @author Parikshit Dutta
51+ */
4152@ SuppressWarnings ("serial" )
4253public class MongoItemWriterTests {
4354
4455 private MongoItemWriter <Object > writer ;
4556 @ Mock
4657 private MongoOperations template ;
58+ @ Mock
59+ private BulkOperations bulkOperations ;
60+ @ Mock
61+ private MongoConverter mongoConverter ;
4762 private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager ();
4863
4964 @ Before
5065 public void setUp () throws Exception {
5166 MockitoAnnotations .initMocks (this );
67+ when (template .bulkOps (any (), anyString ())).thenReturn (bulkOperations );
68+ when (template .bulkOps (any (), any (Class .class ))).thenReturn (bulkOperations );
69+ when (template .getConverter ()).thenReturn (mongoConverter );
70+
5271 writer = new MongoItemWriter <>();
5372 writer .setTemplate (template );
5473 writer .afterPropertiesSet ();
@@ -77,8 +96,8 @@ public void testWriteNoTransactionNoCollection() throws Exception {
7796
7897 writer .write (items );
7998
80- verify (template ).save ( items . get ( 0 ));
81- verify (template ). save ( items . get ( 1 ));
99+ verify (template ).bulkOps ( any (), any ( Class . class ));
100+ verify (bulkOperations , times ( 2 )). replaceOne ( any ( Query . class ), any ( Object . class ), any ( ));
82101 }
83102
84103 @ Test
@@ -92,15 +111,16 @@ public void testWriteNoTransactionWithCollection() throws Exception {
92111
93112 writer .write (items );
94113
95- verify (template ).save ( items . get ( 0 ), "collection" );
96- verify (template ). save ( items . get ( 1 ), "collection" );
114+ verify (template ).bulkOps ( any ( ), anyString () );
115+ verify (bulkOperations , times ( 2 )). replaceOne ( any ( Query . class ), any ( Object . class ), any () );
97116 }
98117
99118 @ Test
100119 public void testWriteNoTransactionNoItems () throws Exception {
101120 writer .write (null );
102121
103122 verifyZeroInteractions (template );
123+ verifyZeroInteractions (bulkOperations );
104124 }
105125
106126 @ Test
@@ -120,8 +140,8 @@ public void testWriteTransactionNoCollection() throws Exception {
120140 return null ;
121141 });
122142
123- verify (template ).save ( items . get ( 0 ));
124- verify (template ). save ( items . get ( 1 ));
143+ verify (template ).bulkOps ( any (), any ( Class . class ));
144+ verify (bulkOperations , times ( 2 )). replaceOne ( any ( Query . class ), any ( Object . class ), any ( ));
125145 }
126146
127147 @ Test
@@ -143,8 +163,8 @@ public void testWriteTransactionWithCollection() throws Exception {
143163 return null ;
144164 });
145165
146- verify (template ).save ( items . get ( 0 ), "collection" );
147- verify (template ). save ( items . get ( 1 ), "collection" );
166+ verify (template ).bulkOps ( any ( ), anyString () );
167+ verify (bulkOperations , times ( 2 )). replaceOne ( any ( Query . class ), any ( Object . class ), any () );
148168 }
149169
150170 @ Test
@@ -172,6 +192,7 @@ public void testWriteTransactionFails() throws Exception {
172192 }
173193
174194 verifyZeroInteractions (template );
195+ verifyZeroInteractions (bulkOperations );
175196 }
176197
177198 /**
@@ -203,6 +224,7 @@ public void testWriteTransactionReadOnly() throws Exception {
203224 }
204225
205226 verifyZeroInteractions (template );
227+ verifyZeroInteractions (bulkOperations );
206228 }
207229
208230 @ Test
@@ -234,31 +256,43 @@ public void testRemoveNoTransactionWithCollection() throws Exception {
234256 verify (template ).remove (items .get (0 ), "collection" );
235257 verify (template ).remove (items .get (1 ), "collection" );
236258 }
237-
238- // BATCH-2018
259+
260+ // BATCH-2018, test code updated to pass BATCH-3713
239261 @ Test
240262 public void testResourceKeyCollision () throws Exception {
241263 final int limit = 5000 ;
242264 @ SuppressWarnings ("unchecked" )
243265 List <MongoItemWriter <String >> writers = new ArrayList <>(limit );
266+ final String [] documents = new String [limit ];
244267 final String [] results = new String [limit ];
245268 for (int i = 0 ; i < limit ; i ++) {
246269 final int index = i ;
247270 MongoOperations mongoOperations = mock (MongoOperations .class );
248-
271+ BulkOperations bulkOperations = mock (BulkOperations .class );
272+ MongoConverter mongoConverter = mock (MongoConverter .class );
273+
274+ when (mongoOperations .bulkOps (any (), any (Class .class ))).thenReturn (bulkOperations );
275+ when (mongoOperations .getConverter ()).thenReturn (mongoConverter );
276+
277+ // mocking the object to document conversion which is used in forming bulk operation
278+ doAnswer (invocation -> {
279+ documents [index ] = (String ) invocation .getArguments ()[0 ];
280+ return null ;
281+ }).when (mongoConverter ).write (any (String .class ), any (Document .class ));
282+
249283 doAnswer (invocation -> {
250- String val = (String ) invocation .getArguments ()[0 ];
251284 if (results [index ] == null ) {
252- results [index ] = val ;
285+ results [index ] = documents [ index ] ;
253286 } else {
254- results [index ] += val ;
287+ results [index ] += documents [ index ] ;
255288 }
256289 return null ;
257- }).when (mongoOperations ).save (any (String .class ));
290+ }).when (bulkOperations ).replaceOne (any (Query .class ), any (Document .class ), any ());
291+
258292 writers .add (i , new MongoItemWriter <>());
259293 writers .get (i ).setTemplate (mongoOperations );
260294 }
261-
295+
262296 new TransactionTemplate (transactionManager ).execute ((TransactionCallback <Void >) status -> {
263297 try {
264298 for (int i =0 ; i < limit ; i ++) {
@@ -270,10 +304,9 @@ public void testResourceKeyCollision() throws Exception {
270304 }
271305 return null ;
272306 });
273-
307+
274308 for (int i =0 ; i < limit ; i ++) {
275309 assertEquals (String .valueOf (i ), results [i ]);
276- }
310+ }
277311 }
278-
279312}
0 commit comments