• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.truth.Truth.assertWithMessage;
12 
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.reflect.ClassPath;
15 import protobuf_unittest.NonNestedExtension;
16 import protobuf_unittest.NonNestedExtensionLite;
17 import java.io.IOException;
18 import java.lang.reflect.Method;
19 import java.net.URL;
20 import java.net.URLClassLoader;
21 import junit.framework.Test;
22 import junit.framework.TestCase;
23 import junit.framework.TestSuite;
24 import org.junit.Ignore;
25 
26 /**
27  * Tests for {@link ExtensionRegistryFactory} and the {@link ExtensionRegistry} instances it
28  * creates.
29  *
30  * <p>This test simulates the runtime behaviour of the ExtensionRegistryFactory by delegating test
31  * definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of which
32  * is executed using a custom ClassLoader, simulating the ProtoLite environment.
33  *
34  * <p>The test mechanism employed here is based on the pattern in {@code
35  * com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
36  *
37  * <p>This test is temporarily disabled while we figure out how to fix the class loading used for
38  * testing lite functionality.
39  */
40 @SuppressWarnings("JUnit4ClassUsedInJUnit3")
41 @Ignore
42 public class ExtensionRegistryFactoryTest extends TestCase {
43 
44   // A classloader which blacklists some non-Lite classes.
45   private static final ClassLoader LITE_CLASS_LOADER = getLiteOnlyClassLoader();
46 
47   /** Defines the set of test methods which will be run. */
48   static interface RegistryTests {
testCreate()49     void testCreate();
50 
testEmpty()51     void testEmpty();
52 
testIsFullRegistry()53     void testIsFullRegistry();
54 
testAdd()55     void testAdd();
56 
testAdd_immutable()57     void testAdd_immutable();
58   }
59 
60   /** Test implementations for the non-Lite usage of ExtensionRegistryFactory. */
61   public static class InnerTest implements RegistryTests {
62 
63     @Override
testCreate()64     public void testCreate() {
65       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
66 
67       assertThat(registry.getClass()).isEqualTo(ExtensionRegistry.class);
68     }
69 
70     @Override
testEmpty()71     public void testEmpty() {
72       ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
73 
74       assertThat(emptyRegistry.getClass()).isEqualTo(ExtensionRegistry.class);
75       assertThat(emptyRegistry).isEqualTo(ExtensionRegistry.EMPTY_REGISTRY);
76     }
77 
78     @Override
testIsFullRegistry()79     public void testIsFullRegistry() {
80       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
81       assertThat(ExtensionRegistryFactory.isFullRegistry(registry)).isTrue();
82     }
83 
84     @Override
testAdd()85     public void testAdd() {
86       ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance();
87       NonNestedExtensionLite.registerAllExtensions(registry1);
88       registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
89 
90       ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance();
91       NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
92       registry2.add(NonNestedExtension.nonNestedExtension);
93 
94       ExtensionRegistry fullRegistry1 = (ExtensionRegistry) registry1;
95       ExtensionRegistry fullRegistry2 = (ExtensionRegistry) registry2;
96 
97       assertWithMessage("Test is using a non-lite extension")
98           .that(NonNestedExtensionLite.nonNestedExtensionLite.getClass())
99           .isInstanceOf(GeneratedMessageLite.GeneratedExtension.class);
100       assertWithMessage("Extension is not registered in masqueraded full registry")
101           .that(fullRegistry1.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"))
102           .isNull();
103       GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
104           extension =
105               registry1.findLiteExtensionByNumber(
106                   NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
107       assertWithMessage("Extension registered in lite registry").that(extension).isNotNull();
108 
109       assertWithMessage("Test is using a non-lite extension")
110           .that(Extension.class.isAssignableFrom(NonNestedExtension.nonNestedExtension.getClass()))
111           .isTrue();
112       assertWithMessage("Extension is registered in masqueraded full registry")
113           .that(fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"))
114           .isNotNull();
115     }
116 
117     @Override
testAdd_immutable()118     public void testAdd_immutable() {
119       ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance().getUnmodifiable();
120       try {
121         NonNestedExtensionLite.registerAllExtensions(registry1);
122         assertWithMessage("expected exception").fail();
123       } catch (UnsupportedOperationException expected) {
124       }
125       try {
126         registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
127         assertWithMessage("expected exception").fail();
128       } catch (UnsupportedOperationException expected) {
129       }
130 
131       ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance().getUnmodifiable();
132       try {
133         NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
134         assertWithMessage("expected exception").fail();
135       } catch (IllegalArgumentException expected) {
136       }
137       try {
138         registry2.add(NonNestedExtension.nonNestedExtension);
139         assertWithMessage("expected exception").fail();
140       } catch (IllegalArgumentException expected) {
141       }
142     }
143   }
144 
145   /** Test implementations for the Lite usage of ExtensionRegistryFactory. */
146   public static final class InnerLiteTest implements RegistryTests {
147 
148     @Override
testCreate()149     public void testCreate() {
150       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
151 
152       assertThat(registry.getClass()).isEqualTo(ExtensionRegistryLite.class);
153     }
154 
155     @Override
testEmpty()156     public void testEmpty() {
157       ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
158 
159       assertThat(emptyRegistry.getClass()).isEqualTo(ExtensionRegistryLite.class);
160       assertThat(emptyRegistry).isEqualTo(ExtensionRegistryLite.EMPTY_REGISTRY_LITE);
161     }
162 
163     @Override
testIsFullRegistry()164     public void testIsFullRegistry() {
165       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
166       assertThat(ExtensionRegistryFactory.isFullRegistry(registry)).isFalse();
167     }
168 
169     @Override
testAdd()170     public void testAdd() {
171       ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
172       NonNestedExtensionLite.registerAllExtensions(registry);
173       GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
174           extension =
175               registry.findLiteExtensionByNumber(
176                   NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
177       assertWithMessage("Extension is registered in Lite registry").that(extension).isNotNull();
178     }
179 
180     @Override
testAdd_immutable()181     public void testAdd_immutable() {
182       ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance().getUnmodifiable();
183       try {
184         NonNestedExtensionLite.registerAllExtensions(registry);
185         assertWithMessage("expected exception").fail();
186       } catch (UnsupportedOperationException expected) {
187       }
188     }
189   }
190 
191   /** Defines a suite of tests which the JUnit3 runner retrieves by reflection. */
suite()192   public static Test suite() {
193     TestSuite suite = new TestSuite();
194     for (Method method : RegistryTests.class.getMethods()) {
195       suite.addTest(TestSuite.createTest(ExtensionRegistryFactoryTest.class, method.getName()));
196     }
197     return suite;
198   }
199 
200   /**
201    * Sequentially runs first the Lite and then the non-Lite test variant via classloader
202    * manipulation.
203    */
204   @Override
runTest()205   public void runTest() throws Exception {
206     ClassLoader storedClassLoader = Thread.currentThread().getContextClassLoader();
207     Thread.currentThread().setContextClassLoader(LITE_CLASS_LOADER);
208     try {
209       runTestMethod(LITE_CLASS_LOADER, InnerLiteTest.class);
210     } finally {
211       Thread.currentThread().setContextClassLoader(storedClassLoader);
212     }
213     try {
214       runTestMethod(storedClassLoader, InnerTest.class);
215     } finally {
216       Thread.currentThread().setContextClassLoader(storedClassLoader);
217     }
218   }
219 
runTestMethod(ClassLoader classLoader, Class<? extends RegistryTests> testClass)220   private void runTestMethod(ClassLoader classLoader, Class<? extends RegistryTests> testClass)
221       throws Exception {
222     classLoader.loadClass(ExtensionRegistryFactory.class.getName());
223     Class<?> test = classLoader.loadClass(testClass.getName());
224     String testName = getName();
225     test.getMethod(testName).invoke(test.getDeclaredConstructor().newInstance());
226   }
227 
228   /**
229    * Constructs a custom ClassLoader blacklisting the classes which are inspected in the SUT to
230    * determine the Lite/non-Lite runtime.
231    */
getLiteOnlyClassLoader()232   private static ClassLoader getLiteOnlyClassLoader() {
233 
234     ImmutableSet<ClassPath.ClassInfo> classes = ImmutableSet.of();
235     try {
236       classes = ClassPath.from(ExtensionRegistryFactoryTest.class.getClassLoader()).getAllClasses();
237     } catch (IOException ex) {
238       throw new RuntimeException(ex);
239     }
240     URL[] urls = new URL[classes.size()];
241     int i = 0;
242     for (ClassPath.ClassInfo classInfo : classes) {
243       urls[i++] = classInfo.url();
244     }
245     final ImmutableSet<String> classNamesNotInLite =
246         ImmutableSet.of(
247             ExtensionRegistryFactory.FULL_REGISTRY_CLASS_NAME,
248             ExtensionRegistry.EXTENSION_CLASS_NAME);
249 
250     // Construct a URLClassLoader delegating to the system ClassLoader, and looking up classes
251     // in jar files based on the URLs already configured for this test's UrlClassLoader.
252     // Certain classes throw a ClassNotFoundException by design.
253     return new URLClassLoader(urls, ClassLoader.getSystemClassLoader()) {
254       @Override
255       public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
256         if (classNamesNotInLite.contains(name)) {
257           throw new ClassNotFoundException("Class deliberately blacklisted by test.");
258         }
259         Class<?> loadedClass = null;
260         try {
261           loadedClass = findLoadedClass(name);
262           if (loadedClass == null) {
263             loadedClass = findClass(name);
264             if (resolve) {
265               resolveClass(loadedClass);
266             }
267           }
268         } catch (ClassNotFoundException | SecurityException e) {
269           // Java 8+ would throw a SecurityException if we attempt to find a loaded class from
270           // java.lang.* package. We don't really care about those anyway, so just delegate to the
271           // parent class loader.
272           loadedClass = super.loadClass(name, resolve);
273         }
274         return loadedClass;
275       }
276     };
277   }
278 }
279