diff --git a/.github/workflows/test_deploy.yml b/.github/workflows/test_deploy.yml index dc190d398b..f8c8f1deae 100644 --- a/.github/workflows/test_deploy.yml +++ b/.github/workflows/test_deploy.yml @@ -14,7 +14,8 @@ on: branches: - "**" - "!master" - +env: + RENKU_TEST_RECREATE_CACHE: "${{ (endsWith(github.ref, 'master') || endsWith(github.ref, 'develop') || startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/release/' ) ) && '1' || '0' }}" jobs: set-matrix: runs-on: ubuntu-latest diff --git a/tests/cli/fixtures/cli_workflow.py b/tests/cli/fixtures/cli_workflow.py index dd9b866a74..ff2666f62b 100644 --- a/tests/cli/fixtures/cli_workflow.py +++ b/tests/cli/fixtures/cli_workflow.py @@ -19,19 +19,22 @@ @pytest.fixture -def workflow_graph(run_shell, project): +def workflow_graph(run_shell, project, cache_test_project): """Setup a project with a workflow graph.""" + cache_test_project.set_name("workflow_graph_fixture") + if not cache_test_project.setup(): - def _run_workflow(name, command, extra_args=""): - output = run_shell(f"renku run --name {name} {extra_args} -- {command}") - # Assert not allocated stderr. - assert output[1] is None + def _run_workflow(name, command, extra_args=""): + output = run_shell(f"renku run --name {name} {extra_args} -- {command}") + # Assert not allocated stderr. + assert output[1] is None - _run_workflow("r1", "echo 'test' > A") - _run_workflow("r2", "tee B C < A") - _run_workflow("r3", "cp A Z") - _run_workflow("r4", "cp B X") - _run_workflow("r5", "cat C Z > Y") - _run_workflow("r6", "bash -c 'cat X Y | tee R S'", extra_args="--input X --input Y --output R --output S") - _run_workflow("r7", "echo 'other' > H") - _run_workflow("r8", "tee I J < H") + _run_workflow("r1", "echo 'test' > A") + _run_workflow("r2", "tee B C < A") + _run_workflow("r3", "cp A Z") + _run_workflow("r4", "cp B X") + _run_workflow("r5", "cat C Z > Y") + _run_workflow("r6", "bash -c 'cat X Y | tee R S'", extra_args="--input X --input Y --output R --output S") + _run_workflow("r7", "echo 'other' > H") + _run_workflow("r8", "tee I J < H") + cache_test_project.save() diff --git a/tests/cli/test_graph.py b/tests/cli/test_graph.py index 3f02bb7676..c81797b442 100644 --- a/tests/cli/test_graph.py +++ b/tests/cli/test_graph.py @@ -27,14 +27,16 @@ @pytest.mark.parametrize("revision", ["", "HEAD", "HEAD^", "HEAD^..HEAD"]) -def test_graph_export_validation(runner, project, directory_tree, run, revision): +def test_graph_export_validation(runner, project, directory_tree, run, revision, cache_test_project): """Test graph validation when exporting.""" - assert 0 == runner.invoke(cli, ["dataset", "add", "--copy", "-c", "my-data", str(directory_tree)]).exit_code + if not cache_test_project.setup(): + assert 0 == runner.invoke(cli, ["dataset", "add", "--copy", "-c", "my-data", str(directory_tree)]).exit_code - file1 = project.path / DATA_DIR / "my-data" / directory_tree.name / "file1" - file2 = project.path / DATA_DIR / "my-data" / directory_tree.name / "dir1" / "file2" - assert 0 == run(["run", "head", str(file1)], stdout="out1") - assert 0 == run(["run", "tail", str(file2)], stdout="out2") + file1 = project.path / DATA_DIR / "my-data" / directory_tree.name / "file1" + file2 = project.path / DATA_DIR / "my-data" / directory_tree.name / "dir1" / "file2" + assert 0 == run(["run", "head", str(file1)], stdout="out1") + assert 0 == run(["run", "tail", str(file2)], stdout="out2") + cache_test_project.save() result = runner.invoke(cli, ["graph", "export", "--format", "json-ld", "--strict", "--revision", revision]) @@ -57,12 +59,14 @@ def test_graph_export_validation(runner, project, directory_tree, run, revision) @pytest.mark.serial @pytest.mark.shelled -def test_graph_export_strict_run(runner, project, run_shell): +def test_graph_export_strict_run(runner, project, run_shell, cache_test_project): """Test graph export output of run command.""" - # Run a shell command with pipe. - assert run_shell('renku run --name run1 echo "my input string" > my_output_file')[1] is None - assert run_shell("renku run --name run2 cp my_output_file my_output_file2")[1] is None - assert run_shell("renku workflow compose my-composite-plan run1 run2")[1] is None + if not cache_test_project.setup(): + # Run a shell command with pipe. + assert run_shell('renku run --name run1 echo "my input string" > my_output_file')[1] is None + assert run_shell("renku run --name run2 cp my_output_file my_output_file2")[1] is None + assert run_shell("renku workflow compose my-composite-plan run1 run2")[1] is None + cache_test_project.save() # Assert created output file. result = runner.invoke(cli, ["graph", "export", "--full", "--strict", "--format=json-ld"]) @@ -80,21 +84,23 @@ def test_graph_export_strict_run(runner, project, run_shell): assert 0 == result.exit_code, format_result_exception(result) -def test_graph_export_strict_dataset(tmpdir, runner, project, subdirectory): +def test_graph_export_strict_dataset(tmpdir, runner, project, subdirectory, cache_test_project): """Test output of graph export for dataset add.""" - result = runner.invoke(cli, ["dataset", "create", "my-dataset"]) - assert 0 == result.exit_code, format_result_exception(result) - paths = [] - test_paths = [] - for i in range(3): - new_file = tmpdir.join(f"file_{i}") - new_file.write(str(i)) - paths.append(str(new_file)) - test_paths.append(os.path.relpath(str(new_file), str(project.path))) - - # add data - result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset"] + paths) - assert 0 == result.exit_code, format_result_exception(result) + with cache_test_project.setup(): + result = runner.invoke(cli, ["dataset", "create", "my-dataset"]) + assert 0 == result.exit_code, format_result_exception(result) + paths = [] + test_paths = [] + for i in range(3): + new_file = tmpdir.join(f"file_{i}") + new_file.write(str(i)) + paths.append(str(new_file)) + test_paths.append(os.path.relpath(str(new_file), str(project.path))) + + # add data + result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset"] + paths) + assert 0 == result.exit_code, format_result_exception(result) + cache_test_project.save() result = runner.invoke(cli, ["graph", "export", "--strict", "--format=json-ld", "--revision", "HEAD"]) assert 0 == result.exit_code, format_result_exception(result) diff --git a/tests/cli/test_merge.py b/tests/cli/test_merge.py index 183d7c4bb2..7d9e3bc6b0 100644 --- a/tests/cli/test_merge.py +++ b/tests/cli/test_merge.py @@ -24,96 +24,98 @@ from tests.utils import format_result_exception -def test_mergetool(runner, project, directory_tree, run_shell, with_injection): +def test_mergetool(runner, project, directory_tree, run_shell, with_injection, cache_test_project): """Test that merge tool can merge renku metadata.""" - result = runner.invoke(cli, ["mergetool", "install"]) + if not cache_test_project.setup(): + result = runner.invoke(cli, ["mergetool", "install"]) - assert 0 == result.exit_code, format_result_exception(result) + assert 0 == result.exit_code, format_result_exception(result) - # create a common dataset - result = runner.invoke( - cli, ["dataset", "add", "--copy", "--create", "shared-dataset", str(directory_tree)], catch_exceptions=False - ) - assert 0 == result.exit_code, format_result_exception(result) + # create a common dataset + result = runner.invoke( + cli, ["dataset", "add", "--copy", "--create", "shared-dataset", str(directory_tree)], catch_exceptions=False + ) + assert 0 == result.exit_code, format_result_exception(result) - # Create a common workflow - output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') + # Create a common workflow + output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # switch to a new branch - output = run_shell("git checkout -b remote-branch") + # switch to a new branch + output = run_shell("git checkout -b remote-branch") - assert b"Switched to a new branch 'remote-branch'\n" == output[0] - assert output[1] is None + assert b"Switched to a new branch 'remote-branch'\n" == output[0] + assert output[1] is None - # edit the dataset - result = runner.invoke(cli, ["dataset", "edit", "-d", "remote description", "shared-dataset"]) - assert 0 == result.exit_code, format_result_exception(result) + # edit the dataset + result = runner.invoke(cli, ["dataset", "edit", "-d", "remote description", "shared-dataset"]) + assert 0 == result.exit_code, format_result_exception(result) - result = runner.invoke( - cli, ["dataset", "add", "--copy", "--create", "remote-dataset", str(directory_tree)], catch_exceptions=False - ) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke( + cli, ["dataset", "add", "--copy", "--create", "remote-dataset", str(directory_tree)], catch_exceptions=False + ) + assert 0 == result.exit_code, format_result_exception(result) - # Create a new workflow - output = run_shell('renku run --name "remote-workflow" echo "a unique string" > remote_output_file') + # Create a new workflow + output = run_shell('renku run --name "remote-workflow" echo "a unique string" > remote_output_file') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Create a downstream workflow - output = run_shell('renku run --name "remote-downstream-workflow" cp my_output_file my_remote_downstream') + # Create a downstream workflow + output = run_shell('renku run --name "remote-downstream-workflow" cp my_output_file my_remote_downstream') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Create another downstream workflow - output = run_shell('renku run --name "remote-downstream-workflow2" cp remote_output_file my_remote_downstream2') + # Create another downstream workflow + output = run_shell('renku run --name "remote-downstream-workflow2" cp remote_output_file my_remote_downstream2') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Edit the project metadata - result = runner.invoke(cli, ["project", "edit", "-k", "remote"]) + # Edit the project metadata + result = runner.invoke(cli, ["project", "edit", "-k", "remote"]) - assert 0 == result.exit_code, format_result_exception(result) + assert 0 == result.exit_code, format_result_exception(result) - # Switch back to master - output = run_shell("git checkout master") + # Switch back to master + output = run_shell("git checkout master") - assert b"Switched to branch 'master'\n" == output[0] - assert output[1] is None + assert b"Switched to branch 'master'\n" == output[0] + assert output[1] is None - # Add a new dataset - result = runner.invoke( - cli, ["dataset", "add", "--copy", "--create", "local-dataset", str(directory_tree)], catch_exceptions=False - ) - assert 0 == result.exit_code, format_result_exception(result) + # Add a new dataset + result = runner.invoke( + cli, ["dataset", "add", "--copy", "--create", "local-dataset", str(directory_tree)], catch_exceptions=False + ) + assert 0 == result.exit_code, format_result_exception(result) - # Create a local workflow - output = run_shell('renku run --name "local-workflow" echo "a unique string" > local_output_file') + # Create a local workflow + output = run_shell('renku run --name "local-workflow" echo "a unique string" > local_output_file') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Create a local downstream workflow - output = run_shell('renku run --name "local-downstream-workflow" cp my_output_file my_local_downstream') + # Create a local downstream workflow + output = run_shell('renku run --name "local-downstream-workflow" cp my_output_file my_local_downstream') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Create another local downstream workflow - output = run_shell('renku run --name "local-downstream-workflow2" cp local_output_file my_local_downstream2') + # Create another local downstream workflow + output = run_shell('renku run --name "local-downstream-workflow2" cp local_output_file my_local_downstream2') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Edit the project in master as well - result = runner.invoke(cli, ["project", "edit", "-k", "local"]) + # Edit the project in master as well + result = runner.invoke(cli, ["project", "edit", "-k", "local"]) - assert 0 == result.exit_code, format_result_exception(result) + assert 0 == result.exit_code, format_result_exception(result) + cache_test_project.save() # Merge branches output = run_shell("git merge --no-edit remote-branch") @@ -146,32 +148,34 @@ def test_mergetool(runner, project, directory_tree, run_shell, with_injection): assert "remote description" == shared_dataset.description -def test_mergetool_workflow_conflict(runner, project, run_shell, with_injection): +def test_mergetool_workflow_conflict(runner, project, run_shell, with_injection, cache_test_project): """Test that merge tool can merge conflicting workflows.""" - result = runner.invoke(cli, ["mergetool", "install"]) + if not cache_test_project.setup(): + result = runner.invoke(cli, ["mergetool", "install"]) - assert 0 == result.exit_code, format_result_exception(result) + assert 0 == result.exit_code, format_result_exception(result) - output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') + output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Switch to a new branch and create some workflows - output = run_shell("git checkout -b remote-branch") + # Switch to a new branch and create some workflows + output = run_shell("git checkout -b remote-branch") - assert b"Switched to a new branch 'remote-branch'\n" == output[0] - assert output[1] is None + assert b"Switched to a new branch 'remote-branch'\n" == output[0] + assert output[1] is None - output = run_shell('renku run --name "remote-workflow" cp my_output_file out1') + output = run_shell('renku run --name "remote-workflow" cp my_output_file out1') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - output = run_shell('renku run --name "common-name" cp my_output_file out2') + output = run_shell('renku run --name "common-name" cp my_output_file out2') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None + cache_test_project.save() with with_injection(): plan_gateway = PlanGateway() @@ -237,30 +241,33 @@ def test_mergetool_workflow_conflict(runner, project, run_shell, with_injection) assert len(plans) == 4 -def test_mergetool_workflow_complex_conflict(runner, project, run_shell, with_injection): +def test_mergetool_workflow_complex_conflict(runner, project, run_shell, with_injection, cache_test_project): """Test that merge tool can merge complex conflicts in workflows.""" - result = runner.invoke(cli, ["mergetool", "install"]) + if not cache_test_project.setup(): + result = runner.invoke(cli, ["mergetool", "install"]) - assert 0 == result.exit_code, format_result_exception(result) + assert 0 == result.exit_code, format_result_exception(result) - output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') + output = run_shell('renku run --name "shared-workflow" echo "a unique string" > my_output_file') - assert b"" == output[0] - assert output[1] is None + assert b"" == output[0] + assert output[1] is None - # Switch to a new branch and create some workflows - output = run_shell("git checkout -b remote-branch") + # Switch to a new branch and create some workflows + output = run_shell("git checkout -b remote-branch") - assert b"Switched to a new branch 'remote-branch'\n" == output[0] - assert output[1] is None + assert b"Switched to a new branch 'remote-branch'\n" == output[0] + assert output[1] is None - output = run_shell('renku run --name "intermediate-workflow" cp my_output_file intermediate') + output = run_shell('renku run --name "intermediate-workflow" cp my_output_file intermediate') - assert b"" == output[0] + assert b"" == output[0] - output = run_shell('renku run --name "final-workflow" cp intermediate final') + output = run_shell('renku run --name "final-workflow" cp intermediate final') - assert b"" == output[0] + assert b"" == output[0] + + cache_test_project.save() with with_injection(): plan_gateway = PlanGateway() diff --git a/tests/cli/test_rollback.py b/tests/cli/test_rollback.py index 1effb780be..21a12b69b1 100644 --- a/tests/cli/test_rollback.py +++ b/tests/cli/test_rollback.py @@ -20,39 +20,41 @@ from tests.utils import format_result_exception -def test_rollback(runner, project): +def test_rollback(runner, project, cache_test_project): """Test renku rollback.""" - result = runner.invoke(cli, ["run", "--name", "run1", "touch", "foo"]) - assert 0 == result.exit_code, format_result_exception(result) + if not cache_test_project.setup(): + result = runner.invoke(cli, ["run", "--name", "run1", "touch", "foo"]) + assert 0 == result.exit_code, format_result_exception(result) - result = runner.invoke(cli, ["run", "--name", "run2", "cp", "foo", "bar"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["run", "--name", "run2", "cp", "foo", "bar"]) + assert 0 == result.exit_code, format_result_exception(result) - metadata_path = project.path / "input" - metadata_path.write_text("input") + metadata_path = project.path / "input" + metadata_path.write_text("input") - project.repository.add("input") - project.repository.commit("add input") + project.repository.add("input") + project.repository.commit("add input") - result = runner.invoke(cli, ["dataset", "create", "my-dataset"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["dataset", "create", "my-dataset"]) + assert 0 == result.exit_code, format_result_exception(result) - result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "foo"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "foo"]) + assert 0 == result.exit_code, format_result_exception(result) - result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "bar"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "bar"]) + assert 0 == result.exit_code, format_result_exception(result) - result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "input"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["dataset", "add", "--copy", "my-dataset", "input"]) + assert 0 == result.exit_code, format_result_exception(result) - metadata_path.write_text("changed input") + metadata_path.write_text("changed input") - project.repository.add("input") - project.repository.commit("change input") + project.repository.add("input") + project.repository.commit("change input") - result = runner.invoke(cli, ["run", "--name", "run3", "cp", "input", "output"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["run", "--name", "run3", "cp", "input", "output"]) + assert 0 == result.exit_code, format_result_exception(result) + cache_test_project.save() result = runner.invoke(cli, ["rollback"], input="q") assert 0 == result.exit_code, format_result_exception(result) diff --git a/tests/cli/test_update.py b/tests/cli/test_update.py index 9ff04ca095..02c5828d38 100644 --- a/tests/cli/test_update.py +++ b/tests/cli/test_update.py @@ -466,7 +466,7 @@ def test_update_multiple_paths_common_output(project, renku_cli, runner): @pytest.mark.serial @pytest.mark.parametrize("provider", available_workflow_providers()) -def test_update_with_execute(runner, project, renku_cli, provider): +def test_update_with_execute(runner, project, renku_cli, provider, cache_test_project): """Test output is updated when source changes.""" source1 = Path("source.txt") output1 = Path("output.txt") @@ -474,28 +474,38 @@ def test_update_with_execute(runner, project, renku_cli, provider): output2 = Path("output2.txt") script = Path("cp.sh") - write_and_commit_file(project.repository, source1, "content_a") - write_and_commit_file(project.repository, source2, "content_b") - write_and_commit_file(project.repository, script, "cp $1 $2") + if not cache_test_project.setup(): + write_and_commit_file(project.repository, source1, "content_a") + write_and_commit_file(project.repository, source2, "content_b") + write_and_commit_file(project.repository, script, "cp $1 $2") - result = runner.invoke(cli, ["run", "--name", "test", "bash", str(script), str(source1), str(output1)]) - assert 0 == result.exit_code, format_result_exception(result) - time.sleep(1) - - assert ( - 0 - == renku_cli( - "workflow", "execute", "-p", provider, "--set", f"input-2={source2}", "--set", f"output-3={output2}", "test" - ).exit_code - ) - - assert "content_a" == (project.path / output1).read_text() - assert "content_b" == (project.path / output2).read_text() + result = runner.invoke(cli, ["run", "--name", "test", "bash", str(script), str(source1), str(output1)]) + assert 0 == result.exit_code, format_result_exception(result) + time.sleep(1) + + assert ( + 0 + == renku_cli( + "workflow", + "execute", + "-p", + provider, + "--set", + f"input-2={source2}", + "--set", + f"output-3={output2}", + "test", + ).exit_code + ) + + assert "content_a" == (project.path / output1).read_text() + assert "content_b" == (project.path / output2).read_text() - result = runner.invoke(cli, ["status"]) - assert 0 == result.exit_code, format_result_exception(result) + result = runner.invoke(cli, ["status"]) + assert 0 == result.exit_code, format_result_exception(result) - write_and_commit_file(project.repository, script, "cp $1 $2\necho '_modified' >> $2") + write_and_commit_file(project.repository, script, "cp $1 $2\necho '_modified' >> $2") + cache_test_project.save() result = runner.invoke(cli, ["status"]) assert 1 == result.exit_code diff --git a/tests/cli/test_workflow.py b/tests/cli/test_workflow.py index d3c312ad3b..c41c63cfc8 100644 --- a/tests/cli/test_workflow.py +++ b/tests/cli/test_workflow.py @@ -1046,39 +1046,41 @@ def _update_screen(data): assert not child.isalive() -def test_workflow_compose_execute(runner, project, run_shell): +def test_workflow_compose_execute(runner, project, run_shell, cache_test_project): """Test renku workflow compose with execute.""" - # Run a shell command with pipe. - output = run_shell('renku run --name run1 -- echo "a" > output1') + if not cache_test_project.setup(): + # Run a shell command with pipe. + output = run_shell('renku run --name run1 -- echo "a" > output1') - # Assert expected empty stdout. - assert b"" == output[0] - # Assert not allocated stderr. - assert output[1] is None + # Assert expected empty stdout. + assert b"" == output[0] + # Assert not allocated stderr. + assert output[1] is None - # Run a shell command with pipe. - output = run_shell("renku run --name run2 -- cp output1 output2") + # Run a shell command with pipe. + output = run_shell("renku run --name run2 -- cp output1 output2") - # Assert expected empty stdout. - assert b"" == output[0] - # Assert not allocated stderr. - assert output[1] is None + # Assert expected empty stdout. + assert b"" == output[0] + # Assert not allocated stderr. + assert output[1] is None - # Run a shell command with pipe. - output = run_shell('renku run --name run3 -- echo "b" > output3') + # Run a shell command with pipe. + output = run_shell('renku run --name run3 -- echo "b" > output3') - # Assert expected empty stdout. - assert b"" == output[0] - # Assert not allocated stderr. - assert output[1] is None + # Assert expected empty stdout. + assert b"" == output[0] + # Assert not allocated stderr. + assert output[1] is None - # Run a shell command with pipe. - output = run_shell("renku run --name run4 -- cp output3 output4") + # Run a shell command with pipe. + output = run_shell("renku run --name run4 -- cp output3 output4") - # Assert expected empty stdout. - assert b"" == output[0] - # Assert not allocated stderr. - assert output[1] is None + # Assert expected empty stdout. + assert b"" == output[0] + # Assert not allocated stderr. + assert output[1] is None + cache_test_project.save() # we need to run in a subprocess to ensure the execute below uses a clean Database, to test against # issues with cached parameters @@ -1210,29 +1212,32 @@ def test_workflow_iterate( @pytest.mark.parametrize("provider", available_workflow_providers()) -def test_workflow_iterate_command_with_parameter_set(runner, run_shell, project, capsys, transaction_id, provider): +def test_workflow_iterate_command_with_parameter_set( + runner, run_shell, project, capsys, transaction_id, provider, cache_test_project +): """Test executing a workflow with --set float value for a renku.ui.api.Parameter.""" script = project.path / "script.py" output = project.path / "output" + if not cache_test_project.setup(): + with with_commit(repository=project.repository, transaction_id=transaction_id): + script.write_text("import sys\nprint(sys.argv[1])\n") - with with_commit(repository=project.repository, transaction_id=transaction_id): - script.write_text("import sys\nprint(sys.argv[1])\n") - - result = run_shell(f"renku run --name run1 -- python {script} 3.98 > {output}") + result = run_shell(f"renku run --name run1 -- python {script} 3.98 > {output}") - # Assert expected empty stdout. - assert b"" == result[0] - # Assert not allocated stderr. - assert result[1] is None + # Assert expected empty stdout. + assert b"" == result[0] + # Assert not allocated stderr. + assert result[1] is None - assert "3.98\n" == output.read_text() + assert "3.98\n" == output.read_text() - result = run_shell(f"renku workflow execute -p {provider} --set parameter-2=2.0 run1") + result = run_shell(f"renku workflow execute -p {provider} --set parameter-2=2.0 run1") - # Assert not allocated stderr. - assert result[1] is None + # Assert not allocated stderr. + assert result[1] is None - assert "2.0\n" == output.read_text() + assert "2.0\n" == output.read_text() + cache_test_project.save() result = run_shell(f"renku workflow iterate -p {provider} --map parameter-2=[0.1,0.3,0.5,0.8,0.95] run1") diff --git a/tests/core/fixtures/core_datasets.py b/tests/core/fixtures/core_datasets.py index 733dda1467..e5c9e76394 100644 --- a/tests/core/fixtures/core_datasets.py +++ b/tests/core/fixtures/core_datasets.py @@ -46,21 +46,28 @@ def request_callback(request): @pytest.fixture -def project_with_datasets(project, directory_tree, with_injection) -> Generator[RenkuProject, None, None]: +def project_with_datasets( + project, directory_tree, with_injection, cache_test_project +) -> Generator[RenkuProject, None, None]: """A project with datasets.""" from renku.domain_model.provenance.agent import Person - person_1 = Person.from_string("P1 [IANA]") - person_2 = Person.from_string("P2 ") + cache_test_project.set_name("project_with_datasets_fixture") + if not cache_test_project.setup(): + person_1 = Person.from_string("P1 [IANA]") + person_2 = Person.from_string("P2 ") - with with_injection(): - create_dataset(name="dataset-1", keywords=["dataset", "1"], creators=[person_1]) + with with_injection(): + create_dataset(name="dataset-1", keywords=["dataset", "1"], creators=[person_1]) - dataset = add_to_dataset("dataset-2", urls=[str(p) for p in directory_tree.glob("*")], create=True, copy=True) - dataset.keywords = ["dataset", "2"] - dataset.creators = [person_1, person_2] + dataset = add_to_dataset( + "dataset-2", urls=[str(p) for p in directory_tree.glob("*")], create=True, copy=True + ) + dataset.keywords = ["dataset", "2"] + dataset.creators = [person_1, person_2] - project.repository.add(all=True) - project.repository.commit("add files to datasets") + project.repository.add(all=True) + project.repository.commit("add files to datasets") + cache_test_project.save() yield project diff --git a/tests/core/fixtures/core_workflow.py b/tests/core/fixtures/core_workflow.py index d6025329ab..c61d46ee33 100644 --- a/tests/core/fixtures/core_workflow.py +++ b/tests/core/fixtures/core_workflow.py @@ -91,7 +91,9 @@ def create_run(name: str) -> Plan: @pytest.fixture -def project_with_runs(project_with_creation_date, with_injection) -> Generator[RenkuProject, None, None]: +def project_with_runs( + project_with_creation_date, with_injection, cache_test_project +) -> Generator[RenkuProject, None, None]: """A project with runs.""" from renku.domain_model.provenance.activity import Activity from renku.infrastructure.gateway.activity_gateway import ActivityGateway @@ -106,44 +108,47 @@ def create_activity(plan, date, index) -> Activity: ended_at_time=date + timedelta(seconds=1), ) - date_1 = datetime(2022, 5, 20, 0, 42, 0, tzinfo=timezone.utc) - date_2 = datetime(2022, 5, 20, 0, 43, 0, tzinfo=timezone.utc) - - plan_1 = create_dummy_plan( - command="command-1", - date_created=date_1, - description="First plan", - index=1, - inputs=["input"], - keywords=["plans", "1"], - name="plan-1", - outputs=[("intermediate", "stdout")], - parameters=[("parameter-1", "42", "-n ")], - success_codes=[0, 1], - ) - - plan_2 = create_dummy_plan( - command="command-2", - date_created=date_2, - description="Second plan", - index=2, - inputs=["intermediate"], - keywords=["plans", "2"], - name="plan-2", - outputs=[("output", "stdout")], - parameters=[("int-parameter", 43, "-n "), ("str-parameter", "some value", None)], - ) - - with with_injection(): - activity_1 = create_activity(plan_1, date_1, index=1) - activity_2 = create_activity(plan_2, date_2, index=2) - - activity_gateway = ActivityGateway() - - activity_gateway.add(activity_1) - activity_gateway.add(activity_2) - - project_with_creation_date.repository.add(all=True) - project_with_creation_date.repository.commit("Add runs") + cache_test_project.set_name("project_with_runs_fixture") + if not cache_test_project.setup(): + date_1 = datetime(2022, 5, 20, 0, 42, 0, tzinfo=timezone.utc) + date_2 = datetime(2022, 5, 20, 0, 43, 0, tzinfo=timezone.utc) + + plan_1 = create_dummy_plan( + command="command-1", + date_created=date_1, + description="First plan", + index=1, + inputs=["input"], + keywords=["plans", "1"], + name="plan-1", + outputs=[("intermediate", "stdout")], + parameters=[("parameter-1", "42", "-n ")], + success_codes=[0, 1], + ) + + plan_2 = create_dummy_plan( + command="command-2", + date_created=date_2, + description="Second plan", + index=2, + inputs=["intermediate"], + keywords=["plans", "2"], + name="plan-2", + outputs=[("output", "stdout")], + parameters=[("int-parameter", 43, "-n "), ("str-parameter", "some value", None)], + ) + + with with_injection(): + activity_1 = create_activity(plan_1, date_1, index=1) + activity_2 = create_activity(plan_2, date_2, index=2) + + activity_gateway = ActivityGateway() + + activity_gateway.add(activity_1) + activity_gateway.add(activity_2) + + project_with_creation_date.repository.add(all=True) + project_with_creation_date.repository.commit("Add runs") + cache_test_project.save() yield project_with_creation_date diff --git a/tests/data/repo-cache/project_with_datasets_fixture.tar.gz b/tests/data/repo-cache/project_with_datasets_fixture.tar.gz new file mode 100644 index 0000000000..be726c7db8 Binary files /dev/null and b/tests/data/repo-cache/project_with_datasets_fixture.tar.gz differ diff --git a/tests/data/repo-cache/project_with_runs_fixture.tar.gz b/tests/data/repo-cache/project_with_runs_fixture.tar.gz new file mode 100644 index 0000000000..5e22aaa15a Binary files /dev/null and b/tests/data/repo-cache/project_with_runs_fixture.tar.gz differ diff --git a/tests/data/repo-cache/test_graph_export_strict_run.tar.gz b/tests/data/repo-cache/test_graph_export_strict_run.tar.gz new file mode 100644 index 0000000000..6af0365012 Binary files /dev/null and b/tests/data/repo-cache/test_graph_export_strict_run.tar.gz differ diff --git a/tests/data/repo-cache/test_graph_export_validation_HEAD_..HEAD_.tar.gz b/tests/data/repo-cache/test_graph_export_validation_HEAD_..HEAD_.tar.gz new file mode 100644 index 0000000000..365557b950 Binary files /dev/null and b/tests/data/repo-cache/test_graph_export_validation_HEAD_..HEAD_.tar.gz differ diff --git a/tests/data/repo-cache/test_graph_export_validation_HEAD_.tar.gz b/tests/data/repo-cache/test_graph_export_validation_HEAD_.tar.gz new file mode 100644 index 0000000000..b30fc7ff50 Binary files /dev/null and b/tests/data/repo-cache/test_graph_export_validation_HEAD_.tar.gz differ diff --git a/tests/data/repo-cache/test_graph_export_validation_HEAD__.tar.gz b/tests/data/repo-cache/test_graph_export_validation_HEAD__.tar.gz new file mode 100644 index 0000000000..8daa3a650d Binary files /dev/null and b/tests/data/repo-cache/test_graph_export_validation_HEAD__.tar.gz differ diff --git a/tests/data/repo-cache/test_graph_export_validation__.tar.gz b/tests/data/repo-cache/test_graph_export_validation__.tar.gz new file mode 100644 index 0000000000..097911ecd3 Binary files /dev/null and b/tests/data/repo-cache/test_graph_export_validation__.tar.gz differ diff --git a/tests/data/repo-cache/test_mergetool.tar.gz b/tests/data/repo-cache/test_mergetool.tar.gz new file mode 100644 index 0000000000..81a7ec8dc5 Binary files /dev/null and b/tests/data/repo-cache/test_mergetool.tar.gz differ diff --git a/tests/data/repo-cache/test_mergetool_workflow_complex_conflict.tar.gz b/tests/data/repo-cache/test_mergetool_workflow_complex_conflict.tar.gz new file mode 100644 index 0000000000..60e65fd287 Binary files /dev/null and b/tests/data/repo-cache/test_mergetool_workflow_complex_conflict.tar.gz differ diff --git a/tests/data/repo-cache/test_mergetool_workflow_conflict.tar.gz b/tests/data/repo-cache/test_mergetool_workflow_conflict.tar.gz new file mode 100644 index 0000000000..bf9d4f252a Binary files /dev/null and b/tests/data/repo-cache/test_mergetool_workflow_conflict.tar.gz differ diff --git a/tests/data/repo-cache/test_rollback.tar.gz b/tests/data/repo-cache/test_rollback.tar.gz new file mode 100644 index 0000000000..b24938a333 Binary files /dev/null and b/tests/data/repo-cache/test_rollback.tar.gz differ diff --git a/tests/data/repo-cache/test_update_with_execute_cwltool_.tar.gz b/tests/data/repo-cache/test_update_with_execute_cwltool_.tar.gz new file mode 100644 index 0000000000..3f9d55d942 Binary files /dev/null and b/tests/data/repo-cache/test_update_with_execute_cwltool_.tar.gz differ diff --git a/tests/data/repo-cache/test_update_with_execute_local_.tar.gz b/tests/data/repo-cache/test_update_with_execute_local_.tar.gz new file mode 100644 index 0000000000..fc9845cfad Binary files /dev/null and b/tests/data/repo-cache/test_update_with_execute_local_.tar.gz differ diff --git a/tests/data/repo-cache/test_update_with_execute_toil_.tar.gz b/tests/data/repo-cache/test_update_with_execute_toil_.tar.gz new file mode 100644 index 0000000000..635a379fe2 Binary files /dev/null and b/tests/data/repo-cache/test_update_with_execute_toil_.tar.gz differ diff --git a/tests/data/repo-cache/test_workflow_compose_execute.tar.gz b/tests/data/repo-cache/test_workflow_compose_execute.tar.gz new file mode 100644 index 0000000000..6de8807094 Binary files /dev/null and b/tests/data/repo-cache/test_workflow_compose_execute.tar.gz differ diff --git a/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_cwltool_.tar.gz b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_cwltool_.tar.gz new file mode 100644 index 0000000000..5a476d87e6 Binary files /dev/null and b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_cwltool_.tar.gz differ diff --git a/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_local_.tar.gz b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_local_.tar.gz new file mode 100644 index 0000000000..a1001261cc Binary files /dev/null and b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_local_.tar.gz differ diff --git a/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_toil_.tar.gz b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_toil_.tar.gz new file mode 100644 index 0000000000..8a770af500 Binary files /dev/null and b/tests/data/repo-cache/test_workflow_iterate_command_with_parameter_set_toil_.tar.gz differ diff --git a/tests/data/repo-cache/workflow_graph_fixture.tar.gz b/tests/data/repo-cache/workflow_graph_fixture.tar.gz new file mode 100644 index 0000000000..e60d6cd5d6 Binary files /dev/null and b/tests/data/repo-cache/workflow_graph_fixture.tar.gz differ diff --git a/tests/fixtures/common.py b/tests/fixtures/common.py index e581b60ecf..df68a26acb 100644 --- a/tests/fixtures/common.py +++ b/tests/fixtures/common.py @@ -17,6 +17,7 @@ """Renku common fixtures.""" import os +import shutil from pathlib import Path from typing import Generator, List @@ -88,3 +89,54 @@ def transaction_id(project) -> Generator[str, None, None]: from renku.domain_model.project_context import project_context yield project_context.transaction_id + + +@pytest.fixture +def cache_test_project(request, project): + """Caches a renku project repository for reuse between tests.""" + marker = request.node.get_closest_marker("project_cache_name") + + if marker: + cache_name = marker.args[0] + else: + cache_name = "".join(x if x.isalnum() or x in "-_." else "_" for x in request.node.name) + + class _ProjectRepoCache: + def __init__(self, cache_name: str) -> None: + self.set_name(cache_name) + + def set_name(self, cache_name: str) -> None: + """Change the name of the cache.""" + self.cache_name = cache_name + self.cache_dir = Path(request.config.rootdir) / Path( + os.environ.get("RENKU_TEST_PROJECT_CACHE_DIR", "tests/data/repo-cache") + ) + self.cache_dir.mkdir(exist_ok=True) + self.filename = self.cache_dir / f"{self.cache_name}.tar.gz" + + def delete_project_contents(self) -> None: + """Delete the contents of the project directory.""" + for filename in os.listdir(project.path): + file_path = os.path.join(project.path, filename) + + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + + def save(self): + """Save state of the project directory.""" + self.filename.unlink(missing_ok=True) + shutil.make_archive(str(self.cache_dir / self.cache_name), "gztar", project.path) + + def setup(self) -> bool: + """Recreate state of project directory from previous test, if applicable.""" + if not self.filename.exists() or os.environ.get("RENKU_TEST_RECREATE_CACHE", "0") == "1": + return False + + self.delete_project_contents() + shutil.unpack_archive(self.filename, project.path, "gztar") + return True + + assert cache_name is not None + return _ProjectRepoCache(cache_name)