/* Copyright (c) 2001-2019, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.io.File;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.FileReader;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.lang.reflect.Method;
import org.hsqldb.test.TestUtil;
import org.hsqldb.lib.RCData;

See Also:
  • main
/** * @see #main */
class TestScriptRunner { protected static final String DEFAULT_RCFILE = "testscriptrunner.rc"; public static String LS = System.getProperty("line.separator"); public static String SYNTAX_MSG = "java " + TestScriptRunner.class.getName() + " [--optionalSwitches...] --urlid=URLID1 [script1.tsql [[--urlid=URLIDX] scriptY.tsql...]...]" + LS + " Specify one input file name as '-' to read from stdin." + LS + " No scripts specified will read from only stdin." + LS + " Simple single-threaded example with RC file '" + DEFAULT_RCFILE + "':" + LS + "java " + TestScriptRunner.class.getName() + "--urlid=URLID script1.tsql script2.tsql" + LS + LS + "OPTIONAL SWITCHES:" + LS + " --verbose Obviously..." + LS + " --threads Each script runs in a parallel thread (dflt. sequential)." + LS + " --rcfile=/path/to/file.rc (Defaults to '" + DEFAULT_RCFILE + "')" + LS + " --populate Use TestCacheSize class to populate one database" + LS + " --sqltool=URLID Invoke an interactive SqlTool session on given URLID" + LS + "(This last is useful for troubleshooting and interactive script dev)."; public boolean verbose = false; public boolean threaded = false;
Executes specified SQL test scripts. Run java org.hsqldb.util.TestScriptRunner with no args to display syntax help. The TestCacheSize database population uses the database details as generated in TestCacheSize. It would be nice to get these from the RC file, but alas, TestCacheSize does much magical work based on components of the URL, for example. Therefore our user must make a URLID definition to match that generated by TestCacheSize for the DB type requested below. We must use that as the URLID for scripts (and/or SqlTool session) which we want to connect to the same database.
/** * Executes specified SQL test scripts. * * Run <CODE>java org.hsqldb.util.TestScriptRunner</CODE> with no * args to display syntax help. * * The TestCacheSize database population uses the database details * as generated in TestCacheSize. It would be nice to get these * from the RC file, but alas, TestCacheSize does much magical work * based on components of the URL, for example. Therefore our user * must make a URLID definition to match that generated by * TestCacheSize for the DB type requested below. We must use that * as the URLID for scripts (and/or SqlTool session) which we want * to connect to the same database. */
public static void main(String[] sa) throws IOException, SQLException { // Make a copy if argv so we can change it safely int argIndex = 0; boolean threaded = false; boolean verbose = false; boolean populate = false; String rcFile = DEFAULT_RCFILE; Map scriptFileMap = new HashMap(); // scriptname -> URLID String currentUrlid = null; String sqlToolUrlid = null; Method sqlToolMainMethod = null; try { for (int i = 0; i < sa.length; i++) { if (sa[i].equals("--verbose")) { verbose = true; continue; } if (sa[i].equals("--threads")) { threaded = true; continue; } if (sa[i].equals("--populate")) { populate = true; continue; } if (sa[i].startsWith("--rcfile=")) { rcFile = sa[i].substring("--rcfile=".length()); continue; } if (sa[i].startsWith("--urlid=")) { currentUrlid = sa[i].substring("--urlid=".length()); continue; } if (sa[i].startsWith("--sqltool=")) { sqlToolUrlid = sa[i].substring("--sqltool=".length()); continue; } if (currentUrlid == null) { throw new IllegalArgumentException( "You must specify 'urlid' before script files."); } if (scriptFileMap.containsKey(sa[i])) throw new IllegalArgumentException( TestScriptRunner.class.getName() + " can't handle the same script name twice. " + "(Just copy or sym-link the script)."); scriptFileMap.put(sa[i], currentUrlid); } if (currentUrlid == null) throw new IllegalArgumentException(); if (scriptFileMap.size() < 1) { scriptFileMap.put("-", currentUrlid); } } catch (IllegalArgumentException e) { if (e.getMessage() != null) System.err.println(e.getMessage()); System.err.println(SYNTAX_MSG); System.exit(2); } if (sqlToolUrlid != null) { Class sqlToolClass = null; try { sqlToolClass = Class.forName("org.hsqldb.util.SqlTool"); } catch (Exception e) { System.err.println("SqlTool class not accessible. " + "Re-run without '--sqltool' switch."); System.exit(3); } try { sqlToolMainMethod = sqlToolClass. getMethod("objectMain", new Class[] {sa.getClass()} ); } catch (Exception e) { System.err.println("SqlTool integration failure: " + e); System.exit(3); } } TestScriptRunner runner = new TestScriptRunner(rcFile, scriptFileMap); runner.setVerbose(verbose); runner.setThreaded(threaded); TestCacheSize tcs = populate ? populate() : null; runner.establishConnections(); boolean success = runner.runScripts(); if (sqlToolMainMethod != null) try { sqlToolMainMethod.invoke(null, new Object[] { new String[] { "--rcfile=" + rcFile, sqlToolUrlid }}); } catch (Exception e) { System.err.println("SqlTool failed: " + e); e.printStackTrace(); } if (tcs != null) tcs.tearDown(); System.exit(success ? 0 : 1); } List scriptRuns = new ArrayList(); private class ScriptRun extends Thread { private Reader reader; private Connection conn = null; private RCData rcdata; private boolean success = false; public ScriptRun(String name, Reader reader, RCData rcdata) { super(name); this.reader = reader; this.rcdata = rcdata; } public boolean getSuccess() { return success; } public void connect() throws SQLException { if (conn != null) { throw new IllegalStateException("Thread '" + getName() + "' has already been connected"); } try { conn = rcdata.getConnection(); } catch (Exception e) { throw new RuntimeException( "Failed to connect to get JDBC connection for '" + getName() + "'", e); } conn.setAutoCommit(false); System.out.println("ScriptRun '" + getName() + "' connected with " + RCData.tiToString(conn.getTransactionIsolation()) + '.'); } public void run() { try { TestUtil.testScript(conn, getName(), reader); success = true; } catch (TestUtil.TestRuntimeException tre) { System.err.println("Script '" + getName() + "' failed"); } catch (IOException ioe) { System.err.println("Aborting thread for script '" + getName() + "' due to: " + ioe); throw new RuntimeException(ioe); } catch (SQLException se) { System.err.println("Aborting thread for script '" + getName() + "' due to: " + se); throw new RuntimeException(se); } finally { try { conn.close(); } catch (SQLException se) { System.err.println("Failed to close JDBC connection for '" + getName() + "': " + se); } } } } public void setVerbose(boolean verbose) { this.verbose = verbose; } public void setThreaded(boolean threaded) { this.threaded = threaded; } public TestScriptRunner(String rcFileString, Map scriptFileMap) throws IOException { TestUtil.setAbortOnErr(true); Map rcdataMap = new HashMap(); File rcFile = new File(rcFileString); if (!rcFile.isFile()) throw new IllegalArgumentException( "RC file '" + rcFileString + "' not a file"); String scriptPath, urlid; Iterator it; File file; Reader reader = null; it = scriptFileMap.values().iterator(); while (it.hasNext()) { urlid = (String) it.next(); if (rcdataMap.containsKey(urlid)) continue; try { rcdataMap.put(urlid, new RCData(rcFile, urlid)); } catch (Exception e) { throw new RuntimeException( "Failed to instantiate RCData with file '" + rcFile + "' for urlid '" + urlid + "'", e); } } it = scriptFileMap.keySet().iterator(); while (it.hasNext()) { scriptPath = (String) it.next(); urlid = (String) scriptFileMap.get(scriptPath); if (scriptPath.equals("-")) { reader = new InputStreamReader(System.in); } else { file = new File(scriptPath); if (!file.isFile()) throw new IOException("'" + file + "' is not a file"); if (!file.canRead()) throw new IOException("'" + file + "' is not readable"); reader = new FileReader(file); } scriptRuns.add(new ScriptRun(scriptPath, reader, (RCData) rcdataMap.get(urlid))); } } public void establishConnections() throws SQLException { for (int i = 0; i < scriptRuns.size(); i++) ((ScriptRun) scriptRuns.get(i)).connect(); if (verbose) System.out.println(Integer.toString(scriptRuns.size()) + " connection threads connected"); } public boolean runScripts() { ScriptRun scriptRun; for (int i = 0; i < scriptRuns.size(); i++) { scriptRun = (ScriptRun) scriptRuns.get(i); if (verbose) System.out.print("Starting " + (++i) + " / " + scriptRuns.size() + "..."); scriptRun.start(); if (verbose) System.out.println(" +"); if (!threaded) try { scriptRun.join(); } catch (InterruptedException ie) { throw new RuntimeException( "Interrupted while waiting for script '" + scriptRun.getName() + "' to execute", ie); } } if (threaded) { if (verbose) System.out.println( "All scripts started. Will now wait for them."); for (int i = 0; i < scriptRuns.size(); i++) try { ((ScriptRun) scriptRuns.get(i)).join(); } catch (InterruptedException ie) { throw new RuntimeException( "Interrupted while waiting for script to execute", ie); } } for (int i = 0; i < scriptRuns.size(); i++) { if (!((ScriptRun) scriptRuns.get(i)).getSuccess()) return false; } return true; }
Copied directly from TestCacheSize.main(). My goal is to configure population of this database by a properties file, not by command line (which would just be too many settings along with the main settings), nor by System Properties (ditto). I see nothing in the TestCacheSize source code to allow loading by a properties file, however.
/** * Copied directly from TestCacheSize.main(). * * My goal is to configure population of this database by a properties * file, not by command line (which would just be too many settings * along with the main settings), nor by System Properties (ditto). * I see nothing in the TestCacheSize source code to allow loading by * a properties file, however. */
static protected TestCacheSize populate() { TestCacheSize test = new TestCacheSize(); /* Use all defaults HsqlProperties props = HsqlProperties.argArrayToProps(argv, "test"); test.bigops = props.getIntegerProperty("test.bigops", test.bigops); test.bigrows = test.bigops; test.smallops = test.bigops / 8; test.cacheScale = props.getIntegerProperty("test.scale", test.cacheScale); test.logType = props.getProperty("test.logtype", test.logType); test.tableType = props.getProperty("test.tabletype", test.tableType); test.nioMode = props.isPropertyTrue("test.nio", test.nioMode); */ test.filepath = "mem:test"; test.filedb = false; test.shutdown = false; test.setUp(); test.testFillUp(); //test.checkResults(); //System.out.println("total test time -- " + sw.elapsedTime() + " ms"); return test; } }