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