1 /* 2 * Copyright 2016 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.testing; 18 19 import static com.google.common.base.Preconditions.checkState; 20 21 import io.grpc.BindableService; 22 import io.grpc.ExperimentalApi; 23 import io.grpc.ManagedChannel; 24 import io.grpc.Server; 25 import io.grpc.ServerServiceDefinition; 26 import io.grpc.inprocess.InProcessChannelBuilder; 27 import io.grpc.inprocess.InProcessServerBuilder; 28 import io.grpc.stub.AbstractStub; 29 import io.grpc.util.MutableHandlerRegistry; 30 import java.util.UUID; 31 import java.util.concurrent.TimeUnit; 32 import org.junit.rules.ExternalResource; 33 import org.junit.rules.TestRule; 34 35 /** 36 * {@code GrpcServerRule} is a JUnit {@link TestRule} that starts an in-process gRPC service with 37 * a {@link MutableHandlerRegistry} for adding services. It is particularly useful for mocking out 38 * external gRPC-based services and asserting that the expected requests were made. 39 * 40 * <p>An {@link AbstractStub} can be created against this service by using the 41 * {@link ManagedChannel} provided by {@link GrpcServerRule#getChannel()}. 42 */ 43 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2488") 44 public final class GrpcServerRule extends ExternalResource { 45 46 private ManagedChannel channel; 47 private Server server; 48 private String serverName; 49 private MutableHandlerRegistry serviceRegistry; 50 private boolean useDirectExecutor; 51 52 /** 53 * Returns {@code this} configured to use a direct executor for the {@link ManagedChannel} and 54 * {@link Server}. This can only be called at the rule instantiation. 55 */ directExecutor()56 public final GrpcServerRule directExecutor() { 57 checkState(serverName == null, "directExecutor() can only be called at the rule instantiation"); 58 useDirectExecutor = true; 59 return this; 60 } 61 62 /** 63 * Returns a {@link ManagedChannel} connected to this service. 64 */ getChannel()65 public final ManagedChannel getChannel() { 66 return channel; 67 } 68 69 /** 70 * Returns the underlying gRPC {@link Server} for this service. 71 */ getServer()72 public final Server getServer() { 73 return server; 74 } 75 76 /** 77 * Returns the randomly generated server name for this service. 78 */ getServerName()79 public final String getServerName() { 80 return serverName; 81 } 82 83 /** 84 * Returns the service registry for this service. The registry is used to add service instances 85 * (e.g. {@link BindableService} or {@link ServerServiceDefinition} to the server. 86 */ getServiceRegistry()87 public final MutableHandlerRegistry getServiceRegistry() { 88 return serviceRegistry; 89 } 90 91 /** 92 * After the test has completed, clean up the channel and server. 93 */ 94 @Override after()95 protected void after() { 96 serverName = null; 97 serviceRegistry = null; 98 99 channel.shutdown(); 100 server.shutdown(); 101 102 try { 103 channel.awaitTermination(1, TimeUnit.MINUTES); 104 server.awaitTermination(1, TimeUnit.MINUTES); 105 } catch (InterruptedException e) { 106 Thread.currentThread().interrupt(); 107 throw new RuntimeException(e); 108 } finally { 109 channel.shutdownNow(); 110 channel = null; 111 112 server.shutdownNow(); 113 server = null; 114 } 115 } 116 117 /** 118 * Before the test has started, create the server and channel. 119 */ 120 @Override before()121 protected void before() throws Throwable { 122 serverName = UUID.randomUUID().toString(); 123 124 serviceRegistry = new MutableHandlerRegistry(); 125 126 InProcessServerBuilder serverBuilder = InProcessServerBuilder.forName(serverName) 127 .fallbackHandlerRegistry(serviceRegistry); 128 129 if (useDirectExecutor) { 130 serverBuilder.directExecutor(); 131 } 132 133 server = serverBuilder.build().start(); 134 135 InProcessChannelBuilder channelBuilder = InProcessChannelBuilder.forName(serverName); 136 137 if (useDirectExecutor) { 138 channelBuilder.directExecutor(); 139 } 140 141 channel = channelBuilder.build(); 142 } 143 } 144