From 6ab3aaedb1a66c264562357ce5fcd7ad6f5e57bc Mon Sep 17 00:00:00 2001 From: Valentin Syrovatskiy <v.syrovatskiy@picodata.io> Date: Wed, 20 Jul 2022 10:23:31 +0300 Subject: [PATCH] test: randomized testing --- test/conftest.py | 11 +++++ test/rand/test_randomized.py | 93 ++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 test/rand/test_randomized.py diff --git a/test/conftest.py b/test/conftest.py index 79bcc23cb9..ac1dda25ef 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -31,6 +31,17 @@ def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) +def pytest_addoption(parser): + parser.addoption( + "--seed", action="store", default=None, help="Seed for randomized tests" + ) + + +@pytest.fixture(scope="session") +def seed(pytestconfig): + return pytestconfig.getoption("seed") + + @pytest.fixture(scope="session") def xdist_worker_number(worker_id: str) -> int: """ diff --git a/test/rand/test_randomized.py b/test/rand/test_randomized.py new file mode 100644 index 0000000000..d1dcbec819 --- /dev/null +++ b/test/rand/test_randomized.py @@ -0,0 +1,93 @@ +import time +import random +import os +import signal +from conftest import Cluster, Instance + + +def int_to_base_62(num: int): + base_62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + BASE = len(base_62) + rete = "" + while num != 0: + rete = base_62[num % BASE] + rete + num = num // BASE + return rete + + +def add(c: Cluster, _): + return c.add_instance() + + +def stop(_, i: Instance): + assert i.process, f"Instance {i.instance_id} expected has process" + assert i.process.pid, f"Instance {i.instance_id} expected process to be alive" + return os.kill(i.process.pid, signal.SIGTERM) + + +def start(_, i: Instance): + return i.start() + + +ACTIONS = { + "add": { + "repr": "Add", + "fn": add, + }, + "stop": { + "repr": "Stop", + "fn": stop, + }, + "start": { + "repr": "Start", + "fn": start, + }, +} +BASE = len(ACTIONS) + + +def possible_actions(i: Instance | None): + if i is None: + return ["add"] + elif i.process is not None: + return ["stop"] + else: + return ["start"] + + +def choose_instance(cluster: Cluster): + if len(cluster.instances) < 2: + return None + new_instance_chance = random.randint(0, 3) % 3 == 0 + if new_instance_chance: + return None + else: + return cluster.instances[random.randint(0, len(cluster.instances) - 1)] + + +def choose_action(i: Instance | None): + actions = possible_actions(i) + return ACTIONS[actions[random.randint(0, len(actions) - 1)]] + + +def step_msg(step: int, action, i: Instance): + if i is None: + msg = f"action {action['repr']}" + else: + msg = f"action {action['repr']} for {i.instance_id}" + return f"Step {step}: {msg}" + + +def test_randomized(cluster: Cluster, seed: int): + seed = seed if seed else int_to_base_62(time.time_ns()) + print(f"Seed: {seed}") + random.seed(seed) + + steps_count = random.randint(1, 5) + print(f"Do {steps_count} steps...") + + for step in range(steps_count): + i = choose_instance(cluster) + a = choose_action(i) + print(step_msg(step, a, i)) + a["fn"](cluster, i) -- GitLab