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. Prefer {@link GrpcCleanupRule} in new code. 38 * 39 * <p>{@code GrpcServerRule} is useful for testing gRPC-based clients and services. However, 40 * because {@code GrpcServerRule} does not support useful features such as transport 41 * types other than in-process, multiple channels per server, custom channel or server builder 42 * options, and configuration inside individual test methods, users would end up to a difficult 43 * situation when later they want to make extensions to their tests that were using {@code 44 * GrpcServerRule}. Little benefit comes from proactively migrating existing code from {@code 45 * GrpcServerRule}, but new code is better served by explicit channel and server creation with 46 * {@code GrpcCleanupRule} managing resource lifetimes. 47 * 48 * <p>An {@link AbstractStub} can be created against this service by using the 49 * {@link ManagedChannel} provided by {@link GrpcServerRule#getChannel()}. 50 */ 51 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2488") 52 public final class GrpcServerRule extends ExternalResource { 53 54 private ManagedChannel channel; 55 private Server server; 56 private String serverName; 57 private MutableHandlerRegistry serviceRegistry; 58 private boolean useDirectExecutor; 59 60 /** 61 * Returns {@code this} configured to use a direct executor for the {@link ManagedChannel} and 62 * {@link Server}. This can only be called at the rule instantiation. 63 */ directExecutor()64 public final GrpcServerRule directExecutor() { 65 checkState(serverName == null, "directExecutor() can only be called at the rule instantiation"); 66 useDirectExecutor = true; 67 return this; 68 } 69 70 /** 71 * Returns a {@link ManagedChannel} connected to this service. 72 */ getChannel()73 public final ManagedChannel getChannel() { 74 return channel; 75 } 76 77 /** 78 * Returns the underlying gRPC {@link Server} for this service. 79 */ getServer()80 public final Server getServer() { 81 return server; 82 } 83 84 /** 85 * Returns the randomly generated server name for this service. 86 */ getServerName()87 public final String getServerName() { 88 return serverName; 89 } 90 91 /** 92 * Returns the service registry for this service. The registry is used to add service instances 93 * (e.g. {@link BindableService} or {@link ServerServiceDefinition} to the server. 94 */ getServiceRegistry()95 public final MutableHandlerRegistry getServiceRegistry() { 96 return serviceRegistry; 97 } 98 99 /** 100 * After the test has completed, clean up the channel and server. 101 */ 102 @Override after()103 protected void after() { 104 serverName = null; 105 serviceRegistry = null; 106 107 channel.shutdown(); 108 server.shutdown(); 109 110 try { 111 channel.awaitTermination(1, TimeUnit.MINUTES); 112 server.awaitTermination(1, TimeUnit.MINUTES); 113 } catch (InterruptedException e) { 114 Thread.currentThread().interrupt(); 115 throw new RuntimeException(e); 116 } finally { 117 channel.shutdownNow(); 118 channel = null; 119 120 server.shutdownNow(); 121 server = null; 122 } 123 } 124 125 /** 126 * Before the test has started, create the server and channel. 127 */ 128 @Override before()129 protected void before() throws Throwable { 130 serverName = UUID.randomUUID().toString(); 131 132 serviceRegistry = new MutableHandlerRegistry(); 133 134 InProcessServerBuilder serverBuilder = InProcessServerBuilder.forName(serverName) 135 .fallbackHandlerRegistry(serviceRegistry); 136 137 if (useDirectExecutor) { 138 serverBuilder.directExecutor(); 139 } 140 141 server = serverBuilder.build().start(); 142 143 InProcessChannelBuilder channelBuilder = InProcessChannelBuilder.forName(serverName); 144 145 if (useDirectExecutor) { 146 channelBuilder.directExecutor(); 147 } 148 149 channel = channelBuilder.build(); 150 } 151 } 152