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 }