#!/usr/bin/env python import os import os.path import pathlib import shutil import tempfile from typing import Iterator import click from sentry.runner import configure configure() _manifest_files_env = { "SENTRY_MODEL_MANIFEST_FILE_PATH": pathlib.Path(__file__).absolute().parent.parent, "GETSENTRY_MODEL_MANIFEST_FILE_PATH": pathlib.Path(__file__) .absolute() .parent.parent.parent.joinpath("getsentry"), } from sentry.testutils.modelmanifest import HybridCloudTestVisitor, ModelManifest def find_test_cases_matching(model_name: str) -> Iterator[HybridCloudTestVisitor]: for env_name, path_root in _manifest_files_env.items(): manifest = ModelManifest.open(os.environ[env_name]) model_test_ids = manifest.connections[ manifest.get_or_create_id(manifest.model_names, model_name) ] for test_id, test_visitor in manifest.each_hybrid_cloud_test(path_root): if test_id not in model_test_ids: continue test_visitor.load() yield test_visitor def pick(prompt, options): choice = "" while choice not in options: choice = input(prompt + " (" + ", ".join(options) + ") ") # noqa return choice @click.command() @click.argument("target_model", required=True) def main(target_model: str): """ Script to decorate the given target test for silo tests, making it easier to deploy changes to given tests. """ for test_visitor in find_test_cases_matching(target_model): print(f"Trying {test_visitor.test_name} in {test_visitor.test_file_path}") # noqa if not test_visitor.decorator_was_stable: print(f"Found {test_visitor.test_name}") # noqa try: if pick("Skip this test?", ["y", "n"]) == "y": continue except EOFError: continue try: silo_mode = pick("silo mode?", ["all", "no", "control", "region"]) set_stable = pick("set stable?", ["y", "n"]) == "y" except EOFError: continue _rewrite(test_visitor, f"{silo_mode}_silo_test", set_stable) def _decorate(target_test_silo_mode, set_stable, lineno, match_line): if not match_line: return False if not match_line[0] == lineno: return False ws = b" " * match_line[1] if set_stable: return ws + f"@{target_test_silo_mode}(stable=True)\n".encode() else: return ws + f"@{target_test_silo_mode}\n".encode() def _rewrite(test_visitor: HybridCloudTestVisitor, target_test_silo_mode, set_stable): path = test_visitor.test_file_path import_line = f"from sentry.testutils.silo import {target_test_silo_mode}\n".encode() if not test_visitor.decorator_match_line and not test_visitor.func_match_line: raise Exception(f"Could not find test case {test_visitor.target_symbol_parts}!") with tempfile.NamedTemporaryFile(delete=False) as tf: with open(path) as f: if not test_visitor.import_match_line: tf.write(import_line) for i, line in enumerate(f.readlines()): i += 1 if test_visitor.import_match_line and test_visitor.import_match_line[0] == i: tf.write(import_line) continue if newline := _decorate( target_test_silo_mode, set_stable, i, test_visitor.decorator_match_line ): # If the decorator type is not changing, keep the original line. # If the decorator that existed was stable, don't replace it, keep it. if test_visitor.decorator_was_stable: tf.write(line.encode("utf8")) else: tf.write(newline) continue if not test_visitor.decorator_match_line and ( newline := _decorate( target_test_silo_mode, set_stable, i, test_visitor.func_match_line ) ): tf.write(newline) tf.write(line.encode("utf8")) tf.close() shutil.move(tf.name, path) if __name__ == "__main__": main()