Author: bimargulies Date: Sun Apr 5 11:17:11 2009 New Revision: 762071 URL: http://svn.apache.org/viewvc?rev=762071&view=rev Log: Complete the confused process of moving this test into the 'right' package.
Added: webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java (with props) Added: webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java?rev=762071&view=auto ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java (added) +++ webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java Sun Apr 5 11:17:11 2009 @@ -0,0 +1,422 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ws.commons.schema; + +import java.lang.ref.SoftReference; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import tests.Resources; + +/** + * Test the resolved Schema cache. + */ +public class SchemaBuilderCacheTest extends Assert { + + // Amount of time the testcase should wait on the test threads before timing + // out + private static final int THREAD_TIMEOUT = 90000; + + /** + * return resolved schema map. + */ + static ThreadLocal<Map<String, SoftReference<XmlSchema>>> getResolvedSchemasHashtable() { + return SchemaBuilder.resolvedSchemas; + } + + /** + * Return the HashMap for the current thread or null if there is not one. + * + * @return + */ + static Map<String, SoftReference<XmlSchema>> getThreadResolvedSchemaHashtable() { + return getResolvedSchemasHashtable().get(); + } + + // ============================================================================================== + // Utility Methods + // ============================================================================================== + + /** + * Set the resolvedSchemas collection to null. This should be done in a + * finally block of any tests that cause an SchemaBuilder.initCache to be + * done to cleanup for the next test. + */ + static void resetResolvedSchemasHashtable() { + SchemaBuilder.resolvedSchemas = new ThreadLocal<Map<String, SoftReference<XmlSchema>>>(); + } + + static Document setupDocument() { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory + .newInstance(); + documentBuilderFactory.setNamespaceAware(true); + Document doc; + try { + doc = documentBuilderFactory.newDocumentBuilder().parse( + Resources.asURI("importBase.xsd")); + } catch (Exception e) { + throw new RuntimeException(e); + } + return doc; + } + + static XmlSchemaCollection setupXmlSchemaCollection() { + XmlSchemaCollection schemaCol = new XmlSchemaCollection(); + schemaCol.setBaseUri(Resources.TEST_RESOURCES); + return schemaCol; + } + + /** + * Test that threads can not affect the cache for other threads. + */ + @Test + public void testMultithreadCache() { + try { + MultithreadUpdateLockMonitor testMonitor = new MultithreadUpdateLockMonitor(); + startupTestThreads(testMonitor); + + if (testMonitor.t1Exception != null) { + fail("Thread T1 encountred an error: " + + testMonitor.t1Exception.toString()); + } + if (testMonitor.t2Exception != null) { + fail("Thread T2 encountred an error: " + + testMonitor.t2Exception.toString()); + } + if (testMonitor.t3Exception != null) { + fail("Thread T3 encountred an error: " + + testMonitor.t3Exception.toString()); + } + } finally { + resetResolvedSchemasHashtable(); + } + } + + /** + * Test if the cache is initialized it will be populated when a schema is + * read and it will be cleared when the clearCache method is called. + * + * @throws Exception + */ + @Test + public void testResolveCacheInitialized() throws Exception { + try { + SchemaBuilder.initCache(); + Document doc = setupDocument(); + XmlSchemaCollection schemaCol = setupXmlSchemaCollection(); + XmlSchema schema = schemaCol.read(doc, null); + assertNotNull(schema); + + // If the cache is in use, it should not be null and there should + // be an entry for this thread ID + assertNotNull(getResolvedSchemasHashtable()); + Map<String, SoftReference<XmlSchema>> threadHT = getThreadResolvedSchemaHashtable(); + assertNotNull(threadHT); + assertFalse(threadHT.isEmpty()); + assertEquals(1, threadHT.size()); + + // After clearing the cache, there should be no entry for this + // thread ID, and + // the hashtable should not be null + SchemaBuilder.clearCache(); + assertNotNull(getResolvedSchemasHashtable()); + assertNull(getThreadResolvedSchemaHashtable()); + System.out.println("Line 13"); + } finally { + resetResolvedSchemasHashtable(); + } + + // If the cache is enabled, then it should be non-null + } + + /** + * Test that if the cache is not initialized, then it should not be used + * when a schema is read. + * + * @throws Exception + */ + @Test + public void testResolveCacheUninitialized() throws Exception { + Document doc = setupDocument(); + XmlSchemaCollection schemaCol = setupXmlSchemaCollection(); + XmlSchema schema = schemaCol.read(doc, null); + assertNotNull(schema); + + // If the cache is not in use, then it should be null + // The thread-local cannot be null + assertNull(getThreadResolvedSchemaHashtable()); + } + + /** + * Configure and start the test threads for the multi-threaded testing. The + * threads will perform various tests between themselves such as clearing + * cache in one thread and making sure the cache used by a different thread + * is not affected. A monitor is used to control the synchonization between + * the threads and for communicating faliures back to the test method. + * + * See thed Runnable classes for details on the tests performed. + * + * @param testMonitor + * Used to synchronize the tests between the threads + */ + private void startupTestThreads(MultithreadUpdateLockMonitor testMonitor) { + TestingRunnable1 testRunnable1 = new TestingRunnable1(); + testRunnable1.testMonitor = testMonitor; + + TestingRunnable2 testRunnable2 = new TestingRunnable2(); + testRunnable2.testMonitor = testMonitor; + + TestingRunnable3 testRunnable3 = new TestingRunnable3(); + testRunnable3.testMonitor = testMonitor; + + Thread thread1 = new Thread(testRunnable1); + Thread thread2 = new Thread(testRunnable2); + Thread thread3 = new Thread(testRunnable3); + + thread1.start(); + thread2.start(); + thread3.start(); + + // Join the threads to wait for their completion, specifying a timeout + // to prevent + // a testcase hang if something goes wrong with the threads. + try { + thread1.join(THREAD_TIMEOUT); + thread2.join(THREAD_TIMEOUT); + thread3.join(THREAD_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + fail("Unable to join to testing threads"); + } + } +} + +/** + * Monitor used to control synchronization between the testing threads and + * communicate failures back to the test method. + */ +class MultithreadUpdateLockMonitor { + Exception t1Exception; + boolean t1SetupComplete; + Exception t2Exception; + boolean t2SetupComplete; + Exception t3Exception; +} + +// ================================================================================================= +// Test execution threads +// ================================================================================================= +/** + * Thread 1 will do the following - Initialize the cache and verify it was used + * during a read - Unblock Thread 2 - Wait until Thread 2 unblocks it - Verify + * that the clearCache done by Thread 2 did not affect this Thread's cache. + */ +...@ignore +class TestingRunnable1 implements Runnable { + + MultithreadUpdateLockMonitor testMonitor; + + public void run() { + SchemaBuilder.initCache(); + Document doc = SchemaBuilderCacheTest.setupDocument(); + XmlSchemaCollection schemaCol = SchemaBuilderCacheTest + .setupXmlSchemaCollection(); + XmlSchema schema = schemaCol.read(doc, null); + if (schema == null) { + testMonitor.t1Exception = new Exception("Schema was null"); + } + + // If the cache is in use, it should not be null and there should be an + // entry for this + // Thread + if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) { + testMonitor.t1Exception = new Exception("resolvedSchemas was null"); + } + Map<String, SoftReference<XmlSchema>> threadHT = SchemaBuilderCacheTest + .getThreadResolvedSchemaHashtable(); + if (threadHT == null) { + testMonitor.t1Exception = new Exception( + "Thread resolvedSchemas was null"); + } + + if (threadHT.isEmpty()) { + testMonitor.t1Exception = new Exception( + "Thread resolvedSchemas was empty"); + } + + synchronized (testMonitor) { + testMonitor.t1SetupComplete = true; + testMonitor.notifyAll(); + while (!testMonitor.t2SetupComplete) { + try { + testMonitor.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + testMonitor.t1Exception = new RuntimeException(e); + throw (RuntimeException) testMonitor.t1Exception; + } + } + } + + // After the other thread does a reset, the cache for this thread should + // NOT be null + if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) { + testMonitor.t1Exception = new Exception( + "resolvedSchemas was null after reset"); + } + threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable(); + if (threadHT == null) { + testMonitor.t1Exception = new Exception( + "Thread resolvedSchemas was null after clear"); + } + + if (threadHT.isEmpty()) { + testMonitor.t1Exception = new Exception( + "Thread resolvedSchemas was empty after clear"); + } + + // Issue our a clear on this TID, and now there should be no entires for + // it + SchemaBuilder.clearCache(); + if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) { + testMonitor.t1Exception = new Exception( + "resolvedSchemas was null after clear on TID"); + } + + threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable(); + if (threadHT != null) { + testMonitor.t1Exception = new Exception( + "Thread resolvedSchemas was not null after clear"); + } + } +} + +/** + * Thread 2 will: - Block until released by Thread 1 - Initialize the cache then + * make sure it was used for a resolve on this thread - clear the cache and make + * sure the entries for this Thread a removed - Unblock Thread 1 to make sure + * the clear did not affect it + */ +...@ignore +class TestingRunnable2 implements Runnable { + + MultithreadUpdateLockMonitor testMonitor; + + public void run() { + synchronized (testMonitor) { + while (!testMonitor.t1SetupComplete) { + try { + testMonitor.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + testMonitor.t2Exception = new RuntimeException(e); + throw (RuntimeException) testMonitor.t2Exception; + } + } + } + SchemaBuilder.initCache(); + Document doc = SchemaBuilderCacheTest.setupDocument(); + XmlSchemaCollection schemaCol = SchemaBuilderCacheTest + .setupXmlSchemaCollection(); + XmlSchema schema = schemaCol.read(doc, null); + if (schema == null) { + testMonitor.t2Exception = new Exception("Schema was null"); + } + + // If the cache is in use, it should not be null. + if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) { + testMonitor.t2Exception = new Exception("resolvedSchemas was null"); + } + Map<String, SoftReference<XmlSchema>> threadHT = SchemaBuilderCacheTest + .getThreadResolvedSchemaHashtable(); + if (threadHT == null) { + testMonitor.t2Exception = new Exception( + "Thread resolvedSchemas was null"); + } + if (threadHT.isEmpty()) { + testMonitor.t2Exception = new Exception( + "Thread resolvedSchemas was empty"); + } + + // Issue our a clear on this TID, and now there should be no entires for + // it + SchemaBuilder.clearCache(); + if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) { + testMonitor.t2Exception = new Exception( + "resolvedSchemas was null after clear on TID"); + } + + threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable(); + if (threadHT != null) { + testMonitor.t2Exception = new Exception( + "Thread resolvedSchemas was not null after clear"); + } + + synchronized (testMonitor) { + testMonitor.t2SetupComplete = true; + testMonitor.notifyAll(); + } + } +} + +/** + * Test that the init done by Thread 1 does NOT cause the cache to be used by + * this thread which did not do an init. + */ +...@ignore +class TestingRunnable3 implements Runnable { + MultithreadUpdateLockMonitor testMonitor; + + public void run() { + synchronized (testMonitor) { + while (!testMonitor.t1SetupComplete) { + try { + testMonitor.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + testMonitor.t3Exception = new RuntimeException(e); + throw (RuntimeException) testMonitor.t2Exception; + } + } + } + Document doc = SchemaBuilderCacheTest.setupDocument(); + XmlSchemaCollection schemaCol = SchemaBuilderCacheTest + .setupXmlSchemaCollection(); + XmlSchema schema = schemaCol.read(doc, null); + if (schema == null) { + testMonitor.t3Exception = new Exception("Schema was null"); + } + Map<String, SoftReference<XmlSchema>> threadHT = SchemaBuilderCacheTest + .getThreadResolvedSchemaHashtable(); + if (threadHT != null) { + testMonitor.t3Exception = new Exception( + "Thread resolvedSchemas was not null"); + } + + } + +} Propchange: webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: webservices/commons/trunk/modules/XmlSchema/src/test/java/org/apache/ws/commons/schema/SchemaBuilderCacheTest.java ------------------------------------------------------------------------------ svn:keywords = Rev Date