core,testing: make MethodDescriptor final and add Test helper

This commit is contained in:
Carl Mastrangelo 2017-01-11 17:30:14 -08:00 committed by GitHub
parent ce3a94bacc
commit ec7f00a272
5 changed files with 119 additions and 27 deletions

View File

@ -50,7 +50,7 @@ import javax.annotation.concurrent.Immutable;
* <p>Can be constructed manually but will often be generated by stub code generators.
*/
@Immutable
public class MethodDescriptor<ReqT, RespT> {
public final class MethodDescriptor<ReqT, RespT> {
private final MethodType type;
private final String fullMethodName;

View File

@ -51,6 +51,7 @@ import static org.mockito.Mockito.when;
import io.grpc.ClientInterceptors.CheckedForwardingClientCall;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener;
import io.grpc.testing.TestMethodDescriptors;
import org.junit.Before;
import org.junit.Test;
@ -74,8 +75,7 @@ public class ClientInterceptorsTest {
private BaseClientCall call = new BaseClientCall();
@Mock
private MethodDescriptor<String, Integer> method;
private final MethodDescriptor<Void, Void> method = TestMethodDescriptors.noopMethod();
/**
* Sets up mocks.
@ -270,8 +270,8 @@ public class ClientInterceptorsTest {
};
Channel intercepted = ClientInterceptors.intercept(channel, interceptor);
@SuppressWarnings("unchecked")
ClientCall.Listener<Integer> listener = mock(ClientCall.Listener.class);
ClientCall<String, Integer> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
ClientCall.Listener<Void> listener = mock(ClientCall.Listener.class);
ClientCall<Void, Void> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
// start() on the intercepted call will eventually reach the call created by the real channel
interceptedCall.start(listener, new Metadata());
// The headers passed to the real channel call will contain the information inserted by the
@ -306,8 +306,8 @@ public class ClientInterceptorsTest {
};
Channel intercepted = ClientInterceptors.intercept(channel, interceptor);
@SuppressWarnings("unchecked")
ClientCall.Listener<Integer> listener = mock(ClientCall.Listener.class);
ClientCall<String, Integer> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
ClientCall.Listener<Void> listener = mock(ClientCall.Listener.class);
ClientCall<Void, Void> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
interceptedCall.start(listener, new Metadata());
// Capture the underlying call listener that will receive headers from the transport.
@ -330,16 +330,16 @@ public class ClientInterceptorsTest {
}
};
Channel intercepted = ClientInterceptors.intercept(channel, interceptor);
ClientCall<String, Integer> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
ClientCall<Void, Void> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
assertNotSame(call, interceptedCall);
@SuppressWarnings("unchecked")
ClientCall.Listener<Integer> listener = mock(ClientCall.Listener.class);
ClientCall.Listener<Void> listener = mock(ClientCall.Listener.class);
Metadata headers = new Metadata();
interceptedCall.start(listener, headers);
assertSame(listener, call.listener);
assertSame(headers, call.headers);
interceptedCall.sendMessage("request");
assertThat(call.messages).containsExactly("request");
interceptedCall.sendMessage(null /*request*/);
assertThat(call.messages).containsExactly((Void) null /*request*/);
interceptedCall.halfClose();
assertTrue(call.halfClosed);
interceptedCall.request(1);
@ -368,11 +368,11 @@ public class ClientInterceptorsTest {
};
Channel intercepted = ClientInterceptors.intercept(channel, interceptor);
@SuppressWarnings("unchecked")
ClientCall.Listener<Integer> listener = mock(ClientCall.Listener.class);
ClientCall<String, Integer> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
ClientCall.Listener<Void> listener = mock(ClientCall.Listener.class);
ClientCall<Void, Void> interceptedCall = intercepted.newCall(method, CallOptions.DEFAULT);
assertNotSame(call, interceptedCall);
interceptedCall.start(listener, new Metadata());
interceptedCall.sendMessage("request");
interceptedCall.sendMessage(null /*request*/);
interceptedCall.halfClose();
interceptedCall.request(1);
call.done = true;

View File

@ -42,7 +42,6 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import io.grpc.internal.FakeClock;
import io.grpc.testing.NoopServerCall;
@ -66,8 +65,6 @@ public class ContextsTest {
/** For use in comparing context by reference. */
private Context uniqueContext = Context.ROOT.withValue(contextKey, new Object());
@SuppressWarnings("unchecked")
private MethodDescriptor<Object, Object> method = mock(MethodDescriptor.class);
@SuppressWarnings("unchecked")
private ServerCall<Object, Object> call = new NoopServerCall<Object, Object>();
private Metadata headers = new Metadata();
@ -108,7 +105,6 @@ public class ContextsTest {
@Override
public ServerCall.Listener<Object> startCall(
ServerCall<Object, Object> call, Metadata headers) {
assertSame(ContextsTest.this.method, method);
assertSame(ContextsTest.this.call, call);
assertSame(ContextsTest.this.headers, headers);
assertSame(uniqueContext, Context.current());

View File

@ -84,6 +84,7 @@ import io.grpc.okhttp.internal.framed.FrameWriter;
import io.grpc.okhttp.internal.framed.Header;
import io.grpc.okhttp.internal.framed.HeadersMode;
import io.grpc.okhttp.internal.framed.Settings;
import io.grpc.testing.TestMethodDescriptors;
import okio.Buffer;
@ -133,8 +134,9 @@ public class OkHttpClientTransportTest {
@Mock
private FrameWriter frameWriter;
@Mock
MethodDescriptor<?, ?> method;
private MethodDescriptor<Void, Void> method = TestMethodDescriptors.noopMethod();
@Mock
private ManagedClientTransport.Listener transportListener;
private OkHttpClientTransport clientTransport;
@ -149,8 +151,6 @@ public class OkHttpClientTransportTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
executor = Executors.newCachedThreadPool();
when(method.getFullMethodName()).thenReturn("fakemethod");
when(method.getType()).thenReturn(MethodType.UNARY);
when(frameWriter.maxDataLength()).thenReturn(Integer.MAX_VALUE);
frameReader = new MockFrameReader();
}
@ -441,7 +441,7 @@ public class OkHttpClientTransportTest {
GrpcUtil.getGrpcUserAgent("okhttp", null));
List<Header> expectedHeaders = Arrays.asList(SCHEME_HEADER, METHOD_HEADER,
new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"),
new Header(Header.TARGET_PATH, "/fakemethod"),
new Header(Header.TARGET_PATH, "/" + method.getFullMethodName()),
userAgentHeader, CONTENT_TYPE_HEADER, TE_HEADER);
verify(frameWriter, timeout(TIME_OUT_MS))
.synStream(eq(false), eq(false), eq(3), eq(0), eq(expectedHeaders));
@ -457,7 +457,7 @@ public class OkHttpClientTransportTest {
stream.start(listener);
List<Header> expectedHeaders = Arrays.asList(SCHEME_HEADER, METHOD_HEADER,
new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"),
new Header(Header.TARGET_PATH, "/fakemethod"),
new Header(Header.TARGET_PATH, "/" + method.getFullMethodName()),
new Header(GrpcUtil.USER_AGENT_KEY.name(),
GrpcUtil.getGrpcUserAgent("okhttp", "fakeUserAgent")),
CONTENT_TYPE_HEADER, TE_HEADER);
@ -967,21 +967,33 @@ public class OkHttpClientTransportTest {
@Test
public void serverStreamingHeadersShouldNotBeFlushed() throws Exception {
when(method.getType()).thenReturn(MethodType.SERVER_STREAMING);
method = MethodDescriptor.create(
MethodType.SERVER_STREAMING,
method.getFullMethodName(),
TestMethodDescriptors.noopMarshaller(),
TestMethodDescriptors.noopMarshaller());
shouldHeadersBeFlushed(false);
shutdownAndVerify();
}
@Test
public void clientStreamingHeadersShouldBeFlushed() throws Exception {
when(method.getType()).thenReturn(MethodType.CLIENT_STREAMING);
method = MethodDescriptor.create(
MethodType.CLIENT_STREAMING,
method.getFullMethodName(),
TestMethodDescriptors.noopMarshaller(),
TestMethodDescriptors.noopMarshaller());
shouldHeadersBeFlushed(true);
shutdownAndVerify();
}
@Test
public void duplexStreamingHeadersShouldNotBeFlushed() throws Exception {
when(method.getType()).thenReturn(MethodType.BIDI_STREAMING);
method = MethodDescriptor.create(
MethodType.BIDI_STREAMING,
method.getFullMethodName(),
TestMethodDescriptors.noopMarshaller(),
TestMethodDescriptors.noopMarshaller());
shouldHeadersBeFlushed(true);
shutdownAndVerify();
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2017, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.grpc.testing;
import io.grpc.ExperimentalApi;
import io.grpc.MethodDescriptor;
import io.grpc.MethodDescriptor.MethodType;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
/**
* A collection of method descriptor constructors useful for tests. These are useful if you need
* a descriptor, but don't really care how it works.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/2600")
public final class TestMethodDescriptors {
private TestMethodDescriptors() {}
/**
* Creates a new method descriptor that always creates zero length messages, and always parses to
* null objects.
*/
public static MethodDescriptor<Void, Void> noopMethod() {
return noopMethod("service_foo", "method_bar");
}
private static MethodDescriptor<Void, Void> noopMethod(
String serviceName, String methodName) {
return MethodDescriptor.create(
MethodType.UNARY,
MethodDescriptor.generateFullMethodName(serviceName, methodName),
noopMarshaller(),
noopMarshaller());
}
/**
* Creates a new marshaller that does nothing.
*/
public static MethodDescriptor.Marshaller<Void> noopMarshaller() {
return new NoopMarshaller();
}
private static final class NoopMarshaller implements MethodDescriptor.Marshaller<Void> {
@Override
public InputStream stream(Void value) {
return new ByteArrayInputStream(new byte[]{});
}
@Override
public Void parse(InputStream stream) {
return null;
}
}
}