1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.PluginState;
4 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
5 import com.atlassian.plugin.descriptors.RequiresRestart;
6 import com.atlassian.plugin.event.PluginEventManager;
7 import com.atlassian.plugin.event.events.PluginContainerRefreshedEvent;
8 import com.atlassian.plugin.module.ModuleFactory;
9 import com.atlassian.plugin.osgi.util.OsgiSystemBundleUtil;
10 import junit.framework.TestCase;
11 import org.mockito.invocation.InvocationOnMock;
12 import org.mockito.stubbing.Answer;
13 import org.osgi.framework.Bundle;
14 import org.osgi.framework.BundleContext;
15 import org.osgi.framework.BundleException;
16 import org.osgi.framework.Constants;
17
18 import java.util.Dictionary;
19 import java.util.Hashtable;
20
21 import static org.mockito.Mockito.doAnswer;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26
27 public class TestOsgiPlugin extends TestCase
28 {
29 private Bundle bundle;
30 private OsgiPlugin plugin;
31 private BundleContext bundleContext;
32 private Bundle systemBundle;
33 private BundleContext systemBundleContext;
34 private Dictionary<String, String> dict;
35 private OsgiPluginHelper helper;
36
37 @Override
38 public void setUp()
39 {
40 bundle = mock(Bundle.class);
41 dict = new Hashtable<String, String>();
42 dict.put(Constants.BUNDLE_DESCRIPTION, "desc");
43 dict.put(Constants.BUNDLE_VERSION, "1.0");
44 when(bundle.getHeaders()).thenReturn(dict);
45 bundleContext = mock(BundleContext.class);
46 when(bundle.getBundleContext()).thenReturn(bundleContext);
47
48 systemBundle = mock(Bundle.class);
49 systemBundleContext = mock(BundleContext.class);
50 when(bundleContext.getBundle(OsgiSystemBundleUtil.SYSTEM_BUNDLE_ID)).thenReturn(systemBundle);
51 when(systemBundle.getBundleContext()).thenReturn(systemBundleContext);
52
53 helper = mock(OsgiPluginHelper.class);
54 when(helper.getBundle()).thenReturn(bundle);
55
56 plugin = new OsgiPlugin(mock(PluginEventManager.class), helper);
57 }
58
59 @Override
60 public void tearDown()
61 {
62 bundle = null;
63 plugin = null;
64 bundleContext = null;
65 }
66
67 public void testEnabled() throws BundleException
68 {
69 when(bundle.getState()).thenReturn(Bundle.RESOLVED);
70 plugin.enable();
71 verify(bundle).start();
72 }
73
74 public void testDisabled() throws BundleException
75 {
76 when(bundle.getState()).thenReturn(Bundle.ACTIVE);
77 plugin.disable();
78 verify(bundle).stop();
79 }
80
81 public void testDisabledOnNonDynamicPlugin() throws BundleException
82 {
83 plugin.addModuleDescriptor(new StaticModuleDescriptor());
84 plugin.onPluginFrameworkStartedEvent(null);
85 when(bundle.getState()).thenReturn(Bundle.ACTIVE);
86 plugin.disable();
87 verify(bundle, never()).stop();
88 }
89
90 public void testUninstall() throws BundleException
91 {
92 when(bundle.getState()).thenReturn(Bundle.ACTIVE);
93 plugin.uninstall();
94 assertEquals(plugin.getPluginState(), PluginState.UNINSTALLED);
95 }
96
97 public void testOnPluginContainerRefresh()
98 {
99 plugin.setKey("plugin-key");
100 when(bundle.getState()).thenReturn(Bundle.RESOLVED);
101 plugin.enable();
102 PluginContainerRefreshedEvent event = new PluginContainerRefreshedEvent(new Object(), "plugin-key");
103 plugin.onPluginContainerRefresh(event);
104 assertEquals(PluginState.ENABLED, plugin.getPluginState());
105 }
106
107 public void testQuickOnPluginContainerRefresh() throws BundleException, InterruptedException
108 {
109 plugin.setKey("plugin-key");
110 when(bundle.getState()).thenReturn(Bundle.RESOLVED);
111
112 final ConcurrentStateEngine states = new ConcurrentStateEngine("bundle-starting", "container-created", "bundle-started", "mid-start", "end");
113 when(bundle.getBundleContext()).thenAnswer(new Answer<Object>()
114 {
115 public Object answer(InvocationOnMock invocation) throws Throwable
116 {
117 states.tryNextState("bundle-started", "mid-start");
118 final BundleContext context = mock(BundleContext.class);
119 when(context.getBundle(OsgiSystemBundleUtil.SYSTEM_BUNDLE_ID)).thenReturn(systemBundle);
120
121 return context;
122 }
123 });
124
125 doAnswer(new Answer<Object>()
126 {
127 public Object answer(InvocationOnMock invocation) throws Throwable
128 {
129 states.state("bundle-starting");
130 Thread t = new Thread()
131 {
132 public void run()
133 {
134 PluginContainerRefreshedEvent event = new PluginContainerRefreshedEvent(new Object(), "plugin-key");
135 states.tryNextState("bundle-starting", "container-created");
136 plugin.onPluginContainerRefresh(event);
137 }
138 };
139 t.start();
140 states.tryNextState("container-created", "bundle-started");
141 return null;
142 }
143 }).when(bundle).start();
144
145 plugin.enable();
146
147
148 states.tryNextState("mid-start", "end");
149
150 assertEquals(PluginState.ENABLED, plugin.getPluginState());
151 }
152
153 public void testOnPluginContainerRefreshNotEnabling()
154 {
155 plugin.setKey("plugin-key");
156 PluginContainerRefreshedEvent event = new PluginContainerRefreshedEvent(new Object(), "plugin-key");
157 when(bundle.getState()).thenReturn(Bundle.ACTIVE);
158 plugin.disable();
159 plugin.onPluginContainerRefresh(event);
160 assertEquals(PluginState.DISABLED, plugin.getPluginState());
161 }
162
163 @RequiresRestart
164 public static class StaticModuleDescriptor extends AbstractModuleDescriptor<Object>
165 {
166 public StaticModuleDescriptor()
167 {
168 super(ModuleFactory.LEGACY_MODULE_FACTORY);
169 }
170
171 public Object getModule()
172 {
173 return null;
174 }
175 }
176 }