Mercurial > hg > monetdb-java
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 } |