private async Task SendABPMessages(int messages_count, TestDeviceInfo 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); // Sends 10x unconfirmed messages for (var i = 0; i < messages_count; ++i) { var msg = GeneratePayloadMessage(); Log($"{device.DeviceID}: Sending unconfirmed '{msg}' {i + 1}/{messages_count}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000005: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000005: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); TestFixtureCi.ClearLogs(); } // Sends 10x confirmed messages for (var i = 0; i < messages_count; ++i) { var msg = GeneratePayloadMessage(); Log($"{device.DeviceID}: Sending confirmed '{msg}' {i + 1}/{messages_count}"); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // 0000000000000005: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000005: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); TestFixtureCi.ClearLogs(); } }
public async Task OTAA_Join_With_Wrong_AppKey_Fails() { var device = TestFixtureCi.Device3_OTAA; LogTestStart(device); var appKeyToUse = AppKey.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); Assert.NotEqual(appKeyToUse, device.AppKey); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWOTAA); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, device.AppEui); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, appKeyToUse); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 3); Assert.False(joinSucceeded, "Join suceeded for invalid AppKey (mic check should fail)"); await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync( $"{device.DeviceID}: join refused: invalid MIC", $"{device.DeviceID}: join request MIC invalid"); await ArduinoDevice.WaitForIdleAsync(); }
public async Task SensorDecoder_ReflectionBased_ValueSensorDecoder_DecodesPayload() { var device = TestFixtureCi.Device12_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); 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); await ArduinoDevice.transferPacketWithConfirmedAsync("4321", 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // Find "0000000000000011: message '{"value":1234}' sent to hub" in network server logs await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":4321}}' sent to hub"); TestFixtureCi.ClearLogs(); }
// Ensures that Mac Commands C2D messages working // Uses Device23_OTAA private async Task Test_OTAA_Unconfirmed_Send_And_Receive_C2D_Mac_Commands(TestDeviceInfo 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); 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); } await Test_OTAA_Unconfirmed_Send_And_Receive_C2D_Mac_CommandsImplAsync(device, "test"); await Test_OTAA_Unconfirmed_Send_And_Receive_C2D_Mac_CommandsImplAsync(device, string.Empty); }
public async Task Test_MultiGW_OTTA_Join_Single() { var device = TestFixtureCi.Device27_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); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); // validate that one GW refused the join const string joinRefusedMsg = "join refused"; var joinRefused = await TestFixtureCi.AssertNetworkServerModuleLogExistsAsync((s) => s.IndexOf(joinRefusedMsg, StringComparison.Ordinal) != -1, new SearchLogOptions(joinRefusedMsg)); Assert.True(joinRefused.Found); await TestFixtureCi.WaitForTwinSyncAfterJoinAsync(ArduinoDevice.SerialLogs, device.DevEui); // expecting both gw to start picking up messages // and sending to IoT hub. var bothReported = false; for (var i = 0; i < 5; i++) { var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); bothReported = await TestFixtureCi.ValidateMultiGatewaySources((log) => log.StartsWith($"{device.DeviceID}: sending message", StringComparison.OrdinalIgnoreCase)); if (bothReported) { break; } } Assert.True(bothReported); }
public async Task Test_Concentrator_Deduplication_OTAA() { Assert.True(this.initializationSucceeded); var device = TestFixtureCi.GetDeviceByPropertyName("Device31_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); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); var droppedLog = await TestFixtureCi.SearchNetworkServerModuleAsync( (log) => log.IndexOf(this.expectedLog, StringComparison.Ordinal) != -1, new SearchLogOptions(this.expectedLog)); Assert.NotNull(droppedLog.MatchedEvent); // wait 1 second after joined await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); const int MESSAGE_COUNT = 5; for (var i = 0; i < MESSAGE_COUNT; ++i) { Log($"{device.DeviceID}: Sending OTAA confirmed message {i + 1}/{MESSAGE_COUNT}"); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // 0000000000000031: message '{"value": 101}' sent to hub var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); droppedLog = await TestFixtureCi.SearchNetworkServerModuleAsync( (log) => log.IndexOf(this.expectedLog, StringComparison.Ordinal) != -1, new SearchLogOptions(this.expectedLog)); Assert.NotNull(droppedLog.MatchedEvent); TestFixtureCi.ClearLogs(); } }
public async Task Test_ClassC_Send_Message_Using_Function_Endpoint_Should_Be_Received() { var device = TestFixtureCi.Device24_ABP; 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); await ArduinoDevice.setClassTypeAsync(LoRaArduinoSerial._class_type_t.CLASS_C); // send one confirmed message for ensuring that a basicstation is "bound" to the device await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); Log($"{device.DeviceID}: Sending confirmed '{msg}'"); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); TestFixtureCi.ClearLogs(); // Now sending a c2d var c2d = new LoRaCloudToDeviceMessage() { DevEUI = DevEui.Parse(device.DeviceID), MessageId = Guid.NewGuid().ToString(), Fport = FramePorts.App23, RawPayload = Convert.ToBase64String(new byte[] { 0xFF, 0x00 }), }; TestLogger.Log($"[INFO] Using service API to send C2D message to device {device.DeviceID}"); TestLogger.Log($"[INFO] {JsonConvert.SerializeObject(c2d, Formatting.None)}"); // send message using the SendCloudToDeviceMessage API endpoint Assert.True(await LoRaAPIHelper.SendCloudToDeviceMessage(device.DevEui, c2d)); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // 0000000000000024: received cloud to device message from direct method await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: received cloud to device message from direct method"); Assert.Contains(ArduinoDevice.SerialLogs, (l) => l.Contains("PORT: 23; RX: \"FF00\"", StringComparison.Ordinal)); Assert.Contains(ArduinoDevice.SerialLogs, (l) => l.Contains("RXWIN0, RSSI", StringComparison.Ordinal)); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); }
public async Task Test_ABP_Mismatch_NwkSKey_And_AppSKey_Fails_Mic_Validation() { var device = TestFixtureCi.Device7_ABP; LogTestStart(device); var appSKeyToUse = AppSessionKey.Parse("000102030405060708090A0B0C0D0E0F"); var nwkSKeyToUse = NetworkSessionKey.Parse("01020304050607080910111213141516"); Assert.NotEqual(appSKeyToUse, device.AppSKey); Assert.NotEqual(nwkSKeyToUse, device.NwkSKey); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, null); await ArduinoDevice.setKeyAsync(nwkSKeyToUse, appSKeyToUse, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); // wait for serial logs to be ready await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +MSG: Done // await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", this.lora.SerialLogs); // 0000000000000005: with devAddr 0028B1B0 check MIC failed. Device will be ignored from now on await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); TestFixtureCi.ClearLogs(); // Try with confirmed message await ArduinoDevice.transferPacketWithConfirmedAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // 0000000000000005: with devAddr 0028B1B0 check MIC failed await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); // wait until arduino stops trying to send confirmed msg await ArduinoDevice.WaitForIdleAsync(); }
public async Task Test_Device_Initiated_Mac_LinkCheckCmd_Should_work() { try { const int MESSAGES_COUNT = 3; var device = TestFixtureCi.Device22_ABP; 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.setPortAsync(0); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); for (var i = 0; i < MESSAGES_COUNT; ++i) { var msg = "02"; Log($"{device.DeviceID}: Sending unconfirmed Mac LinkCheckCmd message"); await ArduinoDevice.transferHexPacketAsync(msg, 10); await Task.Delay(2 *Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSGHEX: Done", ArduinoDevice.SerialLogs); await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: LinkCheckCmd mac command detected in upstream payload:"); } await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: answering to a"); } finally { await ArduinoDevice.setPortAsync(1); } TestFixtureCi.ClearLogs(); }
public async Task OTAA_Join_With_Wrong_DevEUI_Fails() { var device = TestFixtureCi.Device2_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); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 3); Assert.False(joinSucceeded, "Join suceeded for invalid DevEUI"); await ArduinoDevice.WaitForIdleAsync(); }
public async Task Test_ABP_Invalid_NwkSKey_Fails_With_Mic_Error() { var device = TestFixtureCi.Device8_ABP; LogTestStart(device); var nwkSKeyToUse = NetworkSessionKey.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); Assert.NotEqual(nwkSKeyToUse, device.NwkSKey); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, null); await ArduinoDevice.setKeyAsync(nwkSKeyToUse, device.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000008: with devAddr 0028B1B3 check MIC failed. Device will be ignored from now on await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); TestFixtureCi.ClearLogs(); // Try with confirmed message await ArduinoDevice.transferPacketWithConfirmedAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // 0000000000000008: with devAddr 0028B1B3 check MIC failed. await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); // Before starting new test, wait until Lora drivers stops sending/receiving data await ArduinoDevice.WaitForIdleAsync(); }
public async Task Data_Rate_Is_Updated_When_C2D_With_LinkADRCmd_Received() { const int messagesToSend = 10; const int warmUpMessageCount = 2; var device = TestFixtureCi.Device32_ABP; LogTestStart(device); // Setup LoRa device properties await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, device.AppEui); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, device.AppKey); // Setup protocol properties // Start with DR5 await ArduinoDevice.SetupLora(TestFixtureCi.Configuration.LoraRegion, LoRaArduinoSerial._data_rate_t.DR5, 4, true); await TestFixture.CleanupC2DDeviceQueueAsync(device.DeviceID); // 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); TestFixture.ClearLogs(); } var c2dMessage = new LoRaCloudToDeviceMessage() { Fport = FramePort.MacCommand, Payload = String.Empty, MacCommands = { new LinkADRRequest(datarate: 3, txPower: 4, chMask: 25, chMaskCntl: 0, nbTrans: 1) } // Update data rate to DR3 }; await TestFixtureCi.SendCloudToDeviceMessageAsync(device.DeviceID, c2dMessage); Log($"C2D Message sent to device, need to check if it receives"); var foundC2DMessage = false; var foundLinkADRCmd = false; var foundChangedDataRate = false; // Sends 8x unconfirmed messages, stopping if C2D message is found and data rate is updated 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_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // check if C2D message was found if (await SearchMessageAsync($"{device.DeviceID}: cloud to device MAC command LinkADRCmd received Type: LinkADRCmd Answer, datarate: 3")) { foundC2DMessage = true; } // check if LinkADRCmd MAC Command was detected if (await SearchMessageAsync("LinkADRCmd mac command detected in upstream payload: Type: LinkADRCmd Answer, power: changed, data rate: changed")) { foundLinkADRCmd = true; } // check if the data rate was changed to DR3 if (await SearchMessageAsync("\"datr\":\"SF9BW125\"")) { foundChangedDataRate = true; } async Task <bool> SearchMessageAsync(string message) { var searchResult = await TestFixtureCi.SearchNetworkServerModuleAsync(messageBody => messageBody.Contains(message, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(message) { MaxAttempts = 1 }); return(searchResult.Found); } TestFixture.ClearLogs(); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); if (foundC2DMessage && foundLinkADRCmd && foundChangedDataRate) { break; } } Assert.True(foundC2DMessage, $"Could not find C2D message with MAC command LinkADRCmd in LNS log"); Assert.True(foundLinkADRCmd, $"Could not find LinkADRCmd MAC Command in LNS log"); Assert.True(foundChangedDataRate, $"Could not find updated data rate in LNS log"); }
// Verifies that ABP confirmed and unconfirmed messages are working // Uses Device5_ABP private async Task Test_ABP_Confirmed_And_Unconfirmed_Message_With_ADR(TestDeviceInfo device) { if (device.IsMultiGw) { Assert.True(await LoRaAPIHelper.ResetADRCache(device.DevEui)); } await ArduinoDevice.setDeviceDefaultAsync(); const int MESSAGES_COUNT = 10; 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.LoraRegion, LoRaArduinoSerial._data_rate_t.DR3, 4, true); // for a reason I need to set DR twice otherwise it reverts to DR 0 // await ArduinoDevice.setDataRateAsync(LoRaArduinoSerial._data_rate_t.DR3, LoRaArduinoSerial._physical_type_t.EU868); // Sends 5x unconfirmed messages for (var i = 0; i < MESSAGES_COUNT / 2; ++i) { var msg = GeneratePayloadMessage(); Log($"{device.DeviceID}: Sending unconfirmed '{msg}' {i + 1}/{MESSAGES_COUNT}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000005: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000005: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); TestFixtureCi.ClearLogs(); } // Sends 5x confirmed messages for (var i = 0; i < MESSAGES_COUNT / 2; ++i) { var msg = GeneratePayloadMessage(); Log($"{device.DeviceID}: Sending confirmed '{msg}' {i + 1}/{MESSAGES_COUNT / 2}"); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(2 *Constants.DELAY_BETWEEN_MESSAGES); // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // 0000000000000005: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000005: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); if (device.IsMultiGw) { var searchTokenSending = $"{device.DeviceID}: sending message to station with EUI"; var sending = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenSending, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenSending)); Assert.NotNull(sending.MatchedEvent); var searchTokenAlreadySent = $"{device.DeviceID}: another gateway has already sent ack or downlink msg"; var ignored = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenAlreadySent, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenAlreadySent)); Assert.NotNull(ignored.MatchedEvent); Assert.NotEqual(sending.MatchedEvent.SourceId, ignored.MatchedEvent.SourceId); } TestFixtureCi.ClearLogs(); } // Sends 10x unconfirmed messages for (var i = 0; i < MESSAGES_COUNT; ++i) { var msg = GeneratePayloadMessage(); Log($"{device.DeviceID}: Sending unconfirmed '{msg}' {i + 1}/{MESSAGES_COUNT / 2}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000005: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000005: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); TestFixtureCi.ClearLogs(); } // Starting ADR test protocol Log($"{device.DeviceID}: Starting ADR protocol"); for (var i = 0; i < 56; ++i) { var message = GeneratePayloadMessage(); await ArduinoDevice.transferPacketAsync(message, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); } await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: ADR ack request received"); var searchTokenADRRateAdaptation = $"{device.DeviceID}: performing a rate adaptation: DR"; var received = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenADRRateAdaptation, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenADRRateAdaptation)); Assert.NotNull(received.MatchedEvent); if (device.IsMultiGw) { var searchTokenADRAlreadySent = $"{device.DeviceID}: another gateway has already sent ack or downlink msg"; var ignored = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenADRAlreadySent, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenADRAlreadySent)); Assert.NotNull(ignored.MatchedEvent); Assert.NotEqual(received.MatchedEvent.SourceId, ignored.MatchedEvent.SourceId); } // Check the messages are now sent on DR5 for (var i = 0; i < 2; ++i) { var message = GeneratePayloadMessage(); await ArduinoDevice.transferPacketAsync(message, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: LinkADRCmd mac command detected in upstream payload: Type: LinkADRCmd Answer, power: changed, data rate: changed,", $"{device.DevAddr}: LinkADRCmd mac command detected in upstream payload: Type: LinkADRCmd Answer, power: not changed, data rate: changed,"); } }
public async Task Test_ABP_Device_With_Connection_Timeout() { LogTestStart(new TestDeviceInfo[] { TestFixtureCi.Device25_ABP, TestFixtureCi.Device26_ABP }); // Sends 1 message from device 25 var device25 = TestFixtureCi.Device25_ABP; await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device25.DevAddr, device25.DeviceID, null); await ArduinoDevice.setKeyAsync(device25.NwkSKey, device25.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); var expectedLog = $"{device25.DeviceID}: processing time"; await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(expectedLog, StringComparison.Ordinal), new SearchLogOptions(expectedLog)); // wait 61 seconds await Task.Delay(TimeSpan.FromSeconds(120)); // Send 1 message from device 26 var device26 = TestFixtureCi.Device26_ABP; await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device26.DevAddr, device26.DeviceID, null); await ArduinoDevice.setKeyAsync(device26.NwkSKey, device26.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); var expectedLog2 = $"{device25.DeviceID}: device client disconnected"; var result = await TestFixtureCi.SearchNetworkServerModuleAsync( msg => msg.StartsWith(expectedLog2, StringComparison.Ordinal), new SearchLogOptions(expectedLog2) { MaxAttempts = 10, SourceIdFilter = device25.GatewayID, }); Assert.NotNull(result.MatchedEvent); TestFixtureCi.ClearLogs(); // Send 1 message from device 25 and check that connection was restablished await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device25.DevAddr, device25.DeviceID, null); await ArduinoDevice.setKeyAsync(device25.NwkSKey, device25.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); var expectedMessage = GeneratePayloadMessage(); await ArduinoDevice.transferPacketAsync(expectedMessage, 10); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000005: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device25.DeviceID}: message '{{\"value\":{expectedMessage}}}' sent to hub"); // "device client reconnected" await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device25.DeviceID}: device client reconnected"); }
/* 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}'"); }
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(); } }
public async Task Test_Concentrator_Can_Receive_Updates_Then_Connect_To_Lns_And_Receive_Messages() { //arrange var temporaryDirectoryName = string.Empty; var stationEui = StationEui.Parse(TestFixture.Configuration.CupsBasicStationEui); var clientThumbprint = TestFixture.Configuration.ClientThumbprint; var crcParseResult = uint.TryParse(TestFixture.Configuration.ClientBundleCrc, out var crc); var sigCrcParseResult = uint.TryParse(TestFixture.Configuration.CupsSigKeyChecksum, out var sigCrc); try { var device = TestFixtureCi.GetDeviceByPropertyName(nameof(TestFixtureCi.Device33_OTAA)); LogTestStart(device, stationEui); if (!string.IsNullOrEmpty(clientThumbprint)) { //if a test re-run, clientThumbprint will be empty, therefore there's nothing to do, previously generated certificates will be reused //update allowed client thumbprints in IoT Hub Twin to only have the one being added await TestFixture.UpdateExistingConcentratorThumbprint(stationEui, condition : (originalArray) => !originalArray.Any(x => x.Equals(clientThumbprint, StringComparison.OrdinalIgnoreCase)), action : (originalList) => { originalList.RemoveAll(x => true); // remove all keys originalList.Add(clientThumbprint); // add only new thumbprint }); } if (crcParseResult) { //if a test re-run, crc field will be empty, therefore there's nothing to do, previously generated certificates will be reused //update crc value with the one being generated in ci await TestFixture.UpdateExistingConcentratorCrcValues(stationEui, crc); } var fwDigest = TestFixture.Configuration.CupsFwDigest; var fwPackage = TestFixture.Configuration.CupsBasicStationPackage; var fwUrl = TestFixture.Configuration.CupsFwUrl; if (sigCrcParseResult && !string.IsNullOrEmpty(fwDigest) && !string.IsNullOrEmpty(fwPackage) && fwUrl is not null) { //if a test re-run, the fields will be empty, therefore there's no update to achieve await TestFixture.UpdateExistingFirmwareUpgradeValues(stationEui, sigCrc, fwDigest, fwPackage, fwUrl); } //setup the concentrator with CUPS_URI only (certificates are retrieved from default location) TestUtils.StartBasicsStation(TestFixture.Configuration, new Dictionary <string, string>() { { "TLS_SNI", "false" }, { "CUPS_URI", TestFixture.Configuration.SharedCupsEndpoint }, { "FIXED_STATION_EUI", stationEui.ToString() }, { "RADIODEV", TestFixture.Configuration.RadioDev } }, out temporaryDirectoryName); // Waiting 30s for being sure that BasicStation actually started up await Task.Delay(30_000); // If package log does not match, firmware upgrade process failed var expectedLog = stationEui + $": Received 'version' message for station '{TestFixture.Configuration.CupsBasicStationVersion}' with package '{fwPackage}'"; var log = await TestFixtureCi.SearchNetworkServerModuleAsync( (log) => log.IndexOf(expectedLog, StringComparison.Ordinal) != -1, new SearchLogOptions(expectedLog) { MaxAttempts = 1 }); Assert.True(log.Found); //the concentrator should be ready at this point to receive messages //if receiving 'updf' is succeeding, cups worked successfully 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); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); var expectedLog2 = stationEui + ": Received 'jreq' message"; var jreqLog = await TestFixtureCi.SearchNetworkServerModuleAsync( (log) => log.IndexOf(expectedLog2, StringComparison.Ordinal) != -1, new SearchLogOptions(expectedLog2) { MaxAttempts = 2 }); Assert.NotNull(jreqLog.MatchedEvent); // wait 1 second after joined await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); Log($"{device.DeviceID}: Sending OTAA unconfirmed message"); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); var expectedLog3 = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedLog3, new SearchLogOptions(expectedLog3) { MaxAttempts = 2 }); var expectedLog4 = stationEui + ": Received 'updf' message"; var updfLog = await TestFixtureCi.SearchNetworkServerModuleAsync( (log) => log.IndexOf(expectedLog4, StringComparison.Ordinal) != -1, new SearchLogOptions(expectedLog4) { MaxAttempts = 2 }); Assert.True(updfLog.Found); var twin = await TestFixture.GetTwinAsync(stationEui.ToString()); var twinReader = new TwinCollectionReader(twin.Properties.Reported, null); Assert.True(twinReader.TryRead <string>(TwinProperty.Package, out var reportedPackage) && string.Equals(fwPackage, reportedPackage, StringComparison.OrdinalIgnoreCase)); } finally { TestUtils.KillBasicsStation(TestFixture.Configuration, temporaryDirectoryName, out var logFilePath); if (!string.IsNullOrEmpty(logFilePath) && File.Exists(logFilePath)) { Log("[INFO] ** Basic Station Logs Start **"); Log(await File.ReadAllTextAsync(logFilePath)); Log("[INFO] ** Basic Station Logs End **"); File.Delete(logFilePath); } } TestFixtureCi.ClearLogs(); }
public async Task OTAA_Join_With_Valid_Device_Updates_DeviceTwin() { var device = TestFixtureCi.Device1_OTAA; LogTestStart(device); var twinBeforeJoin = await TestFixtureCi.GetTwinAsync(device.DeviceID); 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); var joinSucceeded = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded, "Join failed"); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_JOIN); // After join: Expectation on serial // +JOIN: Network joined // +JOIN: NetID 010000 DevAddr 02:9B:0D:3E // Assert.Contains("+JOIN: Network joined", this.lora.SerialLogs); await AssertUtils.ContainsWithRetriesAsync( (s) => s.StartsWith("+JOIN: NetID", StringComparison.Ordinal), ArduinoDevice.SerialLogs); // verify status in device twin await Task.Delay(TimeSpan.FromSeconds(60)); var twinAfterJoin = await TestFixtureCi.GetTwinAsync(device.DeviceID); Assert.NotNull(twinAfterJoin); Assert.NotNull(twinAfterJoin.Properties.Reported); try { Assert.True(twinAfterJoin.Properties.Reported.Contains("FCntUp"), "Property FCntUp does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("FCntDown"), "Property FCntDown does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("NetId"), "Property NetId does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("DevAddr"), "Property DevAddr does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("DevNonce"), "Property DevNonce does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("NwkSKey"), "Property NwkSKey does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("AppSKey"), "Property AppSKey does not exist"); Assert.True(twinAfterJoin.Properties.Reported.Contains("DevEUI"), "Property DevEUI does not exist"); var devAddrBefore = (string)twinBeforeJoin.Properties.Reported["DevAddr"]; var devAddrAfter = (string)twinAfterJoin.Properties.Reported["DevAddr"]; var actualReportedDevEUI = (string)twinAfterJoin.Properties.Reported["DevEUI"]; Assert.NotEqual(devAddrAfter, devAddrBefore); Assert.Equal(device.DeviceID, actualReportedDevEUI); Assert.True(twinBeforeJoin.Properties.Reported.Version < twinAfterJoin.Properties.Reported.Version, "Twin was not updated after join"); Log($"[INFO] Twin was updated successfully. Version changed from {twinBeforeJoin.Properties.Reported.Version} to {twinAfterJoin.Properties.Reported.Version}"); } catch (XunitException xunitException) { if (TestFixtureCi.Configuration.IoTHubAssertLevel == LogValidationAssertLevel.Warning) { Log($"[WARN] {nameof(OTAA_Join_With_Valid_Device_Updates_DeviceTwin)} failed. {xunitException}"); } else if (TestFixtureCi.Configuration.IoTHubAssertLevel == LogValidationAssertLevel.Error) { throw; } } }
// Performs a OTAA join and sends 1 unconfirmed, 1 confirmed and rejoins private async Task Test_OTAA_Join_Send_And_Rejoin_With_Custom_RX2_DR(TestDeviceInfo 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); 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 1x unconfirmed messages TestFixtureCi.ClearLogs(); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000004: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000004: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000004: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); // Ensure device payload is available // Data: {"value": 51} var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); TestFixtureCi.ClearLogs(); msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs); // Checking than the communication occurs on DR 4 and RX2 as part of preferred windows RX2 and custom RX2 DR await AssertUtils.ContainsWithRetriesAsync(x => x.StartsWith("+CMSG: RXWIN2", StringComparison.Ordinal), ArduinoDevice.SerialLogs); // this test has a custom datarate for RX 2 of 3 const string logMessage2 = "\"Rx2\":{\"DataRate\":3"; await TestFixtureCi.AssertNetworkServerModuleLogExistsAsync(x => x.Contains(logMessage2, StringComparison.Ordinal), new SearchLogOptions(logMessage2)); // 0000000000000004: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000004: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); // Ensure device payload is available // Data: {"value": 51} expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // rejoin 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); var joinSucceeded2 = await ArduinoDevice.setOTAAJoinAsyncWithRetry(LoRaArduinoSerial._otaa_join_cmd_t.JOIN, 20000, 5); Assert.True(joinSucceeded2, "Rejoin failed"); if (device.IsMultiGw) { const string joinRefusedMsg = "join refused"; var joinRefused = await TestFixtureCi.AssertNetworkServerModuleLogExistsAsync((s) => s.IndexOf(joinRefusedMsg, StringComparison.Ordinal) != -1, new SearchLogOptions(joinRefusedMsg)); Assert.True(joinRefused.Found); } }
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}'"); }
// Performs a OTAA join and sends N confirmed and unconfirmed messages // Expects that: // - device message is available on IoT Hub // - frame counter validation is done // - Message is decoded private async Task Test_OTAA_Confirmed_And_Unconfirmed_Message_With_Custom_RX1_DR_Offset(TestDeviceInfo device) { const int MESSAGES_COUNT = 10; 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); 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 10x unconfirmed messages for (var i = 0; i < MESSAGES_COUNT; ++i) { Console.WriteLine($"Starting sending OTAA unconfirmed message {i + 1}/{MESSAGES_COUNT}"); TestFixtureCi.ClearLogs(); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000004: valid frame counter, msg: 1 server: 0 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: valid frame counter, msg:"); // 0000000000000004: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000004: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); // Ensure device payload is available // Data: {"value": 51} var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); } // Sends 10x confirmed messages for (var i = 0; i < MESSAGES_COUNT; ++i) { Console.WriteLine($"Starting sending OTAA confirmed message {i + 1}/{MESSAGES_COUNT}"); TestFixtureCi.ClearLogs(); var msg = PayloadGenerator.Next().ToString(CultureInfo.InvariantCulture); await ArduinoDevice.transferPacketWithConfirmedAsync(msg, 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); if (device.IsMultiGw) { // multi gw, make sure one ignored the message var searchTokenSending = $"{device.DeviceID}: sending message to station with EUI"; var sending = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenSending, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenSending)); Assert.NotNull(sending.MatchedEvent); var searchTokenAlreadySent = $"{device.DeviceID}: another gateway has already sent ack or downlink msg"; var ignored = await TestFixtureCi.SearchNetworkServerModuleAsync((log) => log.StartsWith(searchTokenAlreadySent, StringComparison.OrdinalIgnoreCase), new SearchLogOptions(searchTokenAlreadySent)); Assert.NotNull(ignored.MatchedEvent); Assert.NotEqual(sending.MatchedEvent.SourceId, ignored.MatchedEvent.SourceId); } // After transferPacketWithConfirmed: Expectation from serial // +CMSG: ACK Received await AssertUtils.ContainsWithRetriesAsync("+CMSG: ACK Received", ArduinoDevice.SerialLogs, maxAttempts : 5, interval : TimeSpan.FromSeconds(10)); // 0000000000000004: decoding with: DecoderValueSensor port: 8 await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: decoding with: {device.SensorDecoder} port:"); // 0000000000000004: message '{"value": 51}' sent to hub await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DeviceID}: message '{{\"value\":{msg}}}' sent to hub"); if (ArduinoDevice.SerialLogs.Any(x => x.StartsWith("+CMSG: RXWIN1", StringComparison.Ordinal))) { // Expect that the response is done on DR4 as the RX1 offset is 1 on this device. const string logMessage = "\"Rx1\":{\"DataRate\":4"; await TestFixtureCi.AssertNetworkServerModuleLogExistsAsync(log => log.Contains(logMessage, StringComparison.Ordinal), new SearchLogOptions(logMessage)); } // Ensure device payload is available // Data: {"value": 51} var expectedPayload = $"{{\"value\":{msg}}}"; await TestFixtureCi.AssertIoTHubDeviceMessageExistsAsync(device.DeviceID, expectedPayload, new SearchLogOptions(expectedPayload)); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); } }
public async Task C2D_When_Device_Has_Preferred_Windows_2_Should_Receive_In_2nd_Window_With_Custom_DR() { const int messagesToSend = 10; const int warmUpMessageCount = 2; var device = TestFixtureCi.Device21_ABP; LogTestStart(device); // Setup LoRa device properties await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, device.AppEui); await ArduinoDevice.setKeyAsync(device.NwkSKey, device.AppSKey, device.AppKey); // Setup protocol properties await ArduinoDevice.SetupLora(TestFixture.Configuration); await TestFixture.CleanupC2DDeviceQueueAsync(device.DeviceID); // 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); TestFixture.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 foundReceivePacketInRX2Count = 0; var expectedRxSerial1 = $"+MSG: PORT: 1; RX: \"{ToHexString(c2dMessageBody)}\""; var expectedRxSerial2 = $"+MSG: RXWIN2"; 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: {expectedRxSerial1} and {expectedRxSerial2}"); Log($"Expected TCP log starting with: {expectedTcpMessageV1} or {expectedTcpMessageV2}"); // 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 unconfirmed '{msg}' {i}/{messagesToSend}"); await ArduinoDevice.transferPacketAsync(msg, 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // check if c2d message was found var searchResults = await TestFixture.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); } if (ArduinoDevice.SerialLogs.Contains(expectedRxSerial1)) { foundReceivePacketCount++; Log($"{device.DeviceID}: Found C2D message in serial logs (after sending {i}/{messagesToSend}) {foundReceivePacketCount} times"); EnsureNotSeenTooManyTimes(foundReceivePacketCount); } if (ArduinoDevice.SerialLogs.Any(x => x.StartsWith(expectedRxSerial2, StringComparison.OrdinalIgnoreCase))) { foundReceivePacketInRX2Count++; Log($"{device.DeviceID}: Found C2D message (rx2) in serial logs (after sending {i}/{messagesToSend}) {foundReceivePacketInRX2Count} times"); EnsureNotSeenTooManyTimes(foundReceivePacketInRX2Count); } if (foundReceivePacketCount > 0 && foundReceivePacketInRX2Count > 0 && foundC2DMessageCount > 0) { Log($"{device.DeviceID}: Found all messages in log (after sending {i}/{messagesToSend})"); break; } TestFixture.ClearLogs(); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); } Assert.True(foundC2DMessageCount > 0, $"Did not find {expectedTcpMessageV1} or {expectedTcpMessageV2} in logs"); // checks if serial received the message if (foundReceivePacketCount == 0) { if (ArduinoDevice.SerialLogs.Contains(expectedRxSerial1)) { foundReceivePacketCount++; } } Assert.True(foundReceivePacketCount > 0, $"Could not find lora receiving message '{expectedRxSerial1}'"); // checks if serial received the message in RX2 if (foundReceivePacketInRX2Count == 0) { if (ArduinoDevice.SerialLogs.Any(x => x.StartsWith(expectedRxSerial2, StringComparison.OrdinalIgnoreCase))) { foundReceivePacketInRX2Count++; } } Assert.True(foundReceivePacketInRX2Count > 0, $"Could not find lora receiving message '{expectedRxSerial2}'"); }