comparison tests/OnClientTester.java @ 527:ccf9c7fbdb50 onclient

Add watchdog timer to catch hangs
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Thu, 26 Aug 2021 16:25:09 +0200 (2021-08-26)
parents 6060ca8c5c1a
children 2d14abd1fc52
comparison
equal deleted inserted replaced
526:6060ca8c5c1a 527:ccf9c7fbdb50
18 int failureCount = 0; 18 int failureCount = 0;
19 private MonetConnection conn; 19 private MonetConnection conn;
20 private PrintWriter out; 20 private PrintWriter out;
21 private Statement stmt; 21 private Statement stmt;
22 private StringWriter outBuffer; 22 private StringWriter outBuffer;
23 private WatchDog watchDog;
23 24
24 public static void main(String[] args) throws SQLException, NoSuchMethodException { 25 public static void main(String[] args) throws SQLException, NoSuchMethodException {
25 String jdbcUrl = null; 26 String jdbcUrl = null;
26 String requiredPrefix = null; 27 String requiredPrefix = null;
27 int verbosity = 0; 28 int verbosity = 0;
57 this.jdbcUrl = jdbcUrl; 58 this.jdbcUrl = jdbcUrl;
58 this.verbosity = verbosity; 59 this.verbosity = verbosity;
59 } 60 }
60 61
61 private void runTests(String testPrefix) throws SQLException, NoSuchMethodException { 62 private void runTests(String testPrefix) throws SQLException, NoSuchMethodException {
62 String initialPrefix = "test_"; 63 watchDog = new WatchDog();
63 String methodPrefix = testPrefix == null ? initialPrefix : initialPrefix + testPrefix; 64 try {
64 65 String initialPrefix = "test_";
65 for (Method method : this.getClass().getDeclaredMethods()) { 66 String methodPrefix = testPrefix == null ? initialPrefix : initialPrefix + testPrefix;
66 String methodName = method.getName(); 67
67 if (methodName.startsWith(methodPrefix) && method.getParameterCount() == 0) { 68 for (Method method : this.getClass().getDeclaredMethods()) {
68 String testName = methodName.substring(initialPrefix.length()); 69 String methodName = method.getName();
69 runTest(testName, method); 70 if (methodName.startsWith(methodPrefix) && method.getParameterCount() == 0) {
70 } 71 String testName = methodName.substring(initialPrefix.length());
71 } 72 runTest(testName, method);
72 } 73 }
73 74 }
74 private void runTest(String testName) throws SQLException, NoSuchMethodException { 75 } finally {
75 String methodName = "test_" + testName; 76 watchDog.kill();
76 Method method = this.getClass().getDeclaredMethod(methodName); 77 watchDog = null;
77 runTest(testName, method); 78 }
78 } 79 }
79 80
80 private synchronized void runTest(String testName, Method method) throws SQLException { 81 private synchronized void runTest(String testName, Method method) throws SQLException {
82 watchDog.setContext("test " + testName);
83 watchDog.setDuration(3_000);
81 outBuffer = new StringWriter(); 84 outBuffer = new StringWriter();
82 out = new PrintWriter(outBuffer); 85 out = new PrintWriter(outBuffer);
83 86
84 Connection genericConnection = DriverManager.getConnection(jdbcUrl); 87 Connection genericConnection = DriverManager.getConnection(jdbcUrl);
85 conn = genericConnection.unwrap(MonetConnection.class); 88 conn = genericConnection.unwrap(MonetConnection.class);
86 stmt = conn.createStatement(); 89 stmt = conn.createStatement();
87 90
88 boolean failed = false; 91 boolean failed = false;
89 try { 92 try {
93 long duration;
90 try { 94 try {
95 long t0 = System.currentTimeMillis();
91 method.invoke(this); 96 method.invoke(this);
97 long t1 = System.currentTimeMillis();
98 duration = t1 - t0;
92 } catch (InvocationTargetException e) { 99 } catch (InvocationTargetException e) {
93 Throwable cause = e.getCause(); 100 Throwable cause = e.getCause();
94 if (cause instanceof Failure) 101 if (cause instanceof Failure)
95 throw (Failure)cause; 102 throw (Failure)cause;
96 else if (cause instanceof Exception) { 103 else if (cause instanceof Exception) {
101 } 108 }
102 109
103 if (verbosity > VERBOSITY_ON) 110 if (verbosity > VERBOSITY_ON)
104 System.out.println(); 111 System.out.println();
105 if (verbosity >= VERBOSITY_ON) 112 if (verbosity >= VERBOSITY_ON)
106 System.out.println("Test " + testName + " succeeded"); 113 System.out.println("Test " + testName + " succeeded in " + duration + "ms");
107 if (verbosity >= VERBOSITY_SHOW_ALL) 114 if (verbosity >= VERBOSITY_SHOW_ALL)
108 dumpOutput(testName); 115 dumpOutput(testName);
109 } catch (Failure e) { 116 } catch (Failure e) {
110 failed = true; 117 failed = true;
111 System.out.println(); 118 System.out.println();
125 System.out.println("Innermost cause was " + t); 132 System.out.println("Innermost cause was " + t);
126 if (t.getStackTrace().length > 0) { 133 if (t.getStackTrace().length > 0) {
127 System.out.println(" at " + t.getStackTrace()[0]); 134 System.out.println(" at " + t.getStackTrace()[0]);
128 } 135 }
129 } finally { 136 } finally {
137 watchDog.setContext(null);
130 testCount++; 138 testCount++;
131 if (failed) 139 if (failed)
132 failureCount++; 140 failureCount++;
133 if (failed && verbosity == VERBOSITY_ON) { 141 if (failed && verbosity == VERBOSITY_ON) {
134 // next test case will not print separator 142 // next test case will not print separator
171 fail("Expected <" + quantity + "' to be " + expected + "> got " + actual); 179 fail("Expected <" + quantity + "' to be " + expected + "> got " + actual);
172 } 180 }
173 } 181 }
174 182
175 protected boolean execute(String query) throws SQLException { 183 protected boolean execute(String query) throws SQLException {
176 out.println("EXECUTE: " + query); 184 try {
177 boolean result; 185 watchDog.start();
178 result = stmt.execute(query); 186 out.println("EXECUTE: " + query);
179 if (result) { 187 boolean result;
180 out.println(" OK"); 188 result = stmt.execute(query);
181 } else { 189 if (result) {
182 out.println(" OK, updated " + stmt.getUpdateCount() + " rows"); 190 out.println(" OK");
183 } 191 } else {
184 return result; 192 out.println(" OK, updated " + stmt.getUpdateCount() + " rows");
193 }
194 return result;
195 } finally {
196 watchDog.stop();
197 }
185 } 198 }
186 199
187 protected void update(String query, int expectedUpdateCount) throws SQLException, Failure { 200 protected void update(String query, int expectedUpdateCount) throws SQLException, Failure {
188 execute(query); 201 execute(query);
189 int updateCount = stmt.getUpdateCount(); 202 int updateCount = stmt.getUpdateCount();
352 super(message, cause); 365 super(message, cause);
353 } 366 }
354 367
355 } 368 }
356 369
370 static class WatchDog {
371 private long duration = 1000;
372 private long started = 0;
373 private String context = "no context";
374
375 WatchDog() {
376 Thread watchDog = new Thread(this::work);
377 watchDog.setName("watchdog_timer");
378 watchDog.setDaemon(true);
379 watchDog.start();
380 }
381
382 synchronized void setContext(String context) {
383 this.context = context;
384 }
385 synchronized void setDuration(long duration) {
386 if (duration <= 0)
387 throw new IllegalArgumentException("duration should be > 0");
388 this.duration = duration;
389 this.notifyAll();
390 }
391
392 synchronized void start() {
393 started = System.currentTimeMillis();
394 this.notifyAll();
395 }
396
397 synchronized void stop() {
398 started = 0;
399 this.notifyAll();
400 }
401
402 synchronized void kill() {
403 started = -1;
404 this.notifyAll();
405 }
406
407 private synchronized void work() {
408 long now;
409 try {
410 while (true) {
411 now = System.currentTimeMillis();
412 final long sleepTime;
413 if (started < 0) {
414 // client asked us to go away
415 // System.err.println("++ EXIT");
416 return;
417 } else if (started == 0) {
418 // wait for client to start us
419 sleepTime = 600_000;
420 } else {
421 long deadline = started + duration;
422 sleepTime = deadline - now;
423 }
424 // System.err.printf("++ now=%d, started=now%+d, duration=%d, sleep=%d%n",
425 // now, started - now, duration, sleepTime
426 // );
427 if (sleepTime > 0) {
428 this.wait(sleepTime);
429 } else {
430 trigger();
431 return;
432 }
433 }
434 } catch (InterruptedException e) {
435 System.err.println("WATCHDOG TIMER INTERRUPTED, SHOULDN'T HAPPEN");
436 System.exit(4);
437 }
438 }
439
440 private void trigger() {
441 String c = context != null ? context : "no context";
442 System.err.println();
443 System.err.println();
444 System.err.println("WATCHDOG TIMER EXPIRED [" + c + "], KILLING TESTS");
445 System.exit(3);
446 }
447 }
448
357 public void test_Upload() throws Exception { 449 public void test_Upload() throws Exception {
358 prepare(); 450 prepare();
359 conn.setUploadHandler(new MyUploadHandler(100)); 451 conn.setUploadHandler(new MyUploadHandler(100));
360 update("COPY INTO foo FROM 'banana' ON CLIENT", 100); 452 update("COPY INTO foo FROM 'banana' ON CLIENT", 100);
361 queryInt("SELECT COUNT(*) FROM foo", 100); 453 queryInt("SELECT COUNT(*) FROM foo", 100);
423 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused"); 515 expectError("COPY (SELECT * FROM foo) INTO 'banana' ON CLIENT", "download refused");
424 queryInt("SELECT 42 -- check if the connection still works", 42); 516 queryInt("SELECT 42 -- check if the connection still works", 42);
425 } 517 }
426 518
427 public void test_LargeUpload() throws SQLException, Failure { 519 public void test_LargeUpload() throws SQLException, Failure {
520 watchDog.setDuration(25_000);
428 prepare(); 521 prepare();
429 int n = 4_000_000; 522 int n = 4_000_000;
430 MyUploadHandler handler = new MyUploadHandler(n); 523 MyUploadHandler handler = new MyUploadHandler(n);
431 conn.setUploadHandler(handler); 524 conn.setUploadHandler(handler);
432 handler.setChunkSize(1024 * 1024); 525 handler.setChunkSize(1024 * 1024);
433 update("COPY INTO foo FROM 'banana' ON CLIENT", n); 526 update("COPY INTO foo FROM 'banana' ON CLIENT", n);
434 queryInt("SELECT COUNT(DISTINCT i) FROM foo", n); 527 queryInt("SELECT COUNT(DISTINCT i) FROM foo", n);
435 } 528 }
436 529
437 public void test_LargeDownload() throws SQLException, Failure { 530 public void test_LargeDownload() throws SQLException, Failure {
531 watchDog.setDuration(25_000);
438 test_Download(4_000_000); 532 test_Download(4_000_000);
439 } 533 }
440 534
441 public void test_UploadFromStream() throws SQLException, Failure { 535 public void test_UploadFromStream() throws SQLException, Failure {
442 prepare(); 536 prepare();