001/** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.data.provider; 017 018import org.junit.Before; 019import org.junit.Test; 020import org.kuali.rice.krad.data.provider.impl.ProviderRegistryImpl; 021 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.List; 026import java.util.Random; 027import java.util.concurrent.BlockingQueue; 028import java.util.concurrent.Callable; 029import java.util.concurrent.ExecutorService; 030import java.util.concurrent.Executors; 031import java.util.concurrent.LinkedBlockingQueue; 032import java.util.concurrent.TimeUnit; 033 034import static junit.framework.Assert.assertEquals; 035import static org.junit.Assert.assertNull; 036import static org.junit.Assert.assertSame; 037import static org.mockito.Matchers.any; 038import static org.mockito.Matchers.eq; 039import static org.mockito.Mockito.mock; 040import static org.mockito.Mockito.when; 041 042/** 043 * Tests ProviderRegistryImpl 044 */ 045public class ProviderRegistryImplTest { 046 // various Provider interfaces for testing 047 private static interface CustomProvider extends Provider {} 048 private static interface MultiProvider extends PersistenceProvider, MetadataProvider, CustomProvider {} 049 050 // test types 051 private static class A {} 052 private static class B {} 053 private static Class<A> TYPE_A = A.class; 054 private static Class<B> TYPE_B = B.class; 055 056 private ProviderRegistry registry; 057 058 @Before 059 public void setup() { 060 registry = new ProviderRegistryImpl(); 061 } 062 063 /** 064 * Test empty state 065 */ 066 @Test 067 public void testEmpty() { 068 assertEquals(0, registry.getProviders().size()); 069 assertEquals(0, registry.getMetadataProviders().size()); 070 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 071 assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size()); 072 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 073 assertNull(registry.getPersistenceProvider(String.class)); 074 } 075 076 @Test(expected=IllegalArgumentException.class) 077 public void testRegisterProviderIllegalArgument() { 078 registry.registerProvider(null); 079 } 080 081 @Test(expected=IllegalArgumentException.class) 082 public void testUnregisterProviderIllegalArgument() { 083 registry.unregisterProvider(null); 084 } 085 086 @Test(expected=IllegalArgumentException.class) 087 public void testGetProvidersForTypeIllegalArgument() { 088 registry.getProvidersForType(null); 089 } 090 091 @Test(expected=IllegalArgumentException.class) 092 public void testGetPersistenceProviderIllegalArgument() { 093 registry.getPersistenceProvider(null); 094 } 095 096 /** 097 * Registers various Provider implementations and tests getters 098 */ 099 @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}