Mercurial > hg > monetdb-java
changeset 520:b4c7816e3592 onclient
Add more tests
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Thu, 26 Aug 2021 11:19:01 +0200 (2021-08-26) |
parents | 04a72c5bde80 |
children | 72007c4f8f8a |
files | tests/OnClientTester.java |
diffstat | 1 files changed, 130 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/tests/OnClientTester.java +++ b/tests/OnClientTester.java @@ -1,18 +1,18 @@ import org.monetdb.jdbc.MonetConnection; +import org.monetdb.jdbc.MonetDownloadHandler; import org.monetdb.jdbc.MonetUploadHandler; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.StringWriter; +import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.sql.*; public final class OnClientTester { private String jdbcUrl; boolean verbose = false; - boolean succeeded = true; + int testCount = 0; + int failureCount = 0; private MonetConnection conn; private PrintWriter out; private Statement stmt; @@ -33,16 +33,13 @@ public final class OnClientTester { } OnClientTester tester = new OnClientTester(jdbcUrl); - boolean succeeded; if (specificTest != null) - succeeded = tester.runTest(specificTest); + tester.runTest(specificTest); else - succeeded = tester.runTests(); + tester.runTests(); - if (tester.verbosity >= VERBOSITY_ON || tester.failureCount > 0) { - System.out.println(); - System.out.println("Ran " + tester.testCount + " tests, " + tester.failureCount + " failed"); - } + System.out.println(); + System.out.println("Ran " + tester.testCount + " tests, " + tester.failureCount + " failed"); if (tester.failureCount > 0) { System.exit(1); } @@ -52,7 +49,7 @@ public final class OnClientTester { this.jdbcUrl = jdbcUrl; } - private boolean runTests() throws SQLException, NoSuchMethodException { + private void runTests() throws SQLException, NoSuchMethodException { for (Method method: this.getClass().getDeclaredMethods()) { String methodName = method.getName(); if (methodName.startsWith("test_") && method.getParameterCount() == 0) { @@ -60,18 +57,15 @@ public final class OnClientTester { runTest(testName, method); } } - - return succeeded; } - private boolean runTest(String testName) throws SQLException, NoSuchMethodException { + private void runTest(String testName) throws SQLException, NoSuchMethodException { String methodName = "test_" + testName; Method method = this.getClass().getDeclaredMethod(methodName); - - return runTest(testName, method); + runTest(testName, method); } - private synchronized boolean runTest(String testName, Method method) throws SQLException { + private synchronized void runTest(String testName, Method method) throws SQLException { outBuffer = new StringWriter(); out = new PrintWriter(outBuffer); @@ -81,6 +75,7 @@ public final class OnClientTester { System.out.println(); + boolean failed = false; try { try { method.invoke(this); @@ -97,17 +92,16 @@ public final class OnClientTester { System.out.println("Test " + testName + " succeeded"); if (verbose) - dumpOutput(); + dumpOutput(testName); } catch (Failure e) { - succeeded = false; + failed = true; System.out.println("Test " + testName + " failed"); - dumpOutput(); + dumpOutput(testName); } catch (Exception e) { - succeeded = false; + failed = true; System.out.println("Test " + testName + " failed:"); e.printStackTrace(); - System.out.println(); - dumpOutput(); + dumpOutput(testName); // Show the inner bits of the exception again, they may have scrolled off screen Throwable t = e; while (t.getCause() != null) { @@ -119,19 +113,20 @@ public final class OnClientTester { System.out.println(" at " + t.getStackTrace()[0]); } } finally { + testCount++; + if (failed) + failureCount++; stmt.close(); conn.close(); } - - return succeeded; } - private void dumpOutput() { + private void dumpOutput(String testName) { String output = outBuffer.getBuffer().toString(); if (output.isEmpty()) { System.out.println("(Test did not produce any output)"); } else { - System.out.println("------ Accumulated output:"); + System.out.println("------ Accumulated output for " + testName + ":"); boolean terminated = output.endsWith(System.lineSeparator()); if (terminated) { System.out.print(output); @@ -147,6 +142,12 @@ public final class OnClientTester { throw new Failure(message); } + private void assertEq(String quantity, Object expected, Object actual) throws Failure { + if (expected.equals(actual)) + return; + fail("Expected '" + quantity + "' to be " + expected + ", got " + actual); + } + protected boolean execute(String query) throws SQLException { out.println("EXEC " + query); boolean result; @@ -162,9 +163,7 @@ public final class OnClientTester { 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); - } + assertEq("Update count", expectedUpdateCount, updateCount); } protected void expectError(String query, String expectedError) throws SQLException, Failure { @@ -185,9 +184,7 @@ public final class OnClientTester { } ResultSet rs = stmt.getResultSet(); ResultSetMetaData metaData = rs.getMetaData(); - if (metaData.getColumnCount() != 1) { - fail("Result should have exactly one column"); - } + assertEq("column count", 1, metaData.getColumnCount()); if (!rs.next()) { fail("Result set is empty"); } @@ -197,8 +194,7 @@ public final class OnClientTester { fail(message); } rs.close(); - if (result != expected) - fail("Query returned " + result + ", expected " + expected); + assertEq("query result", expected, result); } protected void prepare() throws SQLException { @@ -225,7 +221,6 @@ public final class OnClientTester { 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; @@ -243,6 +238,79 @@ public final class OnClientTester { } } + + static class MyDownloadHandler implements MonetDownloadHandler { + private final int errorAtByte; + private final String errorMessage; + private int attempts = 0; + private int bytesSeen = 0; + private int lineEndingsSeen = 0; + private int startOfLine = 0; + + MyDownloadHandler(int errorAtByte, String errorMessage) { + this.errorAtByte = errorAtByte; + this.errorMessage = errorMessage; + } + + MyDownloadHandler(String errorMessage) { + this(-1, errorMessage); + } + + MyDownloadHandler() { + this(-1, null); + } + + @Override + public void handleDownload(MonetConnection.Download handle, String name, boolean textMode) throws IOException { + attempts++; + bytesSeen = 0; + lineEndingsSeen = 0; + startOfLine = 0; + + if (errorMessage != null && errorAtByte < 0) { + handle.sendError(errorMessage); + return; + } + + InputStream stream = handle.getStream(); + byte[] buffer = new byte[1024]; + while (true) { + int toRead = buffer.length; + if (errorMessage != null && errorAtByte >= 0) { + if (bytesSeen == errorAtByte) { + throw new IOException(errorMessage); + } + toRead = Integer.min(toRead, errorAtByte - bytesSeen); + } + int nread = stream.read(buffer, 0, toRead); + if (nread < 0) + break; + for (int i = 0; i < nread; i++) { + if (buffer[i] == '\n') { + lineEndingsSeen += 1; + startOfLine = bytesSeen + i + 1; + } + } + bytesSeen += nread; + } + } + + public int countAttempts() { + return attempts; + } + public int countBytes() { + return bytesSeen; + } + + public int lineCount() { + int lines = lineEndingsSeen; + if (startOfLine != bytesSeen) + lines++; + return lines; + } + } + + static class Failure extends Exception { public Failure(String message) { @@ -261,7 +329,7 @@ public final class OnClientTester { queryInt("SELECT COUNT(*) FROM foo", 100); } - private void test_ImmediateError() throws Exception { + private void test_ClientRefuses() throws Exception { prepare(); conn.setUploadHandler(new MyUploadHandler("immediate error")); expectError("COPY INTO foo FROM 'banana' ON CLIENT", "immediate error"); @@ -292,12 +360,32 @@ public final class OnClientTester { queryInt("SELECT MAX(i) FROM foo", 100); } - private void test_ServerCancels() throws SQLException, Failure { + private void testx_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); + // Server stopped reading after 10 rows. Will we stay in sync? + queryInt("SELECT COUNT(i) FROM foo", 10); + } + + private void test_Download() throws SQLException, Failure { + prepare(); + MyDownloadHandler handler = new MyDownloadHandler(); + conn.setDownloadHandler(handler); + update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); + update("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", -1); + assertEq("download attempts", 1, handler.countAttempts()); + assertEq("lines downloaded", 100, handler.lineCount()); + } + + private void test_CancelledDownload() throws SQLException, Failure { + prepare(); + MyDownloadHandler handler = new MyDownloadHandler("download refused"); + conn.setDownloadHandler(handler); + update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); + expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); + // check if the connection still works + queryInt("SELECT 42", 42); }