1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.incubator.http.internal.websocket; 24 25 import java.nio.ByteBuffer; 26 import java.util.*; 27 import java.util.concurrent.*; 28 import java.util.function.Consumer; 29 import java.util.function.Predicate; 30 import java.util.regex.Pattern; 31 import java.util.stream.Collectors; 32 import java.util.stream.Stream; 33 34 import static java.util.List.of; 35 import static java.util.Objects.requireNonNull; 36 37 /* 38 * Auxiliary test infrastructure 39 */ 40 final class TestSupport { 41 42 private TestSupport() { } 43 44 static <A, B, R> Iterator<R> cartesianIterator(List<A> a, 45 List<B> b, 46 F2<A, B, R> f2) { 47 @SuppressWarnings("unchecked") 48 F<R> t = p -> f2.apply((A) p[0], (B) p[1]); 49 return cartesianIterator(of(a, b), t); 50 } 51 52 static <A, B, C, R> Iterator<R> cartesianIterator(List<A> a, 171 return new Iterator<>() { 172 173 int count = maxElements; 174 175 @Override 176 public boolean hasNext() { 177 return count > 0 && elements.hasNext(); 178 } 179 180 @Override 181 public T next() { 182 if (!hasNext()) { 183 throw new NoSuchElementException(); 184 } 185 count--; 186 return elements.next(); 187 } 188 }; 189 } 190 191 // static <T> Iterator<T> filter(Iterator<? extends T> source, 192 // Predicate<? super T> predicate) { 193 // return new Iterator<>() { 194 // 195 // { findNext(); } 196 // 197 // T next; 198 // boolean hasNext; 199 // 200 // @Override 201 // public boolean hasNext() { 202 // return hasNext; 203 // } 204 // 205 // @Override 206 // public T next() { 207 // if (!hasNext) { 208 // throw new NoSuchElementException(); 209 // } 210 // T n = this.next; 211 // findNext(); 212 // return n; 213 // } 214 // 215 // void findNext() { 216 // while (source.hasNext()) { 217 // T n = source.next(); 218 // if (predicate.test(n)) { 219 // hasNext = true; 220 // next = n; 221 // break; 222 // } 223 // } 224 // } 225 // }; 226 // } 227 228 static ByteBuffer fullCopy(ByteBuffer src) { 229 ByteBuffer copy = ByteBuffer.allocate(src.capacity()); 230 int p = src.position(); 231 int l = src.limit(); 232 src.clear(); 233 copy.put(src).position(p).limit(l); 234 src.position(p).limit(l); 235 return copy; 236 } 237 238 static void forEachBufferPartition(ByteBuffer src, 239 Consumer<? super Iterable<? extends ByteBuffer>> action) { 240 forEachPartition(src.remaining(), 241 (lengths) -> { 242 int end = src.position(); 243 List<ByteBuffer> buffers = new LinkedList<>(); 244 for (int len : lengths) { 245 ByteBuffer d = src.duplicate(); 246 d.position(end); 247 d.limit(end + len); 280 } 281 282 private static void permutations(int i, int[] a, Consumer<? super int[]> c) { 283 if (i == a.length) { 284 c.accept(Arrays.copyOf(a, a.length)); 285 return; 286 } 287 for (int j = i; j < a.length; j++) { 288 swap(a, i, j); 289 permutations(i + 1, a, c); 290 swap(a, i, j); 291 } 292 } 293 294 private static void swap(int[] a, int i, int j) { 295 int x = a[i]; 296 a[i] = a[j]; 297 a[j] = x; 298 } 299 300 static <T> Iterator<T> concat(Iterator<? extends Iterator<? extends T>> iterators) { 301 requireNonNull(iterators); 302 return new Iterator<>() { 303 304 private Iterator<? extends T> current = Collections.emptyIterator(); 305 306 @Override 307 public boolean hasNext() { 308 while (!current.hasNext()) { 309 if (!iterators.hasNext()) { 310 return false; 311 } else { 312 current = iterators.next(); 313 } 314 } 315 return true; 316 } 317 318 @Override 319 public T next() { 320 if (!hasNext()) { 321 throw new NoSuchElementException(); 322 } 323 return current.next(); 324 } 325 }; 326 } 327 328 interface Mock { 329 330 /* 331 * Completes exceptionally if there are any expectations that haven't 332 * been met within the given time period, otherwise completes normally 333 */ 334 CompletableFuture<Void> expectations(long timeout, TimeUnit unit); 335 } 336 337 static final class InvocationChecker { 338 339 private final Object lock = new Object(); 340 private final Iterator<InvocationExpectation> expectations; 341 private final CompletableFuture<Void> expectationsViolation 342 = new CompletableFuture<>(); 343 344 InvocationChecker(Iterable<InvocationExpectation> expectations) { 345 this.expectations = requireNonNull(expectations).iterator(); 346 } 347 348 /* 349 * Completes exceptionally if there are any expectations that haven't 350 * been met within the given time period, otherwise completes normally 351 */ 352 CompletableFuture<Void> expectations(long timeout, TimeUnit unit) { 353 return expectationsViolation 354 .orTimeout(timeout, unit) 355 .handle((v, t) -> { 356 if (t == null) { 357 throw new InternalError( 358 "Unexpected normal completion: " + v); 359 } else if (t instanceof TimeoutException) { 360 synchronized (lock) { 361 if (!expectations.hasNext()) { 362 return null; 363 } else { 364 throw new AssertionFailedException( 365 "More invocations were expected"); 366 } 367 } 368 } else if (t instanceof AssertionFailedException) { 369 throw (AssertionFailedException) t; 370 } else { 371 throw new RuntimeException(t); 372 } 373 }); 374 } 375 376 void checkInvocation(String name, Object... args) { 377 synchronized (lock) { 378 if (!expectations.hasNext()) { 379 expectationsViolation.completeExceptionally( 380 new AssertionFailedException( 381 "Less invocations were expected: " + name)); 382 return; 383 } 384 InvocationExpectation next = expectations.next(); 385 if (!next.name.equals(name)) { 386 expectationsViolation.completeExceptionally( 387 new AssertionFailedException( 388 "A different invocation was expected: " + name) 389 ); 390 return; 391 } 392 if (!next.predicate.apply(args)) { 393 expectationsViolation.completeExceptionally( 394 new AssertionFailedException( 395 "Invocation doesn't match the predicate: " 396 + name + ", " + Arrays.toString(args)) 397 ); 398 } 399 } 400 } 401 } 402 403 static final class InvocationExpectation { 404 405 final String name; 406 final F<Boolean> predicate; 407 408 InvocationExpectation(String name, F<Boolean> predicate) { 409 this.name = requireNonNull(name); 410 this.predicate = requireNonNull(predicate); 411 } 412 } 413 414 static void checkExpectations(Mock... mocks) { 415 checkExpectations(0, TimeUnit.SECONDS, mocks); 416 } 417 418 static void checkExpectations(long timeout, TimeUnit unit, Mock... mocks) { 419 CompletableFuture<?>[] completableFutures = Stream.of(mocks) 420 .map(m -> m.expectations(timeout, unit)) 421 .collect(Collectors.toList()).toArray(new CompletableFuture<?>[0]); 422 CompletableFuture<Void> cf = CompletableFuture.allOf(completableFutures); 423 try { 424 cf.join(); 425 } catch (CompletionException e) { 426 Throwable cause = e.getCause(); 427 if (cause instanceof AssertionFailedException) { 428 throw (AssertionFailedException) cause; 429 } else { 430 throw e; 431 } 432 } 433 } 434 435 public static <T extends Throwable> T assertThrows(Class<? extends T> clazz, 436 ThrowingProcedure code) { 437 @SuppressWarnings("unchecked") 438 T t = (T) assertThrows(clazz::isInstance, code); 439 return t; 440 } 441 442 /* 443 * The rationale behind asking for a regex is to not pollute variable names 444 * space in the scope of assertion: if it's something as simple as checking 445 * a message, we can do it inside 446 */ 447 @SuppressWarnings("unchecked") 448 static <T extends Throwable> T assertThrows(Class<? extends T> clazz, 449 String messageRegex, 450 ThrowingProcedure code) { 451 requireNonNull(messageRegex, "messagePattern"); 452 Predicate<Throwable> p = e -> clazz.isInstance(e) 453 && Pattern.matches(messageRegex, e.getMessage()); 454 return (T) assertThrows(p, code); 455 } 456 457 static Throwable assertThrows(Predicate<? super Throwable> predicate, 458 ThrowingProcedure code) { 459 requireNonNull(predicate, "predicate"); 460 requireNonNull(code, "code"); 461 Throwable caught = null; 462 try { 463 code.run(); 464 } catch (Throwable t) { 465 caught = t; 466 } 467 if (predicate.test(caught)) { 468 return caught; 469 } 470 if (caught == null) { 471 throw new AssertionFailedException("No exception was thrown"); 472 } 473 throw new AssertionFailedException("Caught exception didn't match the predicate", caught); 474 } 475 476 /* 477 * Blocking assertion, waits for completion 478 */ 479 static Throwable assertCompletesExceptionally(Class<? extends Throwable> clazz, 480 CompletionStage<?> stage) { 481 CompletableFuture<?> cf = 482 CompletableFuture.completedFuture(null).thenCompose(x -> stage); 483 return assertThrows(t -> clazz.isInstance(t.getCause()), cf::get); 484 } 485 486 interface ThrowingProcedure { 487 void run() throws Throwable; 488 } 489 490 static final class Expectation { 491 492 private final List<Predicate<? super Throwable>> list = new LinkedList<>(); 493 494 static Expectation ifExpect(boolean condition, 495 Predicate<? super Throwable> predicate) { 496 return addPredicate(new Expectation(), condition, predicate); 497 } 498 499 Expectation orExpect(boolean condition, 500 Predicate<? super Throwable> predicate) { 501 return addPredicate(this, condition, predicate); 502 } 503 504 static Expectation addPredicate(Expectation e, boolean condition, 505 Predicate<? super Throwable> predicate) { 506 if (condition) { 507 e.list.add(requireNonNull(predicate)); 508 } 509 return e; 510 } 511 512 public Throwable assertThrows(ThrowingProcedure code) { 513 Predicate<Throwable> p; 514 if (list.isEmpty()) { 515 p = Objects::isNull; 516 } else { 517 p = e -> list.stream().anyMatch(x -> x.test(e)); 518 } 519 return TestSupport.assertThrows(p, code); 520 } 521 } 522 523 static final class AssertionFailedException extends RuntimeException { 524 525 private static final long serialVersionUID = 1L; 526 527 AssertionFailedException(String message) { 528 super(message); 529 } 530 531 AssertionFailedException(String message, Throwable cause) { 532 super(message, cause); 533 } 534 } 535 } | 1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.incubator.http.internal.websocket; 24 25 import java.nio.ByteBuffer; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.Iterator; 29 import java.util.LinkedList; 30 import java.util.List; 31 import java.util.NoSuchElementException; 32 import java.util.Stack; 33 import java.util.concurrent.CompletableFuture; 34 import java.util.concurrent.CompletionStage; 35 import java.util.function.Consumer; 36 import java.util.function.Predicate; 37 import java.util.regex.Pattern; 38 39 import static java.util.List.of; 40 import static java.util.Objects.requireNonNull; 41 42 /* 43 * Auxiliary test infrastructure 44 */ 45 final class TestSupport { 46 47 private TestSupport() { } 48 49 static <A, B, R> Iterator<R> cartesianIterator(List<A> a, 50 List<B> b, 51 F2<A, B, R> f2) { 52 @SuppressWarnings("unchecked") 53 F<R> t = p -> f2.apply((A) p[0], (B) p[1]); 54 return cartesianIterator(of(a, b), t); 55 } 56 57 static <A, B, C, R> Iterator<R> cartesianIterator(List<A> a, 176 return new Iterator<>() { 177 178 int count = maxElements; 179 180 @Override 181 public boolean hasNext() { 182 return count > 0 && elements.hasNext(); 183 } 184 185 @Override 186 public T next() { 187 if (!hasNext()) { 188 throw new NoSuchElementException(); 189 } 190 count--; 191 return elements.next(); 192 } 193 }; 194 } 195 196 static ByteBuffer fullCopy(ByteBuffer src) { 197 ByteBuffer copy = ByteBuffer.allocate(src.capacity()); 198 int p = src.position(); 199 int l = src.limit(); 200 src.clear(); 201 copy.put(src).position(p).limit(l); 202 src.position(p).limit(l); 203 return copy; 204 } 205 206 static void forEachBufferPartition(ByteBuffer src, 207 Consumer<? super Iterable<? extends ByteBuffer>> action) { 208 forEachPartition(src.remaining(), 209 (lengths) -> { 210 int end = src.position(); 211 List<ByteBuffer> buffers = new LinkedList<>(); 212 for (int len : lengths) { 213 ByteBuffer d = src.duplicate(); 214 d.position(end); 215 d.limit(end + len); 248 } 249 250 private static void permutations(int i, int[] a, Consumer<? super int[]> c) { 251 if (i == a.length) { 252 c.accept(Arrays.copyOf(a, a.length)); 253 return; 254 } 255 for (int j = i; j < a.length; j++) { 256 swap(a, i, j); 257 permutations(i + 1, a, c); 258 swap(a, i, j); 259 } 260 } 261 262 private static void swap(int[] a, int i, int j) { 263 int x = a[i]; 264 a[i] = a[j]; 265 a[j] = x; 266 } 267 268 public static <T extends Throwable> T assertThrows(Class<? extends T> clazz, 269 ThrowingProcedure code) { 270 @SuppressWarnings("unchecked") 271 T t = (T) assertThrows(clazz::isInstance, code); 272 return t; 273 } 274 275 /* 276 * The rationale behind asking for a regex is to not pollute variable names 277 * space in the scope of assertion: if it's something as simple as checking 278 * a message, we can do it inside 279 */ 280 @SuppressWarnings("unchecked") 281 static <T extends Throwable> T assertThrows(Class<? extends T> clazz, 282 String messageRegex, 283 ThrowingProcedure code) { 284 requireNonNull(messageRegex, "messagePattern"); 285 Predicate<Throwable> p = e -> clazz.isInstance(e) 286 && Pattern.matches(messageRegex, e.getMessage()); 287 return (T) assertThrows(p, code); 288 } 289 290 static Throwable assertThrows(Predicate<? super Throwable> predicate, 291 ThrowingProcedure code) { 292 requireNonNull(predicate, "predicate"); 293 requireNonNull(code, "code"); 294 Throwable caught = null; 295 try { 296 code.run(); 297 } catch (Throwable t) { 298 caught = t; 299 } 300 if (predicate.test(caught)) { 301 System.out.println("Got expected exception: " + caught); 302 return caught; 303 } 304 if (caught == null) { 305 throw new AssertionFailedException("No exception was thrown"); 306 } 307 throw new AssertionFailedException("Caught exception didn't match the predicate", caught); 308 } 309 310 /* 311 * Blocking assertion, waits for completion 312 */ 313 static Throwable assertCompletesExceptionally(Class<? extends Throwable> clazz, 314 CompletionStage<?> stage) { 315 CompletableFuture<?> cf = 316 CompletableFuture.completedFuture(null).thenCompose(x -> stage); 317 return assertThrows(t -> clazz == t.getCause().getClass(), cf::get); 318 } 319 320 interface ThrowingProcedure { 321 void run() throws Throwable; 322 } 323 324 static final class AssertionFailedException extends RuntimeException { 325 326 private static final long serialVersionUID = 1L; 327 328 AssertionFailedException(String message) { 329 super(message); 330 } 331 332 AssertionFailedException(String message, Throwable cause) { 333 super(message, cause); 334 } 335 } 336 } |