Beispiel #1
0
        public async Task GetCloudConnectionForIdentityWithKeyTest()
        {
            IClientProvider clientProvider           = GetMockDeviceClientProviderWithKey();
            var             tokenProvider            = Mock.Of <ITokenProvider>();
            var             identity                 = Mock.Of <IIdentity>(i => i.Id == "d1");
            var             transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var             messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            CloudConnection cloudConnection = await CloudConnection.Create(
                identity,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                clientProvider,
                Mock.Of <ICloudListener>(),
                tokenProvider,
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20),
                DummyProductInfo);

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);
        }
Beispiel #2
0
        public async Task UpdateInvalidIdentityWithTokenTest()
        {
            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.SetupSequence(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>()))
            .Returns(GetMockDeviceClient())
            .Throws(new UnauthorizedException("Unauthorized"));

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          identity1       = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                identity1,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            ITokenCredentials identity2 = GetMockClientCredentialsWithToken();
            await Assert.ThrowsAsync <UnauthorizedException>(() => cloudConnection.UpdateTokenAsync(identity2));

            Assert.True(cloudProxy1.OrDefault().IsActive);
        }
        public async Task UpdateInvalidIdentityWithTokenTest()
        {
            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.SetupSequence(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <IAuthenticationMethod>(), It.IsAny <ITransportSettings[]>()))
            .Returns(GetMockDeviceClient())
            .Throws(new UnauthorizedException("Unauthorized"));

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            var cloudConnection = new CloudConnection((_, __) => { }, transportSettings, messageConverterProvider, deviceClientProvider.Object, Mock.Of <ICloudListener>(), TokenProvider, DeviceScopeIdentitiesCache, TimeSpan.FromMinutes(60), true);

            IClientCredentials identity1   = GetMockClientCredentialsWithToken();
            ICloudProxy        cloudProxy1 = await cloudConnection.CreateOrUpdateAsync(identity1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());

            IClientCredentials identity2 = GetMockClientCredentialsWithToken();
            await Assert.ThrowsAsync <AggregateException>(() => cloudConnection.CreateOrUpdateAsync(identity2));

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());
        }
        public void ThrowsWhenItDoesNotHaveTheRequestedProvider()
        {
            var provider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter>());
            var fn       = new Func <IMessageConverter <int> >(() => provider.Get <int>());

            Assert.Throws <KeyNotFoundException>(fn);
        }
Beispiel #5
0
        async Task <ICloudProxy> GetCloudProxyWithConnectionStringKey(string connectionStringConfigKey, IEdgeHub edgeHub)
        {
            const int ConnectionPoolSize     = 10;
            string    deviceConnectionString = await SecretsHelper.GetSecretFromConfigKey(connectionStringConfigKey);

            var converters = new MessageConverterProvider(new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Client.Message), new DeviceClientMessageConverter() },
                { typeof(Twin), new TwinMessageConverter() },
                { typeof(TwinCollection), new TwinCollectionMessageConverter() }
            });

            ICloudConnectionProvider cloudConnectionProvider = new CloudConnectionProvider(converters, ConnectionPoolSize, new ClientProvider(), Option.None <UpstreamProtocol>(), Mock.Of <ITokenProvider>(), Mock.Of <IDeviceScopeIdentitiesCache>(), TimeSpan.FromMinutes(60), true);

            cloudConnectionProvider.BindEdgeHub(edgeHub);
            var deviceIdentity    = Mock.Of <IDeviceIdentity>(m => m.Id == ConnectionStringHelper.GetDeviceId(deviceConnectionString));
            var clientCredentials = new SharedKeyCredentials(deviceIdentity, deviceConnectionString, string.Empty);

            Try <ICloudConnection> cloudConnection = await cloudConnectionProvider.Connect(clientCredentials, (_, __) => { });

            Assert.True(cloudConnection.Success);
            Assert.True(cloudConnection.Value.IsActive);
            Assert.True(cloudConnection.Value.CloudProxy.HasValue);
            return(cloudConnection.Value.CloudProxy.OrDefault());
        }
Beispiel #6
0
        public async Task GetCloudConnectionForIdentityWithTokenTest()
        {
            IClientProvider clientProvider           = GetMockDeviceClientProviderWithToken();
            var             transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var             messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          clientCredentials1 = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection    = await ClientTokenCloudConnection.Create(
                clientCredentials1,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                clientProvider,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            ITokenCredentials clientCredentials2 = GetMockClientCredentialsWithToken();
            ICloudProxy       cloudProxy2        = await cloudConnection.UpdateTokenAsync(clientCredentials2);

            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.False(cloudProxy1.OrDefault().IsActive);
            Assert.NotEqual(cloudProxy1.OrDefault(), cloudProxy2);
        }
Beispiel #7
0
        public async Task GetCloudConnectionThrowsTest()
        {
            var deviceClient = new Mock <IClient>();

            deviceClient.SetupGet(dc => dc.IsActive).Returns(true);
            deviceClient.Setup(dc => dc.CloseAsync())
            .Callback(() => deviceClient.SetupGet(dc => dc.IsActive).Returns(false))
            .Returns(Task.FromResult(true));
            deviceClient.Setup(dc => dc.OpenAsync()).ThrowsAsync(new TimeoutException());

            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>()))
            .Returns(deviceClient.Object);

            var tokenProvider            = Mock.Of <ITokenProvider>();
            var identity                 = Mock.Of <IIdentity>(i => i.Id == "d1");
            var transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            await Assert.ThrowsAsync <TimeoutException>(
                () => CloudConnection.Create(
                    identity,
                    (_, __) => { },
                    transportSettings,
                    messageConverterProvider,
                    deviceClientProvider.Object,
                    Mock.Of <ICloudListener>(),
                    tokenProvider,
                    TimeSpan.FromMinutes(60),
                    true,
                    TimeSpan.FromSeconds(20),
                    DummyProductInfo));
        }
Beispiel #8
0
        public async Task RefreshTokenTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            IClientCredentials GetClientCredentialsWithExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddSeconds(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty));
            }

            IAuthenticationMethod authenticationMethod = null;
            IClientProvider       clientProvider       = GetMockDeviceClientProviderWithToken((s, a, t) => authenticationMethod = a);

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var receivedStatus = CloudConnectionStatus.ConnectionEstablished;

            void ConnectionStatusHandler(string id, CloudConnectionStatus status) => receivedStatus = status;

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter>());

            var cloudConnection = new CloudConnection(ConnectionStatusHandler, transportSettings, messageConverterProvider, clientProvider);

            IClientCredentials clientCredentialsWithExpiringToken1 = GetClientCredentialsWithExpiringToken();
            ICloudProxy        cloudProxy1 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());

            Assert.NotNull(authenticationMethod);
            var deviceAuthenticationWithTokenRefresh = authenticationMethod as DeviceAuthenticationWithTokenRefresh;

            Assert.NotNull(deviceAuthenticationWithTokenRefresh);

            // Wait for the token to expire
            await Task.Delay(TimeSpan.FromSeconds(10));

            Task <string> getTokenTask = deviceAuthenticationWithTokenRefresh.GetTokenAsync(iothubHostName);

            Assert.False(getTokenTask.IsCompleted);

            Assert.Equal(receivedStatus, CloudConnectionStatus.TokenNearExpiry);

            IClientCredentials clientCredentialsWithExpiringToken2 = GetClientCredentialsWithExpiringToken();
            ICloudProxy        cloudProxy2 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken2);

            // Wait for the task to complete
            await Task.Delay(TimeSpan.FromSeconds(10));

            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudProxy2);
            Assert.True(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(getTokenTask.Result, (clientCredentialsWithExpiringToken2 as ITokenCredentials)?.Token);
        }
Beispiel #9
0
        async Task <ICloudProxy> GetCloudProxyFromConnectionStringKey(string connectionStringConfigKey, IEdgeHub edgeHub)
        {
            const int ConnectionPoolSize     = 10;
            string    deviceConnectionString = await SecretsHelper.GetSecretFromConfigKey(connectionStringConfigKey);

            string deviceId       = ConnectionStringHelper.GetDeviceId(deviceConnectionString);
            string iotHubHostName = ConnectionStringHelper.GetHostName(deviceConnectionString);
            string sasKey         = ConnectionStringHelper.GetSharedAccessKey(deviceConnectionString);
            var    converters     = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Message), new DeviceClientMessageConverter() },
                { typeof(Twin), new TwinMessageConverter() },
                { typeof(TwinCollection), new TwinCollectionMessageConverter() }
            });

            var credentialsCache = Mock.Of <ICredentialsCache>();
            var metadataStore    = new Mock <IMetadataStore>();

            metadataStore.Setup(m => m.GetMetadata(It.IsAny <string>())).ReturnsAsync(new ConnectionMetadata("dummyValue"));
            ICloudConnectionProvider cloudConnectionProvider = new CloudConnectionProvider(
                converters,
                ConnectionPoolSize,
                new ClientProvider(Option.None <string>()),
                Option.None <UpstreamProtocol>(),
                Mock.Of <Util.ITokenProvider>(),
                Mock.Of <IDeviceScopeIdentitiesCache>(),
                credentialsCache,
                Mock.Of <IIdentity>(i => i.Id == $"{deviceId}/$edgeHub"),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20),
                false,
                Option.None <IWebProxy>(),
                metadataStore.Object,
                true,
                true);

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            var    clientTokenProvider = new ClientTokenProvider(new SharedAccessKeySignatureProvider(sasKey), iotHubHostName, deviceId, TimeSpan.FromHours(1));
            string token = await clientTokenProvider.GetTokenAsync(Option.None <TimeSpan>());

            var deviceIdentity    = new DeviceIdentity(iotHubHostName, deviceId);
            var clientCredentials = new TokenCredentials(deviceIdentity, token, string.Empty, Option.None <string>(), Option.None <string>(), false);

            Try <ICloudConnection> cloudConnection = await cloudConnectionProvider.Connect(clientCredentials, (_, __) => { });

            Assert.True(cloudConnection.Success);
            Assert.True(cloudConnection.Value.IsActive);
            Assert.True(cloudConnection.Value.CloudProxy.HasValue);
            return(cloudConnection.Value.CloudProxy.OrDefault());
        }
        public void ProvidesAConverterForTheGivenType()
        {
            var expectedConverter = new TestMessageConverter();
            var provider          = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>()
            {
                { typeof(int), expectedConverter }
            });

            IMessageConverter <int> actualConverter = provider.Get <int>();

            Assert.Same(expectedConverter, actualConverter);
        }
        public async Task InitializeAndGetCloudProxyTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            ITokenCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, Option.None <string>(), Option.None <string>(), false));
            }

            IClient client = GetMockDeviceClient();
            var     deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>(), Option.None <string>()))
            .Returns(() => client);

            var transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            ITokenCredentials          clientCredentialsWithNonExpiringToken = GetClientCredentialsWithNonExpiringToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithNonExpiringToken,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20),
                DummyProductInfo,
                Option.None <string>());

            Option <ICloudProxy> cloudProxy = cloudConnection.CloudProxy;

            Assert.True(cloudProxy.HasValue);
            Assert.True(cloudProxy.OrDefault().IsActive);
            Mock.Get(client).Verify(c => c.OpenAsync(), Times.Once);
        }
Beispiel #12
0
        static async Task GetCloudConnectionTest(Func <IClientCredentials> credentialsGenerator, IClientProvider clientProvider)
        {
            var transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter>());

            var cloudConnection = new CloudConnection((_, __) => { }, transportSettings, messageConverterProvider, clientProvider);

            IClientCredentials clientCredentials1 = credentialsGenerator();
            ICloudProxy        cloudProxy1        = await cloudConnection.CreateOrUpdateAsync(clientCredentials1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());

            IClientCredentials clientCredentials2 = credentialsGenerator();
            ICloudProxy        cloudProxy2        = await cloudConnection.CreateOrUpdateAsync(clientCredentials2);

            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.False(cloudProxy1.IsActive);
            Assert.NotEqual(cloudProxy1, cloudProxy2);
        }
        static async Task GetCloudConnectionTest(Func <IClientCredentials> credentialsGenerator, IClientProvider clientProvider)
        {
            var transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            var cloudConnection = new CloudConnection((_, __) => { }, transportSettings, messageConverterProvider, clientProvider, Mock.Of <ICloudListener>(), TokenProvider, DeviceScopeIdentitiesCache, TimeSpan.FromMinutes(60), true);

            IClientCredentials clientCredentials1 = credentialsGenerator();
            ICloudProxy        cloudProxy1        = await cloudConnection.CreateOrUpdateAsync(clientCredentials1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());

            IClientCredentials clientCredentials2 = credentialsGenerator();
            ICloudProxy        cloudProxy2        = await cloudConnection.CreateOrUpdateAsync(clientCredentials2);

            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.False(cloudProxy1.IsActive);
            Assert.NotEqual(cloudProxy1, cloudProxy2);
        }
Beispiel #14
0
        public async Task InitializeAndGetCloudProxyTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            IClientCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty));
            }

            IClient client = GetMockDeviceClient();
            var     deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <IAuthenticationMethod>(), It.IsAny <ITransportSettings[]>()))
            .Returns(() => client);

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            var cloudConnection = new CloudConnection((_, __) => { }, transportSettings, messageConverterProvider, deviceClientProvider.Object, Mock.Of <ICloudListener>(), TokenProvider, DeviceScopeIdentitiesCache, TimeSpan.FromMinutes(60), true);

            IClientCredentials clientCredentialsWithExpiringToken2 = GetClientCredentialsWithNonExpiringToken();
            ICloudProxy        cloudProxy = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken2);

            // Wait for the task to complete
            await Task.Delay(TimeSpan.FromSeconds(10));

            Assert.Equal(cloudProxy, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy.IsActive);
            Mock.Get(client).Verify(c => c.OpenAsync(), Times.Once);
        }
Beispiel #15
0
        async Task <(IMessageConsumer, IMessageConsumer, NullBrokerConnector)> SetupEnvironment()
        {
            Routing.UserMetricLogger    = NullRoutingUserMetricLogger.Instance;
            Routing.PerfCounter         = NullRoutingPerfCounter.Instance;
            Routing.UserAnalyticsLogger = NullUserAnalyticsLogger.Instance;

            var defaultRetryStrategy   = new FixedInterval(5, TimeSpan.FromSeconds(5));
            var defaultRevivePeriod    = TimeSpan.FromHours(1);
            var defaultTimeout         = TimeSpan.FromSeconds(60);
            var endpointExecutorConfig = new EndpointExecutorConfig(defaultTimeout, defaultRetryStrategy, defaultRevivePeriod, true);

            var cloudProxyDispatcher    = new BrokeredCloudProxyDispatcher();
            var cloudConnectionProvider = new BrokeredCloudConnectionProvider(cloudProxyDispatcher);

            var identityProvider          = new IdentityProvider(iotHubName);
            var deviceConnectivityManager = new BrokeredDeviceConnectivityManager(cloudProxyDispatcher);

            var connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of <ICredentialsCache>(), new IdentityProvider(iotHubName), deviceConnectivityManager);

            var routingMessageConverter = new RoutingMessageConverter();
            var routeFactory            = new EdgeRouteFactory(new EndpointFactory(connectionManager, routingMessageConverter, edgeDeviceId, 10, 10));
            var routesList   = new[] { routeFactory.Create("FROM /messages INTO $upstream") };
            var endpoints    = routesList.Select(r => r.Endpoint);
            var routerConfig = new RouterConfig(endpoints, routesList);

            var dbStoreProvider         = new InMemoryDbStoreProvider();
            var storeProvider           = new StoreProvider(dbStoreProvider);
            var messageStore            = new MessageStore(storeProvider, CheckpointStore.Create(storeProvider), TimeSpan.MaxValue, false, 1800);
            var endpointExecutorFactory = new StoringAsyncEndpointExecutorFactory(endpointExecutorConfig, new AsyncEndpointExecutorOptions(1, TimeSpan.FromMilliseconds(10)), messageStore);

            var router = await Router.CreateAsync(Guid.NewGuid().ToString(), iotHubName, routerConfig, endpointExecutorFactory);

            var messageConverterProvider = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Twin), new TwinMessageConverter() },
                { typeof(TwinCollection), new TwinCollectionMessageConverter() }
            });

            var twinManager           = TwinManager.CreateTwinManager(connectionManager, messageConverterProvider, Option.None <IStoreProvider>());
            var invokeMethodHandler   = Mock.Of <IInvokeMethodHandler>();
            var subscriptionProcessor = new SubscriptionProcessor(connectionManager, invokeMethodHandler, deviceConnectivityManager);

            var edgeHub = new RoutingEdgeHub(router, routingMessageConverter, connectionManager, twinManager, edgeDeviceId, edgeModuleName, invokeMethodHandler, subscriptionProcessor, Mock.Of <IDeviceScopeIdentitiesCache>());

            var brokerConnector = new NullBrokerConnector(cloudProxyDispatcher);

            cloudProxyDispatcher.SetConnector(brokerConnector);
            cloudProxyDispatcher.BindEdgeHub(edgeHub);

            var connectionProvider = new ConnectionProvider(connectionManager, edgeHub, TimeSpan.FromSeconds(30));
            var authenticator      = new NullAuthenticator();

            var edgeHubIdentity         = new ModuleIdentity(iotHubName, edgeDeviceId, edgeModuleName);
            var tokenCredentials        = new TokenCredentials(edgeHubIdentity, "qwerty", "test-product", Option.Some("test-model"), Option.None <string>(), false);
            var systemComponentProvider = new SystemComponentIdProvider(tokenCredentials);

            var connectionHandler = default(ConnectionHandler);

            connectionHandler = new ConnectionHandler(
                Task.FromResult <IConnectionProvider>(connectionProvider),
                Task.FromResult <IAuthenticator>(authenticator),
                identityProvider,
                systemComponentProvider,
                DeviceProxyFactory);

            DeviceProxy DeviceProxyFactory(IIdentity identity, bool isDirectClient)
            {
                return(new DeviceProxy(identity, isDirectClient, connectionHandler, Mock.Of <ITwinHandler>(), Mock.Of <IModuleToModuleMessageHandler>(), Mock.Of <ICloud2DeviceMessageHandler>(), Mock.Of <IDirectMethodHandler>()));
            }

            var cloud2DeviceMessageHandler   = new Cloud2DeviceMessageHandler(connectionHandler);
            var moduleToModuleMessageHandler = new ModuleToModuleMessageHandler(connectionHandler, identityProvider, new ModuleToModuleResponseTimeout(TimeSpan.FromSeconds(10)));
            var directMethodHandler          = new DirectMethodHandler(connectionHandler, identityProvider);
            var twinHandler = new TwinHandler(connectionHandler, identityProvider);

            var subscriptionChangeHandler = new SubscriptionChangeHandler(
                cloud2DeviceMessageHandler,
                moduleToModuleMessageHandler,
                directMethodHandler,
                twinHandler,
                connectionHandler,
                identityProvider);

            return(subscriptionChangeHandler, cloudProxyDispatcher, brokerConnector);
        }
        public async Task CloudConnectionCallbackTest()
        {
            int receivedConnectedStatusCount = 0;
            ConnectionStatusChangesHandler connectionStatusChangesHandler = (_, __) => { };

            IClient GetMockedDeviceClient()
            {
                var deviceClient = new Mock <IClient>();

                deviceClient.SetupGet(dc => dc.IsActive).Returns(true);
                deviceClient.Setup(dc => dc.CloseAsync())
                .Callback(() => deviceClient.SetupGet(dc => dc.IsActive).Returns(false))
                .Returns(Task.FromResult(true));

                deviceClient.Setup(dc => dc.SetConnectionStatusChangedHandler(It.IsAny <ConnectionStatusChangesHandler>()))
                .Callback <ConnectionStatusChangesHandler>(c => connectionStatusChangesHandler = c);

                deviceClient.Setup(dc => dc.OpenAsync())
                .Callback(
                    () =>
                {
                    Assert.NotNull(connectionStatusChangesHandler);
                    connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
                })
                .Returns(Task.CompletedTask);
                return(deviceClient.Object);
            }

            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>(), Option.None <string>()))
            .Returns(() => GetMockedDeviceClient());

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            void ConnectionStatusHandler(string id, CloudConnectionStatus status)
            {
                if (status == CloudConnectionStatus.ConnectionEstablished)
                {
                    receivedConnectedStatusCount++;
                }
            }

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          clientCredentialsWithExpiringToken1 = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithExpiringToken1,
                ConnectionStatusHandler,
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20),
                DummyProductInfo,
                Option.None <string>());

            Assert.Equal(1, receivedConnectedStatusCount);
            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            Assert.NotNull(connectionStatusChangesHandler);
            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(2, receivedConnectedStatusCount);

            ITokenCredentials clientCredentialsWithExpiringToken2 = GetMockClientCredentialsWithToken();
            ICloudProxy       cloudProxy2 = await cloudConnection.UpdateTokenAsync(clientCredentialsWithExpiringToken2);

            Assert.True(cloudProxy2.IsActive);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.Equal(2, receivedConnectedStatusCount);

            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(3, receivedConnectedStatusCount);
        }
        public async Task TestGetTwin()
        {
            // Arrange
            const string Id                             = "id1";
            var          identity                       = Mock.Of <IIdentity>(i => i.Id == Id);
            var          twinMessageConverter           = new TwinMessageConverter();
            var          twinCollectionMessageConverter = new TwinCollectionMessageConverter();
            var          messageConverterProvider       = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Message), new DeviceClientMessageConverter() },
                { typeof(Shared.Twin), twinMessageConverter },
                { typeof(TwinCollection), twinCollectionMessageConverter }
            });

            var edgeHubTokenProvider = new Mock <ITokenProvider>();

            var clientWatcher = new ClientWatcher();

            var clientProvider = new Mock <IClientProvider>();

            clientProvider.Setup(c => c.Create(identity, edgeHubTokenProvider.Object, It.IsAny <ITransportSettings[]>(), Option.None <string>()))
            .Returns(() => new ThrowingClient(clientWatcher, 3));

            var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(Id))
            .ReturnsAsync(
                Option.Some(
                    new ServiceIdentity(
                        Id,
                        "dummy",
                        new List <string>(),
                        new ServiceAuthentication(new SymmetricKeyAuthentication("foo", "bar")),
                        ServiceIdentityStatus.Enabled)));
            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == Id)))
            .ReturnsAsync(Option.Some(Id));

            var edgeHubIdentity = Mock.Of <IIdentity>();

            ConnectionMetadata connectionMetadata = new ConnectionMetadata("edgeProdInfo");
            var metadataStore = new Mock <IMetadataStore>();

            metadataStore.Setup(p => p.GetMetadata(Id))
            .ReturnsAsync(connectionMetadata);

            var identityProvider = new Mock <IIdentityProvider>();

            identityProvider.Setup(i => i.Create(Id)).Returns(identity);

            var credentialsCache = new Mock <ICredentialsCache>();
            var edgeHub          = new Mock <IEdgeHub>();

            var connectionProvider = new CloudConnectionProvider(
                messageConverterProvider,
                1,
                clientProvider.Object,
                Option.None <UpstreamProtocol>(),
                edgeHubTokenProvider.Object,
                deviceScopeIdentitiesCache.Object,
                credentialsCache.Object,
                edgeHubIdentity,
                TimeSpan.FromMinutes(10),
                false,
                TimeSpan.FromMinutes(10),
                false,
                Option.None <IWebProxy>(),
                metadataStore.Object,
                true);

            connectionProvider.BindEdgeHub(edgeHub.Object);

            var deviceConnectivityManager = Mock.Of <IDeviceConnectivityManager>();
            var connectionManager         = new ConnectionManager(connectionProvider, credentialsCache.Object, identityProvider.Object, deviceConnectivityManager);

            // Act
            Option <ICloudProxy> cloudProxyOption = await connectionManager.GetCloudConnection(Id);

            // Assert
            Assert.True(cloudProxyOption.HasValue);
            ICloudProxy cloudProxy = cloudProxyOption.OrDefault();

            Assert.True(cloudProxy.IsActive);

            // Act
            await RunGetTwin(cloudProxy, 10);

            // Assert
            Assert.Equal(5, clientWatcher.OpenAsyncCount);
            Assert.True(cloudProxy.IsActive);
            Assert.Equal(10, clientWatcher.GetTwinCount);
        }
        public async Task TestMultipleOperations()
        {
            // Arrange
            const string Id                             = "id1";
            var          identity                       = Mock.Of <IIdentity>(i => i.Id == Id);
            var          twinMessageConverter           = new TwinMessageConverter();
            var          twinCollectionMessageConverter = new TwinCollectionMessageConverter();
            var          messageConverterProvider       = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>
            {
                { typeof(Message), new DeviceClientMessageConverter() },
                { typeof(Shared.Twin), twinMessageConverter },
                { typeof(TwinCollection), twinCollectionMessageConverter }
            });

            var edgeHubTokenProvider = new Mock <ITokenProvider>();

            var clientWatcher = new ClientWatcher();

            var clientProvider = new Mock <IClientProvider>();

            clientProvider.Setup(c => c.Create(identity, edgeHubTokenProvider.Object, It.IsAny <ITransportSettings[]>()))
            .Returns(() => new ThrowingClient(clientWatcher, 15));

            var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(Id, false))
            .ReturnsAsync(
                Option.Some(
                    new ServiceIdentity(
                        Id,
                        "dummy",
                        new List <string>(),
                        new ServiceAuthentication(new SymmetricKeyAuthentication("foo", "bar")),
                        ServiceIdentityStatus.Enabled)));

            var edgeHubIdentity = Mock.Of <IIdentity>();

            var productInfoStore = new Mock <IProductInfoStore>();

            productInfoStore.Setup(p => p.GetEdgeProductInfo(Id))
            .ReturnsAsync("ProdInfo1");

            var identityProvider = new Mock <IIdentityProvider>();

            identityProvider.Setup(i => i.Create(Id)).Returns(identity);

            var credentialsCache = new Mock <ICredentialsCache>();
            var edgeHub          = new Mock <IEdgeHub>();

            var connectionProvider = new CloudConnectionProvider(
                messageConverterProvider,
                1,
                clientProvider.Object,
                Option.None <UpstreamProtocol>(),
                edgeHubTokenProvider.Object,
                deviceScopeIdentitiesCache.Object,
                credentialsCache.Object,
                edgeHubIdentity,
                TimeSpan.FromMinutes(10),
                false,
                TimeSpan.FromMinutes(10),
                Option.None <IWebProxy>(),
                productInfoStore.Object);

            connectionProvider.BindEdgeHub(edgeHub.Object);

            var connectionManager = new ConnectionManager(connectionProvider, credentialsCache.Object, identityProvider.Object);

            async Task <ICloudProxy> GetCloudProxy(IConnectionManager cm)
            {
                // Act
                Option <ICloudProxy> cloudProxyOption = await cm.GetCloudConnection(Id);

                // Assert
                Assert.True(cloudProxyOption.HasValue);
                ICloudProxy cloudProxy = cloudProxyOption.OrDefault();

                Assert.True(cloudProxy.IsActive);
                return(cloudProxy);
            }

            var messagesToSend = new List <IMessage>();

            for (int i = 0; i < 60; i++)
            {
                var message = new EdgeMessage.Builder(new byte[i])
                              .SetSystemProperties(
                    new Dictionary <string, string>()
                {
                    [SystemProperties.MessageId] = i.ToString()
                })
                              .Build();
                messagesToSend.Add(message);
            }

            // Act
            ICloudProxy cloudProxy1 = await GetCloudProxy(connectionManager);

            ICloudProxy cloudProxy2 = await GetCloudProxy(connectionManager);

            ICloudProxy cloudProxy3 = await GetCloudProxy(connectionManager);

            // Act
            var tasks = new[]
            {
                RunGetTwin(cloudProxy1, 10),
                RunGetTwin(cloudProxy2, 30),
                RunGetTwin(cloudProxy3, 10),
                RunSendMessages(cloudProxy1, messagesToSend.Take(20), 2),
                RunSendMessages(cloudProxy2, messagesToSend.Skip(20).Take(10)),
                RunSendMessages(cloudProxy3, messagesToSend.Skip(30).Take(30), 3)
            };
            await Task.WhenAll(tasks);

            // Assert
            Assert.Equal(50, clientWatcher.GetTwinCount);
            List <string> expectedMessageIds = messagesToSend
                                               .Select(m => m.SystemProperties[SystemProperties.MessageId])
                                               .OrderBy(s => s)
                                               .ToList();
            List <string> receivedMessageIds = clientWatcher.ReceivedMessages
                                               .Select(m => m.MessageId)
                                               .OrderBy(s => s)
                                               .ToList();

            Assert.Equal(expectedMessageIds.Count, receivedMessageIds.Count);
            Assert.Equal(expectedMessageIds, receivedMessageIds);
        }
        public async Task CloudConnectionCallbackTest()
        {
            int receivedConnectedStatusCount = 0;
            ConnectionStatusChangesHandler connectionStatusChangesHandler = (_, __) => { };

            IClient GetMockedDeviceClient()
            {
                var deviceClient = new Mock <IClient>();

                deviceClient.SetupGet(dc => dc.IsActive).Returns(true);
                deviceClient.Setup(dc => dc.CloseAsync())
                .Callback(() => deviceClient.SetupGet(dc => dc.IsActive).Returns(false))
                .Returns(Task.FromResult(true));

                deviceClient.Setup(dc => dc.SetConnectionStatusChangedHandler(It.IsAny <ConnectionStatusChangesHandler>()))
                .Callback <ConnectionStatusChangesHandler>(c => connectionStatusChangesHandler = c);

                deviceClient.Setup(dc => dc.OpenAsync())
                .Callback(() =>
                {
                    int currentCount = receivedConnectedStatusCount;
                    Assert.NotNull(connectionStatusChangesHandler);
                    connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
                    Assert.Equal(receivedConnectedStatusCount, currentCount);
                })
                .Returns(Task.CompletedTask);
                return(deviceClient.Object);
            }

            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <IAuthenticationMethod>(), It.IsAny <ITransportSettings[]>()))
            .Returns(() => GetMockedDeviceClient());

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            void ConnectionStatusHandler(string id, CloudConnectionStatus status)
            {
                if (status == CloudConnectionStatus.ConnectionEstablished)
                {
                    receivedConnectedStatusCount++;
                }
            }

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            var cloudConnection = new CloudConnection(ConnectionStatusHandler, transportSettings, messageConverterProvider, deviceClientProvider.Object, Mock.Of <ICloudListener>(), TokenProvider, DeviceScopeIdentitiesCache, TimeSpan.FromMinutes(60), true);

            IClientCredentials clientCredentialsWithExpiringToken1 = GetMockClientCredentialsWithToken();

            Assert.Equal(receivedConnectedStatusCount, 0);
            ICloudProxy cloudProxy1 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());
            Assert.Equal(receivedConnectedStatusCount, 0);

            Assert.NotNull(connectionStatusChangesHandler);
            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(receivedConnectedStatusCount, 1);

            IClientCredentials clientCredentialsWithExpiringToken2 = GetMockClientCredentialsWithToken();
            ICloudProxy        cloudProxy2 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken2);

            Assert.True(cloudProxy2.IsActive);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.Equal(receivedConnectedStatusCount, 1);

            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(receivedConnectedStatusCount, 2);
        }
        public async Task RefreshTokenWithRetryTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            IClientCredentials GetClientCredentialsWithExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(3));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty));
            }

            IClientCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty));
            }

            IAuthenticationMethod authenticationMethod = null;
            IClientProvider       clientProvider       = GetMockDeviceClientProviderWithToken((s, a, t) => authenticationMethod = a);

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var receivedStatuses = new List <CloudConnectionStatus>();

            void ConnectionStatusHandler(string id, CloudConnectionStatus status) => receivedStatuses.Add(status);

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            var cloudConnection = new CloudConnection(ConnectionStatusHandler, transportSettings, messageConverterProvider, clientProvider, Mock.Of <ICloudListener>(), TokenProvider, DeviceScopeIdentitiesCache, TimeSpan.FromMinutes(60), true);

            IClientCredentials clientCredentialsWithExpiringToken1 = GetClientCredentialsWithExpiringToken();
            ICloudProxy        cloudProxy1 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken1);

            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudConnection.CloudProxy.OrDefault());

            Assert.NotNull(authenticationMethod);
            var deviceAuthenticationWithTokenRefresh = authenticationMethod as DeviceAuthenticationWithTokenRefresh;

            Assert.NotNull(deviceAuthenticationWithTokenRefresh);

            // Try to refresh token but get an expiring token
            Task <string> getTokenTask = deviceAuthenticationWithTokenRefresh.GetTokenAsync(iothubHostName);

            Assert.False(getTokenTask.IsCompleted);

            Assert.Equal(1, receivedStatuses.Count);
            Assert.Equal(receivedStatuses[0], CloudConnectionStatus.TokenNearExpiry);

            ICloudProxy cloudProxy2 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithExpiringToken1);

            // Wait for the task to process
            await Task.Delay(TimeSpan.FromSeconds(5));

            Assert.False(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudProxy2);

            // Wait for 20 secs for retry to happen
            await Task.Delay(TimeSpan.FromSeconds(20));

            // Check if retry happened
            Assert.Equal(2, receivedStatuses.Count);
            Assert.Equal(receivedStatuses[1], CloudConnectionStatus.TokenNearExpiry);

            IClientCredentials clientCredentialsWithNonExpiringToken = GetClientCredentialsWithNonExpiringToken();
            ICloudProxy        cloudProxy3 = await cloudConnection.CreateOrUpdateAsync(clientCredentialsWithNonExpiringToken);

            // Wait for the task to complete
            await Task.Delay(TimeSpan.FromSeconds(5));

            Assert.True(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(cloudProxy3, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy3.IsActive);
            Assert.True(cloudProxy1.IsActive);
            Assert.Equal(cloudProxy1, cloudProxy3);
            Assert.Equal(getTokenTask.Result, (clientCredentialsWithNonExpiringToken as ITokenCredentials)?.Token);
        }
        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 async Task TestSendMessages()
        {
            // Arrange
            const string Id                             = "id1";
            var          identity                       = Mock.Of <IIdentity>(i => i.Id == Id);
            var          twinMessageConverter           = new TwinMessageConverter();
            var          twinCollectionMessageConverter = new TwinCollectionMessageConverter();
            var          messageConverterProvider       = new MessageConverterProvider(
                new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Message), new DeviceClientMessageConverter() },
                { typeof(Shared.Twin), twinMessageConverter },
                { typeof(TwinCollection), twinCollectionMessageConverter }
            });

            var edgeHubTokenProvider = new Mock <ITokenProvider>();

            var clientWatcher = new ClientWatcher();

            var clientProvider = new Mock <IClientProvider>();

            clientProvider.Setup(c => c.Create(identity, edgeHubTokenProvider.Object, It.IsAny <ITransportSettings[]>(), Option.None <string>()))
            .Returns(() => new ThrowingClient(clientWatcher, 3));

            var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(Id))
            .ReturnsAsync(
                Option.Some(
                    new ServiceIdentity(
                        Id,
                        "dummy",
                        new List <string>(),
                        new ServiceAuthentication(new SymmetricKeyAuthentication("foo", "bar")),
                        ServiceIdentityStatus.Enabled)));
            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == Id)))
            .ReturnsAsync(Option.Some(Id));

            var edgeHubIdentity = Mock.Of <IIdentity>();

            ConnectionMetadata connectionMetadata = new ConnectionMetadata("edgeProdInfo");
            var metadataStore = new Mock <IMetadataStore>();

            metadataStore.Setup(p => p.GetMetadata(Id))
            .ReturnsAsync(connectionMetadata);

            var identityProvider = new Mock <IIdentityProvider>();

            identityProvider.Setup(i => i.Create(Id)).Returns(identity);

            var credentialsCache = new Mock <ICredentialsCache>();
            var edgeHub          = new Mock <IEdgeHub>();

            var connectionProvider = new CloudConnectionProvider(
                messageConverterProvider,
                1,
                clientProvider.Object,
                Option.None <UpstreamProtocol>(),
                edgeHubTokenProvider.Object,
                deviceScopeIdentitiesCache.Object,
                credentialsCache.Object,
                edgeHubIdentity,
                TimeSpan.FromMinutes(10),
                false,
                TimeSpan.FromMinutes(10),
                false,
                Option.None <IWebProxy>(),
                metadataStore.Object,
                scopeAuthenticationOnly: true,
                trackDeviceState: true,
                true);

            connectionProvider.BindEdgeHub(edgeHub.Object);

            var deviceConnectivityManager = Mock.Of <IDeviceConnectivityManager>();
            var connectionManager         = new ConnectionManager(connectionProvider, credentialsCache.Object, identityProvider.Object, deviceConnectivityManager);
            var messagesToSend            = new List <IMessage>();

            for (int i = 0; i < 10; i++)
            {
                var message = new EdgeMessage.Builder(new byte[i])
                              .SetSystemProperties(
                    new Dictionary <string, string>()
                {
                    [SystemProperties.MessageId] = i.ToString()
                })
                              .Build();
                messagesToSend.Add(message);
            }

            // Act
            Option <ICloudProxy> cloudProxyOption = await connectionManager.GetCloudConnection(Id);

            // Assert
            Assert.True(cloudProxyOption.HasValue);
            ICloudProxy cloudProxy = cloudProxyOption.OrDefault();

            Assert.True(cloudProxy.IsActive);

            // Act
            await RunSendMessages(cloudProxy, messagesToSend);

            // Assert
            Assert.Equal(messagesToSend.Count, clientWatcher.ReceivedMessages.Count());
            Assert.Equal(5, clientWatcher.OpenAsyncCount);
            Assert.True(cloudProxy.IsActive);

            IEnumerable <string> expectedMessageIds = messagesToSend.Select(m => m.SystemProperties[SystemProperties.MessageId]);
            IEnumerable <string> receivedMessageIds = clientWatcher.ReceivedMessages.Select(m => m.MessageId);

            Assert.Equal(expectedMessageIds, receivedMessageIds);
        }
Beispiel #23
0
        public async Task RefreshTokenTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            ITokenCredentials GetClientCredentialsWithExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(3));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, false));
            }

            ITokenCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, false));
            }

            ITokenProvider  tokenProvider  = null;
            IClientProvider clientProvider = GetMockDeviceClientProviderWithToken((s, a, t) => tokenProvider = a);

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var receivedStatus = CloudConnectionStatus.ConnectionEstablished;

            void ConnectionStatusHandler(string id, CloudConnectionStatus status) => receivedStatus = status;

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            ITokenCredentials          clientCredentialsWithExpiringToken1 = GetClientCredentialsWithExpiringToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithExpiringToken1,
                ConnectionStatusHandler,
                transportSettings,
                messageConverterProvider,
                clientProvider,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            Assert.NotNull(tokenProvider);

            Task <string> getTokenTask = tokenProvider.GetTokenAsync(Option.None <TimeSpan>());

            Assert.False(getTokenTask.IsCompleted);

            Assert.Equal(receivedStatus, CloudConnectionStatus.TokenNearExpiry);

            ITokenCredentials clientCredentialsWithExpiringToken2 = GetClientCredentialsWithNonExpiringToken();
            ICloudProxy       cloudProxy2 = await cloudConnection.UpdateTokenAsync(clientCredentialsWithExpiringToken2);

            // Wait for the task to complete
            await Task.Delay(TimeSpan.FromSeconds(10));

            Assert.True(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.True(cloudProxy1.OrDefault().IsActive);
            Assert.Equal(cloudProxy1.OrDefault(), cloudProxy2);
            Assert.Equal(getTokenTask.Result, clientCredentialsWithExpiringToken2.Token);
        }