Skip to content

Commit e81dff5

Browse files
committed
binder: Add unit tests for ServerInbound message reassembly
1 parent ac34a50 commit e81dff5

File tree

2 files changed

+121
-2
lines changed

2 files changed

+121
-2
lines changed

binder/src/test/java/io/grpc/binder/internal/RobolectricBinderTransportTest.java

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,19 @@
4747
import com.google.common.collect.ImmutableList;
4848
import com.google.common.truth.TruthJUnit;
4949
import io.grpc.Attributes;
50+
import io.grpc.CallOptions;
5051
import io.grpc.InternalChannelz.SocketStats;
52+
import io.grpc.Metadata;
5153
import io.grpc.ServerStreamTracer;
5254
import io.grpc.Status;
5355
import io.grpc.binder.AndroidComponentAddress;
5456
import io.grpc.binder.ApiConstants;
5557
import io.grpc.binder.AsyncSecurityPolicy;
5658
import io.grpc.binder.SecurityPolicies;
59+
import io.grpc.binder.internal.OneWayBinderProxies.*;
5760
import io.grpc.binder.internal.SettableAsyncSecurityPolicy.AuthRequest;
5861
import io.grpc.internal.AbstractTransportTest;
62+
import io.grpc.internal.ClientStream;
5963
import io.grpc.internal.ClientTransport;
6064
import io.grpc.internal.ClientTransportFactory.ClientTransportOptions;
6165
import io.grpc.internal.ConnectionClientTransport;
@@ -66,6 +70,7 @@
6670
import io.grpc.internal.MockServerTransportListener;
6771
import io.grpc.internal.ObjectPool;
6872
import io.grpc.internal.SharedResourcePool;
73+
import java.io.InputStream;
6974
import java.util.List;
7075
import java.util.concurrent.Executor;
7176
import java.util.concurrent.ScheduledExecutorService;
@@ -124,6 +129,8 @@ public final class RobolectricBinderTransportTest extends AbstractTransportTest
124129
ServiceInfo serviceInfo;
125130

126131
private int nextServerAddress;
132+
private BlockingBinderDecorator<OneWayBinderProxy> blockingDecorator =
133+
new BlockingBinderDecorator<>();
127134

128135
@Parameter(value = 0)
129136
public boolean preAuthServersParam;
@@ -433,4 +440,116 @@ public void flowControlPushBack() {}
433440
@Ignore("See BinderTransportTest#serverAlreadyListening")
434441
@Override
435442
public void serverAlreadyListening() {}
443+
444+
@Test
445+
public void singleTxnMsgsDeliveredToServerOutOfOrder() throws Exception {
446+
server.start(serverListener);
447+
client = newClientTransportBuilder()
448+
.setFactory(
449+
newClientTransportFactoryBuilder()
450+
.setBinderDecorator(blockingDecorator)
451+
.buildClientTransportFactory())
452+
.build();
453+
454+
runIfNotNull(client.start(mockClientTransportListener));
455+
456+
OneWayBinderProxy endpointProxy = blockingDecorator.takeNextRequest(TIMEOUT_MS, MILLISECONDS);
457+
assertThat(endpointProxy).isNotNull();
458+
blockingDecorator.putNextResult(endpointProxy);
459+
460+
OneWayBinderProxy serverProxy = blockingDecorator.takeNextRequest(TIMEOUT_MS, MILLISECONDS);
461+
assertThat(serverProxy).isNotNull();
462+
QueueingOneWayBinderProxy proxy = new QueueingOneWayBinderProxy(serverProxy);
463+
blockingDecorator.putNextResult(proxy);
464+
465+
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportReady();
466+
467+
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), CallOptions.DEFAULT, noopTracers);
468+
stream.writeMessage(methodDescriptor.streamRequest("one"));
469+
stream.writeMessage(methodDescriptor.streamRequest("two"));
470+
stream.flush();
471+
472+
// We expect at least two transactions for the messages.
473+
QueueingOneWayBinderProxy.Transaction tx1 = takeNextTransaction(proxy);
474+
QueueingOneWayBinderProxy.Transaction tx2 = takeNextTransaction(proxy);
475+
476+
// Deliver them out of order!
477+
proxy.deliver(tx2);
478+
proxy.deliver(tx1);
479+
480+
// Verify that the server receives them in order.
481+
MockServerTransportListener serverTransportListener = serverListener.takeListenerOrFail(TIMEOUT_MS, MILLISECONDS);
482+
MockServerTransportListener.StreamCreation streamCreation = serverTransportListener.takeStreamOrFail(TIMEOUT_MS,
483+
MILLISECONDS);
484+
streamCreation.stream.request(2);
485+
486+
InputStream msg1 = streamCreation.listener.messageQueue.poll(TIMEOUT_MS, MILLISECONDS);
487+
assertThat(msg1).isNotNull();
488+
assertThat(methodDescriptor.parseResponse(msg1)).isEqualTo("one");
489+
490+
InputStream msg2 = streamCreation.listener.messageQueue.poll(TIMEOUT_MS, MILLISECONDS);
491+
assertThat(msg2).isNotNull();
492+
assertThat(methodDescriptor.parseResponse(msg2)).isEqualTo("two");
493+
}
494+
495+
@Test
496+
public void msgFragmentsDeliveredToServerOutOfOrder() throws Exception {
497+
server.start(serverListener);
498+
client = newClientTransportBuilder()
499+
.setFactory(
500+
newClientTransportFactoryBuilder()
501+
.setBinderDecorator(blockingDecorator)
502+
.buildClientTransportFactory())
503+
.build();
504+
505+
runIfNotNull(client.start(mockClientTransportListener));
506+
507+
OneWayBinderProxy endpointProxy = blockingDecorator.takeNextRequest(TIMEOUT_MS, MILLISECONDS);
508+
assertThat(endpointProxy).isNotNull();
509+
blockingDecorator.putNextResult(endpointProxy);
510+
511+
OneWayBinderProxy serverProxy = blockingDecorator.takeNextRequest(TIMEOUT_MS, MILLISECONDS);
512+
assertThat(serverProxy).isNotNull();
513+
QueueingOneWayBinderProxy proxy = new QueueingOneWayBinderProxy(serverProxy);
514+
blockingDecorator.putNextResult(proxy);
515+
516+
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportReady();
517+
518+
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), CallOptions.DEFAULT, noopTracers);
519+
520+
String largeMessage = newStringOfLength(20 * 1024);
521+
stream.writeMessage(methodDescriptor.streamRequest(largeMessage));
522+
stream.flush();
523+
524+
// We expect at least two transactions for the large message.
525+
QueueingOneWayBinderProxy.Transaction tx1 = takeNextTransaction(proxy);
526+
QueueingOneWayBinderProxy.Transaction tx2 = takeNextTransaction(proxy);
527+
528+
// Deliver them out of order!
529+
proxy.deliver(tx2);
530+
proxy.deliver(tx1);
531+
532+
// Verify that the server receives the complete message correctly.
533+
MockServerTransportListener serverTransportListener = serverListener.takeListenerOrFail(TIMEOUT_MS, MILLISECONDS);
534+
MockServerTransportListener.StreamCreation streamCreation = serverTransportListener.takeStreamOrFail(TIMEOUT_MS,
535+
MILLISECONDS);
536+
streamCreation.stream.request(1);
537+
538+
InputStream msgStream = streamCreation.listener.messageQueue.poll(TIMEOUT_MS, MILLISECONDS);
539+
assertThat(msgStream).isNotNull();
540+
assertThat(methodDescriptor.parseResponse(msgStream)).isEqualTo(largeMessage);
541+
}
542+
543+
private static QueueingOneWayBinderProxy.Transaction takeNextTransaction(
544+
QueueingOneWayBinderProxy proxy) throws InterruptedException {
545+
QueueingOneWayBinderProxy.Transaction tx = proxy.pollNextTransaction(TIMEOUT_MS, MILLISECONDS);
546+
assertThat(tx).isNotNull();
547+
return tx;
548+
}
549+
550+
private static String newStringOfLength(int numChars) {
551+
char[] chars = new char[numChars];
552+
java.util.Arrays.fill(chars, 'x');
553+
return new String(chars);
554+
}
436555
}

core/src/testFixtures/java/io/grpc/internal/AbstractTransportTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public void log(ChannelLogLevel level, String messageFormat, Object... args) {}
185185
protected final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
186186
clientStreamTracer1, clientStreamTracer2
187187
};
188-
private final ClientStreamTracer[] noopTracers = new ClientStreamTracer[] {
188+
protected final ClientStreamTracer[] noopTracers = new ClientStreamTracer[] {
189189
new ClientStreamTracer() {}
190190
};
191191

@@ -2195,7 +2195,7 @@ public void streamCreated(Attributes transportAttrs, Metadata metadata) {
21952195
}
21962196
}
21972197

2198-
private static class StringMarshaller implements MethodDescriptor.Marshaller<String> {
2198+
protected static class StringMarshaller implements MethodDescriptor.Marshaller<String> {
21992199
public static final StringMarshaller INSTANCE = new StringMarshaller();
22002200

22012201
@Override

0 commit comments

Comments
 (0)