From 217b5e6fda422087ec628bef3fa6e7142b1d8a45 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Sun, 26 Nov 2023 10:02:52 +0000 Subject: [PATCH 1/4] dump_databases flag --- openpype/cli.py | 8 ++++++-- openpype/pype_commands.py | 5 ++++- tests/conftest.py | 10 ++++++++++ tests/lib/testing_classes.py | 29 ++++++++++++++++++++--------- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/openpype/cli.py b/openpype/cli.py index f0fe550a1fa..6e1303b8a60 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -296,12 +296,16 @@ def run(script): @click.option("--mongo_url", help="MongoDB for testing.", default=None) +@click.option("--dump_databases", + help="Dump all databases to data folder.", + is_flag=True, + default=False) def runtests(folder, mark, pyargs, test_data_folder, persist, app_variant, - timeout, setup_only, mongo_url, app_group): + timeout, setup_only, mongo_url, app_group, dump_databases): """Run all automatic tests after proper initialization via start.py""" PypeCommands().run_tests(folder, mark, pyargs, test_data_folder, persist, app_variant, timeout, setup_only, - mongo_url, app_group) + mongo_url, app_group, dump_databases) @main.command(help="DEPRECATED - run sync server") diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index b5828d3dfe8..bd4e9228c15 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -214,7 +214,7 @@ def validate_jsons(self): def run_tests(self, folder, mark, pyargs, test_data_folder, persist, app_variant, timeout, setup_only, - mongo_url, app_group): + mongo_url, app_group, dump_databases): """ Runs tests from 'folder' @@ -275,6 +275,9 @@ def run_tests(self, folder, mark, pyargs, if mongo_url: args.extend(["--mongo_url", mongo_url]) + if dump_databases: + args.extend(["--dump_databases"]) + print("run_tests args: {}".format(args)) import pytest pytest.main(args) diff --git a/tests/conftest.py b/tests/conftest.py index 028c19bc5f5..493d6d947e3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,6 +39,11 @@ def pytest_addoption(parser): help="Provide url of the Mongo database." ) + parser.addoption( + "--dump_databases", action="store_true", default=None, + help="Dump databases to data folder." + ) + @pytest.fixture(scope="module") def test_data_folder(request): @@ -75,6 +80,11 @@ def mongo_url(request): return request.config.getoption("--mongo_url") +@pytest.fixture(scope="module") +def dump_databases(request): + return request.config.getoption("--dump_databases") + + @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): # execute all other hooks to obtain the report object diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 7700381aa63..6b248cf18a3 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -70,7 +70,9 @@ def project_settings(self): ) @pytest.fixture(scope="module") - def download_test_data(self, test_data_folder, persist, request): + def download_test_data( + self, test_data_folder, persist, request, dump_databases + ): test_data_folder = test_data_folder or self.TEST_DATA_FOLDER if test_data_folder: print("Using existing folder {}".format(test_data_folder)) @@ -100,13 +102,13 @@ def download_test_data(self, test_data_folder, persist, request): if ext and ext.lstrip('.') in handler_class.IMPLEMENTED_ZIP_FORMATS: # noqa: E501 handler_class.unzip(os.path.join(tmpdir, file_name)) - yield tmpdir + yield tmpdir - persist = (persist or self.PERSIST or - self.is_test_failed(request)) - if not persist: - print("Removing {}".format(tmpdir)) - shutil.rmtree(tmpdir) + persist = (persist or self.PERSIST or + self.is_test_failed(request) or dump_databases) + if not persist: + print("Removing {}".format(tmpdir)) + shutil.rmtree(tmpdir) @pytest.fixture(scope="module") def output_folder_url(self, download_test_data): @@ -163,7 +165,7 @@ def env_var(self, monkeypatch_session, download_test_data, mongo_url): @pytest.fixture(scope="module") def db_setup(self, download_test_data, env_var, monkeypatch_session, - request, mongo_url): + request, mongo_url, dump_databases, persist): """Restore prepared MongoDB dumps into selected DB.""" backup_dir = os.path.join(download_test_data, "input", "dumps") uri = os.environ.get("OPENPYPE_MONGO") @@ -178,7 +180,13 @@ def db_setup(self, download_test_data, env_var, monkeypatch_session, yield db_handler - persist = self.PERSIST or self.is_test_failed(request) + if dump_databases: + print("Dumping databases to {}".format(download_test_data)) + output_dir = os.path.join(download_test_data, "output", "dumps") + db_handler.backup_to_dump(self.TEST_DB_NAME, output_dir) + db_handler.backup_to_dump(self.TEST_OPENPYPE_NAME, output_dir) + + persist = persist or self.PERSIST or self.is_test_failed(request) if not persist: db_handler.teardown(self.TEST_DB_NAME) db_handler.teardown(self.TEST_OPENPYPE_NAME) @@ -335,6 +343,9 @@ def launched_app(self, dbcon, download_test_data, last_workfile_path, app_process = application_manager.launch(app_name, **data) yield app_process + stdout.close() + stderr.close() + @pytest.fixture(scope="module") def publish_finished(self, dbcon, launched_app, download_test_data, timeout, setup_only): From 431115255a5b8650c8da8bbf8f1918757e17f334 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Sun, 26 Nov 2023 10:25:48 +0000 Subject: [PATCH 2/4] Remove wrongly placed code. --- tests/lib/testing_classes.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 6b248cf18a3..3d31373f10a 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -343,9 +343,6 @@ def launched_app(self, dbcon, download_test_data, last_workfile_path, app_process = application_manager.launch(app_name, **data) yield app_process - stdout.close() - stderr.close() - @pytest.fixture(scope="module") def publish_finished(self, dbcon, launched_app, download_test_data, timeout, setup_only): From 91862484e86b7755f97916d6b9264f311ac47953 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Nov 2023 08:57:51 +0000 Subject: [PATCH 3/4] Turn flag into format and support json export. --- openpype/cli.py | 3 +-- openpype/pype_commands.py | 6 +++++- tests/conftest.py | 2 +- tests/lib/db_handler.py | 42 ++++++++++++++++++++++++++---------- tests/lib/testing_classes.py | 8 +++++-- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/openpype/cli.py b/openpype/cli.py index 6e1303b8a60..8caa1397652 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -298,8 +298,7 @@ def run(script): default=None) @click.option("--dump_databases", help="Dump all databases to data folder.", - is_flag=True, - default=False) + default=None) def runtests(folder, mark, pyargs, test_data_folder, persist, app_variant, timeout, setup_only, mongo_url, app_group, dump_databases): """Run all automatic tests after proper initialization via start.py""" diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index bd4e9228c15..93e6f6f4c6d 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -276,7 +276,11 @@ def run_tests(self, folder, mark, pyargs, args.extend(["--mongo_url", mongo_url]) if dump_databases: - args.extend(["--dump_databases"]) + msg = "dump_databases format is not recognized: {}".format( + dump_databases + ) + assert dump_databases in ["bson", "json"], msg + args.extend(["--dump_databases", dump_databases]) print("run_tests args: {}".format(args)) import pytest diff --git a/tests/conftest.py b/tests/conftest.py index 493d6d947e3..cb4806998ad 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,7 +40,7 @@ def pytest_addoption(parser): ) parser.addoption( - "--dump_databases", action="store_true", default=None, + "--dump_databases", action="store", default=None, help="Dump databases to data folder." ) diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index 82e741cc3b3..d9a52be5b49 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -2,7 +2,7 @@ Helper class for automatic testing, provides dump and restore via command line utilities. - Expect mongodump, mongoimport and mongorestore present at PATH + Expect mongodump, mongoexport, mongoimport and mongorestore present at PATH """ import os import pymongo @@ -148,7 +148,7 @@ def teardown(self, db_name): self.client.drop_database(db_name) def backup_to_dump(self, db_name, dump_dir, overwrite=False, - collection=None): + collection=None, format="bson"): """ Helper method for running mongodump for specific 'db_name' """ @@ -160,15 +160,24 @@ def backup_to_dump(self, db_name, dump_dir, overwrite=False, raise RuntimeError("Backup already exists, " "run with overwrite=True") - query = self._dump_query(self.uri, dump_dir, - db_name=db_name, collection=collection) - print("Mongodump query:: {}".format(query)) - subprocess.run(query) + collections = [collection] + if format == "json" and collection is None: + collections = self.client[db_name].list_collection_names() + + for collection in collections: + query = self._dump_query(self.uri, dump_dir, + db_name=db_name, collection=collection, + format=format) + print("Mongodump query:: {}".format(query)) + process = subprocess.run(query) + assert process.returncode == 0, "Mongo dump failed." def _db_exists(self, db_name): return db_name in self.client.list_database_names() - def _dump_query(self, uri, output_path, db_name=None, collection=None): + def _dump_query( + self, uri, output_path, db_name=None, collection=None, format="bson" + ): """Prepares dump query based on 'db_name' or 'collection'.""" db_part = coll_part = "" if db_name: @@ -177,11 +186,22 @@ def _dump_query(self, uri, output_path, db_name=None, collection=None): if not db_name: raise ValueError("db_name must be present") coll_part = "--collection={}".format(collection) - query = "\"{}\" --uri=\"{}\" --out={} {} {}".format( - "mongodump", uri, output_path, db_part, coll_part - ) - return query + tool = "mongodump" + query = "{} --uri=\"{}\"" + + if format == "json": + assert collection, "Collection is needed for json export." + + query += " --jsonArray --pretty" + tool = "mongoexport" + output_path = os.path.join( + output_path, "{}.{}.json".format(db_name, collection) + ) + + query += " --out={} {} {}" + + return query.format(tool, uri, output_path, db_part, coll_part) def _restore_query(self, uri, dump_dir, db_name=None, db_name_out=None, diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 3d31373f10a..7a90f76662d 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -183,8 +183,12 @@ def db_setup(self, download_test_data, env_var, monkeypatch_session, if dump_databases: print("Dumping databases to {}".format(download_test_data)) output_dir = os.path.join(download_test_data, "output", "dumps") - db_handler.backup_to_dump(self.TEST_DB_NAME, output_dir) - db_handler.backup_to_dump(self.TEST_OPENPYPE_NAME, output_dir) + db_handler.backup_to_dump( + self.TEST_DB_NAME, output_dir, format=dump_databases + ) + db_handler.backup_to_dump( + self.TEST_OPENPYPE_NAME, output_dir, format=dump_databases + ) persist = persist or self.PERSIST or self.is_test_failed(request) if not persist: From adcc6d9f47f805af5090f2f89d0bcc25657b7c78 Mon Sep 17 00:00:00 2001 From: kalisp Date: Wed, 6 Dec 2023 17:29:32 +0100 Subject: [PATCH 4/4] Added new argument to readme --- tests/integration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/README.md b/tests/integration/README.md index 7b9b7cd7067..1e45b55ed51 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -29,7 +29,7 @@ Command line arguments - "--timeout" - "Provide specific timeout value for test case", - "--setup_only" - "Only create dbs, do not run tests", - "--mongo_url" - "MongoDB for testing.", - + - "--dump_databases" - ("json"|"bson") export database in expected format after successful test (to output folder in temp location - which is made persistent by this, must be cleared manually) Run Tray for test ----------------- In case of failed test you might want to run it manually and visually debug what happened.