View Javadoc
1   package com.atlassian.activeobjects.osgi;
2   
3   import com.atlassian.activeobjects.config.ActiveObjectsConfiguration;
4   import com.atlassian.activeobjects.internal.ActiveObjectsFactory;
5   import com.atlassian.activeobjects.osgi.ActiveObjectsServiceFactory.BundleRef;
6   import com.atlassian.activeobjects.plugin.ActiveObjectModuleDescriptor;
7   import com.atlassian.activeobjects.spi.ContextClassLoaderThreadFactory;
8   import com.atlassian.activeobjects.spi.InitExecutorServiceProvider;
9   import com.atlassian.event.api.EventPublisher;
10  import com.atlassian.plugin.ModuleDescriptor;
11  import com.atlassian.plugin.Plugin;
12  import com.atlassian.plugin.event.events.PluginDisabledEvent;
13  import com.atlassian.plugin.event.events.PluginEnabledEvent;
14  import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
15  import com.atlassian.plugin.osgi.factory.OsgiPlugin;
16  import com.atlassian.sal.api.executor.ThreadLocalDelegateExecutorFactory;
17  import com.atlassian.tenancy.api.Tenant;
18  import com.atlassian.tenancy.api.TenantContext;
19  import org.junit.Before;
20  import org.junit.Rule;
21  import org.junit.Test;
22  import org.junit.rules.ExpectedException;
23  import org.junit.runner.RunWith;
24  import org.mockito.Mock;
25  import org.mockito.junit.MockitoJUnitRunner;
26  import org.osgi.framework.Bundle;
27  
28  import java.util.Collections;
29  import java.util.concurrent.ExecutionException;
30  import java.util.concurrent.ExecutorService;
31  import java.util.concurrent.TimeUnit;
32  
33  import static org.hamcrest.CoreMatchers.is;
34  import static org.hamcrest.CoreMatchers.notNullValue;
35  import static org.hamcrest.CoreMatchers.sameInstance;
36  import static org.hamcrest.MatcherAssert.assertThat;
37  import static org.hamcrest.collection.IsMapContaining.hasEntry;
38  import static org.hamcrest.core.IsInstanceOf.instanceOf;
39  import static org.mockito.Mockito.verify;
40  import static org.mockito.Mockito.when;
41  
42  @RunWith(MockitoJUnitRunner.class)
43  public final class ActiveObjectsServiceFactoryTest {
44      private ActiveObjectsServiceFactory serviceFactory;
45  
46      @Rule
47      public ExpectedException expectedException = ExpectedException.none();
48      @Mock
49      private ActiveObjectsFactory factory;
50      @Mock
51      private EventPublisher eventPublisher;
52      @Mock
53      private TenantContext tenantContext;
54      @Mock
55      private ThreadLocalDelegateExecutorFactory threadLocalDelegateExecutorFactory;
56      @Mock
57      private InitExecutorServiceProvider initExecutorServiceProvider;
58      @Mock
59      private Tenant tenant1;
60      @Mock
61      private Tenant tenant2;
62      @Mock
63      private Tenant tenant3;
64      @Mock
65      private ExecutorService executorService1;
66      @Mock
67      private ExecutorService executorService2;
68      @Mock
69      private ExecutorService executorService3;
70      @Mock
71      private Bundle bundle1;
72      @Mock
73      private Bundle bundle2;
74      @Mock
75      private TenantAwareActiveObjects babyBear1;
76      @Mock
77      private TenantAwareActiveObjects babyBear2;
78      @Mock
79      private PluginModuleEnabledEvent moduleEnabledEvent;
80      @Mock
81      private PluginEnabledEvent enabledEvent;
82      @Mock
83      private PluginDisabledEvent disabledEvent;
84      @Mock
85      private ActiveObjectModuleDescriptor moduleDescriptor;
86      @Mock
87      private OsgiPlugin plugin1;
88      @Mock
89      private Plugin nonOsgiPlugin;
90      @Mock
91      private ActiveObjectsConfiguration aoConfig1;
92      @Mock
93      private ActiveObjectsConfiguration aoConfig2;
94  
95      @Before
96      public void setUp() {
97          serviceFactory = new ActiveObjectsServiceFactory(factory, eventPublisher, tenantContext,
98                  threadLocalDelegateExecutorFactory, initExecutorServiceProvider);
99  
100         assertThat(serviceFactory.aoContextThreadFactory, instanceOf(ContextClassLoaderThreadFactory.class));
101         assertThat(((ContextClassLoaderThreadFactory) serviceFactory.aoContextThreadFactory).getContextClassLoader(), sameInstance(Thread.currentThread().getContextClassLoader()));
102         assertThat(serviceFactory.destroying, is(false));
103         assertThat(serviceFactory.cleaning, is(false));
104 
105         when(babyBear1.getBundle()).thenReturn(bundle1);
106         when(babyBear2.getBundle()).thenReturn(bundle2);
107         //noinspection unchecked
108         when(moduleEnabledEvent.getModule()).thenReturn((ModuleDescriptor) moduleDescriptor);
109         when(moduleDescriptor.getPlugin()).thenReturn(plugin1);
110         when(enabledEvent.getPlugin()).thenReturn(plugin1);
111         when(disabledEvent.getPlugin()).thenReturn(plugin1);
112         when(plugin1.getBundle()).thenReturn(bundle1);
113         when(moduleDescriptor.getConfiguration()).thenReturn(aoConfig1);
114     }
115 
116     @Test
117     public void afterPropertiesSet() throws Exception {
118         serviceFactory.afterPropertiesSet();
119 
120         verify(eventPublisher).register(serviceFactory);
121     }
122 
123     @Test
124     public void destroy() throws Exception {
125         serviceFactory.initExecutorsByTenant.put(tenant1, executorService1);
126         serviceFactory.initExecutorsByTenant.put(tenant2, executorService2);
127         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
128         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
129 
130         serviceFactory.destroy();
131 
132         assertThat(serviceFactory.destroying, is(true));
133 
134         verify(eventPublisher).unregister(serviceFactory);
135         verify(babyBear1).destroy();
136         verify(babyBear2).destroy();
137         verify(executorService1).shutdownNow();
138         verify(executorService2).shutdownNow();
139     }
140 
141     @Test
142     public void startCleaning() throws InterruptedException {
143         serviceFactory.initExecutorsByTenant.put(tenant1, executorService1);
144         serviceFactory.initExecutorsByTenant.put(tenant2, executorService2);
145         serviceFactory.initExecutorsByTenant.put(tenant3, executorService3);
146 
147         when(executorService1.awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)).thenThrow(new InterruptedException());
148         when(executorService2.awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)).thenReturn(false);
149         when(executorService3.awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)).thenReturn(true);
150 
151         serviceFactory.startCleaning();
152 
153         assertThat(serviceFactory.cleaning, is(true));
154 
155         verify(executorService1).shutdownNow();
156         verify(executorService2).shutdownNow();
157         verify(executorService3).shutdownNow();
158         verify(executorService1).awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
159         verify(executorService2).awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
160         verify(executorService3).awaitTermination(ActiveObjectsServiceFactory.INIT_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
161     }
162 
163     @Test
164     public void initExecutorFn() {
165         serviceFactory.initExecutorsByTenant.put(tenant1, executorService1);
166         serviceFactory.initExecutorsByTenant.put(tenant2, executorService2);
167 
168         assertThat(serviceFactory.initExecutorFn.apply(tenant1), sameInstance(executorService1));
169     }
170 
171     @Test
172     public void initExecutorFnAfterDestroy() throws Exception {
173         serviceFactory.destroy();
174 
175         expectedException.expect(IllegalStateException.class);
176 
177         serviceFactory.initExecutorFn.apply(tenant1);
178     }
179 
180     @Test
181     public void getService() {
182         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
183         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
184 
185         TenantAwareActiveObjects babyBear = (TenantAwareActiveObjects) serviceFactory.getService(bundle1, null);
186         assertThat(babyBear, sameInstance(babyBear1));
187     }
188 
189     @Test
190     public void unGetService() {
191         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
192         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
193 
194         assertThat(serviceFactory.aoDelegatesByBundle.asMap(), hasEntry(new BundleRef(bundle1), babyBear1));
195         assertThat(serviceFactory.aoDelegatesByBundle.asMap(), hasEntry(new BundleRef(bundle2), babyBear2));
196         assertThat(serviceFactory.aoDelegatesByBundle.asMap().size(), is(2));
197 
198         serviceFactory.ungetService(bundle1, null, babyBear1);
199 
200         assertThat(serviceFactory.aoDelegatesByBundle.asMap(), hasEntry(new BundleRef(bundle2), babyBear2));
201         assertThat(serviceFactory.aoDelegatesByBundle.asMap().size(), is(1));
202 
203         verify(babyBear1).destroy();
204     }
205 
206     @Test
207     public void onTenantArrived() {
208         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
209         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
210 
211         when(tenantContext.getCurrentTenant()).thenReturn(tenant1);
212 
213         serviceFactory.onTenantArrived(null);
214 
215         verify(babyBear1).startActiveObjects(tenant1);
216         verify(babyBear2).startActiveObjects(tenant1);
217     }
218 
219     @Test
220     public void onHotRestart() {
221         serviceFactory.initExecutorsByTenant.put(tenant1, executorService1);
222 
223         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
224         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
225 
226         when(tenantContext.getCurrentTenant()).thenReturn(tenant1);
227 
228         serviceFactory.onHotRestart(null);
229 
230         verify(babyBear1).restartActiveObjects(tenant1);
231         verify(babyBear2).restartActiveObjects(tenant1);
232         verify(executorService1).shutdownNow();
233 
234         assertThat(serviceFactory.initExecutorsByTenant.asMap(), is(Collections.<Tenant, ExecutorService>emptyMap()));
235     }
236 
237     @Test
238     public void onPluginModuleEnabledEventNoDelegate() {
239         serviceFactory.onPluginModuleEnabledEvent(moduleEnabledEvent);
240 
241         assertThat(serviceFactory.unattachedConfigByBundle, hasEntry(bundle1, aoConfig1));
242     }
243 
244     @Test
245     public void onPluginModuleEnabledEventNonOsgi() {
246         when(moduleDescriptor.getPlugin()).thenReturn(nonOsgiPlugin);
247 
248         serviceFactory.onPluginModuleEnabledEvent(moduleEnabledEvent);
249 
250         assertThat(serviceFactory.unattachedConfigByBundle, is(Collections.<Bundle, ActiveObjectsConfiguration>emptyMap()));
251     }
252 
253     @Test
254     public void onPluginModuleEnabledEventHasDelegate() {
255         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
256 
257         serviceFactory.onPluginModuleEnabledEvent(moduleEnabledEvent);
258 
259         assertThat(serviceFactory.unattachedConfigByBundle, is(Collections.<Bundle, ActiveObjectsConfiguration>emptyMap()));
260 
261         verify(babyBear1).setAoConfiguration(aoConfig1);
262     }
263 
264     @Test
265     public void onPluginEnabledAttachMatching() {
266         serviceFactory.unattachedConfigByBundle.put(bundle1, aoConfig1);
267 
268         serviceFactory.onPluginEnabledEvent(enabledEvent);
269 
270         assertThat(serviceFactory.unattachedConfigByBundle, is(Collections.<Bundle, ActiveObjectsConfiguration>emptyMap()));
271     }
272 
273     @Test
274     public void onPluginEnabledIgnoreNonMatching() {
275         serviceFactory.unattachedConfigByBundle.put(bundle2, aoConfig1);
276 
277         serviceFactory.onPluginEnabledEvent(enabledEvent);
278 
279         assertThat(serviceFactory.unattachedConfigByBundle, hasEntry(bundle2, aoConfig1));
280     }
281 
282     @Test
283     public void onPluginEnabledNonOsgi() {
284         when(enabledEvent.getPlugin()).thenReturn(nonOsgiPlugin);
285         serviceFactory.unattachedConfigByBundle.put(bundle1, aoConfig1);
286 
287         serviceFactory.onPluginEnabledEvent(enabledEvent);
288 
289         assertThat(serviceFactory.unattachedConfigByBundle, hasEntry(bundle1, aoConfig1));
290     }
291 
292     @Test
293     public void onPluginDisabledEvent() {
294         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle1), babyBear1);
295         serviceFactory.aoDelegatesByBundle.put(new BundleRef(bundle2), babyBear2);
296         serviceFactory.unattachedConfigByBundle.put(bundle1, aoConfig1);
297         serviceFactory.unattachedConfigByBundle.put(bundle2, aoConfig2);
298 
299         serviceFactory.onPluginDisabledEvent(disabledEvent);
300 
301         assertThat(serviceFactory.aoDelegatesByBundle.asMap(), hasEntry(new BundleRef(bundle2), babyBear2));
302         assertThat(serviceFactory.aoDelegatesByBundle.asMap().size(), is(1));
303         assertThat(serviceFactory.unattachedConfigByBundle, hasEntry(bundle2, aoConfig2));
304         assertThat(serviceFactory.unattachedConfigByBundle.size(), is(1));
305     }
306 
307     @Test
308     public void aoDelegatesByBundleLoader() throws ExecutionException, InterruptedException {
309         serviceFactory.unattachedConfigByBundle.put(bundle1, aoConfig1);
310 
311         final TenantAwareActiveObjects aoDelegate = serviceFactory.aoDelegatesByBundle.get(new BundleRef(bundle1));
312 
313         assertThat(aoDelegate, notNullValue());
314         assertThat(aoDelegate.aoConfigFuture.isDone(), is(true));
315         assertThat(aoDelegate.aoConfigFuture.get(), is(aoConfig1));
316     }
317 }