public static IEnumerable <object[]> GetEdgeHubConfigData() { var r1 = new Route("id", string.Empty, "iotHub", Mock.Of <IMessageSource>(), new HashSet <Endpoint>()); var r2 = new Route("id", string.Empty, "iotHub", Mock.Of <IMessageSource>(), new HashSet <Endpoint>()); var routeConfig1 = new RouteConfig("r1", "FROM /* INTO $upstream", r1); var routeConfig2 = new RouteConfig("r2", "FROM /messages/* INTO $upstream", r2); var routes1 = new Dictionary <string, RouteConfig> { [routeConfig1.Name] = routeConfig1, [routeConfig2.Name] = routeConfig2 }; var routes2 = new Dictionary <string, RouteConfig> { [routeConfig1.Name] = routeConfig1 }; var routes3 = new Dictionary <string, RouteConfig> { [routeConfig2.Name] = routeConfig2 }; var storeAndForwardConfig1 = new StoreAndForwardConfiguration(-1); var storeAndForwardConfig2 = new StoreAndForwardConfiguration(7200); var storeAndForwardConfig3 = new StoreAndForwardConfiguration(3600); string version = "1.0"; var edgeHubConfig1 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1); var edgeHubConfig2 = new EdgeHubConfig(version, routes2, storeAndForwardConfig1); var edgeHubConfig3 = new EdgeHubConfig(version, routes3, storeAndForwardConfig1); var edgeHubConfig4 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1); var edgeHubConfig5 = new EdgeHubConfig(version, routes1, storeAndForwardConfig2); var edgeHubConfig6 = new EdgeHubConfig(version, routes1, storeAndForwardConfig3); var edgeHubConfig7 = new EdgeHubConfig(version, routes2, storeAndForwardConfig2); var edgeHubConfig8 = new EdgeHubConfig(version, routes2, storeAndForwardConfig3); var edgeHubConfig9 = new EdgeHubConfig(version, routes3, storeAndForwardConfig3); var edgeHubConfig10 = new EdgeHubConfig(version, routes3, storeAndForwardConfig3); yield return(new object[] { edgeHubConfig1, edgeHubConfig2, false }); yield return(new object[] { edgeHubConfig2, edgeHubConfig3, false }); yield return(new object[] { edgeHubConfig3, edgeHubConfig4, false }); yield return(new object[] { edgeHubConfig4, edgeHubConfig5, false }); yield return(new object[] { edgeHubConfig5, edgeHubConfig6, false }); yield return(new object[] { edgeHubConfig6, edgeHubConfig7, false }); yield return(new object[] { edgeHubConfig7, edgeHubConfig8, false }); yield return(new object[] { edgeHubConfig8, edgeHubConfig9, false }); yield return(new object[] { edgeHubConfig9, edgeHubConfig10, true }); }
public async Task TestInitialConfigUpdate_WaitForInit() { // Arrange string id = "id"; string iotHub = "foo.azure-devices.net"; var routerConfig = new RouterConfig(Enumerable.Empty <Route>()); var messageStore = new Mock <IMessageStore>(); messageStore.Setup(m => m.SetTimeToLive(It.IsAny <TimeSpan>())); var storageSpaceChecker = new Mock <IStorageSpaceChecker>(); storageSpaceChecker.Setup(m => m.SetMaxSizeBytes(It.IsAny <Option <long> >())); TimeSpan updateFrequency = TimeSpan.FromSeconds(10); Endpoint GetEndpoint() => new ModuleEndpoint("id", Guid.NewGuid().ToString(), "in1", Mock.Of <IConnectionManager>(), Mock.Of <Core.IMessageConverter <IMessage> >()); var endpointFactory = new Mock <IEndpointFactory>(); endpointFactory.Setup(e => e.CreateSystemEndpoint($"$upstream")).Returns(GetEndpoint); var routeFactory = new EdgeRouteFactory(endpointFactory.Object); var endpointExecutorFactory = new Mock <IEndpointExecutorFactory>(); endpointExecutorFactory.Setup(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>())) .Returns <Endpoint, IList <uint>, ICheckpointerFactory>((endpoint, priorities, checkpointerFactory) => Task.FromResult(Mock.Of <IEndpointExecutor>(e => e.Endpoint == endpoint))); Router router = await Router.CreateAsync(id, iotHub, routerConfig, endpointExecutorFactory.Object); var routes1 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration1 = new StoreAndForwardConfiguration(7200); var edgeHubConfig1 = new EdgeHubConfig("1.0", routes1, storeAndForwardConfiguration1, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var configProvider = new Mock <IConfigSource>(); configProvider.SetupSequence(c => c.GetConfig()) .Returns(async() => { await Task.Delay(5000); return(Option.Some(edgeHubConfig1)); }); configProvider.Setup(c => c.GetCachedConfig()) .Returns(() => Task.FromResult(Option.None <EdgeHubConfig>())); // Act var configUpdater = new ConfigUpdater(router, messageStore.Object, updateFrequency, storageSpaceChecker.Object); await configUpdater.Init(configProvider.Object); // Assert Assert.Equal(2, router.Routes.Count); // After 6 seconds no updates await Task.Delay(TimeSpan.FromSeconds(6)); Assert.Equal(2, router.Routes.Count); }
public void EqualityTest(EdgeHubConfig e1, EdgeHubConfig e2, bool areEqual) { Assert.Equal(areEqual, e1.Equals(e2)); Assert.Equal(areEqual, e1 == e2); Assert.Equal(!areEqual, e1 != e2); Assert.Equal(areEqual, e1.Equals((object)e2)); Assert.Equal(areEqual, e1.GetHashCode() == e2.GetHashCode()); }
static BridgeConfig ConfigToBridgeUpdate(EdgeHubConfig config) { Option <BridgeConfig> maybeBridgeConfig = config.BrokerConfiguration.FlatMap( config => config.Bridges); return(maybeBridgeConfig.Match( config => config, () => GetEmptyBridgeConfig())); }
static PolicyUpdate ConfigToPolicyUpdate(EdgeHubConfig config) { Option <AuthorizationConfig> maybePolicy = config.BrokerConfiguration.FlatMap( config => config.Authorizations); return(maybePolicy.Match( policy => new PolicyUpdate(JsonConvert.SerializeObject(policy)), () => GetEmptyPolicy())); }
public void ConstructorHappyPath() { // Arrange IReadOnlyDictionary <string, RouteConfig> routes = new ReadOnlyDictionary <string, RouteConfig>(new Dictionary <string, RouteConfig>()); var snfConfig = new StoreAndForwardConfiguration(1000); // Act var edgeHubConfig = new EdgeHubConfig("1.0", routes, snfConfig); // Assert Assert.NotNull(edgeHubConfig); }
public void ConstructorHappyPath() { // Arrange IEnumerable <(string Name, string Value, Route route)> routes = Enumerable.Empty <(string Name, string Value, Route route)>(); var snfConfig = new StoreAndForwardConfiguration(1000); // Act var edgeHubConfig = new EdgeHubConfig("1.0", routes, snfConfig); // Assert Assert.NotNull(edgeHubConfig); }
public void ConstructorHappyPath(string[] signercert, string[] intermediatecacert, string signature, string algo) { // Arrange IReadOnlyDictionary <string, RouteConfig> routes = new ReadOnlyDictionary <string, RouteConfig>(new Dictionary <string, RouteConfig>()); var snfConfig = new StoreAndForwardConfiguration(1000); var brokerConfig = new BrokerConfig(); var integrity = new ManifestIntegrity(new TwinHeader(signercert, intermediatecacert), new TwinSignature(signature, algo)); // Act var edgeHubConfig = new EdgeHubConfig("1.0", routes, snfConfig, Option.Some(brokerConfig), Option.Some(integrity)); // Assert Assert.NotNull(edgeHubConfig); }
async Task ConfigUpdateHandler(EdgeHubConfig config) { try { PolicyUpdate update = ConfigToPolicyUpdate(config); Events.PublishPolicyUpdate(update); var payload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(update)); await this.connector.SendAsync(Topic, payload); } catch (Exception ex) { Events.ErrorUpdatingPolicy(ex); } }
async Task ConfigUpdateHandler(EdgeHubConfig config) { try { PolicyUpdate policyUpdate = ConfigToPolicyUpdate(config); BridgeConfig bridgeUpdate = ConfigToBridgeUpdate(config); Events.PublishPolicyUpdate(policyUpdate); var policyPayload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(policyUpdate)); await this.connector.SendAsync(PolicyUpdateTopic, policyPayload, retain : true); var bridgePayload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(bridgeUpdate)); await this.connector.SendAsync(BridgeUpdateTopic, bridgePayload, retain : true); } catch (Exception ex) { Events.ErrorUpdatingPolicy(ex); } }
public async Task TestEdgeHubConnection() { const string EdgeDeviceId = "testHubEdgeDevice1"; var twinMessageConverter = new TwinMessageConverter(); var twinCollectionMessageConverter = new TwinCollectionMessageConverter(); var messageConverterProvider = new MessageConverterProvider( new Dictionary <Type, IMessageConverter>() { { typeof(Message), new DeviceClientMessageConverter() }, { typeof(Twin), twinMessageConverter }, { typeof(TwinCollection), twinCollectionMessageConverter } }); string iotHubConnectionString = await SecretsHelper.GetSecretFromConfigKey("iotHubConnStrKey"); IotHubConnectionStringBuilder iotHubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString); RegistryManager registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString); await registryManager.OpenAsync(); string iothubHostName = iotHubConnectionStringBuilder.HostName; var identityProvider = new IdentityProvider(iothubHostName); var identityFactory = new ClientCredentialsFactory(identityProvider); (string edgeDeviceId, string deviceConnStr) = await RegistryManagerHelper.CreateDevice(EdgeDeviceId, iotHubConnectionString, registryManager, true, false); string edgeHubConnectionString = $"{deviceConnStr};ModuleId={EdgeHubModuleId}"; IClientCredentials edgeHubCredentials = identityFactory.GetWithConnectionString(edgeHubConnectionString); string sasKey = ConnectionStringHelper.GetSharedAccessKey(deviceConnStr); var signatureProvider = new SharedAccessKeySignatureProvider(sasKey); var credentialsCache = Mock.Of <ICredentialsCache>(); var metadataStore = new Mock <IMetadataStore>(); metadataStore.Setup(m => m.GetMetadata(It.IsAny <string>())).ReturnsAsync(new ConnectionMetadata("dummyValue")); var cloudConnectionProvider = new CloudConnectionProvider( messageConverterProvider, 1, new ClientProvider(), Option.None <UpstreamProtocol>(), new ClientTokenProvider(signatureProvider, iothubHostName, edgeDeviceId, TimeSpan.FromMinutes(60)), Mock.Of <IDeviceScopeIdentitiesCache>(), credentialsCache, edgeHubCredentials.Identity, TimeSpan.FromMinutes(60), true, TimeSpan.FromSeconds(20), false, Option.None <IWebProxy>(), metadataStore.Object); var deviceConnectivityManager = Mock.Of <IDeviceConnectivityManager>(); var connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of <ICredentialsCache>(), identityProvider, deviceConnectivityManager); try { Mock.Get(credentialsCache) .Setup(c => c.Get(edgeHubCredentials.Identity)) .ReturnsAsync(Option.Some(edgeHubCredentials)); Assert.NotNull(edgeHubCredentials); Assert.NotNull(edgeHubCredentials.Identity); // Set Edge hub desired properties await this.SetDesiredProperties(registryManager, edgeDeviceId); var endpointFactory = new EndpointFactory(connectionManager, new RoutingMessageConverter(), edgeDeviceId, 10, 10); var routeFactory = new EdgeRouteFactory(endpointFactory); var dbStoreProvider = new InMemoryDbStoreProvider(); IStoreProvider storeProvider = new StoreProvider(dbStoreProvider); IEntityStore <string, TwinInfo> twinStore = storeProvider.GetEntityStore <string, TwinInfo>("twins"); var twinManager = new TwinManager(connectionManager, twinCollectionMessageConverter, twinMessageConverter, Option.Some(twinStore)); var routerConfig = new RouterConfig(Enumerable.Empty <Route>()); TimeSpan defaultTimeout = TimeSpan.FromSeconds(60); var endpointExecutorFactory = new SyncEndpointExecutorFactory(new EndpointExecutorConfig(defaultTimeout, new FixedInterval(0, TimeSpan.FromSeconds(1)), defaultTimeout, true)); Router router = await Router.CreateAsync(Guid.NewGuid().ToString(), iothubHostName, routerConfig, endpointExecutorFactory); IInvokeMethodHandler invokeMethodHandler = new InvokeMethodHandler(connectionManager); var subscriptionProcessor = new SubscriptionProcessor(connectionManager, invokeMethodHandler, deviceConnectivityManager); IEdgeHub edgeHub = new RoutingEdgeHub(router, new RoutingMessageConverter(), connectionManager, twinManager, edgeDeviceId, invokeMethodHandler, subscriptionProcessor); cloudConnectionProvider.BindEdgeHub(edgeHub); var versionInfo = new VersionInfo("v1", "b1", "c1"); // Create Edge Hub connection EdgeHubConnection edgeHubConnection = await EdgeHubConnection.Create( edgeHubCredentials.Identity, edgeHub, twinManager, connectionManager, routeFactory, twinCollectionMessageConverter, versionInfo, new NullDeviceScopeIdentitiesCache()); await Task.Delay(TimeSpan.FromMinutes(1)); TwinConfigSource configSource = new TwinConfigSource(edgeHubConnection, edgeHubCredentials.Identity.Id, versionInfo, twinManager, twinMessageConverter, twinCollectionMessageConverter, routeFactory); // Get and Validate EdgeHubConfig Option <EdgeHubConfig> edgeHubConfigOption = await configSource.GetConfig(); Assert.True(edgeHubConfigOption.HasValue); EdgeHubConfig edgeHubConfig = edgeHubConfigOption.OrDefault(); Assert.Equal("1.0", edgeHubConfig.SchemaVersion); Assert.NotNull(edgeHubConfig.Routes); Assert.NotNull(edgeHubConfig.StoreAndForwardConfiguration); Assert.Equal(20, edgeHubConfig.StoreAndForwardConfiguration.TimeToLiveSecs); IReadOnlyDictionary <string, RouteConfig> routes = edgeHubConfig.Routes; Assert.Equal(4, routes.Count); RouteConfig route1 = routes["route1"]; Assert.True(route1.Route.Endpoint.GetType() == typeof(CloudEndpoint)); Assert.Equal("route1", route1.Name); Assert.Equal("from /* INTO $upstream", route1.Value); RouteConfig route2 = routes["route2"]; Endpoint endpoint = route2.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module2/input1", endpoint.Id); Assert.Equal("route2", route2.Name); Assert.Equal("from /modules/module1 INTO BrokeredEndpoint(\"/modules/module2/inputs/input1\")", route2.Value); RouteConfig route3 = routes["route3"]; endpoint = route3.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module3/input1", endpoint.Id); Assert.Equal("route3", route3.Name); Assert.Equal("from /modules/module2 INTO BrokeredEndpoint(\"/modules/module3/inputs/input1\")", route3.Value); RouteConfig route4 = routes["route4"]; endpoint = route4.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module4/input1", endpoint.Id); Assert.Equal("route4", route4.Name); Assert.Equal("from /modules/module3 INTO BrokeredEndpoint(\"/modules/module4/inputs/input1\")", route4.Value); // Make sure reported properties were updated appropriately EdgeHubConnection.ReportedProperties reportedProperties = await this.GetReportedProperties(registryManager, edgeDeviceId); Assert.Equal(200, reportedProperties.LastDesiredStatus.Code); Assert.NotNull(reportedProperties.Clients); Assert.Equal(0, reportedProperties.Clients.Count); Assert.Equal("1.0", reportedProperties.SchemaVersion); Assert.Equal(versionInfo, reportedProperties.VersionInfo); // Simulate a module and a downstream device that connects to Edge Hub. string moduleId = "module1"; string sasToken = TokenHelper.CreateSasToken($"{iothubHostName}/devices/{edgeDeviceId}/modules/{moduleId}"); string moduleConnectionstring = $"HostName={iothubHostName};DeviceId={edgeDeviceId};ModuleId={moduleId};SharedAccessSignature={sasToken}"; IClientCredentials moduleClientCredentials = identityFactory.GetWithConnectionString(moduleConnectionstring); var moduleProxy = Mock.Of <IDeviceProxy>(d => d.IsActive); string downstreamDeviceId = "device1"; sasToken = TokenHelper.CreateSasToken($"{iothubHostName}/devices/{downstreamDeviceId}"); string downstreamDeviceConnectionstring = $"HostName={iothubHostName};DeviceId={downstreamDeviceId};SharedAccessSignature={sasToken}"; IClientCredentials downstreamDeviceCredentials = identityFactory.GetWithConnectionString(downstreamDeviceConnectionstring); var downstreamDeviceProxy = Mock.Of <IDeviceProxy>(d => d.IsActive); // Connect the module and downstream device and make sure the reported properties are updated as expected. await connectionManager.AddDeviceConnection(moduleClientCredentials.Identity, moduleProxy); await connectionManager.AddDeviceConnection(downstreamDeviceCredentials.Identity, downstreamDeviceProxy); string moduleIdKey = $"{edgeDeviceId}/{moduleId}"; await Task.Delay(TimeSpan.FromSeconds(10)); reportedProperties = await this.GetReportedProperties(registryManager, edgeDeviceId); Assert.Equal(2, reportedProperties.Clients.Count); Assert.Equal(ConnectionStatus.Connected, reportedProperties.Clients[moduleIdKey].Status); Assert.NotNull(reportedProperties.Clients[moduleIdKey].LastConnectedTimeUtc); Assert.Null(reportedProperties.Clients[moduleIdKey].LastDisconnectTimeUtc); Assert.Equal(ConnectionStatus.Connected, reportedProperties.Clients[downstreamDeviceId].Status); Assert.NotNull(reportedProperties.Clients[downstreamDeviceId].LastConnectedTimeUtc); Assert.Null(reportedProperties.Clients[downstreamDeviceId].LastDisconnectTimeUtc); Assert.Equal(200, reportedProperties.LastDesiredStatus.Code); Assert.Equal("1.0", reportedProperties.SchemaVersion); Assert.Equal(versionInfo, reportedProperties.VersionInfo); // Update desired propertied and make sure callback is called with valid values bool callbackCalled = false; Task ConfigUpdatedCallback(EdgeHubConfig updatedConfig) { Assert.NotNull(updatedConfig); Assert.NotNull(updatedConfig.StoreAndForwardConfiguration); Assert.NotNull(updatedConfig.Routes); routes = updatedConfig.Routes; Assert.Equal(4, routes.Count); route1 = routes["route1"]; Assert.True(route1.Route.Endpoint.GetType() == typeof(CloudEndpoint)); Assert.Equal("route1", route1.Name); Assert.Equal("from /* INTO $upstream", route1.Value); route2 = routes["route2"]; endpoint = route2.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module2/input1", endpoint.Id); Assert.Equal("route2", route2.Name); Assert.Equal("from /modules/module1 INTO BrokeredEndpoint(\"/modules/module2/inputs/input1\")", route2.Value); route3 = routes["route4"]; endpoint = route3.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module5/input1", endpoint.Id); Assert.Equal("route4", route3.Name); Assert.Equal("from /modules/module3 INTO BrokeredEndpoint(\"/modules/module5/inputs/input1\")", route3.Value); route4 = routes["route5"]; endpoint = route4.Route.Endpoint; Assert.True(endpoint.GetType() == typeof(ModuleEndpoint)); Assert.Equal($"{edgeDeviceId}/module6/input1", endpoint.Id); Assert.Equal("route5", route4.Name); Assert.Equal("from /modules/module5 INTO BrokeredEndpoint(\"/modules/module6/inputs/input1\")", route4.Value); callbackCalled = true; return(Task.CompletedTask); } configSource.SetConfigUpdatedCallback(ConfigUpdatedCallback); await this.UpdateDesiredProperties(registryManager, edgeDeviceId); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.True(callbackCalled); reportedProperties = await this.GetReportedProperties(registryManager, edgeDeviceId); Assert.Equal(200, reportedProperties.LastDesiredStatus.Code); Assert.NotNull(reportedProperties.Clients); Assert.Equal(2, reportedProperties.Clients.Count); Assert.Equal("1.0", reportedProperties.SchemaVersion); Assert.Equal(versionInfo, reportedProperties.VersionInfo); // Disconnect the downstream device and make sure the reported properties are updated as expected. await connectionManager.RemoveDeviceConnection(moduleIdKey); await connectionManager.RemoveDeviceConnection(downstreamDeviceId); await Task.Delay(TimeSpan.FromSeconds(10)); reportedProperties = await this.GetReportedProperties(registryManager, edgeDeviceId); Assert.Equal(1, reportedProperties.Clients.Count); Assert.True(reportedProperties.Clients.ContainsKey(moduleIdKey)); Assert.False(reportedProperties.Clients.ContainsKey(downstreamDeviceId)); Assert.Equal(ConnectionStatus.Disconnected, reportedProperties.Clients[moduleIdKey].Status); Assert.NotNull(reportedProperties.Clients[moduleIdKey].LastConnectedTimeUtc); Assert.NotNull(reportedProperties.Clients[moduleIdKey].LastDisconnectTimeUtc); Assert.Equal(200, reportedProperties.LastDesiredStatus.Code); Assert.Equal("1.0", reportedProperties.SchemaVersion); Assert.Equal(versionInfo, reportedProperties.VersionInfo); // If the edge hub restarts, clear out the connected devices in the reported properties. await EdgeHubConnection.Create( edgeHubCredentials.Identity, edgeHub, twinManager, connectionManager, routeFactory, twinCollectionMessageConverter, versionInfo, new NullDeviceScopeIdentitiesCache()); await Task.Delay(TimeSpan.FromMinutes(1)); reportedProperties = await this.GetReportedProperties(registryManager, edgeDeviceId); Assert.Null(reportedProperties.Clients); Assert.Equal("1.0", reportedProperties.SchemaVersion); Assert.Equal(versionInfo, reportedProperties.VersionInfo); } finally { try { await RegistryManagerHelper.RemoveDevice(edgeDeviceId, registryManager); } catch (Exception) { // ignored } } }
public static IEnumerable <object[]> GetEdgeHubConfigData() { var r1 = new Route("id", string.Empty, "iotHub", Mock.Of <IMessageSource>(), new Mock <Endpoint>("endpoint1").Object, 0, 3600); var r2 = new Route("id", string.Empty, "iotHub", Mock.Of <IMessageSource>(), new Mock <Endpoint>("endpoint2").Object, 0, 3600); var routeConfig1 = new RouteConfig("r1", "FROM /* INTO $upstream", r1); var routeConfig2 = new RouteConfig("r2", "FROM /messages/* INTO $upstream", r2); var routes1 = new Dictionary <string, RouteConfig> { [routeConfig1.Name] = routeConfig1, [routeConfig2.Name] = routeConfig2 }; var routes2 = new Dictionary <string, RouteConfig> { [routeConfig1.Name] = routeConfig1 }; var routes3 = new Dictionary <string, RouteConfig> { [routeConfig2.Name] = routeConfig2 }; var storeAndForwardConfig1 = new StoreAndForwardConfiguration(-1); var storeAndForwardConfig2 = new StoreAndForwardConfiguration(7200); var storeAndForwardConfig3 = new StoreAndForwardConfiguration(3600); StoreLimits s1 = new StoreLimits(100L); StoreLimits s2 = new StoreLimits(200L); var storeAndForwardConfig4 = new StoreAndForwardConfiguration(3600, s1); var storeAndForwardConfig5 = new StoreAndForwardConfiguration(3600, s2); var storeAndForwardConfig6 = new StoreAndForwardConfiguration(3600); var statement1 = new Statement( effect: Effect.Allow, identities: new List <string> { "device_1" }, operations: new List <string> { "read", "write" }, resources: new List <string> { "file1", "file2" }); var statement2 = new Statement( effect: Effect.Deny, identities: new List <string> { "device_1" }, operations: new List <string> { "read" }, resources: new List <string> { "root1", "root2" }); var statement3 = new Statement( effect: Effect.Allow, identities: new List <string> { "device_1" }, operations: new List <string> { "read", "write" }, resources: new List <string> { "file1", "file2" }); var brokerConfig1 = new BrokerConfig( Option.None <BridgeConfig>(), Option.Some(new AuthorizationConfig(new List <Statement> { statement1 }))); var brokerConfig2 = new BrokerConfig( Option.None <BridgeConfig>(), Option.Some(new AuthorizationConfig(new List <Statement> { statement2 }))); var brokerConfig3 = new BrokerConfig( Option.None <BridgeConfig>(), Option.Some(new AuthorizationConfig(new List <Statement> { statement3 }))); string version = "1.0"; var edgeHubConfig1 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1, Option.Some(brokerConfig1)); var edgeHubConfig2 = new EdgeHubConfig(version, routes2, storeAndForwardConfig1, Option.Some(brokerConfig1)); var edgeHubConfig3 = new EdgeHubConfig(version, routes3, storeAndForwardConfig1, Option.Some(brokerConfig1)); var edgeHubConfig4 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1, Option.Some(brokerConfig1)); var edgeHubConfig5 = new EdgeHubConfig(version, routes1, storeAndForwardConfig2, Option.Some(brokerConfig1)); var edgeHubConfig6 = new EdgeHubConfig(version, routes1, storeAndForwardConfig3, Option.Some(brokerConfig1)); var edgeHubConfig7 = new EdgeHubConfig(version, routes2, storeAndForwardConfig2, Option.Some(brokerConfig1)); var edgeHubConfig8 = new EdgeHubConfig(version, routes2, storeAndForwardConfig3, Option.Some(brokerConfig1)); var edgeHubConfig9 = new EdgeHubConfig(version, routes3, storeAndForwardConfig3, Option.Some(brokerConfig1)); var edgeHubConfig10 = new EdgeHubConfig(version, routes3, storeAndForwardConfig3, Option.Some(brokerConfig1)); var edgeHubConfig11 = new EdgeHubConfig(version, routes3, storeAndForwardConfig4, Option.Some(brokerConfig1)); var edgeHubConfig12 = new EdgeHubConfig(version, routes3, storeAndForwardConfig5, Option.Some(brokerConfig1)); var edgeHubConfig13 = new EdgeHubConfig(version, routes3, storeAndForwardConfig6, Option.Some(brokerConfig1)); yield return(new object[] { edgeHubConfig1, edgeHubConfig2, false }); yield return(new object[] { edgeHubConfig2, edgeHubConfig3, false }); yield return(new object[] { edgeHubConfig3, edgeHubConfig4, false }); yield return(new object[] { edgeHubConfig4, edgeHubConfig5, false }); yield return(new object[] { edgeHubConfig5, edgeHubConfig6, false }); yield return(new object[] { edgeHubConfig6, edgeHubConfig7, false }); yield return(new object[] { edgeHubConfig7, edgeHubConfig8, false }); yield return(new object[] { edgeHubConfig8, edgeHubConfig9, false }); yield return(new object[] { edgeHubConfig9, edgeHubConfig10, true }); yield return(new object[] { edgeHubConfig10, edgeHubConfig11, false }); yield return(new object[] { edgeHubConfig11, edgeHubConfig12, false }); yield return(new object[] { edgeHubConfig10, edgeHubConfig13, true }); yield return(new object[] { edgeHubConfig12, edgeHubConfig13, false }); // authorization config equality check var edgeHubConfig14 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1, Option.Some(brokerConfig2)); var edgeHubConfig15 = new EdgeHubConfig(version, routes1, storeAndForwardConfig1, Option.Some(brokerConfig3)); yield return(new object[] { edgeHubConfig1, edgeHubConfig14, false }); yield return(new object[] { edgeHubConfig1, edgeHubConfig15, true }); }
public async Task TestInitialConfigUpdate_NoWaitForInit() { // Arrange string id = "id"; string iotHub = "foo.azure-devices.net"; var routerConfig = new RouterConfig(Enumerable.Empty<Route>()); var messageStore = new Mock<IMessageStore>(); messageStore.Setup(m => m.SetTimeToLive(It.IsAny<TimeSpan>())); TimeSpan updateFrequency = TimeSpan.FromMinutes(10); Endpoint GetEndpoint() => new ModuleEndpoint("id", Guid.NewGuid().ToString(), "in1", Mock.Of<IConnectionManager>(), Mock.Of<Core.IMessageConverter<IMessage>>()); var endpointFactory = new Mock<IEndpointFactory>(); endpointFactory.Setup(e => e.CreateSystemEndpoint($"$upstream")).Returns(GetEndpoint); var routeFactory = new EdgeRouteFactory(endpointFactory.Object); var endpointExecutorFactory = new Mock<IEndpointExecutorFactory>(); endpointExecutorFactory.Setup(e => e.CreateAsync(It.IsAny<Endpoint>())) .Returns<Endpoint>(endpoint => Task.FromResult(Mock.Of<IEndpointExecutor>(e => e.Endpoint == endpoint))); Router router = await Router.CreateAsync(id, iotHub, routerConfig, endpointExecutorFactory.Object); var routes1 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration1 = new StoreAndForwardConfiguration(7200); var edgeHubConfig1 = new EdgeHubConfig("1.0", routes1, storeAndForwardConfiguration1); var routes2 = Routes.Take(3) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration2 = new StoreAndForwardConfiguration(7200); var edgeHubConfig2 = new EdgeHubConfig("1.0", routes2, storeAndForwardConfiguration2); var configProvider = new Mock<IConfigSource>(); configProvider.SetupSequence(c => c.GetConfig()) .Returns(async () => { await Task.Delay(5000); return Option.Some(edgeHubConfig2); }); configProvider.Setup(c => c.SetConfigUpdatedCallback(It.IsAny<Func<EdgeHubConfig, Task>>())); var initialConfigSource = new Mock<IConfigSource>(); initialConfigSource.Setup(c => c.GetConfig()) .Returns(() => { return Task.FromResult(Option.Some(edgeHubConfig1)); }); // Act var configUpdater = new ConfigUpdater(router, messageStore.Object, updateFrequency, Option.Some(initialConfigSource.Object)); await configUpdater.Init(configProvider.Object); // Assert // First only has updated from prefeched config Assert.Equal(2, router.Routes.Count); // After 6 seconds updates from init received await Task.Delay(TimeSpan.FromSeconds(6)); Assert.Equal(3, router.Routes.Count); }
public async Task TestPeriodicConfigUpdate() { // Arrange string id = "id"; string iotHub = "foo.azure-devices.net"; var routerConfig = new RouterConfig(Enumerable.Empty <Route>()); var messageStore = new Mock <IMessageStore>(); messageStore.Setup(m => m.SetTimeToLive(It.IsAny <TimeSpan>())); TimeSpan updateFrequency = TimeSpan.FromSeconds(10); Endpoint GetEndpoint() => new ModuleEndpoint("id", Guid.NewGuid().ToString(), "in1", Mock.Of <IConnectionManager>(), Mock.Of <Core.IMessageConverter <IMessage> >()); var endpointFactory = new Mock <IEndpointFactory>(); endpointFactory.Setup(e => e.CreateSystemEndpoint($"$upstream")).Returns(GetEndpoint); var routeFactory = new EdgeRouteFactory(endpointFactory.Object); var endpointExecutorFactory = new Mock <IEndpointExecutorFactory>(); endpointExecutorFactory.Setup(e => e.CreateAsync(It.IsAny <Endpoint>())) .Returns <Endpoint>(endpoint => Task.FromResult(Mock.Of <IEndpointExecutor>(e => e.Endpoint == endpoint))); Router router = await Router.CreateAsync(id, iotHub, routerConfig, endpointExecutorFactory.Object); var routes1 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration1 = new StoreAndForwardConfiguration(7200); var edgeHubConfig1 = new EdgeHubConfig("1.0", routes1, storeAndForwardConfiguration1); var routes2 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration2 = new StoreAndForwardConfiguration(7200); var edgeHubConfig2 = new EdgeHubConfig("1.0", routes2, storeAndForwardConfiguration2); var routes3 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration3 = new StoreAndForwardConfiguration(7200); var edgeHubConfig3 = new EdgeHubConfig("1.0", routes3, storeAndForwardConfiguration3); var routes4 = Routes.Skip(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration4 = new StoreAndForwardConfiguration(7200); var edgeHubConfig4 = new EdgeHubConfig("1.0", routes4, storeAndForwardConfiguration4); var routes5 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration5 = new StoreAndForwardConfiguration(7200); var edgeHubConfig5 = new EdgeHubConfig("1.0", routes5, storeAndForwardConfiguration5); var routes6 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration6 = new StoreAndForwardConfiguration(3600); var edgeHubConfig6 = new EdgeHubConfig("1.0", routes6, storeAndForwardConfiguration6); var configProvider = new Mock <IConfigSource>(); configProvider.SetupSequence(c => c.GetConfig()) .ReturnsAsync(Option.Some(edgeHubConfig1)) .ReturnsAsync(Option.Some(edgeHubConfig2)) .ReturnsAsync(Option.Some(edgeHubConfig3)) .ReturnsAsync(Option.Some(edgeHubConfig4)) .ReturnsAsync(Option.Some(edgeHubConfig5)) .ReturnsAsync(Option.Some(edgeHubConfig6)); configProvider.Setup(c => c.SetConfigUpdatedCallback(It.IsAny <Func <EdgeHubConfig, Task> >())); // Act var configUpdater = new ConfigUpdater(router, messageStore.Object, updateFrequency); configUpdater.Init(configProvider.Object); // Assert await Task.Delay(TimeSpan.FromSeconds(8)); configProvider.Verify(c => c.GetConfig(), Times.Once); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); await Task.Delay(TimeSpan.FromSeconds(20)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(3)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(4)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(2)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(5)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(3)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(6)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(4)); }
public async Task TestPeriodicAndCallbackConfigUpdate() { // Arrange string id = "id"; string iotHub = "foo.azure-devices.net"; var routerConfig = new RouterConfig(Enumerable.Empty <Route>()); var messageStore = new Mock <IMessageStore>(); messageStore.Setup(m => m.SetTimeToLive(It.IsAny <TimeSpan>())); var storageSpaceChecker = new Mock <IStorageSpaceChecker>(); storageSpaceChecker.Setup(m => m.SetMaxSizeBytes(It.IsAny <Option <long> >())); TimeSpan updateFrequency = TimeSpan.FromSeconds(10); Endpoint GetEndpoint() => new ModuleEndpoint("id", Guid.NewGuid().ToString(), "in1", Mock.Of <IConnectionManager>(), Mock.Of <Core.IMessageConverter <IMessage> >()); var endpointFactory = new Mock <IEndpointFactory>(); endpointFactory.Setup(e => e.CreateSystemEndpoint($"$upstream")).Returns(GetEndpoint); var routeFactory = new EdgeRouteFactory(endpointFactory.Object); var endpointExecutorFactory = new Mock <IEndpointExecutorFactory>(); endpointExecutorFactory.Setup(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >())) .Returns <Endpoint, IList <uint> >((endpoint, priorities) => Task.FromResult(Mock.Of <IEndpointExecutor>(e => e.Endpoint == endpoint))); Router router = await Router.CreateAsync(id, iotHub, routerConfig, endpointExecutorFactory.Object); var routes1 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration1 = new StoreAndForwardConfiguration(7200); var edgeHubConfig1 = new EdgeHubConfig("1.0", routes1, storeAndForwardConfiguration1); var routes2 = Routes.Take(3) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration2 = new StoreAndForwardConfiguration(7200); var edgeHubConfig2 = new EdgeHubConfig("1.0", routes2, storeAndForwardConfiguration2); var routes3 = Routes.Take(4) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration3 = new StoreAndForwardConfiguration(7200); var edgeHubConfig3 = new EdgeHubConfig("1.0", routes3, storeAndForwardConfiguration3); Func <EdgeHubConfig, Task> updateCallback = null; var configProvider = new Mock <IConfigSource>(); configProvider.SetupSequence(c => c.GetConfig()) .ReturnsAsync(Option.Some(edgeHubConfig1)) .ReturnsAsync(Option.Some(edgeHubConfig2)) .ReturnsAsync(Option.Some(edgeHubConfig3)); configProvider.Setup(c => c.SetConfigUpdatedCallback(It.IsAny <Func <EdgeHubConfig, Task> >())) .Callback <Func <EdgeHubConfig, Task> >(callback => { updateCallback = callback; }); configProvider.Setup(c => c.GetCachedConfig()) .Returns(() => Task.FromResult(Option.None <EdgeHubConfig>())); // Act var configUpdater = new ConfigUpdater(router, messageStore.Object, updateFrequency, storageSpaceChecker.Object); await configUpdater.Init(configProvider.Object); // Assert configProvider.Verify(c => c.GetConfig(), Times.Once); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Once); // call update with no changes await updateCallback(edgeHubConfig1); configProvider.Verify(c => c.GetConfig(), Times.Exactly(1)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Once); await Task.Delay(TimeSpan.FromSeconds(12)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(2)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(2)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(2)); // call update with changes await updateCallback(edgeHubConfig3); configProvider.Verify(c => c.GetConfig(), Times.Exactly(2)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(3)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(3)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(3)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(3)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(3)); }
public void GetEdgeHubConfig_ValidInput_MappingIsCorrect() { var validator = new Mock <BrokerPropertiesValidator>(); validator .Setup(v => v.ValidateAuthorizationConfig(It.IsAny <AuthorizationProperties>())) .Returns(new List <string>()); var routeFactory = new EdgeRouteFactory(new Mock <IEndpointFactory>().Object); var configParser = new EdgeHubConfigParser(routeFactory, validator.Object); EdgeHubDesiredProperties properties = ConfigTestData.GetTestData(); // act EdgeHubConfig result = configParser.GetEdgeHubConfig(properties); // assert validator.Verify(v => v.ValidateAuthorizationConfig(properties.BrokerConfiguration.Authorizations), Times.Once()); Assert.Equal("1.2.0", result.SchemaVersion); AuthorizationConfig authzConfig = result .BrokerConfiguration .Expect(() => new InvalidOperationException("missing broker config")) .Authorizations .Expect(() => new InvalidOperationException("missing authorization config")); Assert.Equal(3, authzConfig.Statements.Count); var result0 = authzConfig.Statements[0]; Assert.Equal(Effect.Deny, result0.Effect); Assert.Equal(2, result0.Identities.Count); Assert.Equal("device_1", result0.Identities[0]); Assert.Equal("device_3", result0.Identities[1]); Assert.Equal(1, result0.Operations.Count); Assert.Equal("mqtt:publish", result0.Operations[0]); Assert.Equal(2, result0.Resources.Count); Assert.Equal("system/alerts/+", result0.Resources[0]); Assert.Equal("core/#", result0.Resources[1]); var result1 = authzConfig.Statements[1]; Assert.Equal(Effect.Allow, result1.Effect); Assert.Equal(2, result1.Identities.Count); Assert.Equal("device_1", result1.Identities[0]); Assert.Equal("device_3", result1.Identities[1]); Assert.Equal(2, result1.Operations.Count); Assert.Equal("mqtt:publish", result1.Operations[0]); Assert.Equal("mqtt:subscribe", result1.Operations[1]); Assert.Equal(2, result1.Resources.Count); Assert.Equal("topic/a", result1.Resources[0]); Assert.Equal("topic/b", result1.Resources[1]); var result2 = authzConfig.Statements[2]; Assert.Equal(Effect.Allow, result2.Effect); Assert.Equal(1, result2.Identities.Count); Assert.Equal("device_2", result2.Identities[0]); Assert.Equal(2, result2.Operations.Count); Assert.Equal("mqtt:publish", result2.Operations[0]); Assert.Equal("mqtt:subscribe", result2.Operations[1]); Assert.Equal(2, result2.Resources.Count); Assert.Equal("topic1", result2.Resources[0]); Assert.Equal("topic2", result2.Resources[1]); }
public void EqualityTest(EdgeHubConfig e1, EdgeHubConfig e2, bool areEqual) { Assert.Equal(areEqual, e1.Equals(e2)); }
public async Task TestPeriodicConfigUpdate() { // Arrange string id = "id"; string iotHub = "foo.azure-devices.net"; var routerConfig = new RouterConfig(Enumerable.Empty <Route>()); var messageStore = new Mock <IMessageStore>(); messageStore.Setup(m => m.SetTimeToLive(It.IsAny <TimeSpan>())); var storageSpaceChecker = new Mock <IStorageSpaceChecker>(); storageSpaceChecker.Setup(m => m.SetMaxSizeBytes(It.IsAny <Option <long> >())); TimeSpan updateFrequency = TimeSpan.FromSeconds(10); Endpoint GetEndpoint() => new ModuleEndpoint("id", Guid.NewGuid().ToString(), "in1", Mock.Of <IConnectionManager>(), Mock.Of <Core.IMessageConverter <IMessage> >()); var endpointFactory = new Mock <IEndpointFactory>(); endpointFactory.Setup(e => e.CreateSystemEndpoint($"$upstream")).Returns(GetEndpoint); var routeFactory = new EdgeRouteFactory(endpointFactory.Object); var endpointExecutorFactory = new Mock <IEndpointExecutorFactory>(); endpointExecutorFactory.Setup(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>())) .Returns <Endpoint, IList <uint>, ICheckpointerFactory>((endpoint, priorities, checkpointerFactory) => Task.FromResult(Mock.Of <IEndpointExecutor>(e => e.Endpoint == endpoint))); Router router = await Router.CreateAsync(id, iotHub, routerConfig, endpointExecutorFactory.Object); var routes1 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration1 = new StoreAndForwardConfiguration(7200); var edgeHubConfig1 = new EdgeHubConfig("1.0", routes1, storeAndForwardConfiguration1, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes2 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration2 = new StoreAndForwardConfiguration(7200); var edgeHubConfig2 = new EdgeHubConfig("1.0", routes2, storeAndForwardConfiguration2, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes3 = Routes.Take(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration3 = new StoreAndForwardConfiguration(7200); var edgeHubConfig3 = new EdgeHubConfig("1.0", routes3, storeAndForwardConfiguration3, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes4 = Routes.Skip(2) .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration4 = new StoreAndForwardConfiguration(7200); var edgeHubConfig4 = new EdgeHubConfig("1.0", routes4, storeAndForwardConfiguration4, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes5 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration5 = new StoreAndForwardConfiguration(7200); var edgeHubConfig5 = new EdgeHubConfig("1.0", routes5, storeAndForwardConfiguration5, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes6 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration6 = new StoreAndForwardConfiguration(3600); var edgeHubConfig6 = new EdgeHubConfig("1.0", routes6, storeAndForwardConfiguration6, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes7 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration7 = new StoreAndForwardConfiguration(3600, new StoreLimits(10L)); var edgeHubConfig7 = new EdgeHubConfig("1.0", routes7, storeAndForwardConfiguration7, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var routes8 = Routes .ToDictionary(r => r.Key, r => new RouteConfig(r.Key, r.Value, routeFactory.Create(r.Value))); var storeAndForwardConfiguration8 = new StoreAndForwardConfiguration(3600, new StoreLimits(20L)); var edgeHubConfig8 = new EdgeHubConfig("1.0", routes8, storeAndForwardConfiguration8, Option.None <BrokerConfig>(), Option.None <ManifestIntegrity>()); var configProvider = new Mock <IConfigSource>(); configProvider.SetupSequence(c => c.GetConfig()) .ReturnsAsync(Option.Some(edgeHubConfig1)) .ReturnsAsync(Option.Some(edgeHubConfig2)) .ReturnsAsync(Option.Some(edgeHubConfig3)) .ReturnsAsync(Option.Some(edgeHubConfig4)) .ReturnsAsync(Option.Some(edgeHubConfig5)) .ReturnsAsync(Option.Some(edgeHubConfig6)) .ReturnsAsync(Option.Some(edgeHubConfig7)) .ReturnsAsync(Option.Some(edgeHubConfig8)) .ReturnsAsync(Option.Some(edgeHubConfig8)); configProvider.Setup(c => c.GetCachedConfig()) .Returns(() => Task.FromResult(Option.None <EdgeHubConfig>())); // Act var configUpdater = new ConfigUpdater(router, messageStore.Object, updateFrequency, storageSpaceChecker.Object); await configUpdater.Init(configProvider.Object); // Assert configProvider.Verify(c => c.GetConfig(), Times.Once); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Once); // After 5 seconds, the periodic task should not have run. await Task.Delay(TimeSpan.FromSeconds(5)); configProvider.Verify(c => c.GetConfig(), Times.Once); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Once); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Once); await Task.Delay(TimeSpan.FromSeconds(20)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(3)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(3)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(3)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(4)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(4)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(4)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(5)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(5)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(5)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(6)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(6)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => x.Equals(Option.None <long>()))), Times.Exactly(6)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(7)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(7)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => !x.Equals(Option.None <long>()))), Times.Exactly(1)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(8)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(8)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => !x.Equals(Option.None <long>()))), Times.Exactly(2)); await Task.Delay(TimeSpan.FromSeconds(10)); configProvider.Verify(c => c.GetConfig(), Times.Exactly(9)); endpointExecutorFactory.Verify(e => e.CreateAsync(It.IsAny <Endpoint>(), It.IsAny <IList <uint> >(), It.IsAny <ICheckpointerFactory>()), Times.Once); messageStore.Verify(m => m.SetTimeToLive(It.IsAny <TimeSpan>()), Times.Exactly(8)); storageSpaceChecker.Verify(m => m.SetMaxSizeBytes(It.Is <Option <long> >(x => !x.Equals(Option.None <long>()))), Times.Exactly(2)); }