public async Task When_PerformNeededSyncs_Fails_Should_Release_Lock(string lockToTake) { var devAddrcache = new LoRaDevAddrCache(this.cache, null, null); await LockDevAddrHelper.PrepareLocksForTests(this.cache, lockToTake == null?null : new[] { lockToTake }); var managerInput = new List <DevAddrCacheInfo> { new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = CreateDevAddr() } }; var registryManagerMock = InitRegistryManager(managerInput); registryManagerMock.Setup(x => x.CreateQuery(It.IsAny <string>())).Throws(new RedisException(string.Empty)); await devAddrcache.PerformNeededSyncs(registryManagerMock.Object); // When doing a full update, the FullUpdateKey lock should be reset to 1min, the GlobalDevAddrUpdateKey should be gone // When doing a partial update, the GlobalDevAddrUpdateKey should be gone switch (lockToTake) { case FullUpdateKey: Assert.Null(await this.cache.GetObjectTTL(GlobalDevAddrUpdateKey)); break; case null: var nextFullUpdate = await this.cache.GetObjectTTL(FullUpdateKey); Assert.True(nextFullUpdate <= TimeSpan.FromMinutes(1)); Assert.Null(await this.cache.GetObjectTTL(GlobalDevAddrUpdateKey)); break; default: throw new InvalidOperationException("invalid test case"); } }
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)); } }
private static void InitCache(ILoRaDeviceCacheStore cache, List <DevAddrCacheInfo> deviceIds) { var loradevaddrcache = new LoRaDevAddrCache(cache, null, null); foreach (var device in deviceIds) { loradevaddrcache.StoreInfo(device); } }
// 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() { var gateway1 = NewUniqueEUI64(); var gateway2 = NewUniqueEUI64(); var dateTime = DateTime.UtcNow; var managerInput = new List <DevAddrCacheInfo>(); for (var i = 0; i < 2; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = CreateDevAddr() }); } var devAddrJoining = managerInput[0].DevAddr; var registryManagerMock = InitRegistryManager(managerInput); // In this test we want no updates running // initialize locks for test to run correctly var lockToTake = new string[2] { FullUpdateKey, GlobalDevAddrUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, lockToTake); var deviceGetter = new DeviceGetter(registryManagerMock.Object, this.cache); // Simulate three queries var tasks = from gw in new[] { gateway1, gateway2 } select Enumerable.Repeat(gw, 2) into gws // repeat each gateway twice from gw in gws select deviceGetter.GetDeviceList(null, gw, new DevNonce(0xABCD), 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 ?? string.Empty, 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); }
// 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); }
// 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() { var oldGatewayId = NewUniqueEUI64(); var newGatewayId = NewUniqueEUI64(); var dateTime = DateTime.UtcNow; var updateDateTime = DateTime.UtcNow.AddMinutes(3); var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); var newValues = new List <DevAddrCacheInfo>(); for (var i = 0; i < 5; i++) { newValues.Add(new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = CreateDevAddr(), GatewayId = newGatewayId, LastUpdatedTwins = updateDateTime }); } // The cache start as empty var registryManagerMock = InitRegistryManager(newValues, newValues.Count); // Set up the cache with expectation. var cacheInput = new List <DevAddrCacheInfo>(); for (var i = 0; i < 5; i++) { cacheInput.Add(new DevAddrCacheInfo() { DevEUI = newValues[i].DevEUI, DevAddr = newValues[i].DevAddr, GatewayId = oldGatewayId, LastUpdatedTwins = dateTime, PrimaryKey = primaryKey }); } InitCache(this.cache, cacheInput); // initialize locks for test to run correctly await LockDevAddrHelper.PrepareLocksForTests(this.cache); var 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 (var 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() { var oldGatewayId = NewUniqueEUI64(); var newGatewayId = NewUniqueEUI64(); var dateTime = DateTime.UtcNow; var primaryKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(PrimaryKey)); var managerInput = new List <DevAddrCacheInfo>(); var adressForDuplicateDevAddr = CreateDevAddr(); for (var i = 0; i < 5; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = CreateDevAddr(), GatewayId = newGatewayId, LastUpdatedTwins = dateTime }); } managerInput.Add(new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = adressForDuplicateDevAddr, GatewayId = newGatewayId, LastUpdatedTwins = dateTime }); var devAddrJoining = managerInput[0].DevAddr; // The cache start as empty var registryManagerMock = InitRegistryManager(managerInput, managerInput.Count); // Set up the cache with expectation. var cacheInput = new List <DevAddrCacheInfo>(); for (var 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 devEui = TestEui.GenerateDevEui(); cacheInput.Add(new DevAddrCacheInfo() { DevEUI = devEui, DevAddr = adressForDuplicateDevAddr, GatewayId = oldGatewayId, PrimaryKey = primaryKey, LastUpdatedTwins = dateTime }); InitCache(this.cache, cacheInput); // initialize locks for test to run correctly var locksToTake = new string[1] { FullUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, locksToTake); var devAddrCache = new LoRaDevAddrCache(this.cache, null, newGatewayId); await devAddrCache.PerformNeededSyncs(registryManagerMock.Object); // we expect the devices are saved for (var 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.Length); for (var i = 0; i < 2; i++) { var resultObject = JsonConvert.DeserializeObject <DevAddrCacheInfo>(query2Result[0].Value); if (resultObject.DevEUI == devEui) { 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() { var gatewayId = NewUniqueEUI64(); var dateTime = DateTime.UtcNow; var managerInput = new List <DevAddrCacheInfo>(); for (var i = 0; i < 5; i++) { managerInput.Add(new DevAddrCacheInfo() { DevEUI = TestEui.GenerateDevEui(), DevAddr = CreateDevAddr(), GatewayId = gatewayId, LastUpdatedTwins = dateTime }); } var devAddrJoining = managerInput[0].DevAddr; // The cache start as empty var registryManagerMock = InitRegistryManager(managerInput); // initialize locks for test to run correctly var locksToTake = new string[1] { FullUpdateKey }; await LockDevAddrHelper.PrepareLocksForTests(this.cache, locksToTake); var 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 (var 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); }
// 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 kept as UpdateTime is similar public async Task Full_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> 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 = dateTime }); } newValues.Add(new DevAddrCacheInfo() { DevEUI = NewUniqueEUI64(), DevAddr = adressForDuplicateDevAddr, GatewayId = newGatewayId, LastUpdatedTwins = dateTime }); var devAddrJoining = newValues[0].DevAddr; // 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 }); } cacheInput[2].PrimaryKey = primaryKey; cacheInput[3].PrimaryKey = primaryKey; // this is a device that will be overwritten by the update as it share a devaddr with an updated device 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, 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); if (newValues[i].DevEUI == devEuiDoubleItem) { Assert.Equal(cacheInput[i].PrimaryKey, 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 dropped as updatetime is defferent public async Task Delta_Update_Perform_Correctly_On_Non_Empty_Cache_And_Keep_Old_Values_Except_Primary_Key() { string oldGatewayId = NewUniqueEUI64(); string newGatewayId = NewUniqueEUI64(); DateTime dateTime = DateTime.UtcNow; DateTime updateDateTime = DateTime.UtcNow.AddMinutes(10); 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 = updateDateTime }); } 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, LastUpdatedTwins = dateTime, PrimaryKey = primaryKey }); } 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++) { 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); // as the object changed the keys should not be saved Assert.Equal(string.Empty, 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); }