Пример #1
0
        public async Task ShouldCheckMinimumPerformance()
        {
            var eventIdProvider = new InMemoryEventIdProvider();
            var serializer      = new JsonNetSerializer();
            var eventSerializer = new EventSerializer(serializer);

            var eventCache = new InMemoryEventCache(eventIdProvider, eventSerializer);

            var brokerConfiguration = new BrokerageServiceConfiguration()
            {
                HeartbeatEndpoint       = HeartbeatEndpoint,
                StateOftheWorldEndpoint = StateOfTheWorldEndpoint,
                ToSubscribersEndpoint   = ToSubscribersEndpoint,
                ToPublisherEndpoint     = ToPublishersEndpoint
            };

            var router = new BrokerageService(brokerConfiguration, eventCache, serializer);

            var marketConfiguration = new ProducerConfiguration()
            {
                RouterEndpoint   = ToPublishersEndpoint,
                HearbeatEndpoint = HeartbeatEndpoint
            };

            var market = new Market("FxConnect", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(10));

            await router.Run();

            await market.Run();

            var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject          = string.Empty,
                HeartbeatDelay   = TimeSpan.FromSeconds(10),
                HeartbeatTimeout = TimeSpan.FromSeconds(2)
            };

            var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, eventSerializer);

            await cache.Run();

            //fire a little less than 300 events
            await Task.Delay(3000);

            await Task.WhenAll(new[] { router.Destroy(), market.Destroy(), cache.Destroy() });

            var cacheItems       = cache.GetItems().ToList();
            var cacheItemsEvents = cacheItems.SelectMany(items => items.AppliedEvents).ToList();

            //At least 3/4 events should be processed
            Assert.Greater((double)cacheItemsEvents.Count / (double)market.Prices.Count, 0.75);
        }
Пример #2
0
        public async Task ShouldApplyMultipleEvents()
        {
            using (var publisherSocket = new PublisherSocket())
            {
                publisherSocket.Bind(ToSubscribersEndpoint);

                var streamId = "EUR/USD";

                var createEvent = new Func <IEvent <String, CurrencyPair>, Task>(async(@event) =>
                {
                    var message = _eventSerializer.ToProducerMessage(@event);

                    var eventId = new EventId(@event.EventStreamId, 0, @event.Subject, DateTime.Now.Ticks);

                    publisherSocket.SendMoreFrame(message.Subject)
                    .SendMoreFrame(_serializer.Serialize(eventId))
                    .SendFrame(_serializer.Serialize(message));

                    await Task.Delay(200);
                });

                var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = string.Empty,
                    HeartbeatDelay   = TimeSpan.FromSeconds(1),
                    HeartbeatTimeout = TimeSpan.FromSeconds(1),
                };

                var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

                await cache.Run();

                await Task.Delay(2000);

                var priceEvent = new ChangeCcyPairPrice(streamId, "FxConnect", 0.0, 0.0, 0.0, 0.0);

                await createEvent(priceEvent);

                var changeStateClose = new ChangeCcyPairState(streamId, "FxConnect", CcyPairState.Passive);

                await createEvent(changeStateClose);

                Assert.AreEqual(1, cache.Items.Count());
                Assert.AreEqual(CcyPairState.Passive, cache.Items.First().State);
                Assert.AreEqual(2, cache.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await cache.Destroy();
            }
        }
Пример #3
0
        public async Task ShouldSwitchToStaledState()
        {
            using (var publisherSocket = new PublisherSocket())
            {
                publisherSocket.Bind(ToSubscribersEndpoint);

                var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = string.Empty,
                    HeartbeatDelay   = TimeSpan.FromSeconds(5),
                    HeartbeatTimeout = TimeSpan.FromSeconds(1),
                    IsStaleTimeout   = TimeSpan.FromSeconds(2)
                };

                var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

                await cache.Run();

                await WaitForCachesToCaughtUp(cache);

                Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);
                Assert.AreEqual(true, cache.IsStaled);

                var @event  = new ChangeCcyPairPrice("TEST", "TEST-Market", 0.0, 0.0, 0.0, 0.0);
                var message = _eventSerializer.ToProducerMessage(@event);

                var eventId = new EventId("TEST", 0, "TEST", DateTime.Now.Ticks);

                publisherSocket.SendMoreFrame(message.Subject)
                .SendMoreFrame(_serializer.Serialize(eventId))
                .SendFrame(_serializer.Serialize(message));

                await Task.Delay(200);

                Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);
                Assert.AreEqual(false, cache.IsStaled);

                await Task.Delay(3500);

                Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);
                Assert.AreEqual(true, cache.IsStaled);

                await Task.Delay(2000);

                Assert.AreEqual(true, cache.IsStaled);

                await cache.Destroy();
            }
        }
Пример #4
0
        public async Task ShouldRetrieveStateOfTheWorld()
        {
            var topic = "EUR/USD";


            for (var i = 0; i < 49; i++)
            {
                var next    = Next(topic);
                var message = _eventSerializer.ToProducerMessage(next);
                await _eventCache.AppendToStream(Encoding.UTF8.GetBytes(next.Subject), _serializer.Serialize(message));
            }

            var lastPriceEvent = Next(topic);
            var lastMessage    = _eventSerializer.ToProducerMessage(lastPriceEvent);
            await _eventCache.AppendToStream(Encoding.UTF8.GetBytes(lastPriceEvent.Subject), _serializer.Serialize(lastMessage));

            var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject          = string.Empty,
                HeartbeatDelay   = TimeSpan.FromSeconds(1),
                HeartbeatTimeout = TimeSpan.FromSeconds(1)
            };

            var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

            await cache.Run();

            await WaitForCachesToCaughtUp(cache);

            var ccyPairs = cache.Items
                           .ToList();

            Assert.AreEqual(1, ccyPairs.Count);

            var euroDol = ccyPairs.First();

            Assert.AreEqual(50, euroDol.AppliedEvents.Count());

            Assert.AreEqual(lastPriceEvent.Ask, euroDol.Ask);
            Assert.AreEqual(lastPriceEvent.Bid, euroDol.Bid);
            Assert.AreEqual(lastPriceEvent.Mid, euroDol.Mid);
            Assert.AreEqual(lastPriceEvent.Spread, euroDol.Spread);

            await cache.Destroy();
        }
Пример #5
0
        public async Task ShouldPerformHeartbeat()
        {
            var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject          = string.Empty,
                HeartbeatDelay   = TimeSpan.FromSeconds(1),
                HeartbeatTimeout = TimeSpan.FromSeconds(1)
            };

            var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

            await cache.Run();

            await WaitForCachesToCaughtUp(cache);

            Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);

            await cache.Destroy();
        }
Пример #6
0
        public async Task ShouldSubscribeToAllSubjects()
        {
            using (var publisherSocket = new PublisherSocket())
            {
                publisherSocket.Bind(ToSubscribersEndpoint);

                await Task.Delay(200);

                var createEvent = new Func <string, string, Task>(async(streamId, market) =>
                {
                    var @event  = new ChangeCcyPairPrice(streamId, market, 0.0, 0.0, 0.0, 0.0);
                    var message = _eventSerializer.ToProducerMessage(@event);

                    var eventId = new EventId(streamId, 0, string.IsNullOrEmpty(market) ? streamId : $"{streamId}.{market}", DateTime.Now.Ticks);

                    publisherSocket.SendMoreFrame(message.Subject)
                    .SendMoreFrame(_serializer.Serialize(eventId))
                    .SendFrame(_serializer.Serialize(message));

                    await Task.Delay(200);
                });

                var euroDol = "EUR/USD";
                var harmony = "Harmony";

                var euroGbp   = "EUR/GBP";
                var fxconnect = "FxConnect";

                var cacheConfigurationEuroDol = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = $"{euroDol}",
                    HeartbeatDelay   = TimeSpan.FromSeconds(1),
                    HeartbeatTimeout = TimeSpan.FromSeconds(1),
                };

                var cacheConfigurationAll = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = string.Empty,
                    HeartbeatDelay   = TimeSpan.FromSeconds(1),
                    HeartbeatTimeout = TimeSpan.FromSeconds(1),
                };

                var cacheEuroDol = new DynamicCache <string, CurrencyPair>(cacheConfigurationEuroDol, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);
                var cacheAll     = new DynamicCache <string, CurrencyPair>(cacheConfigurationAll, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

                await cacheEuroDol.Run();

                await cacheAll.Run();

                await WaitForCachesToCaughtUp(cacheEuroDol, cacheAll);

                Assert.AreEqual(DynamicCacheState.Connected, cacheEuroDol.CacheState);
                Assert.AreEqual(DynamicCacheState.Connected, cacheAll.CacheState);

                await createEvent(euroDol, harmony);

                Assert.AreEqual(1, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(1, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(euroDol, fxconnect);

                await Task.Delay(500);

                Assert.AreEqual(2, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(2, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(euroDol, string.Empty);

                Assert.AreEqual(3, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(3, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(euroGbp, string.Empty);

                Assert.AreEqual(3, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(4, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(euroGbp, harmony);

                Assert.AreEqual(3, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(5, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(euroGbp, fxconnect);

                Assert.AreEqual(3, cacheEuroDol.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
                Assert.AreEqual(6, cacheAll.Items.SelectMany(ccy => ccy.AppliedEvents).Count());


                await cacheEuroDol.Destroy();

                await cacheAll.Destroy();
            }
        }
Пример #7
0
        public async Task ShouldHandleNewEventsWhileRebuildingTheCache()
        {
            using (var stateUpdatePublish = new PublisherSocket())
            {
                stateUpdatePublish.Bind(ToSubscribersEndpoint);

                var topic = "EUR/USD";
                var stateOfTheWorldEventCount      = 10000;
                var initialEventCache              = 50;
                var raisedEventDuringCacheBuilding = new List <EventId>();

                for (var i = 0; i < stateOfTheWorldEventCount; i++)
                {
                    var next    = Next(topic);
                    var message = _eventSerializer.ToProducerMessage(next);
                    await _eventCache.AppendToStream(Encoding.UTF8.GetBytes(next.Subject), _serializer.Serialize(message));
                }

                var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = string.Empty,
                    HeartbeatDelay   = TimeSpan.FromSeconds(1),
                    HeartbeatTimeout = TimeSpan.FromSeconds(1)
                };

                var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

                await cache.Run();

                for (var i = 0; i < initialEventCache; i++)
                {
                    var next    = Next(topic);
                    var message = _eventSerializer.ToProducerMessage(next);
                    var payload = _serializer.Serialize(message);
                    var eventId = _eventCache.AppendToStream(Encoding.UTF8.GetBytes(next.Subject), payload).Result;

                    raisedEventDuringCacheBuilding.Add(eventId);

                    stateUpdatePublish.SendMoreFrame(next.Subject)
                    .SendMoreFrame(_serializer.Serialize(eventId))
                    .SendFrame(payload);

                    await Task.Delay(100);
                }

                await WaitForCachesToCaughtUp(cache);

                Assert.IsFalse(cache.IsCaughtingUp);

                var ccyPairs = cache.Items
                               .ToList();

                Assert.AreEqual(1, ccyPairs.Count);



                var euroDol = ccyPairs.First();

                Assert.AreEqual(stateOfTheWorldEventCount + initialEventCache, euroDol.AppliedEvents.Count());

                await cache.Destroy();
            }
        }
Пример #8
0
        public async Task ShouldHandleDisconnectAndCacheRebuild()
        {
            var eventIdProvider = new InMemoryEventIdProvider();
            var serializer      = new JsonNetSerializer();
            var eventSerializer = new EventSerializer(serializer);

            var eventCache = new InMemoryEventCache(eventIdProvider, eventSerializer);

            var brokerConfiguration = new BrokerageServiceConfiguration()
            {
                HeartbeatEndpoint       = HeartbeatEndpoint,
                StateOftheWorldEndpoint = StateOfTheWorldEndpoint,
                ToSubscribersEndpoint   = ToSubscribersEndpoint,
                ToPublisherEndpoint     = ToPublishersEndpoint
            };

            var router = new BrokerageService(brokerConfiguration, eventCache, serializer);

            var marketConfiguration = new ProducerConfiguration()
            {
                RouterEndpoint   = ToPublishersEndpoint,
                HearbeatEndpoint = HeartbeatEndpoint
            };

            var market1 = new Market("FxConnect", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(100));
            var market2 = new Market("Harmony", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(100));

            await router.Run();


            await Task.Delay(1000);

            await market1.Run();

            await market2.Run();

            var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject          = string.Empty,
                HeartbeatDelay   = TimeSpan.FromMilliseconds(500),
                HeartbeatTimeout = TimeSpan.FromSeconds(1)
            };

            var cache      = new DynamicCache <string, CurrencyPair>(cacheConfiguration, eventSerializer);
            var cacheProof = new DynamicCache <string, CurrencyPair>(cacheConfiguration, eventSerializer);

            await cacheProof.Run();

            await cache.Run();

            Assert.AreEqual(DynamicCacheState.NotConnected, cache.CacheState);
            Assert.AreEqual(DynamicCacheState.NotConnected, cacheProof.CacheState);

            await Task.Delay(2000);

            Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);
            Assert.AreEqual(DynamicCacheState.Connected, cacheProof.CacheState);

            await Task.Delay(3000);

            Assert.AreEqual(cache.GetItems()
                            .SelectMany(item => item.AppliedEvents)
                            .Count(),
                            cacheProof.GetItems()
                            .SelectMany(item => item.AppliedEvents)
                            .Count());

            await router.Destroy();

            await Task.Delay(cacheConfiguration.HeartbeatDelay);

            Assert.AreEqual(DynamicCacheState.Disconnected, cache.CacheState);
            Assert.AreEqual(DynamicCacheState.Disconnected, cacheProof.CacheState);

            router = new BrokerageService(brokerConfiguration, eventCache, serializer);

            await router.Run();

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

            Assert.AreEqual(DynamicCacheState.Connected, cache.CacheState);
            Assert.AreEqual(DynamicCacheState.Connected, cacheProof.CacheState);

            await router.Destroy();

            var cacheCCyPair      = cache.GetItems().ToList();
            var cacheProofCcyPair = cacheProof.GetItems().ToList();

            Assert.AreEqual(cacheCCyPair.Count(), cacheProofCcyPair.Count());
            Assert.AreEqual(cacheCCyPair.Count(), cacheProofCcyPair.Count());

            foreach (var ccyPair in cacheCCyPair)
            {
                var proof = cacheProofCcyPair.First(ccy => ccy.Id == ccyPair.Id);

                Assert.AreEqual(ccyPair.Ask, proof.Ask);
                Assert.AreEqual(ccyPair.Bid, proof.Bid);
                Assert.AreEqual(ccyPair.Mid, proof.Mid);
                Assert.AreEqual(ccyPair.Spread, proof.Spread);
            }

            var brokerCacheEvents = (await eventCache.GetStreamBySubject(cacheConfiguration.Subject)).ToList();
            var cacheEvents       = cacheCCyPair.SelectMany(item => item.AppliedEvents).ToList();
            var cacheProofEvents  = cacheProofCcyPair.SelectMany(item => item.AppliedEvents).ToList();


            Assert.AreEqual(cacheEvents.Count(), cacheProofEvents.Count());
            Assert.AreEqual(cacheEvents.Count(), cacheProofEvents.Count());
            Assert.AreEqual(cacheEvents.Count(), cacheProofEvents.Count());

            await Task.WhenAll(new[] { market1.Destroy(), market2.Destroy(), cache.Destroy() });
        }
Пример #9
0
        public async Task ShouldSubscribeToEventFeed()
        {
            var eventIdProvider = new InMemoryEventIdProvider();
            var serializer      = new JsonNetSerializer();
            var eventSerializer = new EventSerializer(serializer);
            var eventCache      = new InMemoryEventCache(eventIdProvider, eventSerializer);

            var brokerConfiguration = new BrokerageServiceConfiguration()
            {
                HeartbeatEndpoint       = HeartbeatEndpoint,
                StateOftheWorldEndpoint = StateOfTheWorldEndpoint,
                ToSubscribersEndpoint   = ToSubscribersEndpoint,
                ToPublisherEndpoint     = ToPublishersEndpoint
            };

            var router = new BrokerageService(brokerConfiguration, eventCache, serializer);

            var marketConfiguration = new ProducerConfiguration()
            {
                RouterEndpoint   = ToPublishersEndpoint,
                HearbeatEndpoint = HeartbeatEndpoint
            };

            var market1 = new Market("FxConnect", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(750));
            var market2 = new Market("Harmony", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(750));

            await router.Run();

            await market1.Run();

            await market2.Run();

            //create an event cache
            await Task.Delay(2000);

            //Assert.Greater(router.Cache.Count(), 0);

            var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint);

            var cache = new DynamicCache <string, CurrencyPair>(cacheConfiguration, eventSerializer);

            var counter = 0;

            var cleanup = cache.OnItemChanged()
                          .Connect()
                          .Subscribe(_ =>
            {
                counter++;
            });

            await cache.Run();

            await Task.Delay(2000);

            // Assert.AreEqual(router.Cache.Count(), counter);
            Assert.AreEqual(cache.GetItems().SelectMany(item => item.AppliedEvents).Count(), counter);

            //fxconnext & harmony
            Assert.AreEqual(2, cache.GetItems()
                            .SelectMany(item => item.AppliedEvents)
                            .Cast <ChangeCcyPairPrice>()
                            .Select(ev => ev.Market)
                            .Distinct()
                            .Count());


            cleanup.Dispose();

            await Task.WhenAll(new[] { router.Destroy(), market1.Destroy(), market2.Destroy(), cache.Destroy() });
        }
Пример #10
0
        public async Task ShouldSubscribeToSubject()
        {
            //todo .NET COre MVC implem
            var eventIdProvider = new InMemoryEventIdProvider();
            var serializer      = new JsonNetSerializer();
            var eventSerializer = new EventSerializer(serializer);

            var eventCache = new InMemoryEventCache(eventIdProvider, eventSerializer);

            var brokerConfiguration = new BrokerageServiceConfiguration()
            {
                HeartbeatEndpoint       = HeartbeatEndpoint,
                StateOftheWorldEndpoint = StateOfTheWorldEndpoint,
                ToSubscribersEndpoint   = ToSubscribersEndpoint,
                ToPublisherEndpoint     = ToPublishersEndpoint
            };

            var router = new BrokerageService(brokerConfiguration, eventCache, serializer);

            var marketConfiguration = new ProducerConfiguration()
            {
                RouterEndpoint   = ToPublishersEndpoint,
                HearbeatEndpoint = HeartbeatEndpoint
            };

            var market1 = new Market("FxConnect", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(750));
            var market2 = new Market("Harmony", marketConfiguration, eventSerializer, TimeSpan.FromMilliseconds(750));

            await router.Run();

            await market1.Run();

            await market2.Run();


            var cacheConfigurationEuroDol = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject = "EUR/USD"
            };

            var cacheConfigurationEuroDolFxConnect = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
            {
                Subject = "EUR/USD.FxConnect"
            };

            var cacheEuroDol          = new DynamicCache <string, CurrencyPair>(cacheConfigurationEuroDol, eventSerializer);
            var cacheEuroDolFxConnect = new DynamicCache <string, CurrencyPair>(cacheConfigurationEuroDolFxConnect, eventSerializer);

            await cacheEuroDol.Run();

            await cacheEuroDolFxConnect.Run();

            //wait for a substential event stream
            await Task.Delay(5000);

            // Assert.Greater(router.Cache.Count(), 1);

            var ccyPairsCacheEuroDol = cacheEuroDol.GetItems()
                                       .SelectMany(item => item.AppliedEvents)
                                       .Select(item => item.Subject)
                                       .Distinct();

            // EUR/USD.FxConnect & EUR/USD.Harmony
            Assert.AreEqual(2, ccyPairsCacheEuroDol.Count());
            Assert.IsTrue(ccyPairsCacheEuroDol.All(subject => subject.EndsWith("FxConnect") || subject.EndsWith("Harmony")));
            Assert.IsTrue(ccyPairsCacheEuroDol.All(subject => subject.StartsWith(cacheConfigurationEuroDol.Subject)));

            var ccyPairsCacheEuroDolFxConnect = cacheEuroDolFxConnect.GetItems()
                                                .SelectMany(item => item.AppliedEvents)
                                                .Select(item => item.Subject)
                                                .Distinct();

            // EUR/USD.FxConnect
            Assert.AreEqual(1, ccyPairsCacheEuroDolFxConnect.Count());
            Assert.AreEqual(cacheConfigurationEuroDolFxConnect.Subject, ccyPairsCacheEuroDolFxConnect.First());


            await Task.WhenAll(new[] { router.Destroy(), market1.Destroy(), market2.Destroy(), cacheEuroDol.Destroy(), cacheEuroDolFxConnect.Destroy() });
        }