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 */ 017package org.apache.commons.transaction.memory; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import junit.framework.Test; 023import junit.framework.TestSuite; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028import org.apache.commons.transaction.util.CommonsLoggingLogger; 029import org.apache.commons.transaction.util.LoggerFacade; 030import org.apache.commons.transaction.util.RendezvousBarrier; 031 032/** 033 * Tests for map wrapper. 034 * 035 * @version $Id: OptimisticMapWrapperTest.java 493628 2007-01-07 01:42:48Z joerg $ 036 */ 037public class OptimisticMapWrapperTest extends MapWrapperTest { 038 039 private static final Log log = LogFactory.getLog(OptimisticMapWrapperTest.class.getName()); 040 private static final LoggerFacade sLogger = new CommonsLoggingLogger(log); 041 042 public static Test suite() { 043 TestSuite suite = new TestSuite(OptimisticMapWrapperTest.class); 044 return suite; 045 } 046 047 public static void main(java.lang.String[] args) { 048 junit.textui.TestRunner.run(suite()); 049 } 050 051 public OptimisticMapWrapperTest(String testName) { 052 super(testName); 053 } 054 055 protected TransactionalMapWrapper getNewWrapper(Map map) { 056 return new OptimisticMapWrapper(map); 057 } 058 059 // XXX no need for this code, just to make clear those tests are run as well 060 public void testBasic() throws Throwable { 061 super.testBasic(); 062 } 063 064 public void testComplex() throws Throwable { 065 super.testComplex(); 066 } 067 068 public void testSets() throws Throwable { 069 super.testSets(); 070 } 071 072 public void testMulti() throws Throwable { 073 log.info("Checking concurrent transaction features"); 074 075 final Map map1 = new HashMap(); 076 077 final OptimisticMapWrapper txMap1 = (OptimisticMapWrapper) getNewWrapper(map1); 078 079 final RendezvousBarrier beforeCommitBarrier = 080 new RendezvousBarrier("Before Commit", 2, BARRIER_TIMEOUT, sLogger); 081 082 final RendezvousBarrier afterCommitBarrier = new RendezvousBarrier("After Commit", 2, BARRIER_TIMEOUT, sLogger); 083 084 Thread thread1 = new Thread(new Runnable() { 085 public void run() { 086 txMap1.startTransaction(); 087 try { 088 beforeCommitBarrier.meet(); 089 txMap1.put("key1", "value2"); 090 txMap1.commitTransaction(); 091 afterCommitBarrier.call(); 092 } catch (InterruptedException e) { 093 sLogger.logWarning("Thread interrupted", e); 094 afterCommitBarrier.reset(); 095 beforeCommitBarrier.reset(); 096 } 097 } 098 }, "Thread1"); 099 100 txMap1.put("key1", "value1"); 101 102 txMap1.startTransaction(); 103 thread1.start(); 104 105 report("value1", (String) txMap1.get("key1")); 106 beforeCommitBarrier.call(); 107 afterCommitBarrier.meet(); 108 // we have serializable as isolation level, that's why I will still see the old value 109 report("value1", (String) txMap1.get("key1")); 110 111 // now when I override it it should of course be my value 112 txMap1.put("key1", "value3"); 113 report("value3", (String) txMap1.get("key1")); 114 115 // after rollback it must be the value written by the other thread 116 txMap1.rollbackTransaction(); 117 report("value2", (String) txMap1.get("key1")); 118 } 119 120 public void testConflict() throws Throwable { 121 log.info("Checking concurrent transaction features"); 122 123 final Map map1 = new HashMap(); 124 125 final OptimisticMapWrapper txMap1 = (OptimisticMapWrapper) getNewWrapper(map1); 126 127 final RendezvousBarrier beforeCommitBarrier = 128 new RendezvousBarrier("Before Commit", 2, BARRIER_TIMEOUT, sLogger); 129 130 final RendezvousBarrier afterCommitBarrier = new RendezvousBarrier("After Commit", 2, BARRIER_TIMEOUT, sLogger); 131 132 Thread thread1 = new Thread(new Runnable() { 133 public void run() { 134 txMap1.startTransaction(); 135 try { 136 beforeCommitBarrier.meet(); 137 txMap1.put("key1", "value2"); 138 txMap1.commitTransaction(); 139 afterCommitBarrier.call(); 140 } catch (InterruptedException e) { 141 sLogger.logWarning("Thread interrupted", e); 142 afterCommitBarrier.reset(); 143 beforeCommitBarrier.reset(); 144 } 145 } 146 }, "Thread1"); 147 148 txMap1.put("key1", "value1"); 149 150 txMap1.startTransaction(); 151 thread1.start(); 152 153 report("value1", (String) txMap1.get("key1")); 154 beforeCommitBarrier.call(); 155 afterCommitBarrier.meet(); 156 // we have serializable as isolation level, that's why I will still see the old value 157 report("value1", (String) txMap1.get("key1")); 158 159 // now when I override it it should of course be my value 160 txMap1.put("key1", "value3"); 161 report("value3", (String) txMap1.get("key1")); 162 163 boolean conflict = false; 164 165 try { 166 txMap1.commitTransaction(); 167 } catch (ConflictException ce) { 168 conflict = true; 169 } 170 assertTrue(conflict); 171 // after failed commit it must be the value written by the other thread 172 report("value2", (String) map1.get("key1")); 173 174 // force commit anyhow... 175 txMap1.commitTransaction(true); 176 // after successful commit it must be the value written by this thread 177 report("value3", (String) txMap1.get("key1")); 178 report("value3", (String) map1.get("key1")); 179 } 180 181 public void testTxControl() throws Throwable { 182 super.testTxControl(); 183 } 184 185}