• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import com.google.common.collect.ImmutableList;
27 import io.grpc.InternalServiceProviders.PriorityAccessor;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.ServiceConfigurationError;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.junit.runners.JUnit4;
35 
36 /** Unit tests for {@link ServiceProviders}. */
37 @RunWith(JUnit4.class)
38 public class ServiceProvidersTest {
39   private static final List<Class<?>> NO_HARDCODED = Collections.emptyList();
40   private static final PriorityAccessor<ServiceProvidersTestAbstractProvider> ACCESSOR =
41       new PriorityAccessor<ServiceProvidersTestAbstractProvider>() {
42         @Override
43         public boolean isAvailable(ServiceProvidersTestAbstractProvider provider) {
44           return provider.isAvailable();
45         }
46 
47         @Override
48         public int getPriority(ServiceProvidersTestAbstractProvider provider) {
49           return provider.priority();
50         }
51       };
52   private final String serviceFile =
53       "META-INF/services/io.grpc.ServiceProvidersTestAbstractProvider";
54 
55   @Test
contextClassLoaderProvider()56   public void contextClassLoaderProvider() {
57     ClassLoader ccl = Thread.currentThread().getContextClassLoader();
58     try {
59       ClassLoader cl = new ReplacingClassLoader(
60           getClass().getClassLoader(),
61           serviceFile,
62           "io/grpc/ServiceProvidersTestAbstractProvider-multipleProvider.txt");
63 
64       // test that the context classloader is used as fallback
65       ClassLoader rcll = new ReplacingClassLoader(
66           getClass().getClassLoader(),
67           serviceFile,
68           "io/grpc/ServiceProvidersTestAbstractProvider-empty.txt");
69       Thread.currentThread().setContextClassLoader(rcll);
70       assertEquals(
71           Available7Provider.class,
72           ServiceProviders.load(
73               ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR).getClass());
74     } finally {
75       Thread.currentThread().setContextClassLoader(ccl);
76     }
77   }
78 
79   @Test
noProvider()80   public void noProvider() {
81     ClassLoader ccl = Thread.currentThread().getContextClassLoader();
82     try {
83       ClassLoader cl = new ReplacingClassLoader(
84           getClass().getClassLoader(),
85           serviceFile,
86           "io/grpc/ServiceProvidersTestAbstractProvider-doesNotExist.txt");
87       Thread.currentThread().setContextClassLoader(cl);
88       assertNull(ServiceProviders.load(
89           ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR));
90     } finally {
91       Thread.currentThread().setContextClassLoader(ccl);
92     }
93   }
94 
95   @Test
multipleProvider()96   public void multipleProvider() throws Exception {
97     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
98         "io/grpc/ServiceProvidersTestAbstractProvider-multipleProvider.txt");
99     assertSame(
100         Available7Provider.class,
101         ServiceProviders.load(
102             ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR).getClass());
103 
104     List<ServiceProvidersTestAbstractProvider> providers = ServiceProviders.loadAll(
105         ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR);
106     assertEquals(3, providers.size());
107     assertEquals(Available7Provider.class, providers.get(0).getClass());
108     assertEquals(Available5Provider.class, providers.get(1).getClass());
109     assertEquals(Available0Provider.class, providers.get(2).getClass());
110   }
111 
112   @Test
unavailableProvider()113   public void unavailableProvider() {
114     // tries to load Available7 and UnavailableProvider, which has priority 10
115     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
116         "io/grpc/ServiceProvidersTestAbstractProvider-unavailableProvider.txt");
117     assertEquals(
118         Available7Provider.class,
119         ServiceProviders.load(
120             ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR).getClass());
121   }
122 
123   @Test
unknownClassProvider()124   public void unknownClassProvider() {
125     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
126         "io/grpc/ServiceProvidersTestAbstractProvider-unknownClassProvider.txt");
127     try {
128       ServiceProviders.load(
129           ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR);
130       fail("Exception expected");
131     } catch (ServiceConfigurationError e) {
132       // noop
133     }
134   }
135 
136   @Test
exceptionSurfacedToCaller_failAtInit()137   public void exceptionSurfacedToCaller_failAtInit() {
138     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
139         "io/grpc/ServiceProvidersTestAbstractProvider-failAtInitProvider.txt");
140     try {
141       // Even though there is a working provider, if any providers fail then we should fail
142       // completely to avoid returning something unexpected.
143       ServiceProviders.load(
144           ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR);
145       fail("Expected exception");
146     } catch (ServiceConfigurationError expected) {
147       // noop
148     }
149   }
150 
151   @Test
exceptionSurfacedToCaller_failAtPriority()152   public void exceptionSurfacedToCaller_failAtPriority() {
153     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
154         "io/grpc/ServiceProvidersTestAbstractProvider-failAtPriorityProvider.txt");
155     try {
156       // The exception should be surfaced to the caller
157       ServiceProviders.load(
158           ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR);
159       fail("Expected exception");
160     } catch (FailAtPriorityProvider.PriorityException expected) {
161       // noop
162     }
163   }
164 
165   @Test
exceptionSurfacedToCaller_failAtAvailable()166   public void exceptionSurfacedToCaller_failAtAvailable() {
167     ClassLoader cl = new ReplacingClassLoader(getClass().getClassLoader(), serviceFile,
168         "io/grpc/ServiceProvidersTestAbstractProvider-failAtAvailableProvider.txt");
169     try {
170       // The exception should be surfaced to the caller
171       ServiceProviders.load(
172           ServiceProvidersTestAbstractProvider.class, NO_HARDCODED, cl, ACCESSOR);
173       fail("Expected exception");
174     } catch (FailAtAvailableProvider.AvailableException expected) {
175       // noop
176     }
177   }
178 
179   @Test
getCandidatesViaHardCoded_multipleProvider()180   public void getCandidatesViaHardCoded_multipleProvider() throws Exception {
181     Iterator<ServiceProvidersTestAbstractProvider> candidates =
182         ServiceProviders.getCandidatesViaHardCoded(
183             ServiceProvidersTestAbstractProvider.class,
184             ImmutableList.<Class<?>>of(
185                 Available7Provider.class,
186                 Available0Provider.class))
187             .iterator();
188     assertEquals(Available7Provider.class, candidates.next().getClass());
189     assertEquals(Available0Provider.class, candidates.next().getClass());
190     assertFalse(candidates.hasNext());
191   }
192 
193   @Test
getCandidatesViaHardCoded_failAtInit()194   public void getCandidatesViaHardCoded_failAtInit() throws Exception {
195     try {
196       ServiceProviders.getCandidatesViaHardCoded(
197           ServiceProvidersTestAbstractProvider.class,
198           Collections.<Class<?>>singletonList(FailAtInitProvider.class));
199       fail("Expected exception");
200     } catch (ServiceConfigurationError expected) {
201       // noop
202     }
203   }
204 
205   @Test
getCandidatesViaHardCoded_failAtInit_moreCandidates()206   public void getCandidatesViaHardCoded_failAtInit_moreCandidates() throws Exception {
207     try {
208       ServiceProviders.getCandidatesViaHardCoded(
209           ServiceProvidersTestAbstractProvider.class,
210           ImmutableList.<Class<?>>of(FailAtInitProvider.class, Available0Provider.class));
211       fail("Expected exception");
212     } catch (ServiceConfigurationError expected) {
213       // noop
214     }
215   }
216 
217   @Test
getCandidatesViaHardCoded_throwsErrorOnMisconfiguration()218   public void getCandidatesViaHardCoded_throwsErrorOnMisconfiguration() throws Exception {
219     class PrivateClass extends BaseProvider {
220       private PrivateClass() {
221         super(true, 5);
222       }
223     }
224 
225     try {
226       ServiceProviders.getCandidatesViaHardCoded(
227           ServiceProvidersTestAbstractProvider.class,
228           Collections.<Class<?>>singletonList(PrivateClass.class));
229       fail("Expected exception");
230     } catch (ServiceConfigurationError expected) {
231       assertTrue("Expected NoSuchMethodException cause: " + expected.getCause(),
232           expected.getCause() instanceof NoSuchMethodException);
233     }
234   }
235 
236   @Test
getCandidatesViaHardCoded_skipsWrongClassType()237   public void getCandidatesViaHardCoded_skipsWrongClassType() throws Exception {
238     class RandomClass {}
239 
240     Iterable<ServiceProvidersTestAbstractProvider> candidates =
241         ServiceProviders.getCandidatesViaHardCoded(
242             ServiceProvidersTestAbstractProvider.class,
243             Collections.<Class<?>>singletonList(RandomClass.class));
244     assertFalse(candidates.iterator().hasNext());
245   }
246 
247   private static class BaseProvider extends ServiceProvidersTestAbstractProvider {
248     private final boolean isAvailable;
249     private final int priority;
250 
BaseProvider(boolean isAvailable, int priority)251     public BaseProvider(boolean isAvailable, int priority) {
252       this.isAvailable = isAvailable;
253       this.priority = priority;
254     }
255 
256     @Override
isAvailable()257     public boolean isAvailable() {
258       return isAvailable;
259     }
260 
261     @Override
priority()262     public int priority() {
263       return priority;
264     }
265   }
266 
267   public static final class Available0Provider extends BaseProvider {
Available0Provider()268     public Available0Provider() {
269       super(true, 0);
270     }
271   }
272 
273   public static final class Available5Provider extends BaseProvider {
Available5Provider()274     public Available5Provider() {
275       super(true, 5);
276     }
277   }
278 
279   public static final class Available7Provider extends BaseProvider {
Available7Provider()280     public Available7Provider() {
281       super(true, 7);
282     }
283   }
284 
285   public static final class UnavailableProvider extends BaseProvider {
UnavailableProvider()286     public UnavailableProvider() {
287       super(false, 10);
288     }
289   }
290 
291   public static final class FailAtInitProvider extends ServiceProvidersTestAbstractProvider {
FailAtInitProvider()292     public FailAtInitProvider() {
293       throw new RuntimeException("intentionally broken");
294     }
295 
296     @Override
isAvailable()297     public boolean isAvailable() {
298       return true;
299     }
300 
301     @Override
priority()302     public int priority() {
303       return 0;
304     }
305   }
306 
307   public static final class FailAtPriorityProvider extends ServiceProvidersTestAbstractProvider {
308     @Override
isAvailable()309     public boolean isAvailable() {
310       return true;
311     }
312 
313     @Override
priority()314     public int priority() {
315       throw new PriorityException();
316     }
317 
318     public static final class PriorityException extends RuntimeException {}
319   }
320 
321   public static final class FailAtAvailableProvider extends ServiceProvidersTestAbstractProvider {
322     @Override
isAvailable()323     public boolean isAvailable() {
324       throw new AvailableException();
325     }
326 
327     @Override
priority()328     public int priority() {
329       return 0;
330     }
331 
332     public static final class AvailableException extends RuntimeException {}
333   }
334 }
335