View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package org.kuali.rice.krad.data.provider;
17  
18  import org.junit.Before;
19  import org.junit.Test;
20  import org.kuali.rice.krad.data.provider.impl.ProviderRegistryImpl;
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Random;
27  import java.util.concurrent.BlockingQueue;
28  import java.util.concurrent.Callable;
29  import java.util.concurrent.ExecutorService;
30  import java.util.concurrent.Executors;
31  import java.util.concurrent.LinkedBlockingQueue;
32  import java.util.concurrent.TimeUnit;
33  
34  import static junit.framework.Assert.assertEquals;
35  import static org.junit.Assert.assertNull;
36  import static org.junit.Assert.assertSame;
37  import static org.mockito.Matchers.any;
38  import static org.mockito.Matchers.eq;
39  import static org.mockito.Mockito.mock;
40  import static org.mockito.Mockito.when;
41  
42  /**
43   * Tests ProviderRegistryImpl
44   */
45  public class ProviderRegistryImplTest {
46      // various Provider interfaces for testing
47      private static interface CustomProvider extends Provider {}
48      private static interface MultiProvider extends PersistenceProvider, MetadataProvider, CustomProvider {}
49  
50      // test types
51      private static class A {}
52      private static class B {}
53      private static Class<A> TYPE_A = A.class;
54      private static Class<B> TYPE_B = B.class;
55  
56      private ProviderRegistry registry;
57  
58      @Before
59      public void setup() {
60          registry = new ProviderRegistryImpl();
61      }
62  
63      /**
64       * Test empty state
65       */
66      @Test
67      public void testEmpty() {
68          assertEquals(0, registry.getProviders().size());
69          assertEquals(0, registry.getMetadataProviders().size());
70          assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
71          assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size());
72          assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
73          assertNull(registry.getPersistenceProvider(String.class));
74      }
75  
76      @Test(expected=IllegalArgumentException.class)
77      public void testRegisterProviderIllegalArgument() {
78          registry.registerProvider(null);
79      }
80  
81      @Test(expected=IllegalArgumentException.class)
82      public void testUnregisterProviderIllegalArgument() {
83          registry.unregisterProvider(null);
84      }
85  
86      @Test(expected=IllegalArgumentException.class)
87      public void testGetProvidersForTypeIllegalArgument() {
88          registry.getProvidersForType(null);
89      }
90  
91      @Test(expected=IllegalArgumentException.class)
92      public void testGetPersistenceProviderIllegalArgument() {
93          registry.getPersistenceProvider(null);
94      }
95  
96      /**
97       * Registers various Provider implementations and tests getters
98       */
99      @Test
100     public void testRegisterProviders() {
101         registry.registerProvider(mock(Provider.class));
102 
103         assertEquals(1, registry.getProviders().size());
104         assertEquals(0, registry.getMetadataProviders().size());
105         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
106         assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size());
107         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
108         assertNull(registry.getPersistenceProvider(String.class));
109 
110         // create mock metadataprovider that handles any dataobjecttype
111         MetadataProvider mockMetadataProvider = mock(MetadataProvider.class);
112         when(mockMetadataProvider.handles(any(Class.class))).thenReturn(true);
113 
114         registry.registerProvider(mockMetadataProvider);
115 
116         assertEquals(2, registry.getProviders().size());
117         assertEquals(1, registry.getMetadataProviders().size());
118         assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size());
119         assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size());
120         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
121         assertNull(registry.getPersistenceProvider(String.class));
122         assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class));
123 
124         assertEquals(2, registry.getProviders().size());
125         assertEquals(1, registry.getMetadataProviders().size());
126         assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size());
127         assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size());
128         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
129         assertNull(registry.getPersistenceProvider(String.class));
130         assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class));
131 
132         PersistenceProvider pp = mock(PersistenceProvider.class);
133         when(pp.handles(TYPE_B)).thenReturn(true);
134         registry.registerProvider(pp);
135 
136         assertEquals(3, registry.getProviders().size());
137         assertEquals(1, registry.getMetadataProviders().size());
138         assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size());
139         assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size());
140         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
141         assertNull(registry.getPersistenceProvider(String.class));
142         assertSame(pp, registry.getPersistenceProvider(B.class));
143         assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class));
144 
145         registry.registerProvider(mock(CustomProvider.class));
146 
147         assertEquals(4, registry.getProviders().size());
148         assertEquals(1, registry.getMetadataProviders().size());
149         assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size());
150         assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size());
151         assertEquals(1, registry.getProvidersForType(CustomProvider.class).size());
152         assertNull(registry.getPersistenceProvider(String.class));
153         assertSame(pp, registry.getPersistenceProvider(B.class));
154         assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class));
155 
156         registry.registerProvider(mock(MultiProvider.class));
157 
158         assertEquals(5, registry.getProviders().size());
159         assertEquals(2, registry.getMetadataProviders().size());
160         assertEquals(2, registry.getProvidersForType(MetadataProvider.class).size());
161         assertEquals(2, registry.getProvidersForType(PersistenceProvider.class).size());
162         assertEquals(2, registry.getProvidersForType(CustomProvider.class).size());
163         assertNull(registry.getPersistenceProvider(String.class));
164         assertSame(pp, registry.getPersistenceProvider(B.class));
165         // returns the *first* metadataprovider that handles the given type
166         assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class));
167     }
168 
169     /**
170      * Verifies duplicate providers can't be registered
171      */
172     @Test
173     public void testRegisterDuplicateProviders() {
174         Provider p = mock(Provider.class);
175         MetadataProvider mp1 = mock(MetadataProvider.class);
176         MetadataProvider mp2 = mock(MetadataProvider.class);
177 
178         registry.registerProvider(p);
179         assertEquals(1, registry.getProviders().size());
180         registry.registerProvider(p);
181         assertEquals(1, registry.getProviders().size());
182 
183         registry.registerProvider(mp1);
184         assertEquals(2, registry.getProviders().size());
185         assertEquals(1, registry.getMetadataProviders().size());
186         registry.registerProvider(mp1);
187         assertEquals(2, registry.getProviders().size());
188         assertEquals(1, registry.getMetadataProviders().size());
189 
190         registry.registerProvider(mp2);
191         assertEquals(3, registry.getProviders().size());
192         assertEquals(2, registry.getMetadataProviders().size());
193         registry.registerProvider(mp2);
194         assertEquals(3, registry.getProviders().size());
195         assertEquals(2, registry.getMetadataProviders().size());
196     }
197 
198     /**
199      * Tests unregistering after registering
200      */
201     @Test
202     public void testRegisterUnregister() {
203         Provider a = mock(Provider.class);
204         Provider b = mock(Provider.class);
205         Provider c = mock(Provider.class);
206         Provider d = mock(Provider.class);
207 
208         registry.registerProvider(a);
209         registry.registerProvider(b);
210         registry.registerProvider(c);
211         registry.registerProvider(d);
212 
213         assertEquals(4, registry.getProviders().size());
214 
215         registry.unregisterProvider(c);
216         registry.unregisterProvider(b);
217         registry.unregisterProvider(d);
218         registry.unregisterProvider(a);
219 
220         assertEquals(0, registry.getProviders().size());
221     }
222 
223     /**
224      * Verifies ProviderRegistryImpl is threadsafe
225      */
226     @Test
227     public void testConcurrency() throws InterruptedException {
228         final Class<? extends Provider>[] TYPES = new Class[] {
229             Provider.class, MetadataProvider.class,
230             PersistenceProvider.class, CustomProvider.class
231         };
232 
233         int providers = 50;
234         int threads = providers * 2; // just use live threads for all consumers/producers to ensure no consumer deadlock
235 
236         final BlockingQueue<Provider> queue = new LinkedBlockingQueue<Provider>();
237         ExecutorService threadpool = Executors.newFixedThreadPool(threads);
238 
239         final Random random = new Random(System.currentTimeMillis());
240 
241         Callable<Object>[] producers = new Callable[providers];
242         Callable<Object>[] consumers = new Callable[providers];
243         Callable<Object> producer = new Callable<Object>() {
244             @Override
245             public Object call() throws Exception {
246                 Provider p = mock(TYPES[random.nextInt(5)]);
247                 registry.registerProvider(p);
248                 queue.add(p);
249                 return null;
250             }
251         };
252         Callable<Object> consumer = new Callable<Object>() {
253             @Override
254             public Object call() throws Exception {
255                 Provider p = queue.take();
256                 registry.unregisterProvider(p);
257                 return null;
258             }
259         };
260 
261         Arrays.fill(producers, producer);
262         Arrays.fill(consumers, consumer);
263 
264         List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(providers * 2);
265         tasks.addAll(Arrays.asList(producers));
266         tasks.addAll(Arrays.asList(consumers));
267         Collections.shuffle(tasks);
268 
269         System.out.println("Registering and unregistering " + providers + " providers");
270         threadpool.invokeAll(tasks, 10, TimeUnit.SECONDS);
271 
272         // all producers and consumers should have run, we should be back at 0 providers registered
273         assertEquals(0, registry.getProviders().size());
274     }
275 
276     /**
277      * Tests registration and lookup of multiple PersistenceProviders
278      */
279     @Test
280     public void testRegisterPersistenceProviders() {
281         PersistenceProvider mockA = mock(PersistenceProvider.class);
282         when(mockA.handles(eq(TYPE_A))).thenReturn(true);
283 
284         PersistenceProvider mockB = mock(PersistenceProvider.class);
285         when(mockB.handles(eq(TYPE_B))).thenReturn(true);
286 
287         PersistenceProvider mockAB = mock(PersistenceProvider.class);
288         when(mockAB.handles(eq(TYPE_A))).thenReturn(true);
289         when(mockAB.handles(eq(TYPE_B))).thenReturn(true);
290 
291         registry.registerProvider(mockA);
292 
293         assertEquals(1, registry.getProviders().size());
294         assertEquals(0, registry.getMetadataProviders().size());
295         assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size());
296         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
297         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
298         assertSame(mockA, registry.getPersistenceProvider(A.class));
299 
300         registry.registerProvider(mockB);
301 
302         assertEquals(2, registry.getProviders().size());
303         assertEquals(0, registry.getMetadataProviders().size());
304         assertEquals(2, registry.getProvidersForType(PersistenceProvider.class).size());
305         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
306         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
307         assertSame(mockA, registry.getPersistenceProvider(A.class));
308         assertSame(mockB, registry.getPersistenceProvider(B.class));
309 
310         registry.registerProvider(mockAB);
311 
312         assertEquals(3, registry.getProviders().size());
313         assertEquals(0, registry.getMetadataProviders().size());
314         assertEquals(3, registry.getProvidersForType(PersistenceProvider.class).size());
315         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
316         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
317         assertSame(mockA, registry.getPersistenceProvider(A.class)); // still returns mockA
318         assertSame(mockB, registry.getPersistenceProvider(B.class));
319     }
320 }