maintainer edit: remove the Feishu-specific config-file guard from the shared CLI login command. Feishu now follows the Weixin pattern where channel.login owns its setup and persistence.
102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
import json
|
|
|
|
import pytest
|
|
from typer.testing import CliRunner
|
|
|
|
from nanobot.channels import feishu as feishu_module
|
|
from nanobot.channels.feishu import FeishuChannel
|
|
from nanobot.cli.commands import app
|
|
from nanobot.config import loader
|
|
from nanobot.config.schema import Config
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_feishu_login_writes_credentials_to_active_config(monkeypatch, tmp_path):
|
|
config_path = tmp_path / "config.json"
|
|
config = Config()
|
|
config.channels.feishu = {"enabled": False, "domain": "feishu"}
|
|
loader.save_config(config, config_path)
|
|
monkeypatch.setattr(loader, "_current_config_path", config_path)
|
|
monkeypatch.setattr(
|
|
feishu_module,
|
|
"qr_register",
|
|
lambda initial_domain="feishu": {
|
|
"app_id": "cli_app",
|
|
"app_secret": "secret",
|
|
"domain": "lark",
|
|
"bot_name": None,
|
|
"bot_open_id": None,
|
|
},
|
|
)
|
|
|
|
channel = FeishuChannel({"enabled": False, "domain": "feishu"}, None)
|
|
|
|
assert await channel.login() is True
|
|
data = json.loads(config_path.read_text(encoding="utf-8"))
|
|
assert data["channels"]["feishu"]["appId"] == "cli_app"
|
|
assert data["channels"]["feishu"]["appSecret"] == "secret"
|
|
assert data["channels"]["feishu"]["domain"] == "lark"
|
|
assert data["channels"]["feishu"]["enabled"] is True
|
|
|
|
|
|
def test_begin_registration_requires_login_url(monkeypatch):
|
|
monkeypatch.setattr(
|
|
feishu_module,
|
|
"_post_registration",
|
|
lambda _base_url, _body: {"device_code": "device"},
|
|
)
|
|
|
|
with pytest.raises(RuntimeError, match="login URL"):
|
|
feishu_module._begin_registration()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_feishu_login_creates_missing_active_config(monkeypatch, tmp_path):
|
|
missing_config = tmp_path / "missing.json"
|
|
monkeypatch.setattr(loader, "_current_config_path", missing_config)
|
|
monkeypatch.setattr(
|
|
feishu_module,
|
|
"qr_register",
|
|
lambda initial_domain="feishu": {
|
|
"app_id": "cli_app",
|
|
"app_secret": "secret",
|
|
"domain": "feishu",
|
|
"bot_name": None,
|
|
"bot_open_id": None,
|
|
},
|
|
)
|
|
|
|
channel = FeishuChannel({}, None)
|
|
|
|
assert await channel.login() is True
|
|
assert missing_config.exists()
|
|
data = json.loads(missing_config.read_text(encoding="utf-8"))
|
|
assert data["channels"]["feishu"]["appId"] == "cli_app"
|
|
|
|
|
|
def test_channels_login_feishu_uses_generic_channel_login(monkeypatch, tmp_path):
|
|
missing_config = tmp_path / "missing.json"
|
|
seen: dict[str, object] = {}
|
|
|
|
class _LoginChannel:
|
|
display_name = "Feishu"
|
|
|
|
def __init__(self, config, bus):
|
|
seen["config"] = config
|
|
seen["bus"] = bus
|
|
|
|
async def login(self, force: bool = False) -> bool:
|
|
seen["force"] = force
|
|
return True
|
|
|
|
monkeypatch.setattr(loader, "_current_config_path", missing_config)
|
|
monkeypatch.setattr(
|
|
"nanobot.channels.registry.discover_all",
|
|
lambda: {"feishu": _LoginChannel},
|
|
)
|
|
|
|
result = CliRunner().invoke(app, ["channels", "login", "feishu", "--force"])
|
|
|
|
assert result.exit_code == 0
|
|
assert seen["force"] is True
|