You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ab...@apache.org on 2006/11/18 00:30:53 UTC
svn commit: r476365 - in
/db/derby/code/trunk/java/testing/org/apache/derbyTesting:
functionTests/tests/lang/XMLBindingTest.java
functionTests/tests/lang/XMLTypeAndOpsTest.java
junit/TestConfiguration.java junit/XML.java
Author: abrown
Date: Fri Nov 17 15:30:51 2006
New Revision: 476365
URL: http://svn.apache.org/viewvc?view=rev&rev=476365
Log:
Adds a new JUnit test to replace the old lang/xmlBinding.java test. The patch does the following:
- Adds XML file insertion utility methods to junit/XML.java
- Creates a new JUnit test called lang/XMLBindingTest.java that
uses the new utility methods to test various binding scenarios
with Derby's SQL/XML operators.
- Overloads the TestConfiguration.defaultSuite() method with a boolean
signature to allow optional addition of CleanDatabaseSetup.
- Updates lang/XMLTypeAndOpsTest to use the new overloaded defaultSuite()
method.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java (with props)
Modified:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLTypeAndOpsTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java?view=auto&rev=476365
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java Fri Nov 17 15:30:51 2006
@@ -0,0 +1,339 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.tests.lang.XMLBindingTest
+
+ 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.derbyTesting.functionTests.tests.lang;
+
+import java.io.InputStreamReader;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.Types;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.XML;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.BaseJDBCTestSetup;
+import org.apache.derbyTesting.junit.BaseTestCase;
+import org.apache.derbyTesting.junit.SupportFilesSetup;
+import org.apache.derbyTesting.junit.TestConfiguration;
+
+/**
+ * This test checks to make sure that the XML data type and
+ * the corresponding XML operations all work as expected
+ * from the JDBC side of things. In particular, this test
+ * verifies that 1) it is NOT possible to bind to/from an XML
+ * datatype (because such an operation requires JDBC 4.0 and
+ * is not yet supported by Derby), and 2) the correct behavior
+ * occurs when null values (both Java and SQL) are bound
+ * into the bindable parameters for the XML operators.
+ *
+ * This test also checks that insertion from XML files
+ * via a character stream works, which is important since
+ * XML files can be arbitrarily long and thus stream-based
+ * processing is a must.
+ */
+public class XMLBindingTest extends BaseJDBCTestCase {
+
+ /**
+ * Public constructor required for running test as standalone JUnit.
+ */
+ public XMLBindingTest(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Return a suite that runs a set of XML binding tests. Only return
+ * such a suite IF the testing classpath has the required XML classes.
+ * Otherwise just return an empty suite.
+ */
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("XML Binding Suite");
+ if (XML.classpathMeetsXMLReqs())
+ {
+ /* "false" in the next line means that we will *not* clean the
+ * database before the embedded and client suites. This ensures
+ * that we do not remove the objects created by XBindTestSetup.
+ */
+ suite.addTest(
+ TestConfiguration.defaultSuite(XMLBindingTest.class, false));
+
+ XBindTestSetup wrapper = new XBindTestSetup(suite);
+
+ /* XML parser needs to read "personal.dtd" for schema-based
+ * insertion, so copy it to user directory.
+ */
+ return new SupportFilesSetup(wrapper,
+ new String [] {
+ "functionTests/tests/lang/xmlTestFiles/personal.dtd"
+ });
+ }
+
+ return suite;
+ }
+
+ /**
+ * Performs a series of binding checks to make sure binding
+ * to or from an XML value never works.
+ */
+ public void testInvalidXMLBindings() throws Exception
+ {
+ // Binding to an XML column.
+ assertCompileError("42Z70", "insert into xTable.t1(x) values (?)");
+
+ // Binding to an XML value in the XMLSERIALIZE operator.
+ assertCompileError("42Z70",
+ "select XMLSERIALIZE(? AS CLOB) FROM XTABLE.T1");
+
+ // Binding to an XML value in the XMLEXISTS operator.
+ assertCompileError("42Z70", "select i from xTable.t1 where " +
+ "XMLEXISTS('//*' PASSING BY REF ?)");
+
+ // Binding to an XML value in the XMLQUERY operator.
+ assertCompileError("42Z70", "select i from xTable.t1 where " +
+ "XMLQUERY('//*' PASSING BY REF ? EMPTY ON EMPTY) is " +
+ "not null");
+
+ /* Make sure that attempts to bind _from_ XML will fail.
+ * We should fail at compile time with an error saying
+ * that XML values are not allowed in top-level result
+ * sets (and thus cannot be bound).
+ */
+ assertCompileError("42Z71", "select x from xTable.t1");
+ }
+
+ /**
+ * Test serialization of the XML values inserted as part
+ * XBindTestSetup processing. For the documents that are
+ * are larger than 32K, this tests that they can be correctly
+ * read from disk as a stream (instead of just as as string).
+ */
+ public void testXMLSerializeBinding() throws Exception
+ {
+ // Array of expected character counts for every row inserted
+ // into xTable.t1 as part of XBindTestSetup setup. A "0"
+ // means empty string; a "-1" means we inserted a null.
+ int [] expectedCharCounts =
+ new int [] { 40869, 40375, 1199, 1187, 1218, 954, 22, -1, -1 };
+
+ int rowCount = 0;
+ ResultSet rs = createStatement().executeQuery(
+ "select i, XMLSERIALIZE(X AS CLOB) FROM xTable.t1");
+
+ while (rs.next())
+ {
+ int charCount;
+ java.io.Reader xResult = rs.getCharacterStream(2);
+
+ // Count the number of characters we read back.
+ if (!rs.wasNull())
+ {
+ for (charCount = 0; xResult.read() != -1; charCount++);
+ xResult.close();
+ }
+ else
+ charCount = -1;
+
+ assertEquals("Unexpected serialized character count:",
+ expectedCharCounts[rowCount], charCount);
+
+ rowCount++;
+ }
+
+ assertEquals("Unexpected row count when serializing:",
+ expectedCharCounts.length, rowCount);
+
+ /* Test binding to the XMLSERIALIZE operand. Since
+ * the operand is an XML value, and since we don't
+ * allow binding to an XML value (which is tested in
+ * testInvalidXMLBindings()), there's nothing more to
+ * to do here.
+ */
+ }
+
+ /**
+ * Run some simple XPath queries against the documents
+ * inserted as part of XBindTestSetup to verify correct
+ * functionality in insertion and XMLEXISTS. Also test
+ * binding of values into the first XMLEXISTS operator
+ * (should fail).
+ */
+ public void testXMLExistsBinding() throws Exception
+ {
+ /* Test binding to the XMLEXISTS operands. Binding
+ * of the second (XML) operand is not allowed and was
+ * checked in "testInvalidXMLBindings()" above. Here we
+ * check binding of the first operand, which should fail
+ * because SQL/XML spec says the first operand must
+ * be a string literal.
+ */
+ assertCompileError("42Z75",
+ "select i from xTable.t1 where " +
+ "XMLEXISTS (? PASSING BY REF x)");
+
+ // Run some sample queries.
+ existsQuery("//abb", 1);
+ existsQuery("//d50", 1);
+ existsQuery("//person/email", 4);
+ existsQuery("/personnel", 5);
+ existsQuery("//person/@id", 4);
+
+ /* This next one is important because it verifies
+ * that implicit/default values which are defined
+ * in a DTD _are_ actually processed, even though
+ * we don't perform validation. Thus this next
+ * query _should_ return a match.
+ */
+ existsQuery("//person/@noteTwo", 1);
+ }
+
+ /**
+ * Test binding of values into the first XMLQUERY operand
+ * (should fail).
+ */
+ public void testXMLQueryBinding() throws Exception
+ {
+ /* Binding of the second (XML) operand is not allowed
+ * and is checked as part of "testInvalidXMLBindings()".
+ * Here we check binding of the first operand, which
+ * should fail because SQL/XML spec says the first
+ * operand must be a string literal.
+ */
+ assertCompileError("42Z75",
+ "select i from xTable.t1 where " +
+ "XMLQUERY (? PASSING BY REF x EMPTY ON EMPTY) " +
+ "is not null");
+ }
+
+ /**
+ * Helper method. Selects all rows (from xTable.t1) against which
+ * evaluation of the received XPath expression returns a non-empty
+ * sequence. Evaluates the query using the XMLEXISTS operator and
+ * then verifies that the number of rows matches the expected row
+ * row count.
+ *
+ * @param xPath The XPath expression to evaluate.
+ * @param expectedRows Number of rows for which we expect XMLEXISTS
+ * to return "true".
+ */
+ private void existsQuery(String xPath, int expectedRows)
+ throws Exception
+ {
+ ResultSet rs = createStatement().executeQuery(
+ "select i from xTable.t1 where " +
+ "xmlexists('" + xPath + "' passing by ref x)");
+
+ JDBC.assertDrainResults(rs, expectedRows);
+ }
+
+ /**
+ * Helper class. Creates a test table and populates it with data.
+ * That data is then used throughout the various test methods that
+ * are run in XMLBindingTest.
+ */
+ private static class XBindTestSetup extends BaseJDBCTestSetup
+ {
+ public XBindTestSetup(TestSuite tSuite) {
+ super(tSuite);
+ }
+
+ /**
+ * Create the XML table and insert all of the test documents.
+ * Some of the documents are small, others are larger than
+ * 32K (which will test stream processing of XML data). This
+ * method is called as part of the XBindTestSetup because the
+ * data is used throughout the test methods in XMLBindingTest.
+ * That said, though, this method is itself a test, as well--
+ * namley, it tests that XMLPARSE binding succeeds in all
+ * of the cases where it is expected to succeed.
+ */
+ public void setUp() throws Exception
+ {
+ String tName = "xTable.t1";
+ Connection c = getConnection();
+ c.createStatement().execute("create table " + tName +
+ "(i int generated always as identity, x xml)");
+
+ // Test parsing of > 32K XML documents.
+ XML.insertFile(c, tName, "x", "wide40k.xml", 1);
+ XML.insertFile(c, tName, "x", "deep40k.xml", 1);
+
+ /* Test parsing of docs that use schemas. Since DTDs
+ * are stored in "{user.dir}/extin" we have to modify
+ * the XML documents that use DTDs so that they can find
+ * the DTD files.
+ */
+
+ XML.insertFile(c, tName, "x", "xsdDoc.xml", 1);
+ XML.insertDocWithDTD(c, tName, "x",
+ "dtdDoc.xml", "personal.dtd", 1);
+
+ // XMLPARSE is not supposed to validate, so the following
+ // inserts should SUCCEED, even though the documents
+ // don't adhere to their schemas.
+
+ XML.insertFile(c, tName, "x", "xsdDoc_invalid.xml", 1);
+ XML.insertDocWithDTD(c, tName, "x",
+ "dtdDoc_invalid.xml", "personal.dtd", 1);
+
+ // Test simple binding to the XMLPARSE operand.
+
+ PreparedStatement pSt = getConnection().prepareStatement(
+ "insert into xTable.t1(x) values " +
+ "(XMLPARSE (DOCUMENT CAST (? as CLOB) PRESERVE WHITESPACE))");
+
+ // This should work. Note we check binding via
+ // a character stream method in XML.insertFile().
+
+ pSt.setString(1, "<simple> doc </simple>");
+ pSt.execute();
+
+ // Null should work, too. Make sure the inserts execute without
+ // error here. We'll verify the results as part of the testing
+ // for XMLSERIALIZE.
+
+ // Java null.
+ pSt.setString(1, null);
+ pSt.execute();
+
+ // SQL null.
+ pSt.setNull(1, Types.CLOB);
+ pSt.execute();
+ pSt.close();
+ c = null;
+ }
+
+ /**
+ * Just have to drop the table we created in setUp().
+ */
+ public void tearDown() throws Exception
+ {
+ getConnection().createStatement().execute("drop table xTable.t1");
+ super.tearDown();
+ }
+ }
+}
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLBindingTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLTypeAndOpsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLTypeAndOpsTest.java?view=diff&rev=476365&r1=476364&r2=476365
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLTypeAndOpsTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLTypeAndOpsTest.java Fri Nov 17 15:30:51 2006
@@ -82,22 +82,14 @@
if (!XML.classpathMeetsXMLReqs())
return suite;
- // First wrap the tests in a TestSetup that sets up / tears down
- // the "fixture", and run those wrapped tests in embedded mode.
+ /* "false" in the next line means that we will *not* clean the
+ * database before the embedded and client suites. This ensures
+ * that we do not remove the objects created by XMLTestSetup.
+ */
+ suite.addTest(
+ TestConfiguration.defaultSuite(XMLTypeAndOpsTest.class, false));
- TestSuite helperSuite = new TestSuite("XML Type And Ops -- Embedded\n");
- helperSuite.addTestSuite(XMLTypeAndOpsTest.class);
- suite.addTest(new XMLTestSetup(helperSuite));
-
- // Then wrap the tests in another TestSetup that does the same
- // thing, but this time run the wrapped tests in client mode.
-
- helperSuite = new TestSuite("XML Type And Ops -- Derby Client\n");
- helperSuite.addTest(TestConfiguration.clientServerSuite(
- XMLTypeAndOpsTest.class));
- suite.addTest(new XMLTestSetup(helperSuite));
-
- return suite;
+ return (new XMLTestSetup(suite));
}
/**
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java?view=diff&rev=476365&r1=476364&r2=476365
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java Fri Nov 17 15:30:51 2006
@@ -166,11 +166,34 @@
*/
public static Test defaultSuite(Class testClass)
{
- final TestSuite suite = new TestSuite(suiteName(testClass));
-
- suite.addTest(new CleanDatabaseTestSetup(embeddedSuite(testClass)));
- suite.addTest(new CleanDatabaseTestSetup(clientServerSuite(testClass)));
-
+ return defaultSuite(testClass, true);
+ }
+
+ /**
+ * Does the work of "defaultSuite" as defined above. Takes
+ * a boolean argument to determine whether or not to "clean"
+ * the test database before each suite. If the resultant
+ * suite is going to be wrapped inside a TestSetup that creates
+ * database objects to be used throughout the tests, then the
+ * cleanDB parameter should be "false" to prevent cleanup of the
+ * database objects that TestSetup created. For example, see
+ * XMLBindingTest.suite().
+ */
+ public static Test defaultSuite(Class testClass, boolean cleanDB)
+ {
+ final TestSuite suite = new TestSuite(suiteName(testClass));
+
+ if (cleanDB)
+ {
+ suite.addTest(new CleanDatabaseTestSetup(embeddedSuite(testClass)));
+ suite.addTest(new CleanDatabaseTestSetup(clientServerSuite(testClass)));
+ }
+ else
+ {
+ suite.addTest(embeddedSuite(testClass));
+ suite.addTest(clientServerSuite(testClass));
+ }
+
return (suite);
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java?view=diff&rev=476365&r1=476364&r2=476365
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/XML.java Fri Nov 17 15:30:51 2006
@@ -19,11 +19,18 @@
*/
package org.apache.derbyTesting.junit;
+import java.io.IOException;
import java.io.PrintWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.InputStreamReader;
import java.lang.reflect.Method;
+import java.security.PrivilegedActionException;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
import java.util.StringTokenizer;
import java.util.Properties;
@@ -32,7 +39,6 @@
/**
* XML utility methods for the JUnit tests.
- *
*/
public class XML {
@@ -77,6 +83,13 @@
= HAVE_XALAN && checkXalanVersion();
/**
+ * The filepath for the directory that holds the XML "helper" files
+ * (i.e. the files to insert and their schema documents).
+ */
+ private static final String HELPER_FILE_LOCATION =
+ "org/apache/derbyTesting/functionTests/tests/lang/xmlTestFiles/";
+
+ /**
* Return true if the classpath contains JAXP and
* Xalan classes (this method doesn't care about
* the particular version of Xalan).
@@ -95,6 +108,129 @@
public static boolean classpathMeetsXMLReqs()
{
return HAVE_JAXP && HAVE_MIN_XALAN;
+ }
+
+ /**
+ * Insert the contents of a file into the received column of
+ * the received table using "setCharacterStream". Expectation
+ * is that the file is in the directory indicated by
+ * HELPER_FILE_LOCATION.
+ *
+ * @param conn Connection on which to perform the insert.
+ * @param tableName Table into which we want to insert.
+ * @param colName Column in tableName into which we want to insert.
+ * @param fName Name of the file whose content we want to insert.
+ * @param numRows Number of times we should insert the received
+ * file's content.
+ */
+ public static void insertFile(Connection conn, String tableName,
+ String colName, String fName, int numRows)
+ throws IOException, SQLException, PrivilegedActionException
+ {
+ // First we have to figure out many chars long the file is.
+
+ fName = HELPER_FILE_LOCATION + fName;
+ java.net.URL xFile = BaseTestCase.getTestResource(fName);
+ Assert.assertNotNull("XML input file missing: " + fName, xFile);
+
+ int charCount = 0;
+ char [] cA = new char[1024];
+ InputStreamReader reader =
+ new InputStreamReader(BaseTestCase.openTestResource(xFile));
+
+ for (int len = reader.read(cA, 0, cA.length); len != -1;
+ charCount += len, len = reader.read(cA, 0, cA.length));
+
+ reader.close();
+
+ // Now that we know the number of characters, we can insert
+ // using a stream.
+
+ PreparedStatement pSt = conn.prepareStatement(
+ "insert into " + tableName + "(" + colName + ") values " +
+ "(xmlparse(document cast (? as clob) preserve whitespace))");
+
+ for (int i = 0; i < numRows; i++)
+ {
+ reader = new InputStreamReader(
+ BaseTestCase.openTestResource(xFile));
+
+ pSt.setCharacterStream(1, reader, charCount);
+ pSt.execute();
+ reader.close();
+ }
+
+ pSt.close();
+ }
+
+ /**
+ * Insert an XML document into the received column of the received
+ * test table using setString. This method parallels "insertFiles"
+ * above, except that it should be used for documents that require
+ * a Document Type Definition (DTD). In that case the location of
+ * the DTD has to be modified _within_ the document so that it can
+ * be found in the running user directory.
+ *
+ * Expectation is that the file to be inserted is in the directory
+ * indicated by HELPER_FILE_LOCATION and that the DTD file has been
+ * copied to the user's running directory (via use of the util
+ * methods in SupportFilesSetup).
+ *
+ * @param conn Connection on which to perform the insert.
+ * @param tableName Table into which we want to insert.
+ * @param colName Column in tableName into which we want to insert.
+ * @param fName Name of the file whose content we want to insert.
+ * @param dtdName Name of the DTD file that the received file uses.
+ * @param numRows Number of times we should insert the received
+ * file's content.
+ */
+ public static void insertDocWithDTD(Connection conn, String tableName,
+ String colName, String fName, String dtdName, int numRows)
+ throws IOException, SQLException, PrivilegedActionException
+ {
+ // Read the file into memory so we can update it.
+ fName = HELPER_FILE_LOCATION + fName;
+ java.net.URL xFile = BaseTestCase.getTestResource(fName);
+ Assert.assertNotNull("XML input file missing: " + fName, xFile);
+
+ int charCount = 0;
+ char [] cA = new char[1024];
+ StringBuffer sBuf = new StringBuffer();
+ InputStreamReader reader =
+ new InputStreamReader(BaseTestCase.openTestResource(xFile));
+
+ for (int len = reader.read(cA, 0, cA.length); len != -1;
+ charCount += len, len = reader.read(cA, 0, cA.length))
+ {
+ sBuf.append(cA, 0, len);
+ }
+
+ reader.close();
+
+ // Now replace the DTD location.
+
+ java.net.URL dtdURL = SupportFilesSetup.getReadOnlyURL(dtdName);
+ Assert.assertNotNull("DTD file missing: " + dtdName, dtdURL);
+
+ String docAsString = sBuf.toString();
+ int pos = docAsString.indexOf(dtdName);
+ if (pos != -1)
+ sBuf.replace(pos, pos+dtdName.length(), dtdURL.toExternalForm());
+
+ // Now (finally) do the insert using the in-memory document with
+ // the correct DTD location.
+ docAsString = sBuf.toString();
+ PreparedStatement pSt = conn.prepareStatement(
+ "insert into " + tableName + "(" + colName + ") values " +
+ "(xmlparse(document cast (? as clob) preserve whitespace))");
+
+ for (int i = 0; i < numRows; i++)
+ {
+ pSt.setString(1, docAsString);
+ pSt.execute();
+ }
+
+ pSt.close();
}
/**