From 919ae4786173501ce9cb5cf130edf59bee3eb1d6 Mon Sep 17 00:00:00 2001 From: Valentin Syrovatskiy <v.syrovatskiy@picodata.io> Date: Fri, 22 Jul 2022 19:40:24 +0300 Subject: [PATCH] test: randomized testing --- test/rand/.gitignore | 1 + test/rand/test_randomized.py | 125 ++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 test/rand/.gitignore diff --git a/test/rand/.gitignore b/test/rand/.gitignore new file mode 100644 index 0000000000..b5b55d57fa --- /dev/null +++ b/test/rand/.gitignore @@ -0,0 +1 @@ +seeds.txt diff --git a/test/rand/test_randomized.py b/test/rand/test_randomized.py index d1dcbec819..546415ed59 100644 --- a/test/rand/test_randomized.py +++ b/test/rand/test_randomized.py @@ -1,8 +1,10 @@ +import sys import time import random import os import signal -from conftest import Cluster, Instance +from conftest import Cluster, Instance, ReturnError +import pathlib def int_to_base_62(num: int): @@ -15,79 +17,108 @@ def int_to_base_62(num: int): return rete -def add(c: Cluster, _): - return c.add_instance() +def create(c: Cluster, istate): + i = c.add_instance(wait_ready=False) + istate[i.instance_id] = {"instance": i, "started": False} + return i, istate -def stop(_, i: Instance): +def stop(i: Instance, istate): 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) + istate[i.instance_id]["started"] = False + return os.kill(i.process.pid, signal.SIGTERM), istate -def start(_, i: Instance): - return i.start() +def start(i: Instance, istate): + istate[i.instance_id]["started"] = True + return i.start(), istate +ADD = "add" +STOP = "stop" +START = "start" ACTIONS = { - "add": { - "repr": "Add", - "fn": add, + ADD: { + "name": ADD, + "repr_fn": lambda i: f"Add new instance {i}", + "pre_fn": create, + "exec_fn": start, }, - "stop": { - "repr": "Stop", - "fn": stop, + STOP: { + "name": STOP, + "repr_fn": lambda i: f"Stop {i}", + "exec_fn": stop, }, - "start": { - "repr": "Start", - "fn": start, + START: { + "name": START, + "repr_fn": lambda i: f"Start {i}", + "exec_fn": start, }, } BASE = len(ACTIONS) +SEEDLOG = "seeds.txt" -def possible_actions(i: Instance | None): - if i is None: - return ["add"] - elif i.process is not None: - return ["stop"] - else: - return ["start"] +def possible_actions(c: Cluster, istate): + actions = [] + actions.append([ADD, None]) + for i in c.instances: + if istate[i.instance_id]["started"]: + actions.append([STOP, i]) + else: + actions.append([START, i]) + return actions -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 choose_action(c: Cluster, istate): + actions = possible_actions(c, istate) + a = actions[random.randint(0, len(actions) - 1)] + return ACTIONS[a[0]], a[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}" + msg = action["repr_fn"](i.instance_id if i and i.instance_id else None) 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}") +def get_seed(): + return int_to_base_62(time.time_ns()) + + +def log_seed(seed): + dir = pathlib.Path(__file__).parent.absolute() + with open(os.path.join(dir, SEEDLOG), "a") as f: + f.write(seed + "\n") + + +def test_randomized(cluster: Cluster, seed: int, capsys): + cluster.deploy(instance_count=3) + + seed = seed if seed else get_seed() + log_seed(seed) + with capsys.disabled(): + print(f"Seed: {seed}") + random.seed(seed) - steps_count = random.randint(1, 5) + steps_count = random.randint(5, 10) print(f"Do {steps_count} steps...") + istate = {} + for i in cluster.instances: + istate[i.instance_id] = {"instance": i, "started": True} + for step in range(steps_count): - i = choose_instance(cluster) - a = choose_action(i) - print(step_msg(step, a, i)) - a["fn"](cluster, i) + a, i = choose_action(cluster, istate) + if "pre_fn" in a.keys(): + i, istate = a["pre_fn"](cluster, istate) + print(step_msg(step + 1, a, i)) + _, istate = a["exec_fn"](i, istate) + time.sleep(0.1) + + for instance_id in istate: + ist = istate[instance_id] + if ist["started"]: + ist["instance"].wait_ready() -- GitLab