1 |
| package org.jboss.cache.transaction.isolationlevels; |
2 |
| |
3 |
| import junit.framework.TestCase; |
4 |
| import org.jboss.cache.Cache; |
5 |
| import org.jboss.cache.CacheFactory; |
6 |
| import org.jboss.cache.DefaultCacheFactory; |
7 |
| import org.jboss.cache.Fqn; |
8 |
| import org.jboss.cache.lock.IsolationLevel; |
9 |
| import static org.jboss.cache.lock.IsolationLevel.*; |
10 |
| import org.jboss.cache.transaction.DummyTransactionManagerLookup; |
11 |
| |
12 |
| import javax.transaction.Transaction; |
13 |
| import javax.transaction.TransactionManager; |
14 |
| import java.util.Collection; |
15 |
| import java.util.HashSet; |
16 |
| |
17 |
| |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| public abstract class IsolationLevelTestBase extends TestCase |
24 |
| { |
25 |
| protected IsolationLevel isolationLevel; |
26 |
| protected Cache<String, String> cache; |
27 |
| protected TransactionManager transactionManager; |
28 |
| protected Fqn<String> fqn = Fqn.fromString("/a/b/c"); |
29 |
| protected Fqn<String> fqnChild1 = Fqn.fromString("/a/b/c/child1"); |
30 |
| protected Fqn<String> fqnChild2 = Fqn.fromString("/a/b/c/child2"); |
31 |
| protected String k = "key", v = "value"; |
32 |
| protected Collection<IsolationLevel> allowedLevels; |
33 |
| |
34 |
35
| protected void setUp()
|
35 |
| { |
36 |
35
| CacheFactory<String, String> cf = DefaultCacheFactory.getInstance();
|
37 |
35
| cache = cf.createCache(false);
|
38 |
35
| cache.getConfiguration().setIsolationLevel(isolationLevel);
|
39 |
35
| cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
|
40 |
| |
41 |
35
| cache.getConfiguration().setLockAcquisitionTimeout(250);
|
42 |
35
| cache.start();
|
43 |
35
| transactionManager = cache.getConfiguration().getRuntimeConfig().getTransactionManager();
|
44 |
35
| allowedLevels = new HashSet<IsolationLevel>();
|
45 |
| } |
46 |
| |
47 |
35
| protected void tearDown()
|
48 |
| { |
49 |
35
| if (transactionManager != null)
|
50 |
| { |
51 |
| |
52 |
35
| try
|
53 |
| { |
54 |
35
| transactionManager.rollback();
|
55 |
| } |
56 |
| catch (Exception e) |
57 |
| { |
58 |
| |
59 |
| } |
60 |
| } |
61 |
35
| cache.stop();
|
62 |
35
| cache.destroy();
|
63 |
35
| cache = null;
|
64 |
35
| allowedLevels = null;
|
65 |
| } |
66 |
| |
67 |
5
| public void testDirtyRead() throws Exception
|
68 |
| { |
69 |
| |
70 |
5
| allowedLevels.add(NONE);
|
71 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
72 |
| |
73 |
| |
74 |
5
| transactionManager.begin();
|
75 |
5
| cache.put(fqn, k, v);
|
76 |
5
| Transaction t1 = transactionManager.suspend();
|
77 |
| |
78 |
| |
79 |
5
| transactionManager.begin();
|
80 |
5
| try
|
81 |
| { |
82 |
5
| assertEquals(v, cache.get(fqn, k));
|
83 |
2
| transactionManager.commit();
|
84 |
2
| if (!allowedLevels.contains(isolationLevel))
|
85 |
| { |
86 |
0
| fail("Should have thrown an exception");
|
87 |
| } |
88 |
| } |
89 |
| catch (Exception e) |
90 |
| { |
91 |
3
| if (allowedLevels.contains(isolationLevel))
|
92 |
| { |
93 |
0
| throw e;
|
94 |
| } |
95 |
| } |
96 |
| |
97 |
5
| transactionManager.resume(t1);
|
98 |
5
| transactionManager.rollback();
|
99 |
| } |
100 |
| |
101 |
5
| public void testDirtyReadWithNoData() throws Exception
|
102 |
| { |
103 |
| |
104 |
5
| allowedLevels.add(NONE);
|
105 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
106 |
5
| allowedLevels.add(READ_COMMITTED);
|
107 |
5
| allowedLevels.add(REPEATABLE_READ);
|
108 |
| |
109 |
| |
110 |
5
| transactionManager.begin();
|
111 |
5
| assertNull(cache.get(fqn, k));
|
112 |
5
| Transaction t1 = transactionManager.suspend();
|
113 |
| |
114 |
| |
115 |
5
| transactionManager.begin();
|
116 |
5
| try
|
117 |
| { |
118 |
5
| cache.put(fqn, k, v);
|
119 |
4
| transactionManager.commit();
|
120 |
4
| if (!allowedLevels.contains(isolationLevel))
|
121 |
| { |
122 |
0
| fail("Should have thrown an exception");
|
123 |
| } |
124 |
| } |
125 |
| catch (Exception e) |
126 |
| { |
127 |
1
| if (allowedLevels.contains(isolationLevel))
|
128 |
| { |
129 |
0
| throw e;
|
130 |
| } |
131 |
| } |
132 |
| |
133 |
5
| transactionManager.resume(t1);
|
134 |
5
| if (allowedLevels.contains(isolationLevel))
|
135 |
| { |
136 |
4
| assertEquals(v, cache.get(fqn, k));
|
137 |
| } |
138 |
| else |
139 |
| { |
140 |
1
| assertNull(cache.get(fqn, k));
|
141 |
| } |
142 |
5
| transactionManager.rollback();
|
143 |
| } |
144 |
| |
145 |
5
| public void testTwoReads() throws Exception
|
146 |
| { |
147 |
| |
148 |
5
| allowedLevels.add(NONE);
|
149 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
150 |
5
| allowedLevels.add(READ_COMMITTED);
|
151 |
5
| allowedLevels.add(REPEATABLE_READ);
|
152 |
| |
153 |
| |
154 |
5
| cache.put(fqn, k, v);
|
155 |
| |
156 |
| |
157 |
5
| transactionManager.begin();
|
158 |
5
| assertEquals(v, cache.get(fqn, k));
|
159 |
5
| Transaction t1 = transactionManager.suspend();
|
160 |
| |
161 |
| |
162 |
5
| transactionManager.begin();
|
163 |
5
| try
|
164 |
| { |
165 |
5
| assertEquals(v, cache.get(fqn, k));
|
166 |
4
| transactionManager.commit();
|
167 |
4
| if (!allowedLevels.contains(isolationLevel))
|
168 |
| { |
169 |
0
| fail("Should have thrown an exception");
|
170 |
| } |
171 |
| } |
172 |
| catch (Exception e) |
173 |
| { |
174 |
1
| if (allowedLevels.contains(isolationLevel))
|
175 |
| { |
176 |
0
| throw e;
|
177 |
| } |
178 |
| } |
179 |
| |
180 |
5
| transactionManager.resume(t1);
|
181 |
5
| transactionManager.rollback();
|
182 |
| } |
183 |
| |
184 |
5
| public void testTwoWrites() throws Exception
|
185 |
| { |
186 |
| |
187 |
5
| allowedLevels.add(NONE);
|
188 |
| |
189 |
| |
190 |
5
| cache.put(fqn, k, v);
|
191 |
| |
192 |
| |
193 |
5
| transactionManager.begin();
|
194 |
5
| cache.put(fqn, k, v);
|
195 |
5
| Transaction t1 = transactionManager.suspend();
|
196 |
| |
197 |
| |
198 |
5
| transactionManager.begin();
|
199 |
5
| try
|
200 |
| { |
201 |
5
| cache.put(fqn, k, v);
|
202 |
1
| transactionManager.commit();
|
203 |
1
| if (!allowedLevels.contains(isolationLevel))
|
204 |
| { |
205 |
0
| fail("Should have thrown an exception");
|
206 |
| } |
207 |
| } |
208 |
| catch (Exception e) |
209 |
| { |
210 |
4
| if (allowedLevels.contains(isolationLevel))
|
211 |
| { |
212 |
0
| throw e;
|
213 |
| } |
214 |
| } |
215 |
| |
216 |
5
| transactionManager.resume(t1);
|
217 |
5
| transactionManager.rollback();
|
218 |
| } |
219 |
| |
220 |
5
| public void testNonRepeatableRead() throws Exception
|
221 |
| { |
222 |
| |
223 |
5
| allowedLevels.add(NONE);
|
224 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
225 |
5
| allowedLevels.add(READ_COMMITTED);
|
226 |
| |
227 |
| |
228 |
5
| cache.put(fqn, k, v);
|
229 |
| |
230 |
| |
231 |
5
| transactionManager.begin();
|
232 |
5
| assertEquals(v, cache.get(fqn, k));
|
233 |
5
| Transaction t1 = transactionManager.suspend();
|
234 |
| |
235 |
| |
236 |
5
| transactionManager.begin();
|
237 |
5
| try
|
238 |
| { |
239 |
5
| cache.put(fqn, k, v);
|
240 |
3
| transactionManager.commit();
|
241 |
3
| if (!allowedLevels.contains(isolationLevel))
|
242 |
| { |
243 |
0
| fail("Should have thrown an exception");
|
244 |
| } |
245 |
| } |
246 |
| catch (Exception e) |
247 |
| { |
248 |
2
| if (allowedLevels.contains(isolationLevel))
|
249 |
| { |
250 |
0
| throw e;
|
251 |
| } |
252 |
| } |
253 |
| |
254 |
5
| transactionManager.resume(t1);
|
255 |
5
| assertEquals(v, cache.get(fqn, k));
|
256 |
5
| transactionManager.rollback();
|
257 |
| } |
258 |
| |
259 |
5
| public void testNonRepeatableReadWithNoData() throws Exception
|
260 |
| { |
261 |
| |
262 |
| |
263 |
| |
264 |
| |
265 |
| |
266 |
5
| allowedLevels.add(NONE);
|
267 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
268 |
5
| allowedLevels.add(READ_COMMITTED);
|
269 |
5
| allowedLevels.add(REPEATABLE_READ);
|
270 |
| |
271 |
| |
272 |
5
| transactionManager.begin();
|
273 |
5
| assertNull(cache.get(fqn, k));
|
274 |
5
| Transaction t1 = transactionManager.suspend();
|
275 |
| |
276 |
| |
277 |
5
| transactionManager.begin();
|
278 |
5
| try
|
279 |
| { |
280 |
5
| cache.put(fqn, k, v);
|
281 |
4
| transactionManager.commit();
|
282 |
4
| if (!allowedLevels.contains(isolationLevel))
|
283 |
| { |
284 |
0
| fail("Should have thrown an exception");
|
285 |
| } |
286 |
| } |
287 |
| catch (Exception e) |
288 |
| { |
289 |
1
| if (allowedLevels.contains(isolationLevel))
|
290 |
| { |
291 |
0
| throw e;
|
292 |
| } |
293 |
| } |
294 |
| |
295 |
5
| transactionManager.resume(t1);
|
296 |
5
| if (allowedLevels.contains(isolationLevel))
|
297 |
| { |
298 |
4
| assertEquals(v, cache.get(fqn, k));
|
299 |
| } |
300 |
| else |
301 |
| { |
302 |
1
| assertNull(cache.get(fqn, k));
|
303 |
| } |
304 |
5
| transactionManager.rollback();
|
305 |
| } |
306 |
| |
307 |
5
| public void testPhantomRead() throws Exception
|
308 |
| { |
309 |
| |
310 |
5
| allowedLevels.add(NONE);
|
311 |
5
| allowedLevels.add(READ_UNCOMMITTED);
|
312 |
5
| allowedLevels.add(READ_COMMITTED);
|
313 |
5
| allowedLevels.add(REPEATABLE_READ);
|
314 |
| |
315 |
| |
316 |
5
| cache.put(fqn, k, v);
|
317 |
5
| cache.put(fqnChild1, k, v);
|
318 |
| |
319 |
| |
320 |
5
| transactionManager.begin();
|
321 |
5
| int numChildren = cache.getRoot().getChild(fqn).getChildren().size();
|
322 |
5
| assertEquals(1, numChildren);
|
323 |
5
| Transaction t1 = transactionManager.suspend();
|
324 |
| |
325 |
| |
326 |
5
| transactionManager.begin();
|
327 |
5
| try
|
328 |
| { |
329 |
5
| cache.put(fqnChild2, k, v);
|
330 |
4
| transactionManager.commit();
|
331 |
4
| if (!allowedLevels.contains(isolationLevel))
|
332 |
| { |
333 |
0
| fail("Should have thrown an exception");
|
334 |
| } |
335 |
| } |
336 |
| catch (Exception e) |
337 |
| { |
338 |
1
| if (allowedLevels.contains(isolationLevel))
|
339 |
| { |
340 |
0
| throw e;
|
341 |
| } |
342 |
| } |
343 |
| |
344 |
5
| transactionManager.resume(t1);
|
345 |
5
| numChildren = cache.getRoot().getChild(fqn).getChildren().size();
|
346 |
5
| assertEquals(allowedLevels.contains(isolationLevel) ? 2 : 1, numChildren);
|
347 |
5
| transactionManager.rollback();
|
348 |
| } |
349 |
| } |