diff options
author | Anna Wawrzyniak <anna.wawrzyniak@mongodb.com> | 2022-11-10 00:07:40 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-11-10 00:36:34 +0000 |
commit | b7a422f4fcd6535192831bbaf71dbd6907f9f985 (patch) | |
tree | aa2c76e011e99f505dd176948b4bf8726a783272 /buildscripts/golden_test.py | |
parent | 05f41623029c6d805fa3699581c3df94590de560 (diff) | |
download | mongo-b7a422f4fcd6535192831bbaf71dbd6907f9f985.tar.gz |
SERVER-71228 - Add support for golden test CLI on windows.
Diffstat (limited to 'buildscripts/golden_test.py')
-rwxr-xr-x | buildscripts/golden_test.py | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/buildscripts/golden_test.py b/buildscripts/golden_test.py index b7164b276cd..d0d811d4b33 100755 --- a/buildscripts/golden_test.py +++ b/buildscripts/golden_test.py @@ -8,6 +8,7 @@ For details on the golden data test framework see: docs/golden_data_test_framewo import json import os import pathlib +import platform import re import sys import shutil @@ -23,7 +24,7 @@ if __name__ == "__main__" and __package__ is None: from buildscripts.util.fileops import read_yaml_file # pylint: enable=wrong-import-position -assert sys.version_info >= (3, 8) +assert sys.version_info >= (3, 7) class AppError(Exception): @@ -73,6 +74,25 @@ def get_path_name_regex(pattern: str) -> str: return '[0-9a-f]'.join([re.escape(part) for part in pattern.split('%')]) +# For compatibility with version<3.8 that does not support shutil.copytree with dirs_exist_ok=True +def copytree_dirs_exist_ok_compatibility(src, dest): + if os.path.isdir(src): + if not os.path.isdir(dest): + os.makedirs(dest) + files = os.listdir(src) + for file in files: + copytree_dirs_exist_ok_compatibility(os.path.join(src, file), os.path.join(dest, file)) + else: + shutil.copyfile(src, dest) + + +def copytree_dirs_exist_ok(src, dest): + if sys.version_info >= (3, 8): + shutil.copytree(src, dest, dirs_exist_ok=True) + else: + copytree_dirs_exist_ok_compatibility(src, dest) + + @click.group() @click.option('-n', '--dry-run', is_flag=True) @click.option('-v', '--verbose', is_flag=True) @@ -96,6 +116,7 @@ class GoldenTestApp(object): verbose: False dry_run: False + config_path: None config: None output_parent_path = None output_name_pattern = None @@ -105,8 +126,10 @@ class GoldenTestApp(object): """Initialize the app.""" self.verbose = verbose self.dry_run = dry_run + self.config_path = config_path - self.config = self.load_config(config_path) + def init_config(self): + self.config = self.load_config(self.config_path) self.output_parent_path = pathlib.Path(self.config.outputRootPattern).parent self.output_name_pattern = str(pathlib.Path(self.config.outputRootPattern).name) @@ -134,13 +157,16 @@ class GoldenTestApp(object): def load_config(self, config_path): """Load configuration file.""" if config_path is None: - raise "Can't load config. GOLDEN_TEST_CONFIG_PATH envrionment variable is not set" + raise AppError(( + "Can't load config. GOLDEN_TEST_CONFIG_PATH envrionment variable is not set. Golden test CLI must be configured before use.\n" + "To configure it, follow the instructions in https://github.com/10gen/mongo/blob/master/docs/golden_data_test_framework.md#how-to-diff-and-accept-new-test-outputs-on-a-workstation\n" + "Note: After setup you may need to rerun the tests for this utility to find them.")) self.vprint(f"Loading config from path: '{config_path}'") config = GoldenTestConfig.from_yaml_file(config_path) if config.outputRootPattern is None: - raise "Invalid config. outputRootPattern config parameter is not set" + raise AppError("Invalid config. outputRootPattern config parameter is not set") return config @@ -192,11 +218,72 @@ class GoldenTestApp(object): actual=os.path.join(output_path, "actual"), expected=os.path.join( output_path, "expected")) + def setup_linux(self): + # Create config file + config_path = os.path.join(os.path.expanduser('~'), ".golden_test_config.yml") + if not os.path.isfile(config_path): + print(f"Creating {config_path}") + config_contents = ( + r"""outputRootPattern: '/var/tmp/test_output/out-%%%%-%%%%-%%%%-%%%%'""" + "\n" + r"""diffCmd: 'git diff --no-index "{{expected}}" "{{actual}}"'""" + "\n") + with open(config_path, 'w') as file: + file.write(config_contents) + else: + print(f"Skipping creating {config_path}, file exists.") + + # Add global GOLDEN_TEST_CONFIG_PATH environment variable + etc_environment_path = "/etc/environment" + env_var_defined = False + if os.path.isfile(etc_environment_path): + with open(etc_environment_path, 'r') as file: + for line in file.readlines(): + if line.startswith("GOLDEN_TEST_CONFIG_PATH="): + env_var_defined = True + if not env_var_defined: + print(f"Adding GOLDEN_TEST_CONFIG_PATH to {etc_environment_path}") + env_var_contents = (f"GOLDEN_TEST_CONFIG_PATH=\"{config_path}\"") + call(["sudo", "/bin/sh", "-c", f"echo '{env_var_contents}' >> {etc_environment_path}"]) + else: + print( + f"Skipping adding GOLDEN_TEST_CONFIG_PATH to {etc_environment_path}, variable already defined." + ) + + def setup_windows(self): + # Create config file + config_path = os.path.join(os.path.expandvars('%LocalAppData%'), ".golden_test_config.yml") + if not os.path.isfile(config_path): + print(f"Creating {config_path}") + config_contents = ( + r"outputRootPattern: 'C:\Users\Administrator\AppData\Local\Temp\test_output\out-%%%%-%%%%-%%%%-%%%%'" + "\n" + r"""diffCmd: 'git diff --no-index "{{expected}}" "{{actual}}"'""" + "\n") + with open(config_path, 'w') as file: + file.write(config_contents) + else: + print(f"Skipping creating {config_path}, file exists.") + + # Add global GOLDEN_TEST_CONFIG_PATH environment variable + if os.environ.get("GOLDEN_TEST_CONFIG_PATH") is None: + print("Setting GOLDEN_TEST_CONFIG_PATH global variable") + call([ + "runas", "/profile", "/user:administrator", + f"setx GOLDEN_TEST_CONFIG_PATH \"{config_path}\"" + ]) + else: + print( + "Skipping setting GOLDEN_TEST_CONFIG_PATH global variable, variable already defined." + ) + @cli.command('diff', help='Diff the expected and actual folders of the test output') @click.argument('output_name', required=False) @click.pass_obj def command_diff(self, output_name): """Diff the expected and actual folders of the test output.""" + self.init_config() + if output_name is None: output_name = self.get_latest_output() @@ -213,6 +300,8 @@ class GoldenTestApp(object): @click.pass_obj def command_get_path(self, output_name): """Get the root folder path of the test output.""" + self.init_config() + if output_name is None: output_name = self.get_latest_output() @@ -225,6 +314,8 @@ class GoldenTestApp(object): @click.pass_obj def command_accept(self, output_name): """Accept the actual test output and copy it as new golden data to the source repo.""" + self.init_config() + if output_name is None: output_name = self.get_latest_output() @@ -235,12 +326,14 @@ class GoldenTestApp(object): self.vprint(f"Copying files recursively from '{paths.actual}' to '{repo_root}'") if not self.dry_run: - shutil.copytree(paths.actual, repo_root, dirs_exist_ok=True) + copytree_dirs_exist_ok(paths.actual, repo_root) @cli.command('clean', help='Remove all test outputs') @click.pass_obj def command_clean(self): """Remove all test outputs.""" + self.init_config() + outputs = self.list_outputs() self.vprint(f"Deleting {len(outputs)} outputs") for output_name in outputs: @@ -253,6 +346,8 @@ class GoldenTestApp(object): @click.pass_obj def command_latest(self): """Get the name of the most recent test output.""" + self.init_config() + output_name = self.get_latest_output() print(output_name) @@ -260,9 +355,22 @@ class GoldenTestApp(object): @click.pass_obj def command_list(self): """List all names of the available test outputs.""" + self.init_config() + for output_name in self.list_outputs(): print(output_name) + @cli.command('setup', help='Performs default setup based on current platform') + @click.pass_obj + def command_setup(self): + """Performs default setup based on current platform.""" + if platform.platform().startswith("Linux"): + self.setup_linux() + elif platform.platform().startswith("Windows"): + self.setup_windows() + else: + raise AppError(f"Platform not supported by this setup utility: {platform.platform()}") + def main(): """Execute main.""" |