Skip to content

Commit 358c36e

Browse files
committed
add tests
1 parent 9a65871 commit 358c36e

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

tests/cli/test_deploy.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6128,3 +6128,167 @@ async def test_deploying_directory_as_prefect_file(self):
61286128
"Is a directory: '.'. Skipping."
61296129
],
61306130
)
6131+
6132+
6133+
class TestDeployDryRun:
6134+
@pytest.fixture
6135+
def project_dir_with_single_deployment(self, project_dir: str):
6136+
prefect_yaml = {
6137+
"name": "test-project",
6138+
"deployments": [
6139+
{
6140+
"name": "test-deployment",
6141+
"entrypoint": "flows.py:hello_world",
6142+
"work_pool": {"name": "test-pool"},
6143+
}
6144+
],
6145+
}
6146+
with open(Path(project_dir) / "prefect.yaml", "w") as f:
6147+
yaml.dump(prefect_yaml, f)
6148+
6149+
flows_file = Path(project_dir) / "flows.py"
6150+
flows_file.write_text("""
6151+
from prefect import flow
6152+
6153+
@flow
6154+
def hello_world():
6155+
print("Hello, world!")
6156+
""")
6157+
return project_dir
6158+
6159+
@pytest.mark.usefixtures("project_dir_with_single_deployment")
6160+
async def test_dry_run_no_api_calls(self):
6161+
"""Test that dry run mode doesn't make API calls."""
6162+
with mock.patch("prefect.cli.deploy.get_client") as mock_get_client:
6163+
mock_client = mock.AsyncMock()
6164+
mock_get_client.return_value = mock_client
6165+
6166+
# Mock the work pool to exist for validation
6167+
mock_work_pool = mock.Mock()
6168+
mock_work_pool.type = "process"
6169+
mock_work_pool.is_push_pool = False
6170+
mock_work_pool.is_managed_pool = False
6171+
mock_work_pool.base_job_template = {"variables": {"properties": {}}}
6172+
mock_client.read_work_pool.return_value = mock_work_pool
6173+
6174+
await run_sync_in_worker_thread(
6175+
invoke_and_assert,
6176+
command="deploy --all --dry-run",
6177+
expected_code=0,
6178+
expected_output_contains=[
6179+
"DRY RUN: Would create/update deployment",
6180+
"DRY RUN COMPLETE",
6181+
],
6182+
)
6183+
6184+
# Verify no deployment creation API calls were made
6185+
mock_client.create_deployment.assert_not_called()
6186+
mock_client.update_deployment.assert_not_called()
6187+
mock_client.create_automation.assert_not_called()
6188+
mock_client.apply_slas_for_deployment.assert_not_called()
6189+
6190+
@pytest.mark.usefixtures("project_dir_with_single_deployment")
6191+
async def test_dry_run_non_interactive(self):
6192+
"""Test that dry run mode is non-interactive."""
6193+
from prefect.cli.deploy import _is_interactive_mode
6194+
6195+
assert _is_interactive_mode(dry_run=True) is False
6196+
6197+
with mock.patch("prefect.cli.deploy.is_interactive", return_value=True):
6198+
assert _is_interactive_mode(dry_run=False) is True
6199+
assert _is_interactive_mode(dry_run=True) is False
6200+
6201+
@pytest.fixture
6202+
def project_dir_with_multi_deployments(self, project_dir: str):
6203+
prefect_yaml = {
6204+
"name": "test-project",
6205+
"build": [
6206+
{
6207+
"prefect_docker.deployments.steps.build_docker_image": {
6208+
"image_name": "test",
6209+
"tag": "latest",
6210+
}
6211+
}
6212+
],
6213+
"deployments": [
6214+
{
6215+
"name": "test-deployment-1",
6216+
"entrypoint": "flows.py:hello_world",
6217+
"work_pool": {"name": "test-pool"},
6218+
},
6219+
{
6220+
"name": "test-deployment-2",
6221+
"entrypoint": "flows.py:hello_world",
6222+
"work_pool": {"name": "test-pool"},
6223+
},
6224+
],
6225+
}
6226+
with open(Path(project_dir) / "prefect.yaml", "w") as f:
6227+
yaml.dump(prefect_yaml, f)
6228+
6229+
flows_file = Path(project_dir) / "flows.py"
6230+
flows_file.write_text("""
6231+
from prefect import flow
6232+
6233+
@flow
6234+
def hello_world():
6235+
print("Hello, world!")
6236+
""")
6237+
return project_dir
6238+
6239+
@pytest.mark.usefixtures("project_dir_with_multi_deployments")
6240+
async def test_dry_run_with_build_steps(self):
6241+
"""Test dry run with build steps doesn't execute them."""
6242+
with mock.patch("prefect.cli.deploy.get_client") as mock_get_client:
6243+
mock_client = mock.AsyncMock()
6244+
mock_get_client.return_value = mock_client
6245+
6246+
mock_work_pool = mock.Mock()
6247+
mock_work_pool.type = "process"
6248+
mock_work_pool.is_push_pool = False
6249+
mock_work_pool.is_managed_pool = False
6250+
mock_work_pool.base_job_template = {"variables": {"properties": {}}}
6251+
mock_client.read_work_pool.return_value = mock_work_pool
6252+
6253+
with mock.patch(
6254+
"prefect.deployments.steps.core.run_steps"
6255+
) as mock_run_steps:
6256+
await run_sync_in_worker_thread(
6257+
invoke_and_assert,
6258+
command="deploy --all --dry-run",
6259+
expected_code=0,
6260+
expected_output_contains=[
6261+
"DRY RUN MODE",
6262+
"Would run 1 build step(s)",
6263+
"DRY RUN COMPLETE",
6264+
],
6265+
)
6266+
6267+
# Verify build steps were not executed
6268+
mock_run_steps.assert_not_called()
6269+
6270+
@pytest.mark.usefixtures("project_dir_with_single_deployment")
6271+
async def test_dry_run_missing_entrypoint_fails(self):
6272+
"""Test that dry run still validates required fields."""
6273+
prefect_yaml = {
6274+
"name": "test-project",
6275+
"deployments": [
6276+
{
6277+
"name": "test-deployment",
6278+
# Missing entrypoint should fail validation
6279+
"work_pool": {"name": "test-pool"},
6280+
}
6281+
],
6282+
}
6283+
6284+
with open("prefect.yaml", "w") as f:
6285+
yaml.dump(prefect_yaml, f)
6286+
6287+
await run_sync_in_worker_thread(
6288+
invoke_and_assert,
6289+
command="deploy --all --dry-run",
6290+
expected_code=1,
6291+
expected_output_contains=[
6292+
"An entrypoint must be provided",
6293+
],
6294+
)

0 commit comments

Comments
 (0)