82 lines
3.5 KiB
Python
82 lines
3.5 KiB
Python
|
|
"""`mas compose` (MAS-WP-0006), with the forms seen in MAS-WP-0003."""
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from mas_cli.main import main
|
||
|
|
from mas_core.discovery import Response, discover
|
||
|
|
|
||
|
|
ROOT = Path(__file__).resolve().parents[1]
|
||
|
|
LIVE = str(ROOT / "examples/statute/mas.coulomb.social/.well-known/mas") # v0.2, stand-ins on
|
||
|
|
V01 = str(ROOT / "examples/statute/great-service.example/.well-known/mas") # v0.1, no stand-ins
|
||
|
|
D = "mas.coulomb.social"
|
||
|
|
|
||
|
|
|
||
|
|
def compose(capsys, *argv, statute=LIVE, domain=D):
|
||
|
|
code = main(["compose", domain, *argv, "--statute", statute, "--json"])
|
||
|
|
return code, json.loads(capsys.readouterr().out)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("argv, canonical, safe", [
|
||
|
|
# IONOS forwarding refused '=' and forced lower case; Google Groups lower-cased.
|
||
|
|
(["ticket=GS-85QJ8WC09P", "--facet", "comments"],
|
||
|
|
"ticket=GS-85QJ8WC09P+comments", "ticket--gs-85qj8wc09p+comments"),
|
||
|
|
(["ticket=GS-85QJ8WC09P"], "ticket=GS-85QJ8WC09P", "ticket--gs-85qj8wc09p"),
|
||
|
|
(["ticket", "--interaction", "callback"], "ticket!callback", "ticket---callback"),
|
||
|
|
(["support"], "support", "support"),
|
||
|
|
])
|
||
|
|
def test_canonical_and_forwarder_safe(capsys, argv, canonical, safe):
|
||
|
|
code, d = compose(capsys, *argv)
|
||
|
|
assert code == 0 and d["local_part"] == canonical and d["address"] == f"{canonical}@{D}"
|
||
|
|
assert d["forms"]["forwarder-safe"]["local_part"] == safe
|
||
|
|
assert d["warnings"] == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_named_destinations(capsys):
|
||
|
|
code, d = compose(capsys, "ticket=GS-85QJ8WC09P", "--facet", "comments",
|
||
|
|
"--for", "google-groups", "--for", "ionos-forward")
|
||
|
|
assert d["forms"]["google-groups"]["local_part"] == "ticket=gs-85qj8wc09p+comments"
|
||
|
|
assert d["forms"]["ionos-forward"]["applied"] == ["resource-alternate", "lowercase"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_id_containing_equals_has_no_forwarder_safe_form(capsys):
|
||
|
|
code, d = compose(capsys, "ticket=RE=2026-4711")
|
||
|
|
assert code == 0 and d["local_part"] == "ticket=RE=2026-4711"
|
||
|
|
assert d["forms"]["forwarder-safe"] == {"local_part": None, "error": "cannot-express",
|
||
|
|
"message": "resource id itself contains '='"}
|
||
|
|
|
||
|
|
|
||
|
|
def test_facet_and_interaction_are_exclusive(capsys):
|
||
|
|
code = main(["compose", D, "ticket=GS-1", "--facet", "c", "--interaction", "callback",
|
||
|
|
"--statute", LIVE])
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert code == 1 and "generator-facet-and-interaction" in out and "exclusive" in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_octet_budget(capsys):
|
||
|
|
code, d = compose(capsys, "ticket=" + "X" * 50)
|
||
|
|
assert code == 0 and d["octets"] == 57
|
||
|
|
assert any("57/64 octets" in w for w in d["warnings"])
|
||
|
|
code = main(["compose", D, "ticket=" + "X" * 60, "--statute", LIVE])
|
||
|
|
assert code == 1 and "64" in capsys.readouterr().out
|
||
|
|
|
||
|
|
|
||
|
|
def test_statute_mismatch_is_a_warning(capsys):
|
||
|
|
code, d = compose(capsys, "ticket=GS-1", "--interaction", "chat")
|
||
|
|
assert code == 0 and any(w.startswith("InteractionModeNotEnabled") for w in d["warnings"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_no_forwarder_safe_form_without_stand_ins(capsys):
|
||
|
|
code, d = compose(capsys, "ticket=PR42", statute=V01, domain="great-service.example")
|
||
|
|
assert code == 0 and d["forms"] == {}
|
||
|
|
|
||
|
|
|
||
|
|
def test_without_statute(capsys, monkeypatch):
|
||
|
|
import mas_cli.main as cli
|
||
|
|
monkeypatch.setattr(cli, "discover", lambda host, **kw: discover(
|
||
|
|
host, transport=lambda u, t: Response(404, {}, b"")))
|
||
|
|
assert main(["compose", D, "ticket=GS-1", "--for", "google-groups", "--json"]) == 0
|
||
|
|
d = json.loads(capsys.readouterr().out)
|
||
|
|
assert d["forms"] == {} and any("no valid MAS statute" in w for w in d["warnings"])
|