1 package com.atlassian.plugin.manager.store;
2
3 import java.util.concurrent.locks.ReadWriteLock;
4 import java.util.concurrent.locks.ReentrantLock;
5
6 import com.atlassian.plugin.manager.PluginPersistentState;
7 import com.atlassian.plugin.manager.PluginPersistentStateStore;
8
9 import com.google.common.collect.ImmutableList;
10
11 import org.junit.Before;
12 import org.junit.Rule;
13 import org.junit.Test;
14 import org.junit.contrib.java.lang.system.RestoreSystemProperties;
15 import org.junit.runner.RunWith;
16 import org.junit.runners.Parameterized;
17 import org.mockito.Mock;
18 import org.mockito.invocation.InvocationOnMock;
19 import org.mockito.runners.MockitoJUnitRunner;
20 import org.mockito.stubbing.Answer;
21
22 import static com.atlassian.plugin.manager.store.SynchronizedPluginPersistentStateStore.LockMode;
23 import static com.atlassian.plugin.manager.store.SynchronizedPluginPersistentStateStore.getLockModeProperty;
24 import static org.hamcrest.MatcherAssert.assertThat;
25 import static org.hamcrest.Matchers.is;
26 import static org.mockito.Mockito.doAnswer;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29
30 @RunWith (MockitoJUnitRunner.class)
31 public class TestSynchronizedPluginPersistentStateStore
32 {
33 @Mock PluginPersistentStateStore delegate;
34 @Mock ReadWriteLock readWriteLock;
35 @Mock PluginPersistentState pluginPersistentState;
36
37 ReentrantLock readLock;
38 ReentrantLock writeLock;
39
40 SynchronizedPluginPersistentStateStore synchronizedPluginPersistentStateStore;
41
42 @Before
43 public void setUp() throws Exception
44 {
45 readLock = new ReentrantLock();
46 writeLock = new ReentrantLock();
47 when(readWriteLock.readLock()).thenReturn(readLock);
48 when(readWriteLock.writeLock()).thenReturn(writeLock);
49 synchronizedPluginPersistentStateStore = new SynchronizedPluginPersistentStateStore(delegate, readWriteLock);
50 }
51
52 @Test
53 public void saveGetsWriteLockAndForwardsToDelegate()
54 {
55 final Answer<Object> answer = new LockCheckingAnswer(false, true, null);
56 doAnswer(answer).when(delegate).save(pluginPersistentState);
57 synchronizedPluginPersistentStateStore.save(pluginPersistentState);
58 verify(delegate).save(pluginPersistentState);
59 assertLockState(false, false);
60 }
61
62 @Test
63 public void loadGetsReadLockAndForwardsToDelegate()
64 {
65 final Answer<Object> answer = new LockCheckingAnswer(true, false, pluginPersistentState);
66 when(delegate.load()).thenAnswer(answer);
67 final PluginPersistentState actual = synchronizedPluginPersistentStateStore.load();
68 assertThat(actual, is(pluginPersistentState));
69 verify(delegate).load();
70 assertLockState(false, false);
71 }
72
73 private class LockCheckingAnswer implements Answer<Object>
74 {
75 private final boolean readLocked;
76 private final boolean writeLocked;
77 private final Object result;
78
79 public LockCheckingAnswer(final boolean readLocked, final boolean writeLocked, final Object result)
80 {
81 this.readLocked = readLocked;
82 this.writeLocked = writeLocked;
83 this.result = result;
84 }
85
86 @Override
87 public Object answer(final InvocationOnMock invocationOnMock) throws Throwable
88 {
89 assertLockState(readLocked, writeLocked);
90 return result;
91 }
92 }
93
94 private void assertLockState(final boolean readLocked, final boolean writeLocked)
95 {
96 assertThat(readLock.isLocked(), is(readLocked));
97 assertThat(writeLock.isLocked(), is(writeLocked));
98 }
99
100 public static class TestLockModeDefault
101 {
102 @Test
103 public void defaultLockModeIsReadWrite()
104 {
105 final LockMode lockMode = LockMode.current();
106 assertThat(lockMode, is(LockMode.READWRITE));
107 }
108 }
109
110 @RunWith(Parameterized.class)
111 public static class TestLockMode
112 {
113 @Rule
114 public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(getLockModeProperty());
115
116 final String propertyValue;
117 final LockMode expectedMode;
118 final boolean simple;
119
120 @Parameterized.Parameters (name = "{index}: Property {0} yields {1}")
121 public static Iterable<Object[]> data()
122 {
123 return ImmutableList.<Object[]>builder()
124 .add(new Object[] { "unlocked", LockMode.UNLOCKED, true })
125 .add(new Object[] { "simple", LockMode.SIMPLE, true })
126 .add(new Object[] { "fairsimple", LockMode.FAIRSIMPLE, true })
127 .add(new Object[] { "readwrite", LockMode.READWRITE, false })
128 .add(new Object[] { "fairreadwrite", LockMode.FAIRREADWRITE, false })
129 .build();
130 }
131
132 public TestLockMode(final String propertyValue, final LockMode expectedMode, final boolean simple)
133 {
134 this.propertyValue = propertyValue;
135 this.expectedMode = expectedMode;
136 this.simple = simple;
137 }
138
139 @Test
140 public void propertyValueYieldsExpectedLockMode()
141 {
142 System.setProperty(getLockModeProperty(), propertyValue);
143
144 final LockMode lockMode = LockMode.current();
145 assertThat(lockMode, is(expectedMode));
146 final ReadWriteLock readWriteLock = lockMode.getReadWriteLock();
147 assertThat(readWriteLock.readLock() == readWriteLock.writeLock(), is(simple));
148 }
149 }
150 }