@@ -569,6 +569,106 @@ public void msgFragmentsDeliveredToServerOutOfOrder() throws Exception {
569569 .isOk ();
570570 }
571571
572+ @ Test
573+ public void singleTxnMsgsDeliveredToClientOutOfOrder () throws Exception {
574+ server = newServerBuilder ().setClientBinderDecorator (blockingDecorator ).build ();
575+ registerServerWithRobolectric ((BinderServer ) server );
576+ server .start (serverListener );
577+
578+ client = newClientTransport (server );
579+ runIfNotNull (client .start (mockClientTransportListener ));
580+
581+ QueueingOneWayBinderProxy queueingClientProxy =
582+ new QueueingOneWayBinderProxy (takeNextBinder (blockingDecorator ));
583+ blockingDecorator .putNextResult (queueingClientProxy );
584+
585+ // Deliver the setup transaction without interference.
586+ queueingClientProxy .deliver (takeNextTransaction (queueingClientProxy ));
587+ verify (mockClientTransportListener , timeout (TIMEOUT_MS )).transportReady ();
588+
589+ ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase ();
590+ ClientStream stream =
591+ client .newStream (methodDescriptor , new Metadata (), CallOptions .DEFAULT , noopTracers );
592+ stream .start (clientStreamListener );
593+ stream .halfClose ();
594+ stream .request (2 );
595+
596+ MockServerTransportListener serverTransportListener =
597+ serverListener .takeListenerOrFail (TIMEOUT_MS , MILLISECONDS );
598+ MockServerTransportListener .StreamCreation serverStreamCreation =
599+ serverTransportListener .takeStreamOrFail (TIMEOUT_MS , MILLISECONDS );
600+
601+ serverStreamCreation .stream .writeMessage (methodDescriptor .streamResponse ("one" ));
602+ serverStreamCreation .stream .writeMessage (methodDescriptor .streamResponse ("two" ));
603+ serverStreamCreation .stream .close (Status .OK , new Metadata ());
604+
605+ // Expect one transaction from the server for each message.
606+ QueueingOneWayBinderProxy .Transaction tx1 = takeNextTransaction (queueingClientProxy );
607+ QueueingOneWayBinderProxy .Transaction tx2 = takeNextTransaction (queueingClientProxy );
608+ QueueingOneWayBinderProxy .Transaction txClose = takeNextTransaction (queueingClientProxy );
609+
610+ // Deliver messages to the client out of order!
611+ queueingClientProxy .deliver (tx2 );
612+ queueingClientProxy .deliver (tx1 );
613+ queueingClientProxy .deliver (txClose );
614+
615+ // Client should deliver messages to the application in the order sent.
616+ InputStream msg1 = takeNextMessage (clientStreamListener .messageQueue );
617+ assertThat (methodDescriptor .parseResponse (msg1 )).isEqualTo ("one" );
618+ InputStream msg2 = takeNextMessage (clientStreamListener .messageQueue );
619+ assertThat (methodDescriptor .parseResponse (msg2 )).isEqualTo ("two" );
620+
621+ assertAbout (status ()).that (clientStreamListener .awaitClose (TIMEOUT_MS , MILLISECONDS )).isOk ();
622+ assertAbout (status ())
623+ .that (serverStreamCreation .listener .awaitClose (TIMEOUT_MS , MILLISECONDS ))
624+ .isOk ();
625+ }
626+
627+ @ Test
628+ public void msgFragmentsDeliveredToClientOutOfOrder () throws Exception {
629+ server = newServerBuilder ().setClientBinderDecorator (blockingDecorator ).build ();
630+ registerServerWithRobolectric ((BinderServer ) server );
631+ server .start (serverListener );
632+
633+ client = newClientTransport (server );
634+ runIfNotNull (client .start (mockClientTransportListener ));
635+
636+ QueueingOneWayBinderProxy queueingClientProxy =
637+ new QueueingOneWayBinderProxy (takeNextBinder (blockingDecorator ));
638+ blockingDecorator .putNextResult (queueingClientProxy );
639+
640+ // Deliver the setup transaction without interference.
641+ queueingClientProxy .deliver (takeNextTransaction (queueingClientProxy ));
642+ verify (mockClientTransportListener , timeout (TIMEOUT_MS )).transportReady ();
643+
644+ ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase ();
645+ ClientStream stream =
646+ client .newStream (methodDescriptor , new Metadata (), CallOptions .DEFAULT , noopTracers );
647+ stream .start (clientStreamListener );
648+ stream .request (1 );
649+
650+ MockServerTransportListener serverTransportListener =
651+ serverListener .takeListenerOrFail (TIMEOUT_MS , MILLISECONDS );
652+ MockServerTransportListener .StreamCreation serverStreamCreation =
653+ serverTransportListener .takeStreamOrFail (TIMEOUT_MS , MILLISECONDS );
654+
655+ String largeMessage = newStringOfLength (BlockPool .BLOCK_SIZE + 1 );
656+ serverStreamCreation .stream .writeMessage (methodDescriptor .streamResponse (largeMessage ));
657+ serverStreamCreation .stream .flush ();
658+
659+ // Expect the client to split largeMessage into two transactions.
660+ QueueingOneWayBinderProxy .Transaction tx1 = takeNextTransaction (queueingClientProxy );
661+ QueueingOneWayBinderProxy .Transaction tx2 = takeNextTransaction (queueingClientProxy );
662+
663+ // Deliver them to the client out of order!
664+ queueingClientProxy .deliver (tx2 );
665+ queueingClientProxy .deliver (tx1 );
666+
667+ // Client should reassemble the message correctly.
668+ InputStream msg = takeNextMessage (clientStreamListener .messageQueue );
669+ assertThat (methodDescriptor .parseResponse (msg )).isEqualTo (largeMessage );
670+ }
671+
572672 private static OneWayBinderProxy takeNextBinder (
573673 BlockingBinderDecorator <OneWayBinderProxy > decorator ) throws InterruptedException {
574674 OneWayBinderProxy proxy = decorator .takeNextRequest (TIMEOUT_MS , MILLISECONDS );
0 commit comments