001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.transaction.memory;
018:
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import javax.transaction.Status;
025:
026: import junit.framework.Test;
027: import junit.framework.TestCase;
028: import junit.framework.TestSuite;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032:
033: import org.apache.commons.transaction.util.CommonsLoggingLogger;
034: import org.apache.commons.transaction.util.LoggerFacade;
035: import org.apache.commons.transaction.util.RendezvousBarrier;
036:
037: /**
038: * Tests for map wrapper.
039: *
040: * @version $Id: MapWrapperTest.java 493628 2007-01-07 01:42:48Z joerg $
041: */
042: public class MapWrapperTest extends TestCase {
043:
044: private static final Log log = LogFactory
045: .getLog(MapWrapperTest.class.getName());
046: private static final LoggerFacade sLogger = new CommonsLoggingLogger(
047: log);
048:
049: protected static final long BARRIER_TIMEOUT = 20000;
050:
051: // XXX need this, as JUnit seems to print only part of these strings
052: protected static void report(String should, String is) {
053: if (!should.equals(is)) {
054: fail("\nWrong output:\n'" + is + "'\nShould be:\n'"
055: + should + "'\n");
056: }
057: }
058:
059: protected static void checkCollection(Collection col,
060: Object[] values) {
061: int cnt = 0;
062: int trueCnt = 0;
063:
064: for (Iterator it = col.iterator(); it.hasNext();) {
065: cnt++;
066: Object value1 = it.next();
067: for (int i = 0; i < values.length; i++) {
068: Object value2 = values[i];
069: if (value2.equals(value1))
070: trueCnt++;
071: }
072: }
073: assertEquals(cnt, values.length);
074: assertEquals(trueCnt, values.length);
075: }
076:
077: public static Test suite() {
078: TestSuite suite = new TestSuite(MapWrapperTest.class);
079: return suite;
080: }
081:
082: public static void main(java.lang.String[] args) {
083: junit.textui.TestRunner.run(suite());
084: }
085:
086: public MapWrapperTest(String testName) {
087: super (testName);
088: }
089:
090: protected TransactionalMapWrapper getNewWrapper(Map map) {
091: return new TransactionalMapWrapper(map);
092: }
093:
094: public void testBasic() throws Throwable {
095:
096: sLogger.logInfo("Checking basic transaction features");
097:
098: final Map map1 = new HashMap();
099:
100: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
101:
102: assertTrue(txMap1.isEmpty());
103:
104: // make sure changes are propagated to wrapped map outside tx
105: txMap1.put("key1", "value1");
106: report("value1", (String) map1.get("key1"));
107: assertFalse(txMap1.isEmpty());
108:
109: // make sure changes are progated to wrapped map only after commit
110: txMap1.startTransaction();
111: assertFalse(txMap1.isEmpty());
112: txMap1.put("key1", "value2");
113: report("value1", (String) map1.get("key1"));
114: report("value2", (String) txMap1.get("key1"));
115: txMap1.commitTransaction();
116: report("value2", (String) map1.get("key1"));
117: report("value2", (String) txMap1.get("key1"));
118:
119: // make sure changes are reverted after rollback
120: txMap1.startTransaction();
121: txMap1.put("key1", "value3");
122: txMap1.rollbackTransaction();
123: report("value2", (String) map1.get("key1"));
124: report("value2", (String) txMap1.get("key1"));
125: }
126:
127: public void testContainsKeyWithNullValue() throws Throwable {
128:
129: sLogger
130: .logInfo("Checking containsKey returns true when the value is null");
131:
132: final Map map1 = new HashMap();
133:
134: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
135:
136: assertTrue(txMap1.isEmpty());
137:
138: // make sure changes are propagated to wrapped map outside tx
139: txMap1.put("key1", null);
140: assertTrue(txMap1.containsKey("key1"));
141:
142: // make sure changes are progated to wrapped map after commit
143: txMap1.startTransaction();
144: txMap1.put("key2", null);
145: assertTrue(txMap1.containsKey("key2"));
146: txMap1.remove("key1");
147: assertTrue(map1.containsKey("key1"));
148: txMap1.commitTransaction();
149: assertTrue(txMap1.containsKey("key2"));
150: assertFalse(txMap1.containsKey("key1"));
151:
152: txMap1.startTransaction();
153: assertTrue(txMap1.containsKey("key2"));
154: txMap1.remove("key2");
155: assertFalse(txMap1.containsKey("key2"));
156: txMap1.commitTransaction();
157: }
158:
159: public void testComplex() throws Throwable {
160:
161: sLogger
162: .logInfo("Checking advanced and complex transaction features");
163:
164: final Map map1 = new HashMap();
165:
166: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
167:
168: // first fill in some global values:
169: txMap1.put("key1", "value1");
170: txMap1.put("key2", "value2");
171:
172: // let's see if we have all values:
173: sLogger.logInfo("Checking if global values are present");
174:
175: assertTrue(txMap1.containsValue("value1"));
176: assertTrue(txMap1.containsValue("value2"));
177: assertFalse(txMap1.containsValue("novalue"));
178:
179: // ... and all keys
180: sLogger.logInfo("Checking if global keys are present");
181: assertTrue(txMap1.containsKey("key1"));
182: assertTrue(txMap1.containsKey("key2"));
183: assertFalse(txMap1.containsKey("nokey"));
184:
185: // and now some inside a transaction
186: txMap1.startTransaction();
187: txMap1.put("key3", "value3");
188: txMap1.put("key4", "value4");
189:
190: // let's see if we have all values:
191: sLogger
192: .logInfo("Checking if values inside transactions are present");
193: assertTrue(txMap1.containsValue("value1"));
194: assertTrue(txMap1.containsValue("value2"));
195: assertTrue(txMap1.containsValue("value3"));
196: assertTrue(txMap1.containsValue("value4"));
197: assertFalse(txMap1.containsValue("novalue"));
198:
199: // ... and all keys
200: sLogger
201: .logInfo("Checking if keys inside transactions are present");
202: assertTrue(txMap1.containsKey("key1"));
203: assertTrue(txMap1.containsKey("key2"));
204: assertTrue(txMap1.containsKey("key3"));
205: assertTrue(txMap1.containsKey("key4"));
206: assertFalse(txMap1.containsKey("nokey"));
207:
208: // now let's delete some old stuff
209: sLogger.logInfo("Checking remove inside transactions");
210: txMap1.remove("key1");
211: assertFalse(txMap1.containsKey("key1"));
212: assertFalse(txMap1.containsValue("value1"));
213: assertNull(txMap1.get("key1"));
214: assertEquals(3, txMap1.size());
215:
216: // and some newly created
217: txMap1.remove("key3");
218: assertFalse(txMap1.containsKey("key3"));
219: assertFalse(txMap1.containsValue("value3"));
220: assertNull(txMap1.get("key3"));
221: assertEquals(2, txMap1.size());
222:
223: sLogger.logInfo("Checking remove and propagation after commit");
224: txMap1.commitTransaction();
225:
226: txMap1.remove("key1");
227: assertFalse(txMap1.containsKey("key1"));
228: assertFalse(txMap1.containsValue("value1"));
229: assertNull(txMap1.get("key1"));
230: assertFalse(txMap1.containsKey("key3"));
231: assertFalse(txMap1.containsValue("value3"));
232: assertNull(txMap1.get("key3"));
233: assertEquals(2, txMap1.size());
234: }
235:
236: public void testSets() throws Throwable {
237:
238: sLogger.logInfo("Checking set opertaions");
239:
240: final Map map1 = new HashMap();
241:
242: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
243:
244: // first fill in some global values:
245: txMap1.put("key1", "value1");
246: txMap1.put("key2", "value200");
247:
248: // and now some inside a transaction
249: txMap1.startTransaction();
250: txMap1.put("key2", "value2"); // modify
251: txMap1.put("key3", "value3");
252: txMap1.put("key4", "value4");
253:
254: // check entry set
255: boolean key1P, key2P, key3P, key4P;
256: key1P = key2P = key3P = key4P = false;
257: int cnt = 0;
258: for (Iterator it = txMap1.entrySet().iterator(); it.hasNext();) {
259: cnt++;
260: Map.Entry entry = (Map.Entry) it.next();
261: if (entry.getKey().equals("key1")
262: && entry.getValue().equals("value1"))
263: key1P = true;
264: else if (entry.getKey().equals("key2")
265: && entry.getValue().equals("value2"))
266: key2P = true;
267: else if (entry.getKey().equals("key3")
268: && entry.getValue().equals("value3"))
269: key3P = true;
270: else if (entry.getKey().equals("key4")
271: && entry.getValue().equals("value4"))
272: key4P = true;
273: }
274: assertEquals(cnt, 4);
275: assertTrue(key1P && key2P && key3P && key4P);
276:
277: checkCollection(txMap1.values(), new String[] { "value1",
278: "value2", "value3", "value4" });
279: checkCollection(txMap1.keySet(), new String[] { "key1", "key2",
280: "key3", "key4" });
281:
282: txMap1.commitTransaction();
283:
284: // check again after commit (should be the same)
285: key1P = key2P = key3P = key4P = false;
286: cnt = 0;
287: for (Iterator it = txMap1.entrySet().iterator(); it.hasNext();) {
288: cnt++;
289: Map.Entry entry = (Map.Entry) it.next();
290: if (entry.getKey().equals("key1")
291: && entry.getValue().equals("value1"))
292: key1P = true;
293: else if (entry.getKey().equals("key2")
294: && entry.getValue().equals("value2"))
295: key2P = true;
296: else if (entry.getKey().equals("key3")
297: && entry.getValue().equals("value3"))
298: key3P = true;
299: else if (entry.getKey().equals("key4")
300: && entry.getValue().equals("value4"))
301: key4P = true;
302: }
303: assertEquals(cnt, 4);
304: assertTrue(key1P && key2P && key3P && key4P);
305:
306: checkCollection(txMap1.values(), new String[] { "value1",
307: "value2", "value3", "value4" });
308: checkCollection(txMap1.keySet(), new String[] { "key1", "key2",
309: "key3", "key4" });
310:
311: // now try clean
312:
313: txMap1.startTransaction();
314:
315: // add
316: txMap1.put("key5", "value5");
317: // modify
318: txMap1.put("key4", "value400");
319: // delete
320: txMap1.remove("key1");
321:
322: assertEquals(txMap1.size(), 4);
323:
324: txMap1.clear();
325: assertEquals(txMap1.size(), 0);
326: assertEquals(map1.size(), 4);
327:
328: // add
329: txMap1.put("key5", "value5");
330: // delete
331: txMap1.remove("key1");
332:
333: // adding one, not removing anything gives size 1
334: assertEquals(txMap1.size(), 1);
335: assertEquals(map1.size(), 4);
336: assertNull(txMap1.get("key4"));
337: assertNotNull(txMap1.get("key5"));
338:
339: txMap1.commitTransaction();
340:
341: // after commit clear must have been propagated to wrapped map:
342: assertEquals(txMap1.size(), 1);
343: assertEquals(map1.size(), 1);
344: assertNull(txMap1.get("key4"));
345: assertNotNull(txMap1.get("key5"));
346: assertNull(map1.get("key4"));
347: assertNotNull(map1.get("key5"));
348: }
349:
350: public void testMulti() throws Throwable {
351: sLogger.logInfo("Checking concurrent transaction features");
352:
353: final Map map1 = new HashMap();
354:
355: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
356:
357: final RendezvousBarrier beforeCommitBarrier = new RendezvousBarrier(
358: "Before Commit", 2, BARRIER_TIMEOUT, sLogger);
359:
360: final RendezvousBarrier afterCommitBarrier = new RendezvousBarrier(
361: "After Commit", 2, BARRIER_TIMEOUT, sLogger);
362:
363: Thread thread1 = new Thread(new Runnable() {
364: public void run() {
365: txMap1.startTransaction();
366: try {
367: beforeCommitBarrier.meet();
368: txMap1.put("key1", "value2");
369: txMap1.commitTransaction();
370: afterCommitBarrier.call();
371: } catch (InterruptedException e) {
372: sLogger.logWarning("Thread interrupted", e);
373: afterCommitBarrier.reset();
374: beforeCommitBarrier.reset();
375: }
376: }
377: }, "Thread1");
378:
379: txMap1.put("key1", "value1");
380:
381: txMap1.startTransaction();
382: thread1.start();
383:
384: report("value1", (String) txMap1.get("key1"));
385: beforeCommitBarrier.call();
386: afterCommitBarrier.meet();
387: // we have read committed as isolation level, that's why I will see the new value of the other thread now
388: report("value2", (String) txMap1.get("key1"));
389:
390: // now when I override it it should of course be my value again
391: txMap1.put("key1", "value3");
392: report("value3", (String) txMap1.get("key1"));
393:
394: // after rollback it must be the value written by the other thread again
395: txMap1.rollbackTransaction();
396: report("value2", (String) txMap1.get("key1"));
397: }
398:
399: public void testTxControl() throws Throwable {
400: sLogger
401: .logInfo("Checking advanced transaction control (heavily used in JCA implementation)");
402:
403: final Map map1 = new HashMap();
404:
405: final TransactionalMapWrapper txMap1 = getNewWrapper(map1);
406:
407: assertEquals(txMap1.getTransactionState(),
408: Status.STATUS_NO_TRANSACTION);
409: txMap1.startTransaction();
410: assertEquals(txMap1.getTransactionState(), Status.STATUS_ACTIVE);
411:
412: assertTrue(txMap1.isReadOnly());
413: txMap1.put("key", "value");
414: assertFalse(txMap1.isReadOnly());
415:
416: assertFalse(txMap1.isTransactionMarkedForRollback());
417: txMap1.markTransactionForRollback();
418: assertTrue(txMap1.isTransactionMarkedForRollback());
419:
420: boolean failed = false;
421: try {
422: txMap1.commitTransaction();
423: } catch (IllegalStateException ise) {
424: failed = true;
425: }
426: assertTrue(failed);
427: txMap1.rollbackTransaction();
428: assertEquals(txMap1.getTransactionState(),
429: Status.STATUS_NO_TRANSACTION);
430:
431: txMap1.startTransaction();
432: final TransactionalMapWrapper.TxContext ctx = txMap1
433: .suspendTransaction();
434: final RendezvousBarrier afterSuspendBarrier = new RendezvousBarrier(
435: "After Suspend", 2, BARRIER_TIMEOUT, sLogger);
436:
437: new Thread(new Runnable() {
438: public void run() {
439: txMap1.resumeTransaction(ctx);
440: txMap1.put("key2", "value2");
441: txMap1.suspendTransaction();
442: afterSuspendBarrier.call();
443: }
444: }).start();
445:
446: afterSuspendBarrier.meet();
447: txMap1.resumeTransaction(ctx);
448:
449: assertEquals(txMap1.size(), 1);
450: txMap1.put("key3", "value3");
451: assertEquals(txMap1.size(), 2);
452: assertEquals(map1.size(), 0);
453:
454: txMap1.commitTransaction();
455: assertEquals(txMap1.size(), 2);
456: assertEquals(map1.size(), 2);
457: }
458:
459: }
|