This change adds the writing of the remote execution log to a file behind an experimental flag. It also adds a logging handler for Execute calls so that they are logged.
PiperOrigin-RevId: 190991493
diff --git a/src/main/java/com/google/devtools/build/lib/remote/BUILD b/src/main/java/com/google/devtools/build/lib/remote/BUILD
index 42bf4020..18e38ed 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/remote/BUILD
@@ -31,6 +31,7 @@
"//src/main/java/com/google/devtools/build/lib/exec/local:options",
"//src/main/java/com/google/devtools/build/lib/remote/blobstore",
"//src/main/java/com/google/devtools/build/lib/remote/blobstore/http",
+ "//src/main/java/com/google/devtools/build/lib/remote/logging",
"//src/main/java/com/google/devtools/build/lib/remote/util",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/common/options",
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
index dbb0e06..805f8f2 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
@@ -22,6 +22,7 @@
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.exec.ExecutorBuilder;
+import com.google.devtools.build.lib.remote.logging.LoggingInterceptor;
import com.google.devtools.build.lib.remote.util.DigestUtil;
import com.google.devtools.build.lib.runtime.BlazeModule;
import com.google.devtools.build.lib.runtime.Command;
@@ -29,6 +30,7 @@
import com.google.devtools.build.lib.runtime.ServerBuilder;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.build.lib.util.io.AsynchronousFileOutputStream;
import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
@@ -36,12 +38,14 @@
import com.google.devtools.common.options.OptionsProvider;
import com.google.devtools.remoteexecution.v1test.Digest;
import io.grpc.Channel;
+import io.grpc.ClientInterceptors;
import java.io.IOException;
import java.util.logging.Logger;
/** RemoteModule provides distributed cache and remote execution for Bazel. */
public final class RemoteModule extends BlazeModule {
private static final Logger logger = Logger.getLogger(RemoteModule.class.getName());
+ private AsynchronousFileOutputStream rpcLogFile;
@VisibleForTesting
static final class CasPathConverter implements PathConverter {
@@ -126,6 +130,10 @@
boolean remoteOrLocalCache = SimpleBlobStoreFactory.isRemoteCacheOptions(remoteOptions);
boolean grpcCache = GrpcRemoteCache.isRemoteCacheOptions(remoteOptions);
+ if (!remoteOptions.experimentalRemoteGrpcLog.isEmpty()) {
+ rpcLogFile = new AsynchronousFileOutputStream(remoteOptions.experimentalRemoteGrpcLog);
+ }
+
RemoteRetrier retrier =
new RemoteRetrier(
remoteOptions, RemoteRetrier.RETRIABLE_GRPC_ERRORS, Retrier.ALLOW_ALL_CALLS);
@@ -157,9 +165,13 @@
final GrpcRemoteExecutor executor;
if (remoteOptions.remoteExecutor != null) {
+ Channel ch = GoogleAuthUtils.newChannel(remoteOptions.remoteExecutor, authAndTlsOptions);
+ if (rpcLogFile != null) {
+ ch = ClientInterceptors.intercept(ch, new LoggingInterceptor(rpcLogFile));
+ }
executor =
new GrpcRemoteExecutor(
- GoogleAuthUtils.newChannel(remoteOptions.remoteExecutor, authAndTlsOptions),
+ ch,
GoogleAuthUtils.newCallCredentials(authAndTlsOptions),
remoteOptions.remoteTimeout,
retrier);
@@ -176,6 +188,19 @@
}
@Override
+ public void afterCommand() {
+ if (rpcLogFile != null) {
+ try {
+ rpcLogFile.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ rpcLogFile = null;
+ }
+ }
+ }
+
+ @Override
public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
if (actionContextProvider != null) {
builder.addActionContextProvider(actionContextProvider);
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java
index e6493f3..dd4f5a0 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java
@@ -206,4 +206,20 @@
+ "writing of files, which could cause false positives."
)
public boolean experimentalGuardAgainstConcurrentChanges;
+
+ @Option(
+ name = "experimental_remote_grpc_log",
+ defaultValue = "",
+ category = "remote",
+ documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+ effectTags = {OptionEffectTag.UNKNOWN},
+ help =
+ "If specified, a path to a file to log gRPC call related details. This log consists "
+ + "of a sequence of serialized "
+ + "com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.LogEntry "
+ + "protobufs with each message prefixed by a varint denoting the size of the following "
+ + "serialized protobuf message, as performed by the method "
+ + "LogEntry.writeDelimitedTo(OutputStream)."
+ )
+ public String experimentalRemoteGrpcLog;
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/logging/BUILD b/src/main/java/com/google/devtools/build/lib/remote/logging/BUILD
index 9d8af58..cd688e1 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/logging/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/remote/logging/BUILD
@@ -11,10 +11,12 @@
srcs = glob(["*.java"]),
tags = ["bazel"],
deps = [
+ "//src/main/java/com/google/devtools/build/lib:io",
"//src/main/java/com/google/devtools/build/lib/remote/util",
"//src/main/protobuf:remote_execution_log_java_proto",
"//third_party:guava",
"//third_party/grpc:grpc-jar",
+ "@googleapis//:google_devtools_remoteexecution_v1test_remote_execution_java_grpc",
"@googleapis//:google_devtools_remoteexecution_v1test_remote_execution_java_proto",
"@googleapis//:google_longrunning_operations_java_proto",
"@googleapis//:google_rpc_status_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/remote/logging/ExecuteHandler.java b/src/main/java/com/google/devtools/build/lib/remote/logging/ExecuteHandler.java
new file mode 100644
index 0000000..52ad59c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/remote/logging/ExecuteHandler.java
@@ -0,0 +1,45 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.remote.logging;
+
+import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.ExecuteDetails;
+import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.RpcCallDetails;
+import com.google.devtools.remoteexecution.v1test.ExecuteRequest;
+import com.google.longrunning.Operation;
+
+/** LoggingHandler for google.devtools.remoteexecution.v1test.Execution.Execute gRPC call. */
+public class ExecuteHandler implements LoggingHandler<ExecuteRequest, Operation> {
+
+ private final ExecuteDetails.Builder builder;
+
+ public ExecuteHandler() {
+ builder = ExecuteDetails.newBuilder();
+ }
+
+ @Override
+ public void handleReq(ExecuteRequest message) {
+ builder.setRequest(message);
+ }
+
+ @Override
+ public void handleResp(Operation message) {
+ builder.setResponse(message);
+ }
+
+ @Override
+ public RpcCallDetails getDetails() {
+ return RpcCallDetails.newBuilder().setExecute(builder).build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingHandler.java b/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingHandler.java
index fb23d6c..d9653a8 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingHandler.java
@@ -14,11 +14,10 @@
package com.google.devtools.build.lib.remote.logging;
-import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.LogEntry;
+import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.RpcCallDetails;
/**
- * An interface for building {@link LogEntry}s specialized for a specific gRPC call with specific
- * request and response types.
+ * An interface for building {@link RpcCallDetails}s specialized for a specific gRPC call.
*
* @param <ReqT> request type of the gRPC call
* @param <RespT> response type of the gRPC call
@@ -39,6 +38,8 @@
*/
void handleResp(RespT message);
- /** Returns a {@link LogEntry} based on the requests and responses handled by this handler * */
- LogEntry getEntry();
+ /**
+ * Returns a {@link RpcCallDetails} based on the requests and responses handled by this handler.
+ */
+ RpcCallDetails getDetails();
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptor.java b/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptor.java
index 37629d7..b46d4e0 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptor.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptor.java
@@ -16,6 +16,8 @@
import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.LogEntry;
import com.google.devtools.build.lib.remote.util.TracingMetadataUtils;
+import com.google.devtools.build.lib.util.io.AsynchronousFileOutputStream;
+import com.google.devtools.remoteexecution.v1test.ExecutionGrpc;
import com.google.devtools.remoteexecution.v1test.RequestMetadata;
import io.grpc.CallOptions;
import io.grpc.Channel;
@@ -30,6 +32,12 @@
/** Client interceptor for logging details of certain gRPC calls. */
public class LoggingInterceptor implements ClientInterceptor {
+ AsynchronousFileOutputStream rpcLogFile;
+
+ /** Constructs a LoggingInterceptor which logs RPC calls to the given file. */
+ public LoggingInterceptor(AsynchronousFileOutputStream rpcLogFile) {
+ this.rpcLogFile = rpcLogFile;
+ }
/**
* Returns a {@link LoggingHandler} to handle logging details for the specified method. If there
@@ -37,9 +45,12 @@
*
* @param method Method to return handler for.
*/
- protected <ReqT, RespT> @Nullable LoggingHandler<ReqT, RespT> selectHandler(
+ @SuppressWarnings("rawtypes")
+ protected <ReqT, RespT> @Nullable LoggingHandler selectHandler(
MethodDescriptor<ReqT, RespT> method) {
- // TODO(cdlee): add handlers for methods
+ if (method == ExecutionGrpc.getExecuteMethod()) {
+ return new ExecuteHandler();
+ }
return null;
}
@@ -56,9 +67,10 @@
}
/**
- * Wraps client call to log call details by building a {@link LogEntry} and writing it to a log.
+ * Wraps client call to log call details by building a {@link LogEntry} and writing it to the RPC
+ * log file.
*/
- private static class LoggingForwardingCall<ReqT, RespT>
+ private class LoggingForwardingCall<ReqT, RespT>
extends ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT> {
private final LoggingHandler<ReqT, RespT> handler;
private final LogEntry.Builder entryBuilder;
@@ -90,8 +102,8 @@
@Override
public void onClose(Status status, Metadata trailers) {
entryBuilder.setStatus(makeStatusProto(status));
- // TODO(cdlee): Actually store this and log the entry.
- entryBuilder.mergeFrom(handler.getEntry()).build();
+ entryBuilder.setDetails(handler.getDetails());
+ rpcLogFile.write(entryBuilder.build());
super.onClose(status, trailers);
}
},
diff --git a/src/main/protobuf/BUILD b/src/main/protobuf/BUILD
index 4154a17..3ed9d1f 100644
--- a/src/main/protobuf/BUILD
+++ b/src/main/protobuf/BUILD
@@ -133,6 +133,7 @@
srcs = ["remote_execution_log.proto"],
deps = [
"@googleapis//:google_devtools_remoteexecution_v1test_remote_execution_proto",
+ "@googleapis//:google_longrunning_operations_proto",
"@googleapis//:google_rpc_status_proto",
],
)
diff --git a/src/main/protobuf/remote_execution_log.proto b/src/main/protobuf/remote_execution_log.proto
index c685bd3..81c8de9 100644
--- a/src/main/protobuf/remote_execution_log.proto
+++ b/src/main/protobuf/remote_execution_log.proto
@@ -17,6 +17,7 @@
package remote_logging;
import "google/devtools/remoteexecution/v1test/remote_execution.proto";
+import "google/longrunning/operations.proto";
import "google/rpc/status.proto";
option java_package = "com.google.devtools.build.lib.remote.logging";
@@ -33,4 +34,24 @@
// io.grpc.MethodDescriptor.getFullMethodName() (i.e. in format
// $FULL_SERVICE_NAME/$METHOD_NAME).
string method_name = 3;
+
+ // Method specific details for this call.
+ RpcCallDetails details = 4;
+}
+
+// Details for a call to
+// google.devtools.remoteexecution.v1test.Execution.Execute.
+message ExecuteDetails {
+ // The google.devtools.remoteexecution.v1test.ExecuteRequest sent by the
+ // call.
+ google.devtools.remoteexecution.v1test.ExecuteRequest request = 1;
+ // The google.longrunning.Operation received by the Execute call.
+ google.longrunning.Operation response = 2;
+}
+
+// Contains details for specific types of calls.
+message RpcCallDetails {
+ oneof details {
+ ExecuteDetails execute = 1;
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptorTest.java b/src/test/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptorTest.java
index b9c3d54..66221c7 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/logging/LoggingInterceptorTest.java
@@ -30,7 +30,16 @@
import com.google.bytestream.ByteStreamProto.ReadResponse;
import com.google.bytestream.ByteStreamProto.WriteRequest;
import com.google.bytestream.ByteStreamProto.WriteResponse;
+import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.ExecuteDetails;
import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.LogEntry;
+import com.google.devtools.build.lib.remote.logging.RemoteExecutionLog.RpcCallDetails;
+import com.google.devtools.build.lib.util.io.AsynchronousFileOutputStream;
+import com.google.devtools.remoteexecution.v1test.Action;
+import com.google.devtools.remoteexecution.v1test.ExecuteRequest;
+import com.google.devtools.remoteexecution.v1test.ExecutionGrpc;
+import com.google.devtools.remoteexecution.v1test.ExecutionGrpc.ExecutionBlockingStub;
+import com.google.devtools.remoteexecution.v1test.ExecutionGrpc.ExecutionImplBase;
+import com.google.longrunning.Operation;
import com.google.protobuf.ByteString;
import io.grpc.Channel;
import io.grpc.ClientInterceptors;
@@ -59,8 +68,9 @@
// This returns a logging interceptor where all calls are handled by the given handler.
@SuppressWarnings({"rawtypes", "unchecked"})
- private LoggingInterceptor getInterceptorWithAlwaysThisHandler(LoggingHandler handler) {
- return new LoggingInterceptor() {
+ private LoggingInterceptor getInterceptorWithAlwaysThisHandler(
+ LoggingHandler handler, AsynchronousFileOutputStream outputFile) {
+ return new LoggingInterceptor(outputFile) {
@Override
public <ReqT, RespT> LoggingHandler<ReqT, RespT> selectHandler(
MethodDescriptor<ReqT, RespT> method) {
@@ -103,18 +113,28 @@
@SuppressWarnings("unchecked")
LoggingHandler<ReadRequest, ReadResponse> handler = Mockito.mock(LoggingHandler.class);
- Mockito.when(handler.getEntry()).thenReturn(LogEntry.getDefaultInstance());
+ RpcCallDetails details = RpcCallDetails.getDefaultInstance();
+ Mockito.when(handler.getDetails()).thenReturn(details);
+ AsynchronousFileOutputStream output = Mockito.mock(AsynchronousFileOutputStream.class);
- LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler);
+ LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler, output);
Channel channel =
ClientInterceptors.intercept(
InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), interceptor);
ByteStreamBlockingStub stub = ByteStreamGrpc.newBlockingStub(channel);
+ LogEntry expectedEntry =
+ LogEntry.newBuilder()
+ .setMethodName(ByteStreamGrpc.getReadMethod().getFullMethodName())
+ .setDetails(details)
+ .setStatus(com.google.rpc.Status.getDefaultInstance())
+ .build();
+
stub.read(request).next();
verify(handler).handleReq(request);
verify(handler).handleResp(response);
- verify(handler).getEntry();
+ verify(handler).getDetails();
+ verify(output).write(expectedEntry);
}
@Test
@@ -136,9 +156,11 @@
@SuppressWarnings("unchecked")
LoggingHandler<ReadRequest, ReadResponse> handler = Mockito.mock(LoggingHandler.class);
- Mockito.when(handler.getEntry()).thenReturn(LogEntry.getDefaultInstance());
+ RpcCallDetails details = RpcCallDetails.getDefaultInstance();
+ Mockito.when(handler.getDetails()).thenReturn(details);
+ AsynchronousFileOutputStream output = Mockito.mock(AsynchronousFileOutputStream.class);
- LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler);
+ LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler, output);
Channel channel =
ClientInterceptors.intercept(
InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), interceptor);
@@ -149,11 +171,19 @@
ArgumentCaptor<ReadResponse> resultCaptor = ArgumentCaptor.forClass(ReadResponse.class);
+ LogEntry expectedEntry =
+ LogEntry.newBuilder()
+ .setMethodName(ByteStreamGrpc.getReadMethod().getFullMethodName())
+ .setDetails(details)
+ .setStatus(com.google.rpc.Status.getDefaultInstance())
+ .build();
+
verify(handler).handleReq(request);
verify(handler, times(2)).handleResp(resultCaptor.capture());
assertThat(resultCaptor.getAllValues().get(0)).isEqualTo(response1);
assertThat(resultCaptor.getAllValues().get(1)).isEqualTo(response2);
- verify(handler).getEntry();
+ verify(handler).getDetails();
+ verify(output).write(expectedEntry);
}
@Test
@@ -191,9 +221,11 @@
@SuppressWarnings("unchecked")
LoggingHandler<WriteRequest, WriteResponse> handler = Mockito.mock(LoggingHandler.class);
- Mockito.when(handler.getEntry()).thenReturn(LogEntry.getDefaultInstance());
+ RpcCallDetails details = RpcCallDetails.getDefaultInstance();
+ Mockito.when(handler.getDetails()).thenReturn(details);
+ AsynchronousFileOutputStream output = Mockito.mock(AsynchronousFileOutputStream.class);
- LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler);
+ LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler, output);
Channel channel =
ClientInterceptors.intercept(
InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), interceptor);
@@ -209,11 +241,19 @@
ArgumentCaptor<WriteRequest> resultCaptor = ArgumentCaptor.forClass(WriteRequest.class);
+ LogEntry expectedEntry =
+ LogEntry.newBuilder()
+ .setMethodName(ByteStreamGrpc.getWriteMethod().getFullMethodName())
+ .setDetails(details)
+ .setStatus(com.google.rpc.Status.getDefaultInstance())
+ .build();
+
verify(handler, times(2)).handleReq(resultCaptor.capture());
assertThat(resultCaptor.getAllValues().get(0)).isEqualTo(request1);
assertThat(resultCaptor.getAllValues().get(1)).isEqualTo(request2);
verify(handler).handleResp(response);
- verify(handler).getEntry();
+ verify(handler).getDetails();
+ verify(output).write(expectedEntry);
}
@Test
@@ -231,9 +271,11 @@
@SuppressWarnings("unchecked")
LoggingHandler<ReadRequest, ReadResponse> handler = Mockito.mock(LoggingHandler.class);
- Mockito.when(handler.getEntry()).thenReturn(LogEntry.getDefaultInstance());
+ RpcCallDetails details = RpcCallDetails.getDefaultInstance();
+ Mockito.when(handler.getDetails()).thenReturn(details);
+ AsynchronousFileOutputStream output = Mockito.mock(AsynchronousFileOutputStream.class);
- LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler);
+ LoggingInterceptor interceptor = getInterceptorWithAlwaysThisHandler(handler, output);
Channel channel =
ClientInterceptors.intercept(
InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), interceptor);
@@ -241,8 +283,57 @@
assertThrows(StatusRuntimeException.class, () -> stub.read(request).next());
+ LogEntry expectedEntry =
+ LogEntry.newBuilder()
+ .setMethodName(ByteStreamGrpc.getReadMethod().getFullMethodName())
+ .setDetails(details)
+ .setStatus(
+ com.google.rpc.Status.newBuilder()
+ .setCode(error.getCode().value())
+ .setMessage("not found"))
+ .build();
+
verify(handler).handleReq(request);
verify(handler, never()).handleResp(any());
- verify(handler).getEntry();
+ verify(handler).getDetails();
+ verify(output).write(expectedEntry);
+ }
+
+ @Test
+ public void testExecuteCallOk() {
+ ExecuteRequest request =
+ ExecuteRequest.newBuilder()
+ .setInstanceName("test-instance")
+ .setAction(Action.newBuilder().addOutputFiles("somefile"))
+ .build();
+ Operation response = Operation.newBuilder().setName("test-operation").build();
+ serviceRegistry.addService(
+ new ExecutionImplBase() {
+ @Override
+ public void execute(ExecuteRequest request, StreamObserver<Operation> responseObserver) {
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+ });
+
+ @SuppressWarnings("unchecked")
+ AsynchronousFileOutputStream output = Mockito.mock(AsynchronousFileOutputStream.class);
+ LoggingInterceptor interceptor = new LoggingInterceptor(output);
+ Channel channel =
+ ClientInterceptors.intercept(
+ InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), interceptor);
+ ExecutionBlockingStub stub = ExecutionGrpc.newBlockingStub(channel);
+
+ stub.execute(request);
+ LogEntry expectedEntry =
+ LogEntry.newBuilder()
+ .setMethodName(ExecutionGrpc.getExecuteMethod().getFullMethodName())
+ .setDetails(
+ RpcCallDetails.newBuilder()
+ .setExecute(
+ ExecuteDetails.newBuilder().setRequest(request).setResponse(response)))
+ .setStatus(com.google.rpc.Status.getDefaultInstance())
+ .build();
+ verify(output).write(expectedEntry);
}
}