/* * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is the Kowari Metadata Store. * * The Initial Developer of the Original Code is Plugged In Software Pty * Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions * created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002 * Plugged In Software Pty Ltd. All Rights Reserved. * * Contributor(s): N/A. * * [NOTE: The text of this Exhibit A may differ slightly from the text * of the notices in the Source Code files of the Original Code. You * should use the text of this Exhibit A rather than the text found in the * Original Code Source Code for Your Modifications.] * */ package org.mulgara.itql; import org.mulgara.query.Answer; import org.mulgara.query.QueryException; import org.mulgara.server.SessionFactory; import org.mulgara.server.driver.SessionFactoryFinder; import org.mulgara.util.Rmi; import org.mulgara.util.StackTrace; import org.mulgara.util.TempDir; // third party packages import junit.framework.TestCase; import junit.framework.TestSuite; // Java 2 standard packages import java.net.URL; import java.util.Vector; import java.net.*; import java.io.File; import java.io.FileOutputStream; // third party packages import javax.xml.parsers.FactoryConfigurationError; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; // Soap packages // Soap packages import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.rpc.*; // emory util package import edu.emory.mathcs.util.remote.io.*; import edu.emory.mathcs.util.remote.io.server.impl.*; /** * Unit test for {@link ItqlInterpreterBeanUnitTest}. * * @created 2001-11-19 * * @author Tate Jones * * @version $Revision: 1.9 $ * * @modified $Date: 2005/01/05 05:13:59 $ by $Author: newmana $ * * @company <a href="mailto:info@PIsoftware.com">Plugged In Software</a> * * @copyright ©2001 <a href="http://www.pisoftware.com/">Plugged In * Software Pty Ltd</a> * * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a> */ public class ItqlInterpreterBeanUnitTest extends TestCase { // // Members // /** The category to send logging info to */ private static final Logger log = Logger.getLogger(ItqlInterpreterBeanUnitTest.class); /** Description of the Field */ private ItqlInterpreterBean bean = null; /** host name of server */ private static String hostName = System.getProperty("host.name", "localhost"); /** an example model */ private static String testModel = "rmi://" + hostName + "/server1#itqlmodel"; /** Data directory for test files */ private static String dataDirectory = System.getProperty("cvs.root") + "/data"; static { if ( System.getProperty("os.name").indexOf("Windows") >= 0 ) { dataDirectory = "/"+dataDirectory.replace('\\','/'); } } /** a temp directory location */ private static File tmpDirectory = TempDir.getTempDir(); // // Public API // /** * Constructs a new ItqlInterpreter unit test. * * @param name the name of the test */ public ItqlInterpreterBeanUnitTest(String name) { // delegate to super class constructor super(name); // load the logging configuration try { DOMConfigurator.configure(System.getProperty("cvs.root") + "/log4j-conf.xml"); } catch (FactoryConfigurationError fce) { log.error("Unable to configure logging service from XML configuration file"); } } /** * Returns a test suite containing the tests to be run. * * @return the test suite */ public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ItqlInterpreterBeanUnitTest("testQuery1")); suite.addTest(new ItqlInterpreterBeanUnitTest("testQuery2")); suite.addTest(new ItqlInterpreterBeanUnitTest("testQuery3")); suite.addTest(new ItqlInterpreterBeanUnitTest("testAnswerIteration")); suite.addTest(new ItqlInterpreterBeanUnitTest("testCreateModel")); suite.addTest(new ItqlInterpreterBeanUnitTest("testLoadApi5")); suite.addTest(new ItqlInterpreterBeanUnitTest("testLoadApi6")); suite.addTest(new ItqlInterpreterBeanUnitTest("testLoadApi7")); suite.addTest(new ItqlInterpreterBeanUnitTest("testLoadApi8")); suite.addTest(new ItqlInterpreterBeanUnitTest("testLoadApi9")); suite.addTest(new ItqlInterpreterBeanUnitTest("testBackupApi1")); suite.addTest(new ItqlInterpreterBeanUnitTest("testBackupApi2")); suite.addTest(new ItqlInterpreterBeanUnitTest("testExportApi1")); suite.addTest(new ItqlInterpreterBeanUnitTest("testExportApi2")); suite.addTest(new ItqlInterpreterBeanUnitTest("testRestoreApi1")); suite.addTest(new ItqlInterpreterBeanUnitTest("testRoundTrip1")); suite.addTest(new ItqlInterpreterBeanUnitTest("testMultipleBeanTest")); suite.addTest(new ItqlInterpreterBeanUnitTest("testExplicitSession")); return suite; } /** * The main program for the ItqlInterpreterBeanUnitTest class * * @param args The command line arguments * @throws Exception General catch-all for exceptions thrown during the entire test suite */ public static void main(String[] args) throws Exception { junit.textui.TestRunner.run(suite()); } /** * Convert Windows line endings... */ private static String convertLineEndings(String str) { String converted = str; if (System.getProperty("os.name").toLowerCase().indexOf("win") > -1) { converted = converted.replaceAll("\r\n", "\n"); } return converted; } /** * Test the interpreter via a direct call and a SOAP call * * @throws Exception if the test fails */ public void testQuery1() throws Exception { String queryString = "select $s $p $o from <rmi://" + hostName + "/server1#> where $s $p $o ;"; String directAnswer = bean.executeQueryToString(queryString); directAnswer = convertLineEndings(directAnswer); String soapAnswer = this.executeSoapCall(queryString); assertEquals( "A basic SELECT SOAP iTQL result is not the same as a direct call", soapAnswer, directAnswer); } /** * A unit test for JUnit * * @throws Exception General catch-all for exceptions thrown during the test */ public void testQuery2() throws Exception { String queryString = "create <rmi://" + hostName + "/server1#model> ;"; String directAnswer = bean.executeQueryToString(queryString); directAnswer = convertLineEndings(directAnswer); String soapAnswer = this.executeSoapCall(queryString); assertEquals("A CREATE SOAP iTQL result is not the same as a direct call", soapAnswer, directAnswer); } /** * A unit test for JUnit * * @throws Exception General catch-all for exceptions thrown during the test */ public void testQuery3() throws Exception { String queryString = "insert <http://google.blogspace.com/archives/000999836> <http://purl.org/rss/1.0/description> 'Google needs to stop sending it\\'s cookie and promise to only store aggregate data, with no connection between users and search terms. ; This issue was publically raised almost a year ago that Google still hasnt dealt with its inexcusable....' into <rmi://" + hostName + "/server1#model>;"; String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<answer xmlns=\"http://mulgara.org/tql#\"><query><message>Successfully inserted statements into rmi://" + hostName + "/server1#model</message></query></answer>"; String directAnswer = bean.executeQueryToString(queryString); directAnswer = convertLineEndings(directAnswer); String soapAnswer = this.executeSoapCall(queryString); if (log.isDebugEnabled()) { log.error("\nDIRECT:'" + directAnswer + "'"); log.error("\nSOAP :'" + soapAnswer + "'"); log.error("\nEQUALS :'" + soapAnswer.equals(directAnswer) + "'"); log.error("\nSSTARTS :'" + soapAnswer.startsWith(directAnswer) + "'"); log.error("\nDSTARTS :'" + directAnswer.startsWith(soapAnswer) + "'"); } assertEquals("A insert SOAP iTQL result is not the same as a direct call", soapAnswer, directAnswer); assertEquals("Incorrect iTQL result found", soapAnswer, result); } /** * A unit test for JUnit. Tests that an Answer can be obtained and * iterated over and reset multiple times. * * @throws Exception General catch-all for exceptions thrown during the test */ public void testAnswerIteration() throws Exception { //create model String model = "rmi://" + hostName + "/server1#answerModel"; String query = "create <" + model + "> ;"; bean.executeQueryToString(query); //load data String dataFile = "file:" + dataDirectory + "/numbers.rdf.gz"; query = "load <" + dataFile + "> into <" + model + "> ;"; //number of statements must be more than 1 page size (1000 statements) System.setProperty("mulgara.rmi.prefetchsize", "10"); bean.executeQueryToString(query); bean.executeQueryToString(query); //get Answer (everything) query = "select $s $p $o from <" + model + "> where $s $p $o;"; Answer result = bean.executeQuery(query); result.close(); //iterate and re-iterate - ensuring rowCount is preserved try { result = bean.executeQuery(query); //determine the number of statements in the Answer long rowCount = result.getRowCount(); long statementCount = 0; //number of times to iterate int NUM_ITERATIONS = 10; for (int i = 0; i < NUM_ITERATIONS; i++) { //count to the end of Answer while (result.next()) { statementCount++; } //ensure all statements were preserved assertEquals("Number of Statements in Answer has changed after " + "iteration: " + i + ". Answer: " + result.getClass().getName(), rowCount, statementCount); //reset result.beforeFirst(); statementCount = 0; } } finally { try { result.close(); } finally { //drop the model bean.executeQueryToString("drop <" + model + "> ;"); } } } /** * Performs a query over the SOAP interface * * @param query The TQL query to execute over the interface. * @return The XML response to the call, as a string. * @throws Exception General catch-all for exceptions thrown during the call */ public String executeSoapCall(String query) throws Exception { //URL url = new URL("http://" + hostName + ":8080/soap/servlet/rpcrouter"); URL url = new URL("http://" + hostName + ":8080/webservices/services/ItqlBeanService"); // Build the call. Call call = new Call(); call.setTargetObjectURI("urn:Query"); call.setMethodName("executeQueryToString"); //call.setEncodingStyleURI(Constants.NS_URI_LITERAL_XML); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); Vector<Parameter> params = new Vector<Parameter>(); params.addElement(new Parameter("queryString", String.class, query, Constants.NS_URI_SOAP_ENC)); call.setParams(params); // make the call: note that the action URI is empty because the // XML-SOAP rpc router does not need this. This may change in the // future. Response resp = call.invoke( /* router URL */ url, /* actionURI */ ""); // Check the response. if (resp.generatedFault()) { Fault fault = resp.getFault(); fail("Soap call has failed : Fault Code = " + fault.getFaultCode() + " Fault String = " + fault.getFaultString()); return fault.getFaultCode() + " - " + fault.getFaultString(); } else { Parameter result = resp.getReturnValue(); return result.getValue().toString(); } } /** * Test the interpreter using a create statement. Executes the following * query: <pre> * create <mulgara://localhost/database> ; * </pre> Expects results: ParserException * * @throws Exception if the test fails */ public void testCreateModel() throws Exception { // log that we're executing the test log.debug("Starting create test 3"); // create the statement String statement = "create <" + testModel + "> ;"; // log the query we'll be sending log.debug("Executing statement : " + statement); String results = ""; // execute the query bean.executeQuery(statement); results = bean.getLastMessage(); // log the results log.debug("Received results : " + results); // log that we've completed the test log.debug("Completed create test 3"); } /** * Test the interpreter using a load API locally * * @throws Exception if the test fails */ public void testLoadApi5() throws Exception { // log that we're executing the test log.debug("Starting load API test 5"); File source = new File(dataDirectory + "/ical.rdf"); URI modelURI = new URI(testModel); // execute the load locally long statements = bean.load(source, modelURI); assertEquals("Incorrect number of statements inserted", 1482, statements); } /** * Test the interpreter using a load API locally * * @throws Exception if the test fails */ public void testLoadApi6() throws Exception { // log that we're executing the test log.debug("Starting load API test 6"); File source = new File(dataDirectory + "/camera.owl"); URI modelURI = new URI(testModel); // execute the load locally long statements = bean.load(source, modelURI); assertEquals("Incorrect number of statements inserted", 103, statements); } /** * Test the interpreter using a load API locally * * @throws Exception if the test fails */ public void testLoadApi7() throws Exception { boolean badFile = false; // log that we're executing the test log.debug("Starting load API test 7"); File source = new File(dataDirectory + "/camera.owl.bad"); URI modelURI = new URI(testModel); // execute the load locally try { bean.load(source, modelURI); } catch (QueryException ex) { badFile = true; } assertTrue("Excepting a bad file", badFile); } /** * Test the interpreter using a load API locally * * @throws Exception if the test fails */ public void testLoadApi8() throws Exception { // log that we're executing the test log.debug("Starting load API test 8"); File source = new File(dataDirectory + "/camera.n3"); URI modelURI = new URI(testModel); // execute the load locally long statements = bean.load(source, modelURI); assertEquals("Incorrect number of statements inserted", 99, statements); } /** * Test the interpreter using a load API locally with a GZip file. * * @throws Exception if the test fails */ public void testLoadApi9() throws Exception { try { // log that we're executing the test log.debug("Starting load API test 9"); File source = new File(dataDirectory + "/numbers.rdf.gz"); URI modelURI = new URI(testModel); // execute the load locally long statements = bean.load(source, modelURI); assertEquals("Incorrect number of statements inserted", 512, statements); } catch (Exception exception) { exception.printStackTrace(); throw exception; } } /** * Test the interpreter using a backup API locally. * Expects the server to exist * * @throws Exception if the test fails */ public void testBackupApi1() throws Exception { // log that we're executing the test log.debug("Starting backup API test 2"); try { File file = new File(tmpDirectory, "server.gz"); file.delete(); URI serverURI = new URI("rmi://localhost/server1"); bean.backup(serverURI, file); assertTrue("Excepting a backup file", file.exists()); } catch (QueryException e) { System.err.println("Error processing query" + e); Throwable t = e.getCause(); while (t != null) { System.err.println("Caused by: " + t + StackTrace.throwableToString(t)); t = t.getCause(); } throw e; } } /** * Test the interpreter using a backup API locally. * Expects the server to exist * * @throws Exception if the test fails */ public void testBackupApi2() throws Exception { // log that we're executing the test log.debug("Starting backup API test 4"); try { File file = new File(tmpDirectory, "server2.gz"); file.delete(); URI serverURI = new URI("rmi://localhost/server1"); bean.backup(serverURI, new FileOutputStream(file)); assertTrue("Excepting a backup file", file.exists()); } catch (QueryException e) { System.err.println("Error processing query" + e); Throwable t = e.getCause(); while (t != null) { System.err.println("Caused by: " + t + StackTrace.throwableToString(t)); t = t.getCause(); } throw e; } } /** * Test the interpreter using an export API locally. * Expects the test model to exist * * @throws Exception if the test fails */ public void testExportApi1() throws Exception { // log that we're executing the test log.debug("Starting backup API test 1"); File file = new File(tmpDirectory, "camera.rdf"); file.delete(); URI modelURI = new URI(testModel); bean.export(modelURI, file); assertTrue("Excepting a backup file", file.exists()); } /** * Test the interpreter using an export API locally. * Expects the test model to exist * * @throws Exception if the test fails */ public void testExportApi2() throws Exception { // log that we're executing the test log.debug("Starting backup API test 3"); File file = new File(tmpDirectory, "camera2.rdf"); file.delete(); URI modelURI = new URI(testModel); bean.export(modelURI, new FileOutputStream(file)); assertTrue("Excepting a backup file", file.exists()); } /** * Test the interpreter using a restore API locally. * Expects the server to exist * * @throws Exception if the test fails */ public void testRestoreApi1() throws Exception { // log that we're executing the test log.debug("Starting restore API test 1"); try { File file = new File(tmpDirectory, "server2.gz"); URI serverURI = new URI("rmi://localhost/server1"); bean.restore(file.toURI().toURL().openStream(), serverURI); } catch (QueryException e) { System.err.println("Error processing query" + e); Throwable t = e.getCause(); while (t != null) { System.err.println("Caused by: " + t + StackTrace.throwableToString(t)); t = t.getCause(); } throw e; } } /** * Test a round trip of backup and restore * * This will test relative and absolute URIs to the server host name. * * @throws Exception if the test fails */ public void testRoundTrip1() throws Exception { try { // log that we're executing the test log.debug("Starting round trip test 1"); URI serverURI = new URI("rmi://" + hostName + "/server1"); // test the output String select = "select $o from <" + testModel + "> " + "where <rmi://" + hostName + "/server1> <http://purl.org/dc/elements/1.1/creator> $o or " + " <rmi://" + hostName + "/foobar> <http://purl.org/dc/elements/1.1/creator> $o or " + " <rmi://" + hostName + "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> $o ;"; // insert statements with a subject the same as the // server name String insert = "insert " + "<rmi://" + hostName + "/server1> <http://purl.org/dc/elements/1.1/creator> 'foo' " + "<rmi://" + hostName + "/foobar> <http://purl.org/dc/elements/1.1/creator> 'foobar' " + "<rmi://" + hostName + "/server1/foobar> <http://purl.org/dc/elements/1.1/creator> 'server1/foobar' " + " into <" + testModel + ">;"; // insert the statement bean.executeQuery(insert); // select the statement Answer answer = bean.executeQuery(select); assertTrue("Excepting a answer before restore", answer != null); assertTrue("Excepting a single result and found :" + answer.getRowCount(), (answer.getRowCount() == 3)); //backup the server File file = new File(tmpDirectory, "roundtrip.gz"); file.delete(); bean.backup(serverURI, new FileOutputStream(file)); assertTrue("Excepting a backup file", file.exists()); // restore the server bean.restore(file.toURI().toURL().openStream(), serverURI); // select the statement answer = bean.executeQuery(select); assertTrue("Excepting a answer after restore", answer != null); assertTrue("Excepting a single result and found :" + answer.getRowCount(), (answer.getRowCount() == 3)); } catch (QueryException e) { System.err.println("Error processing query" + e); Throwable t = e.getCause(); while (t != null) { System.err.println("Caused by: " + t + StackTrace.throwableToString(t)); t = t.getCause(); } throw e; } } /** * Test the multiple creations of the interpreterbean * Ensure the number of open files are not exceeded on OS. * */ public void testMultipleBeanTest() { /* // keep a track of the number of session directories String sessionDir = testDir + File.separator + "server1" + File.separator + "sessions" + File.separator; System.out.println("Session dir is "+ sessionDir ); // log that we're executing the test log.debug("Starting multiple bean test"); // get the initial number of directories int initNumberOfSessionDirs = (new File(sessionDir)).list().length; log.debug("Initial number of session directories are "+initNumberOfSessionDirs); */ String query = "select $s $p $o from <rmi://" + hostName + "/server1#> where $s $p $o;"; // create a 100 beans // TODO: change back to 1000 for (int count = 1; count < 100; count++) { ItqlInterpreterBean bean = null; Answer answer = null; try { // create a new bean. bean = new ItqlInterpreterBean(); log.warn("Starting bean number " + count); // execute a basic query answer = bean.executeQuery(query); assertTrue("Failed to query system model", answer.getRowCount() > 0); answer.close(); } catch (Exception ex) { log.error("Failed to create/query the " + count + " ItqlInterpreterBean", ex); System.err.println("Failed to create/query the " + count + " ItqlInterpreterBean"); System.err.println("Exception: " + ex.getMessage()); ex.printStackTrace(); assertTrue("Failed to create/query the " + count + " ItqlInterpreterBean", false); break; } finally { bean.close(); } } /* // get the end number of directories int endNumberOfSessionDirs = (new File(sessionDir)).list().length; log.debug("The end number of session directories are "+endNumberOfSessionDirs); // the init and end number of directories should be the same assertTrue("Expecting "+initNumberOfSessionDirs+" session to exist, but "+ "found "+endNumberOfSessionDirs+" session directories", endNumberOfSessionDirs == initNumberOfSessionDirs); */ } /** * Test giving ItqlInterpreterBean an explicit session. * * @throws Exception if the test fails */ @SuppressWarnings("deprecation") public void testExplicitSession() throws Exception { // log that we're executing the test log.debug("Starting explicit session test"); URI serverURI = new URI("rmi://" + hostName + "/server1"); SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, true); bean.close(); bean = new ItqlInterpreterBean(sessionFactory.newSession(), sessionFactory.getSecurityDomain()); // auto-commit = true bean.executeQuery( "insert <es:foo1> <es:bar1> 'foo' into <" + testModel + ">;"); Answer answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting a single result", 1, answer.getRowCount()); bean.executeQuery( "delete <es:foo1> <es:bar1> 'foo' from <" + testModel + ">;"); answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting no results", 0, answer.getRowCount()); // explicit tx with commit bean.beginTransaction("explicit-session-test-commit"); bean.executeQuery( "insert <es:foo1> <es:bar1> 'foo' into <" + testModel + ">;"); answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting a single result", 1, answer.getRowCount()); bean.executeQuery( "delete <es:foo1> <es:bar1> 'foo' from <" + testModel + ">;"); bean.commit("explicit-session-test-commit"); answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting no results", 0, answer.getRowCount()); // explicit tx with rollback bean.beginTransaction("explicit-session-test-rollback"); bean.executeQuery( "insert <es:foo1> <es:bar1> 'foo' into <" + testModel + ">;"); answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting a single result", 1, answer.getRowCount()); bean.rollback("explicit-session-test-rollback"); answer = bean.executeQuery( "select $p $o from <" + testModel + "> " + "where <es:foo1> $p $o;"); assertEquals("Expecting no results", 0, answer.getRowCount()); } // ItqlInt /** * Initialise members. * * @throws Exception if something goes wrong */ protected void setUp() throws Exception { bean = new ItqlInterpreterBean(); } protected void tearDown() throws Exception { if (bean != null) { try { bean.close(); } finally { bean = null; } } } }