mirror of https://github.com/grpc/grpc-java.git
binder: Helper class to allow in process servers to use peer uids in test (#11014)
This commit is contained in:
parent
10cb4a3bed
commit
537dbe826a
|
@ -0,0 +1,123 @@
|
||||||
|
package io.grpc.binder;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import io.grpc.CallOptions;
|
||||||
|
import io.grpc.Channel;
|
||||||
|
import io.grpc.ClientInterceptors;
|
||||||
|
import io.grpc.ManagedChannel;
|
||||||
|
import io.grpc.Metadata;
|
||||||
|
import io.grpc.MethodDescriptor;
|
||||||
|
import io.grpc.ServerCallHandler;
|
||||||
|
import io.grpc.ServerInterceptor;
|
||||||
|
import io.grpc.ServerInterceptors;
|
||||||
|
import io.grpc.ServerServiceDefinition;
|
||||||
|
import io.grpc.inprocess.InProcessChannelBuilder;
|
||||||
|
import io.grpc.inprocess.InProcessServerBuilder;
|
||||||
|
import io.grpc.stub.ClientCalls;
|
||||||
|
import io.grpc.stub.MetadataUtils;
|
||||||
|
import io.grpc.stub.ServerCalls;
|
||||||
|
import io.grpc.testing.GrpcCleanupRule;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public final class PeerUidTestHelperTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
|
||||||
|
|
||||||
|
private static final int FAKE_UID = 12345;
|
||||||
|
|
||||||
|
private final AtomicReference<PeerUid> clientUidCapture = new AtomicReference<>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void keyPopulatedWithInterceptorAndHeader() throws Exception {
|
||||||
|
makeServiceCall(/* includeInterceptor= */ true, /* includeUidInHeader= */ true, FAKE_UID);
|
||||||
|
assertThat(clientUidCapture.get()).isEqualTo(new PeerUid(FAKE_UID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void keyNotPopulatedWithInterceptorAndNoHeader() throws Exception {
|
||||||
|
makeServiceCall(/* includeInterceptor= */ true, /* includeUidInHeader= */ false, /* uid= */ -1);
|
||||||
|
assertThat(clientUidCapture.get()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void keyNotPopulatedWithoutInterceptorAndWithHeader() throws Exception {
|
||||||
|
makeServiceCall(
|
||||||
|
/* includeInterceptor= */ false, /* includeUidInHeader= */ true, /* uid= */ FAKE_UID);
|
||||||
|
assertThat(clientUidCapture.get()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MethodDescriptor<String, String> method =
|
||||||
|
MethodDescriptor.newBuilder(StringMarshaller.INSTANCE, StringMarshaller.INSTANCE)
|
||||||
|
.setFullMethodName("test/method")
|
||||||
|
.setType(MethodDescriptor.MethodType.UNARY)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private void makeServiceCall(boolean includeInterceptor, boolean includeUidInHeader, int uid)
|
||||||
|
throws Exception {
|
||||||
|
ServerCallHandler<String, String> callHandler =
|
||||||
|
ServerCalls.asyncUnaryCall(
|
||||||
|
(req, respObserver) -> {
|
||||||
|
clientUidCapture.set(PeerUids.REMOTE_PEER.get());
|
||||||
|
respObserver.onNext(req);
|
||||||
|
respObserver.onCompleted();
|
||||||
|
});
|
||||||
|
ImmutableList<ServerInterceptor> interceptors;
|
||||||
|
if (includeInterceptor) {
|
||||||
|
interceptors = ImmutableList.of(PeerUidTestHelper.newTestPeerIdentifyingServerInterceptor());
|
||||||
|
} else {
|
||||||
|
interceptors = ImmutableList.of();
|
||||||
|
}
|
||||||
|
ServerServiceDefinition serviceDef =
|
||||||
|
ServerInterceptors.intercept(
|
||||||
|
ServerServiceDefinition.builder("test").addMethod(method, callHandler).build(),
|
||||||
|
interceptors);
|
||||||
|
|
||||||
|
InProcessServerBuilder server =
|
||||||
|
InProcessServerBuilder.forName("test").directExecutor().addService(serviceDef);
|
||||||
|
|
||||||
|
grpcCleanup.register(server.build().start());
|
||||||
|
|
||||||
|
Channel channel = InProcessChannelBuilder.forName("test").directExecutor().build();
|
||||||
|
grpcCleanup.register((ManagedChannel) channel);
|
||||||
|
|
||||||
|
if (includeUidInHeader) {
|
||||||
|
Metadata header = new Metadata();
|
||||||
|
header.put(PeerUidTestHelper.UID_KEY, uid);
|
||||||
|
channel =
|
||||||
|
ClientInterceptors.intercept(channel, MetadataUtils.newAttachHeadersInterceptor(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientCalls.blockingUnaryCall(channel, method, CallOptions.DEFAULT, "hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StringMarshaller implements MethodDescriptor.Marshaller<String> {
|
||||||
|
|
||||||
|
public static final StringMarshaller INSTANCE = new StringMarshaller();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream stream(String value) {
|
||||||
|
return new ByteArrayInputStream(value.getBytes(UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String parse(InputStream stream) {
|
||||||
|
try {
|
||||||
|
return new String(stream.readAllBytes(), UTF_8);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package io.grpc.binder;
|
||||||
|
|
||||||
|
import io.grpc.Context;
|
||||||
|
import io.grpc.Contexts;
|
||||||
|
import io.grpc.Metadata;
|
||||||
|
import io.grpc.ServerCall;
|
||||||
|
import io.grpc.ServerCallHandler;
|
||||||
|
import io.grpc.ServerInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class which helps set up {@link PeerUids} to be used in tests.
|
||||||
|
*/
|
||||||
|
public final class PeerUidTestHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UID of the calling package is set with the value of this key.
|
||||||
|
*/
|
||||||
|
public static final Metadata.Key<Integer> UID_KEY =
|
||||||
|
Metadata.Key.of("binder-remote-uid-for-unit-testing", PeerUidTestMarshaller.INSTANCE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an interceptor that associates the {@link PeerUids#REMOTE_PEER} key in the request
|
||||||
|
* {@link Context} with a UID provided by the client in the {@link #UID_KEY} request header, if
|
||||||
|
* present.
|
||||||
|
*
|
||||||
|
* <p>The returned interceptor works with any gRPC transport but is meant for in-process unit
|
||||||
|
* testing of gRPC/binder services that depend on {@link PeerUids}.
|
||||||
|
*/
|
||||||
|
public static ServerInterceptor newTestPeerIdentifyingServerInterceptor() {
|
||||||
|
return new ServerInterceptor() {
|
||||||
|
@Override
|
||||||
|
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
||||||
|
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||||
|
if (headers.containsKey(UID_KEY)) {
|
||||||
|
Context context =
|
||||||
|
Context.current().withValue(PeerUids.REMOTE_PEER, new PeerUid(headers.get(UID_KEY)));
|
||||||
|
return Contexts.interceptCall(context, call, headers, next);
|
||||||
|
}
|
||||||
|
return next.startCall(call, headers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private PeerUidTestHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PeerUidTestMarshaller implements Metadata.AsciiMarshaller<Integer> {
|
||||||
|
|
||||||
|
public static final PeerUidTestMarshaller INSTANCE = new PeerUidTestMarshaller();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toAsciiString(Integer value) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer parseAsciiString(String serialized) {
|
||||||
|
return Integer.parseInt(serialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
Loading…
Reference in New Issue