예제 #1
0
        public void GetFavouriteDelta_should_return_lowest_hash_when_candidate_scores_are_equal()
        {
            using (var realCache = new MemoryCache(new MemoryCacheOptions()))
            {
                _voter = new DeltaVoter(realCache, _producersProvider, _peerSettings, _logger);

                var scoredCandidates = AddCandidatesToCacheAndVote(10, 110, realCache);

                scoredCandidates.Select(c => c.Score).Distinct().Count().Should().Be(1);
                scoredCandidates.Select(c => c.Candidate.Hash).Distinct().Count().Should().Be(2);
                scoredCandidates.Select(c => c.Candidate.PreviousDeltaDfsHash).Distinct().Count().Should().Be(1);

                var found = _voter.TryGetFavouriteDelta(
                    scoredCandidates.First().Candidate.PreviousDeltaDfsHash.ToByteArray().ToCid(),
                    out var favouriteCandidate);

                found.Should().BeTrue();
                var expectedFavourite = scoredCandidates
                                        .OrderBy(c => c.Candidate.Hash.ToByteArray(), ByteUtil.ByteListMinSizeComparer.Default)
                                        .First();

                // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                favouriteCandidate.Candidate.Hash.Equals(expectedFavourite.Candidate.Hash);
            }
        }
예제 #2
0
        private List <IScoredCandidateDelta> AddCandidatesToCacheAndVote(int firstVotesCount,
                                                                         int secondVotesCount,
                                                                         MemoryCache realCache)
        {
            var firstCandidate = DeltaHelper.GetCandidateDelta(_hashProvider, _previousDeltaHash,
                                                               producerId: _producerIds.First());

            var secondCandidate = DeltaHelper.GetCandidateDelta(_hashProvider, _previousDeltaHash,
                                                                producerId: _producerIds.Skip(1).First());

            var candidateStream = Enumerable.Repeat(firstCandidate, firstVotesCount)
                                  .Concat(Enumerable.Repeat(secondCandidate, secondVotesCount))
                                  .Shuffle().ToObservable();

            using (candidateStream.Subscribe(_voter))
            {
                var firstKey  = DeltaVoter.GetCandidateCacheKey(firstCandidate);
                var secondKey = DeltaVoter.GetCandidateCacheKey(secondCandidate);

                realCache.TryGetValue(firstKey, out IScoredCandidateDelta firstRetrieved).Should().BeTrue();
                realCache.TryGetValue(secondKey, out IScoredCandidateDelta secondRetrieved).Should().BeTrue();

                return(new List <IScoredCandidateDelta>
                {
                    firstRetrieved, secondRetrieved
                });
            }
        }
예제 #3
0
        public void When_candidate_in_cache_should_retrieve_ScoredCandidate()
        {
            _voter = new DeltaVoter(_cache, _producersProvider, _peerSettings, _logger);

            var initialScore   = 10;
            var cacheCandidate = ScoredCandidateDeltaHelper.GetScoredCandidateDelta(
                _hashProvider,
                producerId: _producerIds.First(),
                previousDeltaHash: _previousDeltaHash,
                score: initialScore);

            var candidateHash = cacheCandidate.Candidate.Hash.ToByteArray().ToCid();

            _cache.TryGetValue(Arg.Any <string>(), out Arg.Any <object>()).Returns(ci =>
            {
                ci[1] = cacheCandidate;
                return(true);
            });

            _voter.OnNext(cacheCandidate.Candidate);

            _cache.Received(1)
            .TryGetValue(Arg.Is <string>(s => s.EndsWith(candidateHash)), out Arg.Any <object>());
            _cache.DidNotReceiveWithAnyArgs().CreateEntry(Arg.Any <string>());

            cacheCandidate.Score.Should().Be(initialScore + 1);
        }
예제 #4
0
        public void When_candidate_not_in_cache_should_build_ScoredCandidate_with_ranking_and_store_it()
        {
            _voter = new DeltaVoter(_cache, _producersProvider, _peerSettings, _logger);

            var candidate = DeltaHelper.GetCandidateDelta(_hashProvider,
                                                          _previousDeltaHash,
                                                          producerId: _producerIds.First());

            var candidateHash = candidate.Hash.ToByteArray().ToCid();

            var addedEntry = Substitute.For <ICacheEntry>();

            _cache.CreateEntry(Arg.Is <string>(s => s.EndsWith(candidateHash)))
            .Returns(addedEntry);

            _voter.OnNext(candidate);

            _cache.Received(1)
            .TryGetValue(Arg.Is <string>(s => s.EndsWith(candidateHash)), out Arg.Any <object>());

            _cache.ReceivedWithAnyArgs(2).CreateEntry(Arg.Any <object>());
            _cache.Received(1).CreateEntry(Arg.Is <string>(s => s.EndsWith(candidateHash)));

            addedEntry.Value.Should().BeAssignableTo <IScoredCandidateDelta>();
            var scoredCandidateDelta = (IScoredCandidateDelta)addedEntry.Value;

            scoredCandidateDelta.Candidate.Hash.SequenceEqual(candidate.Hash).Should().BeTrue();
            scoredCandidateDelta.Score.Should().Be(100 * _producerIds.Count + 1);
        }
예제 #5
0
        public void When_candidate_is_empty_should_log_and_return_without_hitting_the_cache()
        {
            _voter = new DeltaVoter(_cache, _producersProvider, _peerSettings, _logger);

            _voter.OnNext(new CandidateDeltaBroadcast());

            _cache.DidNotReceiveWithAnyArgs().TryGetValue(Arg.Any <object>(), out Arg.Any <object>());
            _cache.DidNotReceiveWithAnyArgs().CreateEntry(Arg.Any <object>());
        }
예제 #6
0
        public void When_candidate_hash_is_empty_should_log_and_return_without_hitting_the_cache()
        {
            _voter = new DeltaVoter(_cache, _producersProvider, _peerSettings, _logger);

            _voter.OnNext(new CandidateDeltaBroadcast
            {
                PreviousDeltaDfsHash = ByteUtil.GenerateRandomByteArray(32).ToByteString(),
                ProducerId           = PeerIdHelper.GetPeerId("unknown_producer")
            });

            _cache.DidNotReceiveWithAnyArgs().TryGetValue(Arg.Any <object>(), out Arg.Any <object>());
            _cache.DidNotReceiveWithAnyArgs().CreateEntry(Arg.Any <object>());
        }
예제 #7
0
        public void When_candidate_is_produced_by_unexpected_producer_should_log_and_return_without_hitting_the_cache()
        {
            var candidateFromUnknownProducer = DeltaHelper.GetCandidateDelta(_hashProvider,
                                                                             producerId: PeerIdHelper.GetPeerId("unknown_producer"));

            _voter = new DeltaVoter(_cache, _producersProvider, _peerSettings, _logger);
            _voter.OnNext(candidateFromUnknownProducer);

            _logger.Received(1).Error(Arg.Is <Exception>(e => e is KeyNotFoundException),
                                      Arg.Any <string>(), Arg.Any <CandidateDeltaBroadcast>());

            _cache.DidNotReceiveWithAnyArgs().TryGetValue(Arg.Any <object>(), out Arg.Any <object>());
            _cache.DidNotReceiveWithAnyArgs().CreateEntry(Arg.Any <object>());
        }
        public void GetFavouriteDelta_should_return_null_on_unknown_previous_delta_hash()
        {
            using (var realCache = new MemoryCache(new MemoryCacheOptions()))
            {
                _voter = new DeltaVoter(realCache, _producersProvider, _peerSettings, _logger);

                AddCandidatesToCacheAndVote(10, 500, realCache);

                var found = _voter.TryGetFavouriteDelta(_hashProvider.ComputeMultiHash(ByteUtil.GenerateRandomByteArray(32)), out var favouriteCandidate);

                found.Should().BeFalse();
                favouriteCandidate.Should().BeNull();
            }
        }
예제 #9
0
        public void When_second_candidate_is_more_popular_it_should_score_higher()
        {
            using (var realCache = new MemoryCache(new MemoryCacheOptions()))
            {
                _voter = new DeltaVoter(realCache, _producersProvider, _peerSettings, _logger);

                var firstVotesCount  = 10;
                var secondVotesCount = 100 + 100 / 2;

                var retrievedCandidates = AddCandidatesToCacheAndVote(firstVotesCount, secondVotesCount, realCache);

                retrievedCandidates[0].Score.Should().Be(100 * _producerIds.Count + firstVotesCount);
                retrievedCandidates[1].Score.Should().Be(100 * (_producerIds.Count - 1) + secondVotesCount);
            }
        }
예제 #10
0
        public void When_candidates_not_in_cache_should_create_or_update_a_previous_hash_entry()
        {
            using (var realCache = new MemoryCache(new MemoryCacheOptions()))
            {
                _voter = new DeltaVoter(realCache, _producersProvider, _peerSettings, _logger);

                var candidate1 = DeltaHelper.GetCandidateDelta(
                    _hashProvider,
                    _previousDeltaHash,
                    producerId: _producerIds.First());
                var candidate1CacheKey = DeltaVoter.GetCandidateCacheKey(candidate1);

                var candidate2 = DeltaHelper.GetCandidateDelta(
                    _hashProvider,
                    _previousDeltaHash,
                    producerId: _producerIds.Last());
                var candidate2CacheKey = DeltaVoter.GetCandidateCacheKey(candidate2);

                var previousDeltaCacheKey = DeltaVoter.GetCandidateListCacheKey(candidate1);

                _voter.OnNext(candidate1);

                realCache.TryGetValue(candidate1CacheKey,
                                      out ScoredCandidateDelta retrievedCandidate1).Should().BeTrue();
                retrievedCandidate1.Candidate.ProducerId.Should().Be(_producerIds.First());

                realCache.TryGetValue(previousDeltaCacheKey,
                                      out ConcurrentBag <string> retrievedCandidateList).Should().BeTrue();
                retrievedCandidateList.Should().BeEquivalentTo(candidate1CacheKey);

                _voter.OnNext(candidate2);

                realCache.TryGetValue(candidate2CacheKey,
                                      out ScoredCandidateDelta retrievedCandidate2).Should().BeTrue();
                retrievedCandidate2.Candidate.ProducerId.Should().Be(_producerIds.Last());

                realCache.TryGetValue(previousDeltaCacheKey,
                                      out ConcurrentBag <string> retrievedUpdatedCandidateList).Should().BeTrue();
                retrievedUpdatedCandidateList.Should().BeEquivalentTo(candidate1CacheKey, candidate2CacheKey);
            }
        }
        public void GetFavouriteDelta_should_retrieve_favourite_delta()
        {
            using (var realCache = new MemoryCache(new MemoryCacheOptions()))
            {
                _voter = new DeltaVoter(realCache, _producersProvider, _peerSettings, _logger);

                var scoredCandidates = AddCandidatesToCacheAndVote(10, 500, realCache);

                scoredCandidates[1].Score.Should().BeGreaterThan(scoredCandidates[0].Score);

                var previousDeltaHash = _hashProvider.Cast(scoredCandidates[0].Candidate.PreviousDeltaDfsHash.ToByteArray());

                var found = _voter.TryGetFavouriteDelta(previousDeltaHash, out var favouriteCandidate);

                found.Should().BeTrue();

                favouriteCandidate.Candidate.PreviousDeltaDfsHash.ToByteArray().SequenceEqual(previousDeltaHash.ToArray()).Should().BeTrue();
                favouriteCandidate.Candidate.Hash.ToByteArray().SequenceEqual(scoredCandidates[1].Candidate.Hash.ToByteArray()).Should().BeTrue();
                favouriteCandidate.Candidate.ProducerId.Should().Be(scoredCandidates[1].Candidate.ProducerId);
            }
        }