View Javadoc
1   /**
2    * Copyright 2005-2014 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.apache.commons.lang.math.RandomUtils;
19  import org.junit.Before;
20  import org.junit.Test;
21  import org.kuali.rice.krad.data.provider.impl.ProviderRegistryImpl;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.List;
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         Callable<Object>[] producers = new Callable[providers];
240         Callable<Object>[] consumers = new Callable[providers];
241         Callable<Object> producer = new Callable<Object>() {
242             @Override
243             public Object call() throws Exception {
244                 Provider p = mock(TYPES[RandomUtils.nextInt(5)]);
245                 registry.registerProvider(p);
246                 queue.add(p);
247                 return null;
248             }
249         };
250         Callable<Object> consumer = new Callable<Object>() {
251             @Override
252             public Object call() throws Exception {
253                 Provider p = queue.take();
254                 registry.unregisterProvider(p);
255                 return null;
256             }
257         };
258 
259         Arrays.fill(producers, producer);
260         Arrays.fill(consumers, consumer);
261 
262         List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(providers * 2);
263         tasks.addAll(Arrays.asList(producers));
264         tasks.addAll(Arrays.asList(consumers));
265         Collections.shuffle(tasks);
266 
267         System.out.println("Registering and unregistering " + providers + " providers");
268         threadpool.invokeAll(tasks, 10, TimeUnit.SECONDS);
269 
270         // all producers and consumers should have run, we should be back at 0 providers registered
271         assertEquals(0, registry.getProviders().size());
272     }
273 
274     /**
275      * Tests registration and lookup of multiple PersistenceProviders
276      */
277     @Test
278     public void testRegisterPersistenceProviders() {
279         PersistenceProvider mockA = mock(PersistenceProvider.class);
280         when(mockA.handles(eq(TYPE_A))).thenReturn(true);
281 
282         PersistenceProvider mockB = mock(PersistenceProvider.class);
283         when(mockB.handles(eq(TYPE_B))).thenReturn(true);
284 
285         PersistenceProvider mockAB = mock(PersistenceProvider.class);
286         when(mockAB.handles(eq(TYPE_A))).thenReturn(true);
287         when(mockAB.handles(eq(TYPE_B))).thenReturn(true);
288 
289         registry.registerProvider(mockA);
290 
291         assertEquals(1, registry.getProviders().size());
292         assertEquals(0, registry.getMetadataProviders().size());
293         assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size());
294         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
295         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
296         assertSame(mockA, registry.getPersistenceProvider(A.class));
297 
298         registry.registerProvider(mockB);
299 
300         assertEquals(2, registry.getProviders().size());
301         assertEquals(0, registry.getMetadataProviders().size());
302         assertEquals(2, registry.getProvidersForType(PersistenceProvider.class).size());
303         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
304         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
305         assertSame(mockA, registry.getPersistenceProvider(A.class));
306         assertSame(mockB, registry.getPersistenceProvider(B.class));
307 
308         registry.registerProvider(mockAB);
309 
310         assertEquals(3, registry.getProviders().size());
311         assertEquals(0, registry.getMetadataProviders().size());
312         assertEquals(3, registry.getProvidersForType(PersistenceProvider.class).size());
313         assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size());
314         assertEquals(0, registry.getProvidersForType(CustomProvider.class).size());
315         assertSame(mockA, registry.getPersistenceProvider(A.class)); // still returns mockA
316         assertSame(mockB, registry.getPersistenceProvider(B.class));
317     }
318 }