public void TestInvalidSubjects() { EventHandler <MsgHandlerEventArgs> mh = (obj, args) => { /* NOOP */ }; using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var c = Context.OpenConnection(Context.Server1.Port)) { foreach (string s in invalidSubjects) { Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeSync(s)); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeSync(s, "qgroup")); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync(s)); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync(s, mh)); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync(s, "qgroup")); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync(s, "qgroup", mh)); } foreach (string s in invalidQNames) { Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeSync("subject", s)); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync("subject", s)); Assert.Throws <NATSBadSubscriptionException>(() => c.SubscribeAsync("subject", s, mh)); } } } }
public void TestReconnectDisallowedFlags() { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.AllowReconnect = false; Object testLock = new Object(); opts.ClosedEventHandler = (sender, args) => { lock (testLock) { Monitor.Pulse(testLock); } }; using (NATSServer ns = NATSServer.Create(Context.Server1.Port)) { using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { lock (testLock) { ns.Shutdown(); Assert.True(Monitor.Wait(testLock, 1000)); } } } }
public void TestReconnectWaitJitter() { AutoResetEvent reconnected = new AutoResetEvent(false); Stopwatch sw = new Stopwatch(); var opts = Context.GetTestOptions(Context.Server1.Port); opts.ReconnectWait = 100; opts.SetReconnectJitter(500, 0); opts.ReconnectedEventHandler = (obj, args) => { sw.Stop(); reconnected.Set(); }; using (var s = NATSServer.Create(Context.Server1.Port)) { // Create our client connections. using (new ConnectionFactory().CreateConnection(opts)) { sw.Start(); s.Bounce(50); Assert.True(reconnected.WaitOne(5000)); } } // We should wait at least the reconnect wait + random up to 500ms. // Account for a bit of variation since we rely on the reconnect // handler which is not invoked in place. Assert.InRange(sw.ElapsedMilliseconds, 100, 800); }
public void TestReconnectAuthTimeout() { AutoResetEvent ev = new AutoResetEvent(false); using (NATSServer s1 = util.CreateServerWithConfig("auth_1222.conf"), s2 = util.CreateServerWithConfig("auth_1223_timeout.conf"), s3 = util.CreateServerWithConfig("auth_1224.conf")) { Options opts = util.DefaultTestOptions; opts.Servers = new string[] { "nats://*****:*****@localhost:1222", "nats://*****:*****@localhost:1223", "nats://*****:*****@localhost:1224" }; opts.NoRandomize = true; opts.ReconnectedEventHandler += (sender, args) => { ev.Set(); }; IConnection c = new ConnectionFactory().CreateConnection(opts); s1.Shutdown(); // This should fail over to S2 where an authorization timeout occurs // then successfully reconnect to S3. Assert.True(ev.WaitOne(20000)); } }
public void TestBasicReconnectFunctionality() { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.MaxReconnect = 2; opts.ReconnectWait = 1000; AutoResetEvent Disconnected = new AutoResetEvent(false); AutoResetEvent Reconnected = new AutoResetEvent(false); AutoResetEvent MessageArrived = new AutoResetEvent(false); Object testLock = new Object(); Object msgLock = new Object(); opts.DisconnectedEventHandler = (sender, args) => { Disconnected.Set(); }; opts.ReconnectedEventHandler = (sender, args) => { Reconnected.Set(); }; using (var ns1 = NATSServer.Create(Context.Server1.Port)) { using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { using (var s = c.SubscribeAsync("foo")) { s.MessageHandler += (sender, args) => { MessageArrived.Set(); }; s.Start(); c.Flush(); lock (testLock) { ns1.Shutdown(); Assert.True(Disconnected.WaitOne(100000)); } c.Publish("foo", Encoding.UTF8.GetBytes("Hello")); // restart the server. using (NATSServer.Create(Context.Server1.Port)) { Assert.True(Reconnected.WaitOne(20000)); Assert.True(c.Stats.Reconnects == 1); c.Flush(5000); Assert.True(MessageArrived.WaitOne(20000)); } } } } }
public void WhenDisposingAnObserverItShouldNotReceiveMoreMessages() { sync = TestSync.TwoActors(); var subject = "415b09873e3348d3a953e93d35ff61bf"; var payload1 = SamplePayload.Random(); var payload2 = SamplePayload.Random(); using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { var interceptingOb1 = new TestObserver(_ => sync.SignalComplete()); var interceptingOb2 = new TestObserver(_ => sync.SignalComplete()); using (var cn = Context.OpenConnection(Context.Server1.Port)) { using (var observable = cn.Observe(subject)) { using (observable.Subscribe(interceptingOb1)) { using (observable.Subscribe(interceptingOb2)) { cn.Publish(subject, payload1); sync.WaitForAll(); } cn.Publish(subject, payload2); sync.WaitForOne(); } Assert.Equal(new[] { payload1.Data, payload2.Data }, interceptingOb1.OnNextResults.Select(i => i.Data).ToArray()); Assert.Equal(new[] { payload1.Data }, interceptingOb2.OnNextResults.Select(i => i.Data).ToArray()); } } } }
public void TestServersOption() { ConnectionFactory cf = Context.ConnectionFactory; Options o = Context.GetTestOptions(); o.NoRandomize = true; o.Servers = Context.GetTestServersUrls(); Assert.ThrowsAny <NATSNoServersException>(() => cf.CreateConnection(o)); // Make sure we can connect to first server if running using (NATSServer ns = NATSServer.Create(Context.Server1.Port)) { using (var c = cf.CreateConnection(o)) { Assert.Equal(Context.Server1.Url, c.ConnectedUrl); c.Close(); } } // make sure we can connect to a non-first server. using (NATSServer.Create(Context.Server6.Port)) { using (var c = cf.CreateConnection(o)) { Assert.Equal(Context.Server6.Url, c.ConnectedUrl); c.Close(); } } }
public void TestSyncSubscriptionPendingDrain() { int total = 100; byte[] data = Encoding.UTF8.GetBytes("0123456789"); using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (IConnection c = Context.OpenConnection(Context.Server1.Port)) { using (var s = c.SubscribeSync("foo")) { for (int i = 0; i < total; i++) { c.Publish("foo", data); } c.Flush(); while (s.Delivered != total) { s.NextMessage(100); } Assert.True(s.Dropped == 0); Assert.True(s.PendingBytes == 0); Assert.True(s.PendingMessages == 0); s.Unsubscribe(); } } } }
public void TestTlsReconnectAuthTimeout() { AutoResetEvent ev = new AutoResetEvent(false); using (NATSServer s1 = NATSServer.CreateWithConfig(Context.Server1.Port, "auth_tls.conf"), s2 = NATSServer.CreateWithConfig(Context.Server2.Port, "auth_tls_timeout.conf"), s3 = NATSServer.CreateWithConfig(Context.Server3.Port, "auth_tls.conf")) { Options opts = Context.GetTestOptions(); opts.Secure = true; opts.NoRandomize = true; opts.TLSRemoteCertificationValidationCallback = verifyServerCert; opts.Servers = new[] { $"nats://*****:*****@localhost:{Context.Server1.Port}", $"nats://*****:*****@localhost:{Context.Server2.Port}", $"nats://*****:*****@localhost:{Context.Server3.Port}" }; opts.ReconnectedEventHandler += (sender, args) => { ev.Set(); }; using (Context.ConnectionFactory.CreateConnection(opts)) { s1.Shutdown(); // This should fail over to S2 where an authorization timeout occurs // then successfully reconnect to S3. Assert.True(ev.WaitOne(20000)); } } }
public void TestSlowSubscriber() { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.SubChannelLength = 10; using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { using (ISyncSubscription s = c.SubscribeSync("foo")) { Assert.ThrowsAny <Exception>(() => { for (int i = 0; i < (opts.SubChannelLength + 100); i++) { c.Publish("foo", null); } try { c.Flush(); } catch (Exception) { // ignore } s.NextMessage(); }); } } } }
public void TestServerAutoUnsub() { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (IConnection c = Context.OpenConnection(Context.Server1.Port)) { long received = 0; int max = 10; using (IAsyncSubscription s = c.SubscribeAsync("foo")) { s.MessageHandler += (sender, arg) => { received++; }; s.AutoUnsubscribe(max); s.Start(); for (int i = 0; i < (max * 2); i++) { c.Publish("foo", Encoding.UTF8.GetBytes("hello")); } c.Flush(); Thread.Sleep(500); Assert.Equal(max, received); Assert.False(s.IsValid); } } } }
public void TestValidSubscriber() { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (IConnection c = Context.OpenConnection(Context.Server1.Port)) { using (ISyncSubscription s = c.SubscribeSync("foo")) { Assert.True(s.IsValid); try { s.NextMessage(100); } catch (NATSTimeoutException) { } Assert.True(s.IsValid); s.Unsubscribe(); Assert.False(s.IsValid); try { s.NextMessage(100); } catch (NATSBadSubscriptionException) { } } } } }
public void TestRespondFailsWithServerClosed() { Msg m; using (NATSServer ns = NATSServer.CreateFastAndVerify(Context.Server1.Port)) { Options options = Context.GetTestOptions(Context.Server1.Port); options.AllowReconnect = false; using (var c = Context.ConnectionFactory.CreateConnection(options)) { using (var s = c.SubscribeSync("foo")) { string replyTo = c.NewInbox(); c.Publish("foo", replyTo, Encoding.UTF8.GetBytes("message")); m = s.NextMessage(1000); Assert.NotNull(m); Assert.Equal(replyTo, m.Reply); ns.Shutdown(); // Give the server time to close Thread.Sleep(2000); byte[] reply = Encoding.UTF8.GetBytes("reply"); Assert.ThrowsAny <NATSConnectionClosedException>(() => m.Respond(reply)); } } } }
public void TestRespondWithAutoUnsubscribe() { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (IConnection c = Context.OpenConnection(Context.Server1.Port)) using (ISyncSubscription s = c.SubscribeSync("foo")) { s.AutoUnsubscribe(1); string replyTo = c.NewInbox(); using (ISyncSubscription r = c.SubscribeSync(replyTo)) { c.Publish("foo", replyTo, Encoding.UTF8.GetBytes("message")); Msg m = s.NextMessage(1000); Assert.NotNull(m); Assert.Equal(replyTo, m.Reply); byte[] reply = Encoding.UTF8.GetBytes("reply"); m.Respond(reply); m = r.NextMessage(1000); Assert.NotNull(m); Assert.Equal(replyTo, m.Subject); Assert.Equal(reply, m.Data); r.Unsubscribe(); } } } }
public void EnsureDrainAsync() { var subject = "5dc823d90cab46679e0bf51afffda767"; var q = new ConcurrentQueue <int>(); AsyncContext.Run(async() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var sync = TestSync.SingleActor()) { var opts = Context.GetTestOptions(Context.Server1.Port); opts.ClosedEventHandler = (sender, args) => { q.Enqueue(1); sync.SignalComplete(); }; using (var cn = Context.ConnectionFactory.CreateConnection(opts)) { for (var i = 0; i < 50; i++) { cn.Publish(subject, new[] { (byte)i }); } await cn.DrainAsync(); sync.WaitForAll(); Assert.Single(q); } } } }); }
public void TestTlsSuccessWithCert() { using (NATSServer srv = NATSServer.CreateWithConfig(Context.Server1.Port, "tls_verify.conf")) { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.Secure = true; opts.TLSRemoteCertificationValidationCallback = verifyServerCert; // .NET requires the private key and cert in the // same file. 'client.pfx' is generated from: // // openssl pkcs12 -export -out client.pfx // -inkey client-key.pem -in client-cert.pem X509Certificate2 cert = new X509Certificate2( UnitTestUtilities.GetFullCertificatePath("client.pfx"), "password"); opts.AddCertificate(cert); using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { using (ISyncSubscription s = c.SubscribeSync("foo")) { c.Publish("foo", null); c.Flush(); Msg m = s.NextMessage(); } } } }
public void WhenObservingMoreThanOneSubjectTheyShouldNotInterfere() { sync = TestSync.TwoActors(); var subject1 = "eaa520002f1f42b0b5e2d0e162822780"; var subject2 = "319198581087493da52b48c96de2bf7e"; var payload1 = SamplePayload.Random(); var payload2 = SamplePayload.Random(); using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.OpenConnection(Context.Server1.Port)) { using (var observable1 = cn.Observe(subject1)) using (var observable2 = cn.Observe(subject2)) { var interceptingOb1 = new TestObserver(_ => sync.SignalComplete()); var interceptingOb2 = new TestObserver(_ => sync.SignalComplete()); observable1.Subscribe(interceptingOb1); observable2.Subscribe(interceptingOb2); cn.Publish(subject1, payload1); cn.Publish(subject2, payload2); sync.WaitForAll(); Assert.Equal(payload1, interceptingOb1.OnNextResults.Single()); Assert.Equal(payload2, interceptingOb2.OnNextResults.Single()); } } } }
public void EnsureRequestResponderWithFlush() { var subject = "67870ca086184482b52815d288a4388e"; var replies = new ConcurrentQueue <Msg>(); AsyncContext.Run(() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.ConnectionFactory.CreateConnection(Context.Server1.Url)) { using (cn.SubscribeAsync(subject, (_, m) => m.Message.Respond(m.Message.Data))) { for (var i = 0; i < 5; i++) { var reply = cn.Request(subject, new[] { (byte)i }); cn.Flush(); cn.FlushBuffer(); replies.Enqueue(reply); } } } Assert.Equal(5, replies.Count); } }); }
public void WhenSubscribingMoreThanOneObserverToTheObservableOnlyOneServerSubscriptionShouldBeSetup() { sync = TestSync.FourActors(); var subject = "eaa520002f1f42b0b5e2d0e162822780"; var payload = SamplePayload.Random(); using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.OpenConnection(Context.Server1.Port)) { using (var observable = cn.Observe(subject)) { var interceptingOb = new TestObserver(_ => sync.SignalComplete()); var interceptingSafeOb = new TestObserver(_ => sync.SignalComplete()); observable.Subscribe(interceptingOb); observable.Subscribe(interceptingSafeOb); observable.Subscribe(_ => sync.SignalComplete()); observable.SubscribeSafe(_ => sync.SignalComplete()); cn.Publish(subject, payload); sync.WaitForAll(); Assert.Equal(1, cn.SubscriptionCount); } } } }
public void EnsureRequestAsyncResponderWithFlush() { var subject = "3cce135bef9348209dacf9acfc75427e"; var replies = new ConcurrentQueue <Msg>(); AsyncContext.Run(async() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.ConnectionFactory.CreateConnection(Context.Server1.Url)) { using (cn.SubscribeAsync(subject, (_, m) => m.Message.Respond(m.Message.Data))) { for (var i = 0; i < 5; i++) { var reply = await cn.RequestAsync(subject, new[] { (byte)i }); cn.Flush(); cn.FlushBuffer(); replies.Enqueue(reply); } } } Assert.Equal(5, replies.Count); } }); }
public void TestAuthServers() { Options opts = Context.GetTestOptions(); opts.NoRandomize = true; opts.Servers = new [] { Context.Server1.Url, Context.Server3.Url }; opts.Timeout = 5000; using (NATSServer as1 = NATSServer.CreateWithConfig(Context.Server1.Port, "auth.conf"), as2 = NATSServer.CreateWithConfig(Context.Server3.Port, "auth.conf")) { Assert.ThrowsAny <NATSException>(() => Context.ConnectionFactory.CreateConnection(opts)); // Test that we can connect to a subsequent correct server. var authServers = new[] { Context.Server1.Url, $"nats://*****:*****@localhost:{Context.Server3.Port}" }; opts.Servers = authServers; using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { Assert.Equal(authServers[1], c.ConnectedUrl); } } }
public void EnsureDrain() { var subject = "176bb0976ef943e3988de4957c9e1a1a"; var q = new ConcurrentQueue <int>(); AsyncContext.Run(() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var sync = TestSync.SingleActor()) { var opts = Context.GetTestOptions(Context.Server1.Port); opts.ClosedEventHandler = (sender, args) => { q.Enqueue(1); sync.SignalComplete(); }; using (var cn = Context.ConnectionFactory.CreateConnection(opts)) { for (var i = 0; i < 50; i++) { cn.Publish(subject, new[] { (byte)i }); } cn.Drain(); sync.WaitForAll(); Assert.Single(q); } } } }); }
public static NATSServer CreateFastAndVerify(int port, string args = null) { var server = new NATSServer(TimeSpan.Zero, port, args); var cf = new ConnectionFactory(); var opts = ConnectionFactory.GetDefaultOptions(); opts.Url = $"nats://localhost:{port}"; var isVerifiedOk = false; for (int i = 0; i < 10; i++) { try { using (var c = cf.CreateConnection(opts)) c.Close(); isVerifiedOk = true; break; } catch { Thread.Sleep(i * 250); } } if (!isVerifiedOk) { throw new Exception($"Could not connect to test NATS-Server at '{opts.Url}'"); } return(server); }
public void EnsureAutoUnsubscribeForSyncSub() { var subject = "de82267b22454dd7afc37c9e34a8e0ab"; var recieved = new ConcurrentQueue <Msg>(); AsyncContext.Run(() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.ConnectionFactory.CreateConnection(Context.Server1.Url)) { using (var sub = cn.SubscribeSync(subject)) { sub.AutoUnsubscribe(1); cn.Publish(subject, new byte[0]); recieved.Enqueue(sub.NextMessage()); cn.Publish(subject, new byte[0]); Assert.Equal(1, sub.Delivered); } } Assert.Single(recieved); } }); }
public void TestClose() { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.AllowReconnect = true; opts.MaxReconnect = 60; using (NATSServer s1 = NATSServer.Create(Context.Server1.Port)) { using (var c = Context.ConnectionFactory.CreateConnection(opts)) { Assert.False(c.IsClosed()); s1.Shutdown(); Thread.Sleep(100); Assert.False(c.IsClosed(), string.Format("Invalid state, expecting not closed, received: {0}", c.State)); using (NATSServer s2 = NATSServer.Create(Context.Server1.Port)) { Thread.Sleep(1000); Assert.False(c.IsClosed()); c.Close(); Assert.True(c.IsClosed()); } } } }
public void EnsureUnsubscribeForSyncSub() { var subject = "b2dcc4f56fd041cb985300d4966bd1c1"; var recieved = new ConcurrentQueue <Msg>(); AsyncContext.Run(() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var cn = Context.ConnectionFactory.CreateConnection(Context.Server1.Url)) { using (var sub = cn.SubscribeSync(subject)) { cn.Publish(subject, new byte[0]); recieved.Enqueue(sub.NextMessage()); sub.Unsubscribe(); cn.Publish(subject, new byte[0]); Assert.Throws <NATSBadSubscriptionException>(sub.NextMessage); Assert.Equal(1, sub.Delivered); } } Assert.Single(recieved); } }); }
public void TestReconnectBufferBoundary() { AutoResetEvent disconnected = new AutoResetEvent(false); var opts = Context.GetTestOptions(Context.Server1.Port); opts.ReconnectBufferSize = 32; // 32 bytes opts.DisconnectedEventHandler = (obj, args) => { disconnected.Set(); }; EventHandler <MsgHandlerEventArgs> eh = (obj, args) => { /* NOOP */ }; using (var server = NATSServer.Create(Context.Server1.Port)) { using (var c = new ConnectionFactory().CreateConnection(opts)) { using (c.SubscribeAsync("foo", eh)) { server.Shutdown(); // wait until we're disconnected. Assert.True(disconnected.WaitOne(5000)); // PUB foo 25\r\n<...> = 30 so first publish should be OK, 2nd publish // should fail. byte[] payload = new byte[18]; c.Publish("foo", payload); Assert.Throws <NATSReconnectBufferException>(() => c.Publish("foo", payload)); c.Close(); } } } }
public void EnsureUnsubscribeForAsyncSub() { var subject = "d37e3729c5c84702b836a4bb4edf7241"; var recieved = new ConcurrentQueue <Msg>(); AsyncContext.Run(async() => { using (NATSServer.CreateFastAndVerify(Context.Server1.Port)) { using (var sync = TestSync.SingleActor()) { using (var cn = Context.ConnectionFactory.CreateConnection(Context.Server1.Url)) { using (var sub = cn.SubscribeAsync(subject, (_, m) => { recieved.Enqueue(m.Message); sync.SignalComplete(); })) { cn.Publish(subject, new byte[0]); sync.WaitForAll(); sub.Unsubscribe(); cn.Publish(subject, new byte[0]); await Task.Delay(100); Assert.Equal(1, sub.Delivered); } } Assert.Single(recieved); } } }); }
public void TestReconnectWaitBreakOnClose() { var opts = Context.GetTestOptions(Context.Server1.Port); opts.ReconnectWait = 30000; using (var s = NATSServer.Create(Context.Server1.Port)) { // Create our client connections. using (var c = new ConnectionFactory().CreateConnection(opts)) { Stopwatch sw = Stopwatch.StartNew(); s.Shutdown(); // Wait a bit for the reconnect loop to go into wait mode. Thread.Sleep(250); // Close the connection to break waiting c.Close(); sw.Stop(); // It should be around 400 ms max, but only need to check that // it's less than 30000. Assert.True(sw.ElapsedMilliseconds < 30000); } } }
public void TestReconnectAllowedFlags() { Options opts = Context.GetTestOptions(Context.Server1.Port); opts.MaxReconnect = 2; opts.ReconnectWait = 1000; Object testLock = new Object(); opts.ClosedEventHandler = (sender, args) => { lock (testLock) { Monitor.Pulse(testLock); } }; using (NATSServer ns = NATSServer.Create(Context.Server1.Port)) { using (IConnection c = Context.ConnectionFactory.CreateConnection(opts)) { lock (testLock) { ns.Shutdown(); Assert.False(Monitor.Wait(testLock, 1000)); } Assert.True(c.State == ConnState.RECONNECTING); c.Opts.ClosedEventHandler = null; } } }