• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 com.google.common.truth.Truth.assertWithMessage;
20 
21 import com.google.common.collect.Iterators;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Method;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27 import java.util.regex.Pattern;
28 
29 final class ServiceProvidersTestUtil {
30   /**
31    * Creates an iterator from the callable class via reflection, and checks that all expected
32    * classes were loaded.
33    *
34    * <p>{@code callableClassName} is a {@code Callable<Iterable<Class<?>>} rather than the iterable
35    * class name itself so that the iterable class can be non-public.
36    *
37    * <p>We accept class names as input so that we can test against classes not in the
38    * testing class path.
39    */
testHardcodedClasses( String callableClassName, ClassLoader cl, Set<String> hardcodedClassNames)40   static void testHardcodedClasses(
41       String callableClassName,
42       ClassLoader cl,
43       Set<String> hardcodedClassNames) throws Exception {
44     final Set<String> notLoaded = new HashSet<>(hardcodedClassNames);
45     cl = new ClassLoader(cl) {
46       @Override
47       public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
48         if (notLoaded.remove(name)) {
49           throw new ClassNotFoundException();
50         } else {
51           return super.loadClass(name, resolve);
52         }
53       }
54     };
55     cl = new StaticTestingClassLoader(cl, Pattern.compile("io\\.grpc\\.[^.]*"));
56     // Some classes fall back to the context class loader.
57     // Ensure that the context class loader is not an accidental backdoor.
58     ClassLoader ccl = Thread.currentThread().getContextClassLoader();
59     try {
60       Thread.currentThread().setContextClassLoader(cl);
61       Object[] results = Iterators.toArray(
62           invokeIteratorCallable(callableClassName, cl), Object.class);
63       assertWithMessage("The Iterable loaded a class that was not in hardcodedClassNames")
64           .that(results).isEmpty();
65       assertWithMessage(
66           "The Iterable did not attempt to load some classes from hardcodedClassNames")
67           .that(notLoaded).isEmpty();
68     } finally {
69       Thread.currentThread().setContextClassLoader(ccl);
70     }
71   }
72 
invokeIteratorCallable( String callableClassName, ClassLoader cl)73   private static Iterator<?> invokeIteratorCallable(
74       String callableClassName, ClassLoader cl) throws Exception {
75     Class<?> klass = Class.forName(callableClassName, true, cl);
76     Constructor<?> ctor = klass.getDeclaredConstructor();
77     Object instance = ctor.newInstance();
78     Method callMethod = klass.getMethod("call");
79     return (Iterator<?>) callMethod.invoke(instance);
80   }
81 }
82