Exemplo n.º 1
0
class PopularityWinrateDistribution:
	def __init__(self, redis, name, max_items=9, bucket_size=5, ttl=600, use_lua=None):
		self.name = name
		self.max_items = max_items
		self.bucket_size = bucket_size
		self.observations = RedisPopularityDistribution(
			redis,
			name="%s_OBSERVATIONS" % self.name,
			namespace="POPULARITY",
			ttl=ttl,
			max_items=self.max_items,
			bucket_size=self.bucket_size,
			use_lua=use_lua
		)
		self.wins = RedisPopularityDistribution(
			redis,
			name="%s_WINS" % self.name,
			namespace="POPULARITY",
			ttl=ttl,
			max_items=self.max_items,
			bucket_size=self.bucket_size,
			use_lua=use_lua
		)

	def increment(self, key, win=False, as_of=None):
		self.observations.increment(key, as_of=as_of)
		if win:
			self.wins.increment(key, as_of=as_of)

	def distribution(self, start_ts, end_ts):
		games = self.observations.distribution(
			start_ts=start_ts,
			end_ts=end_ts,
		)
		wins = self.wins.distribution(
			start_ts=start_ts,
			end_ts=end_ts,
		)
		result = {}
		for key, val in games.items():
			result[key] = {
				"games": val,
				"wins": wins.get(key, 0)
			}
		return result
def test_redis_popularity_distribution(_mock_lock):
	r = fakeredis.FakeStrictRedis()
	distribution = RedisPopularityDistribution(r, "DECKS", namespace="test")

	actuals = defaultdict(int)
	for deck in DECKS:
		actuals[deck] += 1
		distribution.increment(deck)

	assert distribution.size() == 18
	assert distribution.observations() == len(DECKS)

	actual_most_popular = list(sorted(actuals.items(), key=lambda t: t[1], reverse=True))
	dist_most_popular = list(
		sorted(distribution.distribution().items(), key=lambda t: t[1], reverse=True)
	)
	actual_result = actual_most_popular[0][0]
	expected_result = int(dist_most_popular[0][0])

	assert actual_result == expected_result
	assert distribution.popularity(expected_result) == 32.0
def test_bucket_sizes_and_ttls(_mock_lock):
	r = fakeredis.FakeStrictRedis()
	distribution = RedisPopularityDistribution(
		r,
		"DECKS",
		ttl=5,
		namespace="test",
		bucket_size=1
	)

	# Create t_0 as 5 seconds in the past
	current_ts = datetime.utcnow()
	td = timedelta(seconds=5, microseconds=current_ts.microsecond)
	t_0 = current_ts - td

	def t_N(N):
		return t_0 + timedelta(seconds=N)

	distribution.increment("A", as_of=t_N(1))
	distribution.increment("B", as_of=t_N(2))
	distribution.increment("A", as_of=t_N(3))
	distribution.increment("A", as_of=t_N(4))

	# First assert the full distribution exists
	expected_distribution = {"A": 3.0, "B": 1.0}
	actual_distribution = distribution.distribution()
	assert expected_distribution == actual_distribution

	# Then assert accessing a partial distribution (t_2, t_3) within the full time range
	expected_distribution = {"A": 1.0, "B": 1.0}
	actual_distribution = distribution.distribution(start_ts=t_N(2), end_ts=t_N(3))
	assert expected_distribution == actual_distribution

	# Finally, assert that the first observation of "A" has aged out due to the TTL
	time.sleep(1)

	expected_distribution = {"A": 2.0, "B": 1}
	actual_distribution = distribution.distribution()
	assert expected_distribution == actual_distribution