1   package com.atlassian.util.concurrent;
2   
3   import static junit.framework.Assert.fail;
4   import static org.junit.Assert.assertEquals;
5   import static org.junit.Assert.assertTrue;
6   
7   import org.junit.Test;
8   
9   import java.util.concurrent.Callable;
10  import java.util.concurrent.atomic.AtomicBoolean;
11  import java.util.concurrent.atomic.AtomicReference;
12  import java.util.concurrent.locks.Lock;
13  import java.util.concurrent.locks.ReentrantLock;
14  
15  public class LockManagerTest {
16      private final Function<String, String> reverser = new Function<String, String>() {
17          public String get(final String input) {
18              final StringBuilder result = new StringBuilder();
19              for (int i = input.length(); i > 0; i--) {
20                  result.append(input.charAt(i - 1));
21              }
22              return result.toString();
23          };
24      };
25  
26      @Test public void testLockManagerLocksAndUnlocksAndReturnsValue() throws Exception {
27          final AtomicReference<String> ref = new AtomicReference<String>();
28          final AtomicBoolean called = new AtomicBoolean();
29          final AtomicBoolean locked = new AtomicBoolean();
30          final AtomicBoolean unlocked = new AtomicBoolean();
31          final LockManager<String> manager = new LockManagers.Manager<String, String>(new Function<String, Lock>() {
32              public Lock get(final String input) {
33                  ref.set(input);
34                  return new ReentrantLock() {
35                      @Override public void lock() {
36                          locked.set(true);
37                          super.lock();
38                      }
39  
40                      @Override public void unlock() {
41                          unlocked.set(true);
42                          super.unlock();
43                      }
44                  };
45              };
46          }, reverser);
47  
48          assertEquals("blah", manager.withLock("input", new Callable<String>() {
49              public String call() {
50                  called.set(true);
51                  return "blah";
52              }
53          }));
54  
55          assertTrue(called.get());
56          assertTrue(locked.get());
57          assertTrue(unlocked.get());
58          assertEquals("tupni", ref.get());
59      }
60  
61      @Test public void testLockManagerLocksAndUnlocksAndThrows() throws Exception {
62          final AtomicReference<String> ref = new AtomicReference<String>();
63          final AtomicBoolean called = new AtomicBoolean();
64          final AtomicBoolean locked = new AtomicBoolean();
65          final AtomicBoolean unlocked = new AtomicBoolean();
66          final LockManager<String> manager = new LockManagers.Manager<String, String>(new Function<String, Lock>() {
67              public Lock get(final String input) {
68                  ref.set(input);
69                  return new ReentrantLock() {
70                      @Override public void lock() {
71                          locked.set(true);
72                          super.lock();
73                      }
74  
75                      @Override public void unlock() {
76                          unlocked.set(true);
77                          super.unlock();
78                      }
79                  };
80              };
81          }, reverser);
82  
83          class StupidException extends Exception {}
84  
85          try {
86              manager.withLock("input", new Callable<String>() {
87                  public String call() throws StupidException {
88                      called.set(true);
89                      throw new StupidException();
90                  }
91              });
92              fail("StupidException expected");
93          }
94          catch (final StupidException ignore) {}
95  
96          assertTrue(called.get());
97          assertTrue(locked.get());
98          assertTrue(unlocked.get());
99          assertEquals("tupni", ref.get());
100     }
101 
102     @Test public void testLockManagerLocksAndUnlocksAndRuns() throws Exception {
103         final AtomicReference<String> ref = new AtomicReference<String>();
104         final AtomicBoolean called = new AtomicBoolean();
105         final AtomicBoolean locked = new AtomicBoolean();
106         final AtomicBoolean unlocked = new AtomicBoolean();
107         final LockManager<String> manager = new LockManagers.Manager<String, String>(new Function<String, Lock>() {
108             public Lock get(final String input) {
109                 ref.set(input);
110                 return new ReentrantLock() {
111                     @Override public void lock() {
112                         locked.set(true);
113                         super.lock();
114                     }
115 
116                     @Override public void unlock() {
117                         unlocked.set(true);
118                         super.unlock();
119                     }
120                 };
121             };
122         }, reverser);
123 
124         manager.withLock("input", new Runnable() {
125             public void run() {
126                 called.set(true);
127             }
128         });
129 
130         assertTrue(called.get());
131         assertTrue(locked.get());
132         assertTrue(unlocked.get());
133         assertEquals("tupni", ref.get());
134     }
135 
136     @Test public void testLockManagerLocksAndUnlocksAndThrowsRuntime() throws Exception {
137         final AtomicReference<String> ref = new AtomicReference<String>();
138         final AtomicBoolean called = new AtomicBoolean();
139         final AtomicBoolean locked = new AtomicBoolean();
140         final AtomicBoolean unlocked = new AtomicBoolean();
141         final LockManager<String> manager = new LockManagers.Manager<String, String>(new Function<String, Lock>() {
142             public Lock get(final String input) {
143                 ref.set(input);
144                 return new ReentrantLock() {
145                     @Override public void lock() {
146                         locked.set(true);
147                         super.lock();
148                     }
149 
150                     @Override public void unlock() {
151                         unlocked.set(true);
152                         super.unlock();
153                     }
154                 };
155             };
156         }, reverser);
157 
158         class StupidException extends RuntimeException {}
159 
160         try {
161             manager.withLock("input", new Runnable() {
162                 public void run() throws StupidException {
163                     called.set(true);
164                     throw new StupidException();
165                 }
166             });
167             fail("StupidException expected");
168         }
169         catch (final StupidException ignore) {}
170 
171         assertTrue(called.get());
172         assertTrue(locked.get());
173         assertTrue(unlocked.get());
174         assertEquals("tupni", ref.get());
175     }
176 }