Wraps gRPC server-mocking patterns for client-side tests: Go bufconn (in-memory net.Listener via google.golang.org/grpc/test/bufconn) + mockgen-generated interface mocks, Python pytest-grpc fixtures + unittest.mock patching of stubs, JVM grpc-mock library / in-process gRPC server (InProcessServerBuilder), Node @grpc/grpc-js fake server with NewServer-on-port-0. Also carries the interceptor-layer test patterns (Go / Java / grpc-js auth, retry, logging, error-mapping, chained ordering via a spy handler) in references/interceptors.md. Use when writing client-side tests that need a controllable gRPC server response (success cases, error cases, timeouts, single-response error injection) without spinning up a real backend, or when testing a gRPC interceptor. For multi-message streaming-sequence tests (server-streaming, bidi), use grpc-streaming-test-author instead. Distinct from grpcurl-cli (ad-hoc CLI invocation against a real server) and ghz-load (perf against a real server).
71
89%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Java interceptors are objects; call interceptCall directly with stubbed
ServerCall / Channel collaborators (Mockito) and assert on captured
Status and Metadata.
ServerInterceptor.interceptCall signature per
grpc-java javadoc:
<ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next)Test with a ServerCall stub that captures the close() call:
import io.grpc.*;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class AuthInterceptorTest {
private final ServerInterceptor interceptor = new AuthInterceptor();
@SuppressWarnings("unchecked")
@Test
public void missingAuthHeader_closesWithUnauthenticated() {
ServerCall<Object, Object> call = mock(ServerCall.class);
Metadata headers = new Metadata(); // no authorization key
ServerCallHandler<Object, Object> next = mock(ServerCallHandler.class);
interceptor.interceptCall(call, headers, next);
verify(call).close(
argThat(s -> s.getCode() == Status.Code.UNAUTHENTICATED),
any(Metadata.class));
verifyNoInteractions(next);
}
}Registration per grpc-java javadoc ServerInterceptors.intercept
intercept() applies interceptors in reverse order (last
interceptor's interceptCall fires first); use interceptForward()
to preserve declaration order:// Last-listed interceptor fires first:
ServerServiceDefinition def =
ServerInterceptors.intercept(serviceImpl, authInterceptor, loggingInterceptor);
// First-listed interceptor fires first:
ServerServiceDefinition def =
ServerInterceptors.interceptForward(serviceImpl, authInterceptor, loggingInterceptor);ClientInterceptor.interceptCall signature per
grpc-java javadoc:
<ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next)Test that the interceptor attaches the authorization key to outbound
headers by capturing Metadata passed to ClientCall.start():
@Test
public void tokenInjector_attachesAuthorizationHeader() {
ClientInterceptor interceptor = new TokenInjectorInterceptor("Bearer tok");
Channel channel = mock(Channel.class);
ClientCall<Object, Object> innerCall = mock(ClientCall.class);
when(channel.newCall(any(), any())).thenReturn(innerCall);
ClientCall<Object, Object> call =
interceptor.interceptCall(methodDescriptor(), CallOptions.DEFAULT, channel);
Metadata headers = new Metadata();
call.start(mock(ClientCall.Listener.class), headers);
String auth = headers.get(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER));
assertEquals("Bearer tok", auth);
}