comparison tests/UrlTester.java @ 834:5aa19bbed0d6 monetdbs

Comments and formatting
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Wed, 13 Dec 2023 15:39:47 +0100 (17 months ago)
parents 9f6fe96c0ead
children 839d76eeb4ae
comparison
equal deleted inserted replaced
813:a71afa48f269 834:5aa19bbed0d6
3 import java.io.*; 3 import java.io.*;
4 import java.net.URISyntaxException; 4 import java.net.URISyntaxException;
5 import java.util.ArrayList; 5 import java.util.ArrayList;
6 6
7 public class UrlTester { 7 public class UrlTester {
8 final String filename; 8 final String filename;
9 final int verbose; 9 final int verbose;
10 final BufferedReader reader; 10 final BufferedReader reader;
11 int lineno = 0; 11 int lineno = 0;
12 int testCount = 0; 12 int testCount = 0;
13 Target target = null; 13 Target target = null;
14 Target.Validated validated = null; 14 Target.Validated validated = null;
15 15
16 public UrlTester(String filename, BufferedReader reader, int verbose) { 16 public UrlTester(String filename, BufferedReader reader, int verbose) {
17 this.filename = filename; 17 this.filename = filename;
18 this.verbose = verbose; 18 this.verbose = verbose;
19 this.reader = reader; 19 this.reader = reader;
20 } 20 }
21 21
22 public UrlTester(String filename, int verbose) throws IOException { 22 public UrlTester(String filename, int verbose) throws IOException {
23 this.filename = filename; 23 this.filename = filename;
24 this.verbose = verbose; 24 this.verbose = verbose;
25 this.reader = new BufferedReader(new FileReader(filename)); 25 this.reader = new BufferedReader(new FileReader(filename));
26 } 26 }
27 27
28 public static void main(String[] args) throws IOException { 28 public static void main(String[] args) throws IOException {
29 ArrayList<String> filenames = new ArrayList<>(); 29 ArrayList<String> filenames = new ArrayList<>();
30 int verbose = 0; 30 int verbose = 0;
31 for (String arg : args) { 31 for (String arg : args) {
32 switch (arg) { 32 switch (arg) {
33 case "-vvv": 33 case "-vvv":
34 verbose++; 34 verbose++;
35 case "-vv": 35 case "-vv":
36 verbose++; 36 verbose++;
37 case "-v": 37 case "-v":
38 verbose++; 38 verbose++;
39 break; 39 break;
40 case "-h": 40 case "-h":
41 case "--help": 41 case "--help":
42 exitUsage(null); 42 exitUsage(null);
43 break; 43 break;
44 default: 44 default:
45 if (!arg.startsWith("-")) { 45 if (!arg.startsWith("-")) {
46 filenames.add(arg); 46 filenames.add(arg);
47 } else { 47 } else {
48 exitUsage("Unexpected argument: " + arg); 48 exitUsage("Unexpected argument: " + arg);
49 } 49 }
50 break; 50 break;
51 } 51 }
52 } 52 }
53 53
54 runUnitTests(); 54 runUnitTests();
55 55
56 try { 56 try {
57 if (filenames.isEmpty()) { 57 if (filenames.isEmpty()) {
58 runAllTests(); 58 runAllTests();
59 } else { 59 } else {
60 for (String filename : filenames) { 60 for (String filename : filenames) {
61 new UrlTester(filename, verbose).run(); 61 new UrlTester(filename, verbose).run();
62 } 62 }
63 } 63 }
64 } catch (Failure e) { 64 } catch (Failure e) {
65 System.err.println("Test failed: " + e.getMessage()); 65 System.err.println("Test failed: " + e.getMessage());
66 System.exit(1); 66 System.exit(1);
67 } 67 }
68 } 68 }
69 69
70 private static void exitUsage(String message) { 70 private static void exitUsage(String message) {
71 if (message != null) { 71 if (message != null) {
72 System.err.println(message); 72 System.err.println(message);
73 } 73 }
74 System.err.println("Usage: UrlTester OPTIONS [FILENAME..]"); 74 System.err.println("Usage: UrlTester OPTIONS [FILENAME..]");
75 System.err.println("Options:"); 75 System.err.println("Options:");
76 System.err.println(" -v Be more verbose"); 76 System.err.println(" -v Be more verbose");
77 System.err.println(" -h --help Show this help"); 77 System.err.println(" -h --help Show this help");
78 int status = message == null ? 0 : 1; 78 int status = message == null ? 0 : 1;
79 System.exit(status); 79 System.exit(status);
80 } 80 }
81 81
82 public static UrlTester forResource(String resourceName, int verbose) throws FileNotFoundException { 82 public static UrlTester forResource(String resourceName, int verbose) throws FileNotFoundException {
83 InputStream stream = UrlTester.class.getResourceAsStream(resourceName); 83 InputStream stream = UrlTester.class.getResourceAsStream(resourceName);
84 if (stream == null) { 84 if (stream == null) {
85 throw new FileNotFoundException("Resource " + resourceName); 85 throw new FileNotFoundException("Resource " + resourceName);
86 } 86 }
87 BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); 87 BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
88 return new UrlTester(resourceName, reader, verbose); 88 return new UrlTester(resourceName, reader, verbose);
89 } 89 }
90 90
91 public static void runAllTests() throws IOException, Failure { 91 public static void runAllTests() throws IOException, Failure {
92 runUnitTests(); 92 runUnitTests();
93 UrlTester.forResource("/tests.md", 0).run(); 93 UrlTester.forResource("/tests.md", 0).run();
94 UrlTester.forResource("/javaspecific.md", 0).run(); 94 UrlTester.forResource("/javaspecific.md", 0).run();
95 } 95 }
96 96
97 public static void runUnitTests() { 97 public static void runUnitTests() {
98 testDefaults(); 98 testDefaults();
99 testParameters(); 99 testParameters();
100 } 100 }
101 101
102 private static void testDefaults() { 102 private static void testDefaults() {
103 Target target = new Target(); 103 Target target = new Target();
104 104
105 for (Parameter parm : Parameter.values()) { 105 for (Parameter parm : Parameter.values()) {
106 Object expected = parm.getDefault(); 106 Object expected = parm.getDefault();
107 if (expected == null) 107 if (expected == null)
108 continue; 108 continue;
109 Object actual = target.getObject(parm); 109 Object actual = target.getObject(parm);
110 if (!expected.equals(actual)) { 110 if (!expected.equals(actual)) {
111 throw new RuntimeException("Default for " + parm.name + " expected to be <" + expected + "> but is <" + actual + ">"); 111 throw new RuntimeException("Default for " + parm.name + " expected to be <" + expected + "> but is <" + actual + ">");
112 } 112 }
113 } 113 }
114 } 114 }
115 115
116 private static void testParameters() { 116 private static void testParameters() {
117 for (Parameter parm : Parameter.values()) { 117 for (Parameter parm : Parameter.values()) {
118 Parameter found = Parameter.forName(parm.name); 118 Parameter found = Parameter.forName(parm.name);
119 if (parm != found) { 119 if (parm != found) {
120 String foundStr = found != null ? found.name : "null"; 120 String foundStr = found != null ? found.name : "null";
121 throw new RuntimeException("Looking up <" + parm.name + ">, found <" + foundStr); 121 throw new RuntimeException("Looking up <" + parm.name + ">, found <" + foundStr);
122 } 122 }
123 } 123 }
124 } 124 }
125 125
126 public void run() throws Failure, IOException { 126 public void run() throws Failure, IOException {
127 try { 127 try {
128 processFile(); 128 processFile();
129 } catch (Failure e) { 129 } catch (Failure e) {
130 if (e.getFilename() == null) { 130 if (e.getFilename() == null) {
131 e.setFilename(filename); 131 e.setFilename(filename);
132 e.setLineno(lineno); 132 e.setLineno(lineno);
133 throw e; 133 throw e;
134 } 134 }
135 } 135 }
136 } 136 }
137 137
138 private void processFile() throws IOException, Failure { 138 private void processFile() throws IOException, Failure {
139 while (true) { 139 while (true) {
140 String line = reader.readLine(); 140 String line = reader.readLine();
141 if (line == null) 141 if (line == null)
142 break; 142 break;
143 lineno++; 143 lineno++;
144 processLine(line); 144 processLine(line);
145 } 145 }
146 if (verbose >= 1) { 146 if (verbose >= 1) {
147 System.out.println(); 147 System.out.println();
148 System.out.println("Ran " + testCount + " tests in " + lineno + " lines"); 148 System.out.println("Ran " + testCount + " tests in " + lineno + " lines");
149 } 149 }
150 } 150 }
151 151
152 private void processLine(String line) throws Failure { 152 private void processLine(String line) throws Failure {
153 line = line.replaceFirst("\\s+$", ""); // remove trailing 153 line = line.replaceFirst("\\s+$", ""); // remove trailing
154 if (target == null && line.equals("```test")) { 154 if (target == null && line.equals("```test")) {
155 if (verbose >= 2) { 155 if (verbose >= 2) {
156 if (testCount > 0) { 156 if (testCount > 0) {
157 System.out.println(); 157 System.out.println();
158 } 158 }
159 System.out.println("\u25B6 " + filename + ":" + lineno); 159 System.out.println("\u25B6 " + filename + ":" + lineno);
160 } 160 }
161 target = new Target(); 161 target = new Target();
162 testCount++; 162 testCount++;
163 return; 163 return;
164 } 164 }
165 if (target != null) { 165 if (target != null) {
166 if (line.equals("```")) { 166 if (line.equals("```")) {
167 stopProcessing(); 167 stopProcessing();
168 return; 168 return;
169 } 169 }
170 handleCommand(line); 170 handleCommand(line);
171 } 171 }
172 } 172 }
173 173
174 private void stopProcessing() { 174 private void stopProcessing() {
175 target = null; 175 target = null;
176 validated = null; 176 validated = null;
177 } 177 }
178 178
179 private void handleCommand(String line) throws Failure { 179 private void handleCommand(String line) throws Failure {
180 if (verbose >= 3) { 180 if (verbose >= 3) {
181 System.out.println(line); 181 System.out.println(line);
182 } 182 }
183 if (line.isEmpty()) 183 if (line.isEmpty())
184 return; 184 return;
185 185
186 String[] parts = line.split("\\s+", 2); 186 String[] parts = line.split("\\s+", 2);
187 String command = parts[0]; 187 String command = parts[0];
188 switch (command.toUpperCase()) { 188 switch (command.toUpperCase()) {
189 case "ONLY": 189 case "ONLY":
190 handleOnly(true, parts[1]); 190 handleOnly(true, parts[1]);
191 return; 191 return;
192 case "NOT": 192 case "NOT":
193 handleOnly(false, parts[1]); 193 handleOnly(false, parts[1]);
194 return; 194 return;
195 case "PARSE": 195 case "PARSE":
196 handleParse(parts[1], null); 196 handleParse(parts[1], null);
197 return; 197 return;
198 case "ACCEPT": 198 case "ACCEPT":
199 handleParse(parts[1], true); 199 handleParse(parts[1], true);
200 return; 200 return;
201 case "REJECT": 201 case "REJECT":
202 handleParse(parts[1], false); 202 handleParse(parts[1], false);
203 return; 203 return;
204 case "SET": 204 case "SET":
205 handleSet(parts[1]); 205 handleSet(parts[1]);
206 return; 206 return;
207 case "EXPECT": 207 case "EXPECT":
208 handleExpect(parts[1]); 208 handleExpect(parts[1]);
209 return; 209 return;
210 default: 210 default:
211 throw new Failure("Unexpected command: " + command); 211 throw new Failure("Unexpected command: " + command);
212 } 212 }
213 213
214 } 214 }
215 215
216 private void handleOnly(boolean mustBePresent, String rest) throws Failure { 216 private void handleOnly(boolean mustBePresent, String rest) throws Failure {
217 boolean found = false; 217 boolean found = false;
218 for (String part : rest.split("\\s+")) { 218 for (String part : rest.split("\\s+")) {
219 if (part.equals("jdbc")) { 219 if (part.equals("jdbc")) {
220 found = true; 220 found = true;
221 break; 221 break;
222 } 222 }
223 } 223 }
224 if (found != mustBePresent) { 224 if (found != mustBePresent) {
225 // do not further process this block 225 // do not further process this block
226 stopProcessing(); 226 stopProcessing();
227 } 227 }
228 } 228 }
229 229
230 private int findEqualSign(String rest) throws Failure { 230 private int findEqualSign(String rest) throws Failure {
231 int index = rest.indexOf('='); 231 int index = rest.indexOf('=');
232 if (index < -1) 232 if (index < -1)
233 throw new Failure("Expected to find a '='"); 233 throw new Failure("Expected to find a '='");
234 return index; 234 return index;
235 } 235 }
236 236
237 private String splitKey(String rest) throws Failure { 237 private String splitKey(String rest) throws Failure {
238 int index = findEqualSign(rest); 238 int index = findEqualSign(rest);
239 return rest.substring(0, index); 239 return rest.substring(0, index);
240 } 240 }
241 241
242 private String splitValue(String rest) throws Failure { 242 private String splitValue(String rest) throws Failure {
243 int index = findEqualSign(rest); 243 int index = findEqualSign(rest);
244 return rest.substring(index + 1); 244 return rest.substring(index + 1);
245 } 245 }
246 246
247 private void handleSet(String rest) throws Failure { 247 private void handleSet(String rest) throws Failure {
248 validated = null; 248 validated = null;
249 String key = splitKey(rest); 249 String key = splitKey(rest);
250 String value = splitValue(rest); 250 String value = splitValue(rest);
251 251
252 try { 252 try {
253 target.setString(key, value); 253 target.setString(key, value);
254 } catch (ValidationError e) { 254 } catch (ValidationError e) {
255 throw new Failure(e.getMessage()); 255 throw new Failure(e.getMessage());
256 } 256 }
257 } 257 }
258 258
259 private void handleParse(String rest, Boolean shouldSucceed) throws Failure { 259 private void handleParse(String rest, Boolean shouldSucceed) throws Failure {
260 URISyntaxException parseError = null; 260 URISyntaxException parseError = null;
261 ValidationError validationError = null; 261 ValidationError validationError = null;
262 262
263 validated = null; 263 validated = null;
264 try { 264 try {
265 target.barrier(); 265 target.barrier();
266 MonetUrlParser.parse(target, rest); 266 MonetUrlParser.parse(target, rest);
267 } catch (URISyntaxException e) { 267 } catch (URISyntaxException e) {
268 parseError = e; 268 parseError = e;
269 } catch (ValidationError e) { 269 } catch (ValidationError e) {
270 validationError = e; 270 validationError = e;
271 } 271 }
272 272
273 if (parseError == null && validationError == null) { 273 if (parseError == null && validationError == null) {
274 try { 274 try {
275 tryValidate(); 275 tryValidate();
276 } catch (ValidationError e) { 276 } catch (ValidationError e) {
277 validationError = e; 277 validationError = e;
278 } 278 }
279 } 279 }
280 280
281 if (shouldSucceed == Boolean.FALSE) { 281 if (shouldSucceed == Boolean.FALSE) {
282 if (parseError != null || validationError != null) 282 if (parseError != null || validationError != null)
283 return; // happy 283 return; // happy
284 else 284 else
285 throw new Failure("URL unexpectedly parsed and validated"); 285 throw new Failure("URL unexpectedly parsed and validated");
286 } 286 }
287 287
288 if (parseError != null) 288 if (parseError != null)
289 throw new Failure("Parse error: " + parseError); 289 throw new Failure("Parse error: " + parseError);
290 if (validationError != null && shouldSucceed == Boolean.TRUE) 290 if (validationError != null && shouldSucceed == Boolean.TRUE)
291 throw new Failure("Validation error: " + validationError); 291 throw new Failure("Validation error: " + validationError);
292 } 292 }
293 293
294 private void handleExpect(String rest) throws Failure { 294 private void handleExpect(String rest) throws Failure {
295 String key = splitKey(rest); 295 String key = splitKey(rest);
296 String expectedString = splitValue(rest); 296 String expectedString = splitValue(rest);
297 297
298 Object actual = null; 298 Object actual = null;
299 try { 299 try {
300 actual = extract(key); 300 actual = extract(key);
301 } catch (ValidationError e) { 301 } catch (ValidationError e) {
302 throw new Failure(e.getMessage()); 302 throw new Failure(e.getMessage());
303 } 303 }
304 304
305 Object expected; 305 Object expected;
306 try { 306 try {
307 if (actual instanceof Boolean) 307 if (actual instanceof Boolean)
308 expected = ParameterType.Bool.parse(key, expectedString); 308 expected = ParameterType.Bool.parse(key, expectedString);
309 else if (actual instanceof Integer) 309 else if (actual instanceof Integer)
310 expected = ParameterType.Int.parse(key, expectedString); 310 expected = ParameterType.Int.parse(key, expectedString);
311 else 311 else
312 expected = expectedString; 312 expected = expectedString;
313 } catch (ValidationError e) { 313 } catch (ValidationError e) {
314 String typ = actual.getClass().getName(); 314 String typ = actual.getClass().getName();
315 throw new Failure("Cannot convert expected value <" + expectedString + "> to " + typ + ": " + e.getMessage()); 315 throw new Failure("Cannot convert expected value <" + expectedString + "> to " + typ + ": " + e.getMessage());
316 } 316 }
317 317
318 if (actual.equals(expected)) 318 if (actual.equals(expected))
319 return; 319 return;
320 throw new Failure("Expected " + key + "=<" + expectedString + ">, found <" + actual + ">"); 320 throw new Failure("Expected " + key + "=<" + expectedString + ">, found <" + actual + ">");
321 } 321 }
322 322
323 private Target.Validated tryValidate() throws ValidationError { 323 private Target.Validated tryValidate() throws ValidationError {
324 if (validated == null) 324 if (validated == null)
325 validated = target.validate(); 325 validated = target.validate();
326 return validated; 326 return validated;
327 } 327 }
328 328
329 private Object extract(String key) throws ValidationError, Failure { 329 private Object extract(String key) throws ValidationError, Failure {
330 switch (key) { 330 switch (key) {
331 case "valid": 331 case "valid":
332 try { 332 try {
333 tryValidate(); 333 tryValidate();
334 } catch (ValidationError e) { 334 } catch (ValidationError e) {
335 return Boolean.FALSE; 335 return Boolean.FALSE;
336 } 336 }
337 return Boolean.TRUE; 337 return Boolean.TRUE;
338 338
339 case "connect_scan": 339 case "connect_scan":
340 return tryValidate().connectScan(); 340 return tryValidate().connectScan();
341 case "connect_port": 341 case "connect_port":
342 return tryValidate().connectPort(); 342 return tryValidate().connectPort();
343 case "connect_unix": 343 case "connect_unix":
344 return tryValidate().connectUnix(); 344 return tryValidate().connectUnix();
345 case "connect_tcp": 345 case "connect_tcp":
346 return tryValidate().connectTcp(); 346 return tryValidate().connectTcp();
347 case "connect_tls_verify": 347 case "connect_tls_verify":
348 switch (tryValidate().connectVerify()) { 348 switch (tryValidate().connectVerify()) {
349 case None: 349 case None:
350 return ""; 350 return "";
351 case Cert: 351 case Cert:
352 return "cert"; 352 return "cert";
353 case Hash: 353 case Hash:
354 return "hash"; 354 return "hash";
355 case System: 355 case System:
356 return "system"; 356 return "system";
357 default: 357 default:
358 throw new IllegalStateException("unreachable"); 358 throw new IllegalStateException("unreachable");
359 } 359 }
360 case "connect_certhash_digits": 360 case "connect_certhash_digits":
361 return tryValidate().connectCertHashDigits(); 361 return tryValidate().connectCertHashDigits();
362 case "connect_binary": 362 case "connect_binary":
363 return tryValidate().connectBinary(); 363 return tryValidate().connectBinary();
364 case "connect_clientkey": 364 case "connect_clientkey":
365 return tryValidate().connectClientKey(); 365 return tryValidate().connectClientKey();
366 case "connect_clientcert": 366 case "connect_clientcert":
367 return tryValidate().connectClientCert(); 367 return tryValidate().connectClientCert();
368 368
369 default: 369 default:
370 Parameter parm = Parameter.forName(key); 370 Parameter parm = Parameter.forName(key);
371 if (parm != null) 371 if (parm != null)
372 return target.getObject(parm); 372 return target.getObject(parm);
373 else 373 else
374 throw new Failure("Unknown attribute: " + key); 374 throw new Failure("Unknown attribute: " + key);
375 } 375 }
376 } 376 }
377 377
378 public static class Failure extends Exception { 378 public static class Failure extends Exception {
379 private String filename = null; 379 private String filename = null;
380 private int lineno = -1; 380 private int lineno = -1;
381 381
382 public Failure(String message) { 382 public Failure(String message) {
383 super(message); 383 super(message);
384 } 384 }
385 385
386 @Override 386 @Override
387 public String getMessage() { 387 public String getMessage() {
388 StringBuilder buffer = new StringBuilder(); 388 StringBuilder buffer = new StringBuilder();
389 if (filename != null) { 389 if (filename != null) {
390 buffer.append(filename).append(":"); 390 buffer.append(filename).append(":");
391 if (lineno >= 0) 391 if (lineno >= 0)
392 buffer.append(lineno).append(":"); 392 buffer.append(lineno).append(":");
393 } 393 }
394 buffer.append(super.getMessage()); 394 buffer.append(super.getMessage());
395 return buffer.toString(); 395 return buffer.toString();
396 } 396 }
397 397
398 public String getFilename() { 398 public String getFilename() {
399 return filename; 399 return filename;
400 } 400 }
401 401
402 public void setFilename(String filename) { 402 public void setFilename(String filename) {
403 this.filename = filename; 403 this.filename = filename;
404 } 404 }
405 405
406 public int getLineno() { 406 public int getLineno() {
407 return lineno; 407 return lineno;
408 } 408 }
409 409
410 public void setLineno(int lineno) { 410 public void setLineno(int lineno) {
411 this.lineno = lineno; 411 this.lineno = lineno;
412 } 412 }
413 } 413 }
414 } 414 }