From 3245aabbe66d1fd36bfc9615ff707f47686283e1 Mon Sep 17 00:00:00 2001 From: Patrick Wang Date: Sun, 14 Jul 2024 17:22:38 -0700 Subject: [PATCH] Automated workspace pruning/cleaning (#35) **Summary**: A command to find and remove unneeded files from the workspace directory. **Demo**: Passing 25 unit tests with many edge cases which create files/directories, call `clean_workspace()`, and then verify its contents. ![Screenshot 2024-07-07 at 17 05 07](https://github.com/cmu-db/dbgym/assets/20631215/ed2edeae-062a-40ae-b38e-e2ad3718d6b3) **Details** * "Aggressive" mode removes all task_runs/\*/ directories that are not directly pointed to by a symlink in symlinks/. * "Safe" mode also keeps task_runs/\*/ directories which are indirectly pointed to by a symlink. This can happen if a symlink points to a task_runs/\*/ directory which has a symlink in it that points to another task_runs/*/ directory. * I chose to write so many unit tests because this operation must be bug-free. --- .gitignore | 1 + README.md | 2 +- .../apt_requirements.txt | 0 .../install_dependencies.sh | 0 {dependency => dependencies}/requirements.txt | 0 dependencies/rust.sh | 2 + {tune/protox/test => manage}/__init__.py | 0 manage/cli.py | 217 ++++++ manage/tests/__init__.py | 0 manage/tests/test_clean.py | 702 ++++++++++++++++++ misc/utils.py | 131 +++- task.py | 77 +- tune/protox/env/util/pg_conn.py | 4 +- tune/protox/tests/__init__.py | 0 .../{test => tests}/test_index_space.py | 4 +- tune/protox/{test => tests}/test_primitive.py | 0 tune/protox/{test => tests}/test_workload.py | 20 +- .../{test => tests}/test_workload_utils.py | 0 .../unittest_dsb.yaml | 0 .../unittest_job_full.yaml | 0 .../unittest_tpcc.yaml | 0 .../unittest_tpch.yaml | 0 .../unittest_dsb_dir/order.txt | 0 .../unittest_dsb_dir/query001s0.sql | 0 .../unittest_dsb_dir/query010s0.sql | 0 .../unittest_dsb_dir/query013s0.sql | 0 .../unittest_dsb_dir/query013s0_spj.sql | 0 .../unittest_dsb_dir/query014s0.sql | 0 .../unittest_dsb_dir/query018s0.sql | 0 .../unittest_dsb_dir/query018s0_spj.sql | 0 .../unittest_dsb_dir/query019s0.sql | 0 .../unittest_dsb_dir/query019s0_spj.sql | 0 .../unittest_dsb_dir/query023s0.sql | 0 .../unittest_dsb_dir/query025s0.sql | 0 .../unittest_dsb_dir/query025s0_spj.sql | 0 .../unittest_dsb_dir/query027s0.sql | 0 .../unittest_dsb_dir/query027s0_spj.sql | 0 .../unittest_dsb_dir/query030s0.sql | 0 .../unittest_dsb_dir/query031s0.sql | 0 .../unittest_dsb_dir/query032s0.sql | 0 .../unittest_dsb_dir/query038s0.sql | 0 .../unittest_dsb_dir/query039as0.sql | 0 .../unittest_dsb_dir/query039bs0.sql | 0 .../unittest_dsb_dir/query040s0.sql | 0 .../unittest_dsb_dir/query040s0_spj.sql | 0 .../unittest_dsb_dir/query050s0.sql | 0 .../unittest_dsb_dir/query050s0_spj.sql | 0 .../unittest_dsb_dir/query054s0.sql | 0 .../unittest_dsb_dir/query058s0.sql | 0 .../unittest_dsb_dir/query059s0.sql | 0 .../unittest_dsb_dir/query064s0.sql | 0 .../unittest_dsb_dir/query065s0.sql | 0 .../unittest_dsb_dir/query069s0.sql | 0 .../unittest_dsb_dir/query072s0.sql | 0 .../unittest_dsb_dir/query072s0_spj.sql | 0 .../unittest_dsb_dir/query075s0.sql | 0 .../unittest_dsb_dir/query080s0.sql | 0 .../unittest_dsb_dir/query081s0.sql | 0 .../unittest_dsb_dir/query083s0.sql | 0 .../unittest_dsb_dir/query084s0.sql | 0 .../unittest_dsb_dir/query084s0_spj.sql | 0 .../unittest_dsb_dir/query085s0.sql | 0 .../unittest_dsb_dir/query085s0_spj.sql | 0 .../unittest_dsb_dir/query087s0.sql | 0 .../unittest_dsb_dir/query091s0.sql | 0 .../unittest_dsb_dir/query091s0_spj.sql | 0 .../unittest_dsb_dir/query092s0.sql | 0 .../unittest_dsb_dir/query094s0.sql | 0 .../unittest_dsb_dir/query099s0.sql | 0 .../unittest_dsb_dir/query099s0_spj.sql | 0 .../unittest_dsb_dir/query100s0.sql | 0 .../unittest_dsb_dir/query100s0_spj.sql | 0 .../unittest_dsb_dir/query101s0.sql | 0 .../unittest_dsb_dir/query101s0_spj.sql | 0 .../unittest_dsb_dir/query102s0.sql | 0 .../unittest_dsb_dir/query102s0_spj.sql | 0 .../unittest_job_full_dir/1.sql | 0 .../unittest_job_full_dir/10.sql | 0 .../unittest_job_full_dir/10b.sql | 0 .../unittest_job_full_dir/10c.sql | 0 .../unittest_job_full_dir/11.sql | 0 .../unittest_job_full_dir/11b.sql | 0 .../unittest_job_full_dir/11c.sql | 0 .../unittest_job_full_dir/11d.sql | 0 .../unittest_job_full_dir/12.sql | 0 .../unittest_job_full_dir/12b.sql | 0 .../unittest_job_full_dir/12c.sql | 0 .../unittest_job_full_dir/13.sql | 0 .../unittest_job_full_dir/13b.sql | 0 .../unittest_job_full_dir/13c.sql | 0 .../unittest_job_full_dir/13d.sql | 0 .../unittest_job_full_dir/14.sql | 0 .../unittest_job_full_dir/14b.sql | 0 .../unittest_job_full_dir/14c.sql | 0 .../unittest_job_full_dir/15.sql | 0 .../unittest_job_full_dir/15b.sql | 0 .../unittest_job_full_dir/15c.sql | 0 .../unittest_job_full_dir/15d.sql | 0 .../unittest_job_full_dir/16.sql | 0 .../unittest_job_full_dir/16b.sql | 0 .../unittest_job_full_dir/16c.sql | 0 .../unittest_job_full_dir/16d.sql | 0 .../unittest_job_full_dir/17.sql | 0 .../unittest_job_full_dir/17b.sql | 0 .../unittest_job_full_dir/17c.sql | 0 .../unittest_job_full_dir/17d.sql | 0 .../unittest_job_full_dir/17e.sql | 0 .../unittest_job_full_dir/17f.sql | 0 .../unittest_job_full_dir/18.sql | 0 .../unittest_job_full_dir/18b.sql | 0 .../unittest_job_full_dir/18c.sql | 0 .../unittest_job_full_dir/19.sql | 0 .../unittest_job_full_dir/19b.sql | 0 .../unittest_job_full_dir/19c.sql | 0 .../unittest_job_full_dir/19d.sql | 0 .../unittest_job_full_dir/1b.sql | 0 .../unittest_job_full_dir/1c.sql | 0 .../unittest_job_full_dir/1d.sql | 0 .../unittest_job_full_dir/2.sql | 0 .../unittest_job_full_dir/20.sql | 0 .../unittest_job_full_dir/20b.sql | 0 .../unittest_job_full_dir/20c.sql | 0 .../unittest_job_full_dir/21.sql | 0 .../unittest_job_full_dir/21b.sql | 0 .../unittest_job_full_dir/21c.sql | 0 .../unittest_job_full_dir/22.sql | 0 .../unittest_job_full_dir/22b.sql | 0 .../unittest_job_full_dir/22c.sql | 0 .../unittest_job_full_dir/22d.sql | 0 .../unittest_job_full_dir/23.sql | 0 .../unittest_job_full_dir/23b.sql | 0 .../unittest_job_full_dir/23c.sql | 0 .../unittest_job_full_dir/24.sql | 0 .../unittest_job_full_dir/24b.sql | 0 .../unittest_job_full_dir/25.sql | 0 .../unittest_job_full_dir/25b.sql | 0 .../unittest_job_full_dir/25c.sql | 0 .../unittest_job_full_dir/26.sql | 0 .../unittest_job_full_dir/26b.sql | 0 .../unittest_job_full_dir/26c.sql | 0 .../unittest_job_full_dir/27.sql | 0 .../unittest_job_full_dir/27b.sql | 0 .../unittest_job_full_dir/27c.sql | 0 .../unittest_job_full_dir/28.sql | 0 .../unittest_job_full_dir/28b.sql | 0 .../unittest_job_full_dir/28c.sql | 0 .../unittest_job_full_dir/29.sql | 0 .../unittest_job_full_dir/29b.sql | 0 .../unittest_job_full_dir/29c.sql | 0 .../unittest_job_full_dir/2b.sql | 0 .../unittest_job_full_dir/2c.sql | 0 .../unittest_job_full_dir/2d.sql | 0 .../unittest_job_full_dir/3.sql | 0 .../unittest_job_full_dir/30.sql | 0 .../unittest_job_full_dir/30b.sql | 0 .../unittest_job_full_dir/30c.sql | 0 .../unittest_job_full_dir/31.sql | 0 .../unittest_job_full_dir/31b.sql | 0 .../unittest_job_full_dir/31c.sql | 0 .../unittest_job_full_dir/32.sql | 0 .../unittest_job_full_dir/32b.sql | 0 .../unittest_job_full_dir/33.sql | 0 .../unittest_job_full_dir/33b.sql | 0 .../unittest_job_full_dir/33c.sql | 0 .../unittest_job_full_dir/3b.sql | 0 .../unittest_job_full_dir/3c.sql | 0 .../unittest_job_full_dir/4.sql | 0 .../unittest_job_full_dir/4b.sql | 0 .../unittest_job_full_dir/4c.sql | 0 .../unittest_job_full_dir/5.sql | 0 .../unittest_job_full_dir/5b.sql | 0 .../unittest_job_full_dir/5c.sql | 0 .../unittest_job_full_dir/6.sql | 0 .../unittest_job_full_dir/6b.sql | 0 .../unittest_job_full_dir/6c.sql | 0 .../unittest_job_full_dir/6d.sql | 0 .../unittest_job_full_dir/6e.sql | 0 .../unittest_job_full_dir/6f.sql | 0 .../unittest_job_full_dir/7.sql | 0 .../unittest_job_full_dir/7b.sql | 0 .../unittest_job_full_dir/7c.sql | 0 .../unittest_job_full_dir/8.sql | 0 .../unittest_job_full_dir/8b.sql | 0 .../unittest_job_full_dir/8c.sql | 0 .../unittest_job_full_dir/8d.sql | 0 .../unittest_job_full_dir/9.sql | 0 .../unittest_job_full_dir/9b.sql | 0 .../unittest_job_full_dir/9c.sql | 0 .../unittest_job_full_dir/9d.sql | 0 .../unittest_job_full_dir/order.txt | 0 .../unittest_ref_models/ref_dsb_model.txt | 0 .../ref_job_full_model.txt | 0 .../unittest_ref_models/ref_tpcc_model.txt | 0 .../unittest_ref_models/ref_tpch_model.txt | 0 .../{test => tests}/unittest_tpcc_dir/1.sql | 0 .../{test => tests}/unittest_tpcc_dir/10.sql | 0 .../{test => tests}/unittest_tpcc_dir/11.sql | 0 .../{test => tests}/unittest_tpcc_dir/12.sql | 0 .../{test => tests}/unittest_tpcc_dir/13.sql | 0 .../{test => tests}/unittest_tpcc_dir/14.sql | 0 .../{test => tests}/unittest_tpcc_dir/15.sql | 0 .../{test => tests}/unittest_tpcc_dir/16.sql | 0 .../{test => tests}/unittest_tpcc_dir/17.sql | 0 .../{test => tests}/unittest_tpcc_dir/18.sql | 0 .../{test => tests}/unittest_tpcc_dir/19.sql | 0 .../{test => tests}/unittest_tpcc_dir/2.sql | 0 .../{test => tests}/unittest_tpcc_dir/20.sql | 0 .../{test => tests}/unittest_tpcc_dir/21.sql | 0 .../{test => tests}/unittest_tpcc_dir/22.sql | 0 .../{test => tests}/unittest_tpcc_dir/23.sql | 0 .../{test => tests}/unittest_tpcc_dir/24.sql | 0 .../{test => tests}/unittest_tpcc_dir/25.sql | 0 .../{test => tests}/unittest_tpcc_dir/26.sql | 0 .../{test => tests}/unittest_tpcc_dir/27.sql | 0 .../{test => tests}/unittest_tpcc_dir/28.sql | 0 .../{test => tests}/unittest_tpcc_dir/29.sql | 0 .../{test => tests}/unittest_tpcc_dir/3.sql | 0 .../{test => tests}/unittest_tpcc_dir/30.sql | 0 .../{test => tests}/unittest_tpcc_dir/31.sql | 0 .../{test => tests}/unittest_tpcc_dir/32.sql | 0 .../{test => tests}/unittest_tpcc_dir/33.sql | 0 .../{test => tests}/unittest_tpcc_dir/4.sql | 0 .../{test => tests}/unittest_tpcc_dir/5.sql | 0 .../{test => tests}/unittest_tpcc_dir/6.sql | 0 .../{test => tests}/unittest_tpcc_dir/7.sql | 0 .../{test => tests}/unittest_tpcc_dir/8.sql | 0 .../{test => tests}/unittest_tpcc_dir/9.sql | 0 .../{test => tests}/unittest_tpcc_dir/txn.txt | 0 .../{test => tests}/unittest_tpch_dir/01.sql | 0 .../{test => tests}/unittest_tpch_dir/02.sql | 0 .../{test => tests}/unittest_tpch_dir/03.sql | 0 .../{test => tests}/unittest_tpch_dir/04.sql | 0 .../{test => tests}/unittest_tpch_dir/05.sql | 0 .../{test => tests}/unittest_tpch_dir/06.sql | 0 .../{test => tests}/unittest_tpch_dir/07.sql | 0 .../{test => tests}/unittest_tpch_dir/08.sql | 0 .../{test => tests}/unittest_tpch_dir/09.sql | 0 .../{test => tests}/unittest_tpch_dir/10.sql | 0 .../{test => tests}/unittest_tpch_dir/11.sql | 0 .../{test => tests}/unittest_tpch_dir/12.sql | 0 .../{test => tests}/unittest_tpch_dir/13.sql | 0 .../{test => tests}/unittest_tpch_dir/14.sql | 0 .../{test => tests}/unittest_tpch_dir/15.sql | 0 .../{test => tests}/unittest_tpch_dir/16.sql | 0 .../{test => tests}/unittest_tpch_dir/17.sql | 0 .../{test => tests}/unittest_tpch_dir/18.sql | 0 .../{test => tests}/unittest_tpch_dir/19.sql | 0 .../{test => tests}/unittest_tpch_dir/20.sql | 0 .../{test => tests}/unittest_tpch_dir/21.sql | 0 .../{test => tests}/unittest_tpch_dir/22.sql | 0 .../unittest_tpch_dir/order.txt | 0 251 files changed, 1030 insertions(+), 130 deletions(-) rename {dependency => dependencies}/apt_requirements.txt (100%) rename {dependency => dependencies}/install_dependencies.sh (100%) rename {dependency => dependencies}/requirements.txt (100%) create mode 100755 dependencies/rust.sh rename {tune/protox/test => manage}/__init__.py (100%) create mode 100644 manage/cli.py create mode 100644 manage/tests/__init__.py create mode 100644 manage/tests/test_clean.py create mode 100644 tune/protox/tests/__init__.py rename tune/protox/{test => tests}/test_index_space.py (95%) rename tune/protox/{test => tests}/test_primitive.py (100%) rename tune/protox/{test => tests}/test_workload.py (75%) rename tune/protox/{test => tests}/test_workload_utils.py (100%) rename tune/protox/{test => tests}/unittest_benchmark_configs/unittest_dsb.yaml (100%) rename tune/protox/{test => tests}/unittest_benchmark_configs/unittest_job_full.yaml (100%) rename tune/protox/{test => tests}/unittest_benchmark_configs/unittest_tpcc.yaml (100%) rename tune/protox/{test => tests}/unittest_benchmark_configs/unittest_tpch.yaml (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/order.txt (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query001s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query010s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query013s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query013s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query014s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query018s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query018s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query019s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query019s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query023s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query025s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query025s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query027s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query027s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query030s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query031s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query032s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query038s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query039as0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query039bs0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query040s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query040s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query050s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query050s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query054s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query058s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query059s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query064s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query065s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query069s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query072s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query072s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query075s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query080s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query081s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query083s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query084s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query084s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query085s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query085s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query087s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query091s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query091s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query092s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query094s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query099s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query099s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query100s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query100s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query101s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query101s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query102s0.sql (100%) rename tune/protox/{test => tests}/unittest_dsb_dir/query102s0_spj.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/1.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/10.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/10b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/10c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/11.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/11b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/11c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/11d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/12.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/12b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/12c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/13.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/13b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/13c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/13d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/14.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/14b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/14c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/15.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/15b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/15c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/15d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/16.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/16b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/16c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/16d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17e.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/17f.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/18.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/18b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/18c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/19.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/19b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/19c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/19d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/1b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/1c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/1d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/2.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/20.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/20b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/20c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/21.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/21b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/21c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/22.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/22b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/22c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/22d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/23.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/23b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/23c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/24.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/24b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/25.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/25b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/25c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/26.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/26b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/26c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/27.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/27b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/27c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/28.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/28b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/28c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/29.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/29b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/29c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/2b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/2c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/2d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/3.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/30.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/30b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/30c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/31.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/31b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/31c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/32.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/32b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/33.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/33b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/33c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/3b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/3c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/4.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/4b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/4c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/5.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/5b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/5c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6e.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/6f.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/7.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/7b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/7c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/8.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/8b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/8c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/8d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/9.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/9b.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/9c.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/9d.sql (100%) rename tune/protox/{test => tests}/unittest_job_full_dir/order.txt (100%) rename tune/protox/{test => tests}/unittest_ref_models/ref_dsb_model.txt (100%) rename tune/protox/{test => tests}/unittest_ref_models/ref_job_full_model.txt (100%) rename tune/protox/{test => tests}/unittest_ref_models/ref_tpcc_model.txt (100%) rename tune/protox/{test => tests}/unittest_ref_models/ref_tpch_model.txt (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/1.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/10.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/11.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/12.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/13.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/14.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/15.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/16.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/17.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/18.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/19.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/2.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/20.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/21.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/22.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/23.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/24.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/25.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/26.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/27.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/28.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/29.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/3.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/30.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/31.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/32.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/33.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/4.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/5.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/6.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/7.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/8.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/9.sql (100%) rename tune/protox/{test => tests}/unittest_tpcc_dir/txn.txt (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/01.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/02.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/03.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/04.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/05.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/06.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/07.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/08.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/09.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/10.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/11.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/12.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/13.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/14.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/15.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/16.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/17.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/18.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/19.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/20.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/21.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/22.sql (100%) rename tune/protox/{test => tests}/unittest_tpch_dir/order.txt (100%) diff --git a/.gitignore b/.gitignore index fb05af95..383aa46f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ __pycache__/ .conda/ .idea/ +test_clean_scratchspace/ workspace/ default_*_benchbase_config_*.xml \ No newline at end of file diff --git a/README.md b/README.md index 91419aa6..9637fe79 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ These steps were tested on a fresh repository clone, Ubuntu 22.04. ``` # Setup dependencies. -# You may want to create a Python virtual environment (e.g. with conda) before doing this. +# You may want to create a Python 3.10 virtual environment (e.g. with conda) before doing this. ./dependency/install_dependencies.sh # Compile a custom fork of PostgreSQL, load TPC-H (SF 0.01), train the Proto-X agent, and tune. diff --git a/dependency/apt_requirements.txt b/dependencies/apt_requirements.txt similarity index 100% rename from dependency/apt_requirements.txt rename to dependencies/apt_requirements.txt diff --git a/dependency/install_dependencies.sh b/dependencies/install_dependencies.sh similarity index 100% rename from dependency/install_dependencies.sh rename to dependencies/install_dependencies.sh diff --git a/dependency/requirements.txt b/dependencies/requirements.txt similarity index 100% rename from dependency/requirements.txt rename to dependencies/requirements.txt diff --git a/dependencies/rust.sh b/dependencies/rust.sh new file mode 100755 index 00000000..9af316fc --- /dev/null +++ b/dependencies/rust.sh @@ -0,0 +1,2 @@ +#!/bin/bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh \ No newline at end of file diff --git a/tune/protox/test/__init__.py b/manage/__init__.py similarity index 100% rename from tune/protox/test/__init__.py rename to manage/__init__.py diff --git a/manage/cli.py b/manage/cli.py new file mode 100644 index 00000000..d8c7e9b4 --- /dev/null +++ b/manage/cli.py @@ -0,0 +1,217 @@ +import shutil +from typing import List, Set +import click +import yaml +import logging +from pathlib import Path +from misc.utils import DBGymConfig, is_child_path, parent_dpath_of_path +from itertools import chain +import os + + +task_logger = logging.getLogger("task") +task_logger.setLevel(logging.INFO) + + +@click.group(name="manage") +def manage_group(): + pass + + +@click.command(name="show") +@click.argument("keys", nargs=-1) +@click.pass_obj +def manage_show(dbgym_cfg, keys): + config_path = dbgym_cfg.path + config_yaml = dbgym_cfg.yaml + + # Traverse the YAML. + for key in keys: + config_yaml = config_yaml[key] + + # Pretty-print the requested YAML value. + output_str = None + if type(config_yaml) != dict: + output_str = config_yaml + else: + output_str = yaml.dump(config_yaml, default_flow_style=False) + if len(keys) > 0: + output_str = " " + output_str.replace("\n", "\n ") + output_str = output_str.rstrip() + print(output_str) + + task_logger.info(f"Read: {Path(config_path)}") + + +@click.command(name="write") +@click.argument("keys", nargs=-1) +@click.argument("value_type") +@click.argument("value") +@click.pass_obj +def manage_write(dbgym_cfg, keys, value_type, value): + config_path = dbgym_cfg.path + config_yaml = dbgym_cfg.yaml + + # Traverse the YAML. + root_yaml = config_yaml + for key in keys[:-1]: + config_yaml = config_yaml[key] + + # Modify the requested YAML value and write the YAML file. + assert type(config_yaml[keys[-1]]) != dict + config_yaml[keys[-1]] = getattr(__builtins__, value_type)(value) + new_yaml = yaml.dump(root_yaml, default_flow_style=False).rstrip() + Path(config_path).write_text(new_yaml) + + task_logger.info(f"Updated: {Path(config_path)}") + + +@click.command(name="standardize") +@click.pass_obj +def manage_standardize(dbgym_cfg): + config_path = dbgym_cfg.path + config_yaml = dbgym_cfg.yaml + + # Write the YAML file. + new_yaml = yaml.dump(config_yaml, default_flow_style=False).rstrip() + Path(config_path).write_text(new_yaml) + + task_logger.info(f"Updated: {Path(config_path)}") + + +@click.command("clean") +@click.pass_obj +@click.option( + "--mode", + type=click.Choice(["safe", "aggressive"]), + default="safe", + help="The mode to clean the workspace (default=\"safe\"). \"aggressive\" means \"only keep run_*/ folders referenced by a file in symlinks/\". \"safe\" means \"in addition to that, recursively keep any run_*/ folders referenced by any symlinks in run_*/ folders we are keeping.\"" +) +def manage_clean(dbgym_cfg: DBGymConfig, mode: str): + clean_workspace(dbgym_cfg, mode=mode, verbose=True) + + +@click.command("count") +@click.pass_obj +def manage_count(dbgym_cfg: DBGymConfig): + num_files = _count_files_in_workspace(dbgym_cfg) + print(f"The workspace ({dbgym_cfg.dbgym_workspace_path}) has {num_files} total files/dirs/symlinks.") + + +def add_symlinks_in_dpath(symlinks_stack: List[Path], root_dpath: Path, processed_symlinks: Set[Path]) -> None: + """ + Will modify symlinks_stack and processed_symlinks. + """ + for root_pathstr, dir_names, file_names in os.walk(root_dpath): + root_path = Path(root_pathstr) + # symlinks can either be files or directories, so we go through both dir_names and file_names + for file_name in chain(dir_names, file_names): + file_path = root_path / file_name + if file_path.is_symlink() and file_path not in processed_symlinks: + symlinks_stack.append(file_path) + processed_symlinks.add(file_path) + + +def _count_files_in_workspace(dbgym_cfg: DBGymConfig) -> int: + """ + Counts the number of files (regular file or dir or symlink) in the workspace. + """ + total_count = 0 + for dirpath, dirnames, filenames in os.walk(dbgym_cfg.dbgym_workspace_path, followlinks=False): + # Check if any of the directories are symbolic links and remove them from dirnames + dirnames[:] = [d for d in dirnames if not os.path.islink(os.path.join(dirpath, d))] + + # Count files and directories (non-symlink directories already filtered) + total_count += len(filenames) + len(dirnames) + + return total_count + + +def clean_workspace(dbgym_cfg: DBGymConfig, mode: str="safe", verbose=False) -> None: + """ + Clean all [workspace]/task_runs/run_*/ directories that are not referenced by any "active symlinks". + If mode is "aggressive", "active symlinks" means *only* the symlinks directly in [workspace]/symlinks/. + If mode is "safe", "active symlinks" means the symlinks directly in [workspace]/symlinks/ as well as + any symlinks referenced in task_runs/run_*/ directories we have already decided to keep. + """ + # This stack holds the symlinks that are left to be processed + symlink_fpaths_to_process = [] + # This set holds the symlinks that have already been processed to avoid infinite loops + processed_symlinks = set() + + # 1. Initialize paths to process + if dbgym_cfg.dbgym_symlinks_path.exists(): + add_symlinks_in_dpath(symlink_fpaths_to_process, dbgym_cfg.dbgym_symlinks_path, processed_symlinks) + + # 2. Go through symlinks, figuring out which "children of task runs" to keep + # Based on the rules of the framework, "children of task runs" should be run_*/ directories. + # However, the user's workspace might happen to break these rules by putting directories not + # named "run_*/" or files directly in task_runs/. Thus, I use the term "task_run_child_fordpaths" + # instead of "run_dpaths". + task_run_child_fordpaths_to_keep = set() + + if dbgym_cfg.dbgym_runs_path.exists(): + while symlink_fpaths_to_process: + symlink_fpath: Path = symlink_fpaths_to_process.pop() + assert symlink_fpath.is_symlink() + # Path.resolve() resolves all layers of symlinks while os.readlink() only resolves one layer. + # However, os.readlink() literally reads the string contents of the link. We need to do some + # processing on the result of os.readlink() to convert it to an absolute path + real_fordpath = symlink_fpath.resolve() + one_layer_resolved_fordpath = os.readlink(symlink_fpath) + assert str(real_fordpath) == str(os.readlink(symlink_fpath)), f"symlink_fpath ({symlink_fpath}) seems to point to *another* symlink. This is difficult to handle, so it is currently disallowed. Please resolve this situation manually." + + # If the file doesn't exist, we'll just ignore it. + if not real_fordpath.exists(): + continue + # We're only trying to figure out which direct children of task_runs/ to save. If the file isn't + # even a descendant, we don't care about it. + if not is_child_path(real_fordpath, dbgym_cfg.dbgym_runs_path): + continue + + assert not os.path.samefile(real_fordpath, dbgym_cfg.dbgym_runs_path) + + # Figure out the task_run_child_fordpath to put into task_run_child_fordpaths_to_keep + task_run_child_fordpath = None + if os.path.samefile(parent_dpath_of_path(real_fordpath), dbgym_cfg.dbgym_runs_path): + # While it's true that it shouldn't be possible to symlink to a directory directly in task_runs/, + # we'll just not delete it if the user happens to have one like this. Even if the user messed up + # the structure somehow, it's just a good idea not to delete it. + task_run_child_fordpath = real_fordpath + else: + # Technically, it's not allowed to symlink to any files not in task_runs/run_*/[codebase]/[organization]/. + # However, as with above, we won't just nuke files if the workspace doesn't follow this rule for + # some reason. + task_run_child_fordpath = real_fordpath + while not os.path.samefile(parent_dpath_of_path(task_run_child_fordpath), dbgym_cfg.dbgym_runs_path): + task_run_child_fordpath = parent_dpath_of_path(task_run_child_fordpath) + assert task_run_child_fordpath != None + assert os.path.samefile(parent_dpath_of_path(task_run_child_fordpath), dbgym_cfg.dbgym_runs_path), f"task_run_child_fordpath ({task_run_child_fordpath}) is not a direct child of dbgym_cfg.dbgym_runs_path" + task_run_child_fordpaths_to_keep.add(task_run_child_fordpath) + + # If on safe mode, add symlinks inside the task_run_child_fordpath to be processed + if mode == "safe": + add_symlinks_in_dpath(symlink_fpaths_to_process, task_run_child_fordpath, processed_symlinks) + + # 3. Go through all children of task_runs/*, deleting any that we weren't told to keep + # It's true that symlinks might link outside of task_runs/*. We'll just not care about those + starting_num_files = _count_files_in_workspace(dbgym_cfg) + if dbgym_cfg.dbgym_runs_path.exists(): + for child_fordpath in dbgym_cfg.dbgym_runs_path.iterdir(): + if child_fordpath not in task_run_child_fordpaths_to_keep: + if child_fordpath.is_dir(): + shutil.rmtree(child_fordpath) + else: + os.remove(child_fordpath) + ending_num_files = _count_files_in_workspace(dbgym_cfg) + + if verbose: + task_logger.info(f"Removed {starting_num_files - ending_num_files} out of {starting_num_files} files") + task_logger.info(f"Workspace went from {starting_num_files - ending_num_files} to {starting_num_files}") + + +manage_group.add_command(manage_show) +manage_group.add_command(manage_write) +manage_group.add_command(manage_standardize) +manage_group.add_command(manage_clean) +manage_group.add_command(manage_count) \ No newline at end of file diff --git a/manage/tests/__init__.py b/manage/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manage/tests/test_clean.py b/manage/tests/test_clean.py new file mode 100644 index 00000000..2df33d2d --- /dev/null +++ b/manage/tests/test_clean.py @@ -0,0 +1,702 @@ +import logging +from pathlib import Path +import unittest +import os +import shutil +import copy + +from misc.utils import get_symlinks_path_from_workspace_path, get_runs_path_from_workspace_path, path_exists_dont_follow_symlinks +from manage.cli import clean_workspace + + +# This is here instead of on `if __name__ == "__main__"` because we often run individual tests, which +# does not go through the `if __name__ == "__main__"` codepath. +# Make it DEBUG to see logs from verify_structure(). Make it INFO to not see logs. +logging.basicConfig(level=logging.INFO) + + +class MockDBGymConfig: + def __init__(self, scratchspace_path: Path): + self.dbgym_workspace_path = scratchspace_path + self.dbgym_symlinks_path = get_symlinks_path_from_workspace_path(scratchspace_path) + self.dbgym_runs_path = get_runs_path_from_workspace_path(scratchspace_path) + + +class CleanTests(unittest.TestCase): + """ + I deemed "clean" important enough to write extensive unit tests for because a bug could lead to + losing important files. + """ + @staticmethod + def create_structure(root_path: Path, structure: dict) -> None: + def create_structure_internal(root_path: Path, cur_path: Path, structure: dict) -> None: + for path, content in structure.items(): + full_path: Path = cur_path / path + + if isinstance(content, dict): # Directory + full_path.mkdir(parents=True, exist_ok=True) + create_structure_internal(root_path, full_path, content) + elif isinstance(content, tuple) and content[0] == "file": + assert len(content) == 1 + full_path.touch() + elif isinstance(content, tuple) and content[0] == "symlink": + assert len(content) == 2 + target_path = root_path / content[1] + os.symlink(target_path, full_path) + else: + raise ValueError(f"Unsupported type for path ({path}): {content}") + + root_path.mkdir(parents=True, exist_ok=True) + create_structure_internal(root_path, root_path, structure) + + @staticmethod + def verify_structure(root_path: Path, structure: dict) -> bool: + def verify_structure_internal(root_path: Path, cur_path: Path, structure: dict) -> bool: + # Check for the presence of each item specified in the structure + for name, item in structure.items(): + new_cur_path = cur_path / name + if not path_exists_dont_follow_symlinks(new_cur_path): + logging.debug(f"{new_cur_path} does not exist") + return False + elif isinstance(item, dict): + if not new_cur_path.is_dir(): + logging.debug(f"expected {new_cur_path} to be a directory") + return False + if not verify_structure_internal(root_path, new_cur_path, item): + return False + elif isinstance(item, tuple) and item[0] == "file": + if not new_cur_path.is_file(): + logging.debug(f"expected {new_cur_path} to be a regular file") + return False + elif isinstance(item, tuple) and item[0] == "symlink": + if not new_cur_path.is_symlink(): + logging.debug(f"expected {new_cur_path} to be a symlink") + return False + # If item[1] is None, this indicates that we expect the symlink to be broken + if item[1] != None: + expected_target = root_path / item[1] + if not new_cur_path.resolve().samefile(expected_target): + logging.debug(f"expected {new_cur_path} to link to {expected_target}, but it links to {new_cur_path.resolve()}") + return False + else: + assert False, "structure misconfigured" + + # Check for any extra files or directories not described by the structure + expected_names = set(structure.keys()) + actual_names = {entry.name for entry in cur_path.iterdir()} + if not expected_names.issuperset(actual_names): + logging.debug(f"expected_names={expected_names}, actual_names={actual_names}") + return False + + return True + + if not root_path.exists(): + logging.debug(f"{root_path} does not exist") + return False + return verify_structure_internal(root_path, root_path, structure) + + @staticmethod + def make_workspace_structure(symlinks_structure: dict, task_runs_structure: dict) -> dict: + """ + This function exists so that it's easier to refactor the tests in case we ever change + how the workspace is organized. + """ + return { + "symlinks": symlinks_structure, + "task_runs": task_runs_structure, + } + + @classmethod + def setUpClass(cls): + cls.scratchspace_path = Path.cwd() / "manage/tests/test_clean_scratchspace/" + + def setUp(self): + if self.scratchspace_path.exists(): + shutil.rmtree(self.scratchspace_path) + + def tearDown(self): + if self.scratchspace_path.exists(): + shutil.rmtree(self.scratchspace_path) + + def test_structure_helpers(self): + structure = { + "dir1": { + "file1.txt": ("file",), + "dir2": { + "file2.txt": ("file",) + } + }, + "dir3": { + "nested_link_to_dir1": ("symlink", "dir1") + }, + "link_to_dir1": ("symlink", "dir1"), + "link_to_file2": ("symlink", "dir1/dir2/file2.txt") + } + CleanTests.create_structure(self.scratchspace_path, structure) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, structure)) + + extra_dir_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, extra_dir_structure)) + extra_dir_structure["dir4"] = {} + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, extra_dir_structure)) + + missing_dir_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, missing_dir_structure)) + del missing_dir_structure["dir1"] + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, missing_dir_structure)) + + extra_file_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, extra_file_structure)) + extra_file_structure["file3.txt"] = ("file",) + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, extra_file_structure)) + + missing_file_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, missing_file_structure)) + del missing_file_structure["dir1"]["file1.txt"] + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, missing_file_structure)) + + extra_link_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, extra_link_structure)) + extra_link_structure["link_to_dir3"] = ("symlink", "dir3") + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, extra_link_structure)) + + missing_link_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, missing_link_structure)) + del missing_link_structure["link_to_dir1"] + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, missing_link_structure)) + + wrong_link_structure = copy.deepcopy(structure) + # The "assertTrue, modify, assertFalse" patterns makes sure it was the modification that broke it + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, wrong_link_structure)) + wrong_link_structure["link_to_dir1"] = ("symlink", "dir3") + self.assertFalse(CleanTests.verify_structure(self.scratchspace_path, wrong_link_structure)) + + def test_nonexistent_workspace(self): + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + + def test_no_symlinks_dir_and_no_task_runs_dir(self): + starting_structure = {} + ending_structure = {} + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_no_symlinks_dir_and_yes_task_runs_dir(self): + starting_structure = { + "task_runs": { + "file1.txt": ("file",) + } + } + ending_structure = { + "task_runs": {} + } + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_yes_symlinks_dir_and_no_task_runs_dir(self): + starting_structure = { + "symlinks": {} + } + ending_structure = { + "symlinks": {} + } + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_no_symlinks_in_dir_and_no_task_runs_in_dir(self): + starting_symlinks_structure = {} + starting_task_runs_structure = {} + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = {} + ending_task_runs_structure = {} + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_no_links_in_symlinks(self): + starting_symlinks_structure = {} + starting_task_runs_structure = { + "run_0": {} + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = {} + ending_task_runs_structure = {} + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_file_directly_in_task_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/file1.txt") + } + starting_task_runs_structure = { + "file1.txt": ("file",), + "file2.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/file1.txt") + } + ending_task_runs_structure = { + "file1.txt": ("file",) + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_dir_directly_in_task_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",) + }, + "dir2": { + "file2.txt": ("file",) + } + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",) + } + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_file_in_dir_in_task_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",) + }, + "dir2": { + "file2.txt": ("file",) + } + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",) + } + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_dir_in_dir_in_task_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/dir2") + } + starting_task_runs_structure = { + "dir1": { + "dir2": { + "file1.txt": ("file",) + }, + "file2.txt": ("file",) + }, + "dir3": { + "file3.txt": ("file",) + } + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/dir2") + } + ending_task_runs_structure = { + "dir1": { + "dir2": { + "file1.txt": ("file",) + }, + "file2.txt": ("file",) + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_link_crashes(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/symlink2") + } + starting_task_runs_structure = { + "symlink2": ("symlink", "task_runs/file1.txt"), + "file1.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + with self.assertRaises(AssertionError): + clean_workspace(MockDBGymConfig(self.scratchspace_path)) + + def test_safe_mode_link_to_dir_with_link(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/file1.txt") + }, + "file1.txt": ("file",), + "file2.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/file1.txt") + }, + "file1.txt": ("file",), + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_safe_mode_link_to_file_in_dir_with_link(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/file2.txt") + }, + "file2.txt": ("file",), + "file3.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/file2.txt") + }, + "file2.txt": ("file",), + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_safe_mode_link_to_dir_with_link_to_file_in_dir_in_task_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/dir2/file2.txt") + }, + "dir2": { + "file2.txt": ("file",), + }, + "file3.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/dir2/file2.txt") + }, + "dir2": { + "file2.txt": ("file",), + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_aggressive_mode_link_to_dir_with_link(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/file1.txt") + }, + "file1.txt": ("file",), + "file2.txt": ("file",) + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", None) + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="aggressive") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_link_to_link_to_file_gives_error(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/symlink2") + } + starting_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "task_runs/file2.txt") + }, + "file2.txt": ("file",), + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + + # We disallow links to links so it's an AssertionError + with self.assertRaises(AssertionError): + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + + def test_multi_link_loop_gives_error(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/symlink2") + } + starting_task_runs_structure = { + "dir1": { + "symlink2": ("symlink", "symlinks/symlink1") + }, + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + + # pathlib disallows multi-link loops so it's a RuntimeError + with self.assertRaises(RuntimeError): + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + + def test_link_self_loop_gives_error(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "symlinks/symlink1") + } + starting_task_runs_structure = dict() + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + + # pathlib disallows link self-loops so it's a RuntimeError + with self.assertRaises(RuntimeError): + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + + def test_dont_loop_infinitely_if_there_are_cycles_between_different_dirs_in_runs(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir2/file2.txt") + }, + "dir2": { + "file2.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir2/file2.txt") + }, + "dir2": { + "file2.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_dont_loop_infinitely_if_there_is_a_dir_in_runs_that_links_to_a_file_in_itself(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_dont_loop_infinitely_if_there_is_loop_amongst_symlinks(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/file1.txt") + }, + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_broken_symlink_has_no_effect(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "task_runs/dir1/non_existent_file.txt") + }, + "dir2": { + "file2.txt": ("file",) + } + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", None) + } + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + # The idea behind this test is that we shouldn't be following links outside of task_runs, even on safe mode + def test_link_to_folder_outside_runs_that_contains_link_to_other_run_doesnt_save_other_run(self): + starting_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + starting_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "external/dir3/file3.txt") + }, + "dir2": { + "file2.txt": ("file",) + } + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + starting_structure["external"] = { + "dir3": { + "file3.txt": ("file",), + "symlink3": ("symlink", "task_runs/dir2/file2.txt") + } + } + ending_symlinks_structure = { + "symlink1": ("symlink", "task_runs/dir1/file1.txt") + } + ending_task_runs_structure = { + "dir1": { + "file1.txt": ("file",), + "symlink2": ("symlink", "external/dir3/file3.txt") + } + } + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + ending_structure["external"] = { + "dir3": { + "file3.txt": ("file",), + "symlink3": ("symlink", None) + } + } + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + def test_outside_task_runs_doesnt_get_deleted(self): + starting_symlinks_structure = {} + starting_task_runs_structure = { + "dir1": {} + } + starting_structure = CleanTests.make_workspace_structure(starting_symlinks_structure, starting_task_runs_structure) + starting_structure["external"] = { + "file1.txt": ("file",) + } + ending_symlinks_structure = {} + ending_task_runs_structure = {} + ending_structure = CleanTests.make_workspace_structure(ending_symlinks_structure, ending_task_runs_structure) + ending_structure["external"] = { + "file1.txt": ("file",) + } + + CleanTests.create_structure(self.scratchspace_path, starting_structure) + clean_workspace(MockDBGymConfig(self.scratchspace_path), mode="safe") + self.assertTrue(CleanTests.verify_structure(self.scratchspace_path, ending_structure)) + + +if __name__ == '__main__': + unittest.main() diff --git a/misc/utils.py b/misc/utils.py index fb1dbde4..380cafca 100644 --- a/misc/utils.py +++ b/misc/utils.py @@ -38,6 +38,9 @@ def get_symlinks_path_from_workspace_path(workspace_path): def get_tmp_path_from_workspace_path(workspace_path): return workspace_path / "tmp" +def get_runs_path_from_workspace_path(workspace_path): + return workspace_path / "task_runs" + def get_scale_factor_string(scale_factor: float | str) -> str: assert type(scale_factor) is float or type(scale_factor) is str if scale_factor == SCALE_FACTOR_PLACEHOLDER: @@ -313,21 +316,44 @@ def is_base_git_dir(cwd) -> bool: return False -def parent_dir(dpath: os.PathLike) -> os.PathLike: +def is_fully_resolved(path: Path) -> bool: + assert isinstance(path, Path) + resolved_path = path.resolve() + # Converting them to strings is the most unambiguously strict way of checking equality. + # Stuff like Path.__eq__() or os.path.samefile() might be more lenient. + return str(resolved_path) == str(path) + + +def path_exists_dont_follow_symlinks(path: Path) -> bool: + """ + As of writing this comment, ray is currently constraining us to python <3.12. However, the "follow_symlinks" option in + Path.exists() only comes up in python 3.12. Thus, this is the only way to check if a path exists without following symlinks. + """ + # If the path exists and is a symlink, os.path.islink() will be true (even if the symlink is broken) + if os.path.islink(path): + return True + # Otherwise, we know it's either non-existent or not a symlink, so path.exists() works fine + else: + return path.exists() + + +def parent_dpath_of_path(dpath: Path) -> Path: """ - Return a path of the parent directory of a directory path - Note that os.path.dirname() does not always return the parent directory (it only does when the path doesn't end with a '/') + This function only calls Path.parent, but in a safer way. """ - assert os.path.isdir(dpath) and os.path.isabs(dpath) - return os.path.abspath(os.path.join(dpath, os.pardir)) + assert isinstance(dpath, Path) + assert is_fully_resolved(dpath), f"dpath must be fully resolved because Path.parent has weird behavior on non-resolved paths (see https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.parent)" + parent_dpath = dpath.parent + assert isinstance(parent_dpath, Path) + return parent_dpath -def dir_basename(dpath: os.PathLike) -> str: +def basename_of_path(dpath: Path) -> str: """ - Return the directory name of a directory path - Note that os.path.basename() does not always return the directory name (it only does when the path doesn't end with a '/') + This function only calls Path.name, but in a safer way. """ - assert os.path.isdir(dpath) and os.path.isabs(dpath) + assert isinstance(dpath, Path) + assert is_fully_resolved(dpath), f"dpath must be fully resolved because Path.name has weird behavior on non-resolved paths (like giving \"..\" if the path ends with a \"..\")" dpath_dirname, dpath_basename = os.path.split(dpath) # this means the path ended with a '/' so all os.path.split() does is get rid of the slash if dpath_basename == "": @@ -339,11 +365,15 @@ def dir_basename(dpath: os.PathLike) -> str: def is_child_path(child_path: os.PathLike, parent_dpath: os.PathLike) -> bool: """ Checks whether child_path refers to a file/dir/link that is a child of the dir referred to by parent_dpath + If the two paths are equal, this function returns FALSE """ assert os.path.isdir(parent_dpath) - return os.path.samefile( - os.path.commonpath([parent_dpath, child_path]), parent_dpath - ) + if os.path.samefile(child_path, parent_dpath): + return False + else: + return os.path.samefile( + os.path.commonpath([parent_dpath, child_path]), parent_dpath + ) def open_and_save(dbgym_cfg: DBGymConfig, open_fpath: Path, mode="r"): @@ -364,11 +394,10 @@ def open_and_save(dbgym_cfg: DBGymConfig, open_fpath: Path, mode="r"): - If you open two "config" files of the same name but different paths, only the first open will be saved. - Opening two "dependency" files of the same name but different paths will lead to two different "base dirs" being symlinked. """ - # validate open_fpath - assert isinstance(open_fpath, Path) - assert os.path.isabs( + # process/validate open_fpath + assert is_fully_resolved( open_fpath - ), f"open_and_save(): open_fpath ({open_fpath}) should be an absolute path" + ), f"open_and_save(): open_fpath ({open_fpath}) should be a fully resolved path" assert not os.path.islink(open_fpath), f"open_fpath ({open_fpath}) should not be a symlink" assert os.path.exists(open_fpath), f"open_fpath ({open_fpath}) does not exist" # open_and_save *must* be called on files because it doesn't make sense to open a directory. note that this doesn't mean we'll always save @@ -393,20 +422,20 @@ def extract_from_task_run_fordpath(dbgym_cfg: DBGymConfig, task_run_fordpath: Pa parent_dpath, dbgym_cfg.dbgym_runs_path ), f"task_run_fordpath ({task_run_fordpath}) should be inside a run_*/ dir instead of directly in dbgym_cfg.dbgym_runs_path ({dbgym_cfg.dbgym_runs_path})" assert not os.path.samefile( - parent_dir(parent_dpath), dbgym_cfg.dbgym_runs_path + parent_dpath_of_path(parent_dpath), dbgym_cfg.dbgym_runs_path ), f"task_run_fordpath ({task_run_fordpath}) should be inside a run_*/[codebase]/ dir instead of directly in run_*/ ({dbgym_cfg.dbgym_runs_path})" assert not os.path.samefile( - parent_dir(parent_dir(parent_dpath)), dbgym_cfg.dbgym_runs_path + parent_dpath_of_path(parent_dpath_of_path(parent_dpath)), dbgym_cfg.dbgym_runs_path ), f"task_run_fordpath ({task_run_fordpath}) should be inside a run_*/[codebase]/[organization]/ dir instead of directly in run_*/ ({dbgym_cfg.dbgym_runs_path})" # org_dpath is the run_*/[codebase]/[organization]/ dir that task_run_fordpath is in org_dpath = parent_dpath while not os.path.samefile( - parent_dir(parent_dir(parent_dir(org_dpath))), dbgym_cfg.dbgym_runs_path + parent_dpath_of_path(parent_dpath_of_path(parent_dpath_of_path(org_dpath))), dbgym_cfg.dbgym_runs_path ): - org_dpath = parent_dir(org_dpath) - org_dname = dir_basename(org_dpath) - codebase_dpath = parent_dir(org_dpath) - codebase_dname = dir_basename(codebase_dpath) + org_dpath = parent_dpath_of_path(org_dpath) + org_dname = basename_of_path(org_dpath) + codebase_dpath = parent_dpath_of_path(org_dpath) + codebase_dname = basename_of_path(codebase_dpath) return codebase_dpath, codebase_dname, org_dpath, org_dname @@ -422,8 +451,12 @@ def save_file(dbgym_cfg: DBGymConfig, fpath: Path) -> Path: We create a symlink if it is a "dependency", meaning a task.py command was run to generate it In these cases we create a symlink so we have full provenance for how the dependency was created """ - # validate fpath - assert isinstance(fpath, Path) + # process fpath and ensure that it's a file at the end + fpath = conv_inputpath_to_realabspath(dbgym_cfg, fpath) + fpath = os.path.realpath(fpath) # traverse symlinks + assert is_fully_resolved( + fpath + ), f"fpath ({fpath}) should be a fully resolved path" assert not os.path.islink(fpath), f"fpath ({fpath}) should not be a symlink" assert os.path.exists(fpath), f"fpath ({fpath}) does not exist" assert os.path.isfile(fpath), f"fpath ({fpath}) is not a file" @@ -437,8 +470,28 @@ def save_file(dbgym_cfg: DBGymConfig, fpath: Path) -> Path: # 2. files or dirs generated by a run may be very large (up to 100s of GBs) so we don't want to copy them if is_child_path(fpath, dbgym_cfg.dbgym_runs_path): # get paths we'll need later. - _, codebase_dname, org_dpath, org_dname = extract_from_task_run_fordpath(dbgym_cfg, fpath) - this_run_save_dpath = dbgym_cfg.dbgym_this_run_path / codebase_dname / org_dname + parent_dpath = os.path.dirname(fpath) + assert not os.path.samefile( + parent_dpath, dbgym_cfg.dbgym_runs_path + ), f"fpath ({fpath}) should be inside a run_*/ dir instead of directly in dbgym_cfg.dbgym_runs_path ({dbgym_cfg.dbgym_runs_path})" + assert not os.path.samefile( + parent_dpath_of_path(parent_dpath), dbgym_cfg.dbgym_runs_path + ), f"fpath ({fpath}) should be inside a run_*/[codebase]/ dir instead of directly in run_*/ ({dbgym_cfg.dbgym_runs_path})" + assert not os.path.samefile( + parent_dpath_of_path(parent_dpath_of_path(parent_dpath)), dbgym_cfg.dbgym_runs_path + ), f"fpath ({fpath}) should be inside a run_*/[codebase]/[organization]/ dir instead of directly in run_*/ ({dbgym_cfg.dbgym_runs_path})" + # org_dpath is the run_*/[codebase]/[organization]/ dir that fpath is in + org_dpath = parent_dpath + while not os.path.samefile( + parent_dpath_of_path(parent_dpath_of_path(parent_dpath_of_path(org_dpath))), dbgym_cfg.dbgym_runs_path + ): + org_dpath = parent_dpath_of_path(org_dpath) + org_dname = basename_of_path(org_dpath) + codebase_dpath = parent_dpath_of_path(org_dpath) + codebase_dname = basename_of_path(codebase_dpath) + this_run_save_dpath = os.path.join( + dbgym_cfg.dbgym_this_run_path, codebase_dname, org_dname + ) os.makedirs(this_run_save_dpath, exist_ok=True) # if the fpath file is directly in org_dpath, we symlink the file directly @@ -453,12 +506,12 @@ def save_file(dbgym_cfg: DBGymConfig, fpath: Path) -> Path: else: # set base_dpath such that its parent is org_dpath base_dpath = parent_dpath - while not os.path.samefile(parent_dir(base_dpath), org_dpath): - base_dpath = parent_dir(base_dpath) + while not os.path.samefile(parent_dpath_of_path(base_dpath), org_dpath): + base_dpath = parent_dpath_of_path(base_dpath) # create symlink - open_base_dname = dir_basename(base_dpath) - symlink_dpath = this_run_save_dpath / (open_base_dname + ".link") + open_base_dname = basename_of_path(base_dpath) + symlink_dpath = os.path.join(this_run_save_dpath, open_base_dname) try_create_symlink(base_dpath, symlink_dpath) # if it wasn't generated by a run else: @@ -483,17 +536,18 @@ def link_result(dbgym_cfg: DBGymConfig, result_fordpath: Path, custom_result_nam version of a file. This function will return the path to the symlink that was created. """ - result_fordpath = conv_inputpath_to_realabspath(dbgym_cfg, result_fordpath) - assert is_child_path(result_fordpath, dbgym_cfg.dbgym_this_run_path) - assert not os.path.islink(result_fordpath) + assert is_fully_resolved(result_path), f"result_path ({result_path}) should be a fully resolved path" + result_path = conv_inputpath_to_realabspath(dbgym_cfg, result_path) + assert is_child_path(result_path, dbgym_cfg.dbgym_this_run_path) + assert not os.path.islink(result_path) if custom_result_name != None: result_name = custom_result_name else: - if os.path.isfile(result_fordpath): - result_name = os.path.basename(result_fordpath) + ".link" - elif os.path.isdir(result_fordpath): - result_name = dir_basename(result_fordpath) + ".link" + if os.path.isfile(result_path): + result_name = os.path.basename(result_path) + elif os.path.isdir(result_path): + result_name = basename_of_path(result_path) else: raise AssertionError("result_fordpath must be either a file or dir") @@ -521,7 +575,6 @@ def try_create_symlink(src_path: Path, dst_path: Path) -> None: Our functions that create symlinks might be called by multiple processes at once during HPO. Thus, this is a thread-safe way to create a symlink. """ - assert dst_path.name.endswith(".link") and not dst_path.name.endswith(".link.link") try: os.symlink(src_path, dst_path) except FileExistsError: diff --git a/task.py b/task.py index c20cdf62..31a5bd12 100644 --- a/task.py +++ b/task.py @@ -1,22 +1,17 @@ import logging -from pathlib import Path - import click -import yaml +from misc.utils import DBGymConfig from benchmark.cli import benchmark_group from dbms.cli import dbms_group from misc.utils import DBGymConfig from tune.cli import tune_group +from manage.cli import manage_group # TODO(phw2): save commit, git diff, and run command # TODO(phw2): remove write permissions on old run_*/ dirs to enforce that they are immutable -task_logger = logging.getLogger("task") -task_logger.setLevel(logging.INFO) - - @click.group() @click.option("--config-path", default="config.yaml") @click.pass_context @@ -25,79 +20,13 @@ def task(ctx, config_path): ctx.obj = DBGymConfig(config_path) -@click.group(name="config") -def config_group(): - pass - - -@config_group.command(name="show") -@click.argument("keys", nargs=-1) -@click.pass_obj -def config_show(dbgym_cfg, keys): - config_path = dbgym_cfg.path - config_yaml = dbgym_cfg.yaml - - # Traverse the YAML. - for key in keys: - config_yaml = config_yaml[key] - - # Pretty-print the requested YAML value. - output_str = None - if type(config_yaml) != dict: - output_str = config_yaml - else: - output_str = yaml.dump(config_yaml, default_flow_style=False) - if len(keys) > 0: - output_str = " " + output_str.replace("\n", "\n ") - output_str = output_str.rstrip() - print(output_str) - - task_logger.info(f"Read: {Path(config_path)}") - - -@config_group.command(name="write") -@click.argument("keys", nargs=-1) -@click.argument("value_type") -@click.argument("value") -@click.pass_obj -def config_write(dbgym_cfg, keys, value_type, value): - config_path = dbgym_cfg.path - config_yaml = dbgym_cfg.yaml - - # Traverse the YAML. - root_yaml = config_yaml - for key in keys[:-1]: - config_yaml = config_yaml[key] - - # Modify the requested YAML value and write the YAML file. - assert type(config_yaml[keys[-1]]) != dict - config_yaml[keys[-1]] = getattr(__builtins__, value_type)(value) - new_yaml = yaml.dump(root_yaml, default_flow_style=False).rstrip() - Path(config_path).write_text(new_yaml) - - task_logger.info(f"Updated: {Path(config_path)}") - - -@config_group.command(name="standardize") -@click.pass_obj -def config_standardize(dbgym_cfg): - config_path = dbgym_cfg.path - config_yaml = dbgym_cfg.yaml - - # Write the YAML file. - new_yaml = yaml.dump(config_yaml, default_flow_style=False).rstrip() - Path(config_path).write_text(new_yaml) - - task_logger.info(f"Updated: {Path(config_path)}") - - if __name__ == "__main__": logging.basicConfig( format="%(asctime)s:%(name)s:%(levelname)s - %(message)s", level=logging.INFO ) task.add_command(benchmark_group) - task.add_command(config_group) + task.add_command(manage_group) task.add_command(dbms_group) task.add_command(tune_group) task() diff --git a/tune/protox/env/util/pg_conn.py b/tune/protox/env/util/pg_conn.py index 69b2c701..b28a75bb 100644 --- a/tune/protox/env/util/pg_conn.py +++ b/tune/protox/env/util/pg_conn.py @@ -19,7 +19,7 @@ import yaml from tune.protox.env.logger import Logger, time_record -from misc.utils import DBGymConfig, link_result, open_and_save, parent_dir +from misc.utils import DBGymConfig, link_result, open_and_save, parent_dpath_of_path from util.pg import DBGYM_POSTGRES_USER, DBGYM_POSTGRES_PASS, DBGYM_POSTGRES_DBNAME, SHARED_PRELOAD_LIBRARIES @@ -153,7 +153,7 @@ def start_with_changes( # still have the previous checkpoint available to us f"{self.checkpoint_dbdata_snapshot_fpath}.tmp", "-C", - parent_dir(self.dbdata_dpath), + parent_dpath_of_path(self.dbdata_dpath), self.dbdata_dpath, ].run() diff --git a/tune/protox/tests/__init__.py b/tune/protox/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tune/protox/test/test_index_space.py b/tune/protox/tests/test_index_space.py similarity index 95% rename from tune/protox/test/test_index_space.py rename to tune/protox/tests/test_index_space.py index 2884f758..6e583b36 100644 --- a/tune/protox/test/test_index_space.py +++ b/tune/protox/tests/test_index_space.py @@ -11,7 +11,7 @@ class IndexSpaceTests(unittest.TestCase): @staticmethod def load( - config_path=Path("tune/protox/test/unittest_benchmark_configs/unittest_tpch.yaml"), + config_path=Path("tune/protox/tests/unittest_benchmark_configs/unittest_tpch.yaml"), aux_type=True, aux_include=True, ): @@ -27,7 +27,7 @@ def load( tables=benchmark_config["tables"], attributes=benchmark_config["attributes"], query_spec=benchmark_config["query_spec"], - workload_path=Path("tune/protox/test/unittest_tpch_dir"), + workload_path=Path("tune/protox/tests/unittest_tpch_dir"), pid=None, workload_timeout=0, workload_timeout_penalty=1.0, diff --git a/tune/protox/test/test_primitive.py b/tune/protox/tests/test_primitive.py similarity index 100% rename from tune/protox/test/test_primitive.py rename to tune/protox/tests/test_primitive.py diff --git a/tune/protox/test/test_workload.py b/tune/protox/tests/test_workload.py similarity index 75% rename from tune/protox/test/test_workload.py rename to tune/protox/tests/test_workload.py index a1e4b97c..ac4a0223 100644 --- a/tune/protox/test/test_workload.py +++ b/tune/protox/tests/test_workload.py @@ -49,52 +49,48 @@ def diff_classmapping(self, ref, target): self.assertTrue(v == target[k]) def test_tpch(self): - with open("tune/protox/test/unittest_ref_models/ref_tpch_model.txt", "r") as f: + with open("tune/protox/tests/unittest_ref_models/ref_tpch_model.txt", "r") as f: ref = json.load(f)["class_mapping"] ref = { (v["relname"], v["ord_column"]): int(k) for k, v in ref.items() } - w, i = WorkloadTests.load("tune/protox/test/unittest_benchmark_configs/unittest_tpch.yaml", Path("tune/protox/test/unittest_tpch_dir")) + w, i = WorkloadTests.load("tune/protox/tests/unittest_benchmark_configs/unittest_tpch.yaml", Path("tune/protox/tests/unittest_tpch_dir")) self.assertEqual(i.class_mapping, ref) def test_job(self): # don't call open_and_save() because this is a unittest - with open("tune/protox/test/unittest_ref_models/ref_job_full_model.txt", "r") as f: + with open("tune/protox/tests/unittest_ref_models/ref_job_full_model.txt", "r") as f: ref = json.load(f)["class_mapping"] ref = { (v["relname"], v["ord_column"]): int(k) for k, v in ref.items() } - w, i = WorkloadTests.load("tune/protox/test/unittest_benchmark_configs/unittest_job_full.yaml", Path("tune/protox/test/unittest_job_full_dir")) + w, i = WorkloadTests.load("tune/protox/tests/unittest_benchmark_configs/unittest_job_full.yaml", Path("tune/protox/tests/unittest_job_full_dir")) self.assertEqual(i.class_mapping, ref) def test_dsb(self): # don't call open_and_save() because this is a unittest - with open("tune/protox/test/unittest_ref_models/ref_dsb_model.txt", "r") as f: + with open("tune/protox/tests/unittest_ref_models/ref_dsb_model.txt", "r") as f: ref = json.load(f)["class_mapping"] ref = { (v["relname"], v["ord_column"]): int(k) for k, v in ref.items() } - w, i = WorkloadTests.load("tune/protox/test/unittest_benchmark_configs/unittest_dsb.yaml", Path("tune/protox/test/unittest_dsb_dir")) + w, i = WorkloadTests.load("tune/protox/tests/unittest_benchmark_configs/unittest_dsb.yaml", Path("tune/protox/tests/unittest_dsb_dir")) self.diff_classmapping(ref, i.class_mapping) def test_tpcc(self): # don't call open_and_save() because this is a unittest - with open("tune/protox/test/unittest_ref_models/ref_tpcc_model.txt", "r") as f: + with open("tune/protox/tests/unittest_ref_models/ref_tpcc_model.txt", "r") as f: ref = json.load(f)["class_mapping"] ref = { (v["relname"], v["ord_column"]): int(k) for k, v in ref.items() } - w, i = WorkloadTests.load("tune/protox/test/unittest_benchmark_configs/unittest_tpcc.yaml", Path("tune/protox/test/unittest_tpcc_dir")) + w, i = WorkloadTests.load("tune/protox/tests/unittest_benchmark_configs/unittest_tpcc.yaml", Path("tune/protox/tests/unittest_tpcc_dir")) self.assertEqual(i.class_mapping, ref) - - -if __name__ == "__main__": - unittest.main() diff --git a/tune/protox/test/test_workload_utils.py b/tune/protox/tests/test_workload_utils.py similarity index 100% rename from tune/protox/test/test_workload_utils.py rename to tune/protox/tests/test_workload_utils.py diff --git a/tune/protox/test/unittest_benchmark_configs/unittest_dsb.yaml b/tune/protox/tests/unittest_benchmark_configs/unittest_dsb.yaml similarity index 100% rename from tune/protox/test/unittest_benchmark_configs/unittest_dsb.yaml rename to tune/protox/tests/unittest_benchmark_configs/unittest_dsb.yaml diff --git a/tune/protox/test/unittest_benchmark_configs/unittest_job_full.yaml b/tune/protox/tests/unittest_benchmark_configs/unittest_job_full.yaml similarity index 100% rename from tune/protox/test/unittest_benchmark_configs/unittest_job_full.yaml rename to tune/protox/tests/unittest_benchmark_configs/unittest_job_full.yaml diff --git a/tune/protox/test/unittest_benchmark_configs/unittest_tpcc.yaml b/tune/protox/tests/unittest_benchmark_configs/unittest_tpcc.yaml similarity index 100% rename from tune/protox/test/unittest_benchmark_configs/unittest_tpcc.yaml rename to tune/protox/tests/unittest_benchmark_configs/unittest_tpcc.yaml diff --git a/tune/protox/test/unittest_benchmark_configs/unittest_tpch.yaml b/tune/protox/tests/unittest_benchmark_configs/unittest_tpch.yaml similarity index 100% rename from tune/protox/test/unittest_benchmark_configs/unittest_tpch.yaml rename to tune/protox/tests/unittest_benchmark_configs/unittest_tpch.yaml diff --git a/tune/protox/test/unittest_dsb_dir/order.txt b/tune/protox/tests/unittest_dsb_dir/order.txt similarity index 100% rename from tune/protox/test/unittest_dsb_dir/order.txt rename to tune/protox/tests/unittest_dsb_dir/order.txt diff --git a/tune/protox/test/unittest_dsb_dir/query001s0.sql b/tune/protox/tests/unittest_dsb_dir/query001s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query001s0.sql rename to tune/protox/tests/unittest_dsb_dir/query001s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query010s0.sql b/tune/protox/tests/unittest_dsb_dir/query010s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query010s0.sql rename to tune/protox/tests/unittest_dsb_dir/query010s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query013s0.sql b/tune/protox/tests/unittest_dsb_dir/query013s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query013s0.sql rename to tune/protox/tests/unittest_dsb_dir/query013s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query013s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query013s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query013s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query013s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query014s0.sql b/tune/protox/tests/unittest_dsb_dir/query014s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query014s0.sql rename to tune/protox/tests/unittest_dsb_dir/query014s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query018s0.sql b/tune/protox/tests/unittest_dsb_dir/query018s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query018s0.sql rename to tune/protox/tests/unittest_dsb_dir/query018s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query018s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query018s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query018s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query018s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query019s0.sql b/tune/protox/tests/unittest_dsb_dir/query019s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query019s0.sql rename to tune/protox/tests/unittest_dsb_dir/query019s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query019s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query019s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query019s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query019s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query023s0.sql b/tune/protox/tests/unittest_dsb_dir/query023s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query023s0.sql rename to tune/protox/tests/unittest_dsb_dir/query023s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query025s0.sql b/tune/protox/tests/unittest_dsb_dir/query025s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query025s0.sql rename to tune/protox/tests/unittest_dsb_dir/query025s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query025s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query025s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query025s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query025s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query027s0.sql b/tune/protox/tests/unittest_dsb_dir/query027s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query027s0.sql rename to tune/protox/tests/unittest_dsb_dir/query027s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query027s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query027s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query027s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query027s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query030s0.sql b/tune/protox/tests/unittest_dsb_dir/query030s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query030s0.sql rename to tune/protox/tests/unittest_dsb_dir/query030s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query031s0.sql b/tune/protox/tests/unittest_dsb_dir/query031s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query031s0.sql rename to tune/protox/tests/unittest_dsb_dir/query031s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query032s0.sql b/tune/protox/tests/unittest_dsb_dir/query032s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query032s0.sql rename to tune/protox/tests/unittest_dsb_dir/query032s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query038s0.sql b/tune/protox/tests/unittest_dsb_dir/query038s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query038s0.sql rename to tune/protox/tests/unittest_dsb_dir/query038s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query039as0.sql b/tune/protox/tests/unittest_dsb_dir/query039as0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query039as0.sql rename to tune/protox/tests/unittest_dsb_dir/query039as0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query039bs0.sql b/tune/protox/tests/unittest_dsb_dir/query039bs0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query039bs0.sql rename to tune/protox/tests/unittest_dsb_dir/query039bs0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query040s0.sql b/tune/protox/tests/unittest_dsb_dir/query040s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query040s0.sql rename to tune/protox/tests/unittest_dsb_dir/query040s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query040s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query040s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query040s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query040s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query050s0.sql b/tune/protox/tests/unittest_dsb_dir/query050s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query050s0.sql rename to tune/protox/tests/unittest_dsb_dir/query050s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query050s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query050s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query050s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query050s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query054s0.sql b/tune/protox/tests/unittest_dsb_dir/query054s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query054s0.sql rename to tune/protox/tests/unittest_dsb_dir/query054s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query058s0.sql b/tune/protox/tests/unittest_dsb_dir/query058s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query058s0.sql rename to tune/protox/tests/unittest_dsb_dir/query058s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query059s0.sql b/tune/protox/tests/unittest_dsb_dir/query059s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query059s0.sql rename to tune/protox/tests/unittest_dsb_dir/query059s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query064s0.sql b/tune/protox/tests/unittest_dsb_dir/query064s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query064s0.sql rename to tune/protox/tests/unittest_dsb_dir/query064s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query065s0.sql b/tune/protox/tests/unittest_dsb_dir/query065s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query065s0.sql rename to tune/protox/tests/unittest_dsb_dir/query065s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query069s0.sql b/tune/protox/tests/unittest_dsb_dir/query069s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query069s0.sql rename to tune/protox/tests/unittest_dsb_dir/query069s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query072s0.sql b/tune/protox/tests/unittest_dsb_dir/query072s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query072s0.sql rename to tune/protox/tests/unittest_dsb_dir/query072s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query072s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query072s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query072s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query072s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query075s0.sql b/tune/protox/tests/unittest_dsb_dir/query075s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query075s0.sql rename to tune/protox/tests/unittest_dsb_dir/query075s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query080s0.sql b/tune/protox/tests/unittest_dsb_dir/query080s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query080s0.sql rename to tune/protox/tests/unittest_dsb_dir/query080s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query081s0.sql b/tune/protox/tests/unittest_dsb_dir/query081s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query081s0.sql rename to tune/protox/tests/unittest_dsb_dir/query081s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query083s0.sql b/tune/protox/tests/unittest_dsb_dir/query083s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query083s0.sql rename to tune/protox/tests/unittest_dsb_dir/query083s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query084s0.sql b/tune/protox/tests/unittest_dsb_dir/query084s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query084s0.sql rename to tune/protox/tests/unittest_dsb_dir/query084s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query084s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query084s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query084s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query084s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query085s0.sql b/tune/protox/tests/unittest_dsb_dir/query085s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query085s0.sql rename to tune/protox/tests/unittest_dsb_dir/query085s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query085s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query085s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query085s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query085s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query087s0.sql b/tune/protox/tests/unittest_dsb_dir/query087s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query087s0.sql rename to tune/protox/tests/unittest_dsb_dir/query087s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query091s0.sql b/tune/protox/tests/unittest_dsb_dir/query091s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query091s0.sql rename to tune/protox/tests/unittest_dsb_dir/query091s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query091s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query091s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query091s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query091s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query092s0.sql b/tune/protox/tests/unittest_dsb_dir/query092s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query092s0.sql rename to tune/protox/tests/unittest_dsb_dir/query092s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query094s0.sql b/tune/protox/tests/unittest_dsb_dir/query094s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query094s0.sql rename to tune/protox/tests/unittest_dsb_dir/query094s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query099s0.sql b/tune/protox/tests/unittest_dsb_dir/query099s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query099s0.sql rename to tune/protox/tests/unittest_dsb_dir/query099s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query099s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query099s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query099s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query099s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query100s0.sql b/tune/protox/tests/unittest_dsb_dir/query100s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query100s0.sql rename to tune/protox/tests/unittest_dsb_dir/query100s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query100s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query100s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query100s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query100s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query101s0.sql b/tune/protox/tests/unittest_dsb_dir/query101s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query101s0.sql rename to tune/protox/tests/unittest_dsb_dir/query101s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query101s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query101s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query101s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query101s0_spj.sql diff --git a/tune/protox/test/unittest_dsb_dir/query102s0.sql b/tune/protox/tests/unittest_dsb_dir/query102s0.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query102s0.sql rename to tune/protox/tests/unittest_dsb_dir/query102s0.sql diff --git a/tune/protox/test/unittest_dsb_dir/query102s0_spj.sql b/tune/protox/tests/unittest_dsb_dir/query102s0_spj.sql similarity index 100% rename from tune/protox/test/unittest_dsb_dir/query102s0_spj.sql rename to tune/protox/tests/unittest_dsb_dir/query102s0_spj.sql diff --git a/tune/protox/test/unittest_job_full_dir/1.sql b/tune/protox/tests/unittest_job_full_dir/1.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/1.sql rename to tune/protox/tests/unittest_job_full_dir/1.sql diff --git a/tune/protox/test/unittest_job_full_dir/10.sql b/tune/protox/tests/unittest_job_full_dir/10.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/10.sql rename to tune/protox/tests/unittest_job_full_dir/10.sql diff --git a/tune/protox/test/unittest_job_full_dir/10b.sql b/tune/protox/tests/unittest_job_full_dir/10b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/10b.sql rename to tune/protox/tests/unittest_job_full_dir/10b.sql diff --git a/tune/protox/test/unittest_job_full_dir/10c.sql b/tune/protox/tests/unittest_job_full_dir/10c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/10c.sql rename to tune/protox/tests/unittest_job_full_dir/10c.sql diff --git a/tune/protox/test/unittest_job_full_dir/11.sql b/tune/protox/tests/unittest_job_full_dir/11.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/11.sql rename to tune/protox/tests/unittest_job_full_dir/11.sql diff --git a/tune/protox/test/unittest_job_full_dir/11b.sql b/tune/protox/tests/unittest_job_full_dir/11b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/11b.sql rename to tune/protox/tests/unittest_job_full_dir/11b.sql diff --git a/tune/protox/test/unittest_job_full_dir/11c.sql b/tune/protox/tests/unittest_job_full_dir/11c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/11c.sql rename to tune/protox/tests/unittest_job_full_dir/11c.sql diff --git a/tune/protox/test/unittest_job_full_dir/11d.sql b/tune/protox/tests/unittest_job_full_dir/11d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/11d.sql rename to tune/protox/tests/unittest_job_full_dir/11d.sql diff --git a/tune/protox/test/unittest_job_full_dir/12.sql b/tune/protox/tests/unittest_job_full_dir/12.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/12.sql rename to tune/protox/tests/unittest_job_full_dir/12.sql diff --git a/tune/protox/test/unittest_job_full_dir/12b.sql b/tune/protox/tests/unittest_job_full_dir/12b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/12b.sql rename to tune/protox/tests/unittest_job_full_dir/12b.sql diff --git a/tune/protox/test/unittest_job_full_dir/12c.sql b/tune/protox/tests/unittest_job_full_dir/12c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/12c.sql rename to tune/protox/tests/unittest_job_full_dir/12c.sql diff --git a/tune/protox/test/unittest_job_full_dir/13.sql b/tune/protox/tests/unittest_job_full_dir/13.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/13.sql rename to tune/protox/tests/unittest_job_full_dir/13.sql diff --git a/tune/protox/test/unittest_job_full_dir/13b.sql b/tune/protox/tests/unittest_job_full_dir/13b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/13b.sql rename to tune/protox/tests/unittest_job_full_dir/13b.sql diff --git a/tune/protox/test/unittest_job_full_dir/13c.sql b/tune/protox/tests/unittest_job_full_dir/13c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/13c.sql rename to tune/protox/tests/unittest_job_full_dir/13c.sql diff --git a/tune/protox/test/unittest_job_full_dir/13d.sql b/tune/protox/tests/unittest_job_full_dir/13d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/13d.sql rename to tune/protox/tests/unittest_job_full_dir/13d.sql diff --git a/tune/protox/test/unittest_job_full_dir/14.sql b/tune/protox/tests/unittest_job_full_dir/14.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/14.sql rename to tune/protox/tests/unittest_job_full_dir/14.sql diff --git a/tune/protox/test/unittest_job_full_dir/14b.sql b/tune/protox/tests/unittest_job_full_dir/14b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/14b.sql rename to tune/protox/tests/unittest_job_full_dir/14b.sql diff --git a/tune/protox/test/unittest_job_full_dir/14c.sql b/tune/protox/tests/unittest_job_full_dir/14c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/14c.sql rename to tune/protox/tests/unittest_job_full_dir/14c.sql diff --git a/tune/protox/test/unittest_job_full_dir/15.sql b/tune/protox/tests/unittest_job_full_dir/15.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/15.sql rename to tune/protox/tests/unittest_job_full_dir/15.sql diff --git a/tune/protox/test/unittest_job_full_dir/15b.sql b/tune/protox/tests/unittest_job_full_dir/15b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/15b.sql rename to tune/protox/tests/unittest_job_full_dir/15b.sql diff --git a/tune/protox/test/unittest_job_full_dir/15c.sql b/tune/protox/tests/unittest_job_full_dir/15c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/15c.sql rename to tune/protox/tests/unittest_job_full_dir/15c.sql diff --git a/tune/protox/test/unittest_job_full_dir/15d.sql b/tune/protox/tests/unittest_job_full_dir/15d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/15d.sql rename to tune/protox/tests/unittest_job_full_dir/15d.sql diff --git a/tune/protox/test/unittest_job_full_dir/16.sql b/tune/protox/tests/unittest_job_full_dir/16.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/16.sql rename to tune/protox/tests/unittest_job_full_dir/16.sql diff --git a/tune/protox/test/unittest_job_full_dir/16b.sql b/tune/protox/tests/unittest_job_full_dir/16b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/16b.sql rename to tune/protox/tests/unittest_job_full_dir/16b.sql diff --git a/tune/protox/test/unittest_job_full_dir/16c.sql b/tune/protox/tests/unittest_job_full_dir/16c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/16c.sql rename to tune/protox/tests/unittest_job_full_dir/16c.sql diff --git a/tune/protox/test/unittest_job_full_dir/16d.sql b/tune/protox/tests/unittest_job_full_dir/16d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/16d.sql rename to tune/protox/tests/unittest_job_full_dir/16d.sql diff --git a/tune/protox/test/unittest_job_full_dir/17.sql b/tune/protox/tests/unittest_job_full_dir/17.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17.sql rename to tune/protox/tests/unittest_job_full_dir/17.sql diff --git a/tune/protox/test/unittest_job_full_dir/17b.sql b/tune/protox/tests/unittest_job_full_dir/17b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17b.sql rename to tune/protox/tests/unittest_job_full_dir/17b.sql diff --git a/tune/protox/test/unittest_job_full_dir/17c.sql b/tune/protox/tests/unittest_job_full_dir/17c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17c.sql rename to tune/protox/tests/unittest_job_full_dir/17c.sql diff --git a/tune/protox/test/unittest_job_full_dir/17d.sql b/tune/protox/tests/unittest_job_full_dir/17d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17d.sql rename to tune/protox/tests/unittest_job_full_dir/17d.sql diff --git a/tune/protox/test/unittest_job_full_dir/17e.sql b/tune/protox/tests/unittest_job_full_dir/17e.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17e.sql rename to tune/protox/tests/unittest_job_full_dir/17e.sql diff --git a/tune/protox/test/unittest_job_full_dir/17f.sql b/tune/protox/tests/unittest_job_full_dir/17f.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/17f.sql rename to tune/protox/tests/unittest_job_full_dir/17f.sql diff --git a/tune/protox/test/unittest_job_full_dir/18.sql b/tune/protox/tests/unittest_job_full_dir/18.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/18.sql rename to tune/protox/tests/unittest_job_full_dir/18.sql diff --git a/tune/protox/test/unittest_job_full_dir/18b.sql b/tune/protox/tests/unittest_job_full_dir/18b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/18b.sql rename to tune/protox/tests/unittest_job_full_dir/18b.sql diff --git a/tune/protox/test/unittest_job_full_dir/18c.sql b/tune/protox/tests/unittest_job_full_dir/18c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/18c.sql rename to tune/protox/tests/unittest_job_full_dir/18c.sql diff --git a/tune/protox/test/unittest_job_full_dir/19.sql b/tune/protox/tests/unittest_job_full_dir/19.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/19.sql rename to tune/protox/tests/unittest_job_full_dir/19.sql diff --git a/tune/protox/test/unittest_job_full_dir/19b.sql b/tune/protox/tests/unittest_job_full_dir/19b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/19b.sql rename to tune/protox/tests/unittest_job_full_dir/19b.sql diff --git a/tune/protox/test/unittest_job_full_dir/19c.sql b/tune/protox/tests/unittest_job_full_dir/19c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/19c.sql rename to tune/protox/tests/unittest_job_full_dir/19c.sql diff --git a/tune/protox/test/unittest_job_full_dir/19d.sql b/tune/protox/tests/unittest_job_full_dir/19d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/19d.sql rename to tune/protox/tests/unittest_job_full_dir/19d.sql diff --git a/tune/protox/test/unittest_job_full_dir/1b.sql b/tune/protox/tests/unittest_job_full_dir/1b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/1b.sql rename to tune/protox/tests/unittest_job_full_dir/1b.sql diff --git a/tune/protox/test/unittest_job_full_dir/1c.sql b/tune/protox/tests/unittest_job_full_dir/1c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/1c.sql rename to tune/protox/tests/unittest_job_full_dir/1c.sql diff --git a/tune/protox/test/unittest_job_full_dir/1d.sql b/tune/protox/tests/unittest_job_full_dir/1d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/1d.sql rename to tune/protox/tests/unittest_job_full_dir/1d.sql diff --git a/tune/protox/test/unittest_job_full_dir/2.sql b/tune/protox/tests/unittest_job_full_dir/2.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/2.sql rename to tune/protox/tests/unittest_job_full_dir/2.sql diff --git a/tune/protox/test/unittest_job_full_dir/20.sql b/tune/protox/tests/unittest_job_full_dir/20.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/20.sql rename to tune/protox/tests/unittest_job_full_dir/20.sql diff --git a/tune/protox/test/unittest_job_full_dir/20b.sql b/tune/protox/tests/unittest_job_full_dir/20b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/20b.sql rename to tune/protox/tests/unittest_job_full_dir/20b.sql diff --git a/tune/protox/test/unittest_job_full_dir/20c.sql b/tune/protox/tests/unittest_job_full_dir/20c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/20c.sql rename to tune/protox/tests/unittest_job_full_dir/20c.sql diff --git a/tune/protox/test/unittest_job_full_dir/21.sql b/tune/protox/tests/unittest_job_full_dir/21.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/21.sql rename to tune/protox/tests/unittest_job_full_dir/21.sql diff --git a/tune/protox/test/unittest_job_full_dir/21b.sql b/tune/protox/tests/unittest_job_full_dir/21b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/21b.sql rename to tune/protox/tests/unittest_job_full_dir/21b.sql diff --git a/tune/protox/test/unittest_job_full_dir/21c.sql b/tune/protox/tests/unittest_job_full_dir/21c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/21c.sql rename to tune/protox/tests/unittest_job_full_dir/21c.sql diff --git a/tune/protox/test/unittest_job_full_dir/22.sql b/tune/protox/tests/unittest_job_full_dir/22.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/22.sql rename to tune/protox/tests/unittest_job_full_dir/22.sql diff --git a/tune/protox/test/unittest_job_full_dir/22b.sql b/tune/protox/tests/unittest_job_full_dir/22b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/22b.sql rename to tune/protox/tests/unittest_job_full_dir/22b.sql diff --git a/tune/protox/test/unittest_job_full_dir/22c.sql b/tune/protox/tests/unittest_job_full_dir/22c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/22c.sql rename to tune/protox/tests/unittest_job_full_dir/22c.sql diff --git a/tune/protox/test/unittest_job_full_dir/22d.sql b/tune/protox/tests/unittest_job_full_dir/22d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/22d.sql rename to tune/protox/tests/unittest_job_full_dir/22d.sql diff --git a/tune/protox/test/unittest_job_full_dir/23.sql b/tune/protox/tests/unittest_job_full_dir/23.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/23.sql rename to tune/protox/tests/unittest_job_full_dir/23.sql diff --git a/tune/protox/test/unittest_job_full_dir/23b.sql b/tune/protox/tests/unittest_job_full_dir/23b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/23b.sql rename to tune/protox/tests/unittest_job_full_dir/23b.sql diff --git a/tune/protox/test/unittest_job_full_dir/23c.sql b/tune/protox/tests/unittest_job_full_dir/23c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/23c.sql rename to tune/protox/tests/unittest_job_full_dir/23c.sql diff --git a/tune/protox/test/unittest_job_full_dir/24.sql b/tune/protox/tests/unittest_job_full_dir/24.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/24.sql rename to tune/protox/tests/unittest_job_full_dir/24.sql diff --git a/tune/protox/test/unittest_job_full_dir/24b.sql b/tune/protox/tests/unittest_job_full_dir/24b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/24b.sql rename to tune/protox/tests/unittest_job_full_dir/24b.sql diff --git a/tune/protox/test/unittest_job_full_dir/25.sql b/tune/protox/tests/unittest_job_full_dir/25.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/25.sql rename to tune/protox/tests/unittest_job_full_dir/25.sql diff --git a/tune/protox/test/unittest_job_full_dir/25b.sql b/tune/protox/tests/unittest_job_full_dir/25b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/25b.sql rename to tune/protox/tests/unittest_job_full_dir/25b.sql diff --git a/tune/protox/test/unittest_job_full_dir/25c.sql b/tune/protox/tests/unittest_job_full_dir/25c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/25c.sql rename to tune/protox/tests/unittest_job_full_dir/25c.sql diff --git a/tune/protox/test/unittest_job_full_dir/26.sql b/tune/protox/tests/unittest_job_full_dir/26.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/26.sql rename to tune/protox/tests/unittest_job_full_dir/26.sql diff --git a/tune/protox/test/unittest_job_full_dir/26b.sql b/tune/protox/tests/unittest_job_full_dir/26b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/26b.sql rename to tune/protox/tests/unittest_job_full_dir/26b.sql diff --git a/tune/protox/test/unittest_job_full_dir/26c.sql b/tune/protox/tests/unittest_job_full_dir/26c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/26c.sql rename to tune/protox/tests/unittest_job_full_dir/26c.sql diff --git a/tune/protox/test/unittest_job_full_dir/27.sql b/tune/protox/tests/unittest_job_full_dir/27.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/27.sql rename to tune/protox/tests/unittest_job_full_dir/27.sql diff --git a/tune/protox/test/unittest_job_full_dir/27b.sql b/tune/protox/tests/unittest_job_full_dir/27b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/27b.sql rename to tune/protox/tests/unittest_job_full_dir/27b.sql diff --git a/tune/protox/test/unittest_job_full_dir/27c.sql b/tune/protox/tests/unittest_job_full_dir/27c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/27c.sql rename to tune/protox/tests/unittest_job_full_dir/27c.sql diff --git a/tune/protox/test/unittest_job_full_dir/28.sql b/tune/protox/tests/unittest_job_full_dir/28.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/28.sql rename to tune/protox/tests/unittest_job_full_dir/28.sql diff --git a/tune/protox/test/unittest_job_full_dir/28b.sql b/tune/protox/tests/unittest_job_full_dir/28b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/28b.sql rename to tune/protox/tests/unittest_job_full_dir/28b.sql diff --git a/tune/protox/test/unittest_job_full_dir/28c.sql b/tune/protox/tests/unittest_job_full_dir/28c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/28c.sql rename to tune/protox/tests/unittest_job_full_dir/28c.sql diff --git a/tune/protox/test/unittest_job_full_dir/29.sql b/tune/protox/tests/unittest_job_full_dir/29.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/29.sql rename to tune/protox/tests/unittest_job_full_dir/29.sql diff --git a/tune/protox/test/unittest_job_full_dir/29b.sql b/tune/protox/tests/unittest_job_full_dir/29b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/29b.sql rename to tune/protox/tests/unittest_job_full_dir/29b.sql diff --git a/tune/protox/test/unittest_job_full_dir/29c.sql b/tune/protox/tests/unittest_job_full_dir/29c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/29c.sql rename to tune/protox/tests/unittest_job_full_dir/29c.sql diff --git a/tune/protox/test/unittest_job_full_dir/2b.sql b/tune/protox/tests/unittest_job_full_dir/2b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/2b.sql rename to tune/protox/tests/unittest_job_full_dir/2b.sql diff --git a/tune/protox/test/unittest_job_full_dir/2c.sql b/tune/protox/tests/unittest_job_full_dir/2c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/2c.sql rename to tune/protox/tests/unittest_job_full_dir/2c.sql diff --git a/tune/protox/test/unittest_job_full_dir/2d.sql b/tune/protox/tests/unittest_job_full_dir/2d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/2d.sql rename to tune/protox/tests/unittest_job_full_dir/2d.sql diff --git a/tune/protox/test/unittest_job_full_dir/3.sql b/tune/protox/tests/unittest_job_full_dir/3.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/3.sql rename to tune/protox/tests/unittest_job_full_dir/3.sql diff --git a/tune/protox/test/unittest_job_full_dir/30.sql b/tune/protox/tests/unittest_job_full_dir/30.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/30.sql rename to tune/protox/tests/unittest_job_full_dir/30.sql diff --git a/tune/protox/test/unittest_job_full_dir/30b.sql b/tune/protox/tests/unittest_job_full_dir/30b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/30b.sql rename to tune/protox/tests/unittest_job_full_dir/30b.sql diff --git a/tune/protox/test/unittest_job_full_dir/30c.sql b/tune/protox/tests/unittest_job_full_dir/30c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/30c.sql rename to tune/protox/tests/unittest_job_full_dir/30c.sql diff --git a/tune/protox/test/unittest_job_full_dir/31.sql b/tune/protox/tests/unittest_job_full_dir/31.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/31.sql rename to tune/protox/tests/unittest_job_full_dir/31.sql diff --git a/tune/protox/test/unittest_job_full_dir/31b.sql b/tune/protox/tests/unittest_job_full_dir/31b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/31b.sql rename to tune/protox/tests/unittest_job_full_dir/31b.sql diff --git a/tune/protox/test/unittest_job_full_dir/31c.sql b/tune/protox/tests/unittest_job_full_dir/31c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/31c.sql rename to tune/protox/tests/unittest_job_full_dir/31c.sql diff --git a/tune/protox/test/unittest_job_full_dir/32.sql b/tune/protox/tests/unittest_job_full_dir/32.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/32.sql rename to tune/protox/tests/unittest_job_full_dir/32.sql diff --git a/tune/protox/test/unittest_job_full_dir/32b.sql b/tune/protox/tests/unittest_job_full_dir/32b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/32b.sql rename to tune/protox/tests/unittest_job_full_dir/32b.sql diff --git a/tune/protox/test/unittest_job_full_dir/33.sql b/tune/protox/tests/unittest_job_full_dir/33.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/33.sql rename to tune/protox/tests/unittest_job_full_dir/33.sql diff --git a/tune/protox/test/unittest_job_full_dir/33b.sql b/tune/protox/tests/unittest_job_full_dir/33b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/33b.sql rename to tune/protox/tests/unittest_job_full_dir/33b.sql diff --git a/tune/protox/test/unittest_job_full_dir/33c.sql b/tune/protox/tests/unittest_job_full_dir/33c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/33c.sql rename to tune/protox/tests/unittest_job_full_dir/33c.sql diff --git a/tune/protox/test/unittest_job_full_dir/3b.sql b/tune/protox/tests/unittest_job_full_dir/3b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/3b.sql rename to tune/protox/tests/unittest_job_full_dir/3b.sql diff --git a/tune/protox/test/unittest_job_full_dir/3c.sql b/tune/protox/tests/unittest_job_full_dir/3c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/3c.sql rename to tune/protox/tests/unittest_job_full_dir/3c.sql diff --git a/tune/protox/test/unittest_job_full_dir/4.sql b/tune/protox/tests/unittest_job_full_dir/4.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/4.sql rename to tune/protox/tests/unittest_job_full_dir/4.sql diff --git a/tune/protox/test/unittest_job_full_dir/4b.sql b/tune/protox/tests/unittest_job_full_dir/4b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/4b.sql rename to tune/protox/tests/unittest_job_full_dir/4b.sql diff --git a/tune/protox/test/unittest_job_full_dir/4c.sql b/tune/protox/tests/unittest_job_full_dir/4c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/4c.sql rename to tune/protox/tests/unittest_job_full_dir/4c.sql diff --git a/tune/protox/test/unittest_job_full_dir/5.sql b/tune/protox/tests/unittest_job_full_dir/5.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/5.sql rename to tune/protox/tests/unittest_job_full_dir/5.sql diff --git a/tune/protox/test/unittest_job_full_dir/5b.sql b/tune/protox/tests/unittest_job_full_dir/5b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/5b.sql rename to tune/protox/tests/unittest_job_full_dir/5b.sql diff --git a/tune/protox/test/unittest_job_full_dir/5c.sql b/tune/protox/tests/unittest_job_full_dir/5c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/5c.sql rename to tune/protox/tests/unittest_job_full_dir/5c.sql diff --git a/tune/protox/test/unittest_job_full_dir/6.sql b/tune/protox/tests/unittest_job_full_dir/6.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6.sql rename to tune/protox/tests/unittest_job_full_dir/6.sql diff --git a/tune/protox/test/unittest_job_full_dir/6b.sql b/tune/protox/tests/unittest_job_full_dir/6b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6b.sql rename to tune/protox/tests/unittest_job_full_dir/6b.sql diff --git a/tune/protox/test/unittest_job_full_dir/6c.sql b/tune/protox/tests/unittest_job_full_dir/6c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6c.sql rename to tune/protox/tests/unittest_job_full_dir/6c.sql diff --git a/tune/protox/test/unittest_job_full_dir/6d.sql b/tune/protox/tests/unittest_job_full_dir/6d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6d.sql rename to tune/protox/tests/unittest_job_full_dir/6d.sql diff --git a/tune/protox/test/unittest_job_full_dir/6e.sql b/tune/protox/tests/unittest_job_full_dir/6e.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6e.sql rename to tune/protox/tests/unittest_job_full_dir/6e.sql diff --git a/tune/protox/test/unittest_job_full_dir/6f.sql b/tune/protox/tests/unittest_job_full_dir/6f.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/6f.sql rename to tune/protox/tests/unittest_job_full_dir/6f.sql diff --git a/tune/protox/test/unittest_job_full_dir/7.sql b/tune/protox/tests/unittest_job_full_dir/7.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/7.sql rename to tune/protox/tests/unittest_job_full_dir/7.sql diff --git a/tune/protox/test/unittest_job_full_dir/7b.sql b/tune/protox/tests/unittest_job_full_dir/7b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/7b.sql rename to tune/protox/tests/unittest_job_full_dir/7b.sql diff --git a/tune/protox/test/unittest_job_full_dir/7c.sql b/tune/protox/tests/unittest_job_full_dir/7c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/7c.sql rename to tune/protox/tests/unittest_job_full_dir/7c.sql diff --git a/tune/protox/test/unittest_job_full_dir/8.sql b/tune/protox/tests/unittest_job_full_dir/8.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/8.sql rename to tune/protox/tests/unittest_job_full_dir/8.sql diff --git a/tune/protox/test/unittest_job_full_dir/8b.sql b/tune/protox/tests/unittest_job_full_dir/8b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/8b.sql rename to tune/protox/tests/unittest_job_full_dir/8b.sql diff --git a/tune/protox/test/unittest_job_full_dir/8c.sql b/tune/protox/tests/unittest_job_full_dir/8c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/8c.sql rename to tune/protox/tests/unittest_job_full_dir/8c.sql diff --git a/tune/protox/test/unittest_job_full_dir/8d.sql b/tune/protox/tests/unittest_job_full_dir/8d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/8d.sql rename to tune/protox/tests/unittest_job_full_dir/8d.sql diff --git a/tune/protox/test/unittest_job_full_dir/9.sql b/tune/protox/tests/unittest_job_full_dir/9.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/9.sql rename to tune/protox/tests/unittest_job_full_dir/9.sql diff --git a/tune/protox/test/unittest_job_full_dir/9b.sql b/tune/protox/tests/unittest_job_full_dir/9b.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/9b.sql rename to tune/protox/tests/unittest_job_full_dir/9b.sql diff --git a/tune/protox/test/unittest_job_full_dir/9c.sql b/tune/protox/tests/unittest_job_full_dir/9c.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/9c.sql rename to tune/protox/tests/unittest_job_full_dir/9c.sql diff --git a/tune/protox/test/unittest_job_full_dir/9d.sql b/tune/protox/tests/unittest_job_full_dir/9d.sql similarity index 100% rename from tune/protox/test/unittest_job_full_dir/9d.sql rename to tune/protox/tests/unittest_job_full_dir/9d.sql diff --git a/tune/protox/test/unittest_job_full_dir/order.txt b/tune/protox/tests/unittest_job_full_dir/order.txt similarity index 100% rename from tune/protox/test/unittest_job_full_dir/order.txt rename to tune/protox/tests/unittest_job_full_dir/order.txt diff --git a/tune/protox/test/unittest_ref_models/ref_dsb_model.txt b/tune/protox/tests/unittest_ref_models/ref_dsb_model.txt similarity index 100% rename from tune/protox/test/unittest_ref_models/ref_dsb_model.txt rename to tune/protox/tests/unittest_ref_models/ref_dsb_model.txt diff --git a/tune/protox/test/unittest_ref_models/ref_job_full_model.txt b/tune/protox/tests/unittest_ref_models/ref_job_full_model.txt similarity index 100% rename from tune/protox/test/unittest_ref_models/ref_job_full_model.txt rename to tune/protox/tests/unittest_ref_models/ref_job_full_model.txt diff --git a/tune/protox/test/unittest_ref_models/ref_tpcc_model.txt b/tune/protox/tests/unittest_ref_models/ref_tpcc_model.txt similarity index 100% rename from tune/protox/test/unittest_ref_models/ref_tpcc_model.txt rename to tune/protox/tests/unittest_ref_models/ref_tpcc_model.txt diff --git a/tune/protox/test/unittest_ref_models/ref_tpch_model.txt b/tune/protox/tests/unittest_ref_models/ref_tpch_model.txt similarity index 100% rename from tune/protox/test/unittest_ref_models/ref_tpch_model.txt rename to tune/protox/tests/unittest_ref_models/ref_tpch_model.txt diff --git a/tune/protox/test/unittest_tpcc_dir/1.sql b/tune/protox/tests/unittest_tpcc_dir/1.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/1.sql rename to tune/protox/tests/unittest_tpcc_dir/1.sql diff --git a/tune/protox/test/unittest_tpcc_dir/10.sql b/tune/protox/tests/unittest_tpcc_dir/10.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/10.sql rename to tune/protox/tests/unittest_tpcc_dir/10.sql diff --git a/tune/protox/test/unittest_tpcc_dir/11.sql b/tune/protox/tests/unittest_tpcc_dir/11.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/11.sql rename to tune/protox/tests/unittest_tpcc_dir/11.sql diff --git a/tune/protox/test/unittest_tpcc_dir/12.sql b/tune/protox/tests/unittest_tpcc_dir/12.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/12.sql rename to tune/protox/tests/unittest_tpcc_dir/12.sql diff --git a/tune/protox/test/unittest_tpcc_dir/13.sql b/tune/protox/tests/unittest_tpcc_dir/13.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/13.sql rename to tune/protox/tests/unittest_tpcc_dir/13.sql diff --git a/tune/protox/test/unittest_tpcc_dir/14.sql b/tune/protox/tests/unittest_tpcc_dir/14.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/14.sql rename to tune/protox/tests/unittest_tpcc_dir/14.sql diff --git a/tune/protox/test/unittest_tpcc_dir/15.sql b/tune/protox/tests/unittest_tpcc_dir/15.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/15.sql rename to tune/protox/tests/unittest_tpcc_dir/15.sql diff --git a/tune/protox/test/unittest_tpcc_dir/16.sql b/tune/protox/tests/unittest_tpcc_dir/16.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/16.sql rename to tune/protox/tests/unittest_tpcc_dir/16.sql diff --git a/tune/protox/test/unittest_tpcc_dir/17.sql b/tune/protox/tests/unittest_tpcc_dir/17.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/17.sql rename to tune/protox/tests/unittest_tpcc_dir/17.sql diff --git a/tune/protox/test/unittest_tpcc_dir/18.sql b/tune/protox/tests/unittest_tpcc_dir/18.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/18.sql rename to tune/protox/tests/unittest_tpcc_dir/18.sql diff --git a/tune/protox/test/unittest_tpcc_dir/19.sql b/tune/protox/tests/unittest_tpcc_dir/19.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/19.sql rename to tune/protox/tests/unittest_tpcc_dir/19.sql diff --git a/tune/protox/test/unittest_tpcc_dir/2.sql b/tune/protox/tests/unittest_tpcc_dir/2.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/2.sql rename to tune/protox/tests/unittest_tpcc_dir/2.sql diff --git a/tune/protox/test/unittest_tpcc_dir/20.sql b/tune/protox/tests/unittest_tpcc_dir/20.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/20.sql rename to tune/protox/tests/unittest_tpcc_dir/20.sql diff --git a/tune/protox/test/unittest_tpcc_dir/21.sql b/tune/protox/tests/unittest_tpcc_dir/21.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/21.sql rename to tune/protox/tests/unittest_tpcc_dir/21.sql diff --git a/tune/protox/test/unittest_tpcc_dir/22.sql b/tune/protox/tests/unittest_tpcc_dir/22.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/22.sql rename to tune/protox/tests/unittest_tpcc_dir/22.sql diff --git a/tune/protox/test/unittest_tpcc_dir/23.sql b/tune/protox/tests/unittest_tpcc_dir/23.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/23.sql rename to tune/protox/tests/unittest_tpcc_dir/23.sql diff --git a/tune/protox/test/unittest_tpcc_dir/24.sql b/tune/protox/tests/unittest_tpcc_dir/24.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/24.sql rename to tune/protox/tests/unittest_tpcc_dir/24.sql diff --git a/tune/protox/test/unittest_tpcc_dir/25.sql b/tune/protox/tests/unittest_tpcc_dir/25.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/25.sql rename to tune/protox/tests/unittest_tpcc_dir/25.sql diff --git a/tune/protox/test/unittest_tpcc_dir/26.sql b/tune/protox/tests/unittest_tpcc_dir/26.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/26.sql rename to tune/protox/tests/unittest_tpcc_dir/26.sql diff --git a/tune/protox/test/unittest_tpcc_dir/27.sql b/tune/protox/tests/unittest_tpcc_dir/27.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/27.sql rename to tune/protox/tests/unittest_tpcc_dir/27.sql diff --git a/tune/protox/test/unittest_tpcc_dir/28.sql b/tune/protox/tests/unittest_tpcc_dir/28.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/28.sql rename to tune/protox/tests/unittest_tpcc_dir/28.sql diff --git a/tune/protox/test/unittest_tpcc_dir/29.sql b/tune/protox/tests/unittest_tpcc_dir/29.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/29.sql rename to tune/protox/tests/unittest_tpcc_dir/29.sql diff --git a/tune/protox/test/unittest_tpcc_dir/3.sql b/tune/protox/tests/unittest_tpcc_dir/3.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/3.sql rename to tune/protox/tests/unittest_tpcc_dir/3.sql diff --git a/tune/protox/test/unittest_tpcc_dir/30.sql b/tune/protox/tests/unittest_tpcc_dir/30.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/30.sql rename to tune/protox/tests/unittest_tpcc_dir/30.sql diff --git a/tune/protox/test/unittest_tpcc_dir/31.sql b/tune/protox/tests/unittest_tpcc_dir/31.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/31.sql rename to tune/protox/tests/unittest_tpcc_dir/31.sql diff --git a/tune/protox/test/unittest_tpcc_dir/32.sql b/tune/protox/tests/unittest_tpcc_dir/32.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/32.sql rename to tune/protox/tests/unittest_tpcc_dir/32.sql diff --git a/tune/protox/test/unittest_tpcc_dir/33.sql b/tune/protox/tests/unittest_tpcc_dir/33.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/33.sql rename to tune/protox/tests/unittest_tpcc_dir/33.sql diff --git a/tune/protox/test/unittest_tpcc_dir/4.sql b/tune/protox/tests/unittest_tpcc_dir/4.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/4.sql rename to tune/protox/tests/unittest_tpcc_dir/4.sql diff --git a/tune/protox/test/unittest_tpcc_dir/5.sql b/tune/protox/tests/unittest_tpcc_dir/5.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/5.sql rename to tune/protox/tests/unittest_tpcc_dir/5.sql diff --git a/tune/protox/test/unittest_tpcc_dir/6.sql b/tune/protox/tests/unittest_tpcc_dir/6.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/6.sql rename to tune/protox/tests/unittest_tpcc_dir/6.sql diff --git a/tune/protox/test/unittest_tpcc_dir/7.sql b/tune/protox/tests/unittest_tpcc_dir/7.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/7.sql rename to tune/protox/tests/unittest_tpcc_dir/7.sql diff --git a/tune/protox/test/unittest_tpcc_dir/8.sql b/tune/protox/tests/unittest_tpcc_dir/8.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/8.sql rename to tune/protox/tests/unittest_tpcc_dir/8.sql diff --git a/tune/protox/test/unittest_tpcc_dir/9.sql b/tune/protox/tests/unittest_tpcc_dir/9.sql similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/9.sql rename to tune/protox/tests/unittest_tpcc_dir/9.sql diff --git a/tune/protox/test/unittest_tpcc_dir/txn.txt b/tune/protox/tests/unittest_tpcc_dir/txn.txt similarity index 100% rename from tune/protox/test/unittest_tpcc_dir/txn.txt rename to tune/protox/tests/unittest_tpcc_dir/txn.txt diff --git a/tune/protox/test/unittest_tpch_dir/01.sql b/tune/protox/tests/unittest_tpch_dir/01.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/01.sql rename to tune/protox/tests/unittest_tpch_dir/01.sql diff --git a/tune/protox/test/unittest_tpch_dir/02.sql b/tune/protox/tests/unittest_tpch_dir/02.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/02.sql rename to tune/protox/tests/unittest_tpch_dir/02.sql diff --git a/tune/protox/test/unittest_tpch_dir/03.sql b/tune/protox/tests/unittest_tpch_dir/03.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/03.sql rename to tune/protox/tests/unittest_tpch_dir/03.sql diff --git a/tune/protox/test/unittest_tpch_dir/04.sql b/tune/protox/tests/unittest_tpch_dir/04.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/04.sql rename to tune/protox/tests/unittest_tpch_dir/04.sql diff --git a/tune/protox/test/unittest_tpch_dir/05.sql b/tune/protox/tests/unittest_tpch_dir/05.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/05.sql rename to tune/protox/tests/unittest_tpch_dir/05.sql diff --git a/tune/protox/test/unittest_tpch_dir/06.sql b/tune/protox/tests/unittest_tpch_dir/06.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/06.sql rename to tune/protox/tests/unittest_tpch_dir/06.sql diff --git a/tune/protox/test/unittest_tpch_dir/07.sql b/tune/protox/tests/unittest_tpch_dir/07.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/07.sql rename to tune/protox/tests/unittest_tpch_dir/07.sql diff --git a/tune/protox/test/unittest_tpch_dir/08.sql b/tune/protox/tests/unittest_tpch_dir/08.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/08.sql rename to tune/protox/tests/unittest_tpch_dir/08.sql diff --git a/tune/protox/test/unittest_tpch_dir/09.sql b/tune/protox/tests/unittest_tpch_dir/09.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/09.sql rename to tune/protox/tests/unittest_tpch_dir/09.sql diff --git a/tune/protox/test/unittest_tpch_dir/10.sql b/tune/protox/tests/unittest_tpch_dir/10.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/10.sql rename to tune/protox/tests/unittest_tpch_dir/10.sql diff --git a/tune/protox/test/unittest_tpch_dir/11.sql b/tune/protox/tests/unittest_tpch_dir/11.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/11.sql rename to tune/protox/tests/unittest_tpch_dir/11.sql diff --git a/tune/protox/test/unittest_tpch_dir/12.sql b/tune/protox/tests/unittest_tpch_dir/12.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/12.sql rename to tune/protox/tests/unittest_tpch_dir/12.sql diff --git a/tune/protox/test/unittest_tpch_dir/13.sql b/tune/protox/tests/unittest_tpch_dir/13.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/13.sql rename to tune/protox/tests/unittest_tpch_dir/13.sql diff --git a/tune/protox/test/unittest_tpch_dir/14.sql b/tune/protox/tests/unittest_tpch_dir/14.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/14.sql rename to tune/protox/tests/unittest_tpch_dir/14.sql diff --git a/tune/protox/test/unittest_tpch_dir/15.sql b/tune/protox/tests/unittest_tpch_dir/15.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/15.sql rename to tune/protox/tests/unittest_tpch_dir/15.sql diff --git a/tune/protox/test/unittest_tpch_dir/16.sql b/tune/protox/tests/unittest_tpch_dir/16.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/16.sql rename to tune/protox/tests/unittest_tpch_dir/16.sql diff --git a/tune/protox/test/unittest_tpch_dir/17.sql b/tune/protox/tests/unittest_tpch_dir/17.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/17.sql rename to tune/protox/tests/unittest_tpch_dir/17.sql diff --git a/tune/protox/test/unittest_tpch_dir/18.sql b/tune/protox/tests/unittest_tpch_dir/18.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/18.sql rename to tune/protox/tests/unittest_tpch_dir/18.sql diff --git a/tune/protox/test/unittest_tpch_dir/19.sql b/tune/protox/tests/unittest_tpch_dir/19.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/19.sql rename to tune/protox/tests/unittest_tpch_dir/19.sql diff --git a/tune/protox/test/unittest_tpch_dir/20.sql b/tune/protox/tests/unittest_tpch_dir/20.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/20.sql rename to tune/protox/tests/unittest_tpch_dir/20.sql diff --git a/tune/protox/test/unittest_tpch_dir/21.sql b/tune/protox/tests/unittest_tpch_dir/21.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/21.sql rename to tune/protox/tests/unittest_tpch_dir/21.sql diff --git a/tune/protox/test/unittest_tpch_dir/22.sql b/tune/protox/tests/unittest_tpch_dir/22.sql similarity index 100% rename from tune/protox/test/unittest_tpch_dir/22.sql rename to tune/protox/tests/unittest_tpch_dir/22.sql diff --git a/tune/protox/test/unittest_tpch_dir/order.txt b/tune/protox/tests/unittest_tpch_dir/order.txt similarity index 100% rename from tune/protox/test/unittest_tpch_dir/order.txt rename to tune/protox/tests/unittest_tpch_dir/order.txt