comparison tests/OnClientTester.java @ 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
children b4c7816e3592
comparison
equal deleted inserted replaced
518:e84b3cbd8b57 519:04a72c5bde80
1 import org.monetdb.jdbc.MonetConnection;
2 import org.monetdb.jdbc.MonetUploadHandler;
3
4 import java.io.IOException;
5 import java.io.PrintStream;
6 import java.io.PrintWriter;
7 import java.io.StringWriter;
8 import java.lang.reflect.InvocationTargetException;
9 import java.lang.reflect.Method;
10 import java.sql.*;
11
12 public final class OnClientTester {
13 private String jdbcUrl;
14 boolean verbose = false;
15 boolean succeeded = true;
16 private MonetConnection conn;
17 private PrintWriter out;
18 private Statement stmt;
19 private StringWriter outBuffer;
20
21 public static void main(String[] args) throws SQLException, NoSuchMethodException {
22 String jdbcUrl;
23 String specificTest = null;
24 switch (args.length) {
25 case 2:
26 specificTest = args[1];
27 /* fallthrough */
28 case 1:
29 jdbcUrl = args[0];
30 break;
31 default:
32 throw new IllegalArgumentException("Usage: OnClientTester JDBC_URL [TESTNAME]");
33 }
34
35 OnClientTester tester = new OnClientTester(jdbcUrl);
36 boolean succeeded;
37 if (specificTest != null)
38 succeeded = tester.runTest(specificTest);
39 else
40 succeeded = tester.runTests();
41
42 if (tester.verbosity >= VERBOSITY_ON || tester.failureCount > 0) {
43 System.out.println();
44 System.out.println("Ran " + tester.testCount + " tests, " + tester.failureCount + " failed");
45 }
46 if (tester.failureCount > 0) {
47 System.exit(1);
48 }
49 }
50
51 public OnClientTester(String jdbcUrl) {
52 this.jdbcUrl = jdbcUrl;
53 }
54
55 private boolean runTests() throws SQLException, NoSuchMethodException {
56 for (Method method: this.getClass().getDeclaredMethods()) {
57 String methodName = method.getName();
58 if (methodName.startsWith("test_") && method.getParameterCount() == 0) {
59 String testName = methodName.substring(5);
60 runTest(testName, method);
61 }
62 }
63
64 return succeeded;
65 }
66
67 private boolean runTest(String testName) throws SQLException, NoSuchMethodException {
68 String methodName = "test_" + testName;
69 Method method = this.getClass().getDeclaredMethod(methodName);
70
71 return runTest(testName, method);
72 }
73
74 private synchronized boolean runTest(String testName, Method method) throws SQLException {
75 outBuffer = new StringWriter();
76 out = new PrintWriter(outBuffer);
77
78 Connection genericConnection = DriverManager.getConnection(jdbcUrl);
79 conn = genericConnection.unwrap(MonetConnection.class);
80 stmt = conn.createStatement();
81
82 System.out.println();
83
84 try {
85 try {
86 method.invoke(this);
87 } catch (InvocationTargetException e) {
88 Throwable cause = e.getCause();
89 if (cause instanceof Failure)
90 throw (Failure)cause;
91 else if (cause instanceof Exception) {
92 throw (Exception)cause;
93 } else {
94 throw e;
95 }
96 }
97
98 System.out.println("Test " + testName + " succeeded");
99 if (verbose)
100 dumpOutput();
101 } catch (Failure e) {
102 succeeded = false;
103 System.out.println("Test " + testName + " failed");
104 dumpOutput();
105 } catch (Exception e) {
106 succeeded = false;
107 System.out.println("Test " + testName + " failed:");
108 e.printStackTrace();
109 System.out.println();
110 dumpOutput();
111 // Show the inner bits of the exception again, they may have scrolled off screen
112 Throwable t = e;
113 while (t.getCause() != null) {
114 t = t.getCause();
115 }
116 System.out.println();
117 System.out.println("Innermost cause was " + t);
118 if (t.getStackTrace().length > 0) {
119 System.out.println(" at " + t.getStackTrace()[0]);
120 }
121 } finally {
122 stmt.close();
123 conn.close();
124 }
125
126 return succeeded;
127 }
128
129 private void dumpOutput() {
130 String output = outBuffer.getBuffer().toString();
131 if (output.isEmpty()) {
132 System.out.println("(Test did not produce any output)");
133 } else {
134 System.out.println("------ Accumulated output:");
135 boolean terminated = output.endsWith(System.lineSeparator());
136 if (terminated) {
137 System.out.print(output);
138 } else {
139 System.out.println(output);
140 }
141 System.out.println("------ End of accumulated output" + (terminated ? "" : " (no trailing newline)"));
142 }
143 }
144
145 private void fail(String message) throws Failure {
146 out.println("FAILURE: " + message);
147 throw new Failure(message);
148 }
149
150 protected boolean execute(String query) throws SQLException {
151 out.println("EXEC " + query);
152 boolean result;
153 result = stmt.execute(query);
154 if (result) {
155 out.println(" OK");
156 } else {
157 out.println(" OK, updated " + stmt.getUpdateCount() + " rows");
158 }
159 return result;
160 }
161
162 protected void update(String query, int expectedUpdateCount) throws SQLException, Failure {
163 execute(query);
164 int updateCount = stmt.getUpdateCount();
165 if (updateCount != expectedUpdateCount) {
166 fail("Query updated " + updateCount + "rows, expected " + expectedUpdateCount);
167 }
168 }
169
170 protected void expectError(String query, String expectedError) throws SQLException, Failure {
171 try {
172 execute(query);
173 } catch (SQLException e) {
174 if (e.getMessage().contains(expectedError)) {
175 out.println(" GOT EXPECTED EXCEPTION: " + e.getMessage());
176 } else {
177 throw e;
178 }
179 }
180 }
181
182 protected void queryInt(String query, int expected) throws SQLException, Failure {
183 if (execute(query) == false) {
184 fail("Query does not return a result set");
185 }
186 ResultSet rs = stmt.getResultSet();
187 ResultSetMetaData metaData = rs.getMetaData();
188 if (metaData.getColumnCount() != 1) {
189 fail("Result should have exactly one column");
190 }
191 if (!rs.next()) {
192 fail("Result set is empty");
193 }
194 int result = rs.getInt(1);
195 if (rs.next()) {
196 String message = "Result set has more than one row";
197 fail(message);
198 }
199 rs.close();
200 if (result != expected)
201 fail("Query returned " + result + ", expected " + expected);
202 }
203
204 protected void prepare() throws SQLException {
205 execute("DROP TABLE IF EXISTS foo");
206 execute("CREATE TABLE foo (i INT, t TEXT)");
207 }
208
209 static class MyUploadHandler implements MonetUploadHandler {
210
211 private final int rows;
212 private final int errorAt;
213 private final String errorMessage;
214 MyUploadHandler(int rows, int errorAt, String errorMessage) {
215 this.rows = rows;
216 this.errorAt = errorAt;
217 this.errorMessage = errorMessage;
218 }
219
220 MyUploadHandler(int rows) {
221 this(rows, -1, null);
222 }
223
224 MyUploadHandler(String errorMessage) {
225 this(0, -1, errorMessage);
226 }
227
228
229 @Override
230 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException {
231 int toSkip = offset > 0 ? offset - 1 : 0;
232 if (errorAt == -1 && errorMessage != null) {
233 handle.sendError(errorMessage);
234 return;
235 }
236 PrintStream stream = handle.getStream();
237 for (int i = toSkip; i < rows; i++) {
238 if (i == errorAt) {
239 throw new IOException(errorMessage);
240 }
241 stream.printf("%d|%d%n", i + 1, i + 1);
242 }
243 }
244
245 }
246 static class Failure extends Exception {
247
248 public Failure(String message) {
249 super(message);
250 }
251 public Failure(String message, Throwable cause) {
252 super(message, cause);
253 }
254
255 }
256
257 private void test_Upload() throws Exception {
258 prepare();
259 conn.setUploadHandler(new MyUploadHandler(100));
260 update("COPY INTO foo FROM 'banana' ON CLIENT", 100);
261 queryInt("SELECT COUNT(*) FROM foo", 100);
262 }
263
264 private void test_ImmediateError() throws Exception {
265 prepare();
266 conn.setUploadHandler(new MyUploadHandler("immediate error"));
267 expectError("COPY INTO foo FROM 'banana' ON CLIENT", "immediate error");
268 queryInt("SELECT COUNT(*) FROM foo", 0);
269 }
270
271 private void test_Offset0() throws SQLException, Failure {
272 prepare();
273 conn.setUploadHandler(new MyUploadHandler(100));
274 update("COPY OFFSET 0 INTO foo FROM 'banana' ON CLIENT", 100);
275 queryInt("SELECT MIN(i) FROM foo", 1);
276 queryInt("SELECT MAX(i) FROM foo", 100);
277 }
278
279 private void test_Offset1() throws SQLException, Failure {
280 prepare();
281 conn.setUploadHandler(new MyUploadHandler(100));
282 update("COPY OFFSET 1 INTO foo FROM 'banana' ON CLIENT", 100);
283 queryInt("SELECT MIN(i) FROM foo", 1);
284 queryInt("SELECT MAX(i) FROM foo", 100);
285 }
286
287 private void test_Offset5() throws SQLException, Failure {
288 prepare();
289 conn.setUploadHandler(new MyUploadHandler(100));
290 update("COPY OFFSET 5 INTO foo FROM 'banana' ON CLIENT", 96);
291 queryInt("SELECT MIN(i) FROM foo", 5);
292 queryInt("SELECT MAX(i) FROM foo", 100);
293 }
294
295 private void test_ServerCancels() throws SQLException, Failure {
296 prepare();
297 conn.setUploadHandler(new MyUploadHandler(100));
298 update("COPY 10 RECORDS INTO foo FROM 'banana' ON CLIENT", 96);
299 queryInt("SELECT MIN(i) FROM foo", 5);
300 queryInt("SELECT MAX(i) FROM foo", 100);
301 }
302
303
304 }