diff --git a/tests_integration/nativeapp/test_bundle.py b/tests_integration/nativeapp/test_bundle.py index e9fd0f3ce1..b6a1bc01ff 100644 --- a/tests_integration/nativeapp/test_bundle.py +++ b/tests_integration/nativeapp/test_bundle.py @@ -7,35 +7,49 @@ from tests.project.fixtures import * from tests_integration.test_utils import pushd +from tests_integration.testing_utils import ( + assert_that_result_failed_with_message_containing, +) USER_NAME = f"user_{uuid.uuid4().hex}" TEST_ENV = generate_user_env(USER_NAME) @pytest.fixture -def template_setup(request, runner, temporary_working_directory): - try: - template_name = request.param - except: - template_name = "basic" # default +def template_setup(runner, temporary_working_directory): project_name = "myapp" result = runner.invoke_json( - ["app", "init", project_name, "--template", template_name], + ["app", "init", project_name], # Uses default template + env=TEST_ENV, + ) + assert result.exit_code == 0 + + # Vanilla bundle on the unmodified template + result = runner.invoke_json( + ["app", "bundle", "--project", project_name], env=TEST_ENV, ) assert result.exit_code == 0 - return project_name, temporary_working_directory, runner + # The newly created deploy_root is explicitly deleted here, as bundle should take care of it. + + # TODO: replace with assert_dir_snapshot util once available + project_root = Path(temporary_working_directory, project_name) + deploy_root = Path(project_root, "output", "deploy") + assert Path(deploy_root, "manifest.yml").is_file() + assert Path(deploy_root, "setup_script.sql").is_file() + assert Path(deploy_root, "README.md").is_file() + + return project_root, runner # Tests that we disallow polluting the project source through symlinks @pytest.mark.integration -@pytest.mark.parametrize("template_setup", ["basic", "streamlit-python"], indirect=True) def test_nativeapp_bundle_does_not_create_files_outside_deploy_root( template_setup, ): - project_name, temporary_working_directory, runner = template_setup + project_root, runner = template_setup - with pushd(Path(temporary_working_directory, project_name)): + with pushd(project_root): # overwrite the snowflake.yml rules with open("snowflake.yml", "w") as f: f.write( @@ -58,30 +72,27 @@ def test_nativeapp_bundle_does_not_create_files_outside_deploy_root( env=TEST_ENV, ) assert result.exit_code == 1 - assert ( - "The specified destination path is outside of the deploy root" - in result.output + assert_that_result_failed_with_message_containing( + result, "The specified destination path is outside of the deploy root" ) - assert not os.path.exists("app/snowflake.yml") # Tests restrictions on the deploy root: It must be a sub-directory within the project directory @pytest.mark.integration -@pytest.mark.parametrize("template_setup", ["basic", "streamlit-python"], indirect=True) def test_nativeapp_bundle_throws_error_due_to_project_root_deploy_root_mismatch( template_setup, ): - project_name, temporary_working_directory, runner = template_setup + project_root, runner = template_setup + # Delete deploy_root since we test requirement of deploy_root being a directory + shutil.rmtree(Path(project_root, "output", "deploy")) - with pushd(Path(temporary_working_directory, project_name)) as project_dir: + with pushd(project_root) as project_dir: deploy_root = Path(project_dir, "output") - deploy_root.mkdir(parents=True, exist_ok=False) # Make deploy root a file instead of directory deploy_root_as_file = Path(deploy_root, "deploy") - with open(deploy_root_as_file, "x"): - pass + deploy_root_as_file.touch(exist_ok=False) assert deploy_root_as_file.is_file() @@ -91,7 +102,9 @@ def test_nativeapp_bundle_throws_error_due_to_project_root_deploy_root_mismatch( ) assert result.exit_code == 1 - assert "exists, but is not a directory!" in result.output + assert_that_result_failed_with_message_containing( + result, "exists, but is not a directory!" + ) os.remove(deploy_root_as_file) deploy_root.rmdir() @@ -103,7 +116,7 @@ def test_nativeapp_bundle_throws_error_due_to_project_root_deploy_root_mismatch( deploy_root = Path(original_cwd, "output", "deploy") deploy_root.mkdir(parents=True, exist_ok=False) - with pushd(Path(original_cwd, project_name)) as project_dir: + with pushd(project_root): with open("snowflake.yml", "w") as f: f.write( dedent( @@ -127,65 +140,77 @@ def test_nativeapp_bundle_throws_error_due_to_project_root_deploy_root_mismatch( ) assert result.exit_code == 1 - assert "is not a descendent of the project directory!" in result.output + assert_that_result_failed_with_message_containing( + result, "is not a descendent of the project directory!" + ) -# Tests restrictions on the src spec: It must be a glob that returns matches, and must be relative to project root +# Tests restrictions on the src spec that it must be a glob that returns matches @pytest.mark.integration -@pytest.mark.parametrize( - "pdf_content, error_msg", - [ - [ - dedent( - f""" +def test_nativeapp_bundle_throws_error_on_incorrect_src_glob(template_setup): + project_root, runner = template_setup + + with pushd(project_root): + # overwrite the snowflake.yml with incorrect glob + with open("snowflake.yml", "w") as f: + f.write( + dedent( + f""" definition_version: 1 native_app: name: myapp artifacts: - app/? """ - ), + ), + ) + + result = runner.invoke_json( + ["app", "bundle"], + env=TEST_ENV, + ) + assert result.exit_code == 1 + assert_that_result_failed_with_message_containing( + result, "No match was found for the specified source in the project directory", - ], - [ - dedent( - f""" + ) + + +# Tests restrictions on the src spec that it must be relative to project root +def test_nativeapp_bundle_throws_error_on_bad_src(template_setup): + project_root, runner = template_setup + + with pushd(project_root): + # overwrite the snowflake.yml with incorrect glob + with open("snowflake.yml", "w") as f: + f.write( + dedent( + f""" definition_version: 1 native_app: name: myapp artifacts: - - /app + - {Path(project_root, "app").absolute()} """ - ), - "Source path must be a relative path", - ], - ], -) -def test_nativeapp_bundle_throws_error_on_incorrect_src_glob( - pdf_content, error_msg, template_setup -): - project_name, temporary_working_directory, runner = template_setup - - with pushd(Path(temporary_working_directory, project_name)): - # overwrite the snowflake.yml with incorrect glob - with open("snowflake.yml", "w") as f: - f.write(pdf_content) + ), + ) result = runner.invoke_json( ["app", "bundle"], env=TEST_ENV, ) assert result.exit_code == 1 - assert error_msg in result.output + assert_that_result_failed_with_message_containing( + result, "Source path must be a relative path" + ) # Tests restrictions on the dest spec: It must be within the deploy root, and must be a relative path @pytest.mark.integration -@pytest.mark.parametrize("template_setup", ["basic", "streamlit-python"], indirect=True) def test_nativeapp_bundle_throws_error_on_bad_dest(template_setup): - project_name, temporary_working_directory, runner = template_setup + project_root, runner = template_setup - with pushd(Path(temporary_working_directory, project_name)): + with pushd(project_root): # overwrite the snowflake.yml rules with open("snowflake.yml", "w") as f: f.write( @@ -206,9 +231,8 @@ def test_nativeapp_bundle_throws_error_on_bad_dest(template_setup): env=TEST_ENV, ) assert result.exit_code == 1 - assert ( - "The specified destination path is outside of the deploy root" - in result.output + assert_that_result_failed_with_message_containing( + result, "The specified destination path is outside of the deploy root" ) with open("snowflake.yml", "w") as f: @@ -220,7 +244,7 @@ def test_nativeapp_bundle_throws_error_on_bad_dest(template_setup): name: myapp artifacts: - src: app/* - dest: /Users/ + dest: {Path(project_root, "output", "deploy", "stagepath").absolute()} """ ) ) @@ -230,16 +254,17 @@ def test_nativeapp_bundle_throws_error_on_bad_dest(template_setup): env=TEST_ENV, ) assert result.exit_code == 1 - assert "Destination path must be a relative path" in result.output + assert_that_result_failed_with_message_containing( + result, "Destination path must be a relative path" + ) # Tests restriction on mapping multiple files to the same destination file @pytest.mark.integration -@pytest.mark.parametrize("template_setup", ["basic", "streamlit-python"], indirect=True) def test_nativeapp_bundle_throws_error_on_too_many_files_to_dest(template_setup): - project_name, temporary_working_directory, runner = template_setup - with pushd(Path(temporary_working_directory, project_name)): + project_root, runner = template_setup + with pushd(project_root): # overwrite the snowflake.yml rules with open("snowflake.yml", "w") as f: f.write( @@ -262,16 +287,17 @@ def test_nativeapp_bundle_throws_error_on_too_many_files_to_dest(template_setup) env=TEST_ENV, ) assert result.exit_code == 1 - assert "Multiple files were mapped to one output file." in result.output + assert_that_result_failed_with_message_containing( + result, "Multiple files were mapped to one output file." + ) # Tests that bundle wipes out any existing deploy root to recreate it from scratch on every run @pytest.mark.integration -@pytest.mark.parametrize("template_setup", ["basic", "streamlit-python"], indirect=True) def test_nativeapp_bundle_deletes_existing_deploy_root(template_setup): - project_name, temporary_working_directory, runner = template_setup + project_root, runner = template_setup - with pushd(Path(temporary_working_directory, project_name)) as project_dir: + with pushd(project_root) as project_dir: existing_deploy_root_dest = Path(project_dir, "output", "deploy", "dummy.txt") existing_deploy_root_dest.mkdir(parents=True, exist_ok=False) result = runner.invoke_json(