static void flushAndWait(Connection nc, TestHandler handler) { try { nc.flush(Duration.ofSeconds(1)); } catch (Exception exp) { } handler.waitForStatusChange(15, TimeUnit.SECONDS); }
@Override public CompletableFuture<BenchmarkConsumer> createConsumer(String topic, String subscriptionName, ConsumerCallback consumerCallback) { Dispatcher natsConsumer; Connection cn; log.info("createConsumer"); try { Options options = new Options.Builder().server(config.natsHostUrl).maxReconnects(5).build(); cn = Nats.connect(options); natsConsumer = cn.createDispatcher((msg) -> { consumerCallback.messageReceived(msg.getData(), Long.parseLong(msg.getReplyTo())); }); natsConsumer.subscribe(topic, subscriptionName); cn.flush(Duration.ZERO); } catch (Exception e) { log.error("createConsumer excetopin " + e); return null; } log.info("createCOnsumer done"); return CompletableFuture.completedFuture(new NatsBenchmarkConsumer(cn)); }
@Test public void testDispatchHandlesExceptionInHandler() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { final CompletableFuture<Boolean> done = new CompletableFuture<>(); int msgCount = 100; assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final ConcurrentLinkedQueue<Message> q = new ConcurrentLinkedQueue<>(); Dispatcher d = nc.createDispatcher((msg) -> { if (msg.getSubject().equals("done")) { done.complete(Boolean.TRUE); } else { q.add(msg); throw new NumberFormatException(); } }); d.subscribe("subject"); d.subscribe("done"); nc.flush(Duration.ofMillis(500));// Get them all to the server for (int i = 0; i < msgCount; i++) { nc.publish("subject", new byte[16]); } nc.publish("done", new byte[16]); nc.flush(Duration.ofMillis(1000)); // wait for them to go through done.get(200, TimeUnit.MILLISECONDS); assertEquals(msgCount, q.size()); } }
@Test public void testUnsubFromCallback() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { final CompletableFuture<Boolean> done = new CompletableFuture<>(); assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final AtomicReference<Dispatcher> dispatcher = new AtomicReference<>(); final ConcurrentLinkedQueue<Message> q = new ConcurrentLinkedQueue<>(); final Dispatcher d = nc.createDispatcher((msg) -> { if (msg.getSubject().equals("done")) { done.complete(Boolean.TRUE); } else { q.add(msg); dispatcher.get().unsubscribe("subject"); } }); dispatcher.set(d); d.subscribe("subject"); d.subscribe("done"); nc.flush(Duration.ofMillis(500));// Get them all to the server nc.publish("subject", new byte[16]); nc.publish("subject", new byte[16]); nc.publish("done", new byte[16]); // when we get this we know the others are dispatched nc.flush(Duration.ofMillis(1000)); // Wait for the publish, or we will get multiples for sure done.get(200, TimeUnit.MILLISECONDS); // make sure we got them assertEquals(1, q.size()); } }
@Test public void testMultiMessage() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { final CompletableFuture<Boolean> done = new CompletableFuture<>(); int msgCount = 100; assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final ConcurrentLinkedQueue<Message> q = new ConcurrentLinkedQueue<>(); Dispatcher d = nc.createDispatcher((msg) -> { if (msg.getSubject().equals("done")) { done.complete(Boolean.TRUE); } else { q.add(msg); } }); d.subscribe("subject"); d.subscribe("done"); nc.flush(Duration.ofMillis(1000)); // wait for them to go through for (int i = 0; i < msgCount; i++) { nc.publish("subject", new byte[16]); } nc.publish("done", new byte[16]); nc.flush(Duration.ofMillis(1000)); // wait for them to go through done.get(500, TimeUnit.MILLISECONDS); assertEquals(msgCount, q.size()); } }
@Test public void testPublishAndFlushFromCallback() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final CompletableFuture<Message> msgFuture = new CompletableFuture<>(); Dispatcher d = nc.createDispatcher((msg) -> { try { nc.flush(Duration.ofMillis(1000)); } catch (Exception ex) { System.out.println("!!! Exception in callback"); ex.printStackTrace(); } msgFuture.complete(msg); }); d.subscribe("subject"); nc.flush(Duration.ofMillis(500));// Get them all to the server nc.publish("subject", new byte[16]); // publish one to kick it off Message msg = msgFuture.get(500, TimeUnit.MILLISECONDS); assertNotNull(msg); assertEquals(2, ((NatsStatistics)(nc.getStatistics())).getFlushCounter()); } }
@Test(expected = IllegalStateException.class) public void testUnsubscribeWhileWaiting() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); Subscription sub = nc.subscribe("subject"); nc.flush(Duration.ofMillis(1000)); Thread t = new Thread(()->{ try { Thread.sleep(100); }catch(Exception e){} sub.unsubscribe(); }); t.start(); sub.nextMessage(Duration.ofMillis(5000)); // Should throw assertTrue(false); } } }
@Test(expected = IllegalStateException.class) public void testCantUnsubSubFromDispatcher() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final CompletableFuture<Message> msgFuture = new CompletableFuture<>(); Dispatcher d = nc.createDispatcher((msg) -> { msgFuture.complete(msg); }); d.subscribe("subject"); nc.flush(Duration.ofMillis(500));// Get them all to the server nc.publish("subject", new byte[16]); Message msg = msgFuture.get(500, TimeUnit.MILLISECONDS); msg.getSubscription().unsubscribe(); // Should throw assertFalse(true); } }
@Test(expected = IllegalStateException.class) public void testCantAutoUnsubSubFromDispatcher() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final CompletableFuture<Message> msgFuture = new CompletableFuture<>(); Dispatcher d = nc.createDispatcher((msg) -> { msgFuture.complete(msg); }); d.subscribe("subject"); nc.flush(Duration.ofMillis(500));// Get them all to the server nc.publish("subject", new byte[16]); Message msg = msgFuture.get(500, TimeUnit.MILLISECONDS); msg.getSubscription().unsubscribe(1); // Should throw assertFalse(true); } }
@Test(expected = IllegalStateException.class) public void testSubDuringDrainThrows() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build()); Connection pubCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); assertTrue("Connected Status", Connection.Status.CONNECTED == pubCon.getStatus()); subCon.subscribe("draintest"); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server pubCon.publish("draintest", null); pubCon.publish("draintest", null); pubCon.flush(Duration.ofSeconds(1)); subCon.flush(Duration.ofSeconds(1)); CompletableFuture<Boolean> tracker = subCon.drain(Duration.ofSeconds(500)); // Try to subscribe while we are draining the sub subCon.subscribe("another"); // Should throw assertTrue(tracker.get(1000, TimeUnit.SECONDS)); } }
@Test(expected = IllegalStateException.class) public void testCreateDispatcherDuringDrainThrows() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build()); Connection pubCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); assertTrue("Connected Status", Connection.Status.CONNECTED == pubCon.getStatus()); subCon.subscribe("draintest"); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server pubCon.publish("draintest", null); pubCon.publish("draintest", null); pubCon.flush(Duration.ofSeconds(1)); subCon.flush(Duration.ofSeconds(1)); CompletableFuture<Boolean> tracker = subCon.drain(Duration.ofSeconds(500)); subCon.createDispatcher((msg) -> { }); assertTrue(tracker.get(1000, TimeUnit.SECONDS)); } }
@Test(expected = TimeoutException.class) public void throwsIfClosedOnFlush() throws IOException, TimeoutException, InterruptedException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { nc.close(); nc.flush(null); assertFalse(true); } }
@Test public void testHumanReadableString() throws Exception { // This test is purely for coverage, any test without a human is likely pedantic try (NatsTestServer ts = new NatsTestServer(); Connection nc = Nats.connect(new Options.Builder() .server(ts.getURI()) .turnOnAdvancedStats() .build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); Dispatcher d = nc.createDispatcher((msg) -> { nc.publish(msg.getReplyTo(), new byte[16]); }); d.subscribe("subject"); nc.flush(Duration.ofMillis(500)); Future<Message> incoming = nc.request("subject", new byte[8]); nc.flush(Duration.ofMillis(500)); Message msg = incoming.get(500, TimeUnit.MILLISECONDS); String str = nc.getStatistics().toString(); assertNotNull(msg); assertNotNull(str); assertTrue(str.length() > 0); assertTrue(str.contains("### Connection ###")); assertTrue(str.contains("Socket Writes")); } }
@Test(expected=IllegalStateException.class) public void testFirstTimeRequestReplyDuringDrain() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build()); Connection pubCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); assertTrue("Connected Status", Connection.Status.CONNECTED == pubCon.getStatus()); Subscription sub = subCon.subscribe("draintest"); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server Dispatcher d = pubCon.createDispatcher((msg) -> { pubCon.publish(msg.getReplyTo(), null); }); d.subscribe("reply"); pubCon.flush(Duration.ofSeconds(1)); // Get the sub to the server pubCon.publish("draintest", null); pubCon.publish("draintest", null); pubCon.flush(Duration.ofSeconds(1)); CompletableFuture<Boolean> tracker = subCon.drain(Duration.ofSeconds(500)); Message msg = sub.nextMessage(Duration.ofSeconds(1)); // read 1 assertNotNull(msg); CompletableFuture<Message> response = subCon.request("reply", null); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server assertNotNull(response.get(200, TimeUnit.SECONDS)); msg = sub.nextMessage(Duration.ofSeconds(1)); // read 1 assertNotNull(msg); assertTrue(tracker.get(500, TimeUnit.SECONDS)); // wait for the drain to complete assertTrue(Connection.Status.CLOSED == subCon.getStatus()); } }
@Test public void testDrainWithZeroTimeout() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build()); Connection pubCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); assertTrue("Connected Status", Connection.Status.CONNECTED == pubCon.getStatus()); Subscription sub = subCon.subscribe("draintest"); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server pubCon.publish("draintest", null); pubCon.publish("draintest", null); // publish 2 pubCon.flush(Duration.ofSeconds(1)); Message msg = sub.nextMessage(Duration.ofSeconds(1)); // read 1 assertNotNull(msg); subCon.flush(Duration.ofSeconds(1)); CompletableFuture<Boolean> tracker = sub.drain(Duration.ZERO); msg = sub.nextMessage(Duration.ofSeconds(1)); // read the second one, should be there because we drained assertNotNull(msg); assertTrue(tracker.get(1, TimeUnit.SECONDS)); assertFalse(sub.isActive()); } }
@Test public void testSimpleSubDrain() throws Exception { try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build()); Connection pubCon = Nats.connect(new Options.Builder().server(ts.getURI()).maxReconnects(0).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); assertTrue("Connected Status", Connection.Status.CONNECTED == pubCon.getStatus()); Subscription sub = subCon.subscribe("draintest"); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server pubCon.publish("draintest", null); pubCon.publish("draintest", null); // publish 2 pubCon.flush(Duration.ofSeconds(1)); Message msg = sub.nextMessage(Duration.ofSeconds(1)); // read 1 assertNotNull(msg); subCon.flush(Duration.ofSeconds(1)); CompletableFuture<Boolean> tracker = sub.drain(Duration.ofSeconds(1)); msg = sub.nextMessage(Duration.ofSeconds(1)); // read the second one, should be there because we drained assertNotNull(msg); assertTrue(tracker.get(1, TimeUnit.SECONDS)); assertFalse(sub.isActive()); assertEquals(((NatsConnection) subCon).getConsumerCount(), 0); } }
@Test(expected = IllegalStateException.class) public void testAutoUnsubAfterMaxIsReached() throws IOException, InterruptedException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { int msgCount = 10; assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); Subscription sub = nc.subscribe("subject"); for (int i = 0; i < msgCount; i++) { nc.publish("subject", new byte[16]); } nc.flush(Duration.ofMillis(1000)); // Slow things down so we have time to unsub for (int i = 0; i < msgCount; i++) { sub.nextMessage(null); } sub.unsubscribe(msgCount); // we already have that many sub.nextMessage(Duration.ofMillis(500)); // Will throw an exception assertFalse(true); } }
@Test(expected=TimeoutException.class) public void testThrowIfCantFlush() throws Exception { TestHandler handler = new TestHandler(); try (NatsTestServer ts = new NatsTestServer(false); Connection subCon = Nats.connect(new Options.Builder().connectionListener(handler).server(ts.getURI()).build())) { assertTrue("Connected Status", Connection.Status.CONNECTED == subCon.getStatus()); subCon.flush(Duration.ofSeconds(1)); // Get the sub to the server handler.prepForStatusChange(Events.DISCONNECTED); ts.close(); // make the drain flush fail handler.waitForStatusChange(2, TimeUnit.SECONDS); // make sure the connection is down subCon.drain(Duration.ofSeconds(1)); //should throw } }
@Test public void testSingleMessage() throws IOException, InterruptedException, ExecutionException, TimeoutException { try (NatsTestServer ts = new NatsTestServer(false); Connection nc = Nats.connect(ts.getURI())) { assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus()); final CompletableFuture<Message> msgFuture = new CompletableFuture<>(); Dispatcher d = nc.createDispatcher((msg) -> { msgFuture.complete(msg); }); d.subscribe("subject"); nc.flush(Duration.ofMillis(500));// Get them all to the server nc.publish("subject", new byte[16]); Message msg = msgFuture.get(500, TimeUnit.MILLISECONDS); assertTrue(d.isActive()); assertEquals("subject", msg.getSubject()); assertNotNull(msg.getSubscription()); assertNull(msg.getReplyTo()); assertEquals(16, msg.getData().length); } }