Skip to content

Commit 7b87dd5

Browse files
committed
Server code for the interoperability tests of the grpc-web repo.
https://github.com/grpc/grpc-web/blob/a639b4cf2611de2b68883571787083b73cf61f5e/doc/interop-test-descriptions.md All tests pass using manual verification Signed-off-by: Thomas Segismont <tsegismont@gmail.com>
1 parent c20bd05 commit 7b87dd5

3 files changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.grpc.server.web.interop;
13+
14+
import io.grpc.*;
15+
import io.grpc.Metadata.Key;
16+
17+
import java.util.Collections;
18+
import java.util.Set;
19+
20+
import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;
21+
import static io.grpc.Metadata.BINARY_BYTE_MARSHALLER;
22+
23+
class Interceptor implements ServerInterceptor {
24+
25+
private static final Key<String> ECHO_INITIAL_KEY = Key.of("x-grpc-test-echo-initial", ASCII_STRING_MARSHALLER);
26+
private static final Set<Key<?>> HEADERS_KEY_SET = Collections.singleton(ECHO_INITIAL_KEY);
27+
private static final Key<byte[]> ECHO_TRAILING_KEY = Key.of("x-grpc-test-echo-trailing-bin", BINARY_BYTE_MARSHALLER);
28+
private static final Set<Key<?>> TRAILERS_KEY_SET = Collections.singleton(ECHO_TRAILING_KEY);
29+
30+
@Override
31+
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata metadata, ServerCallHandler<ReqT, RespT> next) {
32+
return next.startCall(new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
33+
34+
@Override
35+
public void sendHeaders(Metadata headers) {
36+
headers.merge(metadata, HEADERS_KEY_SET);
37+
super.sendHeaders(headers);
38+
}
39+
40+
@Override
41+
public void close(Status status, Metadata trailers) {
42+
trailers.merge(metadata, TRAILERS_KEY_SET);
43+
super.close(status, trailers);
44+
}
45+
}, metadata);
46+
}
47+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.grpc.server.web.interop;
13+
14+
import io.grpc.ServerInterceptors;
15+
import io.grpc.ServerServiceDefinition;
16+
import io.vertx.core.AbstractVerticle;
17+
import io.vertx.core.Promise;
18+
import io.vertx.core.Vertx;
19+
import io.vertx.grpc.server.GrpcServer;
20+
import io.vertx.grpc.server.GrpcServerOptions;
21+
import io.vertx.grpc.server.GrpcServiceBridge;
22+
23+
/**
24+
* A gRPC-Web server for grpc-web interop tests.
25+
*/
26+
public class InteropServer extends AbstractVerticle {
27+
28+
public static void main(String[] args) {
29+
Vertx vertx = Vertx.vertx();
30+
vertx.deployVerticle(new InteropServer())
31+
.onFailure(Throwable::printStackTrace)
32+
.onSuccess(v -> System.out.println("Deployed InteropServer"));
33+
}
34+
35+
@Override
36+
public void start(Promise<Void> startPromise) {
37+
GrpcServer grpcServer = GrpcServer.server(vertx, new GrpcServerOptions().setGrpcWebEnabled(true));
38+
39+
ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(new TestServiceImpl(vertx), new Interceptor());
40+
GrpcServiceBridge.bridge(serviceDefinition).bind(grpcServer);
41+
42+
vertx.createHttpServer()
43+
.requestHandler(grpcServer)
44+
.listen(8080)
45+
.<Void>mapEmpty()
46+
.onComplete(startPromise);
47+
}
48+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.grpc.server.web.interop;
13+
14+
import com.google.protobuf.ByteString;
15+
import grpc.testing.EmptyOuterClass;
16+
import grpc.testing.Messages;
17+
import grpc.testing.TestServiceGrpc;
18+
import io.grpc.Status;
19+
import io.grpc.StatusException;
20+
import io.grpc.stub.StreamObserver;
21+
import io.vertx.core.Future;
22+
import io.vertx.core.Promise;
23+
import io.vertx.core.Vertx;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
import static java.util.concurrent.TimeUnit.MICROSECONDS;
29+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
30+
31+
class TestServiceImpl extends TestServiceGrpc.TestServiceImplBase {
32+
33+
private final Vertx vertx;
34+
35+
TestServiceImpl(Vertx vertx) {
36+
this.vertx = vertx;
37+
}
38+
39+
@Override
40+
public void emptyCall(EmptyOuterClass.Empty request, StreamObserver<EmptyOuterClass.Empty> responseObserver) {
41+
responseObserver.onNext(EmptyOuterClass.Empty.newBuilder().build());
42+
responseObserver.onCompleted();
43+
}
44+
45+
@Override
46+
public void unaryCall(Messages.SimpleRequest request, StreamObserver<Messages.SimpleResponse> responseObserver) {
47+
if (request.hasResponseStatus()) {
48+
Messages.EchoStatus echoStatus = request.getResponseStatus();
49+
Status status = Status.fromCodeValue(echoStatus.getCode())
50+
.withDescription(echoStatus.getMessage());
51+
responseObserver.onError(new StatusException(status));
52+
return;
53+
}
54+
Messages.Payload payload = Messages.Payload.newBuilder()
55+
.setTypeValue(request.getResponseTypeValue())
56+
.setBody(ByteString.copyFrom(new byte[request.getResponseSize()]))
57+
.build();
58+
Messages.SimpleResponse response = Messages.SimpleResponse.newBuilder()
59+
.setPayload(payload)
60+
.build();
61+
responseObserver.onNext(response);
62+
responseObserver.onCompleted();
63+
}
64+
65+
@Override
66+
public void streamingOutputCall(Messages.StreamingOutputCallRequest request, StreamObserver<Messages.StreamingOutputCallResponse> responseObserver) {
67+
List<Future<Void>> futures = new ArrayList<>(request.getResponseParametersCount());
68+
long delay = 0;
69+
for (Messages.ResponseParameters parameters : request.getResponseParametersList()) {
70+
delay += Math.max(1, MILLISECONDS.convert(parameters.getIntervalUs(), MICROSECONDS));
71+
Promise<Void> promise = Promise.promise();
72+
vertx.setTimer(delay, l -> {
73+
Messages.Payload payload = Messages.Payload.newBuilder()
74+
.setType(request.getResponseType())
75+
.setBody(ByteString.copyFrom(new byte[parameters.getSize()]))
76+
.build();
77+
Messages.StreamingOutputCallResponse response = Messages.StreamingOutputCallResponse.newBuilder()
78+
.setPayload(payload)
79+
.build();
80+
responseObserver.onNext(response);
81+
promise.complete();
82+
});
83+
futures.add(promise.future());
84+
}
85+
Future.join(futures).onComplete(v -> responseObserver.onCompleted());
86+
}
87+
}

0 commit comments

Comments
 (0)