KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > core > component > test > ComponentKeeperTest


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.core.component.test;
19
20 import org.sape.carbon.core.bootstrap.BootStrapper;
21 import org.sape.carbon.core.component.Component;
22 import org.sape.carbon.core.component.ComponentKeeper;
23 import org.sape.carbon.core.component.ComponentNotFoundException;
24 import org.sape.carbon.core.component.lifecycle.LifecycleInterceptor;
25 import org.sape.carbon.core.component.lifecycle.LifecycleStateEnum;
26 import org.sape.carbon.core.exception.InvalidParameterException;
27
28 import junit.extensions.ActiveTestSuite;
29 import junit.framework.Test;
30 import junit.framework.TestCase;
31 import junit.framework.TestSuite;
32
33 /**
34  * This test case tests all the methods of the ComponentKeeper. It tests
35  * to make sure that
36  * <ul>
37  * <li>returned components references remain consistent</li>
38  * <li>returned components are in the correct state</li>
39  * <li>components are destroyed when requested</li>
40  * <li>fetch requests are blocked appropriately when a component is being
41  * created</li>
42  * <li>the keeper behaves correctly in a multi-threaded environment</li
43  * </ul>
44  *
45  * Copyright 2002 Sapient
46  * @since carbon 1.0
47  * @author Douglas Voet, Febuary 2002
48  * @version $Revision: 1.14 $($Author: ghinkl $ / $Date: 2003/10/16 13:22:00 $)
49  */

50 public class ComponentKeeperTest extends TestCase {
51     private ComponentKeeper keeper;
52
53     public ComponentKeeperTest(String JavaDoc name) {
54         super(name);
55     }
56
57     /**
58      * This method tests to make sure that the component returned from the
59      * keeper is in the LifecycleStateEnum.RUNNING state. This test assumes
60      * no other thread is creating the component.
61      */

62     public void testComponentState() {
63         LifecycleInterceptor component = (LifecycleInterceptor) this.keeper.
64             fetchComponent(EMPTY_TEST_COMPONENT);
65         if (component.getLifecycleState() != LifecycleStateEnum.RUNNING) {
66             TestCase.fail("Fetched component was not in " +
67                 "LifecycleStateEnum.RUNNING state as was expected");
68         }
69     }
70
71     /**
72      * This method tests to make sure that if a component is destroyed by
73      * calling the destroyComponent lifecycle method directly, the next
74      * call to fetchComponent will return a new component, not the destroyed
75      * one
76      */

77     public void testFetchDestroyedComponent() {
78         LifecycleInterceptor component = (LifecycleInterceptor) this.keeper.
79             fetchComponent(EMPTY_TEST_COMPONENT);
80
81         component.destroyComponent();
82
83         component = (LifecycleInterceptor) this.keeper.
84             fetchComponent(EMPTY_TEST_COMPONENT);
85
86         if (component.getLifecycleState() == LifecycleStateEnum.DESTROYED) {
87             TestCase.fail("Fetched component was in " +
88                 "LifecycleStateEnum.DESTROYED state, expected otherwise");
89         }
90     }
91
92     /**
93      * This method tests that repeated calls the the fetchComponent method
94      * returns the same reference.
95      */

96     public void testComponentConsistency() {
97         Component component = this.keeper.fetchComponent(EMPTY_TEST_COMPONENT);
98         if (component != this.keeper.fetchComponent(EMPTY_TEST_COMPONENT)) {
99             TestCase.fail("Keeper did not return consistent " +
100                 "component references");
101         }
102     }
103
104     /**
105      * This test checks 2 things, that fetching a destroyed component will
106      * return a new component and that the destroyed component is in the
107      * LifecycleStateEnum.DESTROYED state.
108      */

109     public void testDestroyComponent() {
110         LifecycleInterceptor component = (LifecycleInterceptor) this.keeper.
111             fetchComponent(EMPTY_TEST_COMPONENT);
112
113         this.keeper.destroyComponent(EMPTY_TEST_COMPONENT);
114
115         if (component.getLifecycleState() != LifecycleStateEnum.DESTROYED) {
116             TestCase.fail("Fetched component was not in " +
117                 "LifecycleStateEnum.DESTROYED state as was expected");
118         }
119         if (component == this.keeper.fetchComponent(EMPTY_TEST_COMPONENT)) {
120             TestCase.fail("Keeper failed to destroy a component");
121         }
122     }
123
124     /**
125      * Same as testDestroyComponent, but repeats the test for 2 components
126      * to make sure that more than one component is destroyed.
127      */

128     public void testDestroyAllComponents() {
129         LifecycleInterceptor component1 = (LifecycleInterceptor) this.keeper.
130             fetchComponent(EMPTY_TEST_COMPONENT);
131         LifecycleInterceptor component2 = (LifecycleInterceptor) this.keeper.
132             fetchComponent(EMPTY_TEST_COMPONENT_2);
133         try {
134             this.keeper.destroyAllComponents();
135         } catch(Exception JavaDoc e) {
136             TestCase.fail("Caught exception while destroying " +
137                 "all components: " + e);
138         }
139
140         if ((component1.getLifecycleState() != LifecycleStateEnum.DESTROYED) ||
141            (component2.getLifecycleState() != LifecycleStateEnum.DESTROYED)) {
142
143             TestCase.fail("Fetched component was not in " +
144                     "LifecycleStateEnum.DESTROYED state as was expected");
145         }
146
147         if (component1 == this.keeper.fetchComponent(EMPTY_TEST_COMPONENT) ||
148            component2 == this.keeper.fetchComponent(EMPTY_TEST_COMPONENT_2)) {
149
150             TestCase.fail("Keeper failed to destroy all components");
151         }
152     }
153
154     /**
155      * This method tests that components with circular dependancies do not
156      * cause deadlocks. It does this by creating 3 components A, B, and C.
157      * A depends on B, B depends on C, and C depends on A. This request will
158      * be made on a separate thread. If the thread does not complete execution
159      * within a reasonable amount of time, the test fails.
160      */

161     public void testCircularDependency() {
162         // construct thread that requests a component that has a circular
163
// dependency
164
Thread JavaDoc testThread = new Thread JavaDoc(new Runnable JavaDoc() {
165             public void run() {
166                 try {
167                     keeper.fetchComponent(CIRCULAR_REFERENCE_A);
168                 } catch (Throwable JavaDoc t) {
169                     ComponentKeeperTest.threadException = t;
170                 }
171             }
172         }, "testCircularDependency");
173         // start the thread
174
testThread.start();
175         try {
176             // wait for it to complete or to timeout
177
testThread.join(THREAD_TIMEOUT);
178         } catch (InterruptedException JavaDoc ie) {
179             // this should never happen so let's fail
180
throw new RuntimeException JavaDoc("Caught InterruptedException: " + ie);
181         }
182
183         if (ComponentKeeperTest.threadException != null) {
184             TestCase.fail("Circular dependency test failed with exception " +
185                 ComponentKeeperTest.threadException);
186         }
187
188         // if the thread is still alive, fail
189
if (testThread.isAlive()) {
190             TestCase.fail("Circular dependency test did not complete within " +
191                 THREAD_TIMEOUT + " ms, dead lock suspected");
192         }
193     }
194
195     /**
196      * This method tests to make sure that a ComponentNotFoundException is
197      * thrown when a non-existent component is requested.
198      */

199     public void testComponentNotFound() {
200         boolean passedTest = false;
201         try {
202             this.keeper.fetchComponent(NON_EXISTENT_COMPONENT);
203         } catch(ComponentNotFoundException cnfe) {
204             passedTest = true;
205         }
206         if (!passedTest) {
207             TestCase.fail("Keeper did not throw exception when attempting " +
208                 "to fetch a non-existent component");
209         }
210     }
211
212     /**
213      * This method tests to make sure that an IllegalArgumentException is
214      * thrown when null is passed as the requested component name.
215      */

216     public void testNullComponentName() {
217         boolean passedTest = false;
218         try {
219             this.keeper.fetchComponent(null);
220         } catch(InvalidParameterException ipe) {
221             passedTest = true;
222         }
223         if (!passedTest) {
224             TestCase.fail("Keeper did not throw exception when attempting " +
225                 "to fetch a component with a null name");
226         }
227     }
228
229     /**
230      * Tests to make sure that creating a component does not block the
231      * retrieval of other components. This is done by kicking off 2 threads.
232      * The first will try to fetch a component that takes a long time to
233      * create. The second will fetch a component that is already created.
234      * If the second thread completes first, the test is sucessful.
235      */

236     public void testCreationNonBlocking() {
237         // make sure EMPTY_TEST_COMPONENT is created
238
LifecycleInterceptor component = (LifecycleInterceptor) this.keeper.
239             fetchComponent(EMPTY_TEST_COMPONENT);
240
241         this.keeper.destroyComponent(LONG_INIT_COMPONENT);
242
243         // create the thread that will take a long time to run
244
Thread JavaDoc longThread = new Thread JavaDoc(new Runnable JavaDoc() {
245             public void run() {
246                 keeper.fetchComponent(LONG_INIT_COMPONENT);
247             }
248         });
249
250         // create the thread that will complete quickly
251
Thread JavaDoc shortThread = new Thread JavaDoc(new Runnable JavaDoc() {
252             public void run() {
253                 keeper.fetchComponent(EMPTY_TEST_COMPONENT);
254             }
255         });
256
257         // start the threads, long one first
258
longThread.start();
259         // yield control to let longThread get going (hopefully)
260
Thread.yield();
261         // start the shortThread
262
shortThread.start();
263
264         try {
265             // wait for shortThread to complete
266
shortThread.join(THREAD_TIMEOUT);
267         } catch (InterruptedException JavaDoc ie) {
268             // this should never happen so let's fail
269
throw new RuntimeException JavaDoc("Caught InterruptedException: " + ie);
270         }
271
272         if (shortThread.isAlive()) {
273             synchronized(ComponentKeeperTest.TEST_LOCK) {
274                 ComponentKeeperTest.TEST_LOCK.notifyAll();
275             }
276             TestCase.fail("Creation of a component blocked retrieval of " +
277                 "unrelated component");
278         }
279         synchronized(ComponentKeeperTest.TEST_LOCK) {
280             ComponentKeeperTest.TEST_LOCK.notifyAll();
281         }
282     }
283
284     public void testReturnedComponentState() {
285         this.keeper.destroyComponent(LONG_START_COMPONENT);
286
287         Runnable JavaDoc fetchLongStartComponent = new Runnable JavaDoc() {
288             public void run() {
289                 keeper.fetchComponent(LONG_START_COMPONENT);
290             }
291         };
292
293         // create the thread that will create a component that will take a
294
// long time to start
295
Thread JavaDoc createThread = new Thread JavaDoc(fetchLongStartComponent, "createThread");
296
297         // start createThread
298
createThread.start();
299
300         LifecycleInterceptor component = (LifecycleInterceptor)
301             keeper.fetchComponent(LONG_START_COMPONENT);
302
303         if (component.getLifecycleState() != LifecycleStateEnum.RUNNING) {
304             TestCase.fail("Component was not returned in a running state");
305         }
306     }
307
308     /**
309      * Tests to make sure that building a component will block all requests
310      * for that component until the component is in either the
311      * LifecycleStateEnum.STOPPED or .STARTING states.
312      * This test depends on the component being requested taking a long
313      * time to load. This test makes 2 requests for a component, one on this
314      * thread, one on a new one. This thread contains the second request.
315      * The second request should complete while the new thread is still alive
316      * (i.e. the first request is still being processed). This test fails if
317      * the new thread has completed or if the component is not in the
318      * LifecycleStateEnum.STOPPED or .STARTING states.
319      */

320     public void testCreationBlocking() {
321         // make sure LONG_START_COMPONENT does not exist
322
this.keeper.destroyComponent(LONG_START_COMPONENT);
323
324         Runnable JavaDoc fetchLongStartComponent = new Runnable JavaDoc() {
325             public void run() {
326                 keeper.fetchComponent(LONG_START_COMPONENT);
327             }
328         };
329
330         // create the thread that will create a component that will take a
331
// long time to start
332
Thread JavaDoc createThread = new Thread JavaDoc(fetchLongStartComponent, "createThread");
333
334         // create the thread that will do the same but is expected to complete
335
// earlier than createThread because it does not need to wait for the
336
// component to start
337
Thread JavaDoc fetchThread = new Thread JavaDoc(fetchLongStartComponent, "fetchThread");
338
339         // start createThread
340
createThread.start();
341         // wait for createThread to signal that it is starting
342
try {
343             synchronized(ComponentKeeperTest.TEST_LOCK) {
344                 ComponentKeeperTest.TEST_LOCK.wait();
345             }
346         } catch (InterruptedException JavaDoc ie) {
347             // this should never happen so let's fail
348
throw new RuntimeException JavaDoc("Caught InterruptedException: " + ie);
349         }
350
351         try {
352             // start fetchThread which should complete
353
fetchThread.start();
354
355             try {
356                 // wait for fetchThread to complete
357
fetchThread.join(THREAD_TIMEOUT);
358             } catch (InterruptedException JavaDoc ie) {
359                 // this should never happen so let's fail
360
throw new RuntimeException JavaDoc("Caught InterruptedException: " + ie);
361             }
362
363             // check to make sure that fetchThread is done
364
if (fetchThread.isAlive()) {
365                 TestCase.fail("Creation of component blocked fetch of the " +
366                     "same component by another thread");
367             }
368         } catch(RuntimeException JavaDoc re) {
369             // don't care about the exception, just want the finally block
370
throw re;
371         } finally {
372             // let createThread complete
373
synchronized(ComponentKeeperTest.TEST_LOCK) {
374                 ComponentKeeperTest.TEST_LOCK.notifyAll();
375             }
376         }
377     }
378
379     /**
380      * Fetches a component multiple times and makes sure the return references
381      * remain consistent. This test method is used as part of a multi-threaded
382      * test, each thread repeatedly asking for a different component.
383      */

384     public void testFetchComponentA() {
385         fetchComponentMultipleTimes(TEST_COMPONENT_A);
386     }
387
388     /**
389      * Fetches a component multiple times and makes sure the return references
390      * remain consistent. This test method is used as part of a multi-threaded
391      * test, each thread repeatedly asking for a different component.
392      */

393     public void testFetchComponentB() {
394         fetchComponentMultipleTimes(TEST_COMPONENT_B);
395     }
396
397     /**
398      * Fetches a component multiple times and makes sure the return references
399      * remain consistent. This test method is used as part of a multi-threaded
400      * test, each thread repeatedly asking for a different component.
401      */

402     public void testFetchComponentC() {
403         fetchComponentMultipleTimes(TEST_COMPONENT_C);
404     }
405
406     private void fetchComponentMultipleTimes(String JavaDoc componentName) {
407         Component component = this.keeper.fetchComponent(componentName);
408         for(int i=0; i<NUMBER_REPETITIONS; i++) {
409             if (component != this.keeper.fetchComponent(componentName)) {
410                 TestCase.fail("keeper is returning inconsistent component " +
411                     "references");
412             }
413         }
414     }
415
416     /** Gets a reference to the keeper for use in all tests */
417     protected void setUp() {
418         keeper = BootStrapper.getInstance().fetchComponentKeeper();
419     }
420
421     // static members
422

423     /**
424      * Lock object used by test components that need to wait for an extended
425      * period of time
426      */

427     public static final Object JavaDoc TEST_LOCK = new Object JavaDoc();
428
429     private static final String JavaDoc EMPTY_TEST_COMPONENT =
430         "/core/test/KeeperTestComponent1";
431     private static final String JavaDoc EMPTY_TEST_COMPONENT_2 =
432         "/core/test/KeeperTestComponent2";
433     private static final String JavaDoc CIRCULAR_REFERENCE_A =
434         "/core/test/KeeperCircRefTestA";
435     private static final String JavaDoc TEST_COMPONENT_A =
436         "/core/test/KeeperTestComponentA";
437     private static final String JavaDoc TEST_COMPONENT_B =
438         "/core/test/KeeperTestComponentB";
439     private static final String JavaDoc TEST_COMPONENT_C =
440         "/core/test/KeeperTestComponentC";
441     private static final String JavaDoc LONG_INIT_COMPONENT =
442         "/core/test/KeeperLongInitTestComponent";
443     private static final String JavaDoc LONG_START_COMPONENT =
444         "/core/test/KeeperLongStartTestComponent";
445     private static final String JavaDoc NON_EXISTENT_COMPONENT = "/asasdfa";
446
447     private static Throwable JavaDoc threadException = null;
448
449     private static final long THREAD_TIMEOUT = 3000;
450     private static final int NUMBER_REPETITIONS = 100;
451
452     /** Method called by jUnit to get all the tests in this test case */
453     public static Test suite() {
454         TestSuite masterSuite = new TestSuite();
455         // add single threaded tests
456
Test singleThreadedTests = getSingleThreadedTests();
457         if (singleThreadedTests != null) {
458             masterSuite.addTest(singleThreadedTests);
459         }
460         // add multi threaded tests
461
Test multiThreadedTests = getMultiThreadedTests();
462         if (multiThreadedTests != null) {
463             masterSuite.addTest(multiThreadedTests);
464         }
465         return masterSuite;
466     }
467
468     /**
469      * The single threaded tests, in order, are:
470      * <ol>
471      * <li>testBadComponentName</li>
472      * <li>testNullComponentName</li>
473      * <li>testDestroyNonExistentComponent</li>
474      * <li>testComponentState</li>
475      * <li>testComponentConsistency</li>
476      * <li>testDestroyComponent</li>
477      * <li>testDestroyAllComponents</li>
478      * <li>testCircularDependency</li>
479      * <li>testCreationNonBlocking</li>
480      * <li>testCreationBlocking</li>
481      * </ol>
482      */

483     private static Test getSingleThreadedTests() {
484         TestSuite suite = new TestSuite("ComponentKeeperTest");
485
486         suite.addTest(new ComponentKeeperTest("testComponentNotFound"));
487         suite.addTest(new ComponentKeeperTest("testNullComponentName"));
488         suite.addTest(new ComponentKeeperTest("testComponentState"));
489         suite.addTest(new ComponentKeeperTest("testComponentConsistency"));
490         suite.addTest(new ComponentKeeperTest("testDestroyComponent"));
491         suite.addTest(new ComponentKeeperTest("testDestroyAllComponents"));
492         suite.addTest(new ComponentKeeperTest("testCircularDependency"));
493         suite.addTest(new ComponentKeeperTest("testCreationNonBlocking"));
494         suite.addTest(new ComponentKeeperTest("testReturnedComponentState"));
495         suite.addTest(new ComponentKeeperTest("testFetchDestroyedComponent"));
496
497         return suite;
498     }
499
500     /**
501      * This test harness' multi-threaded test consists of running each of:
502      * <ul>
503      * <li>testFetchComponentA</li>
504      * <li>testFetchComponentB</li>
505      * <li>testFetchComponentC</li>
506      * </ul>
507      * in 3 threads.
508      */

509     private static Test getMultiThreadedTests() {
510         TestSuite suite = new ActiveTestSuite();
511
512         addTest(suite, "testFetchComponentA", 3);
513         addTest(suite, "testFetchComponentB", 3);
514         addTest(suite, "testFetchComponentC", 3);
515
516         return suite;
517     }
518
519     /**
520      * This method will add the give test to the give suite the specified
521      * number of times. This is best used for multi-threaded tests where
522      * suite is an instance of ActiveTestSuite and you want to run the same test in multiple threads.
523      */

524     private static void addTest(TestSuite suite, String JavaDoc testName, int number) {
525         for (int count = 0; count < number; count++) {
526             suite.addTest(new ComponentKeeperTest(testName));
527         }
528     }
529 }
530
Popular Tags