mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-20 03:24:33 +08:00
Refactor session and connection handling in server. Fix QoS level 2 issues.
This commit is contained in:
@@ -25,7 +25,7 @@ namespace MQTTnet.AspNetCore.Tests
|
||||
|
||||
pipe.Receive.Writer.Complete();
|
||||
|
||||
await Assert.ThrowsExceptionAsync<MqttCommunicationException>(() => ctx.ReceivePacketAsync(TimeSpan.FromSeconds(1), CancellationToken.None));
|
||||
await Assert.ThrowsExceptionAsync<MqttCommunicationException>(() => ctx.ReceivePacketAsync(TimeSpan.Zero, CancellationToken.None));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -41,7 +41,7 @@ namespace MQTTnet.AspNetCore.Tests
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
await ctx.SendPacketAsync(new MqttPublishPacket(), CancellationToken.None).ConfigureAwait(false);
|
||||
await ctx.SendPacketAsync(new MqttPublishPacket(), TimeSpan.Zero, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace MQTTnet.Benchmarks
|
||||
|
||||
for (var i = 0; i < 10000; i++)
|
||||
{
|
||||
_channelAdapter.SendPacketAsync(_packet, CancellationToken.None).GetAwaiter().GetResult();
|
||||
_channelAdapter.SendPacketAsync(_packet, TimeSpan.Zero, CancellationToken.None).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
_stream.Position = 0;
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace MQTTnet.Benchmarks
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task DisconnectAsync()
|
||||
public Task DisconnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
@@ -14,20 +15,20 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public async Task TimeoutAfter()
|
||||
{
|
||||
await MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct), TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||
await MqttTaskTimeout.WaitAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct), TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||
}
|
||||
|
||||
[ExpectedException(typeof(MqttCommunicationTimedOutException))]
|
||||
[TestMethod]
|
||||
public async Task TimeoutAfterWithResult()
|
||||
{
|
||||
await MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct).ContinueWith(t => 5, ct), TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||
await MqttTaskTimeout.WaitAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct).ContinueWith(t => 5, ct), TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task TimeoutAfterCompleteInTime()
|
||||
{
|
||||
var result = await MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(100), ct).ContinueWith(t => 5, ct), TimeSpan.FromMilliseconds(500), CancellationToken.None);
|
||||
var result = await MqttTaskTimeout.WaitAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(100), ct).ContinueWith(t => 5, ct), TimeSpan.FromMilliseconds(500), CancellationToken.None);
|
||||
Assert.AreEqual(5, result);
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
await MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Run(() =>
|
||||
await MqttTaskTimeout.WaitAsync(ct => Task.Run(() =>
|
||||
{
|
||||
var iis = new int[0];
|
||||
iis[1] = 0;
|
||||
@@ -55,7 +56,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
await MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Run(() =>
|
||||
await MqttTaskTimeout.WaitAsync(ct => Task.Run(() =>
|
||||
{
|
||||
var iis = new int[0];
|
||||
iis[1] = 0;
|
||||
@@ -76,7 +77,7 @@ namespace MQTTnet.Tests
|
||||
var tasks = Enumerable.Range(0, 100000)
|
||||
.Select(i =>
|
||||
{
|
||||
return MQTTnet.Internal.TaskExtensions.TimeoutAfterAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(1), ct), TimeSpan.FromMinutes(1), CancellationToken.None);
|
||||
return MqttTaskTimeout.WaitAsync(ct => Task.Delay(TimeSpan.FromMilliseconds(1), ct), TimeSpan.FromMinutes(1), CancellationToken.None);
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
+8
-8
@@ -16,7 +16,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
public class Client_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Client_Connect()
|
||||
public async Task Connect()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -33,7 +33,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Connect_And_Disconnect()
|
||||
public async Task Connect_And_Disconnect()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -52,7 +52,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Subscribe()
|
||||
public async Task Subscribe()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -75,7 +75,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Unsubscribe()
|
||||
public async Task Unsubscribe()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -99,7 +99,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Publish_QoS0()
|
||||
public async Task Publish_QoS_0()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -121,7 +121,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Publish_QoS1()
|
||||
public async Task Publish_QoS_1()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -143,7 +143,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Publish_QoS2()
|
||||
public async Task Publish_QoS_2()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
@@ -165,7 +165,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Publish_With_Properties()
|
||||
public async Task Publish_With_Properties()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
var client = new MqttFactory().CreateMqttClient();
|
||||
+15
-8
@@ -7,9 +7,9 @@ using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public class TestSetup : IDisposable
|
||||
public class TestEnvironment : IDisposable
|
||||
{
|
||||
private readonly MqttFactory _mqttFactory = new MqttFactory();
|
||||
private readonly List<IMqttClient> _clients = new List<IMqttClient>();
|
||||
@@ -24,9 +24,12 @@ namespace MQTTnet.Tests
|
||||
private IMqttServer _server;
|
||||
|
||||
public bool IgnoreClientLogErrors { get; set; }
|
||||
|
||||
public bool IgnoreServerLogErrors { get; set; }
|
||||
|
||||
public TestSetup()
|
||||
public int ServerPort { get; set; } = 1888;
|
||||
|
||||
public TestEnvironment()
|
||||
{
|
||||
_serverLogger.LogMessagePublished += (s, e) =>
|
||||
{
|
||||
@@ -51,6 +54,11 @@ namespace MQTTnet.Tests
|
||||
};
|
||||
}
|
||||
|
||||
public IMqttClient CreateClient()
|
||||
{
|
||||
return _mqttFactory.CreateMqttClient(_clientLogger);
|
||||
}
|
||||
|
||||
public Task<IMqttServer> StartServerAsync()
|
||||
{
|
||||
return StartServerAsync(new MqttServerOptionsBuilder());
|
||||
@@ -64,7 +72,7 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
|
||||
_server = _mqttFactory.CreateMqttServer(_serverLogger);
|
||||
await _server.StartAsync(options.WithDefaultEndpointPort(1888).Build());
|
||||
await _server.StartAsync(options.WithDefaultEndpointPort(ServerPort).Build());
|
||||
|
||||
return _server;
|
||||
}
|
||||
@@ -77,7 +85,7 @@ namespace MQTTnet.Tests
|
||||
public async Task<IMqttClient> ConnectClientAsync(MqttClientOptionsBuilder options)
|
||||
{
|
||||
var client = _mqttFactory.CreateMqttClient(_clientLogger);
|
||||
await client.ConnectAsync(options.WithTcpServer("localhost", 1888).Build());
|
||||
await client.ConnectAsync(options.WithTcpServer("localhost", ServerPort).Build());
|
||||
|
||||
_clients.Add(client);
|
||||
return client;
|
||||
@@ -106,17 +114,16 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
foreach (var mqttClient in _clients)
|
||||
{
|
||||
mqttClient?.DisconnectAsync().GetAwaiter().GetResult();
|
||||
mqttClient?.Dispose();
|
||||
}
|
||||
|
||||
_server.StopAsync().GetAwaiter().GetResult();
|
||||
_server?.StopAsync().GetAwaiter().GetResult();
|
||||
|
||||
ThrowIfLogErrors();
|
||||
|
||||
if (_exceptions.Any())
|
||||
{
|
||||
throw new Exception($"{_exceptions.Count} exceptions tracked.");
|
||||
throw new Exception($"{_exceptions.Count} exceptions tracked.\r\n" + string.Join(Environment.NewLine, _exceptions));
|
||||
}
|
||||
}
|
||||
|
||||
+5
-24
@@ -6,7 +6,7 @@ using MQTTnet.Adapter;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public class TestMqttCommunicationAdapter : IMqttChannelAdapter
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace MQTTnet.Tests
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
public Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfPartnerIsNull();
|
||||
|
||||
@@ -44,30 +44,11 @@ namespace MQTTnet.Tests
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
public Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfPartnerIsNull();
|
||||
|
||||
if (timeout > TimeSpan.Zero)
|
||||
{
|
||||
using (var timeoutCts = new CancellationTokenSource(timeout))
|
||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _incomingPackets.Take(cts.Token);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}, cts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
return await Task.Run(() =>
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public class TestMqttCommunicationAdapterFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
+1
-1
@@ -7,7 +7,7 @@ using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public class TestMqttServerAdapter : IMqttServerAdapter
|
||||
{
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public static class TestServerExtensions
|
||||
{
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public class TestServerStorage : IMqttServerStorage
|
||||
{
|
||||
public IList<MqttApplicationMessage> Messages = new List<MqttApplicationMessage>();
|
||||
|
||||
public Task SaveRetainedMessagesAsync(IList<MqttApplicationMessage> messages)
|
||||
{
|
||||
Messages = messages;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IList<MqttApplicationMessage>> LoadRetainedMessagesAsync()
|
||||
{
|
||||
return Task.FromResult(Messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
@@ -11,50 +10,73 @@ using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class MqttClientTests
|
||||
public class Client_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Client_Disconnect_Exception()
|
||||
public async Task Invalid_Connect_Throws_Exception()
|
||||
{
|
||||
var factory = new MqttFactory();
|
||||
var client = factory.CreateMqttClient();
|
||||
|
||||
Exception ex = null;
|
||||
client.Disconnected += (s, e) =>
|
||||
using (var client = factory.CreateMqttClient())
|
||||
{
|
||||
ex = e.Exception;
|
||||
};
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
|
||||
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
|
||||
Assert.Fail("Must fail!");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Assert.IsNotNull(exception);
|
||||
Assert.IsInstanceOfType(exception, typeof(MqttCommunicationException));
|
||||
Assert.IsInstanceOfType(exception.InnerException, typeof(SocketException));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Assert.IsNotNull(ex);
|
||||
Assert.IsInstanceOfType(ex, typeof(MqttCommunicationException));
|
||||
Assert.IsInstanceOfType(ex.InnerException, typeof(SocketException));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Preserve_Message_Order()
|
||||
public async Task Disconnect_Event_Contains_Exception()
|
||||
{
|
||||
var factory = new MqttFactory();
|
||||
using (var client = factory.CreateMqttClient())
|
||||
{
|
||||
Exception ex = null;
|
||||
client.Disconnected += (s, e) =>
|
||||
{
|
||||
ex = e.Exception;
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Assert.IsNotNull(ex);
|
||||
Assert.IsInstanceOfType(ex, typeof(MqttCommunicationException));
|
||||
Assert.IsInstanceOfType(ex.InnerException, typeof(SocketException));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Preserve_Message_Order()
|
||||
{
|
||||
// The messages are sent in reverse or to ensure that the delay in the handler
|
||||
// needs longer for the first messages and later messages may be processed earlier (if there
|
||||
// is an issue).
|
||||
const int MessagesCount = 50;
|
||||
|
||||
using (var testSetup = new TestSetup())
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testSetup.StartServerAsync();
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var client1 = await testSetup.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
await client1.SubscribeAsync("x");
|
||||
|
||||
var receivedValues = new List<int>();
|
||||
@@ -72,7 +94,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseReceivedApplicationMessageHandler(Handler1);
|
||||
|
||||
var client2 = await testSetup.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
for (var i = MessagesCount; i > 0; i--)
|
||||
{
|
||||
await client2.PublishAsync("x", i.ToString());
|
||||
@@ -88,13 +110,13 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Send_Reply_For_Any_Received_Message()
|
||||
public async Task Send_Reply_For_Any_Received_Message()
|
||||
{
|
||||
using (var testSetup = new TestSetup())
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testSetup.StartServerAsync();
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var client1 = await testSetup.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
await client1.SubscribeAsync("request/+");
|
||||
|
||||
async Task Handler1(MqttApplicationMessageHandlerContext context)
|
||||
@@ -104,7 +126,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseReceivedApplicationMessageHandler(Handler1);
|
||||
|
||||
var client2 = await testSetup.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
await client2.SubscribeAsync("reply/#");
|
||||
|
||||
var replies = new List<string>();
|
||||
@@ -132,30 +154,26 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Publish()
|
||||
public async Task Publish_With_Correct_Retain_Flag()
|
||||
{
|
||||
var server = new MqttFactory().CreateMqttServer();
|
||||
|
||||
try
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
await server.StartAsync(new MqttServerOptions());
|
||||
|
||||
var client1 = new MqttFactory().CreateMqttClient();
|
||||
client1.ApplicationMessageReceived += (_, e) =>
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
client1.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(e.ApplicationMessage);
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
await client1.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1").Build());
|
||||
await client1.SubscribeAsync("a");
|
||||
|
||||
var client2 = new MqttFactory().CreateMqttClient();
|
||||
await client2.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1").Build());
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithRetainFlag().Build();
|
||||
await client2.PublishAsync(message);
|
||||
|
||||
@@ -164,26 +182,18 @@ namespace MQTTnet.Tests
|
||||
Assert.AreEqual(1, receivedMessages.Count);
|
||||
Assert.IsFalse(receivedMessages.First().Retain); // Must be false even if set above!
|
||||
}
|
||||
finally
|
||||
{
|
||||
await server.StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_Special_Content()
|
||||
public async Task Subscribe_In_Callback_Events()
|
||||
{
|
||||
var factory = new MqttFactory();
|
||||
var server = factory.CreateMqttServer();
|
||||
var serverOptions = new MqttServerOptionsBuilder().Build();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
var client = factory.CreateMqttClient();
|
||||
|
||||
try
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await server.StartAsync(serverOptions);
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
client.Connected += async (s, e) =>
|
||||
{
|
||||
@@ -196,43 +206,37 @@ namespace MQTTnet.Tests
|
||||
await client.PublishAsync(msg.Build());
|
||||
};
|
||||
|
||||
client.ApplicationMessageReceived += (s, e) =>
|
||||
client.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(e.ApplicationMessage);
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost").Build());
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, receivedMessages.Count);
|
||||
Assert.AreEqual("DA|18RS00SC00XI0000RV00R100R200R300R400L100L200L300L400Y100Y200AC0102031800BELK0000BM0000|", receivedMessages.First().ConvertPayloadToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await server.StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Exception_In_Application_Message_Handler()
|
||||
public async Task Message_Send_Retry()
|
||||
{
|
||||
using (var testSetup = new TestSetup())
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
testSetup.IgnoreClientLogErrors = true;
|
||||
testSetup.IgnoreServerLogErrors = true;
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
testEnvironment.IgnoreServerLogErrors = true;
|
||||
|
||||
await testSetup.StartServerAsync(
|
||||
await testEnvironment.StartServerAsync(
|
||||
new MqttServerOptionsBuilder()
|
||||
.WithPersistentSessions()
|
||||
.WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(50)));
|
||||
|
||||
var client1 = await testSetup.ConnectClientAsync(new MqttClientOptionsBuilder()
|
||||
.WithCleanSession(false));
|
||||
.WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(250)));
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithCleanSession(false));
|
||||
await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
|
||||
var retries = 0;
|
||||
@@ -241,16 +245,16 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
retries++;
|
||||
|
||||
await Task.Delay(50);
|
||||
await Task.Delay(1000);
|
||||
throw new Exception("Broken!");
|
||||
}
|
||||
|
||||
client1.UseReceivedApplicationMessageHandler(Handler1);
|
||||
|
||||
var client2 = await testSetup.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
await client2.PublishAsync("x");
|
||||
|
||||
await Task.Delay(1000);
|
||||
await Task.Delay(3000);
|
||||
|
||||
// The server should disconnect clients which are not responding.
|
||||
Assert.IsFalse(client1.IsConnected);
|
||||
@@ -262,40 +266,5 @@ namespace MQTTnet.Tests
|
||||
Assert.AreEqual(2, retries);
|
||||
}
|
||||
}
|
||||
|
||||
//#if DEBUG
|
||||
// [TestMethod]
|
||||
// public async Task Client_Cleanup_On_Authentification_Fails()
|
||||
// {
|
||||
// var channel = new TestMqttCommunicationAdapter();
|
||||
// var channel2 = new TestMqttCommunicationAdapter();
|
||||
// channel.Partner = channel2;
|
||||
// channel2.Partner = channel;
|
||||
|
||||
// Task.Run(async () => {
|
||||
// var connect = await channel2.ReceivePacketAsync(TimeSpan.Zero, CancellationToken.None);
|
||||
// await channel2.SendPacketAsync(new MqttConnAckPacket
|
||||
// {
|
||||
// ConnectReturnCode = Protocol.MqttConnectReturnCode.ConnectionRefusedNotAuthorized
|
||||
// }, CancellationToken.None);
|
||||
// });
|
||||
|
||||
// var fake = new TestMqttCommunicationAdapterFactory(channel);
|
||||
|
||||
// var client = new MqttClient(fake, new MqttNetLogger());
|
||||
|
||||
// try
|
||||
// {
|
||||
// await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("any-server").Build());
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Assert.IsInstanceOfType(ex, typeof(MqttConnectingFailedException));
|
||||
// }
|
||||
|
||||
// Assert.IsTrue(client._packetReceiverTask == null || client._packetReceiverTask.IsCompleted, "receive loop not completed");
|
||||
// Assert.IsTrue(client._keepAliveMessageSenderTask == null || client._keepAliveMessageSenderTask.IsCompleted, "keepalive loop not completed");
|
||||
// }
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Server.Status;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
@@ -44,9 +45,9 @@ namespace MQTTnet.Tests
|
||||
|
||||
// Simulate traffic.
|
||||
Thread.Sleep(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification.
|
||||
monitor.PacketReceived(new MqttPublishPacket());
|
||||
monitor.PacketReceived();
|
||||
Thread.Sleep(1000);
|
||||
monitor.PacketReceived(new MqttPublishPacket());
|
||||
monitor.PacketReceived();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
Assert.AreEqual(0, clientSession.StopCalledCount);
|
||||
@@ -62,12 +63,12 @@ namespace MQTTnet.Tests
|
||||
|
||||
public int StopCalledCount { get; private set; }
|
||||
|
||||
public void FillStatus(MqttClientSessionStatus status)
|
||||
public void FillStatus(MqttClientStatus status)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void EnqueueApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
public void EnqueueApplicationMessage(MqttClientConnection senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@@ -82,7 +83,7 @@ namespace MQTTnet.Tests
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Task StopAsync(MqttClientDisconnectType disconnectType)
|
||||
public Task StopAsync()
|
||||
{
|
||||
StopCalledCount++;
|
||||
return Task.FromResult(0);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public void MqttSubscriptionsManager_SubscribeSingleSuccess()
|
||||
{
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerOptions(), new MqttServerEventDispatcher());
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerEventDispatcher(), new MqttServerOptions());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
@@ -26,7 +26,7 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public void MqttSubscriptionsManager_SubscribeDifferentQoSSuccess()
|
||||
{
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerOptions(), new MqttServerEventDispatcher());
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerEventDispatcher(), new MqttServerOptions());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new TopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
@@ -41,7 +41,7 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public void MqttSubscriptionsManager_SubscribeTwoTimesSuccess()
|
||||
{
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerOptions(), new MqttServerEventDispatcher());
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerEventDispatcher(), new MqttServerOptions());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new TopicFilter { Topic = "#", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
@@ -57,7 +57,7 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public void MqttSubscriptionsManager_SubscribeSingleNoSuccess()
|
||||
{
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerOptions(), new MqttServerEventDispatcher());
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerEventDispatcher(), new MqttServerOptions());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
@@ -70,7 +70,7 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public void MqttSubscriptionsManager_SubscribeAndUnsubscribeSingle()
|
||||
{
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerOptions(), new MqttServerEventDispatcher());
|
||||
var sm = new MqttClientSubscriptionsManager("", new MqttServerEventDispatcher(), new MqttServerOptions());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
@@ -81,7 +81,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
var up = new MqttUnsubscribePacket();
|
||||
up.TopicFilters.Add("A/B/C");
|
||||
sm.Unsubscribe(up);
|
||||
sm.UnsubscribeAsync(up);
|
||||
|
||||
Assert.IsFalse(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Server_Status_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Show_Client_And_Session_Statistics()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
var sessionStatus = await server.GetSessionStatusAsync();
|
||||
|
||||
Assert.AreEqual(2, clientStatus.Count);
|
||||
Assert.AreEqual(2, sessionStatus.Count);
|
||||
|
||||
Assert.IsTrue(clientStatus.Any(s => s.ClientId == "client1"));
|
||||
Assert.IsTrue(clientStatus.Any(s => s.ClientId == "client2"));
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
await c2.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
clientStatus = await server.GetClientStatusAsync();
|
||||
sessionStatus = await server.GetSessionStatusAsync();
|
||||
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
Assert.AreEqual(0, sessionStatus.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Disconnect_Client()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
|
||||
Assert.AreEqual(1, clientStatus.Count);
|
||||
|
||||
Assert.IsTrue(clientStatus.Any(s => s.ClientId == "client1"));
|
||||
|
||||
await clientStatus.First().DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.IsFalse(c1.IsConnected);
|
||||
|
||||
clientStatus = await server.GetClientStatusAsync();
|
||||
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Keep_Persistent_Session()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
var sessionStatus = await server.GetSessionStatusAsync();
|
||||
|
||||
Assert.AreEqual(1, clientStatus.Count);
|
||||
Assert.AreEqual(2, sessionStatus.Count);
|
||||
|
||||
await c2.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
clientStatus = await server.GetClientStatusAsync();
|
||||
sessionStatus = await server.GetSessionStatusAsync();
|
||||
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
Assert.AreEqual(2, sessionStatus.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Track_Sent_Application_Messages()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
for (var i = 1; i < 25; i++)
|
||||
{
|
||||
await c1.PublishAsync("a");
|
||||
await Task.Delay(50);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
Assert.AreEqual(i, clientStatus.First().SentApplicationMessagesCount);
|
||||
Assert.AreEqual(0, clientStatus.First().ReceivedApplicationMessagesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Track_Sent_Packets()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithNoKeepAlive());
|
||||
|
||||
for (var i = 1; i < 25; i++)
|
||||
{
|
||||
// At most once will send one packet to the client and the server will reply
|
||||
// with an additional ACK packet.
|
||||
await c1.PublishAsync("a", string.Empty, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
await Task.Delay(50);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
|
||||
Assert.AreEqual(i, clientStatus.First().SentApplicationMessagesCount, "SAMC invalid!");
|
||||
Assert.AreEqual(i, clientStatus.First().SentPacketsCount, "SPC invalid!");
|
||||
|
||||
// +1 because ConnACK package is already counted.
|
||||
Assert.AreEqual(i + 1, clientStatus.First().ReceivedPacketsCount, "RPC invalid!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,970 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Server_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Publish_At_Most_Once_0x00()
|
||||
{
|
||||
await TestPublishAsync(
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.AtMostOnce,
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.AtMostOnce,
|
||||
1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_At_Least_Once_0x01()
|
||||
{
|
||||
await TestPublishAsync(
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.AtLeastOnce,
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.AtLeastOnce,
|
||||
1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_Exactly_Once_0x02()
|
||||
{
|
||||
await TestPublishAsync(
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.ExactlyOnce,
|
||||
"A/B/C",
|
||||
MqttQualityOfServiceLevel.ExactlyOnce,
|
||||
1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Will_Message_Do_Not_Send()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
c1.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
await c2.DisconnectAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Will_Message_Send()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
c1.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
Assert.AreEqual(1, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Subscribe_Unsubscribe()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c1"));
|
||||
c1.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c2"));
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
|
||||
await c2.PublishAsync(message);
|
||||
|
||||
await Task.Delay(500);
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
|
||||
var subscribeEventCalled = false;
|
||||
server.ClientSubscribedTopic += (_, e) =>
|
||||
{
|
||||
subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == "c1";
|
||||
};
|
||||
|
||||
await c1.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(subscribeEventCalled, "Subscribe event not called.");
|
||||
|
||||
await c2.PublishAsync(message);
|
||||
await Task.Delay(250);
|
||||
Assert.AreEqual(1, receivedMessagesCount);
|
||||
|
||||
var unsubscribeEventCalled = false;
|
||||
server.ClientUnsubscribedTopic += (_, e) =>
|
||||
{
|
||||
unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == "c1";
|
||||
};
|
||||
|
||||
await c1.UnsubscribeAsync("a");
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called.");
|
||||
|
||||
await c2.PublishAsync(message);
|
||||
await Task.Delay(500);
|
||||
Assert.AreEqual(1, receivedMessagesCount);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_From_Server()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
client.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
|
||||
await client.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
|
||||
await server.PublishAsync(message);
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
Assert.AreEqual(1, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_Multiple_Clients()
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
var locked = new object();
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
c1.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (locked)
|
||||
{
|
||||
receivedMessagesCount++;
|
||||
}
|
||||
});
|
||||
|
||||
c2.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (locked)
|
||||
{
|
||||
receivedMessagesCount++;
|
||||
}
|
||||
});
|
||||
|
||||
await c1.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
await c2.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
|
||||
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
await c1.PublishAsync(message);
|
||||
}
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(2000, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Session_Takeover()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var options = new MqttClientOptionsBuilder()
|
||||
.WithCleanSession(false)
|
||||
.WithClientId("a");
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync(options);
|
||||
await Task.Delay(500);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync(options);
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.IsFalse(client1.IsConnected);
|
||||
Assert.IsTrue(client2.IsConnected);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task No_Messages_If_No_Subscription()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
client.Connected += async (s, e) =>
|
||||
{
|
||||
await client.PublishAsync("Connected");
|
||||
};
|
||||
|
||||
client.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
await client.PublishAsync("Hello");
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessages.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Set_Subscription_At_Server()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
server.ClientConnected += async (s, e) =>
|
||||
{
|
||||
await server.SubscribeAsync(e.ClientId, "topic1");
|
||||
};
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
client.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
await client.PublishAsync("Hello");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(0, receivedMessages.Count);
|
||||
|
||||
await client.PublishAsync("topic1");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(1, receivedMessages.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Shutdown_Disconnects_Clients_Gracefully()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var disconnectCalled = 0;
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
c1.Disconnected += (sender, args) => disconnectCalled++;
|
||||
|
||||
await Task.Delay(100);
|
||||
|
||||
await server.StopAsync();
|
||||
|
||||
await Task.Delay(100);
|
||||
|
||||
Assert.AreEqual(1, disconnectCalled);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Handle_Clean_Disconnect()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var clientConnectedCalled = 0;
|
||||
var clientDisconnectedCalled = 0;
|
||||
|
||||
server.ClientConnected += (_, __) => Interlocked.Increment(ref clientConnectedCalled);
|
||||
server.ClientDisconnected += (_, __) => Interlocked.Increment(ref clientDisconnectedCalled);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
|
||||
Assert.AreEqual(1, clientConnectedCalled);
|
||||
Assert.AreEqual(0, clientDisconnectedCalled);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, clientConnectedCalled);
|
||||
Assert.AreEqual(1, clientDisconnectedCalled);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Client_Disconnect_Without_Errors()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
bool clientWasConnected;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
try
|
||||
{
|
||||
var client = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
|
||||
clientWasConnected = true;
|
||||
|
||||
await client.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await server.StopAsync();
|
||||
}
|
||||
|
||||
Assert.IsTrue(clientWasConnected);
|
||||
|
||||
testEnvironment.ThrowIfLogErrors();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Handle_Lots_Of_Parallel_Retained_Messages()
|
||||
{
|
||||
const int ClientCount = 50;
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var tasks = new List<Task>();
|
||||
for (var i = 0; i < ClientCount; i++)
|
||||
{
|
||||
var i2 = i;
|
||||
var testEnvironment2 = testEnvironment;
|
||||
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = await testEnvironment2.ConnectClientAsync())
|
||||
{
|
||||
// Clear retained message.
|
||||
await client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("r" + i2)
|
||||
.WithPayload(new byte[0]).WithRetainFlag().Build());
|
||||
|
||||
// Set retained message.
|
||||
await client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("r" + i2)
|
||||
.WithPayload("value").WithRetainFlag().Build());
|
||||
|
||||
await client.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
testEnvironment2.TrackException(exception);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var retainedMessages = await server.GetRetainedMessagesAsync();
|
||||
|
||||
Assert.AreEqual(ClientCount, retainedMessages.Count);
|
||||
|
||||
for (var i = 0; i < ClientCount; i++)
|
||||
{
|
||||
Assert.IsTrue(retainedMessages.Any(m => m.Topic == "r" + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Retained_Messages_Flow()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
var receivedMessages = 0;
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
Interlocked.Increment(ref receivedMessages);
|
||||
});
|
||||
|
||||
await c1.PublishAsync(retainedMessage);
|
||||
await c1.DisconnectAsync();
|
||||
await Task.Delay(500);
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
await c2.UnsubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(i, receivedMessages);
|
||||
|
||||
await c2.SubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(i + 1, receivedMessages);
|
||||
}
|
||||
|
||||
await c2.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_No_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained_other").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, receivedMessages.Count);
|
||||
Assert.IsTrue(receivedMessages.First().Retain);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Clear_Retained_Message()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build());
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
c2.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
await Task.Delay(200);
|
||||
await c2.SubscribeAsync(new TopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Persist_Retained_Message()
|
||||
{
|
||||
var serverStorage = new TestServerStorage();
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithStorage(serverStorage));
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, serverStorage.Messages.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Intercept_Message()
|
||||
{
|
||||
void Interceptor(MqttApplicationMessageInterceptorContext context)
|
||||
{
|
||||
context.ApplicationMessage.Payload = Encoding.ASCII.GetBytes("extended");
|
||||
}
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithApplicationMessageInterceptor(Interceptor));
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("test").Build());
|
||||
|
||||
var isIntercepted = false;
|
||||
c2.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
isIntercepted = string.Compare("extended", Encoding.UTF8.GetString(c.ApplicationMessage.Payload), StringComparison.Ordinal) == 0;
|
||||
});
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("test").Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.IsTrue(isIntercepted);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Send_Long_Body()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
const int PayloadSizeInMB = 30;
|
||||
const int CharCount = PayloadSizeInMB * 1024 * 1024;
|
||||
|
||||
var longBody = new byte[CharCount];
|
||||
byte @char = 32;
|
||||
|
||||
for (long i = 0; i < PayloadSizeInMB * 1024L * 1024L; i++)
|
||||
{
|
||||
longBody[i] = @char;
|
||||
|
||||
@char++;
|
||||
|
||||
if (@char > 126)
|
||||
{
|
||||
@char = 32;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] receivedBody = null;
|
||||
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
client1.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
receivedBody = c.ApplicationMessage.Payload;
|
||||
});
|
||||
|
||||
await client1.SubscribeAsync("string");
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
await client2.PublishAsync("string", longBody);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.IsTrue(longBody.SequenceEqual(receivedBody ?? new byte[0]));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Deny_Connection()
|
||||
{
|
||||
var serverOptions = new MqttServerOptionsBuilder().WithConnectionValidator(context =>
|
||||
{
|
||||
context.ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized;
|
||||
});
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
|
||||
try
|
||||
{
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
Assert.Fail("An exception should be raised.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is MqttConnectingFailedException connectingFailedException)
|
||||
{
|
||||
Assert.AreEqual(MqttClientConnectResultCode.NotAuthorized, connectingFailedException.ResultCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("Wrong exception.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Same_Client_Id_Connect_Disconnect_Event_Order()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var events = new List<string>();
|
||||
|
||||
server.ClientConnected += (_, __) =>
|
||||
{
|
||||
lock (events)
|
||||
{
|
||||
events.Add("c");
|
||||
}
|
||||
};
|
||||
|
||||
server.ClientDisconnected += (_, __) =>
|
||||
{
|
||||
lock (events)
|
||||
{
|
||||
events.Add("d");
|
||||
}
|
||||
};
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithClientId("same_id");
|
||||
|
||||
// c
|
||||
var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var flow = string.Join(string.Empty, events);
|
||||
Assert.AreEqual("c", flow);
|
||||
|
||||
// dc
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
flow = string.Join(string.Empty, events);
|
||||
Assert.AreEqual("cdc", flow);
|
||||
|
||||
// nothing
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
// d
|
||||
await c2.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
await server.StopAsync();
|
||||
|
||||
flow = string.Join(string.Empty, events);
|
||||
Assert.AreEqual("cdcd", flow);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Remove_Session()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder();
|
||||
var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
await Task.Delay(500);
|
||||
Assert.AreEqual(1, (await server.GetClientStatusAsync()).Count);
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, (await server.GetClientStatusAsync()).Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Stop_And_Restart()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await server.StopAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
Assert.Fail("Connecting should fail.");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
await server.StartAsync(new MqttServerOptionsBuilder().WithDefaultEndpointPort(testEnvironment.ServerPort).Build());
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Close_Idle_Connection()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
|
||||
var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
await client.ConnectAsync("localhost", testEnvironment.ServerPort);
|
||||
|
||||
// Don't send anything. The server should close the connection.
|
||||
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||
|
||||
try
|
||||
{
|
||||
var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
|
||||
if (receivedBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail("Receive should throw an exception.");
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Send_Garbage()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
|
||||
// Send an invalid packet and ensure that the server will close the connection and stay in a waiting state
|
||||
// forever. This is security related.
|
||||
var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
await client.ConnectAsync("localhost", testEnvironment.ServerPort);
|
||||
await client.SendAsync(Encoding.UTF8.GetBytes("Garbage"), SocketFlags.None);
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||
|
||||
try
|
||||
{
|
||||
var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
|
||||
if (receivedBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail("Receive should throw an exception.");
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Do_Not_Send_Retained_Messages_For_Denied_Subscription()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(c =>
|
||||
{
|
||||
// This should lead to no subscriptions for "n" at all. So also no sending of retained messages.
|
||||
if (c.TopicFilter.Topic == "n")
|
||||
{
|
||||
c.AcceptSubscription = false;
|
||||
}
|
||||
}));
|
||||
|
||||
// Prepare some retained messages.
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("y").WithPayload("x").WithRetainFlag().Build());
|
||||
await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("n").WithPayload("x").WithRetainFlag().Build());
|
||||
await client1.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
// Subscribe to all retained message types.
|
||||
// It is important to do this in a range of filters to ensure that a subscription is not "hidden".
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
client2.UseReceivedApplicationMessageHandler(c =>
|
||||
{
|
||||
lock (buffer)
|
||||
{
|
||||
buffer.Append(c.ApplicationMessage.Topic);
|
||||
}
|
||||
});
|
||||
|
||||
await client2.SubscribeAsync(new TopicFilter { Topic = "y" }, new TopicFilter { Topic = "n" });
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual("y", buffer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Collect_Messages_In_Disconnected_Session()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
// Create the session including the subscription.
|
||||
var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a"));
|
||||
await client1.SubscribeAsync("x");
|
||||
await client1.DisconnectAsync();
|
||||
await Task.Delay(500);
|
||||
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("b"));
|
||||
await client2.PublishAsync("x", "1");
|
||||
await client2.PublishAsync("x", "2");
|
||||
await client2.PublishAsync("x", "3");
|
||||
await client2.DisconnectAsync();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
clientStatus = await server.GetClientStatusAsync();
|
||||
var sessionStatus = await server.GetSessionStatusAsync();
|
||||
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
Assert.AreEqual(2, sessionStatus.Count);
|
||||
|
||||
Assert.AreEqual(3, sessionStatus.First(s => s.ClientId == "a").PendingApplicationMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task TestPublishAsync(
|
||||
string topic,
|
||||
MqttQualityOfServiceLevel qualityOfServiceLevel,
|
||||
string topicFilter,
|
||||
MqttQualityOfServiceLevel filterQualityOfServiceLevel,
|
||||
int expectedReceivedMessagesCount)
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("receiver"));
|
||||
c1.UseReceivedApplicationMessageHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic(topicFilter).WithQualityOfServiceLevel(filterQualityOfServiceLevel).Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("sender"));
|
||||
await c2.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(new byte[0]).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
|
||||
await c2.DisconnectAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(500);
|
||||
await c1.UnsubscribeAsync(topicFilter);
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:server="using:MQTTnet.Server"
|
||||
xmlns:status="using:MQTTnet.Server.Status"
|
||||
d:DesignHeight="800"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
@@ -228,7 +229,7 @@
|
||||
|
||||
<ListView ItemsSource="{Binding}" x:Name="ListViewSessions">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="server:IMqttClientSessionStatus">
|
||||
<DataTemplate x:DataType="status:IMqttClientStatus">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
@@ -237,11 +238,10 @@
|
||||
</StackPanel.Resources>
|
||||
<TextBlock Text="{Binding ClientId}"></TextBlock>
|
||||
<TextBlock Text="{Binding Endpoint}"></TextBlock>
|
||||
<TextBlock Text="{Binding IsConnected}"></TextBlock>
|
||||
<TextBlock Text="{Binding LastPacketReceived}"></TextBlock>
|
||||
<TextBlock Text="{Binding LastNonKeepAlivePacketReceived}"></TextBlock>
|
||||
<TextBlock Text="{Binding ProtocolVersion}"></TextBlock>
|
||||
<TextBlock Text="{Binding PendingApplicationMessagesCount}"></TextBlock>
|
||||
<TextBlock Text="{Binding Session}"></TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
|
||||
@@ -16,6 +16,7 @@ using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Server.Status;
|
||||
using MqttClientConnectedEventArgs = MQTTnet.Client.Connecting.MqttClientConnectedEventArgs;
|
||||
using MqttClientDisconnectedEventArgs = MQTTnet.Client.Disconnecting.MqttClientDisconnectedEventArgs;
|
||||
|
||||
@@ -24,7 +25,7 @@ namespace MQTTnet.TestApp.UniversalWindows
|
||||
public sealed partial class MainPage
|
||||
{
|
||||
private readonly ConcurrentQueue<MqttNetLogMessage> _traceMessages = new ConcurrentQueue<MqttNetLogMessage>();
|
||||
private readonly ObservableCollection<IMqttClientSessionStatus> _sessions = new ObservableCollection<IMqttClientSessionStatus>();
|
||||
private readonly ObservableCollection<IMqttClientStatus> _sessions = new ObservableCollection<IMqttClientStatus>();
|
||||
|
||||
private IMqttClient _mqttClient;
|
||||
private IManagedMqttClient _managedMqttClient;
|
||||
@@ -450,7 +451,7 @@ namespace MQTTnet.TestApp.UniversalWindows
|
||||
return;
|
||||
}
|
||||
|
||||
var sessions = _mqttServer.GetClientSessionsStatusAsync().GetAwaiter().GetResult();
|
||||
var sessions = _mqttServer.GetClientStatusAsync().GetAwaiter().GetResult();
|
||||
_sessions.Clear();
|
||||
|
||||
foreach (var session in sessions)
|
||||
|
||||
Reference in New Issue
Block a user