chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
"""CLI tests for `opensquilla channels`."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from opensquilla.cli.main import app
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
||||
def _setenv(monkeypatch, tmp_path: Path) -> Path:
|
||||
target = tmp_path / "c.toml"
|
||||
monkeypatch.setenv("OPENSQUILLA_GATEWAY_CONFIG_PATH", str(target))
|
||||
return target
|
||||
|
||||
|
||||
def test_channels_list_empty(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "list"])
|
||||
assert result.exit_code == 0
|
||||
assert "0 channels" in result.stdout.lower()
|
||||
|
||||
|
||||
def test_channels_add_telegram_polling_minimal(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
["channels", "add", "telegram", "--name", "tg", "--token", "abc"],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
text = target.read_text()
|
||||
assert "tg" in text
|
||||
assert "telegram" in text
|
||||
assert "abc" not in result.stdout
|
||||
assert "restart" in result.stdout.lower()
|
||||
|
||||
|
||||
def test_channels_add_slack_missing_token_fails(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "add", "slack", "--name", "w"])
|
||||
assert result.exit_code != 0
|
||||
combined = (result.stdout + (result.stderr or "")).lower()
|
||||
assert "token" in combined
|
||||
|
||||
|
||||
def test_channels_add_slack_succeeds_with_token(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"channels", "add", "slack",
|
||||
"--name", "w", "--token", "xoxb-x",
|
||||
"--field", "signing_secret=ss",
|
||||
"--field", "slack_channel_id=C123",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
text = target.read_text()
|
||||
assert "C123" in text
|
||||
assert "xoxb-x" not in result.stdout
|
||||
|
||||
|
||||
def test_channels_remove(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(app, ["channels", "add", "slack",
|
||||
"--name", "w", "--token", "x",
|
||||
"--field", "signing_secret=ss"])
|
||||
result = runner.invoke(app, ["channels", "remove", "w"])
|
||||
assert result.exit_code == 0
|
||||
# Either the channel is gone, or the [[channels.channels]] table is empty.
|
||||
text = target.read_text()
|
||||
assert 'name = "w"' not in text
|
||||
|
||||
|
||||
def test_channels_disable_then_enable(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(app, ["channels", "add", "slack",
|
||||
"--name", "w", "--token", "x",
|
||||
"--field", "signing_secret=ss"])
|
||||
r1 = runner.invoke(app, ["channels", "disable", "w"])
|
||||
assert r1.exit_code == 0
|
||||
assert "enabled = false" in target.read_text()
|
||||
r2 = runner.invoke(app, ["channels", "enable", "w"])
|
||||
assert r2.exit_code == 0
|
||||
assert "enabled = true" in target.read_text()
|
||||
|
||||
|
||||
def test_channels_list_redacts_secrets(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(app, ["channels", "add", "slack",
|
||||
"--name", "w", "--token", "supersecret",
|
||||
"--field", "signing_secret=ss"])
|
||||
result = runner.invoke(app, ["channels", "list"])
|
||||
assert "supersecret" not in result.stdout
|
||||
assert "***" in result.stdout
|
||||
|
||||
|
||||
def test_channels_edit_updates_only_provided_fields(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(
|
||||
app,
|
||||
["channels", "add", "slack", "--name", "w",
|
||||
"--token", "xoxb-original",
|
||||
"--field", "signing_secret=ss",
|
||||
"--field", "slack_channel_id=C111"],
|
||||
)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
["channels", "edit", "w", "--field", "slack_channel_id=C222"],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
text = target.read_text()
|
||||
assert "C222" in text
|
||||
assert "C111" not in text
|
||||
assert "xoxb-original" in text
|
||||
|
||||
|
||||
def test_channels_edit_unknown_name_fails(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "edit", "missing"])
|
||||
assert result.exit_code != 0
|
||||
|
||||
|
||||
def test_channels_edit_preserves_enabled_when_unchanged(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(
|
||||
app,
|
||||
["channels", "add", "slack", "--name", "w",
|
||||
"--token", "xoxb-x", "--field", "signing_secret=ss", "--disabled"],
|
||||
)
|
||||
assert "enabled = false" in target.read_text()
|
||||
r = runner.invoke(
|
||||
app, ["channels", "edit", "w", "--field", "slack_channel_id=C9"]
|
||||
)
|
||||
assert r.exit_code == 0, r.stdout
|
||||
text = target.read_text()
|
||||
assert "enabled = false" in text
|
||||
assert "C9" in text
|
||||
|
||||
|
||||
def test_channels_edit_preserves_agent_id_when_unchanged(tmp_path, monkeypatch):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(
|
||||
app,
|
||||
["channels", "add", "slack", "--name", "w",
|
||||
"--token", "xoxb-x", "--field", "signing_secret=ss", "--agent-id", "ops"],
|
||||
)
|
||||
assert 'agent_id = "ops"' in target.read_text()
|
||||
r = runner.invoke(
|
||||
app, ["channels", "edit", "w", "--field", "slack_channel_id=C9"]
|
||||
)
|
||||
assert r.exit_code == 0, r.stdout
|
||||
assert 'agent_id = "ops"' in target.read_text()
|
||||
|
||||
|
||||
def test_channels_edit_preserves_non_secret_bool_when_unchanged(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
target = _setenv(monkeypatch, tmp_path)
|
||||
runner.invoke(
|
||||
app,
|
||||
["channels", "add", "slack", "--name", "w",
|
||||
"--token", "xoxb-x",
|
||||
"--field", "signing_secret=ss",
|
||||
"--field", "reply_in_thread=true"],
|
||||
)
|
||||
assert "reply_in_thread = true" in target.read_text()
|
||||
r = runner.invoke(
|
||||
app, ["channels", "edit", "w", "--field", "slack_channel_id=C9"]
|
||||
)
|
||||
assert r.exit_code == 0, r.stdout
|
||||
assert "reply_in_thread = true" in target.read_text()
|
||||
|
||||
|
||||
def test_channels_add_token_resolves_to_alias_order_not_field_order(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""For wecom, --token should resolve to the literal 'token' field
|
||||
(alias index 0), not 'corp_secret' (alias index 5) which would happen
|
||||
under naive spec-field-order resolution.
|
||||
"""
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
["channels", "add", "wecom",
|
||||
"--name", "wc",
|
||||
"--token", "wecom-token",
|
||||
"--field", "corp_id=cid",
|
||||
"--field", "corp_secret=cs",
|
||||
"--field", "agent_id_int=1000",
|
||||
"--field", "encoding_aes_key=" + "a" * 43],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
assert "wecom.token" in result.stdout
|
||||
assert "wecom.corp_secret" not in result.stdout
|
||||
|
||||
|
||||
def test_channels_add_token_flag_echoes_resolved_field(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app, ["channels", "add", "matrix",
|
||||
"--name", "m",
|
||||
"--token", "syt-abc",
|
||||
"--field", "homeserver_url=https://matrix.org",
|
||||
"--field", "user_id=@me:matrix.org"]
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
assert "--token" in result.stdout
|
||||
assert "matrix.access_token" in result.stdout
|
||||
|
||||
|
||||
def test_channels_add_token_flag_for_slack_resolves_to_token(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"channels", "add", "slack",
|
||||
"--name", "w", "--token", "xoxb-x",
|
||||
"--field", "signing_secret=ss",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
assert "slack.token" in result.stdout
|
||||
|
||||
|
||||
def test_channels_describe_slack(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "describe", "slack"])
|
||||
assert result.exit_code == 0
|
||||
out = result.stdout
|
||||
assert "token" in out
|
||||
assert "signing_secret" in out
|
||||
assert "webhook" in out.lower()
|
||||
assert "api.slack.com" in out
|
||||
|
||||
|
||||
def test_channels_describe_unknown_type_fails(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "describe", "no-such-type"])
|
||||
assert result.exit_code != 0
|
||||
|
||||
|
||||
def test_channels_types_lists_all_supported(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(app, ["channels", "types"])
|
||||
assert result.exit_code == 0
|
||||
out = result.stdout
|
||||
for t in ("slack", "telegram", "discord", "feishu",
|
||||
"dingtalk", "wecom", "qq", "matrix"):
|
||||
assert t in out
|
||||
# msteams is intentionally hidden from the channel catalog CLI surface
|
||||
# until first-class support lands.
|
||||
assert "msteams" not in out
|
||||
assert "transport" in out.lower()
|
||||
|
||||
|
||||
def test_channels_add_restart_notice_disambiguates(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"channels", "add", "slack",
|
||||
"--name", "w", "--token", "x",
|
||||
"--field", "signing_secret=ss",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
out = result.stdout.lower()
|
||||
assert "gateway process" in out
|
||||
assert "not the same as" in out
|
||||
assert "channels restart" in out
|
||||
|
||||
|
||||
def test_channels_add_prints_status_verification_next_step(tmp_path, monkeypatch):
|
||||
_setenv(monkeypatch, tmp_path)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"channels", "add", "slack",
|
||||
"--name", "w", "--token", "x",
|
||||
"--field", "signing_secret=ss",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
out = result.stdout.lower()
|
||||
assert "opensquilla gateway restart" in out
|
||||
assert "opensquilla channels status w --json" in out
|
||||
|
||||
|
||||
def test_channels_add_echoes_resolved_path_and_source(tmp_path, monkeypatch):
|
||||
monkeypatch.delenv("OPENSQUILLA_GATEWAY_CONFIG_PATH", raising=False)
|
||||
monkeypatch.setenv("HOME", str(tmp_path / "home"))
|
||||
project = tmp_path / "project"
|
||||
project.mkdir()
|
||||
(project / "opensquilla.toml").write_text("")
|
||||
monkeypatch.chdir(project)
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"channels", "add", "slack",
|
||||
"--name", "w", "--token", "x",
|
||||
"--field", "signing_secret=ss",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
assert str(project / "opensquilla.toml") in result.stdout
|
||||
assert "cwd" in result.stdout.lower()
|
||||
Reference in New Issue
Block a user