static void Main(string[] args) { PublicationConfig publicationConfig = new PublicationConfig(); PublicationGenerator publicationGenerator = new PublicationGenerator(); publicationGenerator.GeneratePublications(); SubscriptionGenerator subscriptionGenerator = new SubscriptionGenerator(); subscriptionGenerator.GenerateSubscriptions(); }
public async Task ConnectionsAndSubscriptionsAreBeingTracked() { // Generating the necessary edgeHub components and the test clients var(connectionManager, connectionHandler, subscriptionChangeHandler, telemetryHandler) = await SetupEdgeHub("something"); var clients = GenerateClients(100, 0.5, 0.5); var rnd = new Random(548196703); var subscriptionTypes = new[] { SubscriptionOrMessage.C2D, SubscriptionOrMessage.DesiredPropertyUpdates, SubscriptionOrMessage.DirectMethod, SubscriptionOrMessage.TwinResponse }; // Start playing the playbook. At every iteration it executes the operations (e.g. subscribe to twin results) that the playbook of a // given client dictates. for (var phase = 0; phase < PlaybookLength; phase++) { // get a randomized order of clients so the messages are more stochastic clients.Shuffle(rnd); // Direct clients can send their subscriptions immediately, however for nested clients we collect them and send a single // update, as in this case edgeHub sends a single event describing all the nested clients. var edgeHubSubscriptions = new List <string>(); foreach (var client in clients) { // This is just to avoid sending the subscriptions always the same order, e.g. always twin first, then c2d subscriptionTypes.Shuffle(rnd); if (client.IsDirect) { var hasChanged = false; var currentSubscriptions = new List <string>(); foreach (var sub in subscriptionTypes) { // we are interested only in changes. Note, that the playbook handles the call with -1 (phase=0), so no error at the next line if (client.Playbook.IsActive(sub, phase) ^ client.Playbook.IsActive(sub, phase - 1)) { hasChanged = true; } if (client.Playbook.IsActive(sub, phase)) { currentSubscriptions.Add(SubscriptionGenerator[sub](true, client.Identity)); } } if (hasChanged) { client.SetNoticed(); var subscriptionEvent = $"[{currentSubscriptions.Select(s => $"\"{s}\"").Join(", ")}]"; await subscriptionChangeHandler.HandleAsync(new MqttPublishInfo($"$edgehub/{client.Identity.Id}/subscriptions", Encoding.UTF8.GetBytes(subscriptionEvent))); } if (client.Playbook.IsActive(SubscriptionOrMessage.Message, phase)) { client.SetNoticed(); await telemetryHandler.HandleAsync(new MqttPublishInfo($"$edgehub/{client.Identity.Id}/messages/events", Encoding.UTF8.GetBytes("hello"))); } } else { foreach (var sub in subscriptionTypes) { // just store all the subscribed topics. Note, that this code does not care if the result is the same as previously, // however resending an event twice should not cause problems for edgeHub if (client.Playbook.IsActive(sub, phase)) { client.SetNoticed(); edgeHubSubscriptions.Add(SubscriptionGenerator[sub](false, client.Identity)); } } if (client.Playbook.IsActive(SubscriptionOrMessage.Message, phase)) { client.SetNoticed(); await telemetryHandler.HandleAsync(new MqttPublishInfo($"$iothub/{client.Identity.Id}/messages/events", Encoding.UTF8.GetBytes("hello"))); } } } var edgeHubsubscriptionEvent = $"[{edgeHubSubscriptions.Select(s => $"\"{s}\"").Join(", ")}]"; await subscriptionChangeHandler.HandleAsync(new MqttPublishInfo("$edgehub/nested_dev/$edgeHub/subscriptions", Encoding.UTF8.GetBytes(edgeHubsubscriptionEvent))); // we do a phase check at around %20 of the steps if (rnd.NextDouble() < 0.2 || phase + 1 == PlaybookLength) { var clientsShouldBeKnown = new HashSet <IIdentity>(clients.Where(c => c.IsNoticed).Select(c => c.Identity)); var started = DateTime.Now; var knownClientsAreOk = false; // Calculating the actual state in a loop, that is because it may take time till the subscription events are get processed do { var clientsKnown = new HashSet <IIdentity>((connectionHandler.AsPrivateAccessible().knownConnections as ConcurrentDictionary <IIdentity, IDeviceListener>).Keys); knownClientsAreOk = clientsKnown.SetEquals(clientsShouldBeKnown); if (!knownClientsAreOk) { await Task.Delay(500); } }while (!knownClientsAreOk && DateTime.Now - started < TimeSpan.FromSeconds(5)); Assert.True(knownClientsAreOk); started = DateTime.Now; var subscriptionsAreOk = false; foreach (var client in clients.Where(c => c.IsNoticed)) { var expectedSubscriptions = default(HashSet <DeviceSubscription>); var actualSubscriptions = default(HashSet <DeviceSubscription>); do { expectedSubscriptions = new HashSet <DeviceSubscription>(); foreach (var sub in subscriptionTypes) { if (client.Playbook.IsActive(sub, phase)) { expectedSubscriptions.Add( sub switch { SubscriptionOrMessage.C2D => DeviceSubscription.C2D, SubscriptionOrMessage.DesiredPropertyUpdates => DeviceSubscription.DesiredPropertyUpdates, SubscriptionOrMessage.DirectMethod => DeviceSubscription.Methods, SubscriptionOrMessage.TwinResponse => DeviceSubscription.TwinResponse, _ => DeviceSubscription.Unknown, }); } } actualSubscriptions = new HashSet <DeviceSubscription>( connectionManager.GetSubscriptions(client.Identity.Id).Expect(() => new Exception("client should be known")) .Where(s => s.Value == true) .Select(s => s.Key)); subscriptionsAreOk = expectedSubscriptions.SetEquals(actualSubscriptions); if (!subscriptionsAreOk) { await Task.Delay(500); } }while (!subscriptionsAreOk && DateTime.Now - started < TimeSpan.FromSeconds(5)); Assert.True(subscriptionsAreOk); }