// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using MQTTnet.Formatter; using MQTTnet.Packets; using MQTTnet.Protocol; namespace MQTTnet.Tests.Server; // ReSharper disable InconsistentNaming [TestClass] public sealed class KeepAlive_Tests : BaseTestClass { [TestMethod] public async Task Disconnect_Client_DueTo_KeepAlive() { using var testEnvironment = CreateTestEnvironment(); await testEnvironment.StartServer(); var client = await testEnvironment.ConnectLowLevelClient(o => o .WithTimeout(TimeSpan.FromSeconds(1)) .WithTimeout(TimeSpan.Zero) .WithProtocolVersion(MqttProtocolVersion.V500)); await client.SendAsync(new MqttConnectPacket { CleanSession = true, ClientId = "Disconnect_Client_DueTo_KeepAlive", KeepAlivePeriod = 1 }, CancellationToken.None); var responsePacket = await client.ReceiveAsync(CancellationToken.None); Assert.IsTrue(responsePacket is MqttConnAckPacket); for (var i = 0; i < 6; i++) { await Task.Delay(500); await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None); responsePacket = await client.ReceiveAsync(CancellationToken.None); Assert.IsTrue(responsePacket is MqttPingRespPacket); } // If we reach this point everything works as expected (server did not close the connection // due to proper ping messages. // Now we will wait 1.1 seconds because the server MUST wait 1.5 seconds in total (See spec). await Task.Delay(1100); await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None); responsePacket = await client.ReceiveAsync(CancellationToken.None); Assert.IsTrue(responsePacket is MqttPingRespPacket); // Now we will wait longer than 1.5 so that the server will close the connection. responsePacket = await client.ReceiveAsync(CancellationToken.None); var disconnectPacket = responsePacket as MqttDisconnectPacket; Assert.IsNotNull(disconnectPacket); Assert.AreEqual(MqttDisconnectReasonCode.KeepAliveTimeout, disconnectPacket.ReasonCode); } }