|
58 | 58 | import java.time.Duration;
|
59 | 59 | import java.time.Instant;
|
60 | 60 | import java.util.ArrayList;
|
| 61 | +import java.util.Collections; |
| 62 | +import java.util.HashSet; |
61 | 63 | import java.util.List;
|
62 | 64 | import java.util.Map;
|
63 | 65 | import java.util.Optional;
|
64 | 66 | import java.util.Set;
|
65 | 67 | import java.util.UUID;
|
66 | 68 | import java.util.concurrent.Callable;
|
| 69 | +import java.util.concurrent.CompletableFuture; |
| 70 | +import java.util.concurrent.ConcurrentHashMap; |
| 71 | +import java.util.concurrent.ConcurrentSkipListSet; |
| 72 | +import java.util.concurrent.CountDownLatch; |
| 73 | +import java.util.concurrent.ExecutionException; |
| 74 | +import java.util.concurrent.ExecutorService; |
67 | 75 | import java.util.concurrent.Executors;
|
68 | 76 | import java.util.concurrent.Future;
|
69 | 77 | import java.util.concurrent.TimeUnit;
|
| 78 | +import java.util.concurrent.atomic.AtomicBoolean; |
| 79 | +import java.util.concurrent.atomic.AtomicInteger; |
70 | 80 |
|
| 81 | +import static java.util.Collections.newSetFromMap; |
71 | 82 | import static org.assertj.core.api.Assertions.assertThat;
|
72 | 83 | import static org.assertj.core.api.Assertions.fail;
|
73 | 84 | import static org.openqa.selenium.grid.data.Availability.DRAINING;
|
@@ -372,6 +383,82 @@ public void testDrainNodeFromNode() {
|
372 | 383 | assertThat(localNode.isDraining()).isTrue();
|
373 | 384 | }
|
374 | 385 |
|
| 386 | + @Test |
| 387 | + public void slowStartingNodesShouldNotCauseReservationsToBeSerialized() { |
| 388 | + NewSessionQueue queue = new LocalNewSessionQueue( |
| 389 | + tracer, |
| 390 | + bus, |
| 391 | + new DefaultSlotMatcher(), |
| 392 | + Duration.ofSeconds(2), |
| 393 | + Duration.ofSeconds(2), |
| 394 | + registrationSecret); |
| 395 | + |
| 396 | + LocalDistributor distributor = new LocalDistributor( |
| 397 | + tracer, |
| 398 | + bus, |
| 399 | + clientFactory, |
| 400 | + new LocalSessionMap(tracer, bus), |
| 401 | + queue, |
| 402 | + new GridModel(bus), |
| 403 | + new DefaultSlotSelector(), |
| 404 | + registrationSecret, |
| 405 | + Duration.ofMinutes(5), |
| 406 | + false); |
| 407 | + |
| 408 | + Capabilities caps = new ImmutableCapabilities("browserName", "cheese"); |
| 409 | + |
| 410 | + long delay = 4000; |
| 411 | + LocalNode node = LocalNode.builder(tracer, bus, uri, uri, registrationSecret) |
| 412 | + .add(caps, new TestSessionFactory(caps, (id, c) -> { |
| 413 | + try { |
| 414 | + Thread.sleep(delay); |
| 415 | + } catch (InterruptedException e) { |
| 416 | + e.printStackTrace(); |
| 417 | + } |
| 418 | + return new Handler(c); |
| 419 | + })) |
| 420 | + .build(); |
| 421 | + |
| 422 | + distributor.add(node); |
| 423 | + |
| 424 | + Set<Future<Either<SessionNotCreatedException, CreateSessionResponse>>> futures = |
| 425 | + newSetFromMap(new ConcurrentHashMap<>()); |
| 426 | + ExecutorService service = Executors.newFixedThreadPool(2); |
| 427 | + |
| 428 | + long start = System.currentTimeMillis(); |
| 429 | + futures.add( |
| 430 | + service.submit(() -> distributor.newSession(new SessionRequest( |
| 431 | + new RequestId(UUID.randomUUID()), |
| 432 | + Instant.now(), |
| 433 | + Set.of(W3C), |
| 434 | + Set.of(caps), |
| 435 | + Map.of(), |
| 436 | + Map.of())))); |
| 437 | + futures.add( |
| 438 | + service.submit(() -> distributor.newSession(new SessionRequest( |
| 439 | + new RequestId(UUID.randomUUID()), |
| 440 | + Instant.now(), |
| 441 | + Set.of(W3C), |
| 442 | + Set.of(caps), |
| 443 | + Map.of(), |
| 444 | + Map.of())))); |
| 445 | + |
| 446 | + futures.forEach(f -> { |
| 447 | + try { |
| 448 | + f.get(); |
| 449 | + } catch (InterruptedException e) { |
| 450 | + fail("Interrupted"); |
| 451 | + } catch (ExecutionException e) { |
| 452 | + throw new RuntimeException(e); |
| 453 | + } |
| 454 | + }); |
| 455 | + |
| 456 | + // If the sessions are created serially, then we expect the first |
| 457 | + // session to take up to `delay` ms to complete, followed by the |
| 458 | + // second session. |
| 459 | + assertThat(System.currentTimeMillis() - start).isLessThan(delay * 2); |
| 460 | + } |
| 461 | + |
375 | 462 | private class Handler extends Session implements HttpHandler {
|
376 | 463 |
|
377 | 464 | private Handler(Capabilities capabilities) {
|
|
0 commit comments