public async Task When_PerformNeededSyncs_Fails_Should_Release_Lock(params string[] lockToTake) { var devAddrcache = new LoRaDevAddrCache(this.cache, null, null); await LockDevAddrHelper.PrepareLocksForTests(this.cache, null, lockToTake); List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 2; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32() }); } var registryManagerMock = this.InitRegistryManager(managerInput); registryManagerMock.Setup(x => x.CreateQuery(It.IsAny <string>())).Throws <Exception>(); await devAddrcache.PerformNeededSyncs(registryManagerMock.Object); Assert.Null(this.cache.GetObject <DevAddrCacheInfo>(GlobalDevAddrUpdateKey)); var nextFullUpdate = await this.cache.GetObjectTTL(FullUpdateKey); if (lockToTake[0] == DeltaUpdateKey) { Assert.True(nextFullUpdate < TimeSpan.FromMinutes(1)); } }
// This test ensure that if the device has the key within the cache, it should not make any query to iot hub public async Task When_Device_Is_Not_Ours_Save_In_Cache_And_Dont_Query_Hub_Again() { string gatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; // In this test we want no updates running // initialize locks for test to run correctly var lockToTake = new string[2] { FullUpdateKey, DeltaUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, null, lockToTake); List <IoTHubDeviceInfo> items = new List <IoTHubDeviceInfo>(); var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 2; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = gatewayId, PrimaryKey = primaryKey, LastUpdatedTwins = dateTime }); } var devAddrJoining = NewUniqueEUI32(); this.InitCache(this.cache, managerInput); var registryManagerMock = this.InitRegistryManager(managerInput); var deviceGetter = new DeviceGetter(registryManagerMock.Object, this.cache); items = await deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining); Assert.Empty(items); var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, devAddrJoining)); Assert.Single(queryResult); var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(resultObject.DevEUI, string.Empty); Assert.Null(resultObject.PrimaryKey); Assert.Null(resultObject.GatewayId); var query2Result = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, devAddrJoining)); Assert.Single(query2Result); // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Never, "IoT Hub should not have been called, as the device was present in the cache."); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never, "IoT Hub should not have been called, as the device was present in the cache."); // Should not query for the key as key is there registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Never); }
// This test ensure that if a device is in cache without a key, it get the keys from iot hub and saave it public async Task Multi_Gateway_When_DevAddr_Is_In_Cache_Without_Key_Should_Not_Query_Iot_Hub_For_Twin_But_Should_Get_Key_And_Update() { string gatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 2; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = gatewayId, LastUpdatedTwins = dateTime }); } var devAddrJoining = managerInput[0].DevAddr; this.InitCache(this.cache, managerInput); var registryManagerMock = this.InitRegistryManager(managerInput); // In this test we want no updates running // initialize locks for test to run correctly var lockToTake = new string[2] { FullUpdateKey, DeltaUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, null, lockToTake); var deviceGetter = new DeviceGetter(registryManagerMock.Object, this.cache); var tasks = new Task[3] { deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), }; await Task.WhenAll(tasks); // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Never, "IoT Hub should not have been called, as the device was present in the cache."); registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>(), It.IsAny <int>()), Times.Never, "IoT Hub should not have been called, as the device was present in the cache."); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never, "IoT Hub should not have been called, as the device was present in the cache."); // Should query for the key as key is missing registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Once); var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, devAddrJoining)); Assert.Single(queryResult); // The key should have been saved var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.NotNull(resultObject.PrimaryKey); }
// This test simulate a call received by multiple server. It ensures IoT Hub is only queried once. public async Task Multi_Gateway_When_DevAddr_Is_Not_In_Cache_Query_Iot_Hub_Only_Once_And_Save_In_Cache() { string gatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 2; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32() }); } var devAddrJoining = managerInput[0].DevAddr; var registryManagerMock = this.InitRegistryManager(managerInput); // In this test we want no updates running // initialize locks for test to run correctly var lockToTake = new string[2] { FullUpdateKey, DeltaUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, null, lockToTake); var deviceGetter = new DeviceGetter(registryManagerMock.Object, this.cache); // Simulate three queries var tasks = new Task[3] { deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining), }; await Task.WhenAll(tasks); // If a cache miss it should save it in the redisCache var devAddrcache = new LoRaDevAddrCache(this.cache, null, null); var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, devAddrJoining)); Assert.Single(queryResult); var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(managerInput[0].DevAddr, resultObject.DevAddr); Assert.Equal(managerInput[0].GatewayId, resultObject.GatewayId); Assert.Equal(managerInput[0].DevEUI, resultObject.DevEUI); registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>(), It.IsAny <int>()), Times.Once); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never); registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Once); }
// Check that the server perform a full reload if the locking key for full reload is not present public async Task When_FullUpdateKey_Is_Not_there_Should_Perform_Full_Reload() { string gatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 5; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = gatewayId, }); } var devAddrJoining = managerInput[0].DevAddr; // The cache start as empty var registryManagerMock = this.InitRegistryManager(managerInput); // initialize locks for test to run correctly string[] neededLocksForTestToRun = new string[2] { FullUpdateKey, GlobalDevAddrUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, neededLocksForTestToRun, null); List <IoTHubDeviceInfo> items = new List <IoTHubDeviceInfo>(); var deviceGetter = new DeviceGetter(registryManagerMock.Object, this.cache); items = await deviceGetter.GetDeviceList(null, gatewayId, "ABCD", devAddrJoining); Assert.Single(items); // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Once); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never); // We expect to query for the key once (the device with an active connection) registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Once); // we expect the devices are saved for (int i = 1; i < 5; i++) { var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, managerInput[i].DevAddr)); Assert.Single(queryResult); var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(managerInput[i].GatewayId, resultObject.GatewayId); Assert.Equal(managerInput[i].DevEUI, resultObject.DevEUI); } }
// This test perform a full update and we check the following // primary key present in the cache is still here after a fullupdate // Items with same Devaddr are correctly saved (one old from cache, one from iot hub) // Old cache items sharing a devaddr not in the new update are correctly removed // Items with a devAddr not in the update are correctly still in cache // Gateway Id is correctly updated in old cache information. // Primary Key are not kept as UpdateTime is not similar public async Task Full_Update_Perform_Correctly_On_Non_Empty_Cache_And_Keep_Old_Values_Except_Primary_Keys() { string oldGatewayId = NewUniqueEUI64(); string newGatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; DateTime updateDateTime = DateTime.UtcNow.AddMinutes(3); var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); List <DevAddrCacheInfo> newValues = new List <DevAddrCacheInfo>(); var adressForDuplicateDevAddr = NewUniqueEUI32(); for (int i = 0; i < 5; i++) { newValues.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = newGatewayId, LastUpdatedTwins = updateDateTime }); } // The cache start as empty var registryManagerMock = this.InitRegistryManager(newValues, newValues.Count()); // Set up the cache with expectation. List <DevAddrCacheInfo> cacheInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 5; i++) { cacheInput.Add(new DevAddrCacheInfo() { DevEUI = newValues[i].DevEUI, DevAddr = newValues[i].DevAddr, GatewayId = oldGatewayId, LastUpdatedTwins = dateTime, PrimaryKey = primaryKey }); } this.InitCache(this.cache, cacheInput); // initialize locks for test to run correctly string[] neededLocksForTestToRun = new string[2] { GlobalDevAddrUpdateKey, FullUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, neededLocksForTestToRun, null); LoRaDevAddrCache devAddrCache = new LoRaDevAddrCache(this.cache, null, newGatewayId); await devAddrCache.PerformNeededSyncs(registryManagerMock.Object); // we expect the devices are saved, the double device id should not be there anymore for (int i = 0; i < newValues.Count; i++) { var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, newValues[i].DevAddr)); Assert.Single(queryResult); var result2Object = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(newGatewayId, result2Object.GatewayId); Assert.Equal(newValues[i].DevEUI, result2Object.DevEUI); Assert.Equal(string.Empty, result2Object.PrimaryKey); } // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Once); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never); // We expect to query for the key once (the device with an active connection) registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Never); }
// This test perform a delta update and we check the following // primary key present in the cache is still here after a delta up // Items with save Devaddr are correctly saved (one old from cache, one from iot hub) // Gateway Id is correctly updated in old cache information. // Primary Key are kept as UpdateTime is similar public async Task Delta_Update_Perform_Correctly_On_Non_Empty_Cache_And_Keep_Old_Values() { string oldGatewayId = NewUniqueEUI64(); string newGatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); var adressForDuplicateDevAddr = NewUniqueEUI32(); for (int i = 0; i < 5; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = newGatewayId, LastUpdatedTwins = dateTime }); } managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = adressForDuplicateDevAddr, GatewayId = newGatewayId, LastUpdatedTwins = dateTime }); var devAddrJoining = managerInput[0].DevAddr; // The cache start as empty var registryManagerMock = this.InitRegistryManager(managerInput, managerInput.Count()); // Set up the cache with expectation. List <DevAddrCacheInfo> cacheInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 5; i++) { cacheInput.Add(new DevAddrCacheInfo() { DevEUI = managerInput[i].DevEUI, DevAddr = managerInput[i].DevAddr, GatewayId = oldGatewayId, LastUpdatedTwins = dateTime }); } cacheInput[2].PrimaryKey = primaryKey; cacheInput[3].PrimaryKey = primaryKey; var devEuiDoubleItem = NewUniqueEUI64(); cacheInput.Add(new DevAddrCacheInfo() { DevEUI = devEuiDoubleItem, DevAddr = adressForDuplicateDevAddr, GatewayId = oldGatewayId, PrimaryKey = primaryKey, LastUpdatedTwins = dateTime }); this.InitCache(this.cache, cacheInput); // initialize locks for test to run correctly string[] neededLocksForTestToRun = new string[2] { GlobalDevAddrUpdateKey, DeltaUpdateKey }; var locksGuideTest = new string[1] { FullUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, neededLocksForTestToRun, locksGuideTest); LoRaDevAddrCache devAddrCache = new LoRaDevAddrCache(this.cache, null, newGatewayId); await devAddrCache.PerformNeededSyncs(registryManagerMock.Object); // we expect the devices are saved for (int i = 0; i < managerInput.Count; i++) { if (managerInput[i].DevAddr != adressForDuplicateDevAddr) { var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, managerInput[i].DevAddr)); Assert.Single(queryResult); var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(managerInput[i].GatewayId, resultObject.GatewayId); Assert.Equal(managerInput[i].DevEUI, resultObject.DevEUI); Assert.Equal(cacheInput[i].PrimaryKey, resultObject.PrimaryKey); } } // let's check the devices with a double EUI var query2Result = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, adressForDuplicateDevAddr)); Assert.Equal(2, query2Result.Count()); for (int i = 0; i < 2; i++) { var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(query2Result[0].Value); if (resultObject.DevEUI == devEuiDoubleItem) { Assert.Equal(oldGatewayId, resultObject.GatewayId); Assert.Equal(primaryKey, resultObject.PrimaryKey); } else { Assert.Equal(newGatewayId, resultObject.GatewayId); Assert.True(string.IsNullOrEmpty(resultObject.PrimaryKey)); } } // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Once); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never); // We expect to query for the key once (the device with an active connection) registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Never); registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>(), It.IsAny <int>()), Times.Never); }
// Trigger delta update correctly to see if it performs correctly on an empty cache public async Task Delta_Update_Perform_Correctly_On_Empty_Cache() { string gatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; List <DevAddrCacheInfo> managerInput = new List <DevAddrCacheInfo>(); for (int i = 0; i < 5; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = NewUniqueEUI32(), GatewayId = gatewayId, LastUpdatedTwins = dateTime }); } var devAddrJoining = managerInput[0].DevAddr; // The cache start as empty var registryManagerMock = this.InitRegistryManager(managerInput); // initialize locks for test to run correctly string[] neededLocksForTestToRun = new string[2] { GlobalDevAddrUpdateKey, DeltaUpdateKey }; var locksGuideTest = new string[1] { FullUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, neededLocksForTestToRun, locksGuideTest); LoRaDevAddrCache devAddrCache = new LoRaDevAddrCache(this.cache, null, gatewayId); await devAddrCache.PerformNeededSyncs(registryManagerMock.Object); while (!string.IsNullOrEmpty(this.cache.StringGet(GlobalDevAddrUpdateKey))) { await Task.Delay(100); } var foundItem = 0; // we expect the devices are saved for (int i = 0; i < 5; i++) { var queryResult = this.cache.GetHashObject(string.Concat(CacheKeyPrefix, managerInput[i].DevAddr)); if (queryResult.Length > 0) { foundItem++; Assert.Single(queryResult); var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(queryResult[0].Value); Assert.Equal(managerInput[i].GatewayId, resultObject.GatewayId); Assert.Equal(managerInput[i].DevEUI, resultObject.DevEUI); } } // Only two items should be updated by the delta updates Assert.Equal(2, foundItem); // Iot hub should never have been called. registryManagerMock.Verify(x => x.CreateQuery(It.IsAny <string>()), Times.Once); registryManagerMock.Verify(x => x.GetTwinAsync(It.IsAny <string>()), Times.Never); // We expect to query for the key once (the device with an active connection) registryManagerMock.Verify(x => x.GetDeviceAsync(It.IsAny <string>()), Times.Never); }