async Task <Device> SetupDeviceAsync(string iotHubConnectionString)
        {
            IotHubConnectionStringBuilder hubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
            bool deviceNameProvided;

            this.deviceId = ConfigurationManager.AppSettings["End2End.DeviceName"];
            if (!string.IsNullOrEmpty(this.deviceId))
            {
                deviceNameProvided = true;
            }
            else
            {
                deviceNameProvided = false;
                this.deviceId      = Guid.NewGuid().ToString("N");
            }

            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);

            if (!deviceNameProvided)
            {
                await registryManager.AddDeviceAsync(new Device(this.deviceId));

                this.ScheduleCleanup(async() =>
                {
                    await registryManager.RemoveDeviceAsync(this.deviceId);
                    await registryManager.CloseAsync();
                });
            }

            Device device = await registryManager.GetDeviceAsync(this.deviceId);

            this.deviceSas =
                new Client.SharedAccessSignatureBuilder
            {
                Key        = device.Authentication.SymmetricKey.PrimaryKey,
                Target     = $"{hubConnectionStringBuilder.HostName}/devices/{this.deviceId}",
                KeyName    = null,
                TimeToLive = TimeSpan.FromMinutes(20)
            }.ToSignature();

            return(device);
        }
        public async Task DeviceMethodTestAsync()
        {
            await this.EnsureServerInitializedAsync();

            int protocolGatewayPort = this.ProtocolGatewayPort;

            string iotHubConnectionString = ConfigurationManager.AppSettings["IotHubClient.ConnectionString"];
            IotHubConnectionStringBuilder hubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);

            var device = await this.SetupDeviceAsync(iotHubConnectionString);

            await this.CleanupDeviceQueueAsync(hubConnectionStringBuilder.HostName, device);

            var clientScenarios = new ClientScenarios(hubConnectionStringBuilder.HostName, this.deviceId, this.deviceSas);

            var    group      = new MultithreadEventLoopGroup();
            string targetHost = this.tlsCertificate.GetNameInfo(X509NameType.DnsName, false);

            var       readHandler1 = new ReadListeningHandler(CommunicationTimeout);
            Bootstrap bootstrap    = new Bootstrap()
                                     .Group(group)
                                     .Channel <TcpSocketChannel>()
                                     .Option(ChannelOption.TcpNodelay, true)
                                     .Handler(this.ComposeClientChannelInitializer(targetHost, readHandler1));
            IChannel clientChannel = await bootstrap.ConnectAsync(this.ServerAddress, protocolGatewayPort);

            this.ScheduleCleanup(() => clientChannel.CloseAsync());

            // Connect + Subscribe
            await clientScenarios.ConnectAsync(clientChannel, readHandler1).WithTimeout(TestTimeout);

            await clientScenarios.SubscribeAsync(clientChannel, readHandler1).WithTimeout(TestTimeout);

            // Invoke method
            await this.InvokeMethodAsync(iotHubConnectionString, device);

            // Receive and complete
            await this.ReceiveAndCompleteCommandAsync(clientChannel, readHandler1, hubConnectionStringBuilder, device);
        }
        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 InvokeMethodOnModuleTest(ITransportSettings[] transportSettings)
        {
            // Arrange
            string iotHubConnectionString = await SecretsHelper.GetSecretFromConfigKey("iotHubConnStrKey");

            IotHubConnectionStringBuilder connectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
            RegistryManager rm       = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
            ModuleClient    receiver = null;

            string edgeDeviceConnectionString = ConfigHelper.TestConfig[EdgeHubConstants.ConfigKey.IotHubConnectionString];

            Client.IotHubConnectionStringBuilder edgeHubConnectionStringBuilder = Client.IotHubConnectionStringBuilder.Create(edgeDeviceConnectionString);
            string edgeDeviceId = edgeHubConnectionStringBuilder.DeviceId;

            var request  = new TestMethodRequest("Prop1", 10);
            var response = new TestMethodResponse("RespProp1", 20);
            TestMethodRequest receivedRequest = null;

            Task <MethodResponse> MethodHandler(MethodRequest methodRequest, object context)
            {
                receivedRequest = JsonConvert.DeserializeObject <TestMethodRequest>(methodRequest.DataAsJson);
                return(Task.FromResult(
                           new MethodResponse(
                               Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response)),
                               200)));
            }

            string receiverModuleName = "method-module";

            try
            {
                ServiceClient sender = ServiceClient.CreateFromConnectionString(iotHubConnectionString);

                string receiverModuleConnectionString = await RegistryManagerHelper.CreateModuleIfNotExists(rm, connectionStringBuilder.HostName, edgeDeviceId, receiverModuleName);

                receiver = ModuleClient.CreateFromConnectionString(receiverModuleConnectionString, transportSettings);
                await receiver.OpenAsync();

                await receiver.SetMethodHandlerAsync("poke", MethodHandler, null);

                var waitStart   = DateTime.Now;
                var isConnected = false;

                while (!isConnected && (DateTime.Now - waitStart) < TimeSpan.FromSeconds(30))
                {
                    var connectedDevice = await rm.GetModuleAsync(edgeDeviceId, receiverModuleName);

                    isConnected = connectedDevice.ConnectionState == DeviceConnectionState.Connected;
                }

                Assert.True(isConnected);

                // Need longer sleep to ensure receiver is completely initialized
                await Task.Delay(TimeSpan.FromSeconds(10));

                // Act
                CloudToDeviceMethodResult cloudToDeviceMethodResult = await sender.InvokeDeviceMethodAsync(
                    edgeDeviceId,
                    receiverModuleName,
                    new CloudToDeviceMethod("poke").SetPayloadJson(JsonConvert.SerializeObject(request)));

                // Assert
                Assert.NotNull(cloudToDeviceMethodResult);
                Assert.NotNull(receivedRequest);
                Assert.Equal(receivedRequest.RequestProp1, request.RequestProp1);
                Assert.Equal(receivedRequest.RequestProp2, request.RequestProp2);

                Assert.Equal(200, cloudToDeviceMethodResult.Status);
                var receivedResponse = JsonConvert.DeserializeObject <TestMethodResponse>(cloudToDeviceMethodResult.GetPayloadAsJson());
                Assert.NotNull(receivedResponse);
                Assert.Equal(receivedResponse.ResponseProp1, response.ResponseProp1);
                Assert.Equal(receivedResponse.ResponseProp2, response.ResponseProp2);
            }
            finally
            {
                await rm.CloseAsync();

                if (receiver != null)
                {
                    await receiver.CloseAsync();
                }

                try
                {
                    await RegistryManagerHelper.RemoveModule(edgeDeviceId, receiverModuleName, rm);
                }
                catch (Exception)
                {
                    // ignored
                }
            }

            // wait for the connection to be closed on the Edge side
            await Task.Delay(TimeSpan.FromSeconds(10));
        }
        public async Task BasicFunctionalityTest()
        {
            await this.EnsureServerInitializedAsync();

            int protocolGatewayPort = this.ProtocolGatewayPort;

            string iotHubConnectionString = ConfigurationManager.AppSettings["IotHubClient.ConnectionString"];
            IotHubConnectionStringBuilder hubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
            bool deviceNameProvided;
            this.deviceId = ConfigurationManager.AppSettings["End2End.DeviceName"];
            if (!string.IsNullOrEmpty(this.deviceId))
            {
                deviceNameProvided = true;
            }
            else
            {
                deviceNameProvided = false;
                this.deviceId = Guid.NewGuid().ToString("N");
            }

            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
            if (!deviceNameProvided)
            {
                await registryManager.AddDeviceAsync(new Device(this.deviceId));
                this.ScheduleCleanup(async () =>
                {
                    await registryManager.RemoveDeviceAsync(this.deviceId);
                    await registryManager.CloseAsync();
                });
            }

            Device device = await registryManager.GetDeviceAsync(this.deviceId);
            this.deviceSas =
                new SharedAccessSignatureBuilder
                {
                    Key = device.Authentication.SymmetricKey.PrimaryKey,
                    Target = $"{hubConnectionStringBuilder.HostName}/devices/{this.deviceId}",
                    KeyName = null,
                    TimeToLive = TimeSpan.FromMinutes(20)
                }
                    .ToSignature();

            EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(iotHubConnectionString, "messages/events");
            EventHubConsumerGroup ehGroup = eventHubClient.GetDefaultConsumerGroup();

            string[] partitionIds = (await eventHubClient.GetRuntimeInformationAsync()).PartitionIds;
            EventHubReceiver[] receivers = await Task.WhenAll(partitionIds.Select(pid => ehGroup.CreateReceiverAsync(pid.Trim(), DateTime.UtcNow)));

            ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(iotHubConnectionString);

            Stopwatch sw = Stopwatch.StartNew();

            await this.CleanupDeviceQueueAsync(hubConnectionStringBuilder.HostName, device);

            var clientScenarios = new ClientScenarios(hubConnectionStringBuilder.HostName, this.deviceId, this.deviceSas);

            var group = new MultithreadEventLoopGroup();
            string targetHost = this.tlsCertificate.GetNameInfo(X509NameType.DnsName, false);

            var readHandler1 = new ReadListeningHandler(CommunicationTimeout);
            Bootstrap bootstrap = new Bootstrap()
                .Group(group)
                .Channel<TcpSocketChannel>()
                .Option(ChannelOption.TcpNodelay, true)
                .Handler(this.ComposeClientChannelInitializer(targetHost, readHandler1));
            IChannel clientChannel = await bootstrap.ConnectAsync(this.ServerAddress, protocolGatewayPort);
            this.ScheduleCleanup(() => clientChannel.CloseAsync());

            Task testWorkTask = Task.Run(async () =>
            {
                Tuple<EventData, string>[] ehMessages = await CollectEventHubMessagesAsync(receivers, 2);
                Tuple<EventData, string> qos0Event = Assert.Single(ehMessages.Where(x => TelemetryQoS0Content.Equals(x.Item2, StringComparison.Ordinal)));
                Tuple<EventData, string> qos1Event = Assert.Single(ehMessages.Where(x => TelemetryQoS1Content.Equals(x.Item2, StringComparison.Ordinal)));

                string qosPropertyName = ConfigurationManager.AppSettings["QoSPropertyName"];

                var qos0Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS0Content));
                qos0Notification.Properties[qosPropertyName] = "0";
                qos0Notification.Properties["subTopic"] = "tips";
                await serviceClient.SendAsync(this.deviceId, qos0Notification);

                var qos1Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS1Content));
                qos1Notification.Properties["subTopic"] = "firmware-update";
                await serviceClient.SendAsync(this.deviceId, qos1Notification);

                var qos2Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS2Content));
                qos2Notification.Properties[qosPropertyName] = "2";
                qos2Notification.Properties["subTopic"] = "critical-alert";
                await serviceClient.SendAsync(this.deviceId, qos2Notification);

                var qos2Notification2 = new Message(Encoding.UTF8.GetBytes(NotificationQoS2Content2));
                qos2Notification2.Properties[qosPropertyName] = "2";
                await serviceClient.SendAsync(this.deviceId, qos2Notification2);
            });

            await clientScenarios.RunPart1StepsAsync(clientChannel, readHandler1).WithTimeout(TestTimeout);
            await testWorkTask.WithTimeout(TestTimeout);

            this.output.WriteLine($"part 1 completed in {sw.Elapsed}");
            await this.EnsureDeviceQueueLengthAsync(hubConnectionStringBuilder.HostName, device, 1);
            this.output.WriteLine($"part 1 clean completed in {sw.Elapsed}");

            string part2Payload = Guid.NewGuid().ToString("N");
            await serviceClient.SendAsync(this.deviceId, new Message(Encoding.ASCII.GetBytes(part2Payload)));

            var readHandler2 = new ReadListeningHandler(CommunicationTimeout);
            IChannel clientChannelPart2 = await bootstrap
                .Handler(this.ComposeClientChannelInitializer(targetHost, readHandler2))
                .ConnectAsync(this.ServerAddress, protocolGatewayPort);
            this.ScheduleCleanup(async () =>
            {
                await clientChannelPart2.CloseAsync();
                await group.ShutdownGracefullyAsync();
            });

            await clientScenarios.RunPart2StepsAsync(clientChannelPart2, readHandler2).WithTimeout(TestTimeout);

            this.output.WriteLine($"Core test completed in {sw.Elapsed}");

            await this.EnsureDeviceQueueLengthAsync(hubConnectionStringBuilder.HostName, device, 0);
        }
        public async Task BasicFunctionalityTest()
        {
            await this.EnsureServerInitializedAsync();

            int protocolGatewayPort = this.ProtocolGatewayPort;

            string iotHubConnectionString = ConfigurationManager.AppSettings["IoTHubConnectionString"];
            IotHubConnectionStringBuilder hubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
            bool deviceNameProvided;

            this.deviceId = ConfigurationManager.AppSettings["End2End.DeviceName"];
            if (!string.IsNullOrEmpty(this.deviceId))
            {
                deviceNameProvided = true;
            }
            else
            {
                deviceNameProvided = false;
                this.deviceId      = Guid.NewGuid().ToString("N");
            }

            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);

            if (!deviceNameProvided)
            {
                await registryManager.AddDeviceAsync(new Device(this.deviceId));

                this.ScheduleCleanup(async() =>
                {
                    await registryManager.RemoveDeviceAsync(this.deviceId);
                    await registryManager.CloseAsync();
                });
            }

            Device device = await registryManager.GetDeviceAsync(this.deviceId);

            this.deviceSas =
                new SharedAccessSignatureBuilder
            {
                Key        = device.Authentication.SymmetricKey.PrimaryKey,
                Target     = string.Format("{0}/devices/{1}", hubConnectionStringBuilder.HostName, this.deviceId),
                KeyName    = null,
                TimeToLive = TimeSpan.FromMinutes(20)
            }
            .ToSignature();

            EventHubClient        eventHubClient = EventHubClient.CreateFromConnectionString(iotHubConnectionString, "messages/events");
            EventHubConsumerGroup ehGroup        = eventHubClient.GetDefaultConsumerGroup();

            string[]           partitionIds = (await eventHubClient.GetRuntimeInformationAsync()).PartitionIds;
            EventHubReceiver[] receivers    = await Task.WhenAll(partitionIds.Select(pid => ehGroup.CreateReceiverAsync(pid.Trim(), DateTime.UtcNow)));

            ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(iotHubConnectionString);

            Stopwatch sw = Stopwatch.StartNew();

            var testPromise = new TaskCompletionSource();

            var       group      = new MultithreadEventLoopGroup();
            string    targetHost = this.tlsCertificate.GetNameInfo(X509NameType.DnsName, false);
            Bootstrap bootstrap  = new Bootstrap()
                                   .Group(group)
                                   .Channel <TcpSocketChannel>()
                                   .Option(ChannelOption.TcpNodelay, true)
                                   .Handler(new ActionChannelInitializer <ISocketChannel>(ch => ch.Pipeline.AddLast(
                                                                                              TlsHandler.Client(targetHost, null, (sender, certificate, chain, errors) => true),
                                                                                              MqttEncoder.Instance,
                                                                                              new MqttDecoder(false, 256 * 1024),
                                                                                              new TestScenarioRunner(cmf => GetClientScenario(cmf, hubConnectionStringBuilder.HostName, this.deviceId, this.deviceSas), testPromise, CommunicationTimeout, CommunicationTimeout),
                                                                                              new XUnitLoggingHandler(this.output))));
            IChannel clientChannel = await bootstrap.ConnectAsync(this.ServerAddress, protocolGatewayPort);

            this.ScheduleCleanup(async() =>
            {
                await clientChannel.CloseAsync();
                await group.ShutdownGracefullyAsync();
            });

            Task testWorkTask = Task.Run(async() =>
            {
                Tuple <EventData, string>[] ehMessages = await CollectEventHubMessagesAsync(receivers, 2);

                Tuple <EventData, string> qos0Event = Assert.Single(ehMessages.Where(x => TelemetryQoS0Content.Equals(x.Item2, StringComparison.Ordinal)));
                //Assert.Equal((string)qos0Event.Item1.Properties["level"], "verbose");
                //Assert.Equal((string)qos0Event.Item1.Properties["subject"], "n/a");

                Tuple <EventData, string> qos1Event = Assert.Single(ehMessages.Where(x => TelemetryQoS1Content.Equals(x.Item2, StringComparison.Ordinal)));

                string qosPropertyName = ConfigurationManager.AppSettings["QoSPropertyName"];

                var qos0Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS0Content));
                qos0Notification.Properties[qosPropertyName] = "0";
                qos0Notification.Properties["subTopic"]      = "tips";
                await serviceClient.SendAsync(this.deviceId, qos0Notification);

                var qos1Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS1Content));
                qos1Notification.Properties["subTopic"] = "firmware-update";
                await serviceClient.SendAsync(this.deviceId, qos1Notification);

                var qos2Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS2Content));
                qos2Notification.Properties[qosPropertyName] = "2";
                qos2Notification.Properties["subTopic"]      = "critical-alert";
                await serviceClient.SendAsync(this.deviceId, qos2Notification);
            });

            Task timeoutTask = Task.Run(async() =>
            {
                await Task.Delay(TestTimeout);
                throw new TimeoutException("Test has timed out.");
            });

            await TaskExtensions.WhenSome(new[]
            {
                testPromise.Task,
                testWorkTask,
                timeoutTask
            }, 2);

            this.output.WriteLine(string.Format("Core test completed in {0}", sw.Elapsed));

            // making sure that device queue is empty.
            await Task.Delay(TimeSpan.FromSeconds(3));

            DeviceClient deviceClient = DeviceClient.Create(
                hubConnectionStringBuilder.HostName,
                new DeviceAuthenticationWithRegistrySymmetricKey(this.deviceId, device.Authentication.SymmetricKey.PrimaryKey));

            Client.Message message = await deviceClient.ReceiveAsync(TimeSpan.FromSeconds(1));

            Assert.True(message == null, string.Format("Message is not null: {0}", message));
        }
Beispiel #7
0
        public async Task InvokeMethodOnModuleTest(ITransportSettings[] transportSettings)
        {
            // Arrange
            string deviceName             = string.Format("moduleMethodTest-{0}", transportSettings.First().GetTransportType().ToString("g"));
            string iotHubConnectionString = await SecretsHelper.GetSecretFromConfigKey("iotHubConnStrKey");

            IotHubConnectionStringBuilder connectionStringBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
            RegistryManager rm       = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
            ModuleClient    receiver = null;

            var request  = new TestMethodRequest("Prop1", 10);
            var response = new TestMethodResponse("RespProp1", 20);
            TestMethodRequest receivedRequest = null;

            Task <MethodResponse> MethodHandler(MethodRequest methodRequest, object context)
            {
                receivedRequest = JsonConvert.DeserializeObject <TestMethodRequest>(methodRequest.DataAsJson);
                return(Task.FromResult(
                           new MethodResponse(
                               Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response)),
                               200)));
            }

            string receiverModuleName = "method-module";

            (string edgeDeviceId, string deviceConnStr) = await RegistryManagerHelper.CreateDevice(deviceName, iotHubConnectionString, rm, true, false);

            try
            {
                ServiceClient sender = ServiceClient.CreateFromConnectionString(iotHubConnectionString);

                string receiverModuleConnectionString = await RegistryManagerHelper.CreateModuleIfNotExists(rm, connectionStringBuilder.HostName, edgeDeviceId, receiverModuleName);

                receiver = ModuleClient.CreateFromConnectionString(receiverModuleConnectionString, transportSettings);
                await receiver.OpenAsync();

                await receiver.SetMethodHandlerAsync("poke", MethodHandler, null);

                await Task.Delay(TimeSpan.FromSeconds(5));

                // Act
                CloudToDeviceMethodResult cloudToDeviceMethodResult = await sender.InvokeDeviceMethodAsync(
                    edgeDeviceId,
                    receiverModuleName,
                    new CloudToDeviceMethod("poke").SetPayloadJson(JsonConvert.SerializeObject(request)));

                // Assert
                Assert.NotNull(cloudToDeviceMethodResult);
                Assert.NotNull(receivedRequest);
                Assert.Equal(receivedRequest.RequestProp1, request.RequestProp1);
                Assert.Equal(receivedRequest.RequestProp2, request.RequestProp2);

                Assert.Equal(200, cloudToDeviceMethodResult.Status);
                var receivedResponse = JsonConvert.DeserializeObject <TestMethodResponse>(cloudToDeviceMethodResult.GetPayloadAsJson());
                Assert.NotNull(receivedResponse);
                Assert.Equal(receivedResponse.ResponseProp1, response.ResponseProp1);
                Assert.Equal(receivedResponse.ResponseProp2, response.ResponseProp2);
            }
            finally
            {
                if (rm != null)
                {
                    await rm.CloseAsync();
                }

                if (receiver != null)
                {
                    await receiver.CloseAsync();
                }

                try
                {
                    await RegistryManagerHelper.RemoveDevice(edgeDeviceId, rm);
                }
                catch (Exception)
                {
                    // ignored
                }
            }

            // wait for the connection to be closed on the Edge side
            await Task.Delay(TimeSpan.FromSeconds(10));
        }
        async Task ReceiveAndCompleteCommandAsync(IChannel clientChannel, ReadListeningHandler readHandler, IotHubConnectionStringBuilder hubConnectionStringBuilder, Device device)
        {
            var packet = Assert.IsType <PublishPacket>(await readHandler.ReceiveAsync());

            Assert.Equal($"devices/{this.deviceId}/messages/devicebound", packet.TopicName);
            Assert.Equal(MethodContent, Encoding.UTF8.GetString(packet.Payload.ToArray()));

            await clientChannel.WriteAndFlushManyAsync(PubAckPacket.InResponseTo(packet), PubRecPacket.InResponseTo(packet));

            var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync());

            await clientChannel.WriteAndFlushManyAsync(
                PubCompPacket.InResponseTo(pubRelQoS2Packet2),
                DisconnectPacket.Instance);

            await this.EnsureDeviceQueueLengthAsync(hubConnectionStringBuilder.HostName, device, 0);
        }