001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.services.uniqueid.test;
019:
020: import java.sql.PreparedStatement;
021: import java.sql.SQLException;
022: import java.util.Collections;
023: import java.util.HashSet;
024: import java.util.Set;
025:
026: import org.sape.carbon.core.component.Lookup;
027: import org.sape.carbon.core.component.lifecycle.LifecycleInterceptor;
028: import org.sape.carbon.core.component.lifecycle.LifecycleStateEnum;
029: import org.sape.carbon.core.component.lifecycle.StateTransitionException;
030: import org.sape.carbon.core.config.InvalidConfigurationException;
031: import org.sape.carbon.core.exception.ExceptionUtility;
032: import org.sape.carbon.services.sql.StatementFactory;
033: import org.sape.carbon.services.sql.StatementFactoryException;
034: import org.sape.carbon.services.uniqueid.UniqueIDNotFoundException;
035: import org.sape.carbon.services.uniqueid.UniqueIDService;
036: import org.sape.carbon.services.uniqueid.UniqueIDServiceException;
037:
038: import junit.extensions.ActiveTestSuite;
039: import junit.framework.Test;
040: import junit.framework.TestCase;
041: import junit.framework.TestSuite;
042:
043: /**
044: * Test harness for the DefaultUniqueIDServiceImpl implementation of the
045: * UniqueIDService
046: *
047: * Copyright 2002 Sapient
048: * @since carbon 1.0
049: * @author Douglas Voet, July 2002
050: * @version $Revision: 1.6 $($Author: dvoet $ / $Date: 2003/05/05 21:21:38 $)
051: */
052: public class UniqueIDServiceTest extends TestCase {
053:
054: private static Set usedIDs = Collections
055: .synchronizedSet(new HashSet());
056: private static final int NUM_ITERATIONS = 100;
057: private static final int NUM_THREADS = 2;
058:
059: private static final String ID_NOT_FOUND_NAME = "/uniqueid/test/NotFoundUniqueIDService";
060: private static final String INVALID_ID_SERVICE = "/uniqueid/test/InvalidUniqueIDService";
061: private static final String INVALID_CONNECTION_SERVICE = "/uniqueid/test/InvalidConnectionUniqueIDService";
062: private static final String ID_SERVICE_BLOCK_SIZE_1 = "/uniqueid/test/BlockSize1UniqueIDService";
063: private static final String ID_SERVICE_1 = "/uniqueid/test/UniqueIDService1";
064: private static final String ID_SERVICE_2 = "/uniqueid/test/UniqueIDService2";
065: private static final String ID_SERVICE_3 = "/uniqueid/test/UniqueIDService3";
066: private static final String UNIQUE_ID_STATEMENT_FACTORY = "/uniqueid/test/UniqueIDStatementFactory";
067: private static final String CREATE_TABLE_UNIQUE_ID_QUERY = "CreateTableUniqueID";
068: private static final String DROP_TABLE_UNIQUE_ID_QUERY = "DropTableUniqueID";
069:
070: public UniqueIDServiceTest(String name) {
071: super (name);
072: }
073:
074: /**
075: * Method create table for unique id service to work in case it is
076: * not already there.
077: */
078: public void createUniqueIdTable() {
079: PreparedStatement preparedStatement = null;
080:
081: try {
082:
083: StatementFactory sf = (StatementFactory) Lookup
084: .getInstance().fetchComponent(
085: UNIQUE_ID_STATEMENT_FACTORY);
086: preparedStatement = sf
087: .createPreparedStatement(CREATE_TABLE_UNIQUE_ID_QUERY);
088: preparedStatement.executeUpdate();
089: } catch (SQLException se) {
090: // expected. this case will arise when table already existed
091: } catch (StatementFactoryException sfe) {
092: // expected. this case will arise when table already existed
093: }
094:
095: }
096:
097: /**
098: * Tests that the appropriate exception is thrown when an ID is not
099: * found and AutoCreate is false
100: */
101: public void testIDNotFound() {
102: UniqueIDService uniqueIDService = (UniqueIDService) Lookup
103: .getInstance().fetchComponent(ID_NOT_FOUND_NAME);
104:
105: try {
106: uniqueIDService.getNextID();
107:
108: fail("Did not catch expected UniqueIDNotFoundException");
109: } catch (UniqueIDNotFoundException uidnfe) {
110: // expected
111: } catch (UniqueIDServiceException uidse) {
112: fail("Did not catch expected UniqueIDNotFoundException, "
113: + "caught UniqueIDServiceException: " + uidse
114: + ExceptionUtility.captureStackTrace(uidse));
115: }
116: }
117:
118: /**
119: * Tests to make sure that the service does not skip IDs under single
120: * threaded, single client conditions
121: */
122: public void testIDsNotSkipped() {
123: UniqueIDService uniqueIDService = (UniqueIDService) Lookup
124: .getInstance().fetchComponent(ID_SERVICE_BLOCK_SIZE_1);
125:
126: try {
127: // initialize ID trackers
128: long currentID = uniqueIDService.getNextID();
129: long lastID = currentID;
130:
131: for (int i = 0; i < 10; i++) {
132: currentID = uniqueIDService.getNextID();
133:
134: if (currentID <= lastID) {
135: fail("UniqueIDService returned an ID out of sequence. "
136: + "IDs should be in sequence under test conditions");
137: }
138:
139: lastID = currentID;
140: }
141:
142: } catch (UniqueIDServiceException uidse) {
143: fail("Caught UniqueIDServiceException: " + uidse
144: + ExceptionUtility.captureStackTrace(uidse));
145: }
146: }
147:
148: /**
149: * Tests that the appropriate exception is thrown when an invalid
150: * configuration is used
151: */
152: public void testInvalidConfiguration() {
153: try {
154: Lookup.getInstance().fetchComponent(INVALID_ID_SERVICE);
155:
156: fail("Did not catch expected StateTransition or "
157: + "InvalidConfiguration exception");
158: } catch (InvalidConfigurationException ice) {
159: // expected
160: } catch (StateTransitionException ste) {
161: //expected
162: }
163:
164: }
165:
166: /**
167: * Tests that an appropriate exception is thrown when an invalid
168: * connection is used.
169: */
170: public void testInvalidConnectionFactory() throws Exception {
171: try {
172: UniqueIDService uniqueIDService = (UniqueIDService) Lookup
173: .getInstance().fetchComponent(
174: INVALID_CONNECTION_SERVICE);
175:
176: uniqueIDService.getNextID();
177:
178: fail("Did not catch expected UniqueIDServiceException "
179: + "when using an invalid connection to the database.");
180:
181: } catch (UniqueIDServiceException uidse) {
182: // expected
183: }
184: }
185:
186: /**
187: * Tests that returned IDs are unique in multi-threaded, multi-client
188: * conditions. Used in conjunction with testMultiComponentAccess2
189: * and testMultiComponentAccess3 started in an ActiveTestSuite
190: */
191: public void testMultiComponentAccess1() {
192: testMultiComponentAccess(ID_SERVICE_1);
193: }
194:
195: /** see testMultiComponentAccess1 */
196: public void testMultiComponentAccess2() {
197: testMultiComponentAccess(ID_SERVICE_2);
198: }
199:
200: /** see testMultiComponentAccess1 */
201: public void testMultiComponentAccess3() {
202: testMultiComponentAccess(ID_SERVICE_3);
203: }
204:
205: /** Called by testMultiComponentAccess1 2 & 3 to to run the test */
206: private void testMultiComponentAccess(String uniqueIDServiceName) {
207: UniqueIDService uniqueIDService = (UniqueIDService) Lookup
208: .getInstance().fetchComponent(uniqueIDServiceName);
209:
210: while (((LifecycleInterceptor) uniqueIDService)
211: .getLifecycleState() != LifecycleStateEnum.RUNNING) {
212:
213: try {
214: Thread.sleep(100);
215: } catch (InterruptedException e) {
216: }
217: }
218:
219: try {
220: for (int i = 0; i < NUM_ITERATIONS; i++) {
221: boolean idNotUsed = UniqueIDServiceTest.usedIDs
222: .add(new Long(uniqueIDService.getNextID()));
223:
224: if (!idNotUsed) {
225: fail("UniqueIDService returned a non-unique ID");
226: }
227: }
228:
229: } catch (UniqueIDServiceException uidse) {
230: fail("Caught UniqueIDServiceException: " + uidse
231: + ExceptionUtility.captureStackTrace(uidse));
232: }
233: }
234:
235: /**
236: * Method called by jUnit to get all the tests in this test case.
237: * @return Test the suite of tests in this test case
238: */
239: public static Test suite() {
240: TestSuite masterSuite = new TestSuite();
241: // add single threaded tests
242: Test singleThreadedTests = getSingleThreadedTests();
243: if (singleThreadedTests != null) {
244: masterSuite.addTest(singleThreadedTests);
245: }
246: // add multi threaded tests
247: Test multiThreadedTests = getMultiThreadedTests();
248: if (multiThreadedTests != null) {
249: masterSuite.addTest(multiThreadedTests);
250: }
251: return masterSuite;
252: }
253:
254: /**
255: * Single threaded tests:
256: *
257: * testIDNotFound
258: * testIDsNotSkipped
259: * testInvalidConfiguration
260: * testInvalidConnectionFactory
261: *
262: * @return Test the suite of single threaded tests in this test case
263: */
264: private static Test getSingleThreadedTests() {
265: TestSuite suite = new TestSuite();
266: suite.addTest(new UniqueIDServiceTest("createUniqueIdTable"));
267: suite.addTest(new UniqueIDServiceTest("testIDNotFound"));
268: suite.addTest(new UniqueIDServiceTest("testIDsNotSkipped"));
269: suite.addTest(new UniqueIDServiceTest(
270: "testInvalidConfiguration"));
271: suite.addTest(new UniqueIDServiceTest(
272: "testInvalidConnectionFactory"));
273:
274: return suite;
275: }
276:
277: /**
278: * Multi-Threaded tests
279: *
280: * testMultiComponentAccess1
281: * testMultiComponentAccess2
282: * testMultiComponentAccess3
283: *
284: * @return Test the suite of multi-threaded tests in this test case
285: */
286: private static Test getMultiThreadedTests() {
287: TestSuite suite = new ActiveTestSuite();
288:
289: addTest(suite, "testMultiComponentAccess1",
290: UniqueIDServiceTest.NUM_THREADS);
291:
292: // Akash:
293: // Commented out to as these test cases were failing
294: // MultiComponentAccess1 already checks for synchronization by using
295: // multiple threads to call getNextID() method of uniqueId Service.
296: // Providing 3 MultiComponent accesses leads to synchronization problem
297: // for the same id name block in the table at the time of creation of this
298: // ID name. This scenario is not realistic from usage point of view as no
299: // two uniqueId components should work on the same ID name.
300:
301: addTest(suite, "testMultiComponentAccess2",
302: UniqueIDServiceTest.NUM_THREADS);
303: addTest(suite, "testMultiComponentAccess3",
304: UniqueIDServiceTest.NUM_THREADS);
305:
306: return suite;
307: }
308:
309: /**
310: * This method will add the give test to the give suite the specified
311: * number of times. This is best used for multi-threaded tests where
312: * suite is an instance of ActiveTestSuite and you want to run the same test in
313: * multiple threads.
314: * @param suite the suite to add the test to.
315: * @param testName the name of the test to add.
316: * @param number the number of times to add the test to the suite
317: */
318: private static void addTest(TestSuite suite, String testName,
319: int number) {
320: for (int count = 0; count < number; count++) {
321: suite.addTest(new UniqueIDServiceTest(testName));
322: }
323: }
324: }
|