// 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); }
// 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); } }
// 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); } }
/* 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}'"); }