286 lines
9.0 KiB
Python
286 lines
9.0 KiB
Python
"""
|
|
Tests for cloudflare-deploy.py
|
|
|
|
Run with: pytest test_cloudflare_deploy.py -v
|
|
"""
|
|
|
|
import pytest
|
|
import subprocess
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch, mock_open
|
|
import sys
|
|
import os
|
|
|
|
# Add parent directory to path for imports
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from cloudflare_deploy import CloudflareDeploy, CloudflareDeployError
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_project(tmp_path):
|
|
"""Create temporary project directory with wrangler.toml"""
|
|
project_dir = tmp_path / "test-worker"
|
|
project_dir.mkdir()
|
|
|
|
wrangler_toml = project_dir / "wrangler.toml"
|
|
wrangler_toml.write_text('''
|
|
name = "test-worker"
|
|
main = "src/index.ts"
|
|
compatibility_date = "2024-01-01"
|
|
''')
|
|
|
|
return project_dir
|
|
|
|
|
|
@pytest.fixture
|
|
def deployer(temp_project):
|
|
"""Create CloudflareDeploy instance with temp project"""
|
|
return CloudflareDeploy(
|
|
project_dir=temp_project,
|
|
env="staging",
|
|
dry_run=False,
|
|
verbose=False
|
|
)
|
|
|
|
|
|
class TestCloudflareDeployInit:
|
|
"""Test CloudflareDeploy initialization"""
|
|
|
|
def test_init_with_defaults(self, temp_project):
|
|
deployer = CloudflareDeploy(project_dir=temp_project)
|
|
assert deployer.project_dir == temp_project.resolve()
|
|
assert deployer.env is None
|
|
assert deployer.dry_run is False
|
|
assert deployer.verbose is False
|
|
|
|
def test_init_with_custom_params(self, temp_project):
|
|
deployer = CloudflareDeploy(
|
|
project_dir=temp_project,
|
|
env="production",
|
|
dry_run=True,
|
|
verbose=True
|
|
)
|
|
assert deployer.env == "production"
|
|
assert deployer.dry_run is True
|
|
assert deployer.verbose is True
|
|
|
|
|
|
class TestValidateProject:
|
|
"""Test project validation"""
|
|
|
|
def test_validate_existing_project(self, deployer):
|
|
assert deployer.validate_project() is True
|
|
|
|
def test_validate_nonexistent_project(self, tmp_path):
|
|
deployer = CloudflareDeploy(project_dir=tmp_path / "nonexistent")
|
|
with pytest.raises(CloudflareDeployError, match="does not exist"):
|
|
deployer.validate_project()
|
|
|
|
def test_validate_missing_wrangler_toml(self, tmp_path):
|
|
project_dir = tmp_path / "no-toml"
|
|
project_dir.mkdir()
|
|
deployer = CloudflareDeploy(project_dir=project_dir)
|
|
|
|
with pytest.raises(CloudflareDeployError, match="wrangler.toml not found"):
|
|
deployer.validate_project()
|
|
|
|
|
|
class TestCheckWranglerInstalled:
|
|
"""Test wrangler CLI detection"""
|
|
|
|
@patch('subprocess.run')
|
|
def test_wrangler_installed(self, mock_run, deployer):
|
|
mock_run.return_value = Mock(
|
|
returncode=0,
|
|
stdout="wrangler 3.0.0",
|
|
stderr=""
|
|
)
|
|
assert deployer.check_wrangler_installed() is True
|
|
|
|
@patch('subprocess.run')
|
|
def test_wrangler_not_installed(self, mock_run, deployer):
|
|
mock_run.side_effect = FileNotFoundError()
|
|
assert deployer.check_wrangler_installed() is False
|
|
|
|
@patch('subprocess.run')
|
|
def test_wrangler_command_fails(self, mock_run, deployer):
|
|
mock_run.side_effect = subprocess.CalledProcessError(1, "wrangler")
|
|
assert deployer.check_wrangler_installed() is False
|
|
|
|
|
|
class TestGetWorkerName:
|
|
"""Test worker name extraction"""
|
|
|
|
def test_get_worker_name_success(self, deployer):
|
|
name = deployer.get_worker_name()
|
|
assert name == "test-worker"
|
|
|
|
def test_get_worker_name_no_name(self, tmp_path):
|
|
project_dir = tmp_path / "no-name"
|
|
project_dir.mkdir()
|
|
|
|
wrangler_toml = project_dir / "wrangler.toml"
|
|
wrangler_toml.write_text("main = 'index.ts'")
|
|
|
|
deployer = CloudflareDeploy(project_dir=project_dir)
|
|
with pytest.raises(CloudflareDeployError, match="Worker name not found"):
|
|
deployer.get_worker_name()
|
|
|
|
def test_get_worker_name_with_quotes(self, tmp_path):
|
|
project_dir = tmp_path / "quoted"
|
|
project_dir.mkdir()
|
|
|
|
wrangler_toml = project_dir / "wrangler.toml"
|
|
wrangler_toml.write_text('name = "my-worker"\n')
|
|
|
|
deployer = CloudflareDeploy(project_dir=project_dir)
|
|
assert deployer.get_worker_name() == "my-worker"
|
|
|
|
def test_get_worker_name_single_quotes(self, tmp_path):
|
|
project_dir = tmp_path / "single-quotes"
|
|
project_dir.mkdir()
|
|
|
|
wrangler_toml = project_dir / "wrangler.toml"
|
|
wrangler_toml.write_text("name = 'my-worker'\n")
|
|
|
|
deployer = CloudflareDeploy(project_dir=project_dir)
|
|
assert deployer.get_worker_name() == "my-worker"
|
|
|
|
|
|
class TestBuildDeployCommand:
|
|
"""Test deploy command construction"""
|
|
|
|
def test_basic_command(self, temp_project):
|
|
deployer = CloudflareDeploy(project_dir=temp_project)
|
|
cmd = deployer.build_deploy_command()
|
|
assert cmd == ["wrangler", "deploy"]
|
|
|
|
def test_command_with_env(self, temp_project):
|
|
deployer = CloudflareDeploy(project_dir=temp_project, env="production")
|
|
cmd = deployer.build_deploy_command()
|
|
assert cmd == ["wrangler", "deploy", "--env", "production"]
|
|
|
|
def test_command_with_dry_run(self, temp_project):
|
|
deployer = CloudflareDeploy(project_dir=temp_project, dry_run=True)
|
|
cmd = deployer.build_deploy_command()
|
|
assert cmd == ["wrangler", "deploy", "--dry-run"]
|
|
|
|
def test_command_with_env_and_dry_run(self, temp_project):
|
|
deployer = CloudflareDeploy(
|
|
project_dir=temp_project,
|
|
env="staging",
|
|
dry_run=True
|
|
)
|
|
cmd = deployer.build_deploy_command()
|
|
assert cmd == ["wrangler", "deploy", "--env", "staging", "--dry-run"]
|
|
|
|
|
|
class TestRunCommand:
|
|
"""Test command execution"""
|
|
|
|
@patch('subprocess.run')
|
|
def test_run_command_success(self, mock_run, deployer):
|
|
mock_run.return_value = Mock(
|
|
returncode=0,
|
|
stdout="Success",
|
|
stderr=""
|
|
)
|
|
|
|
exit_code, stdout, stderr = deployer.run_command(["echo", "test"])
|
|
|
|
assert exit_code == 0
|
|
assert stdout == "Success"
|
|
assert stderr == ""
|
|
mock_run.assert_called_once()
|
|
|
|
@patch('subprocess.run')
|
|
def test_run_command_failure_with_check(self, mock_run, deployer):
|
|
mock_run.side_effect = subprocess.CalledProcessError(
|
|
1, "cmd", stderr="Error"
|
|
)
|
|
|
|
with pytest.raises(CloudflareDeployError, match="Command failed"):
|
|
deployer.run_command(["false"], check=True)
|
|
|
|
@patch('subprocess.run')
|
|
def test_run_command_failure_no_check(self, mock_run, deployer):
|
|
mock_run.side_effect = subprocess.CalledProcessError(
|
|
1, "cmd", output="", stderr="Error"
|
|
)
|
|
|
|
exit_code, stdout, stderr = deployer.run_command(["false"], check=False)
|
|
|
|
assert exit_code == 1
|
|
|
|
|
|
class TestDeploy:
|
|
"""Test full deployment flow"""
|
|
|
|
@patch.object(CloudflareDeploy, 'check_wrangler_installed')
|
|
@patch.object(CloudflareDeploy, 'run_command')
|
|
def test_deploy_success(self, mock_run_cmd, mock_check_wrangler, deployer):
|
|
mock_check_wrangler.return_value = True
|
|
mock_run_cmd.return_value = (0, "Deployed successfully", "")
|
|
|
|
result = deployer.deploy()
|
|
|
|
assert result is True
|
|
mock_check_wrangler.assert_called_once()
|
|
mock_run_cmd.assert_called_once()
|
|
|
|
@patch.object(CloudflareDeploy, 'check_wrangler_installed')
|
|
def test_deploy_wrangler_not_installed(self, mock_check_wrangler, deployer):
|
|
mock_check_wrangler.return_value = False
|
|
|
|
with pytest.raises(CloudflareDeployError, match="wrangler CLI not installed"):
|
|
deployer.deploy()
|
|
|
|
@patch.object(CloudflareDeploy, 'check_wrangler_installed')
|
|
@patch.object(CloudflareDeploy, 'run_command')
|
|
def test_deploy_command_fails(self, mock_run_cmd, mock_check_wrangler, deployer):
|
|
mock_check_wrangler.return_value = True
|
|
mock_run_cmd.side_effect = CloudflareDeployError("Deploy failed")
|
|
|
|
with pytest.raises(CloudflareDeployError, match="Deploy failed"):
|
|
deployer.deploy()
|
|
|
|
def test_deploy_invalid_project(self, tmp_path):
|
|
deployer = CloudflareDeploy(project_dir=tmp_path / "nonexistent")
|
|
|
|
with pytest.raises(CloudflareDeployError):
|
|
deployer.deploy()
|
|
|
|
|
|
class TestIntegration:
|
|
"""Integration tests"""
|
|
|
|
@patch.object(CloudflareDeploy, 'check_wrangler_installed')
|
|
@patch.object(CloudflareDeploy, 'run_command')
|
|
def test_full_deployment_flow(self, mock_run_cmd, mock_check_wrangler, temp_project):
|
|
mock_check_wrangler.return_value = True
|
|
mock_run_cmd.return_value = (0, "Success", "")
|
|
|
|
deployer = CloudflareDeploy(
|
|
project_dir=temp_project,
|
|
env="production",
|
|
dry_run=False,
|
|
verbose=True
|
|
)
|
|
|
|
result = deployer.deploy()
|
|
|
|
assert result is True
|
|
assert mock_run_cmd.call_count == 1
|
|
|
|
# Verify correct command was built
|
|
call_args = mock_run_cmd.call_args[0][0]
|
|
assert "wrangler" in call_args
|
|
assert "deploy" in call_args
|
|
assert "--env" in call_args
|
|
assert "production" in call_args
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"])
|