Mercurial > hg > monetdb-java
comparison tests/OnClientTester.java @ 531:53dc4349ace9 onclient
Extract OnClientTester infrastructure into separate class
So OnClientTester itself only contains tests.
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Fri, 27 Aug 2021 11:40:24 +0200 (2021-08-27) |
parents | bf47aab3aeb7 |
children | b75464874130 |
comparison
equal
deleted
inserted
replaced
530:bf47aab3aeb7 | 531:53dc4349ace9 |
---|---|
1 import org.monetdb.jdbc.MonetConnection; | 1 import org.monetdb.jdbc.MonetConnection; |
2 import org.monetdb.jdbc.MonetDownloadHandler; | 2 import org.monetdb.jdbc.MonetDownloadHandler; |
3 import org.monetdb.jdbc.MonetUploadHandler; | 3 import org.monetdb.jdbc.MonetUploadHandler; |
4 | 4 |
5 import java.io.*; | 5 import java.io.*; |
6 import java.lang.reflect.InvocationTargetException; | |
7 import java.lang.reflect.Method; | |
8 import java.nio.charset.StandardCharsets; | 6 import java.nio.charset.StandardCharsets; |
9 import java.sql.*; | 7 import java.sql.SQLException; |
10 | 8 |
11 public final class OnClientTester { | 9 public final class OnClientTester extends TestRunner { |
12 public static final int VERBOSITY_NONE = 0; | 10 |
13 public static final int VERBOSITY_ON = 1; | 11 public OnClientTester(String jdbcUrl, int verbosity, boolean watchDogEnabled) { |
14 public static final int VERBOSITY_SHOW_ALL = 2; | 12 super(jdbcUrl, verbosity, watchDogEnabled); |
15 private String jdbcUrl; | 13 } |
16 int verbosity = VERBOSITY_NONE; | |
17 int testCount = 0; | |
18 int failureCount = 0; | |
19 private MonetConnection conn; | |
20 private PrintWriter out; | |
21 private Statement stmt; | |
22 private StringWriter outBuffer; | |
23 private final WatchDog watchDog; | |
24 | 14 |
25 public static void main(String[] args) throws SQLException, NoSuchMethodException { | 15 public static void main(String[] args) throws SQLException, NoSuchMethodException { |
26 String jdbcUrl = null; | 16 String jdbcUrl = null; |
27 String requiredPrefix = null; | 17 String requiredPrefix = null; |
28 int verbosity = 0; | 18 int verbosity = 0; |
44 System.exit(2); | 34 System.exit(2); |
45 } | 35 } |
46 } | 36 } |
47 | 37 |
48 OnClientTester tester = new OnClientTester(jdbcUrl, verbosity, watchDogEnabled); | 38 OnClientTester tester = new OnClientTester(jdbcUrl, verbosity, watchDogEnabled); |
49 tester.runTests(requiredPrefix); | 39 int failures = tester.runTests(requiredPrefix); |
50 | 40 |
51 if (tester.verbosity >= VERBOSITY_ON || tester.failureCount > 0) { | 41 if (failures > 0) |
52 System.out.println(); | |
53 System.out.println("Ran " + tester.testCount + " tests, " + tester.failureCount + " failed"); | |
54 } | |
55 if (tester.failureCount > 0) { | |
56 System.exit(1); | 42 System.exit(1); |
57 } | |
58 } | |
59 | |
60 public OnClientTester(String jdbcUrl, int verbosity, boolean watchDogEnabled) { | |
61 this.jdbcUrl = jdbcUrl; | |
62 this.verbosity = verbosity; | |
63 watchDog = new WatchDog(); | |
64 if (watchDogEnabled) | |
65 watchDog.enable(); | |
66 else | |
67 watchDog.disable(); | |
68 } | |
69 | |
70 private void runTests(String testPrefix) throws SQLException, NoSuchMethodException { | |
71 watchDog.stop(); | |
72 try { | |
73 String initialPrefix = "test_"; | |
74 String methodPrefix = testPrefix == null ? initialPrefix : initialPrefix + testPrefix; | |
75 | |
76 for (Method method : this.getClass().getDeclaredMethods()) { | |
77 String methodName = method.getName(); | |
78 if (methodName.startsWith(methodPrefix) && method.getParameterCount() == 0) { | |
79 String testName = methodName.substring(initialPrefix.length()); | |
80 runTest(testName, method); | |
81 } | |
82 } | |
83 } finally { | |
84 watchDog.stop(); | |
85 } | |
86 } | |
87 | |
88 private synchronized void runTest(String testName, Method method) throws SQLException { | |
89 watchDog.setContext("test " + testName); | |
90 watchDog.setDuration(3_000); | |
91 outBuffer = new StringWriter(); | |
92 out = new PrintWriter(outBuffer); | |
93 | |
94 Connection genericConnection = DriverManager.getConnection(jdbcUrl); | |
95 conn = genericConnection.unwrap(MonetConnection.class); | |
96 stmt = conn.createStatement(); | |
97 | |
98 boolean failed = false; | |
99 try { | |
100 long duration; | |
101 try { | |
102 long t0 = System.currentTimeMillis(); | |
103 method.invoke(this); | |
104 long t1 = System.currentTimeMillis(); | |
105 duration = t1 - t0; | |
106 } catch (InvocationTargetException e) { | |
107 Throwable cause = e.getCause(); | |
108 if (cause instanceof Failure) | |
109 throw (Failure)cause; | |
110 else if (cause instanceof Exception) { | |
111 throw (Exception)cause; | |
112 } else { | |
113 throw e; | |
114 } | |
115 } | |
116 | |
117 if (verbosity > VERBOSITY_ON) | |
118 System.out.println(); | |
119 if (verbosity >= VERBOSITY_ON) | |
120 System.out.println("Test " + testName + " succeeded in " + duration + "ms"); | |
121 if (verbosity >= VERBOSITY_SHOW_ALL) | |
122 dumpOutput(testName); | |
123 } catch (Failure e) { | |
124 failed = true; | |
125 System.out.println(); | |
126 System.out.println("Test " + testName + " failed"); | |
127 dumpOutput(testName); | |
128 } catch (Exception e) { | |
129 failed = true; | |
130 System.out.println(); | |
131 System.out.println("Test " + testName + " failed:"); | |
132 e.printStackTrace(System.out); | |
133 dumpOutput(testName); | |
134 // Show the inner bits of the exception again, they may have scrolled off screen | |
135 Throwable t = e; | |
136 while (t.getCause() != null) { | |
137 t = t.getCause(); | |
138 } | |
139 System.out.println("Innermost cause was " + t); | |
140 if (t.getStackTrace().length > 0) { | |
141 System.out.println(" at " + t.getStackTrace()[0]); | |
142 } | |
143 } finally { | |
144 watchDog.setContext(null); | |
145 testCount++; | |
146 if (failed) | |
147 failureCount++; | |
148 if (failed && verbosity == VERBOSITY_ON) { | |
149 // next test case will not print separator | |
150 System.out.println(); | |
151 } | |
152 stmt.close(); | |
153 conn.close(); | |
154 } | |
155 } | |
156 | |
157 private void dumpOutput(String testName) { | |
158 String output = outBuffer.getBuffer().toString(); | |
159 if (output.isEmpty()) { | |
160 System.out.println("(Test did not produce any output)"); | |
161 } else { | |
162 System.out.println("------ Accumulated output for test " + testName + ":"); | |
163 boolean terminated = output.endsWith(System.lineSeparator()); | |
164 if (terminated) { | |
165 System.out.print(output); | |
166 } else { | |
167 System.out.println(output); | |
168 } | |
169 System.out.println("------ End of accumulated output" + (terminated ? "" : " (no trailing newline)")); | |
170 } | |
171 } | |
172 | |
173 private void fail(String message) throws Failure { | |
174 out.println("FAILURE: " + message); | |
175 throw new Failure(message); | |
176 } | |
177 | |
178 private void checked(String quantity, Object actual) { | |
179 out.println(" CHECKED: " + "<" + quantity + "> is " + actual + " as expected"); | |
180 } | |
181 | |
182 private void assertEq(String quantity, Object expected, Object actual) throws Failure { | |
183 if (expected.equals(actual)) { | |
184 checked(quantity, actual); | |
185 } else { | |
186 fail("Expected <" + quantity + "' to be " + expected + "> got " + actual); | |
187 } | |
188 } | |
189 | |
190 protected boolean execute(String query) throws SQLException { | |
191 try { | |
192 watchDog.start(); | |
193 out.println("EXECUTE: " + query); | |
194 boolean result; | |
195 result = stmt.execute(query); | |
196 if (result) { | |
197 out.println(" OK"); | |
198 } else { | |
199 out.println(" OK, updated " + stmt.getUpdateCount() + " rows"); | |
200 } | |
201 return result; | |
202 } finally { | |
203 watchDog.stop(); | |
204 } | |
205 } | |
206 | |
207 protected void update(String query, int expectedUpdateCount) throws SQLException, Failure { | |
208 execute(query); | |
209 int updateCount = stmt.getUpdateCount(); | |
210 assertEq("Update count", expectedUpdateCount, updateCount); | |
211 } | |
212 | |
213 protected void expectError(String query, String expectedError) throws SQLException, Failure { | |
214 try { | |
215 execute(query); | |
216 } catch (SQLException e) { | |
217 if (e.getMessage().contains(expectedError)) { | |
218 out.println(" GOT EXPECTED EXCEPTION: " + e.getMessage()); | |
219 } else { | |
220 throw e; | |
221 } | |
222 } | |
223 } | |
224 | |
225 protected void queryInt(String query, int expected) throws SQLException, Failure { | |
226 if (execute(query) == false) { | |
227 fail("Query does not return a result set"); | |
228 } | |
229 ResultSet rs = stmt.getResultSet(); | |
230 ResultSetMetaData metaData = rs.getMetaData(); | |
231 assertEq("column count", 1, metaData.getColumnCount()); | |
232 if (!rs.next()) { | |
233 fail("Result set is empty"); | |
234 } | |
235 int result = rs.getInt(1); | |
236 if (rs.next()) { | |
237 String message = "Result set has more than one row"; | |
238 fail(message); | |
239 } | |
240 rs.close(); | |
241 checked("row count", 1); | |
242 assertEq("query result", expected, result); | |
243 } | 43 } |
244 | 44 |
245 protected void prepare() throws SQLException { | 45 protected void prepare() throws SQLException { |
246 execute("DROP TABLE IF EXISTS foo"); | 46 execute("DROP TABLE IF EXISTS foo"); |
247 execute("CREATE TABLE foo (i INT, t TEXT)"); | 47 execute("CREATE TABLE foo (i INT, t TEXT)"); |
48 } | |
49 | |
50 public void test_Upload() throws Exception { | |
51 prepare(); | |
52 conn.setUploadHandler(new MyUploadHandler(100)); | |
53 update("COPY INTO foo FROM 'banana' ON CLIENT", 100); | |
54 queryInt("SELECT COUNT(*) FROM foo", 100); | |
55 } | |
56 | |
57 public void test_ClientRefusesUpload() throws Exception { | |
58 prepare(); | |
59 conn.setUploadHandler(new MyUploadHandler("immediate error")); | |
60 expectError("COPY INTO foo FROM 'banana' ON CLIENT", "immediate error"); | |
61 queryInt("SELECT COUNT(*) FROM foo", 0); | |
62 } | |
63 | |
64 public void test_Offset0() throws SQLException, Failure { | |
65 prepare(); | |
66 conn.setUploadHandler(new MyUploadHandler(100)); | |
67 update("COPY OFFSET 0 INTO foo FROM 'banana' ON CLIENT", 100); | |
68 queryInt("SELECT MIN(i) FROM foo", 1); | |
69 queryInt("SELECT MAX(i) FROM foo", 100); | |
70 } | |
71 | |
72 public void test_Offset1() throws SQLException, Failure { | |
73 prepare(); | |
74 conn.setUploadHandler(new MyUploadHandler(100)); | |
75 update("COPY OFFSET 1 INTO foo FROM 'banana' ON CLIENT", 100); | |
76 queryInt("SELECT MIN(i) FROM foo", 1); | |
77 queryInt("SELECT MAX(i) FROM foo", 100); | |
78 } | |
79 | |
80 public void test_Offset5() throws SQLException, Failure { | |
81 prepare(); | |
82 conn.setUploadHandler(new MyUploadHandler(100)); | |
83 update("COPY OFFSET 5 INTO foo FROM 'banana' ON CLIENT", 96); | |
84 queryInt("SELECT MIN(i) FROM foo", 5); | |
85 queryInt("SELECT MAX(i) FROM foo", 100); | |
86 } | |
87 | |
88 public void test_ServerStopsReading() throws SQLException, Failure { | |
89 prepare(); | |
90 conn.setUploadHandler(new MyUploadHandler(100)); | |
91 update("COPY 10 RECORDS INTO foo FROM 'banana' ON CLIENT", 96); | |
92 // Server stopped reading after 10 rows. Will we stay in sync? | |
93 queryInt("SELECT COUNT(i) FROM foo", 10); | |
94 } | |
95 | |
96 public void test_Download(int n) throws SQLException, Failure { | |
97 prepare(); | |
98 MyDownloadHandler handler = new MyDownloadHandler(); | |
99 conn.setDownloadHandler(handler); | |
100 String q = "INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, " + n + ")"; | |
101 update(q, n); | |
102 update("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", -1); | |
103 assertEq("download attempts", 1, handler.countAttempts()); | |
104 assertEq("lines downloaded", n, handler.lineCount()); | |
105 } | |
106 | |
107 public void test_Download() throws SQLException, Failure { | |
108 test_Download(100); | |
109 } | |
110 | |
111 public void test_ClientRefusesDownload() throws SQLException, Failure { | |
112 prepare(); | |
113 MyDownloadHandler handler = new MyDownloadHandler("download refused"); | |
114 conn.setDownloadHandler(handler); | |
115 update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); | |
116 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); | |
117 queryInt("SELECT 42 -- check if the connection still works", 42); | |
118 } | |
119 | |
120 public void test_LargeUpload() throws SQLException, Failure { | |
121 watchDog.setDuration(25_000); | |
122 prepare(); | |
123 int n = 4_000_000; | |
124 MyUploadHandler handler = new MyUploadHandler(n); | |
125 conn.setUploadHandler(handler); | |
126 handler.setChunkSize(1024 * 1024); | |
127 update("COPY INTO foo FROM 'banana' ON CLIENT", n); | |
128 queryInt("SELECT COUNT(DISTINCT i) FROM foo", n); | |
129 } | |
130 | |
131 public void test_LargeDownload() throws SQLException, Failure { | |
132 watchDog.setDuration(25_000); | |
133 test_Download(4_000_000); | |
134 } | |
135 | |
136 public void test_UploadFromStream() throws SQLException, Failure { | |
137 prepare(); | |
138 MonetUploadHandler handler = new MonetUploadHandler() { | |
139 final String data = "1|one\n2|two\n3|three\n"; | |
140 | |
141 @Override | |
142 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
143 ByteArrayInputStream s = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); | |
144 handle.uploadFrom(s); | |
145 } | |
146 }; | |
147 conn.setUploadHandler(handler); | |
148 update("COPY INTO foo FROM 'banana' ON CLIENT", 3); | |
149 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
150 } | |
151 | |
152 public void test_UploadFromReader() throws SQLException, Failure { | |
153 prepare(); | |
154 MonetUploadHandler handler = new MonetUploadHandler() { | |
155 final String data = "1|one\n2|two\n3|three\n"; | |
156 | |
157 @Override | |
158 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
159 StringReader r = new StringReader(data); | |
160 handle.uploadFrom(r); | |
161 } | |
162 }; | |
163 conn.setUploadHandler(handler); | |
164 update("COPY INTO foo FROM 'banana' ON CLIENT", 3); | |
165 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
166 } | |
167 | |
168 public void test_UploadFromReaderOffset() throws SQLException, Failure { | |
169 prepare(); | |
170 MonetUploadHandler handler = new MonetUploadHandler() { | |
171 final String data = "1|one\n2|two\n3|three\n"; | |
172 | |
173 @Override | |
174 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
175 BufferedReader r = new BufferedReader(new StringReader(data)); | |
176 handle.uploadFrom(r, offset); | |
177 } | |
178 }; | |
179 conn.setUploadHandler(handler); | |
180 update("COPY OFFSET 2 INTO foo FROM 'banana' ON CLIENT", 2); | |
181 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
182 } | |
183 | |
184 public void test_FailUploadLate() throws SQLException, Failure { | |
185 prepare(); | |
186 conn.setUploadHandler(new MyUploadHandler(100, 50, "i don't like line 50")); | |
187 expectError("COPY INTO foo FROM 'banana' ON CLIENT", "i don't like"); | |
188 assertEq("connection is closed", true, conn.isClosed()); | |
189 } | |
190 | |
191 // Disabled because it hangs, triggering the watchdog timer | |
192 public void testx_FailDownloadLate() throws SQLException, Failure { | |
193 prepare(); | |
194 MyDownloadHandler handler = new MyDownloadHandler(200, "download refused"); | |
195 conn.setDownloadHandler(handler); | |
196 update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); | |
197 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); | |
198 queryInt("SELECT 42 -- check if the connection still works", 42); | |
248 } | 199 } |
249 | 200 |
250 static class MyUploadHandler implements MonetUploadHandler { | 201 static class MyUploadHandler implements MonetUploadHandler { |
251 private final int rows; | 202 private final int rows; |
252 private final int errorAt; | 203 private final int errorAt; |
348 } | 299 } |
349 | 300 |
350 public int countAttempts() { | 301 public int countAttempts() { |
351 return attempts; | 302 return attempts; |
352 } | 303 } |
304 | |
353 public int countBytes() { | 305 public int countBytes() { |
354 return bytesSeen; | 306 return bytesSeen; |
355 } | 307 } |
356 | 308 |
357 public int lineCount() { | 309 public int lineCount() { |
360 lines++; | 312 lines++; |
361 return lines; | 313 return lines; |
362 } | 314 } |
363 } | 315 } |
364 | 316 |
365 | |
366 static class Failure extends Exception { | |
367 | |
368 public Failure(String message) { | |
369 super(message); | |
370 } | |
371 public Failure(String message, Throwable cause) { | |
372 super(message, cause); | |
373 } | |
374 | |
375 } | |
376 | |
377 static class WatchDog { | |
378 private boolean enabled; | |
379 private long duration = 1000; | |
380 private long started = 0; | |
381 private String context = "no context"; | |
382 | |
383 WatchDog() { | |
384 Thread watchDog = new Thread(this::work); | |
385 watchDog.setName("watchdog_timer"); | |
386 watchDog.setDaemon(true); | |
387 watchDog.start(); | |
388 } | |
389 | |
390 synchronized void enable() { | |
391 this.enabled = true; | |
392 this.notifyAll(); | |
393 } | |
394 | |
395 synchronized void disable() { | |
396 this.enabled = false; | |
397 this.notifyAll(); | |
398 } | |
399 | |
400 synchronized void setContext(String context) { | |
401 this.context = context; | |
402 } | |
403 synchronized void setDuration(long duration) { | |
404 if (duration <= 0) | |
405 throw new IllegalArgumentException("duration should be > 0"); | |
406 this.duration = duration; | |
407 this.notifyAll(); | |
408 } | |
409 | |
410 synchronized void start() { | |
411 started = System.currentTimeMillis(); | |
412 this.notifyAll(); | |
413 } | |
414 | |
415 synchronized void stop() { | |
416 started = 0; | |
417 this.notifyAll(); | |
418 } | |
419 | |
420 synchronized void kill() { | |
421 started = -1; | |
422 this.notifyAll(); | |
423 } | |
424 | |
425 private synchronized void work() { | |
426 long now; | |
427 try { | |
428 while (true) { | |
429 now = System.currentTimeMillis(); | |
430 final long sleepTime; | |
431 if (started < 0) { | |
432 // client asked us to go away | |
433 // System.err.println("++ EXIT"); | |
434 return; | |
435 } else if (!enabled || started == 0) { | |
436 // wait for client to enable/start us | |
437 sleepTime = 600_000; | |
438 } else { | |
439 long deadline = started + duration; | |
440 sleepTime = deadline - now; | |
441 } | |
442 // System.err.printf("++ now=%d, started=now%+d, duration=%d, sleep=%d%n", | |
443 // now, started - now, duration, sleepTime | |
444 // ); | |
445 if (sleepTime > 0) { | |
446 this.wait(sleepTime); | |
447 } else { | |
448 trigger(); | |
449 return; | |
450 } | |
451 } | |
452 } catch (InterruptedException e) { | |
453 System.err.println("WATCHDOG TIMER INTERRUPTED, SHOULDN'T HAPPEN"); | |
454 System.exit(4); | |
455 } | |
456 } | |
457 | |
458 private void trigger() { | |
459 String c = context != null ? context : "no context"; | |
460 System.err.println(); | |
461 System.err.println(); | |
462 System.err.println("WATCHDOG TIMER EXPIRED [" + c + "], KILLING TESTS"); | |
463 System.exit(3); | |
464 } | |
465 } | |
466 | |
467 public void test_Upload() throws Exception { | |
468 prepare(); | |
469 conn.setUploadHandler(new MyUploadHandler(100)); | |
470 update("COPY INTO foo FROM 'banana' ON CLIENT", 100); | |
471 queryInt("SELECT COUNT(*) FROM foo", 100); | |
472 } | |
473 | |
474 public void test_ClientRefusesUpload() throws Exception { | |
475 prepare(); | |
476 conn.setUploadHandler(new MyUploadHandler("immediate error")); | |
477 expectError("COPY INTO foo FROM 'banana' ON CLIENT", "immediate error"); | |
478 queryInt("SELECT COUNT(*) FROM foo", 0); | |
479 } | |
480 | |
481 public void test_Offset0() throws SQLException, Failure { | |
482 prepare(); | |
483 conn.setUploadHandler(new MyUploadHandler(100)); | |
484 update("COPY OFFSET 0 INTO foo FROM 'banana' ON CLIENT", 100); | |
485 queryInt("SELECT MIN(i) FROM foo", 1); | |
486 queryInt("SELECT MAX(i) FROM foo", 100); | |
487 } | |
488 | |
489 public void test_Offset1() throws SQLException, Failure { | |
490 prepare(); | |
491 conn.setUploadHandler(new MyUploadHandler(100)); | |
492 update("COPY OFFSET 1 INTO foo FROM 'banana' ON CLIENT", 100); | |
493 queryInt("SELECT MIN(i) FROM foo", 1); | |
494 queryInt("SELECT MAX(i) FROM foo", 100); | |
495 } | |
496 | |
497 public void test_Offset5() throws SQLException, Failure { | |
498 prepare(); | |
499 conn.setUploadHandler(new MyUploadHandler(100)); | |
500 update("COPY OFFSET 5 INTO foo FROM 'banana' ON CLIENT", 96); | |
501 queryInt("SELECT MIN(i) FROM foo", 5); | |
502 queryInt("SELECT MAX(i) FROM foo", 100); | |
503 } | |
504 | |
505 public void test_ServerStopsReading() throws SQLException, Failure { | |
506 prepare(); | |
507 conn.setUploadHandler(new MyUploadHandler(100)); | |
508 update("COPY 10 RECORDS INTO foo FROM 'banana' ON CLIENT", 96); | |
509 // Server stopped reading after 10 rows. Will we stay in sync? | |
510 queryInt("SELECT COUNT(i) FROM foo", 10); | |
511 } | |
512 | |
513 public void test_Download(int n) throws SQLException, Failure { | |
514 prepare(); | |
515 MyDownloadHandler handler = new MyDownloadHandler(); | |
516 conn.setDownloadHandler(handler); | |
517 String q = "INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, " + n + ")"; | |
518 update(q, n); | |
519 update("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", -1); | |
520 assertEq("download attempts", 1, handler.countAttempts()); | |
521 assertEq("lines downloaded", n, handler.lineCount()); | |
522 } | |
523 | |
524 public void test_Download() throws SQLException, Failure { | |
525 test_Download(100); | |
526 } | |
527 | |
528 public void test_ClientRefusesDownload() throws SQLException, Failure { | |
529 prepare(); | |
530 MyDownloadHandler handler = new MyDownloadHandler("download refused"); | |
531 conn.setDownloadHandler(handler); | |
532 update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); | |
533 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); | |
534 queryInt("SELECT 42 -- check if the connection still works", 42); | |
535 } | |
536 | |
537 public void test_LargeUpload() throws SQLException, Failure { | |
538 watchDog.setDuration(25_000); | |
539 prepare(); | |
540 int n = 4_000_000; | |
541 MyUploadHandler handler = new MyUploadHandler(n); | |
542 conn.setUploadHandler(handler); | |
543 handler.setChunkSize(1024 * 1024); | |
544 update("COPY INTO foo FROM 'banana' ON CLIENT", n); | |
545 queryInt("SELECT COUNT(DISTINCT i) FROM foo", n); | |
546 } | |
547 | |
548 public void test_LargeDownload() throws SQLException, Failure { | |
549 watchDog.setDuration(25_000); | |
550 test_Download(4_000_000); | |
551 } | |
552 | |
553 public void test_UploadFromStream() throws SQLException, Failure { | |
554 prepare(); | |
555 MonetUploadHandler handler = new MonetUploadHandler() { | |
556 String data = "1|one\n2|two\n3|three\n"; | |
557 | |
558 @Override | |
559 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
560 ByteArrayInputStream s = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); | |
561 handle.uploadFrom(s); | |
562 } | |
563 }; | |
564 conn.setUploadHandler(handler); | |
565 update("COPY INTO foo FROM 'banana' ON CLIENT", 3); | |
566 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
567 } | |
568 | |
569 public void test_UploadFromReader() throws SQLException, Failure { | |
570 prepare(); | |
571 MonetUploadHandler handler = new MonetUploadHandler() { | |
572 String data = "1|one\n2|two\n3|three\n"; | |
573 | |
574 @Override | |
575 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
576 StringReader r = new StringReader(data); | |
577 handle.uploadFrom(r); | |
578 } | |
579 }; | |
580 conn.setUploadHandler(handler); | |
581 update("COPY INTO foo FROM 'banana' ON CLIENT", 3); | |
582 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
583 } | |
584 | |
585 public void test_UploadFromReaderOffset() throws SQLException, Failure { | |
586 prepare(); | |
587 MonetUploadHandler handler = new MonetUploadHandler() { | |
588 String data = "1|one\n2|two\n3|three\n"; | |
589 | |
590 @Override | |
591 public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { | |
592 BufferedReader r = new BufferedReader(new StringReader(data)); | |
593 handle.uploadFrom(r, offset); | |
594 } | |
595 }; | |
596 conn.setUploadHandler(handler); | |
597 update("COPY OFFSET 2 INTO foo FROM 'banana' ON CLIENT", 2); | |
598 queryInt("SELECT i FROM foo WHERE t = 'three'", 3); | |
599 } | |
600 | |
601 public void test_FailUploadLate() throws SQLException, Failure { | |
602 prepare(); | |
603 conn.setUploadHandler(new MyUploadHandler(100, 50, "i don't like line 50")); | |
604 expectError("COPY INTO foo FROM 'banana' ON CLIENT", "i don't like"); | |
605 assertEq("connection is closed", true, conn.isClosed()); | |
606 } | |
607 | |
608 // Disabled because it hangs, triggering the watchdog timer | |
609 public void testx_FailDownloadLate() throws SQLException, Failure { | |
610 prepare(); | |
611 MyDownloadHandler handler = new MyDownloadHandler(200, "download refused"); | |
612 conn.setDownloadHandler(handler); | |
613 update("INSERT INTO foo SELECT value as i, 'number' || value AS t FROM sys.generate_series(0, 100)", 100); | |
614 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); | |
615 queryInt("SELECT 42 -- check if the connection still works", 42); | |
616 } | |
617 | |
618 } | 317 } |