private void SetUpSnapshotAndMarkets(MatchStatus status = MatchStatus.InRunning)
        {
            _snapshot = new Fixture {Id = "123", MatchStatus = ((int) status).ToString()};
            _snapshot.Tags.Add("Sport", "TestFootball");
            _market1 = new Mock<Market>();
            _market2 = new Mock<Market>();
            _market3 = new Mock<Market>();

            // Initial Active Market
            _market1.SetupAllProperties();
            _market1.Setup(m => m.Selections).Returns(GetSelections(true, false));
            _market1.Object.Id = "One";
            _market1.Object.AddOrUpdateTagValue("name", "One");

            // Initial Inactive (pending) Market

            _market2.SetupAllProperties();
            _market2.Setup(m => m.Selections).Returns(GetSelections(false, false));
            _market2.Object.Id = "Two";
            _market2.Object.AddOrUpdateTagValue("name", "Two");


            // Initial Active Market
            _market3.SetupAllProperties();
            _market3.Setup(m => m.Selections).Returns(GetSelections(true, false));
            _market3.Object.Id = "Three";
            _market3.Object.AddOrUpdateTagValue("name", "Three");

            _snapshot.Markets.Add(_market1.Object);
            _snapshot.Markets.Add(_market2.Object);
            _snapshot.Markets.Add(_market3.Object);
        }
        public void ShouldStartAndStopListening()
        {
            var fixtureSnapshot = new Fixture { Id = "TestId", MatchStatus = "30", Sequence = 1 };
            var plugin = new Mock<IAdapterPlugin>();

            var resource = new Mock<IResourceFacade>();
            var connector = new Mock<IAdapterPlugin>();
            var eventState = new Mock<IEventState>();
            
            var marketFilterObjectStore = new StateManager(_settings.Object,plugin.Object);
            
            resource.Setup(r => r.Sport).Returns("Football");
            resource.Setup(r => r.Content).Returns(new Summary());
            resource.Setup(r => r.StartStreaming()).Raises(r => r.StreamConnected += null, EventArgs.Empty);
            resource.Setup(r => r.StopStreaming()).Raises(r => r.StreamDisconnected += null, EventArgs.Empty);
            resource.Setup(r => r.GetSnapshot()).Returns(FixtureJsonHelper.ToJson(fixtureSnapshot));
            resource.Setup(r => r.Id).Returns("TestId");
            eventState.Setup(e => e.GetCurrentSequence(It.IsAny<string>(), It.IsAny<string>())).Returns(-1);

            var listener = new StreamListener(resource.Object, connector.Object, eventState.Object, marketFilterObjectStore,_settings.Object);
            
            listener.MonitorEvents();
            
            listener.Start();

            listener.Stop();

            listener.ShouldRaise("OnConnected");
            listener.ShouldNotRaise("OnError");
            listener.ShouldRaise("OnStop");
            listener.ShouldNotRaise("OnDisconnected","The disconnection is triggered by the user");

            connector.Verify(c => c.ProcessSnapshot(It.IsAny<Fixture>(), false), Times.Once());
        }
        public IMarketRuleResultIntent Apply(Fixture fixture, IMarketStateCollection oldState,
            IMarketStateCollection newState)
        {            

            var result = new MarketRuleResultIntent();

            if (oldState == null)
                return result;
            
            var deletedMarkets =
                newState.Markets.Select(marketId => newState[marketId])
                    .Where(marketState => marketState.IsDeleted && oldState.HasMarket(marketState.Id) && !oldState[marketState.Id].IsDeleted)
                    .ToList();

            var newDeletedMarketState = deletedMarkets.Select(CreateSuspendedMarket).ToList();

            if (deletedMarkets.Any())
            {
                newDeletedMarketState.ForEach(m =>
                {
                    _logger.DebugFormat("market rule={0} => {1} of fixtureId={2} was deleted from UDAPI - it will be suspended", Name, m, fixture.Id);
                    result.AddMarket(m, new MarketRuleAddIntent(MarketRuleAddIntent.OperationType.CHANGE_SELECTIONS));
                });
            }
            
            return result;

        }
        public IMarketRuleResultIntent Apply(Fixture fixture, IMarketStateCollection oldState, IMarketStateCollection newState)
        {
            MarketRuleResultIntent intent = new MarketRuleResultIntent();

            // only apply delta rule on a full snapshot
            if (fixture.Tags == null || !fixture.Tags.Any() || oldState == null)
                return intent;


            foreach (var mkt in fixture.Markets)
            {
                if (oldState.HasMarket(mkt.Id))
                {
                    IMarketState state = oldState[mkt.Id];
                    
                    // do not apply the delta rule on markets which have 
                    // been put in a forced suspended state
                    if (state.IsForcedSuspended)
                        continue;

                    if (Severity == DeltaRuleSeverity.REMOVE_SELECTIONS)
                    {
                        ApplyDeltaRule_RemovingSelections(fixture, mkt, state, intent);
                    }
                    else if (Severity == DeltaRuleSeverity.REMOVE_MARKETS)
                    {
                        ApplyDeltaRule_RemovingMarkets(fixture, mkt, state, intent);
                    }
                }
            }

            return intent;
        }
        public IMarketRuleResultIntent Apply(Fixture fixture, IMarketStateCollection oldState, IMarketStateCollection newState)
        {
         
            var result = new MarketRuleResultIntent();

            if (!fixture.IsMatchOver || oldState == null)
                return result;

            var markets = fixture.Markets.ToDictionary(m => m.Id);

            // get list of markets which are either no longer in snapshot or are in the snapshot and are not resulted
            // markets which were already priced (activated) should be ignored
            var marketsNotPresentInTheSnapshot = new List<IMarketState>();
            foreach (var mkt in newState.Markets)
            {
                IMarketState mkt_state = newState[mkt];
                if (!mkt_state.IsResulted && (!markets.ContainsKey(mkt_state.Id) || !markets[mkt_state.Id].IsResulted))
                    marketsNotPresentInTheSnapshot.Add(mkt_state);
            }
            
            foreach (var mkt_state in marketsNotPresentInTheSnapshot)
            {
                if (mkt_state.HasBeenActive)
                {
                    _logger.DebugFormat("market rule={0} => marketId={1} of {2} was priced during the fixture lifetime but has NOT been settled on match over.", 
                        Name, mkt_state.Id, fixture);
                    continue;
                }

                if (!mkt_state.HasBeenProcessed)
                {
                    _logger.DebugFormat("market rule={0} => marketId={1} of {2} was never passed to the plugin.", Name, mkt_state.Id, fixture);
                    continue;
                }

                var market = fixture.Markets.FirstOrDefault(m => m.Id == mkt_state.Id);
                if (market == null)
                {
                    _logger.DebugFormat("market rule={0} => marketId={1} of {2} is marked to be voided", Name, mkt_state.Id, fixture);

                    result.AddMarket(CreateSettledMarket(mkt_state), new MarketRuleAddIntent(MarketRuleAddIntent.OperationType.SETTLE_SELECTIONS));
                }
                else
                {
                    _logger.DebugFormat("market rule={0} => marketId={1} of {2} that was in the snapshot but wasn't resulted is marked to be voided", 
                        Name, market.Id, fixture);

                    Action<Market> action = x => x.Selections.ForEach(s => s.Status = SelectionStatus.Void);
                    MarketRuleEditIntent edit = new MarketRuleEditIntent(action, MarketRuleEditIntent.OperationType.CHANGE_SELECTIONS);
                    result.EditMarket(market, edit);
                }

            }

            return result;
        }
        public void CreateFixture()
        {
            _fixture = new Fixture()
            {
                Id = "TestFixtureId",
                FixtureName = "Testing fixture gamestate"
            };

            _fixture.GameState.Clear();
        }
        /// <summary>
        /// 
        ///     Remove markets from snapshot/update when: 
        ///     current market state is inactive AND the previous state was inactive too (with no change in status or name)
        /// 
        ///     NB: If there is a change in market's name or status then will not be removed
        /// 
        /// </summary>
        public IMarketRuleResultIntent Apply(Fixture fixture, IMarketStateCollection oldState, IMarketStateCollection newState)
        {
            var result = new MarketRuleResultIntent();

            var inactiveMarkets = fixture.Markets.Where(
                m => (oldState != null && oldState.HasMarket(m.Id) && oldState[m.Id].IsEqualTo(newState[m.Id]))
                        && (!m.IsActive && !oldState[m.Id].IsActive));

            foreach (var market in inactiveMarkets.ToList())
            {
                result.MarkAsRemovable(market);
                _Logger.DebugFormat("market rule={0} => {1} of fixtureId={2} is marked as removable", Name, market, fixture.Id);
            }

            return result;
        }
        public void Update(Fixture fixture, bool fullSnapshot)
        {
            FixtureSequence = fixture.Sequence;
            FixtureName = fixture.FixtureName;
            FixtureStatus = (MatchStatus) Enum.Parse(typeof (MatchStatus), fixture.MatchStatus);

            if (fullSnapshot)
            {
                if(fixture.Tags.ContainsKey("Sport"))
                    Sport = fixture.Tags["Sport"].ToString();

                var marketsLookUp = fixture.Markets.ToDictionary(m => m.Id);

                //if market doesn't exist in the snapshot the definition must have been changed
                Markets.Where(marketId => !marketsLookUp.ContainsKey(marketId)).ForEach(marketId => this[marketId].IsDeleted = true);
            }

            _processed = new Dictionary<string, IUpdatableMarketState>();

            foreach (var market in fixture.Markets)
            {
                IUpdatableMarketState mkt_state = null;
                if (HasMarket(market.Id))
                {
                    mkt_state = this[market.Id] as IUpdatableMarketState;
                    mkt_state.Update(market, fullSnapshot);
                }
                else
                {
                    mkt_state = new MarketState(market, fullSnapshot);
                    ((MarketState)mkt_state).Index = _States.Count;
                    this[market.Id] = mkt_state;
                }

                _processed.Add(market.Id, mkt_state);
            }
        }
 public void ProcessFixtureDeletion(Fixture fixture)
 {
     _Logger.InfoFormat("Request for delete {0} received", fixture);
 }
 public void ProcessStreamUpdate(Fixture fixture, bool hasEpochChanged = false)
 {
     _Logger.InfoFormat("Received delta snapshot for {0} (hasEpochChanged={1}), written to queue at: {2}", fixture, hasEpochChanged,fixture.TimeStamp);
 }
        private static Fixture GetFixtureWithSuspendedMarkets(IMarketStateCollection state, out IEnumerable<IMarketState> includedMarketStates)
        {
            includedMarketStates = new List<IMarketState>();

            var fixture = new Fixture
            {
                Id = state.FixtureId,
                MatchStatus = ((int) state.FixtureStatus).ToString(),
                Sequence = state.FixtureSequence
            };

            foreach (var mkt_id in state.Markets)
            {
                ((List<IMarketState>)includedMarketStates).Add(state[mkt_id]);
                fixture.Markets.Add(CreateMarket(state[mkt_id]));
            }

            return fixture;
        }
        private void BuildDefaultStrategies()
        {
            DoNothingStrategy = x => { };

            SuspendFixtureStrategy = x => _plugin.Suspend(x.FixtureId);

            SuspendFixtureIfInPlayStrategy = x => { if (x.FixtureStatus == MatchStatus.InRunning) _plugin.Suspend(x.FixtureId); };

            SuspendAllMarketsStrategy = x =>
                {
                    IEnumerable<IMarketState> includedMarketStates;
                    var fixture = GetFixtureWithSuspendedMarkets(x, out includedMarketStates);

                    _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0}", x.FixtureId);

                    _plugin.ProcessStreamUpdate(fixture);

                    _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                    ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
                };

            SuspendAllMarketsAndSetMatchStatusDeleted = x =>
            {
                IEnumerable<IMarketState> includedMarketStates;
                
                var fixture = GetFixtureWithSuspendedMarkets(x, out includedMarketStates);
                fixture.MatchStatus = ((int)MatchStatus.Deleted).ToString();

                _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0} and setting its MatchStatus as deleted", x.FixtureId);
                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
            };

            SuspendFixtureAndSetMatchStatusDeleted = x =>
            {
                var fixture = new Fixture
                {
                    Id = x.FixtureId,
                    MatchStatus = ((int)MatchStatus.Deleted).ToString(),
                    Sequence = x.FixtureSequence
                };

                
                _logger.DebugFormat("Sending suspension command through the plugin for fixtureId={0} and setting its MatchStatus as deleted", x.FixtureId);
                _plugin.ProcessStreamUpdate(fixture);

                _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
            };

            SuspendInPlayMarketsStrategy = x =>
                {
                    List<IMarketState> includedMarketStates = new List<IMarketState>();

                    var fixture = new Fixture
                    {
                        Id = x.FixtureId,
                        MatchStatus = ((int)x.FixtureStatus).ToString(),
                        Sequence = x.FixtureSequence
                    };

                    foreach (var mkt_id in x.Markets)
                    {

                        // we take a conservative approach here.
                        // If, for any reason, the traded_in_play
                        // is not present, we assume it is. Better
                        // to suspend more markets, than less
                        IMarketState state = x[mkt_id];
                        if (state.HasTag("traded_in_play") && 
                            string.Equals(state.GetTagValue("traded_in_play"), "false", StringComparison.OrdinalIgnoreCase))
                        {
                            _logger.DebugFormat("marketId={0} of fixtureId={1} will not be suspended as it is not traded in play", mkt_id, fixture.Id);
                            continue;
                        }

                        if (!state.HasBeenActive)
                        {
                            _logger.DebugFormat("marketId={0} of fixtureId={1} will not be suspended as it has not been active before", mkt_id, fixture.Id);
                            continue;
                        }
                        
                        includedMarketStates.Add(state);
                        fixture.Markets.Add(CreateMarket(x[mkt_id]));
                    }


                    _logger.DebugFormat("Sending suspension command through the plugin for in-play markets of fixtureId={0}", x.FixtureId);
                    _plugin.ProcessStreamUpdate(fixture);

                    _logger.InfoFormat("Marking markets for fixtureId={0} as suspended", x.FixtureId);
                    ((IUpdatableMarketStateCollection)x).OnMarketsForcedSuspension(includedMarketStates);
                };
        }
        public void SerializeModelTest()
        {

            Fixture fixture = new Fixture
            {
                FixtureName = "TEST-NAME",
                Epoch = 10,
                LastEpochChangeReason = new[] { 10, 20 },
                Id = "TEST-ID",
                StartTime = new DateTime(2000, 01, 01),
                Sequence = 12,
                MatchStatus = "40"
            };
            fixture.Tags.Add("TEST-TAG-1", "1");
            fixture.Tags.Add("TEST-TAG-2", 2);
            fixture.GameState.Add("TEST-STATE-1", 1);
            fixture.GameState.Add("TEST-STATE-2", "2");

            Participant p1 = new Participant { Id = 1, Name = "P1" };
            p1.Tags.Add("TEST-TAG-1", "1");
            p1.Tags.Add("TEST-TAG-2", 2);

            Participant p2 = new Participant { Id = 2, Name = "P2" };

            fixture.Participants.Add(p1);
            fixture.Participants.Add(p2);

            Market mkt1 = new Market { Id = "MKT1" };
            mkt1.AddOrUpdateTagValue("name", "MKT1");

            Selection seln1 = new Selection
            {
                Id = "SELN1",
                Price = 2.0,
                Status = SelectionStatus.Active,
                Tradable = false
            };
            seln1.AddOrUpdateTagValue("name", "seln1");
            seln1.AddOrUpdateTagValue("displayed", "true");

            Selection seln2 = new Selection
            {
                Id = "SELN2",
                Price = 3.0,
                Status = SelectionStatus.Pending,
                Tradable = true
            };
            seln2.AddOrUpdateTagValue("name", "seln2");
            seln2.AddOrUpdateTagValue("displayed", "false");

            mkt1.Selections.Add(seln1);
            mkt1.Selections.Add(seln2);

            RollingMarket mkt2 = new RollingMarket { Id = "RMKT2", Line = 2.0 };
            mkt2.AddOrUpdateTagValue("name", "RMKT2");

            RollingSelection seln3 = new RollingSelection
            {
                Id = "SELN3",
                Price = 7.0,
                Status = SelectionStatus.Pending,
                Tradable = true,
                Line = 21
            };

            ((Market)mkt2).Selections.Add(seln3);
            Market test2 = mkt2;
            test2.Selections.Count.Should().Be(1);
            (test2.Selections.FirstOrDefault() is RollingSelection).Should().BeTrue();

            Market mkt3 = new RollingMarket();
            mkt3.Id = "RMKT3";
            mkt3.AddOrUpdateTagValue("name", "RMKT3");

            fixture.Markets.Add(mkt1);
            fixture.Markets.Add(mkt2);
            fixture.Markets.Add(mkt3);

            fixture.RollingMarkets.FirstOrDefault(x => x.Id == "MKT1").Should().BeNull();
            fixture.RollingMarkets.FirstOrDefault(x => x.Id == "RMKT2").Should().NotBeNull();
            fixture.RollingMarkets.FirstOrDefault(x => x.Id == "RMKT3").Should().NotBeNull();

            fixture.StandardMarkets.FirstOrDefault(x => x.Id == "MKT1").Should().NotBeNull();
            fixture.StandardMarkets.FirstOrDefault(x => x.Id == "RMKT2").Should().BeNull();
            fixture.StandardMarkets.FirstOrDefault(x => x.Id == "RMKT3").Should().BeNull();

            string value = FixtureJsonHelper.ToJson(fixture);
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(value)))
            {

                stream.Position = 0;
                string value2 = Encoding.UTF8.GetString(stream.ToArray());

                value.Should().BeEquivalentTo(value2);

                fixture = FixtureJsonHelper.GetFromJson(value2);
            }

            fixture.RollingMarkets.Count().Should().Be(2);
            fixture.StandardMarkets.Count().Should().Be(1);
            fixture.Markets.Count().Should().Be(3);
            fixture.Tags.Count.Should().Be(2);
            fixture.GameState.Count().Should().Be(2);
            fixture.Participants.Count().Should().Be(2);

            fixture.Markets.FirstOrDefault(x => x.Id == "MKT1").Selections.Count.Should().Be(2);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT2").Selections.Count.Should().Be(1);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT3").Selections.Count.Should().Be(0);

            BinaryStoreProvider<Fixture> provider = new BinaryStoreProvider<Fixture>(".", "test-{0}.dat");

            provider.SetObject("TEST", fixture);

            fixture = provider.GetObject("TEST");

            fixture.RollingMarkets.Count().Should().Be(2);
            fixture.StandardMarkets.Count().Should().Be(1);
            fixture.Markets.Count().Should().Be(3);
            fixture.Tags.Count.Should().Be(2);
            fixture.GameState.Count().Should().Be(2);
            fixture.Participants.Count().Should().Be(2);

            fixture.Markets.FirstOrDefault(x => x.Id == "MKT1").Selections.Count.Should().Be(2);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT2").Selections.Count.Should().Be(1);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT3").Selections.Count.Should().Be(0);

            fixture = value.FromJson<Fixture>();

            fixture.RollingMarkets.Count().Should().Be(2);
            fixture.StandardMarkets.Count().Should().Be(1);
            fixture.Markets.Count().Should().Be(3);
            fixture.Tags.Count.Should().Be(2);
            fixture.GameState.Count().Should().Be(2);
            fixture.Participants.Count().Should().Be(2);

            fixture.Markets.FirstOrDefault(x => x.Id == "MKT1").Selections.Count.Should().Be(2);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT2").Selections.Count.Should().Be(1);
            fixture.Markets.FirstOrDefault(x => x.Id == "RMKT3").Selections.Count.Should().Be(0);
        }
        public void GetFixtureOverviewAfterStreamUpdatesTest()
        {
            var fixtureOneId = "fixtureOne";

            _resource.Setup(x => x.Id).Returns(fixtureOneId);
            _resource.Setup(x => x.Content).Returns(new Summary());
            _resource.Setup(x => x.MatchStatus).Returns(MatchStatus.InRunning);
            _resource.Setup(x => x.GetSnapshot()).Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId)));
            _resource.Setup(x => x.StartStreaming()).Raises(r => r.StreamConnected += null, EventArgs.Empty);

            var deltas = new List<IFixtureOverviewDelta>();
            var subscriber = _supervisor.GetFixtureOverviewStream().ObserveOn(NewThreadScheduler.Default).Subscribe(deltas.Add);

            _supervisor.CreateStreamListener(_resource.Object, _plugin.Object);

            var fixtureOverviews = _supervisor.GetFixtures();
            fixtureOverviews.Should().NotBeNullOrEmpty();
            fixtureOverviews.Should().Contain(f => f.Id == fixtureOneId);

            _supervisor.StartStreaming(fixtureOneId);

            var epoch = 1;

            var streamUpdate = new Fixture
            {
                Id = fixtureOneId,
                Sequence = 2,
                Epoch = epoch,
                MatchStatus = ((int)MatchStatus.InRunning).ToString()
            };

            SendStreamUpdate(streamUpdate);

            Thread.Sleep(1000);

            deltas.Should().NotBeEmpty();
            var sequenceTwoDeltas = deltas.Where(d => d.FeedUpdate != null && d.FeedUpdate.Sequence == 2).ToList();
            sequenceTwoDeltas.Should().NotBeNull();
            sequenceTwoDeltas.Count.Should().Be(2);

            //FeedUpdate with IsProcessed in both states exists
            sequenceTwoDeltas.Any(d => d.FeedUpdate.IsProcessed).Should().BeTrue();
            sequenceTwoDeltas.Any(d => !d.FeedUpdate.IsProcessed).Should().BeTrue();

            var fixtureOverview = _supervisor.GetFixtureOverview(fixtureOneId);
            fixtureOverview.GetFeedAudit().Count(f => f.Sequence == 2).Should().Be(1);

            subscriber.Dispose();
        }
        private void ProcessSnapshot(Fixture snapshot, bool isFullSnapshot, bool hasEpochChanged, bool setErrorState = true, bool skipMarketRules = false)
        {
            var logString = isFullSnapshot ? "snapshot" : "stream update";

            if (snapshot == null || (snapshot != null && string.IsNullOrWhiteSpace(snapshot.Id)))
                throw new ArgumentException(string.Format("Received empty {0} for {1}", logString, _resource));

            _logger.InfoFormat("Processing {0} for {1}", logString, snapshot);

            Stopwatch timer = new Stopwatch();
            timer.Start();

            try
            {
                if (isFullSnapshot && !VerifySequenceOnSnapshot(snapshot)) return;
                if (IsDisposing || IsStopping)
                {
                    _logger.WarnFormat("Shutting down stream listener, the snapshot {0} won't be processed.", snapshot);
                    return;
                }

                bool is_inplay = string.Equals(snapshot.MatchStatus, ((int)MatchStatus.InRunning).ToString(), StringComparison.OrdinalIgnoreCase);
                IsInPlay = is_inplay;
               
                if (!skipMarketRules)
                {
                    _marketsRuleManager.ApplyRules(snapshot);
                    
                    snapshot.IsModified = true;
                }
                else
                {
                    _marketsRuleManager.ApplyRules(snapshot,isRemovalDisabled : true);   
                }

                if (isFullSnapshot)
                    _platformConnector.ProcessSnapshot(snapshot, hasEpochChanged);
                else
                    _platformConnector.ProcessStreamUpdate(snapshot, hasEpochChanged);

                UpdateState(snapshot, isFullSnapshot);

                IsErrored = false;
            }
            catch (FixtureIgnoredException ex)
            {
                _logger.WarnFormat("{0} received a FixtureIgnoredException", _resource);
                IsIgnored = true;

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);
                RaiseEvent(OnError, ex);
            }
            catch (AggregateException ex)
            {
                _marketsRuleManager.RollbackChanges();

                int total = ex.InnerExceptions.Count;
                int count = 0; 
                foreach (var e in ex.InnerExceptions)
                {
                    _logger.Error(string.Format("Error processing {0} for {1} ({2}/{3})", logString, snapshot, ++count, total), e);
                }

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);
                RaiseEvent(OnError, ex);

                if (setErrorState)
                    SetErrorState();
                else
                    throw;
            }
            catch (Exception ex)
            {
                _marketsRuleManager.RollbackChanges();

                _Stats.IncrementValue(AdapterCoreKeys.ERROR_COUNTER);

                _logger.Error(string.Format("Error processing {0} {1}", logString, snapshot), ex);

                RaiseEvent(OnError, ex);

                if (setErrorState)
                    SetErrorState();
                else
                    throw;
            }
            finally
            {
                timer.Stop();
                if (isFullSnapshot)
                    _Stats.AddValue(AdapterCoreKeys.SNAPSHOT_PROCESSING_TIME, timer.ElapsedMilliseconds.ToString());
                else
                    _Stats.AddValue(AdapterCoreKeys.UPDATE_PROCESSING_TIME, timer.ElapsedMilliseconds.ToString());
            }

            _logger.InfoFormat("Finished processing {0} for {1}", logString, snapshot);
        }
        public IMarketRuleResultIntent Apply(Fixture fixture, IMarketStateCollection oldState, IMarketStateCollection newState)
        {
            var result = new MarketRuleResultIntent();

            if (_includedSports.Contains(newState.Sport.ToLower()))
            {
                
                foreach (var mkt in fixture.Markets)
                {
                    string type = string.Format("{0}.{1}", newState.Sport, mkt.Type).ToLower();

                    if (_excludedMarketTypes.Contains(type))
                    {
                        _Logger.DebugFormat("market rule={0} => {1} of {2} is excluded from rule due its type={3}",
                            Name, mkt, fixture, mkt.Type);

                        continue;
                    }

                    var oldMarketState = oldState != null ? oldState[mkt.Id] : null;
                    var newMarketState = newState[mkt.Id];

                    if (oldMarketState == null)
                    {
                        //must be a snapshot then
                        if (newMarketState.IsActive)
                        {
                            //create market
                            _Logger.DebugFormat("market rule={0} => {1} of {2} is created", Name, mkt, fixture);
                            result.MarkAsUnRemovable(mkt);
                        }
                        else
                        {
                            //dont create market
                            _Logger.DebugFormat("market rule={0} => {1} of {2} is not created", Name, mkt, fixture);
                            result.MarkAsRemovable(mkt);
                        }
                    }
                    else
                    {
                        if (oldMarketState.HasBeenActive) continue;
                        if (newMarketState.IsActive)
                        {
                            //create
                            Action<Market> editMarketAction = (m =>
                            {
                                if (newMarketState.TagsCount == 0)
                                    return;

                                foreach (var tagKey in newMarketState.TagKeys)
                                {
                                    m.AddOrUpdateTagValue(tagKey, newMarketState.GetTagValue(tagKey));
                                }

                                foreach (var sel in m.Selections)
                                {
                                    var selState = newMarketState[sel.Id];
                                    foreach (var tagKey in selState.TagKeys)
                                    {
                                        sel.AddOrUpdateTagValue(tagKey, selState.GetTagValue(tagKey));
                                    }
                                }
                            });

                            var mri = new MarketRuleEditIntent(editMarketAction, MarketRuleEditIntent.OperationType.CHANGE_DATA);
                            _Logger.DebugFormat("market rule={0} => {1} of {2} is created", Name, mkt, fixture);
                            result.EditMarket(mkt, mri);
                        }
                        else
                        {
                            //dont create market
                            _Logger.DebugFormat("market rule={0} => {1} of {2} is not created", Name, mkt, fixture);
                            result.MarkAsRemovable(mkt);
                        }
                    }
                }                
            }

            return result;
        }
        public void SelectionResulStateTest()
        {
            Market mkt = new Market("123");

            var seln = new Selection()
            {
                Id = "A1",
                Result = new Result()
                {
                    StakeParticipants = 1,
                    StakePlaces = 2,
                    WinParticipants = 3,
                    WinPlaces = 4
                }
            };

            mkt.Selections.Add(seln);

            Fixture fxt = new Fixture()
            {
                Id = "FXT",
                FixtureName = "TestSelectionResultTest",
                MatchStatus = "40",
            };

            fxt.Markets.Add(mkt);

            MarketStateCollection collection = new MarketStateCollection("FXT");
            collection.Update(fxt, true);

            var model = collection["123"]["A1"].Result as SelectionResultState;
            model.Should().NotBeNull();

            model.IsEquivalentTo(seln.Result).Should().BeTrue();

            var clone = model.Clone();
            model.IsEqualTo(clone).Should().BeTrue();

            seln.Result.WinParticipants = 2;
            model.IsEquivalentTo(seln.Result).Should().BeFalse();

        }
        public void GetDeltaErrorsTest()
        {
            var fixtureOneId = "fixtureOne";

            var resourceOne = new Mock<IResourceFacade>();

            resourceOne.Setup(x => x.Id).Returns(fixtureOneId);
            resourceOne.Setup(x => x.Content).Returns(new Summary());
            resourceOne.Setup(x => x.MatchStatus).Returns(MatchStatus.InRunning);
            resourceOne.Setup(x => x.Sport).Returns("Football");
            resourceOne.SetupSequence(x => x.GetSnapshot())
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId)))
                .Returns(String.Empty)
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId, 10, 3)));

            resourceOne.Setup(x => x.StartStreaming()).Raises(r => r.StreamConnected += null, EventArgs.Empty);

            _supervisor.CreateStreamListener(resourceOne.Object, _plugin.Object);

            var fixtureOverviews = _supervisor.GetFixtures();
            fixtureOverviews.Should().NotBeNullOrEmpty();
            fixtureOverviews.Should().Contain(f => f.Id == fixtureOneId);

            _supervisor.StartStreaming(fixtureOneId);

            var streamUpdate = new Fixture
            {
                Id = fixtureOneId,
                Sequence = 2,
                //Epoch increased
                Epoch = 10,
                MatchStatus = ((int)MatchStatus.InRunning).ToString()
            };

            var deltas = new List<IFixtureOverviewDelta>();

            using (var subscriber = _supervisor.GetFixtureOverviewStream().Subscribe(deltas.Add))
            {
                //in order to generate error the resource is setup to return empty snapshot
                //the snapshot should be taken because epoch is changed
                SendStreamUpdate(streamUpdate);
                
                deltas.Should().NotBeEmpty();
                deltas.FirstOrDefault(d => d.LastError != null).Should().NotBeNull();

                //error was resolved with a further snapshot
                deltas.FirstOrDefault(d => d.LastError != null && !d.LastError.IsErrored).Should().NotBeNull();
            }
        }
        public void GivenAFixtureWithTheFollowingMarkets(Table table)
        {
            ScenarioContext.Current.Clear();

            Fixture fixture = new Fixture { Id = "Test", MatchStatus = "40" };
            ScenarioContext.Current.Add("FIXTURE", fixture);

            foreach (var row in table.Rows)
            {
                Market mkt = new Market {Id = row["Market"]};
                mkt.AddOrUpdateTagValue("name", row["Name"]);

                fixture.Markets.Add(mkt);

                if (table.ContainsColumn("Selections"))
                {
                    int seln_count = Convert.ToInt32(row["Selections"]);
                    for (int i = 0; i < seln_count; i++)
                    {
                        Selection seln = new Selection { Name = row["Name"] + (i + 1) };
                        seln.Id = seln.Name;
                        mkt.Selections.Add(seln);
                    }
                }
            }
        }
        public void CheckUpdatesAreTrackedTest()
        {
            var fixtureOneId = "fixtureOne";

            var resourceOne = new Mock<IResourceFacade>();

            resourceOne.Setup(x => x.Id).Returns(fixtureOneId);
            resourceOne.Setup(x => x.Content).Returns(new Summary());
            resourceOne.Setup(x => x.MatchStatus).Returns(MatchStatus.InRunning);
            resourceOne.SetupSequence(x => x.GetSnapshot())
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId)))
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId, 10, 3)));

            resourceOne.Setup(x => x.StartStreaming()).Raises(r => r.StreamConnected += null, EventArgs.Empty);

            _supervisor.CreateStreamListener(resourceOne.Object, _plugin.Object);

            var fixtureOverviews = _supervisor.GetFixtures();
            fixtureOverviews.Should().NotBeNullOrEmpty();
            fixtureOverviews.Should().Contain(f => f.Id == fixtureOneId);

            _supervisor.StartStreaming(fixtureOneId);

            var streamUpdate = new Fixture
            {
                Id = fixtureOneId,
                Sequence = 2,
                //Epoch increased
                Epoch = 10,
                MatchStatus = ((int)MatchStatus.InRunning).ToString()
            };


            Enumerable.Range(3, 13).ForEach(s =>
            {
                streamUpdate.Sequence = s;
                SendStreamUpdate(streamUpdate);
            });

            var fixtureOverview = _supervisor.GetFixtureOverview(fixtureOneId);
            fixtureOverview.GetFeedAudit().Should().NotBeEmpty();
            fixtureOverview.GetFeedAudit().FirstOrDefault(f => f.Sequence == 12 && f.IsProcessed).Should().NotBeNull();

            fixtureOverview.FeedUpdate.Sequence.Should().BeGreaterThan(10);
        }
        private Fixture GetUnsuspendedFixture(IMarketStateCollection state,out List<IMarketState> marketStates)
        {
            marketStates = new List<IMarketState>();

            var fixture = new Fixture
            {
                Id = state.FixtureId,
                MatchStatus = ((int)state.FixtureStatus).ToString(),
                Sequence = state.FixtureSequence
            };

            foreach (var mkt_id in state.Markets)
            {
                var marketState = state[mkt_id];
                if(marketState == null)
                    continue;

                marketStates.Add(marketState);
                //only unsuspend market if it's suspended by Adapter and not suspended in the feed
                if (marketState.IsForcedSuspended && !marketState.IsSuspended)
                {
                    fixture.Markets.Add(CreateMarket(state[mkt_id], false));
                }

            }

            return fixture;
        }
        public void CheckErrorsAreTrackedTest()
        {
            var fixtureOneId = "fixtureOne";
            
            _resource.Setup(x => x.Id).Returns(fixtureOneId);
            _resource.Setup(x => x.Content).Returns(new Summary());
            _resource.Setup(x => x.MatchStatus).Returns(MatchStatus.InRunning);
            _resource.SetupSequence(x => x.GetSnapshot())
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId)))
                .Returns(String.Empty)
                .Returns(String.Empty)
                .Returns(String.Empty)
                .Returns(String.Empty)
                .Returns(FixtureJsonHelper.ToJson(GetSnapshotWithMarkets(fixtureOneId, 10, 15)));

            _resource.Setup(x => x.StartStreaming()).Raises(r => r.StreamConnected += null, EventArgs.Empty);

            _supervisor.CreateStreamListener(_resource.Object, _plugin.Object);

            var fixtureOverviews = _supervisor.GetFixtures();
            fixtureOverviews.Should().NotBeNullOrEmpty();
            fixtureOverviews.Should().Contain(f => f.Id == fixtureOneId);

            _supervisor.StartStreaming(fixtureOneId);

            var streamUpdate = new Fixture
            {
                Id = fixtureOneId,
                Sequence = 2,
                //Epoch increased
                Epoch = 10,
                MatchStatus = ((int)MatchStatus.InRunning).ToString()
            };

            var deltas = new List<IFixtureOverviewDelta>();

            using (var subscriber = _supervisor.GetFixtureOverviewStream().Subscribe(deltas.Add))
            {
                Enumerable.Range(3, 10).ForEach(s =>
                {
                    streamUpdate.Sequence = s;
                    SendStreamUpdate(streamUpdate);
                });
            }

            var fixtureOverview = _supervisor.GetFixtureOverview(fixtureOneId);
            fixtureOverview.GetErrorsAudit().Should().NotBeEmpty();
            var errorsAudit = fixtureOverview.GetErrorsAudit();

            //at least 4 failed snapshots
            errorsAudit.Count().Should().Be(4);

            //the final snapshot sholud have succeeded
            fixtureOverview.LastError.IsErrored.Should().BeFalse();

            //there should be delta notification with LastError update IsErrored = false
            deltas.FirstOrDefault(d=> 
                d.LastError != null 
                && d.LastError.ResolvedAt == fixtureOverview.LastError.ResolvedAt 
                && d.LastError.Sequence == fixtureOverview.LastError.Sequence).Should().NotBeNull();
        }
 public void ProcessSnapshot(Fixture fixture, bool hasEpochChanged = false)
 {
     _Logger.InfoFormat("Received snapshot for {0} (hasEpochChanged={1})", fixture, hasEpochChanged);
 }
        private void SendStreamUpdate(Fixture streamUpdate)
        {
            var listener = _supervisor.GetType()
                .InvokeMember("GetStreamListener"
                    , BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                    null, _supervisor, new object[] { streamUpdate.Id }) as StreamListener;

            var message = new StreamMessage { Content = streamUpdate };

            listener.ResourceOnStreamEvent(null, new StreamEventArgs(JsonConvert.SerializeObject(message)));
        }
 public void ProcessMatchStatus(Fixture fixture)
 {
     _Logger.InfoFormat("Request for processing Match Statuf of {0} received", fixture);
 }
        private Fixture GetSnapshotWithMarkets(string id, int epoch = 1, int sequence = 1)
        {
            var snapshot = new Fixture 
            { Id = id, Sequence = sequence, MatchStatus = ((int)MatchStatus.InRunning).ToString(), Epoch = epoch };

            AddMarket(snapshot);
            AddTags(snapshot);

            return snapshot;
        }
 public void UnSuspend(Fixture fixture)
 {
     _Logger.InfoFormat("Request for un-suspend {0} received", fixture);
 }
 private void AddTags(Fixture snapshot)
 {
     snapshot.Tags.Add("SSLNCompetitionId","TestCompId");
     snapshot.Tags.Add("SSLNCompetitionName", "Test Competition Name");
 }
 public void ApplyPostRulesProcessing(Fixture fixture)
 {
     foreach(var mkt in fixture.Markets)
     {
         IUpdatableMarketState tmp = null;
         if(_processed.TryGetValue(mkt.Id, out tmp))
         {
             tmp.ApplyPostRulesProcessing();
         }
     }
 }
        private void AddMarket(Fixture snapshot)
        {
            var selections = new List<Selection>
            {
                new Selection {Id = "Sel1", Status = "1", Price = 0.45, Name = "Sel 1", Tradable = false},
                new Selection {Id = "Sel2", Status = "1", Price = 0.45, Name = "Sel 2", Tradable = false},
                new Selection {Id = "Sel3", Status = "1", Price = 0.45, Name = "Sel 3", Tradable = false}
            };

            var market = new Market("testMarketId");
            market.Selections.AddRange(selections);

            snapshot.Markets.Add(market);
        }