246 lines
7.9 KiB
Python
246 lines
7.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from yuxi.channels.adapters.whatsapp.accounts.account_config import merge_account_config
|
||
|
|
from yuxi.channels.adapters.whatsapp.accounts.account_selection import resolve_default_account
|
||
|
|
from yuxi.channels.adapters.whatsapp.accounts.accounts import AccountState, MultiAccountManager
|
||
|
|
from yuxi.channels.adapters.whatsapp.per_dm_config import PerDmConfig
|
||
|
|
|
||
|
|
|
||
|
|
class TestMergeAccountConfig:
|
||
|
|
def test_override_simple_value(self):
|
||
|
|
base = {"a": 1, "b": 2}
|
||
|
|
override = {"b": 3, "c": 4}
|
||
|
|
merged = merge_account_config(base, override)
|
||
|
|
assert merged["a"] == 1
|
||
|
|
assert merged["b"] == 3
|
||
|
|
assert merged["c"] == 4
|
||
|
|
|
||
|
|
def test_merge_nested_dicts(self):
|
||
|
|
base = {"nested": {"x": 1, "y": 2}}
|
||
|
|
override = {"nested": {"y": 20, "z": 30}}
|
||
|
|
merged = merge_account_config(base, override)
|
||
|
|
assert merged["nested"]["x"] == 1
|
||
|
|
assert merged["nested"]["y"] == 20
|
||
|
|
assert merged["nested"]["z"] == 30
|
||
|
|
|
||
|
|
def test_override_nested_with_non_dict(self):
|
||
|
|
base = {"nested": {"x": 1}}
|
||
|
|
override = {"nested": "not_a_dict"}
|
||
|
|
merged = merge_account_config(base, override)
|
||
|
|
assert merged["nested"] == "not_a_dict"
|
||
|
|
|
||
|
|
def test_empty_override(self):
|
||
|
|
base = {"a": 1}
|
||
|
|
merged = merge_account_config(base, {})
|
||
|
|
assert merged == {"a": 1}
|
||
|
|
|
||
|
|
def test_empty_base(self):
|
||
|
|
merged = merge_account_config({}, {"a": 1})
|
||
|
|
assert merged == {"a": 1}
|
||
|
|
|
||
|
|
|
||
|
|
class TestResolveDefaultAccount:
|
||
|
|
def test_empty_list(self):
|
||
|
|
assert resolve_default_account([]) is None
|
||
|
|
|
||
|
|
def test_default_exists(self):
|
||
|
|
assert resolve_default_account(["account1", "default", "account2"]) == "default"
|
||
|
|
|
||
|
|
def test_no_default_returns_first(self):
|
||
|
|
assert resolve_default_account(["account1", "account2"]) == "account1"
|
||
|
|
|
||
|
|
def test_single_account(self):
|
||
|
|
assert resolve_default_account(["only"]) == "only"
|
||
|
|
|
||
|
|
|
||
|
|
class TestAccountState:
|
||
|
|
def test_create_basic(self):
|
||
|
|
state = AccountState(
|
||
|
|
account_id="test",
|
||
|
|
config={"name": "Test"},
|
||
|
|
auth_dir="/tmp/auth",
|
||
|
|
bridge_port=1234,
|
||
|
|
)
|
||
|
|
assert state.account_id == "test"
|
||
|
|
assert state.config["name"] == "Test"
|
||
|
|
assert state.auth_dir == "/tmp/auth"
|
||
|
|
assert state.bridge_port == 1234
|
||
|
|
|
||
|
|
|
||
|
|
class TestMultiAccountManager:
|
||
|
|
def test_empty_config_creates_default(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
assert mgr.account_count == 1
|
||
|
|
assert mgr.default_account_id == "default"
|
||
|
|
assert mgr.get_config() == {}
|
||
|
|
|
||
|
|
def test_default_account_id(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
assert mgr.default_account_id == "default"
|
||
|
|
|
||
|
|
def test_get_config_default(self):
|
||
|
|
mgr = MultiAccountManager({"setting": "value"})
|
||
|
|
assert mgr.get_config()["setting"] == "value"
|
||
|
|
|
||
|
|
def test_get_config_specific(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"accounts": {
|
||
|
|
"acc1": {"setting": "value1"},
|
||
|
|
"acc2": {"setting": "value2"},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
cfg = mgr.get_config("acc1")
|
||
|
|
assert cfg["setting"] == "value1"
|
||
|
|
|
||
|
|
def test_get_account_nonexistent(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
assert mgr.get_account("nonexistent") is None
|
||
|
|
|
||
|
|
def test_list_account_ids(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"accounts": {
|
||
|
|
"acc1": {},
|
||
|
|
"acc2": {},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
ids = mgr.list_account_ids()
|
||
|
|
assert set(ids) == {"acc1", "acc2"}
|
||
|
|
|
||
|
|
def test_multiple_accounts_with_default_account_config(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"defaultAccount": "acc2",
|
||
|
|
"accounts": {
|
||
|
|
"acc1": {},
|
||
|
|
"acc2": {},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
assert mgr.default_account_id == "acc2"
|
||
|
|
|
||
|
|
def test_add_account(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
mgr.add_account("new_acc", {"setting": "value"})
|
||
|
|
assert mgr.account_count == 2
|
||
|
|
assert mgr.get_account("new_acc") is not None
|
||
|
|
|
||
|
|
def test_remove_account(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"accounts": {
|
||
|
|
"acc1": {},
|
||
|
|
"acc2": {},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
assert mgr.remove_account("acc1") is True
|
||
|
|
assert mgr.account_count == 1
|
||
|
|
assert mgr.get_account("acc1") is None
|
||
|
|
|
||
|
|
def test_remove_nonexistent_account(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
assert mgr.remove_account("nonexistent") is False
|
||
|
|
|
||
|
|
def test_remove_default_account_reassigns(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"accounts": {
|
||
|
|
"acc1": {},
|
||
|
|
"acc2": {},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
old_default = mgr.default_account_id
|
||
|
|
mgr.remove_account(old_default)
|
||
|
|
assert mgr.default_account_id is not None
|
||
|
|
assert mgr.account_count == 1
|
||
|
|
|
||
|
|
def test_non_dict_account_config_uses_base(self):
|
||
|
|
mgr = MultiAccountManager({
|
||
|
|
"base_setting": "base_value",
|
||
|
|
"accounts": {
|
||
|
|
"acc1": "not_a_dict",
|
||
|
|
},
|
||
|
|
})
|
||
|
|
cfg = mgr.get_config("acc1")
|
||
|
|
assert cfg["base_setting"] == "base_value"
|
||
|
|
|
||
|
|
def test_default_get_account_returns_default(self):
|
||
|
|
mgr = MultiAccountManager({"setting": "val"})
|
||
|
|
acc = mgr.get_account()
|
||
|
|
assert acc is not None
|
||
|
|
assert acc.account_id == "default"
|
||
|
|
|
||
|
|
def test_get_config_none_returns_empty(self):
|
||
|
|
mgr = MultiAccountManager({})
|
||
|
|
mgr.remove_account("default")
|
||
|
|
assert mgr.get_config() == {}
|
||
|
|
|
||
|
|
|
||
|
|
class TestPerDmConfig:
|
||
|
|
def test_from_config_empty(self):
|
||
|
|
cfg = PerDmConfig.from_config({})
|
||
|
|
assert len(cfg.entries) == 0
|
||
|
|
|
||
|
|
def test_from_config_with_entries(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {
|
||
|
|
"8613800138000": {"enabled": True, "systemPrompt": "custom"},
|
||
|
|
"8613800138001": {"enabled": False},
|
||
|
|
}
|
||
|
|
})
|
||
|
|
assert len(cfg.entries) == 2
|
||
|
|
|
||
|
|
def test_from_config_bool_value(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {
|
||
|
|
"8613800138000": True,
|
||
|
|
}
|
||
|
|
})
|
||
|
|
entry = cfg.get("8613800138000")
|
||
|
|
assert entry is not None
|
||
|
|
assert entry["enabled"] is True
|
||
|
|
|
||
|
|
def test_get_by_phone_exact(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"8613800138000": {"enabled": True}}
|
||
|
|
})
|
||
|
|
assert cfg.get("8613800138000") is not None
|
||
|
|
|
||
|
|
def test_get_by_phone_with_plus(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"8613800138000": {"enabled": True}}
|
||
|
|
})
|
||
|
|
assert cfg.get("+8613800138000") is not None
|
||
|
|
|
||
|
|
def test_get_by_phone_normalized(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"+1 555 123 4567": {"enabled": False}}
|
||
|
|
})
|
||
|
|
entry = cfg.get("15551234567")
|
||
|
|
assert entry is not None
|
||
|
|
assert entry["enabled"] is False
|
||
|
|
|
||
|
|
def test_get_nonexistent(self):
|
||
|
|
cfg = PerDmConfig.from_config({})
|
||
|
|
assert cfg.get("nonexistent") is None
|
||
|
|
|
||
|
|
def test_is_enabled_default_true(self):
|
||
|
|
cfg = PerDmConfig.from_config({})
|
||
|
|
assert cfg.is_enabled("8613800138000") is True
|
||
|
|
|
||
|
|
def test_is_enabled_false(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"8613800138000": {"enabled": False}}
|
||
|
|
})
|
||
|
|
assert cfg.is_enabled("8613800138000") is False
|
||
|
|
|
||
|
|
def test_system_prompt_exists(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"8613800138000": {"systemPrompt": "You are helpful"}}
|
||
|
|
})
|
||
|
|
assert cfg.system_prompt("8613800138000") == "You are helpful"
|
||
|
|
|
||
|
|
def test_system_prompt_none(self):
|
||
|
|
cfg = PerDmConfig.from_config({})
|
||
|
|
assert cfg.system_prompt("unknown") is None
|
||
|
|
|
||
|
|
def test_system_prompt_not_set(self):
|
||
|
|
cfg = PerDmConfig.from_config({
|
||
|
|
"direct": {"8613800138000": {"enabled": True}}
|
||
|
|
})
|
||
|
|
assert cfg.system_prompt("8613800138000") is None
|