public async Task when_connect_clients_then_succeeds(int count)
        {
            List <IMqttClient> clients   = new List <IMqttClient>();
            List <string>      clientIds = new List <string>();
            List <Task>        tasks     = new List <Task>();

            for (int i = 1; i <= count; i++)
            {
                IMqttClient client = await GetClientAsync();

                string clientId = MqttTestHelper.GetClientId();

                tasks.Add(client.ConnectAsync(new MqttClientCredentials(clientId)));
                clients.Add(client);
                clientIds.Add(clientId);
            }

            await Task.WhenAll(tasks);

            Server.ActiveClients.Where(c => clientIds.Contains(c)).Should().HaveCount(count);
            Assert.True(clients.All(c => c.IsConnected));
            Assert.True(clients.All(c => !string.IsNullOrEmpty(c.Id)));

            foreach (IMqttClient client in clients)
            {
                client.Dispose();
            }
        }
        public async Task when_in_process_client_communicate_with_tcp_client_then_succeeds()
        {
            IMqttConnectedClient inProcessClient = await Server.CreateClientAsync();

            IMqttClient remoteClient = await GetClientAsync();

            await remoteClient.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

            string fooTopic = "foo/message";
            string barTopic = "bar/message";

            await inProcessClient.SubscribeAsync(fooTopic, MqttQualityOfService.ExactlyOnce);

            await remoteClient.SubscribeAsync(barTopic, MqttQualityOfService.AtLeastOnce);

            int fooMessagesReceived = 0;
            int barMessagesReceived = 0;

            inProcessClient.MessageStream.Subscribe(message =>
            {
                if (message.Topic == fooTopic)
                {
                    fooMessagesReceived++;
                }
            });
            remoteClient.MessageStream.Subscribe(message =>
            {
                if (message.Topic == barTopic)
                {
                    barMessagesReceived++;
                }
            });

            await remoteClient.PublishAsync(new MqttApplicationMessage( fooTopic, new byte[255] ), MqttQualityOfService.AtMostOnce);

            await remoteClient.PublishAsync(new MqttApplicationMessage( fooTopic, new byte[10] ), MqttQualityOfService.AtLeastOnce);

            await remoteClient.PublishAsync(new MqttApplicationMessage( "other/topic", new byte[500] ), MqttQualityOfService.ExactlyOnce);

            await remoteClient.PublishAsync(new MqttApplicationMessage( fooTopic, new byte[50] ), MqttQualityOfService.ExactlyOnce);

            await inProcessClient.PublishAsync(new MqttApplicationMessage( barTopic, new byte[255] ), MqttQualityOfService.AtMostOnce);

            await inProcessClient.PublishAsync(new MqttApplicationMessage( barTopic, new byte[10] ), MqttQualityOfService.AtLeastOnce);

            await inProcessClient.PublishAsync(new MqttApplicationMessage( "other/topic", new byte[500] ), MqttQualityOfService.ExactlyOnce);

            await inProcessClient.PublishAsync(new MqttApplicationMessage( barTopic, new byte[50] ), MqttQualityOfService.ExactlyOnce);

            await Task.Delay(TimeSpan.FromMilliseconds(1000));

            Assert.True(inProcessClient.IsConnected);
            Assert.True(remoteClient.IsConnected);
            fooMessagesReceived.Should().Be(3);
            barMessagesReceived.Should().Be(3);

            inProcessClient.Dispose();
            remoteClient.Dispose();
        }
        public async Task when_client_connects_with_valid_credentials_and_authentication_is_supported_then_connection_succeeds()
        {
            string      username = "******";
            string      password = "******";
            IMqttClient client   = await GetClientAsync();

            await client.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId(), username, password ));

            Assert.True(client.IsConnected);
            Assert.False(string.IsNullOrEmpty(client.Id));
        }
        public async Task when_connecting_twice_with_same_client_without_disconnecting_then_fails()
        {
            IMqttClient client = await GetClientAsync();

            string clientId = MqttTestHelper.GetClientId();

            await client.ConnectAsync(new MqttClientCredentials( clientId ));

            AggregateException ex = Assert.Throws <AggregateException>(() => client.ConnectAsync(new MqttClientCredentials(clientId)).Wait());

            Assert.NotNull(ex);
            Assert.NotNull(ex.InnerException);
            Assert.True(ex.InnerException is MqttClientException);
        }
Beispiel #5
0
        public async Task when_keep_alive_enabled_and_client_is_disposed_then_server_refresh_active_client_list()
        {
            IMqttClient client = await GetClientAsync();

            await client.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

            string clientId = client.Id;
            bool   existClientAfterConnect    = Server.ActiveClients.Any(c => c == clientId);
            ManualResetEventSlim clientClosed = new ManualResetEventSlim();

            IDisposable subscription = Observable.Create <bool>(observer =>
            {
                System.Timers.Timer timer = new System.Timers.Timer();

                timer.Interval = 200;
                timer.Elapsed += (sender, args) =>
                {
                    if (Server.ActiveClients.Any(c => c == clientId))
                    {
                        observer.OnNext(false);
                    }
                    else
                    {
                        observer.OnNext(true);
                        clientClosed.Set();
                        observer.OnCompleted();
                    }
                };
                timer.Start();

                return(() =>
                {
                    timer.Dispose();
                });
            })
                                       .Subscribe(
                _ => { },
                ex => { Console.WriteLine($"Error: {ex.Message}"); });

            client.Dispose();

            bool serverDetectedClientClosed = clientClosed.Wait(TimeSpan.FromSeconds(KeepAliveSecs * 2));

            subscription.Dispose();

            Assert.True(existClientAfterConnect);
            Assert.True(serverDetectedClientClosed);
            Assert.False(Server.ActiveClients.Any(c => c == clientId));
        }
        public async Task when_disconnect_client_then_server_decrease_active_client_list()
        {
            using (IMqttClient client = await GetClientAsync())
            {
                await client.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

                string clientId = client.Id;
                bool   existClientAfterConnect = Server.ActiveClients.Any(c => c == clientId);

                await client.DisconnectAsync();

                ManualResetEventSlim clientClosed = new ManualResetEventSlim();

                IDisposable subscription = Observable.Create <bool>(observer =>
                {
                    System.Timers.Timer timer = new System.Timers.Timer();

                    timer.Interval = 200;
                    timer.Elapsed += (sender, args) =>
                    {
                        if (Server.ActiveClients.Any(c => c == clientId))
                        {
                            observer.OnNext(false);
                        }
                        else
                        {
                            observer.OnNext(true);
                            clientClosed.Set();
                            observer.OnCompleted();
                        }
                    };
                    timer.Start();

                    return(() =>
                    {
                        timer.Dispose();
                    });
                })
                                           .Subscribe(
                    _ => { },
                    ex => { Console.WriteLine("Error: {0}", ex.Message); });

                bool clientDisconnected = clientClosed.Wait(2000);

                Assert.True(existClientAfterConnect);
                Assert.True(clientDisconnected);
                Server.ActiveClients.Should().NotContain(c => c == clientId);
            }
        }
        public async Task when_connecting_twice_with_same_client_with_disconnecting_then_succeeds()
        {
            using (IMqttClient client = await GetClientAsync())
            {
                string clientId = MqttTestHelper.GetClientId();

                await client.ConnectAsync(new MqttClientCredentials( clientId ));

                await client.DisconnectAsync();

                await client.ConnectAsync(new MqttClientCredentials( clientId ));

                Server.ActiveClients.Count(c => c == clientId).Should().Be(1);
            }
        }
        public async Task when_client_disconnects_by_protocol_then_will_message_is_not_sent()
        {
            using (IMqttClient client1 = await GetClientAsync())
                using (IMqttClient client2 = await GetClientAsync())
                    using (IMqttClient client3 = await GetClientAsync())
                    {
                        string topic               = Guid.NewGuid().ToString();
                        MqttQualityOfService qos   = MqttQualityOfService.ExactlyOnce;
                        bool           retain      = true;
                        FooWillMessage willMessage = new FooWillMessage {
                            Message = "Client 1 has been disconnected unexpectedly"
                        };
                        MqttLastWill will = new MqttLastWill(topic, qos, retain, willMessage.GetPayload());

                        await client1.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()), will);

                        await client2.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

                        await client3.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

                        await client2.SubscribeAsync(topic, MqttQualityOfService.AtMostOnce);

                        await client3.SubscribeAsync(topic, MqttQualityOfService.AtLeastOnce);

                        ManualResetEventSlim willReceivedSignal = new ManualResetEventSlim(initialState: false);

                        client2.MessageStream.Subscribe(m =>
                        {
                            if (m.Topic == topic)
                            {
                                willReceivedSignal.Set();
                            }
                        });
                        client3.MessageStream.Subscribe(m =>
                        {
                            if (m.Topic == topic)
                            {
                                willReceivedSignal.Set();
                            }
                        });

                        await client1.DisconnectAsync();

                        bool willReceived = willReceivedSignal.Wait(2000);

                        Assert.False(willReceived);
                    }
        }
Beispiel #9
0
        public async Task when_keep_alive_enabled_and_no_packets_are_sent_then_connection_is_maintained()
        {
            IMqttClient client = await GetClientAsync();

            string clientId = MqttTestHelper.GetClientId();

            await client.ConnectAsync(new MqttClientCredentials( clientId ));

            await Task.Delay(TimeSpan.FromSeconds(KeepAliveSecs * 5));

            Assert.True(Server.ActiveClients.Any(c => c == clientId));
            Assert.True(client.IsConnected);
            Assert.False(string.IsNullOrEmpty(client.Id));

            client.Dispose();
        }
        public async Task when_connect_clients_and_one_client_drops_connection_then_other_client_survives()
        {
            using (IMqttClient fooClient = await GetClientAsync())
                using (IMqttClient barClient = await GetClientAsync())
                {
                    string fooClientId = MqttTestHelper.GetClientId();
                    string barClientId = MqttTestHelper.GetClientId();

                    await fooClient.ConnectAsync(new MqttClientCredentials( fooClientId ));

                    await barClient.ConnectAsync(new MqttClientCredentials( barClientId ));

                    List <string> clientIds = new List <string> {
                        fooClientId, barClientId
                    };
                    int  initialConnectedClients = Server.ActiveClients.Where(c => clientIds.Contains(c)).Count();
                    bool exceptionThrown         = false;

                    try
                    {
                        //Force an exception to be thrown by publishing null message
                        await fooClient.PublishAsync(message : null, qos : MqttQualityOfService.AtMostOnce);
                    }
                    catch
                    {
                        exceptionThrown = true;
                    }

                    ManualResetEventSlim serverSignal = new ManualResetEventSlim();

                    while (!serverSignal.IsSet)
                    {
                        if (!Server.ActiveClients.Any(c => c == fooClientId))
                        {
                            serverSignal.Set();
                        }
                    }

                    serverSignal.Wait();

                    int finalConnectedClients = Server.ActiveClients.Where(c => clientIds.Contains(c)).Count();

                    initialConnectedClients.Should().Be(2);
                    Assert.True(exceptionThrown);
                    finalConnectedClients.Should().Be(1);
                }
        }
        public async Task when_client_disconnects_then_message_stream_completes()
        {
            ManualResetEventSlim streamCompletedSignal = new ManualResetEventSlim(initialState: false);
            IMqttClient          client = await GetClientAsync();

            await client.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

            client.MessageStream.Subscribe(_ => { }, onCompleted: () => streamCompletedSignal.Set());

            await client.DisconnectAsync();

            bool streamCompleted = streamCompletedSignal.Wait(2000);

            Assert.True(streamCompleted);

            client.Dispose();
        }
        public async Task when_connecting_client_with_clean_session_false_then_session_is_preserved()
        {
            using (IMqttClient client = await GetClientAsync())
            {
                string clientId = MqttTestHelper.GetClientId();

                SessionState sessionState1 = await client.ConnectAsync(new MqttClientCredentials( clientId ), cleanSession : false);

                await client.DisconnectAsync();

                SessionState sessionState2 = await client.ConnectAsync(new MqttClientCredentials( clientId ), cleanSession : false);

                await client.DisconnectAsync();

                sessionState1.Should().Be(SessionState.CleanSession);
                sessionState2.Should().Be(SessionState.SessionPresent);
            }
        }
        public async Task when_disconnect_clients_then_succeeds(int count)
        {
            List <IMqttClient> clients   = new List <IMqttClient>();
            List <string>      clientIds = new List <string>();

            for (int i = 1; i <= count; i++)
            {
                IMqttClient client = await GetClientAsync();

                string clientId = MqttTestHelper.GetClientId();

                await client.ConnectAsync(new MqttClientCredentials( clientId ));

                clients.Add(client);
                clientIds.Add(clientId);
            }

            int initialConnectedClients = Server.ActiveClients.Where(c => clientIds.Contains(c)).Count();

            foreach (IMqttClient client in clients)
            {
                await client.DisconnectAsync();
            }

            ManualResetEventSlim disconnectedSignal = new ManualResetEventSlim(initialState: false);

            while (!disconnectedSignal.IsSet)
            {
                if (Server.ActiveClients.Where(c => clientIds.Contains(c)).Count() == 0 && clients.All(c => !c.IsConnected))
                {
                    disconnectedSignal.Set();
                }
            }

            initialConnectedClients.Should().Be(clients.Count);
            Server.ActiveClients.Where(c => clientIds.Contains(c)).Should().BeEmpty();
            Assert.True(clients.All(c => !c.IsConnected));
            Assert.True(clients.All(c => string.IsNullOrEmpty(c.Id)));

            foreach (IMqttClient client in clients)
            {
                client.Dispose();
            }
        }
        public async Task when_connecting_client_to_non_existing_server_then_fails()
        {
            try
            {
                Server.Dispose();

                IMqttClient client = await GetClientAsync();

                await client.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));
            }
            catch (Exception ex)
            {
                Assert.True(ex is MqttClientException);
                Assert.NotNull(ex.InnerException);
                //Assert.True( ex.InnerException is MqttException );//Not throwing this with SSL.
                //Assert.NotNull( ex.InnerException.InnerException );
                //Assert.True( ex.InnerException.InnerException is SocketException );
            }
        }
        public async Task when_clients_connect_and_disconnect_then_server_raises_events()
        {
            using (IMqttClient fooClient = await GetClientAsync())
                using (IMqttClient barClient = await GetClientAsync())
                {
                    string clientId1 = MqttTestHelper.GetClientId();
                    string clientId2 = MqttTestHelper.GetClientId();

                    List <string> connected    = new List <string>();
                    List <string> disconnected = new List <string>();

                    Server.ClientConnected    += (sender, id) => connected.Add(id);
                    Server.ClientDisconnected += (sender, id) =>
                    {
                        connected.Remove(id);
                        disconnected.Add(id);
                    };

                    await fooClient.ConnectAsync(new MqttClientCredentials( clientId1 ));

                    connected.Should().BeEquivalentTo(clientId1);

                    await barClient.ConnectAsync(new MqttClientCredentials( clientId2 ));

                    connected.Should().BeEquivalentTo(clientId1, clientId2);

                    await barClient.DisconnectAsync();

                    disconnected.Should().BeEquivalentTo(clientId2);
                    connected.Should().BeEquivalentTo(clientId1);

                    await fooClient.DisconnectAsync();

                    disconnected.Should().BeEquivalentTo(clientId2, clientId1);
                    connected.Should().BeEmpty();
                }
        }
        public async Task when_client_disconnects_unexpectedly_then_will_message_is_sent()
        {
            IMqttClient client1 = await GetClientAsync();

            IMqttClient client2 = await GetClientAsync();

            IMqttClient client3 = await GetClientAsync();

            string topic               = Guid.NewGuid().ToString();
            MqttQualityOfService qos   = MqttQualityOfService.ExactlyOnce;
            bool           retain      = true;
            FooWillMessage willMessage = new FooWillMessage {
                Message = "Client 1 has been disconnected unexpectedly"
            };

            byte[]       willMessagePayload = willMessage.GetPayload();
            MqttLastWill will = new MqttLastWill(topic, qos, retain, willMessagePayload);

            await client1.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()), will);

            await client2.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

            await client3.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()));

            await client2.SubscribeAsync(topic, MqttQualityOfService.AtMostOnce);

            await client3.SubscribeAsync(topic, MqttQualityOfService.AtLeastOnce);

            ManualResetEventSlim   willReceivedSignal     = new ManualResetEventSlim(initialState: false);
            MqttApplicationMessage willApplicationMessage = default;

            client2.MessageStream.Subscribe(m =>
            {
                if (m.Topic == topic)
                {
                    willApplicationMessage = m;
                    willReceivedSignal.Set();
                }
            });
            client3.MessageStream.Subscribe(m =>
            {
                if (m.Topic == topic)
                {
                    willApplicationMessage = m;
                    willReceivedSignal.Set();
                }
            });

            //Forces socket disconnection without using protocol Disconnect (Disconnect or Dispose Client method)
            (client1 as MqttClientImpl).Channel.Dispose();

            bool willReceived = willReceivedSignal.Wait(2000);

            Assert.True(willReceived);
            Assert.NotNull(willMessage);
            willApplicationMessage.Topic.Should().Be(topic);
            FooWillMessage.GetMessage(willApplicationMessage.Payload).Message.Should().Be(willMessage.Message);

            client2.Dispose();
            client3.Dispose();
        }
        public async Task when_client_connects_with_invalid_credentials_and_authentication_is_supported_then_connection_is_closed()
        {
            string      username = "******";
            string      password = "******";
            IMqttClient client   = await GetClientAsync();

            AggregateException aggregateEx = Assert.Throws <AggregateException>(() => client.ConnectAsync(new MqttClientCredentials(MqttTestHelper.GetClientId(), username, password)).Wait());

            Assert.NotNull(aggregateEx.InnerException);
            Assert.True(aggregateEx.InnerException is MqttClientException);
            Assert.NotNull(aggregateEx.InnerException.InnerException);
            Assert.True(aggregateEx.InnerException.InnerException is MqttConnectionException);

            ((MqttConnectionException)aggregateEx.InnerException.InnerException).ReturnCode.Should().Be(MqttConnectionStatus.BadUserNameOrPassword);
        }
        public async Task when_connecting_twice_from_two_client_with_same_id_server_first_client_disconnect_in_right_order()
        {
            string clientId = MqttTestHelper.GetClientId();

            using (IMqttClient clientFoo = await GetClientAsync())
                using (IMqttClient clientBar = await GetClientAsync())
                {
                    List <char> events = new List <char>();

                    void onConnect(object sender, string id)
                    {
                        lock ( events )
                        {
                            events.Add('c');
                            Monitor.Pulse(events);
                        }
                    }

                    void onDisconnect(object sender, string id)
                    {
                        lock ( events )
                        {
                            events.Add('d');
                            Monitor.Pulse(events);
                        }
                    }

                    Server.ClientDisconnected += onDisconnect;
                    Server.ClientConnected    += onConnect;

                    await clientFoo.ConnectAsync(new MqttClientCredentials( clientId ));

                    bool didNotTimeout = true;
                    lock ( events )
                    {
                        if (events.Count < 1)
                        {
                            didNotTimeout = Monitor.Wait(events, 500);
                        }
                    }

                    Assert.True(didNotTimeout);
                    string.Concat(events).Should().Be("c");

                    try
                    {
                        await clientBar.ConnectAsync(new MqttClientCredentials( clientId ));
                    }
                    catch
                    {
                        Assume.That(false, "To be investigated. Tests sometime throw exception on reconnection.");
                    }
                    lock ( events )
                    {
                        while (events.Count < 4)
                        {
                            didNotTimeout &= Monitor.Wait(events, 500);
                        }
                    }
                    Assert.True(didNotTimeout);
                    string.Concat(events).Should().Be("ccdd");
                    Server.ClientDisconnected -= onDisconnect;
                    Server.ClientConnected    -= onConnect;
                    //"cdc".Should().Be(events ); //Require MQTT-3.1.4-2
                }
        }