001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.ioc.internal.util;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
018:
019: import java.util.List;
020:
021: import org.apache.tapestry.ioc.internal.util.ConcurrentBarrier;
022: import org.apache.tapestry.ioc.test.TestBase;
023: import org.testng.annotations.Test;
024:
025: /**
026: * Test is structured a bit oddly, since it evolved from when the Concurrence annotation and aspect
027: * evolved into the {@link ConcurrentBarrier} utility class.
028: */
029: @Test(sequential=true)
030: public class ConcurrentBarrierTest extends TestBase {
031: private ConcurrentTarget _target = new ConcurrentTarget();
032:
033: private static final int THREAD_COUNT = 100;
034:
035: private static final int THREAD_BLOCK_SIZE = 5;
036:
037: @Test
038: public void read_lock_then_write_lock() throws Exception {
039: Runnable operation = new Runnable() {
040: public void run() {
041: _target.incrementCounter();
042: }
043: };
044:
045: runOperationAndCheckCounter(operation);
046: }
047:
048: @Test
049: public void read_lock_inside_write_lock() throws Exception {
050: Runnable operation = new Runnable() {
051: public void run() {
052: // Gets a write lock, then a read lock.
053: _target.incrementCounterHard();
054: }
055: };
056:
057: runOperationAndCheckCounter(operation);
058: }
059:
060: @Test(enabled=true)
061: public void write_lock_inside_read_lock() throws Exception {
062: Runnable operation = new Runnable() {
063: public void run() {
064: // A read lock method that upgrades to a write lock
065:
066: _target.incrementIfNonNegative();
067: }
068: };
069:
070: runOperationAndCheckCounter(operation);
071: }
072:
073: @Test(enabled=true)
074: public void indirection_between_read_method_and_write_method()
075: throws Exception {
076: Runnable operation = new Runnable() {
077: public void run() {
078:
079: // Read lock method invokes other class, that invokes write method.
080:
081: _target.incrementViaRunnable();
082: }
083: };
084:
085: runOperationAndCheckCounter(operation);
086: }
087:
088: /**
089: * Test that locking, especially read lock upgrade and downgrade, work properly when there's
090: * more than one object involved.
091: */
092: @Test
093: public void multiple_synchronized_objects() throws Exception {
094: Runnable operation = new ConcurrentTargetWrapper(_target);
095:
096: runOperationAndCheckCounter(operation);
097: }
098:
099: @Test
100: public void read_lock_then_try_write_lock() throws Exception {
101: Runnable operation = new Runnable() {
102: public void run() {
103: _target.tryIncrementCounter();
104: }
105: };
106:
107: runOperationAndCheckCounter(operation);
108: }
109:
110: @Test
111: public void read_lock_inside_try_write_lock() throws Exception {
112: Runnable operation = new Runnable() {
113: public void run() {
114: // Gets a write lock, then a read lock.
115: _target.tryIncrementCounterHard();
116: }
117: };
118:
119: runOperationAndCheckCounter(operation);
120: }
121:
122: @Test(enabled=true)
123: public void try_write_lock_inside_read_lock() throws Exception {
124: Runnable operation = new Runnable() {
125: public void run() {
126: // A read lock method that upgrades to a write lock
127:
128: _target.tryIncrementIfNonNegative();
129: }
130: };
131:
132: runOperationAndCheckCounter(operation);
133: }
134:
135: @Test(enabled=true)
136: public void write_lock_timeout_inside_read_lock() throws Exception {
137: final Runnable operation = new Runnable() {
138: public void run() {
139: // A read lock method that upgrades to a write lock
140:
141: _target.tryIncrementIfNonNegative();
142: }
143: };
144:
145: _target.withRead(new Runnable() {
146: public void run() {
147: try {
148: runOperation(operation);
149: } catch (InterruptedException e) {
150: }
151: }
152: });
153: assertEquals(_target.getCounter(), 0);
154:
155: }
156:
157: private void runOperationAndCheckCounter(Runnable operation)
158: throws InterruptedException {
159: runOperation(operation);
160:
161: assertEquals(_target.getCounter(), THREAD_COUNT);
162: }
163:
164: private void runOperation(Runnable operation)
165: throws InterruptedException {
166: List<Thread> threads = newList();
167: List<Thread> running = newList();
168:
169: _target.setCounter(0);
170:
171: for (int i = 0; i < THREAD_COUNT; i++) {
172:
173: Thread t = new Thread(operation);
174:
175: threads.add(t);
176:
177: if (threads.size() >= THREAD_BLOCK_SIZE)
178: startThreads(threads, running);
179: }
180:
181: startThreads(threads, running);
182:
183: for (Thread t : running)
184: t.join();
185: }
186:
187: private void startThreads(List<Thread> threads, List<Thread> running) {
188: for (Thread t : threads) {
189: t.start();
190: running.add(t);
191: }
192:
193: threads.clear();
194: }
195:
196: }
|