1 package org.wamblee.concurrency;
3 import static junit.framework.Assert.*;
4 import static org.mockito.Matchers.*;
5 import static org.mockito.Mockito.*;
7 import java.util.ArrayList;
9 import java.util.Timer;
10 import java.util.TimerTask;
11 import java.util.concurrent.atomic.AtomicInteger;
13 import org.junit.Before;
14 import org.junit.Test;
15 import org.mockito.invocation.InvocationOnMock;
16 import org.mockito.stubbing.Answer;
18 public class ReadWriteLockProxyFactoryTest {
21 * This test works with time intervals of this size.
23 private static final int INTERVAL_MILLIS = 10;
25 public static interface X {
31 public static interface Y {
32 void doY(String aValue);
35 public static interface Z extends X, Y {
39 private final Runnable doX = new Runnable() {
45 private final Runnable doNoLock = new Runnable() {
51 private final Runnable doY = new Runnable() {
57 private ReadWriteLockProxyFactory<Z> factory;
61 private boolean threadFailed;
63 private List<Thread> threads;
68 factory = new ReadWriteLockProxyFactory<ReadWriteLockProxyFactoryTest.Z>();
72 threads = new ArrayList<Thread>();
75 private void startTiming() {
76 tstart = System.currentTimeMillis();
79 private float endTiming() {
80 return (float) (System.currentTimeMillis() - tstart) / INTERVAL_MILLIS;
83 private void sleep(int aUnits) {
85 Thread.sleep(aUnits * INTERVAL_MILLIS);
86 } catch (InterruptedException e) {
91 private void schedule(final AtomicInteger aUnstartedThreads,
92 final Thread aThread, int aUnits) {
93 aUnstartedThreads.incrementAndGet();
94 timer.schedule(new TimerTask() {
98 aUnstartedThreads.decrementAndGet();
100 }, aUnits * INTERVAL_MILLIS);
103 private void schedule(AtomicInteger aUnstartedThreads, Runnable aTask,
105 Thread t = new Thread(aTask);
106 schedule(aUnstartedThreads, t, aUnits);
110 private void join(AtomicInteger aUnstartedThreads, List<Thread> aThreads) {
111 while (aUnstartedThreads.get() > 0) {
114 for (Thread t : aThreads) {
117 } catch (InterruptedException e) {
122 assertFalse(threadFailed);
125 private void join(AtomicInteger aUnstartedThreads) {
126 join(aUnstartedThreads, threads);
129 private void stubDelays() {
132 public void doX(int aValue) {
137 public void doY(String aValue) {
142 public void doNoLocking() {
148 Answer sleep = new Answer() {
150 public Object answer(InvocationOnMock aInvocation) throws Throwable {
158 public void testProxyDelegates() {
159 service = mock(Z.class);
161 assertTrue(proxyX instanceof X);
162 assertTrue(proxyY instanceof Y);
165 verify(service).doX(10);
169 verify(service).doY("hello");
173 private void createProxy() {
174 proxyX = factory.getProxy(service, X.class, Y.class);
179 public void testConcurrentReadCalls() {
183 AtomicInteger unstarted = new AtomicInteger();
184 for (int i = 0; i < n; i++) {
185 schedule(unstarted, doX, 0);
188 float duration = endTiming();
189 assertTrue(duration < 15);
193 public void testNoConcurrentWrites() {
197 AtomicInteger unstarted = new AtomicInteger();
198 for (int i = 0; i < n; i++) {
199 schedule(unstarted, doY, 0);
202 float duration = endTiming();
203 System.out.println("no concurrent writes: duration " + duration);
204 assertTrue(duration >= n * 10);
208 public void testConcurrentWriteAndNoLock() {
211 AtomicInteger unstarted = new AtomicInteger();
213 schedule(unstarted, doY, 0);
214 for (int i = 0; i < 10; i++) {
215 schedule(unstarted, doNoLock, 0);
218 float duration = endTiming();
219 System.out.println("concurrent write and no lock: duration: " +
221 assertTrue(duration < 15);
225 public void testNoConcurrentReadAndWrite() {
229 AtomicInteger unstartedReaders = new AtomicInteger();
230 for (int i = 0; i < 4; i++) {
231 schedule(unstartedReaders, doX, 0);
233 List<Thread> readers = threads;
234 threads = new ArrayList<Thread>();
235 // start the write some time later.
236 AtomicInteger unstartedWriters = new AtomicInteger();
237 schedule(unstartedWriters, doY, 5);
239 join(unstartedReaders, readers);
240 float duration = endTiming();
241 System.out.println("no concurrent read and write: readers duration: " +
243 assertTrue(duration < 15);
244 join(unstartedWriters, threads);
245 duration = endTiming();
246 System.out.println("no concurrent read and write: writer duration: " +
248 assertTrue(duration >= 20 && duration <= 25);