コード例 #1
0
        public async Task OneTimeSetUp()
        {
            _eventIdProvider = new InMemoryEventIdProvider();
            _serializer      = new JsonNetSerializer();
            _eventSerializer = new EventSerializer(_serializer);
            _eventCache      = new InMemoryEventCache(_eventIdProvider, _eventSerializer);

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

            _broker = new BrokerageService(brokerConfiguration, LoggerForTests <BrokerageService> .Default(), _eventCache, _serializer);

            await _broker.Run();

            JsonConvert.DefaultSettings = () =>
            {
                var settings = new JsonSerializerSettings
                {
                    Formatting       = Formatting.Indented,
                    TypeNameHandling = TypeNameHandling.Objects,
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                };

                return(settings);
            };

            await Task.Delay(1000);
        }
コード例 #2
0
        public IActor GetBrokerageService(IBrokerageServiceConfiguration configuration)
        {
            var router = new BrokerageService(configuration, LoggerForTests <BrokerageService> .Default(), _eventCache, _serializer);

            _actors.Add(router);

            return(router);
        }
コード例 #3
0
        public Market GetMarket(MarketConfiguration configuration)
        {
            var market = new Market(configuration, LoggerForTests <Market> .Default(), _eventSerializer);

            _actors.Add(market);

            return(market);
        }
コード例 #4
0
        public DynamicCache <string, CurrencyPair> GetCache(IDynamicCacheConfiguration configuration)
        {
            var cache = new DynamicCache <string, CurrencyPair>(configuration, LoggerForTests <DynamicCache <string, CurrencyPair> > .Default(), _eventSerializer);

            _actors.Add(cache);

            return(cache);
        }
コード例 #5
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();
        }
コード例 #6
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();
        }
コード例 #7
0
        public async Task ShouldHandleConnectivityErrors()
        {
            var cacheConfiguration = new DynamicCacheConfiguration("tcp://localhost:9090", "tcp://localhost:9090", HeartbeatEndpoint)
            {
                Subject             = string.Empty,
                HeartbeatDelay      = TimeSpan.FromMilliseconds(500),
                HeartbeatTimeout    = TimeSpan.FromMilliseconds(500),
                StateCatchupTimeout = TimeSpan.FromMilliseconds(500)
            };

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

            await cache.Run();

            await Task.Delay(2000);

            Assert.Greater(cache.Errors.Count, 0);

            var error = cache.Errors.First();

            Assert.AreEqual(ActorErrorType.DynamicCacheGetStateOfTheWorldFailure, error.CacheErrorStatus);
            Assert.AreEqual(typeof(UnreachableBrokerException), error.Exception.GetType());
        }
コード例 #8
0
        public async Task ShouldProduceEventsAndConsumeThemViaEventCache()
        {
            var marketConfiguration = new MarketConfiguration("TEST")
            {
                BrokerEndpoint    = ToPublishersEndpoint,
                HeartbeatEndpoint = HeartbeatEndpoint,
                HeartbeatDelay    = TimeSpan.FromSeconds(1),
                HeartbeatTimeout  = TimeSpan.FromSeconds(1)
            };

            var producer = new Market(marketConfiguration, LoggerForTests <Market> .Default(), _eventSerializer);
            await producer.Run();

            await Task.Delay(2000);

            var eventCountOnProducer = producer.Prices.Count;
            var eventsOnEventCache   = (await _eventCache.GetAllStreams())
                                       .Select(msg => _serializer.Deserialize <ChangeCcyPairPrice>(msg.ProducerMessage.MessageBytes))
                                       .ToList();

            Assert.Greater(eventCountOnProducer, 0);
            Assert.Greater(eventsOnEventCache.Count, 0);
            Assert.AreEqual(eventCountOnProducer, eventsOnEventCache.Count);

            Assert.IsTrue(eventsOnEventCache.All(ev => producer.Prices.Any(p => p.Ask == ev.Ask)));

            producer.Publish(new ChangeCcyPairPrice("TEST", "TEST-Market", 0.0, 0.0, 0.0, 0.0));

            await Task.Delay(200);

            var testEvent = await _eventCache.GetStream("TEST");

            Assert.AreEqual(1, testEvent.Count());

            await producer.Destroy();
        }
コード例 #9
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();
            }
        }
コード例 #10
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();
            }
        }
コード例 #11
0
        public async Task ShouldSubscribeToSpecificSubject()
        {
            using (var publisherSocket = new PublisherSocket())
            {
                publisherSocket.Bind(ToSubscribersEndpoint);

                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(500);
                });

                var subscribedToStreamId = "EUR/USD";
                var subscribedToMarket   = "Harmony";

                var NOTsubscribedToStreamId = "EUR/GBP";
                var NOTsubscribedToMarket   = "FxConnect";

                var cacheConfiguration = new DynamicCacheConfiguration(ToSubscribersEndpoint, StateOfTheWorldEndpoint, HeartbeatEndpoint)
                {
                    Subject          = $"{subscribedToStreamId}.{subscribedToMarket}",
                    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(1000);

                await createEvent(NOTsubscribedToStreamId, NOTsubscribedToMarket);

                Assert.AreEqual(0, cache.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(NOTsubscribedToStreamId, subscribedToMarket);

                Assert.AreEqual(0, cache.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(subscribedToStreamId, NOTsubscribedToMarket);

                Assert.AreEqual(0, cache.Items.SelectMany(ccy => ccy.AppliedEvents).Count());

                await createEvent(subscribedToStreamId, subscribedToMarket);

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

                await createEvent(subscribedToStreamId, string.Empty);

                Assert.AreEqual(1, cache.Items.SelectMany(ccy => ccy.AppliedEvents).Count());
            }
        }
コード例 #12
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();
            }
        }
コード例 #13
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();
            }
        }