Search in sources :

Example 11 with ServerStream

use of io.grpc.internal.ServerStream in project grpc-java by grpc.

the class AbstractTransportTest method flowControlPushBack.

@Test
public void flowControlPushBack() throws Exception {
    server.start(serverListener);
    client = newClientTransport(server);
    runIfNotNull(client.start(mockClientTransportListener));
    MockServerTransportListener serverTransportListener = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
    serverTransport = serverTransportListener.transport;
    ClientStream clientStream = client.newStream(methodDescriptor, new Metadata());
    clientStream.start(mockClientStreamListener);
    StreamCreation serverStreamCreation = serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
    assertEquals(methodDescriptor.getFullMethodName(), serverStreamCreation.method);
    ServerStream serverStream = serverStreamCreation.stream;
    ServerStreamListener mockServerStreamListener = serverStreamCreation.listener;
    serverStream.writeHeaders(new Metadata());
    Answer<Void> closeStream = new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Exception {
            Object[] args = invocation.getArguments();
            ((InputStream) args[0]).close();
            return null;
        }
    };
    String largeMessage;
    {
        int size = 1 * 1024;
        StringBuffer sb = new StringBuffer(size);
        for (int i = 0; i < size; i++) {
            sb.append('a');
        }
        largeMessage = sb.toString();
    }
    doAnswer(closeStream).when(mockServerStreamListener).messageRead(any(InputStream.class));
    serverStream.request(1);
    verify(mockClientStreamListener, timeout(TIMEOUT_MS)).onReady();
    assertTrue(clientStream.isReady());
    final int maxToSend = 10 * 1024;
    int clientSent;
    // Verify that flow control will push back on client.
    for (clientSent = 0; clientStream.isReady(); clientSent++) {
        if (clientSent > maxToSend) {
            // It seems like flow control isn't working. _Surely_ flow control would have pushed-back
            // already. If this is normal, please configure the transport to buffer less.
            fail("Too many messages sent before isReady() returned false");
        }
        clientStream.writeMessage(methodDescriptor.streamRequest(largeMessage));
        clientStream.flush();
    }
    assertTrue(clientSent > 0);
    // Make sure there are at least a few messages buffered.
    for (; clientSent < 5; clientSent++) {
        clientStream.writeMessage(methodDescriptor.streamResponse(largeMessage));
        clientStream.flush();
    }
    doPingPong(serverListener);
    verify(mockServerStreamListener, timeout(TIMEOUT_MS)).messageRead(any(InputStream.class));
    doAnswer(closeStream).when(mockClientStreamListener).messageRead(any(InputStream.class));
    clientStream.request(1);
    verify(mockServerStreamListener, timeout(TIMEOUT_MS)).onReady();
    assertTrue(serverStream.isReady());
    int serverSent;
    // Verify that flow control will push back on server.
    for (serverSent = 0; serverStream.isReady(); serverSent++) {
        if (serverSent > maxToSend) {
            // It seems like flow control isn't working. _Surely_ flow control would have pushed-back
            // already. If this is normal, please configure the transport to buffer less.
            fail("Too many messages sent before isReady() returned false");
        }
        serverStream.writeMessage(methodDescriptor.streamResponse(largeMessage));
        serverStream.flush();
    }
    assertTrue(serverSent > 0);
    // Make sure there are at least a few messages buffered.
    for (; serverSent < 5; serverSent++) {
        serverStream.writeMessage(methodDescriptor.streamResponse(largeMessage));
        serverStream.flush();
    }
    doPingPong(serverListener);
    verify(mockClientStreamListener, timeout(TIMEOUT_MS)).messageRead(any(InputStream.class));
    serverStream.request(3);
    clientStream.request(3);
    doPingPong(serverListener);
    // times() is total number throughout the entire test
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(4)).messageRead(any(InputStream.class));
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(4)).messageRead(any(InputStream.class));
    // Request the rest
    serverStream.request(clientSent);
    clientStream.request(serverSent);
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(clientSent)).messageRead(any(InputStream.class));
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(serverSent)).messageRead(any(InputStream.class));
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(2)).onReady();
    assertTrue(clientStream.isReady());
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(2)).onReady();
    assertTrue(serverStream.isReady());
    // Request four more
    for (int i = 0; i < 5; i++) {
        clientStream.writeMessage(methodDescriptor.streamRequest(largeMessage));
        clientStream.flush();
        serverStream.writeMessage(methodDescriptor.streamResponse(largeMessage));
        serverStream.flush();
    }
    doPingPong(serverListener);
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(clientSent + 4)).messageRead(any(InputStream.class));
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(serverSent + 4)).messageRead(any(InputStream.class));
    // Drain exactly how many messages are left
    serverStream.request(1);
    clientStream.request(1);
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(serverSent + 5)).messageRead(any(InputStream.class));
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(clientSent + 5)).messageRead(any(InputStream.class));
    // And now check that the streams can still complete gracefully
    clientStream.writeMessage(methodDescriptor.streamRequest(largeMessage));
    clientStream.flush();
    clientStream.halfClose();
    doPingPong(serverListener);
    verify(mockServerStreamListener, never()).halfClosed();
    serverStream.request(1);
    verify(mockServerStreamListener, timeout(TIMEOUT_MS).times(serverSent + 6)).messageRead(any(InputStream.class));
    verify(mockServerStreamListener, timeout(TIMEOUT_MS)).halfClosed();
    serverStream.writeMessage(methodDescriptor.streamResponse(largeMessage));
    serverStream.flush();
    Status status = Status.OK.withDescription("... quite a lengthy discussion");
    serverStream.close(status, new Metadata());
    doPingPong(serverListener);
    verify(mockClientStreamListener, never()).closed(any(Status.class), any(Metadata.class));
    clientStream.request(1);
    verify(mockClientStreamListener, timeout(TIMEOUT_MS).times(clientSent + 6)).messageRead(any(InputStream.class));
    verify(mockServerStreamListener, timeout(TIMEOUT_MS)).closed(statusCaptor.capture());
    assertCodeEquals(Status.OK, statusCaptor.getValue());
    verify(mockClientStreamListener, timeout(TIMEOUT_MS)).closed(statusCaptor.capture(), any(Metadata.class));
    assertEquals(status.getCode(), statusCaptor.getValue().getCode());
    assertEquals(status.getDescription(), statusCaptor.getValue().getDescription());
}
Also used : Status(io.grpc.Status) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) Metadata(io.grpc.Metadata) ServerStream(io.grpc.internal.ServerStream) ClientStream(io.grpc.internal.ClientStream) Mockito.doAnswer(org.mockito.Mockito.doAnswer) Answer(org.mockito.stubbing.Answer) ServerStreamListener(io.grpc.internal.ServerStreamListener) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Test(org.junit.Test)

Aggregations

Metadata (io.grpc.Metadata)11 ClientStream (io.grpc.internal.ClientStream)11 ServerStream (io.grpc.internal.ServerStream)11 Status (io.grpc.Status)10 ServerStreamListener (io.grpc.internal.ServerStreamListener)10 Test (org.junit.Test)10 IOException (java.io.IOException)4 ExecutionException (java.util.concurrent.ExecutionException)4 TimeoutException (java.util.concurrent.TimeoutException)4 ExpectedException (org.junit.rules.ExpectedException)4 ClientStreamListener (io.grpc.internal.ClientStreamListener)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InputStream (java.io.InputStream)2 ManagedClientTransport (io.grpc.internal.ManagedClientTransport)1 Matchers.anyBoolean (org.mockito.Matchers.anyBoolean)1 Mockito.doAnswer (org.mockito.Mockito.doAnswer)1 InvocationOnMock (org.mockito.invocation.InvocationOnMock)1 Answer (org.mockito.stubbing.Answer)1