001: package org.tigris.scarab.util.word;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2002 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import org.tigris.scarab.om.IssueType;
050: import org.tigris.scarab.om.Module;
051: import org.tigris.scarab.om.ScarabUser;
052: import org.tigris.scarab.test.BaseScarabTestCase;
053:
054: /**
055: * A Testing Suite for the util.word.IssueSearchFactory class. This class
056: * includes concurrency tests, which have timings on a much shorter time
057: * scale than is possible in production. Attempts to shorten the maxWait
058: * even further causes tests to fail, just because threads to not necessarily
059: * wake up immediately on the notifyAll signal. if failures are seen, try
060: * adjusting maxWait used here up before assuming the code is broken. Max
061: * wait in production is measured in seconds, values in this class are
062: * given in millis.
063: *
064: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
065: * @version $Id: IssueSearchFactoryTest.java 9446 2005-03-12 11:59:50Z jorgeuriarte $
066: */
067: public class IssueSearchFactoryTest extends BaseScarabTestCase {
068: private IssueSearch search;
069:
070: /**
071: * Testing the factory's limit using one thread
072: * can't test maxWait this way.
073: */
074: public void testSingleThread() throws Exception {
075: IssueSearchFactory issueSearchFactory = new IssueSearchFactory() {
076: int getMaxInstances() {
077: return 5;
078: }
079:
080: int getMaxWait() {
081: return 0;
082: }
083: };
084:
085: Module module = getModule();
086: IssueType it = getDefaultIssueType();
087: ScarabUser user = getUser1();
088:
089: IssueSearch[] isa = new IssueSearch[5];
090: for (int i = 0; i < 5; i++) {
091: isa[i] = issueSearchFactory.getInstance(module, it, user);
092: }
093:
094: // try to get one more than max
095: try {
096: issueSearchFactory.getInstance(module, it, getUser1());
097: fail("Created more than maxInstances");
098: } catch (MaxConcurrentSearchException expected) {
099: }
100:
101: // let the factory know we are done
102: issueSearchFactory.notifyDone();
103:
104: // try again should work this time
105: try {
106: issueSearchFactory.getInstance(module, it, getUser1());
107: } catch (MaxConcurrentSearchException failure) {
108: fail("Could not create new instance after returning one.");
109: }
110: }
111:
112: /**
113: * I can't seem to grok this one. I know I should have paid more attention to
114: * threads in Java 101.
115: * @throws Exception
116: */
117: public void OFFtestConcurrency() throws Exception {
118: String message = multipleThreads(1);
119: assertTrue(message, message.length() == 0);
120: message = multipleThreads(2 * 50); // 2 * maxWait
121: assertTrue("Didn't timeout. " + message, message
122: .startsWith("Exception: "));
123: }
124:
125: private String multipleThreads(final int holdTime) throws Exception {
126: final long startTime = System.currentTimeMillis();
127:
128: final StringBuffer sb = new StringBuffer(20);
129:
130: final ISFactoryTest[] pts = new ISFactoryTest[2 * 5]; // 2 * maxActive
131: final ThreadGroup threadGroup = new ThreadGroup("foo") {
132: public void uncaughtException(Thread t, Throwable e) {
133: for (int i = 0; i < pts.length; i++) {
134: pts[i].stop();
135: }
136:
137: sb.append("Exception: " + e.getMessage());
138: }
139: };
140:
141: // would like to use variables here but an inner class does not
142: // initialize its version of the local variable until after the
143: // ctor is executed and these methods are called from the ctor
144: // we have to hardcode.
145: IssueSearchFactory issueSearchFactory = new IssueSearchFactory() {
146:
147: int getMaxInstances() {
148: return 5;
149: }
150:
151: int getMaxWait() {
152: return 50;
153: }
154: };
155:
156: Module module = getModule();
157: IssueType it = getDefaultIssueType();
158: ScarabUser user = getUser1();
159:
160: for (int i = 0; i < pts.length; i++) {
161: pts[i] = new ISFactoryTest(threadGroup, holdTime,
162: issueSearchFactory, module, it, user);
163: }
164:
165: // let threads run for a bit
166: Thread.sleep(1000);
167: for (int i = 0; i < pts.length; i++) {
168: pts[i].stop();
169: }
170:
171: // check for deadlock, give threads time to complete an iteration
172: Thread.sleep(200);
173: for (int i = 0; i < pts.length; i++) {
174: //System.out.println(pts[i].getState());
175: if (!pts[i].getState().startsWith("Stopped")) {
176: sb
177: .append("Possible deadlock. First try increasing sleep time.");
178: }
179: }
180:
181: long time = System.currentTimeMillis() - startTime;
182: System.out.println("Multithread test time = " + time + " ms");
183: return sb.toString();
184: }
185:
186: private static int currentThreadCount = 0;
187:
188: private class ISFactoryTest implements Runnable {
189: /**
190: * The number of milliseconds to hold the object
191: */
192: private final int isHoldTime;
193: private final Module module;
194: private final IssueType it;
195: private final ScarabUser user;
196: private final IssueSearchFactory isFactory;
197:
198: private boolean isRun;
199:
200: private String state;
201: private int runCounter;
202:
203: protected ISFactoryTest(ThreadGroup threadGroup,
204: int isHoldTime, IssueSearchFactory isFactory,
205: Module module, IssueType it, ScarabUser user) {
206: this .isHoldTime = isHoldTime;
207: this .module = module;
208: this .it = it;
209: this .user = user;
210: this .isFactory = isFactory;
211: Thread thread = new Thread(threadGroup, this , "Thread+"
212: + currentThreadCount++);
213: thread.setDaemon(false);
214: thread.start();
215: }
216:
217: public void run() {
218: isRun = true;
219: runCounter = 0;
220: while (isRun) {
221: runCounter++;
222: try {
223: IssueSearch is = null;
224: state = "Getting IS";
225: is = isFactory.getInstance(module, it, user);
226: state = "Using IS";
227: assertTrue(null != is);
228: Thread.sleep(isHoldTime);
229: state = "Returning IS";
230: isFactory.notifyDone();
231: // if we let this thread immediately enter into competition
232: // for the lock on the factory, it sometimes beats those
233: // that were waiting.
234: Thread.sleep(10);
235: } catch (RuntimeException e) {
236: throw e;
237: } catch (Exception e) {
238: throw new RuntimeException(e.toString());
239: }
240: }
241: state = "Stopped";
242: }
243:
244: public void stop() {
245: isRun = false;
246: }
247:
248: public String getState() {
249: return state + "; ran " + runCounter + " times";
250: }
251: }
252: }
|