Mercurial > hg > monetdb-java
changeset 519:04a72c5bde80 onclient
Add OnclientTester.java
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Wed, 25 Aug 2021 15:42:22 +0200 (2021-08-25) |
parents | e84b3cbd8b57 |
children | b4c7816e3592 |
files | tests/OnClientTester.java tests/build.xml |
diffstat | 2 files changed, 311 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/tests/OnClientTester.java @@ -0,0 +1,304 @@ +import org.monetdb.jdbc.MonetConnection; +import org.monetdb.jdbc.MonetUploadHandler; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.*; + +public final class OnClientTester { + private String jdbcUrl; + boolean verbose = false; + boolean succeeded = true; + private MonetConnection conn; + private PrintWriter out; + private Statement stmt; + private StringWriter outBuffer; + + public static void main(String[] args) throws SQLException, NoSuchMethodException { + String jdbcUrl; + String specificTest = null; + switch (args.length) { + case 2: + specificTest = args[1]; + /* fallthrough */ + case 1: + jdbcUrl = args[0]; + break; + default: + throw new IllegalArgumentException("Usage: OnClientTester JDBC_URL [TESTNAME]"); + } + + OnClientTester tester = new OnClientTester(jdbcUrl); + boolean succeeded; + if (specificTest != null) + succeeded = tester.runTest(specificTest); + else + succeeded = tester.runTests(); + + if (tester.verbosity >= VERBOSITY_ON || tester.failureCount > 0) { + System.out.println(); + System.out.println("Ran " + tester.testCount + " tests, " + tester.failureCount + " failed"); + } + if (tester.failureCount > 0) { + System.exit(1); + } + } + + public OnClientTester(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + private boolean runTests() throws SQLException, NoSuchMethodException { + for (Method method: this.getClass().getDeclaredMethods()) { + String methodName = method.getName(); + if (methodName.startsWith("test_") && method.getParameterCount() == 0) { + String testName = methodName.substring(5); + runTest(testName, method); + } + } + + return succeeded; + } + + private boolean runTest(String testName) throws SQLException, NoSuchMethodException { + String methodName = "test_" + testName; + Method method = this.getClass().getDeclaredMethod(methodName); + + return runTest(testName, method); + } + + private synchronized boolean runTest(String testName, Method method) throws SQLException { + outBuffer = new StringWriter(); + out = new PrintWriter(outBuffer); + + Connection genericConnection = DriverManager.getConnection(jdbcUrl); + conn = genericConnection.unwrap(MonetConnection.class); + stmt = conn.createStatement(); + + System.out.println(); + + try { + try { + method.invoke(this); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof Failure) + throw (Failure)cause; + else if (cause instanceof Exception) { + throw (Exception)cause; + } else { + throw e; + } + } + + System.out.println("Test " + testName + " succeeded"); + if (verbose) + dumpOutput(); + } catch (Failure e) { + succeeded = false; + System.out.println("Test " + testName + " failed"); + dumpOutput(); + } catch (Exception e) { + succeeded = false; + System.out.println("Test " + testName + " failed:"); + e.printStackTrace(); + System.out.println(); + dumpOutput(); + // Show the inner bits of the exception again, they may have scrolled off screen + Throwable t = e; + while (t.getCause() != null) { + t = t.getCause(); + } + System.out.println(); + System.out.println("Innermost cause was " + t); + if (t.getStackTrace().length > 0) { + System.out.println(" at " + t.getStackTrace()[0]); + } + } finally { + stmt.close(); + conn.close(); + } + + return succeeded; + } + + private void dumpOutput() { + String output = outBuffer.getBuffer().toString(); + if (output.isEmpty()) { + System.out.println("(Test did not produce any output)"); + } else { + System.out.println("------ Accumulated output:"); + boolean terminated = output.endsWith(System.lineSeparator()); + if (terminated) { + System.out.print(output); + } else { + System.out.println(output); + } + System.out.println("------ End of accumulated output" + (terminated ? "" : " (no trailing newline)")); + } + } + + private void fail(String message) throws Failure { + out.println("FAILURE: " + message); + throw new Failure(message); + } + + protected boolean execute(String query) throws SQLException { + out.println("EXEC " + query); + boolean result; + result = stmt.execute(query); + if (result) { + out.println(" OK"); + } else { + out.println(" OK, updated " + stmt.getUpdateCount() + " rows"); + } + return result; + } + + protected void update(String query, int expectedUpdateCount) throws SQLException, Failure { + execute(query); + int updateCount = stmt.getUpdateCount(); + if (updateCount != expectedUpdateCount) { + fail("Query updated " + updateCount + "rows, expected " + expectedUpdateCount); + } + } + + protected void expectError(String query, String expectedError) throws SQLException, Failure { + try { + execute(query); + } catch (SQLException e) { + if (e.getMessage().contains(expectedError)) { + out.println(" GOT EXPECTED EXCEPTION: " + e.getMessage()); + } else { + throw e; + } + } + } + + protected void queryInt(String query, int expected) throws SQLException, Failure { + if (execute(query) == false) { + fail("Query does not return a result set"); + } + ResultSet rs = stmt.getResultSet(); + ResultSetMetaData metaData = rs.getMetaData(); + if (metaData.getColumnCount() != 1) { + fail("Result should have exactly one column"); + } + if (!rs.next()) { + fail("Result set is empty"); + } + int result = rs.getInt(1); + if (rs.next()) { + String message = "Result set has more than one row"; + fail(message); + } + rs.close(); + if (result != expected) + fail("Query returned " + result + ", expected " + expected); + } + + protected void prepare() throws SQLException { + execute("DROP TABLE IF EXISTS foo"); + execute("CREATE TABLE foo (i INT, t TEXT)"); + } + + static class MyUploadHandler implements MonetUploadHandler { + + private final int rows; + private final int errorAt; + private final String errorMessage; + MyUploadHandler(int rows, int errorAt, String errorMessage) { + this.rows = rows; + this.errorAt = errorAt; + this.errorMessage = errorMessage; + } + + MyUploadHandler(int rows) { + this(rows, -1, null); + } + + MyUploadHandler(String errorMessage) { + this(0, -1, errorMessage); + } + + + @Override + public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { + int toSkip = offset > 0 ? offset - 1 : 0; + if (errorAt == -1 && errorMessage != null) { + handle.sendError(errorMessage); + return; + } + PrintStream stream = handle.getStream(); + for (int i = toSkip; i < rows; i++) { + if (i == errorAt) { + throw new IOException(errorMessage); + } + stream.printf("%d|%d%n", i + 1, i + 1); + } + } + + } + static class Failure extends Exception { + + public Failure(String message) { + super(message); + } + public Failure(String message, Throwable cause) { + super(message, cause); + } + + } + + private void test_Upload() throws Exception { + prepare(); + conn.setUploadHandler(new MyUploadHandler(100)); + update("COPY INTO foo FROM 'banana' ON CLIENT", 100); + queryInt("SELECT COUNT(*) FROM foo", 100); + } + + private void test_ImmediateError() throws Exception { + prepare(); + conn.setUploadHandler(new MyUploadHandler("immediate error")); + expectError("COPY INTO foo FROM 'banana' ON CLIENT", "immediate error"); + queryInt("SELECT COUNT(*) FROM foo", 0); + } + + private void test_Offset0() throws SQLException, Failure { + prepare(); + conn.setUploadHandler(new MyUploadHandler(100)); + update("COPY OFFSET 0 INTO foo FROM 'banana' ON CLIENT", 100); + queryInt("SELECT MIN(i) FROM foo", 1); + queryInt("SELECT MAX(i) FROM foo", 100); + } + + private void test_Offset1() throws SQLException, Failure { + prepare(); + conn.setUploadHandler(new MyUploadHandler(100)); + update("COPY OFFSET 1 INTO foo FROM 'banana' ON CLIENT", 100); + queryInt("SELECT MIN(i) FROM foo", 1); + queryInt("SELECT MAX(i) FROM foo", 100); + } + + private void test_Offset5() throws SQLException, Failure { + prepare(); + conn.setUploadHandler(new MyUploadHandler(100)); + update("COPY OFFSET 5 INTO foo FROM 'banana' ON CLIENT", 96); + queryInt("SELECT MIN(i) FROM foo", 5); + queryInt("SELECT MAX(i) FROM foo", 100); + } + + private void test_ServerCancels() throws SQLException, Failure { + prepare(); + conn.setUploadHandler(new MyUploadHandler(100)); + update("COPY 10 RECORDS INTO foo FROM 'banana' ON CLIENT", 96); + queryInt("SELECT MIN(i) FROM foo", 5); + queryInt("SELECT MAX(i) FROM foo", 100); + } + + +} \ No newline at end of file
--- a/tests/build.xml +++ b/tests/build.xml @@ -72,6 +72,7 @@ Copyright 1997 - July 2008 CWI, August 2 <jar jarfile="${jdbctests-jar}"> <fileset dir="${builddir}"> <include name="JDBC_API_Tester.class" /> + <include name="OnClientTester.class" /> </fileset> </jar> </target> @@ -122,4 +123,10 @@ Copyright 1997 - July 2008 CWI, August 2 </antcall> </target> + <target name="OnClientTester"> + <antcall target="test_class"> + <param name="test.class" value="OnClientTester" /> + </antcall> + </target> + </project>