1 package com.atlassian.activeobjects.internal;
2
3 import com.atlassian.activeobjects.ActiveObjectsPluginException;
4 import com.atlassian.activeobjects.config.ActiveObjectsConfiguration;
5 import com.atlassian.activeobjects.config.PluginKey;
6 import com.atlassian.activeobjects.spi.DatabaseType;
7 import com.atlassian.activeobjects.spi.TenantAwareDataSourceProvider;
8 import com.atlassian.activeobjects.spi.TransactionSynchronisationManager;
9 import com.atlassian.beehive.ClusterLock;
10 import com.atlassian.beehive.ClusterLockService;
11 import com.atlassian.sal.api.transaction.TransactionCallback;
12 import com.atlassian.sal.api.transaction.TransactionTemplate;
13 import com.atlassian.tenancy.api.Tenant;
14 import net.java.ao.EntityManager;
15 import org.junit.After;
16 import org.junit.Before;
17 import org.junit.Rule;
18 import org.junit.Test;
19 import org.junit.rules.ExpectedException;
20 import org.junit.runner.RunWith;
21 import org.mockito.Mock;
22 import org.mockito.Mockito;
23 import org.mockito.junit.MockitoJUnitRunner;
24 import org.osgi.framework.Bundle;
25
26 import javax.sql.DataSource;
27 import java.util.concurrent.TimeUnit;
28
29 import static org.hamcrest.core.Is.isA;
30 import static org.hamcrest.core.IsNull.nullValue;
31 import static org.junit.Assert.assertNotNull;
32 import static org.junit.Assert.fail;
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyString;
35 import static org.mockito.ArgumentMatchers.isNull;
36 import static org.mockito.Mockito.mock;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
39
40
41
42
43 @RunWith(MockitoJUnitRunner.class)
44 public class TenantAwareDataSourceProviderActiveObjectsFactoryTest {
45 private DataSourceProviderActiveObjectsFactory activeObjectsFactory;
46
47 @Rule
48 public ExpectedException expectedException = ExpectedException.none();
49
50 @Mock
51 private ActiveObjectUpgradeManager upgradeManager;
52
53 @Mock
54 private TenantAwareDataSourceProvider tenantAwareDataSourceProvider;
55
56 @Mock
57 private EntityManagerFactory entityManagerFactory;
58
59 @Mock
60 private TransactionTemplate transactionTemplate;
61
62 @Mock
63 private ActiveObjectsConfiguration configuration;
64
65 @Mock
66 private TransactionSynchronisationManager transactionSynchronizationManager;
67
68 @Mock
69 private Tenant tenant;
70
71 @Mock
72 private ClusterLock clusterLock;
73
74 @Before
75 public void setUp() {
76 Bundle bundle = mock(Bundle.class);
77 when(bundle.getSymbolicName()).thenReturn("com.example.plugin");
78 PluginKey pluginKey = PluginKey.fromBundle(bundle);
79 ClusterLockService clusterLockService = mock(ClusterLockService.class);
80 when(clusterLockService.getLockForName(anyString())).thenReturn(clusterLock);
81 when(configuration.getDataSourceType()).thenReturn(DataSourceType.APPLICATION);
82 when(configuration.getPluginKey()).thenReturn(pluginKey);
83 activeObjectsFactory = new DataSourceProviderActiveObjectsFactory(upgradeManager, entityManagerFactory,
84 tenantAwareDataSourceProvider, transactionTemplate, clusterLockService);
85 activeObjectsFactory.setTransactionSynchronizationManager(transactionSynchronizationManager);
86 when(transactionTemplate.execute(any())).thenAnswer(invocation ->
87 ((TransactionCallback<?>) invocation.getArgument(0)).doInTransaction());
88 }
89
90 @After
91 public void tearDown() {
92 activeObjectsFactory = null;
93 entityManagerFactory = null;
94 tenantAwareDataSourceProvider = null;
95 }
96
97 @Test
98 public void testCreateWithNullDataSource() throws Exception {
99 when(tenantAwareDataSourceProvider.getDataSource(tenant)).thenReturn(null);
100 when(clusterLock.tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)).thenReturn(true);
101 try {
102 activeObjectsFactory.create(configuration, tenant);
103 fail("Should have thrown " + ActiveObjectsPluginException.class.getName());
104 } catch (ActiveObjectsPluginException e) {
105 verify(clusterLock).tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
106 verify(clusterLock).unlock();
107 }
108 }
109
110 @Test
111 public void testCreateWithNullDatabaseType() throws Exception {
112 final DataSource dataSource = mock(DataSource.class);
113
114 when(tenantAwareDataSourceProvider.getDataSource(tenant)).thenReturn(dataSource);
115 when(clusterLock.tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)).thenReturn(true);
116 when(tenantAwareDataSourceProvider.getDatabaseType(tenant)).thenReturn(null);
117 try {
118 activeObjectsFactory.create(configuration, tenant);
119 fail("Should have thrown " + ActiveObjectsPluginException.class.getName());
120 } catch (ActiveObjectsPluginException e) {
121 verify(clusterLock).tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
122 verify(clusterLock).unlock();
123 }
124 }
125
126 @Test
127 public void testCreate() throws Exception {
128 final DataSource dataSource = mock(DataSource.class);
129 final EntityManager entityManager = mock(EntityManager.class);
130
131 when(tenantAwareDataSourceProvider.getDataSource(tenant)).thenReturn(dataSource);
132 when(entityManagerFactory.getEntityManager(anyDataSource(), anyDatabaseType(), isNull(), anyConfiguration())).thenReturn(entityManager);
133 when(configuration.getDataSourceType()).thenReturn(DataSourceType.APPLICATION);
134 when(tenantAwareDataSourceProvider.getDatabaseType(tenant)).thenReturn(DatabaseType.DERBY_EMBEDDED);
135 when(clusterLock.tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)).thenReturn(true);
136
137 assertNotNull(activeObjectsFactory.create(configuration, tenant));
138 verify(entityManagerFactory).getEntityManager(anyDataSource(), anyDatabaseType(), isNull(), anyConfiguration());
139 verify(clusterLock).tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
140 verify(clusterLock).unlock();
141 }
142
143 @Test
144 public void testCreateLockTimeout() throws InterruptedException {
145 when(clusterLock.tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)).thenReturn(false);
146
147 expectedException.expect(ActiveObjectsInitException.class);
148 expectedException.expectCause(nullValue(Throwable.class));
149
150 activeObjectsFactory.create(configuration, tenant);
151 }
152
153 @Test
154 public void testCreateLockInterrupted() throws InterruptedException {
155 when(clusterLock.tryLock(AbstractActiveObjectsFactory.LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)).thenThrow(new InterruptedException());
156
157 expectedException.expect(ActiveObjectsInitException.class);
158 expectedException.expectCause(isA(InterruptedException.class));
159
160 activeObjectsFactory.create(configuration, tenant);
161 }
162
163 private static DataSource anyDataSource() {
164 return Mockito.any();
165 }
166
167 private static DatabaseType anyDatabaseType() {
168 return Mockito.any();
169 }
170
171 private static ActiveObjectsConfiguration anyConfiguration() {
172 return Mockito.any();
173 }
174 }