import asyncio import async_timeout import string from redis import asyncio as aioredis from . import dfly_args from .seeder import Seeder, StaticSeeder @dfly_args({"proactor_threads": 4}) async def test_static_seeder(async_client: aioredis.Redis): s = StaticSeeder(key_target=10_000, data_size=100) await s.run(async_client) assert abs(await async_client.dbsize() - 10_000) <= 50 @dfly_args({"proactor_threads": 4}) async def test_static_collection_size(async_client: aioredis.Redis): async def check_list(): keys = await async_client.keys() assert (await async_client.llen(keys[0])) == 1 assert len(await async_client.lpop(keys[0])) == 10_000 s = StaticSeeder( key_target=10, data_size=10_000, variance=1, samples=1, collection_size=1, types=["LIST"] ) await s.run(async_client) await check_list() await async_client.flushall() s = Seeder( units=1, key_target=10, data_size=10_000, collection_size=1, types=["LIST"], huge_value_percentage=0, huge_value_size=0, ) await s.run(async_client) await check_list() @dfly_args({"proactor_threads": 4}) async def test_seeder_key_target(async_client: aioredis.Redis): """Ensure seeder reaches its key targets""" s = Seeder(units=len(Seeder.DEFAULT_TYPES) * 2, key_target=5000) # Ensure tests are not reasonably slow async with async_timeout.timeout(1 + 4): # Fill with 5k keys, 1% derivation = 50 await s.run(async_client, target_deviation=0.01) assert abs(await async_client.dbsize() - 5000) <= 50 # Run 1k ops, ensure key balance stays the "more or less" the same await s.run(async_client, target_ops=1000) assert abs(await async_client.dbsize() - 5000) <= 100 # Run one second until stopped task = asyncio.create_task(s.run(async_client)) await asyncio.sleep(1.0) await s.stop(async_client) await task # Change key target, 100 is actual minimum because "math breaks" s.change_key_target(0) await s.run(async_client, target_deviation=0.5) # don't set low precision with low values assert await async_client.dbsize() < 200 # Get cmdstat calls info = await async_client.info("ALL") calls = { k.split("_")[1]: v["calls"] for k, v in info.items() if k.startswith("cmdstat_") and v["calls"] > 50 } assert len(calls) > 15 # we use at least 15 different commands @dfly_args({"proactor_threads": 4}) async def test_seeder_capture(async_client: aioredis.Redis): """Ensure same data produces same state hashes""" async def set_data(): p = async_client.pipeline() p.mset(mapping={f"string{i}": f"{i}" for i in range(100)}) p.lpush("list1", *list(string.ascii_letters)) p.sadd("set1", *list(string.ascii_letters)) p.hset("hash1", mapping={f"{i}": l for i, l in enumerate(string.ascii_letters)}) p.zadd("zset1", mapping={l: i for i, l in enumerate(string.ascii_letters)}) await p.execute() # Capture with filled data await set_data() capture = await Seeder.capture(async_client) # Check hashes are 0 without data await async_client.flushall() assert all(h == 0 for h in (await Seeder.capture(async_client))) # Check setting the same data results in same hashes await set_data() assert capture == await Seeder.capture(async_client) # Check changing the data gives different hahses await async_client.lpush("list1", "NEW") assert capture != await Seeder.capture(async_client) # Undo our change await async_client.lpop("list1") assert capture == await Seeder.capture(async_client) # Do another change await async_client.spop("set1") assert capture != await Seeder.capture(async_client)