Initial import of cf-temp-email deploy CLI
This commit is contained in:
275
tests/test_cli.py
Normal file
275
tests/test_cli.py
Normal file
@@ -0,0 +1,275 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from cf_temp_email_deploy import cli
|
||||
from cf_temp_email_deploy.environment import ToolVersion
|
||||
from cf_temp_email_deploy.wrangler import build_wrangler_command
|
||||
|
||||
|
||||
class FakeCloudflareClient:
|
||||
def __init__(self, config: object) -> None:
|
||||
self.config = config
|
||||
self.resolve_account_called = False
|
||||
|
||||
def __enter__(self) -> "FakeCloudflareClient":
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type: object, exc: object, tb: object) -> None:
|
||||
return None
|
||||
|
||||
def verify_token(self) -> dict[str, str]:
|
||||
return {"status": "active"}
|
||||
|
||||
def resolve_account(self, *, account_id: str = "", account_name: str = "") -> dict[str, str]:
|
||||
self.resolve_account_called = True
|
||||
return {"id": account_id or "acc-1", "name": account_name or "demo-account"}
|
||||
|
||||
def resolve_zone(self, *, zone_name: str, account_id: str = "") -> dict[str, str]:
|
||||
payload = {"id": "zone-1", "name": zone_name}
|
||||
if not account_id:
|
||||
payload["account"] = {"id": "acc-from-zone", "name": "zone-account"}
|
||||
return payload
|
||||
|
||||
def list_dns_records(self, zone_id: str, *, name: str = "", record_type: str = "") -> list[dict[str, str]]:
|
||||
_ = zone_id
|
||||
_ = name
|
||||
_ = record_type
|
||||
return [
|
||||
{"type": "MX", "name": "mail.kotei.us.ci", "content": "route1.mx.cloudflare.net"},
|
||||
{"type": "MX", "name": "maila.kotei.us.ci", "content": "route2.mx.cloudflare.net"},
|
||||
{"type": "CNAME", "name": "email.kotei.us.ci", "content": "cf-temp-email-pages.pages.dev"},
|
||||
]
|
||||
|
||||
def list_email_routing_addresses(self, *, account_id: str) -> list[dict[str, str]]:
|
||||
_ = account_id
|
||||
return [{"email": "verified@kotei.us.ci", "status": "verified"}]
|
||||
|
||||
def email_address_ready(self, address: dict[str, str], target: str) -> bool:
|
||||
return address["email"] == target and address["status"] == "verified"
|
||||
|
||||
def list_d1_databases(self, *, account_id: str, database_name: str = "") -> list[dict[str, str]]:
|
||||
_ = account_id
|
||||
_ = database_name
|
||||
return [{"name": "cf-temp-email-kotei"}]
|
||||
|
||||
def list_pages_projects(self, *, account_id: str) -> list[dict[str, str]]:
|
||||
_ = account_id
|
||||
return [{"name": "cf-temp-email-pages", "subdomain": "cf-temp-email-pages.pages.dev"}]
|
||||
|
||||
def get_catch_all(self, *, zone_id: str) -> dict[str, object]:
|
||||
_ = zone_id
|
||||
return {"actions": [{"type": "worker", "value": ["temp-email-api"]}]}
|
||||
|
||||
def extract_worker_targets(self, value: object) -> set[str]:
|
||||
if isinstance(value, list):
|
||||
return {str(item) for item in value}
|
||||
return set()
|
||||
|
||||
def list_worker_scripts(self, *, account_id: str) -> list[dict[str, object]]:
|
||||
_ = account_id
|
||||
return [{"id": "temp-email-api", "handlers": ["fetch", "email"]}]
|
||||
|
||||
def worker_script_supports_email(self, script: dict[str, object]) -> bool:
|
||||
handlers = script.get("handlers", [])
|
||||
return isinstance(handlers, list) and "email" in handlers
|
||||
|
||||
def is_authentication_error(self, error: Exception) -> bool:
|
||||
_ = error
|
||||
return False
|
||||
|
||||
|
||||
def test_init_config_and_check_command(monkeypatch, tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.toml"
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli,
|
||||
"check_required_tools",
|
||||
lambda runner: {
|
||||
"git": ToolVersion(name="git", version="git version 2.43.0"),
|
||||
"node": ToolVersion(name="node", version="v24.14.0"),
|
||||
"npm": ToolVersion(name="npm", version="11.9.0"),
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(cli, "CloudflareClient", FakeCloudflareClient)
|
||||
|
||||
assert cli.main(["init-config", "--config", str(config_path)]) == 0
|
||||
assert (
|
||||
cli.main(
|
||||
[
|
||||
"check",
|
||||
"--config",
|
||||
str(config_path),
|
||||
"--api-token",
|
||||
"token-value",
|
||||
"--account-id",
|
||||
"acc-1",
|
||||
"--zone-name",
|
||||
"example.com",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
|
||||
state_path = tmp_path / ".deploy" / "state.toml"
|
||||
assert state_path.exists()
|
||||
state_text = state_path.read_text(encoding="utf-8")
|
||||
config_text = config_path.read_text(encoding="utf-8")
|
||||
assert "zone-1" in state_text
|
||||
assert 'api_token = "token-value"' in config_text
|
||||
|
||||
|
||||
def test_build_wrangler_command_uses_npm_exec() -> None:
|
||||
assert build_wrangler_command("deploy", "--minify") == (
|
||||
"npm",
|
||||
"exec",
|
||||
"--",
|
||||
"wrangler",
|
||||
"deploy",
|
||||
"--minify",
|
||||
)
|
||||
|
||||
|
||||
def test_build_parser_uses_cf_temp_email_program_name() -> None:
|
||||
parser = cli.build_parser()
|
||||
|
||||
assert parser.prog == "cf-temp-email"
|
||||
|
||||
|
||||
def test_resolve_cli_argv_defaults_to_deploy() -> None:
|
||||
assert cli.resolve_cli_argv([]) == ["deploy"]
|
||||
assert cli.resolve_cli_argv(["--config", "config.toml"]) == ["deploy", "--config", "config.toml"]
|
||||
assert cli.resolve_cli_argv(["deploy", "--config", "config.toml"]) == ["deploy", "--config", "config.toml"]
|
||||
|
||||
|
||||
def test_main_defaults_to_deploy_when_subcommand_is_omitted(monkeypatch, tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.toml"
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_handle_deploy(args: object) -> int:
|
||||
captured["command"] = getattr(args, "command", "")
|
||||
captured["config"] = getattr(args, "config", None)
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(cli, "handle_deploy", fake_handle_deploy)
|
||||
|
||||
assert cli.main(["--config", str(config_path)]) == 0
|
||||
assert captured["command"] == "deploy"
|
||||
assert captured["config"] == config_path
|
||||
|
||||
|
||||
def test_check_command_can_resolve_zone_without_explicit_account(monkeypatch, tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.toml"
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli,
|
||||
"check_required_tools",
|
||||
lambda runner: {
|
||||
"git": ToolVersion(name="git", version="git version 2.43.0"),
|
||||
"node": ToolVersion(name="node", version="v24.14.0"),
|
||||
"npm": ToolVersion(name="npm", version="11.9.0"),
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(cli, "CloudflareClient", FakeCloudflareClient)
|
||||
|
||||
assert cli.main(["init-config", "--config", str(config_path)]) == 0
|
||||
assert (
|
||||
cli.main(
|
||||
[
|
||||
"check",
|
||||
"--config",
|
||||
str(config_path),
|
||||
"--api-token",
|
||||
"token-value",
|
||||
"--zone-name",
|
||||
"osozos.top",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
|
||||
state_path = tmp_path / ".deploy" / "state.toml"
|
||||
state_text = state_path.read_text(encoding="utf-8")
|
||||
assert "acc-from-zone" in state_text
|
||||
assert "osozos.top" in state_text
|
||||
|
||||
|
||||
def test_check_command_supports_profile_scoped_config_and_state(monkeypatch, tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.toml"
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli,
|
||||
"check_required_tools",
|
||||
lambda runner: {
|
||||
"git": ToolVersion(name="git", version="git version 2.43.0"),
|
||||
"node": ToolVersion(name="node", version="v24.14.0"),
|
||||
"npm": ToolVersion(name="npm", version="11.9.0"),
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(cli, "CloudflareClient", FakeCloudflareClient)
|
||||
|
||||
assert cli.main(["init-config", "--config", str(config_path)]) == 0
|
||||
assert (
|
||||
cli.main(
|
||||
[
|
||||
"check",
|
||||
"--config",
|
||||
str(config_path),
|
||||
"--profile",
|
||||
"account_b",
|
||||
"--api-token",
|
||||
"token-b",
|
||||
"--account-id",
|
||||
"acc-b",
|
||||
"--zone-name",
|
||||
"kotei.asia",
|
||||
"--pages-domain",
|
||||
"email.kotei.asia",
|
||||
"--set",
|
||||
'mail.domains=["mail.kotei.asia","maila.kotei.asia"]',
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
|
||||
profile_state_path = tmp_path / ".deploy" / "profiles" / "account_b" / "state.toml"
|
||||
assert profile_state_path.exists()
|
||||
config_text = config_path.read_text(encoding="utf-8")
|
||||
state_text = profile_state_path.read_text(encoding="utf-8")
|
||||
assert '[profiles.account_b.cloudflare]' in config_text
|
||||
assert 'api_token = "token-b"' in config_text
|
||||
assert 'domains = ["mail.kotei.asia", "maila.kotei.asia"]' in config_text
|
||||
assert "acc-b" in state_text
|
||||
|
||||
|
||||
def test_discover_config_writes_detected_cloudflare_resources(monkeypatch, tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.toml"
|
||||
monkeypatch.setattr(cli, "CloudflareClient", FakeCloudflareClient)
|
||||
|
||||
assert cli.main(["init-config", "--config", str(config_path)]) == 0
|
||||
assert (
|
||||
cli.main(
|
||||
[
|
||||
"discover-config",
|
||||
"--config",
|
||||
str(config_path),
|
||||
"--profile",
|
||||
"kotei",
|
||||
"--api-token",
|
||||
"token-value",
|
||||
"--zone-name",
|
||||
"kotei.us.ci",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
|
||||
config_text = config_path.read_text(encoding="utf-8")
|
||||
assert '[profiles.kotei.cloudflare]' in config_text
|
||||
assert 'zone_name = "kotei.us.ci"' in config_text
|
||||
assert 'account_id = "acc-from-zone"' in config_text
|
||||
assert 'verified_destination_address = "verified@kotei.us.ci"' in config_text
|
||||
assert 'domains = ["mail.kotei.us.ci", "maila.kotei.us.ci"]' in config_text
|
||||
assert 'project_name = "cf-temp-email-pages"' in config_text
|
||||
assert 'custom_domain = "email.kotei.us.ci"' in config_text
|
||||
assert 'script_name = "temp-email-api"' in config_text
|
||||
Reference in New Issue
Block a user