/* Commented multi gateway tests as they make C2D tests flaky for now * [RetryFact] * public Task Test_OTAA_Unconfirmed_Receives_Confirmed_C2D_Message_MultiGw() * { * var device = TestFixtureCi.GetDeviceByPropertyName(nameof(TestFixtureCi.Device14_OTAA_MultiGw)); * LogTestStart(device); * return Test_OTAA_Unconfirmed_Receives_Confirmed_C2D_Message(device); * } */ // Ensures that C2D messages are received when working with unconfirmed messages // Uses Device10_OTAA private async Task Test_OTAA_Unconfirmed_Receives_Confirmed_C2D_Message(TestDeviceInfo device) { const int messagesToSend = 10; const int warmUpMessageCount = 2; await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWOTAA); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, device.AppEui); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, device.AppKey); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await TestFixture.CleanupC2DDeviceQueueAsync(device.DeviceID); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); // wait 1 second after joined await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); if (device.IsMultiGw) { await TestFixtureCi.WaitForTwinSyncAfterJoinAsync(ArduinoDevice.SerialLogs, device.DevEui); } // Sends 2x unconfirmed messages for (var i = 1; i <= warmUpMessageCount; ++i) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); Log($"{device.DeviceID}: Sending unconfirmed '{msg}' {i}/{messagesToSend}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); TestFixtureCi.ClearLogs(); } // sends C2D - between 10 and 99 var c2dMessageBody = (100 + random.Next(90)).ToString(CultureInfo.InvariantCulture); var msgId = Guid.NewGuid().ToString(); var c2dMessage = new LoRaCloudToDeviceMessage() { Payload = c2dMessageBody, Fport = FramePorts.App1, MessageId = msgId, Confirmed = true, }; await TestFixtureCi.SendCloudToDeviceMessageAsync(device.DeviceID, c2dMessage); Log($"Message {c2dMessageBody} sent to device, need to check if it receives"); var foundC2DMessageCount = 0; var foundReceivePacketCount = 0; var expectedRxSerial = $"+MSG: PORT: 1; RX: \"{ToHexString(c2dMessageBody)}\""; var expectedTcpMessageV1 = $"{device.DevAddr}: ConfirmedDataDown"; var expectedTcpMessageV2 = $"{device.DeviceID}: cloud to device message: {ToHexString(c2dMessageBody)}, id: {msgId}, fport: 1, confirmed: True"; Log($"Expected C2D received log is: {expectedRxSerial}"); Log($"Expected TCP log starting with: {expectedTcpMessageV1} or {expectedTcpMessageV2}"); // Sends 8x unconfirmed messages, stopping if C2D message is found for (var i = warmUpMessageCount + 1; i <= messagesToSend; ++i) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); Log($"{device.DeviceID}: Sending unconfirmed '{msg}' {i}/{messagesToSend}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // check if c2d message was found var searchResults = await TestFixtureCi.SearchNetworkServerModuleAsync( (messageBody) => { return(messageBody.StartsWith(expectedTcpMessageV1, StringComparison.OrdinalIgnoreCase) || messageBody.StartsWith(expectedTcpMessageV2, StringComparison.OrdinalIgnoreCase)); }, new SearchLogOptions($"{expectedTcpMessageV1} or {expectedTcpMessageV2}") { MaxAttempts = 1 }); // We should only receive the message once if (searchResults.Found) { foundC2DMessageCount++; Log($"{device.DeviceID}: Found C2D message in log (after sending {i}/{messagesToSend}) {foundC2DMessageCount} times"); EnsureNotSeenTooManyTimes(foundC2DMessageCount); } var localFoundCloudToDeviceInSerial = ArduinoDevice.SerialLogs.Contains(expectedRxSerial); if (localFoundCloudToDeviceInSerial) { foundReceivePacketCount++; Log($"{device.DeviceID}: Found C2D message in serial logs (after sending {i}/{messagesToSend}) {foundReceivePacketCount} times"); EnsureNotSeenTooManyTimes(foundReceivePacketCount); } TestFixtureCi.ClearLogs(); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); } Assert.True(foundC2DMessageCount > 0, $"Did not find {expectedTcpMessageV1} or {expectedTcpMessageV2} in logs"); // checks if log arrived if (foundReceivePacketCount == 0) { if (ArduinoDevice.SerialLogs.Contains(expectedRxSerial)) { foundReceivePacketCount++; } } Assert.True(foundReceivePacketCount > 0, $"Could not find lora receiving message '{expectedRxSerial}'"); }
public async Task Test_OTAA_Confirmed_Receives_C2D_Message_With_RX_Delay_2() { const int messagesToSend = 10; const int warmUpMessageCount = 2; var device = TestFixtureCi.Device9_OTAA; LogTestStart(device); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWOTAA); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, device.AppEui); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, device.AppKey); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await TestFixture.CleanupC2DDeviceQueueAsync(device.DeviceID); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); // find the gateway that accepted the join const string expectedLog = "JoinAccept"; var joinAccept = await TestFixtureCi.SearchNetworkServerModuleAsync((s) => s.IndexOf(expectedLog, StringComparison.OrdinalIgnoreCase) != -1, new SearchLogOptions(expectedLog)); Assert.NotNull(joinAccept); Assert.NotNull(joinAccept.MatchedEvent); var targetGw = joinAccept.MatchedEvent.SourceId; Assert.Equal(device.GatewayID, targetGw); // wait 1 second after joined await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); // Sends 2x confirmed messages for (var i = 1; i <= warmUpMessageCount; ++i) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); Log($"{device.DeviceID}: Sending confirmed '{msg}' {i}/{messagesToSend}"); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); TestFixtureCi.ClearLogs(); } // sends C2D - between 10 and 99 var c2dMessageBody = (100 + random.Next(90)).ToString(CultureInfo.InvariantCulture); var c2dMessage = new LoRaCloudToDeviceMessage() { Payload = c2dMessageBody, Fport = FramePorts.App1, MessageId = Guid.NewGuid().ToString(), }; await TestFixtureCi.SendCloudToDeviceMessageAsync(device.DeviceID, c2dMessage); Log($"Message {c2dMessageBody} sent to device, need to check if it receives"); var foundC2DMessageCount = 0; var foundReceivePacketCount = 0; var expectedRxSerial = $"+CMSG: PORT: 1; RX: \"{ToHexString(c2dMessageBody)}\""; Log($"Expected C2D received log is: {expectedRxSerial}"); var c2dLogMessage = $"{device.DeviceID}: done completing cloud to device message, id: {c2dMessage.MessageId}"; Log($"Expected C2D network server log is: {expectedRxSerial}"); // Sends 8x confirmed messages, stopping if C2D message is found for (var i = warmUpMessageCount + 1; i <= messagesToSend; ++i) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); Log($"{device.DeviceID}: Sending confirmed '{msg}' {i}/{messagesToSend}"); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(TimeSpan.FromSeconds(5)); // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // Check that RXDelay was correctly used await TestFixtureCi.CheckAnswerTimingAsync(device.RXDelay, device.GatewayID); // check if c2d message was found // 0000000000000009: C2D message: 58 var searchResults = await TestFixtureCi.SearchNetworkServerModuleAsync( (messageBody) => { return(messageBody.StartsWith(c2dLogMessage, StringComparison.OrdinalIgnoreCase)); }, new SearchLogOptions(c2dLogMessage) { MaxAttempts = 1 }); // We should only receive the message once if (searchResults.Found) { foundC2DMessageCount++; Log($"{device.DeviceID}: Found C2D message in log (after sending {i}/{messagesToSend}) {foundC2DMessageCount} times"); EnsureNotSeenTooManyTimes(foundC2DMessageCount); } var localFoundCloudToDeviceInSerial = ArduinoDevice.SerialLogs.Contains(expectedRxSerial); if (localFoundCloudToDeviceInSerial) { foundReceivePacketCount++; Log($"{device.DeviceID}: Found C2D message in serial logs (after sending {i}/{messagesToSend}) {foundReceivePacketCount} times"); EnsureNotSeenTooManyTimes(foundReceivePacketCount); } TestFixtureCi.ClearLogs(); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); } Assert.True(foundC2DMessageCount > 0, $"Did not find '{device.DeviceID}: C2D message: {c2dMessageBody}' in logs"); // checks if log arrived if (foundReceivePacketCount == 0) { if (ArduinoDevice.SerialLogs.Contains(expectedRxSerial)) { foundReceivePacketCount++; } } Assert.True(foundReceivePacketCount > 0, $"Could not find lora receiving message '{expectedRxSerial}'"); }
private async Task Test_Deduplication_Strategies(string devicePropertyName, string strategy) { var device = TestFixtureCi.GetDeviceByPropertyName(devicePropertyName); LogTestStart(device); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, null); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); for (var i = 0; i < 10; i++) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); var allGwGotIt = await TestFixtureCi.ValidateMultiGatewaySources((log) => log.IndexOf($"deduplication Strategy: {strategy}", StringComparison.OrdinalIgnoreCase) != -1); if (allGwGotIt) { var notDuplicate = "\"IsDuplicate\":false"; var isDuplicate = "\"IsDuplicate\":true"; var notDuplicateResult = await TestFixtureCi.SearchNetworkServerModuleAsync((s) => s.IndexOf(notDuplicate, StringComparison.Ordinal) != -1, new SearchLogOptions(notDuplicate)); var duplicateResult = await TestFixtureCi.SearchNetworkServerModuleAsync((s) => s.IndexOf(isDuplicate, StringComparison.Ordinal) != -1, new SearchLogOptions(isDuplicate)); Assert.NotNull(notDuplicateResult.MatchedEvent); Assert.NotNull(duplicateResult.MatchedEvent); Assert.NotEqual(duplicateResult.MatchedEvent.SourceId, notDuplicateResult.MatchedEvent.SourceId); switch (strategy) { case "Mark": var expectedProperty = "dupmsg"; await TestFixture.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedProperty, "true", new SearchLogOptions(expectedProperty) { SourceIdFilter = duplicateResult.MatchedEvent.SourceId, TreatAsError = true }); await TestFixture.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedProperty, "true", new SearchLogOptions(expectedProperty) { SourceIdFilter = notDuplicateResult.MatchedEvent.SourceId, TreatAsError = true }); break; case "Drop": var logMsg = $"{device.DeviceID}: duplication strategy indicated to not process message"; var droppedLog = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(logMsg, StringComparison.Ordinal), new SearchLogOptions(logMsg) { SourceIdFilter = duplicateResult.MatchedEvent.SourceId }); Assert.NotNull(droppedLog.MatchedEvent); var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload) { TreatAsError = true }); break; default: throw new SwitchExpressionException(); } } TestFixtureCi.ClearLogs(); } }