public async Task Success() { // arrange const string primaryKey = "foo"; const string package = "1.0.0"; SetupDeviceKeyLookup(primaryKey); var deviceClientMock = new Mock <ILoRaDeviceClient>(); this.loRaDeviceFactoryMock.Setup(ldf => ldf.CreateDeviceClient(this.devEui.ToString(), primaryKey)) .Returns(deviceClientMock.Object); // act await this.sut.SetReportedPackageVersionAsync(this.stationEui, package, CancellationToken.None); // assert Func <TwinCollection, bool> twinCondition = (t) => { var twinReader = new TwinCollectionReader(t, null); var reported = twinReader.SafeRead(TwinProperty.Package, string.Empty); return(string.Equals(package, reported, StringComparison.OrdinalIgnoreCase)); }; deviceClientMock.Verify(c => c.UpdateReportedPropertiesAsync(It.Is <TwinCollection>(t => twinCondition(t)), It.IsAny <CancellationToken>()), Times.Once()); }
private bool TryUpdateConfigurationWithDesiredProperties(TwinCollection desiredProperties) { if (desiredProperties is null) { return(false); } var reader = new TwinCollectionReader(desiredProperties, this.logger); if (reader.TryRead <string>(Constants.FacadeServerUrlKey, out var faceServerUrl)) { if (Uri.TryCreate(faceServerUrl, UriKind.Absolute, out var url) && (url.Scheme == Uri.UriSchemeHttp || url.Scheme == Uri.UriSchemeHttps)) { this.loRaDeviceAPIService.URL = url; if (reader.TryRead <string>(Constants.FacadeServerAuthCodeKey, out var authCode)) { this.loRaDeviceAPIService.SetAuthCode(authCode); } return(true); } else { this.logger.LogError("The Facade server Url present in device desired properties was malformed."); throw new ConfigurationErrorsException(nameof(desiredProperties)); } } this.logger.LogDebug("no desired property changed"); return(false); }
public void ReadRequired_Throws_If_TryParse_Fails(bool add, string val) { const string key = "test"; var tc = new TwinCollection(); var reader = new TwinCollectionReader(tc, this.logger); if (add) { tc[key] = val; } Assert.Throws <InvalidOperationException>(() => reader.ReadRequired <StationEui>(key)); }
public void ReadRequiredString_Throws_If_String_Is_Not_Configured(bool add, string val) { const string key = "test"; var tc = new TwinCollection(); var reader = new TwinCollectionReader(tc, this.logger); if (add) { tc[key] = val; } Assert.Throws <InvalidOperationException>(() => reader.ReadRequiredString(key)); }
public void SafeRead_Returns_Default_If_Value_Does_Not_Exist() { var tc = new TwinCollection(); var reader = new TwinCollectionReader(tc, this.logger); Assert.False(reader.TryRead <string>("test", out var someString)); Assert.Null(someString); Assert.False(reader.TryRead <ushort>("test", out var someUShort)); Assert.Equal(0, someUShort); Assert.False(reader.TryRead <ushort?>("test", out var someUShortNullable)); Assert.Null(someUShortNullable); }
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 void TryRead_Returns_False_When_Key_Does_Not_Exist() { var tc = new TwinCollectionReader(new TwinCollection(), this.logger); Assert.False(tc.TryRead <string>("invalid", out _)); }
public async Task <IActionResult> SendCloudToDeviceMessageImplementationAsync(DevEui devEUI, LoRaCloudToDeviceMessage c2dMessage) { if (c2dMessage == null) { return(new BadRequestObjectResult("Missing cloud to device message")); } if (!c2dMessage.IsValid(out var errorMessage)) { return(new BadRequestObjectResult(errorMessage)); } var cachedPreferredGateway = LoRaDevicePreferredGateway.LoadFromCache(this.cacheStore, devEUI); if (cachedPreferredGateway != null && !string.IsNullOrEmpty(cachedPreferredGateway.GatewayID)) { return(await SendMessageViaDirectMethodAsync(cachedPreferredGateway.GatewayID, devEUI, c2dMessage)); } var queryText = $"SELECT * FROM devices WHERE deviceId = '{devEUI}'"; var query = this.registryManager.CreateQuery(queryText, 1); if (query.HasMoreResults) { IEnumerable <Twin> deviceTwins; try { deviceTwins = await query.GetNextAsTwinAsync(); } catch (IotHubException ex) { this.log.LogError(ex, "Failed to query devices with {query}", queryText); return(new ObjectResult("Failed to query devices") { StatusCode = (int)HttpStatusCode.InternalServerError }); } var twin = deviceTwins.FirstOrDefault(); if (twin != null) { var desiredReader = new TwinCollectionReader(twin.Properties.Desired, this.log); var reportedReader = new TwinCollectionReader(twin.Properties.Reported, this.log); // the device must have a DevAddr if (!desiredReader.TryRead(LoraKeysManagerFacadeConstants.TwinProperty_DevAddr, out DevAddr _) && !reportedReader.TryRead(LoraKeysManagerFacadeConstants.TwinProperty_DevAddr, out DevAddr _)) { return(new BadRequestObjectResult("Device DevAddr is unknown. Ensure the device has been correctly setup as a LoRa device and that it has connected to network at least once.")); } if (desiredReader.TryRead(LoraKeysManagerFacadeConstants.TwinProperty_ClassType, out string deviceClass) && string.Equals("c", deviceClass, StringComparison.OrdinalIgnoreCase)) { if ((reportedReader.TryRead(LoraKeysManagerFacadeConstants.TwinProperty_PreferredGatewayID, out string gatewayID) || desiredReader.TryRead(LoraKeysManagerFacadeConstants.TwinProperty_GatewayID, out gatewayID)) && !string.IsNullOrEmpty(gatewayID)) { // add it to cache (if it does not exist) var preferredGateway = new LoRaDevicePreferredGateway(gatewayID, 0); _ = LoRaDevicePreferredGateway.SaveToCache(this.cacheStore, devEUI, preferredGateway, onlyIfNotExists: true); return(await SendMessageViaDirectMethodAsync(gatewayID, devEUI, c2dMessage)); } // class c device that did not send a single upstream message return(new ObjectResult("Class C devices must sent at least one message upstream. None has been received") { StatusCode = (int)HttpStatusCode.InternalServerError }); } // Not a class C device? Send message using sdk/queue return(await SendMessageViaCloudToDeviceMessageAsync(devEUI, c2dMessage)); } } return(new NotFoundObjectResult($"Device '{devEUI}' was not found")); }