public async Task CanGetSubscriptions()
        {
            // setting up subscriptions for 3 endpoints and 3 different topics
            // component names are not important, so all will be dummy values
            var entries = new[] {
                new Subscription("topic1", "endpoint1", "_"),
                new Subscription("topic1", "endpoint2", "_"),
                new Subscription("topic2", "endpoint3", "_"),
                new Subscription("topic3", "endpoint2", "_"),
                new Subscription("topic3", "endpoint1", "_"),
                new Subscription("topic3", "endpoint3", "_"),
            };

            // arrange
            await Task.WhenAll(
                entries.Select(
                    subscription => this.store.AddSubscription(subscription))
                .ToArray());

            // act
            var topic1 = await this.store.GetByTopic("topic1");
            var topic2 = await this.store.GetByTopic("topic2");
            var topic3 = await this.store.GetByTopic("topic3");
            var endpoint1 = await this.store.GetByEndpoint("endpoint1");
            var endpoint2 = await this.store.GetByEndpoint("endpoint2");
            var endpoint3 = await this.store.GetByEndpoint("endpoint3");
            var all = await this.store.GetAll();

            // assert
            // no need to preserve order
            CollectionAssert.AreEquivalent(entries, all);

            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Topic == "topic1"),
                topic1);
            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Topic == "topic2"),
                topic2);
            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Topic == "topic3"),
                topic3);
            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Endpoint == "endpoint1"),
                endpoint1);
            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Endpoint == "endpoint2"),
                endpoint2);
            CollectionAssert.AreEquivalent(
                entries.Where(e => e.Endpoint == "endpoint3"),
                endpoint3);
        }
        public async Task CanNotifyChanges()
        {
            // arrange
            var subscription1 = new Subscription("t1", "e1", "c1");
            var subscription2 = new Subscription("t2", "e2", "c2");
            var subscription3 = new Subscription("t3", "e3", "c3");

            // will be published, should be received
            var notifications = new [] {
                new Tuple<SubscriptionChange, Subscription>(SubscriptionChange.Add, subscription1),
                new Tuple<SubscriptionChange, Subscription>(SubscriptionChange.Remove, subscription2),
                new Tuple<SubscriptionChange, Subscription>(SubscriptionChange.Add, subscription3),
                new Tuple<SubscriptionChange, Subscription>(SubscriptionChange.Remove, subscription1)
            };
            var pending = notifications.ToList();

            var done = new TaskCompletionSource<bool>();
            var expectedNotificationsReceived = pending.Count;
            int receivedNotifications = 0;

            // subscribe
            await this.broker.SubscribeChangeNotifications(
                (c, s) =>
                {
                    lock (pending)
                    {
                        // remove from pending list after we receive it, 
                        // to ensure we don't process the same notification twice
                        var item = pending.Single(n => n.Item1 == c && n.Item2.Equals(s));
                        pending.Remove(item);

                        if (Interlocked.Increment(ref receivedNotifications) == expectedNotificationsReceived)
                        {
                            done.SetResult(true);
                        }
                    }
                });

            // act
            foreach (var notification in notifications)
            {
                await this.broker.NotifyChange(notification.Item1, notification.Item2);
            }

            // awaits either for timeout or receivers completion
            await Task.WhenAny(done.Task, Task.Delay(TimeSpan.FromSeconds(2))); 

            // assert
            Assert.AreEqual(TaskStatus.RanToCompletion, done.Task.Status);
        }