コード例 #1
0
        public async Task CreateFromEnvironmentTest(
            Option <UpstreamProtocol> upstreamProtocol,
            Option <IWebProxy> webProxy,
            string productInfo)
        {
            // Arrange
            ITransportSettings receivedTransportSettings = null;

            var sdkModuleClient = new Mock <ISdkModuleClient>();

            var sdkModuleClientProvider = new Mock <ISdkModuleClientProvider>();

            sdkModuleClientProvider.Setup(s => s.GetSdkModuleClient(It.IsAny <ITransportSettings>()))
            .Callback <ITransportSettings>(t => receivedTransportSettings = t)
            .ReturnsAsync(sdkModuleClient.Object);

            bool     closeOnIdleTimeout            = false;
            TimeSpan idleTimeout                   = TimeSpan.FromMinutes(5);
            ConnectionStatusChangesHandler handler = (status, reason) => { };

            // Act
            var moduleClientProvider = new ModuleClientProvider(
                sdkModuleClientProvider.Object,
                upstreamProtocol,
                webProxy,
                productInfo,
                closeOnIdleTimeout,
                idleTimeout,
                false);
            IModuleClient moduleClient = await moduleClientProvider.Create(handler);

            // Assert
            Assert.NotNull(moduleClient);
            sdkModuleClientProvider.Verify(s => s.GetSdkModuleClient(It.IsAny <ITransportSettings>()), Times.Once);

            sdkModuleClient.Verify(s => s.SetProductInfo(productInfo), Times.Once);

            Assert.NotNull(receivedTransportSettings);
            UpstreamProtocol up = upstreamProtocol.GetOrElse(UpstreamProtocol.Amqp);

            Assert.Equal(up, moduleClient.UpstreamProtocol);
            switch (up)
            {
            case UpstreamProtocol.Amqp:
            case UpstreamProtocol.AmqpWs:
                var amqpTransportSettings = receivedTransportSettings as AmqpTransportSettings;
                Assert.NotNull(amqpTransportSettings);
                webProxy.ForEach(w => Assert.Equal(w, amqpTransportSettings.Proxy));
                break;

            case UpstreamProtocol.Mqtt:
            case UpstreamProtocol.MqttWs:
                var mqttTransportSettings = receivedTransportSettings as MqttTransportSettings;
                Assert.NotNull(mqttTransportSettings);
                webProxy.ForEach(w => Assert.Equal(w, mqttTransportSettings.Proxy));
                break;
            }

            sdkModuleClient.Verify(s => s.OpenAsync(), Times.Once);
        }
コード例 #2
0
        static ITransportSettings GetTransportSettings(UpstreamProtocol protocol, Option <IWebProxy> proxy, bool useServerHeartbeat)
        {
            switch (protocol)
            {
            case UpstreamProtocol.Amqp:
            {
                var settings = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
                if (useServerHeartbeat)
                {
                    settings.IdleTimeout = HeartbeatTimeout;
                }

                return(settings);
            }

            case UpstreamProtocol.AmqpWs:
            {
                var settings = new AmqpTransportSettings(TransportType.Amqp_WebSocket_Only);
                if (useServerHeartbeat)
                {
                    settings.IdleTimeout = HeartbeatTimeout;
                }

                // Only WebSocket protocols can use an HTTP forward proxy
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            case UpstreamProtocol.Mqtt:
            {
                var settings = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only);
                return(settings);
            }

            case UpstreamProtocol.MqttWs:
            {
                var settings = new MqttTransportSettings(TransportType.Mqtt_WebSocket_Only);

                // Only WebSocket protocols can use an HTTP forward proxy
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            default:
            {
                throw new InvalidEnumArgumentException();
            }
            }
        }
コード例 #3
0
        public async Task CreateForUpstreamProtocolTest(UpstreamProtocol upstreamProtocol, Client.TransportType expectedTransportType)
        {
            // Arrange
            var receivedTransportType = Client.TransportType.Http1;

            Task <Client.ModuleClient> ModuleClientCreator(Client.TransportType transportType)
            {
                receivedTransportType = transportType;
                return(Task.FromResult((Client.ModuleClient)null));
            }

            // Act
            await ModuleClient.CreateDeviceClientForUpstreamProtocol(Option.Some(upstreamProtocol), ModuleClientCreator);

            // Assert
            Assert.Equal(expectedTransportType, receivedTransportType);
        }
コード例 #4
0
ファイル: ModuleClientTest.cs プロジェクト: darobs/iotedge-HA
        public async Task CreateForUpstreamProtocolTest(UpstreamProtocol upstreamProtocol)
        {
            // Arrange
            Option <UpstreamProtocol> receivedProtocol = Option.None <UpstreamProtocol>();

            Task <Client.ModuleClient> ModuleClientCreator(UpstreamProtocol up)
            {
                receivedProtocol = Option.Some(up);
                return(Task.FromResult((Client.ModuleClient)null));
            }

            // Act
            await ModuleClient.CreateDeviceClientForUpstreamProtocol(Option.Some(upstreamProtocol), ModuleClientCreator);

            // Assert
            Assert.Equal(Option.Some(upstreamProtocol), receivedProtocol);
        }
コード例 #5
0
ファイル: ModuleClient.cs プロジェクト: vjrantal/iotedge
        static async Task <Client.ModuleClient> CreateAndOpenDeviceClient(
            UpstreamProtocol upstreamProtocol,
            Option <string> connectionString,
            ConnectionStatusChangesHandler statusChangedHandler,
            Option <IWebProxy> proxy,
            Option <string> productInfo)
        {
            ITransportSettings settings = GetTransportSettings(upstreamProtocol, proxy);

            Events.AttemptingConnectionWithTransport(settings.GetTransportType());
            Client.ModuleClient deviceClient = await connectionString
                                               .Map(cs => Task.FromResult(Client.ModuleClient.CreateFromConnectionString(cs, new[] { settings })))
                                               .GetOrElse(() => Client.ModuleClient.CreateFromEnvironmentAsync(new[] { settings }));

            productInfo.ForEach(p => deviceClient.ProductInfo = p);
            await OpenAsync(statusChangedHandler, deviceClient);

            Events.ConnectedWithTransport(settings.GetTransportType());
            return(deviceClient);
        }
コード例 #6
0
        async void OnConnectionStatusChanged(ConnectionStatus status, ConnectionStatusChangeReason reason)
        {
            try
            {
                UpstreamProtocol protocol =
                    this.ModuleConnection.GetModuleClient().Map(x => x.UpstreamProtocol).GetOrElse(UpstreamProtocol.Amqp);
                Events.ConnectionStatusChanged(status, reason);

                // We want to notify the IoT Edge daemon in the following two cases -
                // 1. The device has been deprovisioned and might have been reprovisioned on another IoT hub.
                // 2. The IoT Hub that the device belongs to is no longer in existence and the device might have been
                // moved to a different IoT hub.
                //
                // When the Amqp or AmqpWs protocol is used, the SDK returns a connection status change reason of
                // Device_Disabled when a device is either disabled or deleted in IoT hub.
                // For the Mqtt and MqttWs protocol however, the SDK returns a Bad_Credential status as it's not
                // possible for IoT hub to distinguish between 'device does not exist', 'device is disabled' and
                // 'device exists but wrong credentials were supplied' cases.
                //
                // When an IoT hub is no longer in existence (i.e., it has been deleted), the SDK returns the
                // connection status change reason of Bad_Credential for all the Amqp and Mqtt protocols.
                if ((reason == ConnectionStatusChangeReason.Device_Disabled &&
                     (protocol == UpstreamProtocol.Amqp || protocol == UpstreamProtocol.AmqpWs)) ||
                    reason == ConnectionStatusChangeReason.Bad_Credential)
                {
                    await this.deviceManager.ReprovisionDeviceAsync();
                }

                if (this.pullOnReconnect && this.initTask.IsCompleted && status == ConnectionStatus.Connected)
                {
                    using (await this.twinLock.LockAsync())
                    {
                        await this.RefreshTwinAsync();
                    }
                }
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                Events.ConnectionStatusChangedHandlingError(ex);
            }
        }
コード例 #7
0
        async Task <ISdkModuleClient> CreateAndOpenSdkModuleClient(UpstreamProtocol upstreamProtocol, ConnectionStatusChangesHandler statusChangedHandler)
        {
            ITransportSettings settings = GetTransportSettings(upstreamProtocol, this.proxy);

            Events.AttemptingConnectionWithTransport(settings.GetTransportType());

            ISdkModuleClient moduleClient = await this.connectionString
                                            .Map(cs => Task.FromResult(this.sdkModuleClientProvider.GetSdkModuleClient(cs, settings)))
                                            .GetOrElse(this.sdkModuleClientProvider.GetSdkModuleClient(settings));

            moduleClient.SetProductInfo(this.productInfo);

            // note: it's important to set the status-changed handler and
            // timeout value *before* we open a connection to the hub
            moduleClient.SetOperationTimeoutInMilliseconds(ModuleClientTimeoutMilliseconds);
            moduleClient.SetConnectionStatusChangesHandler(statusChangedHandler);
            await moduleClient.OpenAsync();

            Events.ConnectedWithTransport(settings.GetTransportType());
            return(moduleClient);
        }
コード例 #8
0
        static ITransportSettings GetTransportSettings(UpstreamProtocol protocol, Option <IWebProxy> proxy)
        {
            switch (protocol)
            {
            case UpstreamProtocol.Amqp:
            {
                var settings = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            case UpstreamProtocol.AmqpWs:
            {
                var settings = new AmqpTransportSettings(TransportType.Amqp_WebSocket_Only);
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            case UpstreamProtocol.Mqtt:
            {
                var settings = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only);
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            case UpstreamProtocol.MqttWs:
            {
                var settings = new MqttTransportSettings(TransportType.Mqtt_WebSocket_Only);
                proxy.ForEach(p => settings.Proxy = p);
                return(settings);
            }

            default:
            {
                throw new InvalidEnumArgumentException();
            }
            }
        }
コード例 #9
0
        async void OnConnectionStatusChanged(ConnectionStatus status, ConnectionStatusChangeReason reason)
        {
            try
            {
                UpstreamProtocol protocol =
                    this.ModuleConnection.GetModuleClient().Map(x => x.UpstreamProtocol).GetOrElse(UpstreamProtocol.Amqp);
                Events.ConnectionStatusChanged(status, reason);

                // Notify the IoT Edge daemon that a device has been deprovisioned and it should check
                // if the device has been provisioned to a different IoT hub instead.
                // When the Amqp or AmqpWs protocol is used, the SDK returns a connection status change reason of
                // Device_Disabled when a device is either disabled or deleted in IoT hub.
                // For the Mqtt and MqttWs protocol however, the SDK returns a Bad_Credential status as it's not
                // possible for IoT hub to distinguish between 'device does not exist', 'device is disabled' and
                // 'device exists but wrong credentials were supplied' cases.
                if ((reason == ConnectionStatusChangeReason.Device_Disabled &&
                     (protocol == UpstreamProtocol.Amqp || protocol == UpstreamProtocol.AmqpWs)) ||
                    (reason == ConnectionStatusChangeReason.Bad_Credential &&
                     (protocol == UpstreamProtocol.Mqtt || protocol == UpstreamProtocol.MqttWs)))
                {
                    await this.deviceManager.ReprovisionDeviceAsync();
                }

                if (this.pullOnReconnect && this.initTask.IsCompleted && status == ConnectionStatus.Connected)
                {
                    using (await this.twinLock.LockAsync())
                    {
                        await this.RefreshTwinAsync();
                    }
                }
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                Events.ConnectionStatusChangedHandlingError(ex);
            }
        }
コード例 #10
0
ファイル: ModuleClient.cs プロジェクト: nlcamp/iotedge
 public ModuleClient(ISdkModuleClient inner, TimeSpan idleTimeout, bool closeOnIdleTimeout, UpstreamProtocol protocol)
 {
     this.inner            = Preconditions.CheckNotNull(inner, nameof(inner));
     this.UpstreamProtocol = protocol;
     this.inactivityTimer  = new ResettableTimer(this.CloseOnInactivity, idleTimeout, Events.Log, closeOnIdleTimeout);
     this.inactivityTimer.Start();
 }
コード例 #11
0
        public async Task CreateFromEnvironmentTest(
            Option <UpstreamProtocol> upstreamProtocol,
            Option <IWebProxy> webProxy,
            string productInfo)
        {
            // Arrange
            ITransportSettings receivedTransportSettings = null;

            var sdkModuleClient     = new Mock <ISdkModuleClient>();
            var runtimeInfoProvider = new Mock <IRuntimeInfoProvider>();
            var systemInfo          = new SystemInfo("foo", "bar", "baz");

            runtimeInfoProvider.Setup(p => p.GetSystemInfo(CancellationToken.None))
            .ReturnsAsync(systemInfo);

            var sdkModuleClientProvider = new Mock <ISdkModuleClientProvider>();

            sdkModuleClientProvider.Setup(s => s.GetSdkModuleClient(It.IsAny <ITransportSettings>()))
            .Callback <ITransportSettings>(t => receivedTransportSettings = t)
            .ReturnsAsync(sdkModuleClient.Object);

            bool     closeOnIdleTimeout            = false;
            TimeSpan idleTimeout                   = TimeSpan.FromMinutes(5);
            ConnectionStatusChangesHandler handler = (status, reason) => { };

            // Act
            var moduleClientProvider = new ModuleClientProvider(
                sdkModuleClientProvider.Object,
                Option.Some(Task.FromResult(runtimeInfoProvider.Object)),
                upstreamProtocol,
                webProxy,
                productInfo,
                closeOnIdleTimeout,
                idleTimeout,
                false);
            IModuleClient moduleClient = await moduleClientProvider.Create(handler);

            // Assert
            Assert.NotNull(moduleClient);
            sdkModuleClientProvider.Verify(s => s.GetSdkModuleClient(It.IsAny <ITransportSettings>()), Times.Once);

            // Write product info explicitly
            sdkModuleClient.Verify(s => s.SetProductInfo($"{productInfo} (kernel_name=foo;cpu_architecture=bar;)"), Times.Once);

            Assert.NotNull(receivedTransportSettings);
            UpstreamProtocol up = upstreamProtocol.GetOrElse(UpstreamProtocol.Amqp);

            Assert.Equal(up, moduleClient.UpstreamProtocol);
            switch (up)
            {
            case UpstreamProtocol.Amqp:
            case UpstreamProtocol.AmqpWs:
                var amqpTransportSettings = receivedTransportSettings as AmqpTransportSettings;
                Assert.NotNull(amqpTransportSettings);

                if (up == UpstreamProtocol.AmqpWs)
                {
                    webProxy.ForEach(w => Assert.Equal(w, amqpTransportSettings.Proxy));
                }

                break;

            case UpstreamProtocol.Mqtt:
            case UpstreamProtocol.MqttWs:
                var mqttTransportSettings = receivedTransportSettings as MqttTransportSettings;
                Assert.NotNull(mqttTransportSettings);

                if (up == UpstreamProtocol.MqttWs)
                {
                    webProxy.ForEach(w => Assert.Equal(w, mqttTransportSettings.Proxy));
                }

                break;
            }

            sdkModuleClient.Verify(s => s.OpenAsync(), Times.Once);
        }