@Test public void testChangeListener() throws InterruptedException { Map.Entry<DiscoveryService, DiscoveryServiceClient> entry = create(); DiscoveryService discoveryService = entry.getKey(); DiscoveryServiceClient discoveryServiceClient = entry.getValue(); // Start discovery String serviceName = "listener_test"; ServiceDiscovered serviceDiscovered = discoveryServiceClient.discover(serviceName); // Watch for changes. final BlockingQueue<List<Discoverable>> events = new ArrayBlockingQueue<List<Discoverable>>(10); serviceDiscovered.watchChanges( new ServiceDiscovered.ChangeListener() { @Override public void onChange(ServiceDiscovered serviceDiscovered) { events.add(ImmutableList.copyOf(serviceDiscovered)); } }, Threads.SAME_THREAD_EXECUTOR); // An empty list will be received first, as no endpoint has been registered. List<Discoverable> discoverables = events.poll(20, TimeUnit.SECONDS); Assert.assertNotNull(discoverables); Assert.assertTrue(discoverables.isEmpty()); // Register a service Cancellable cancellable = register(discoveryService, serviceName, "localhost", 10000); discoverables = events.poll(20, TimeUnit.SECONDS); Assert.assertNotNull(discoverables); Assert.assertEquals(1, discoverables.size()); // Register another service endpoint Cancellable cancellable2 = register(discoveryService, serviceName, "localhost", 10001); discoverables = events.poll(20, TimeUnit.SECONDS); Assert.assertNotNull(discoverables); Assert.assertEquals(2, discoverables.size()); // Cancel both of them cancellable.cancel(); cancellable2.cancel(); // There could be more than one event triggered, but the last event should be an empty list. discoverables = events.poll(20, TimeUnit.SECONDS); Assert.assertNotNull(discoverables); if (!discoverables.isEmpty()) { discoverables = events.poll(20, TimeUnit.SECONDS); } Assert.assertTrue(discoverables.isEmpty()); }
@Test public void testCancelChangeListener() throws InterruptedException { Map.Entry<DiscoveryService, DiscoveryServiceClient> entry = create(); DiscoveryService discoveryService = entry.getKey(); DiscoveryServiceClient discoveryServiceClient = entry.getValue(); String serviceName = "cancel_listener"; ServiceDiscovered serviceDiscovered = discoveryServiceClient.discover(serviceName); // An executor that delay execute a Runnable. It's for testing race because listener cancel and // discovery changes. Executor delayExecutor = new Executor() { @Override public void execute(final Runnable command) { Thread t = new Thread() { @Override public void run() { try { TimeUnit.SECONDS.sleep(2); command.run(); } catch (InterruptedException e) { throw Throwables.propagate(e); } } }; t.start(); } }; final BlockingQueue<List<Discoverable>> events = new ArrayBlockingQueue<List<Discoverable>>(10); Cancellable cancelWatch = serviceDiscovered.watchChanges( new ServiceDiscovered.ChangeListener() { @Override public void onChange(ServiceDiscovered serviceDiscovered) { events.add(ImmutableList.copyOf(serviceDiscovered)); } }, delayExecutor); // Wait for the init event call Assert.assertNotNull(events.poll(3, TimeUnit.SECONDS)); // Register a new service endpoint, wait a short while and then cancel the listener register(discoveryService, serviceName, "localhost", 1); TimeUnit.SECONDS.sleep(1); cancelWatch.cancel(); // The change listener shouldn't get any event, since the invocation is delayed by the executor. Assert.assertNull(events.poll(3, TimeUnit.SECONDS)); }
@Test public void simpleDiscoverable() throws Exception { Map.Entry<DiscoveryService, DiscoveryServiceClient> entry = create(); DiscoveryService discoveryService = entry.getKey(); DiscoveryServiceClient discoveryServiceClient = entry.getValue(); // Register one service running on one host:port Cancellable cancellable = register(discoveryService, "foo", "localhost", 8090); // Discover that registered host:port. ServiceDiscovered serviceDiscovered = discoveryServiceClient.discover("foo"); Assert.assertTrue(waitTillExpected(1, serviceDiscovered)); Discoverable discoverable = new Discoverable() { @Override public String getName() { return "foo"; } @Override public InetSocketAddress getSocketAddress() { return new InetSocketAddress("localhost", 8090); } }; // Check it exists. Assert.assertTrue(serviceDiscovered.contains(discoverable)); // Remove the service cancellable.cancel(); // There should be no service. Assert.assertTrue(waitTillExpected(0, serviceDiscovered)); Assert.assertFalse(serviceDiscovered.contains(discoverable)); }
@Test public void testIterator() throws InterruptedException { // This test is to verify TWILL-75 Map.Entry<DiscoveryService, DiscoveryServiceClient> entry = create(); final DiscoveryService service = entry.getKey(); DiscoveryServiceClient client = entry.getValue(); final String serviceName = "iterator"; ServiceDiscovered discovered = client.discover(serviceName); // Create a thread for performing registration. Thread t = new Thread() { @Override public void run() { service.register( new Discoverable() { @Override public String getName() { return serviceName; } @Override public InetSocketAddress getSocketAddress() { return new InetSocketAddress(12345); } }); } }; Iterator<Discoverable> iterator = discovered.iterator(); t.start(); t.join(); // This would throw exception if there is race condition. Assert.assertFalse(iterator.hasNext()); }
protected boolean waitTillExpected(final int expected, ServiceDiscovered serviceDiscovered) { final CountDownLatch latch = new CountDownLatch(1); serviceDiscovered.watchChanges( new ServiceDiscovered.ChangeListener() { @Override public void onChange(ServiceDiscovered serviceDiscovered) { if (expected == Iterables.size(serviceDiscovered)) { latch.countDown(); } } }, Threads.SAME_THREAD_EXECUTOR); try { return latch.await(60, TimeUnit.SECONDS); } catch (InterruptedException e) { throw Throwables.propagate(e); } }