• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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