22
33import java .io .IOException ;
44import java .util .ArrayList ;
5- import java .util .Collection ;
5+ import java .util .Arrays ;
66import java .util .Collections ;
77import java .util .List ;
88import java .util .Map ;
@@ -150,13 +150,12 @@ public void test_sendOneBatch() throws Exception {
150150 Assertions .assertThat (tasks )
151151 .extracting (TaskHandle ::isAcked ).allMatch (CompletableFuture ::isDone );
152152
153- Future <?> results = out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
153+ out .beforeEof (new Event .Results (received , Collections .emptyMap ()));
154154
155155 // Since MockServer runs in the same thread as this test,
156156 // the context will be updated before the last emitEvent returns.
157157 context .close ();
158158
159- results .get (); // Wait until the Results event has been processed.
160159 Assertions .assertThat (tasks ).extracting (TaskHandle ::result )
161160 .allMatch (CompletableFuture ::isDone )
162161 .extracting (CompletableFuture ::get ).extracting (TaskHandle .Result ::error )
@@ -179,18 +178,19 @@ public void test_drainOnClose() throws Exception {
179178 BACKGROUND .submit (() -> {
180179 try {
181180 List <String > received = recvDataAndAck ();
182- Assertions .assertThat (tasks )
183- .extracting (TaskHandle ::id ).containsExactlyInAnyOrderElementsOf (received );
184- Assertions .assertThat (tasks )
185- .extracting (TaskHandle ::isAcked ).allMatch (CompletableFuture ::isDone );
186- out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
181+ Assertions .assertThat (tasks ).extracting (TaskHandle ::id )
182+ .containsExactlyInAnyOrderElementsOf (received );
183+ Assertions .assertThat (tasks ).extracting (TaskHandle ::isAcked )
184+ .allMatch (CompletableFuture ::isDone );
187185 } catch (Exception e ) {
188186 throw new RuntimeException (e );
189187 }
190188 });
191189
190+ List <String > submitted = tasks .stream ().map (TaskHandle ::id ).toList ();
191+ out .beforeEof (new Event .Results (submitted , Collections .emptyMap ()));
192+
192193 context .close ();
193- awaitResults (tasks );
194194
195195 Assertions .assertThat (tasks ).extracting (TaskHandle ::result )
196196 .allMatch (CompletableFuture ::isDone )
@@ -220,15 +220,15 @@ public void test_backoff() throws Exception {
220220 // set by the Backoff message, i.e. BATCH_SIZE / 2.
221221 List <String > received = recvDataAndAck ();
222222 Assertions .assertThat (received ).hasSize (BATCH_SIZE / 2 );
223- out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
223+ out .beforeEof (new Event .Results (received , Collections .emptyMap ()));
224224
225225 backgroundAdd .get (); // Finish populating batch context.
226226
227227 // Since testUser will try and add BATCH_SIZE no. objects,
228228 // we should expect there to be exactly 2 batches.
229229 received = recvDataAndAck ();
230230 Assertions .assertThat (received ).hasSize (BATCH_SIZE / 2 );
231- out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
231+ out .beforeEof (new Event .Results (received , Collections .emptyMap ()));
232232
233233 context .close ();
234234
@@ -262,20 +262,13 @@ public void test_backoffBacklog() throws Exception {
262262 tasks .add (context .add (WeaviateObject .of ()));
263263
264264 Assertions .assertThat (received = recvDataAndAck ()).hasSize (batchSizeNew );
265- out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
265+ out .beforeEof (new Event .Results (received , Collections .emptyMap ()));
266266
267267 Assertions .assertThat (received = recvDataAndAck ()).hasSize (batchSizeNew );
268- out .emitEvent (new Event .Results (received , Collections .emptyMap ()));
268+ out .beforeEof (new Event .Results (received , Collections .emptyMap ()));
269269
270270 context .close ();
271271
272- // Wait until the Results event's been processed to guarantee
273- // that the tasks' futures are completed before asserting.
274- CompletableFuture .allOf (
275- tasks .stream ().map (TaskHandle ::result )
276- .toArray (CompletableFuture []::new ))
277- .get (100 , TimeUnit .MILLISECONDS );
278-
279272 Assertions .assertThat (tasks ).extracting (TaskHandle ::result )
280273 .allMatch (CompletableFuture ::isDone )
281274 .extracting (CompletableFuture ::get ).extracting (TaskHandle .Result ::error )
@@ -301,9 +294,11 @@ public void test_reconnect_onOom() throws Exception {
301294 in .expectMessage (START );
302295 out .emitEvent (Event .STARTED );
303296
297+ List <TaskHandle > tasks = new ArrayList <>();
298+
304299 // OOM is the opposite of Ack -- trigger a flush first.
305300 for (int i = 0 ; i < BATCH_SIZE ; i ++) {
306- context .add (WeaviateObject .of ());
301+ tasks . add ( context .add (WeaviateObject .of () ));
307302 }
308303
309304 // Respond with OOM and wait for the client to close its end of the stream.
@@ -317,16 +312,20 @@ public void test_reconnect_onOom() throws Exception {
317312 in .expectMessage (START );
318313 out .emitEvent (Event .STARTED );
319314 recvDataAndAck ();
315+
316+ List <String > submitted = tasks .stream ().map (TaskHandle ::id ).toList ();
317+ out .beforeEof (new Event .Results (submitted , Collections .emptyMap ()));
320318 }
321319
322320 @ Test
323321 public void test_reconnect_onStreamHangup () throws Exception {
324322 in .expectMessage (START );
325323 out .emitEvent (Event .STARTED );
326324
325+ List <TaskHandle > tasks = new ArrayList <>();
327326 // Trigger a flush.
328327 for (int i = 0 ; i < BATCH_SIZE ; i ++) {
329- context .add (WeaviateObject .of ());
328+ tasks . add ( context .add (WeaviateObject .of () ));
330329 }
331330
332331 // Expect a new batch to arrive. Hangup the stream before sending the Acks.
@@ -348,14 +347,17 @@ public void test_reconnect_onStreamHangup() throws Exception {
348347 out .hangup ();
349348 in .expectMessage (START );
350349 out .emitEvent (Event .STARTED );
351- context .add (WeaviateObject .of ());
350+ tasks . add ( context .add (WeaviateObject .of () ));
352351 recvDataAndAck ();
353352
354353 // Now fill up the rest of the batch to trigger a flush. Ack the incoming batch.
355354 for (int i = 0 ; i < BATCH_SIZE - 1 ; i ++) {
356- context .add (WeaviateObject .of ());
355+ tasks . add ( context .add (WeaviateObject .of () ));
357356 }
358357 recvDataAndAck ();
358+
359+ List <String > submitted = tasks .stream ().map (TaskHandle ::id ).toList ();
360+ out .beforeEof (new Event .Results (submitted , Collections .emptyMap ()));
359361 }
360362
361363 @ Test
@@ -391,20 +393,17 @@ public void test_reconnect_DrainAfterStreamHangup() throws Exception {
391393 out .emitEvent (Event .STARTED );
392394 Future <?> backgroundAcks = BACKGROUND .submit (() -> {
393395 try {
394- List <String > ids = recvDataAndAck ();
395- out .emitEvent (new Event .Results (ids , Collections .emptyMap ()));
396-
397- ids = recvDataAndAck ();
398- out .emitEvent (new Event .Results (ids , Collections .emptyMap ()));
399-
400- ids = recvDataAndAck ();
401- Future <?> lastEvent = out .emitEvent (new Event .Results (ids , Collections .emptyMap ()));
402- lastEvent .get ();
396+ recvDataAndAck ();
397+ recvDataAndAck ();
398+ recvDataAndAck ();
403399 } catch (Exception e ) {
404400 throw new RuntimeException (e );
405401 }
406402 });
407403
404+ List <String > submitted = tasks .stream ().map (TaskHandle ::id ).toList ();
405+ out .beforeEof (new Event .Results (submitted , Collections .emptyMap ()));
406+
408407 context .close ();
409408 backgroundAcks .get ();
410409
@@ -480,22 +479,14 @@ private List<String> recvData() throws InterruptedException {
480479 .toList ();
481480 }
482481
483- private void awaitResults (Collection <TaskHandle > tasks ) throws Exception {
484- // Wait until the Results event's been processed to guarantee
485- // that the tasks' futures are completed before asserting.
486- CompletableFuture .allOf (
487- tasks .stream ().map (TaskHandle ::result )
488- .toArray (CompletableFuture []::new ))
489- .get (100 , TimeUnit .MILLISECONDS );
490- }
491-
492482 static String getBeacon (WeaviateProtoBatch .BatchReference reference ) {
493483 return "weaviate://localhost/" + reference .getToCollection () + "/" + reference .getToUuid ();
494484 }
495485
496486 /** OutboundStream is a mock which dispatches server-side events. */
497487 private static final class OutboundStream {
498488 private final StreamObserver <Event > stream ;
489+ private List <Event > beforeEof = new ArrayList <>();
499490
500491 OutboundStream (StreamObserver <Event > stream ) {
501492 this .stream = stream ;
@@ -508,13 +499,22 @@ Future<?> emitEvent(Event event) {
508499 return EVENT_THREAD .submit (() -> stream .onNext (event ));
509500 }
510501
511- /** Terminate the server-side of the stream abruptly. */
502+ /** Terminate the server half of the stream abruptly. */
503+
512504 Future <?> hangup () {
513505 return EVENT_THREAD .submit (() -> stream .onError (new RuntimeException ("whaam!" )));
514506 }
515507
516- void eof () {
508+ /** Emit events before closing the server half of the stream. */
509+ void beforeEof (Event ... events ) {
510+ this .beforeEof .addAll (Arrays .asList (events ));
511+ }
512+
513+ void eof (boolean ok ) {
517514 assert Thread .currentThread () != TEST_THREAD : "test MUST NOT close/terminate the the stream" ;
515+ if (ok ) {
516+ beforeEof .forEach (this ::emitEvent );
517+ }
518518 EVENT_THREAD .submit (stream ::onCompleted );
519519 }
520520 }
@@ -548,13 +548,13 @@ WeaviateProtoBatch.BatchStreamRequest expectMessage(
548548 @ Override
549549 public void onCompleted () {
550550 done .complete (null );
551- outbound .eof ();
551+ outbound .eof (true );
552552 }
553553
554554 @ Override
555555 public void onError (Throwable t ) {
556556 done .completeExceptionally (t );
557- outbound .eof ();
557+ outbound .eof (false );
558558 }
559559
560560 @ Override
0 commit comments