ForcePilot/backend/test/unit/channels/test_twitch_config_schema.py

323 lines
11 KiB
Python
Raw Normal View History

from __future__ import annotations
from yuxi.channels.adapters.twitch.config_schema import (
TwitchAccountSchema,
TwitchConfigSchema,
super_refine_twitch_config,
validate_twitch_config,
)
class TestTwitchConfigSchemaDefaults:
def test_defaults(self):
schema = TwitchConfigSchema()
assert schema.bot_username == ""
assert schema.access_token == ""
assert schema.client_id == ""
assert schema.channels == []
assert schema.group_policy == "open"
assert schema.rate_limit == 20
assert schema.rate_window == 30
assert schema.irc_host == "irc.chat.twitch.tv"
assert schema.irc_port == 6697
assert schema.strip_markdown is True
assert schema.dm_policy == "pairing"
assert schema.silent is False
assert schema.prefer_helix_send is False
def test_account_schema_defaults(self):
schema = TwitchAccountSchema()
assert schema.bot_username == ""
assert schema.access_token == ""
assert schema.channels == []
assert schema.group_policy == "open"
assert schema.rate_limit == 20
class TestTwitchConfigSchemaValidation:
def test_valid_group_policy_accepted(self):
schema = TwitchConfigSchema(group_policy="allowlist")
assert schema.group_policy == "allowlist"
def test_rate_limit_minimum(self):
schema = TwitchConfigSchema(rate_limit=1)
assert schema.rate_limit == 1
def test_valid_irc_port(self):
schema = TwitchConfigSchema(irc_port=6697)
assert schema.irc_port == 6697
def test_accounts_dict(self):
schema = TwitchConfigSchema(accounts={"default": TwitchAccountSchema(bot_username="bot1")})
assert "default" in schema.accounts
assert schema.accounts["default"].bot_username == "bot1"
def test_require_mention_default(self):
schema = TwitchConfigSchema()
assert schema.require_mention is True
def test_pairing_disabled_default(self):
schema = TwitchConfigSchema()
assert schema.pairing_enabled is False
def test_response_prefix_default(self):
schema = TwitchConfigSchema()
assert schema.response_prefix == ""
class TestValidateTwitchConfig:
def test_valid_config_no_errors(self):
config = {
"bot_username": "testbot",
"access_token": "oauth:abc",
"client_id": "client123",
"channels": ["test_channel"],
}
errors = validate_twitch_config(config)
assert errors == []
def test_missing_client_id(self):
errors = validate_twitch_config({"bot_username": "bot", "access_token": "tok", "channels": ["ch"]})
assert any("client_id" in e for e in errors)
def test_missing_access_token(self):
errors = validate_twitch_config({"bot_username": "bot", "client_id": "cid", "channels": ["ch"]})
assert any("access_token" in e for e in errors)
def test_missing_bot_username(self):
errors = validate_twitch_config({"access_token": "tok", "client_id": "cid", "channels": ["ch"]})
assert any("bot_username" in e for e in errors)
def test_missing_channels(self):
errors = validate_twitch_config({"bot_username": "bot", "access_token": "tok", "client_id": "cid"})
assert any("channel" in e for e in errors)
def test_invalid_group_policy(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"group_policy": "invalid_policy",
}
errors = validate_twitch_config(config)
assert any("group_policy" in e for e in errors)
def test_allowlist_with_empty_allow_from(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"group_policy": "allowlist",
}
errors = validate_twitch_config(config)
assert any("allowlist" in e for e in errors)
def test_allowlist_with_per_channel_allow_from_is_ok(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"group_policy": "allowlist",
"channels_config": {"ch": {"allow_from": ["user1"]}},
}
errors = validate_twitch_config(config)
assert not any("allowlist" in e for e in errors)
def test_invalid_role_in_allowed_roles(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"allowedRoles": ["admin"],
}
errors = validate_twitch_config(config)
assert any("allowedRoles" in e for e in errors)
def test_all_roles_with_allowlist_redundant(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"allowedRoles": ["all"],
"group_policy": "allowlist",
"group_allow_from": ["user1"],
}
errors = validate_twitch_config(config)
assert any("redundant" in e for e in errors)
def test_invalid_rate_limit(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"rate_limit": 0,
}
errors = validate_twitch_config(config)
assert any("rate_limit" in e for e in errors)
def test_invalid_irc_port(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"irc_port": 99999,
}
errors = validate_twitch_config(config)
assert any("irc_port" in e for e in errors)
def test_account_missing_bot_username(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"accounts": {"acct1": {"access_token": "tok"}},
}
errors = validate_twitch_config(config)
assert any("bot_username" in e for e in errors)
def test_account_missing_access_token(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"accounts": {"acct1": {"bot_username": "bot2"}},
}
errors = validate_twitch_config(config)
assert any("access_token" in e for e in errors)
def test_default_account_not_found(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"accounts": {"acct1": {"bot_username": "b", "access_token": "t"}},
"defaultAccount": "nonexistent",
}
errors = validate_twitch_config(config)
assert any("defaultAccount" in e for e in errors)
def test_invalid_dm_policy(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"dm_policy": "block_all",
}
errors = validate_twitch_config(config)
assert any("dm_policy" in e for e in errors)
def test_probe_timeout_too_small(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"probe_timeout_ms": 500,
}
errors = validate_twitch_config(config)
assert any("probe_timeout" in e for e in errors)
def test_valid_roles_accepted(self):
config = {
"bot_username": "bot",
"access_token": "tok",
"client_id": "cid",
"channels": ["ch"],
"allowedRoles": ["moderator", "vip", "subscriber"],
}
errors = validate_twitch_config(config)
assert errors == []
def test_empty_config_all_errors(self):
errors = validate_twitch_config({})
assert len(errors) >= 4
class TestSuperRefineTwitchConfig:
def test_converts_allowall_to_open(self):
config = {"group_policy": "allowall"}
refined = super_refine_twitch_config(config)
assert refined["group_policy"] == "open"
def test_converts_mention_only_to_mention(self):
config = {"group_policy": "mention_only"}
refined = super_refine_twitch_config(config)
assert refined["group_policy"] == "mention"
def test_adds_oauth_prefix(self):
config = {"access_token": "mytoken123"}
refined = super_refine_twitch_config(config)
assert refined["access_token"] == "oauth:mytoken123"
def test_preserves_existing_oauth_prefix(self):
config = {"access_token": "oauth:mytoken"}
refined = super_refine_twitch_config(config)
assert refined["access_token"] == "oauth:mytoken"
def test_strips_channel_hash_prefix(self):
config = {"channels": ["#testchannel", "@otherchannel", "plainchannel"]}
refined = super_refine_twitch_config(config)
assert refined["channels"] == ["testchannel", "otherchannel", "plainchannel"]
def test_account_tokens_normalized(self):
config = {
"access_token": "oauth:master",
"client_id": "master_cid",
"accounts": {
"acct1": {"bot_username": "b1", "access_token": "rawtoken"},
},
}
refined = super_refine_twitch_config(config)
assert refined["accounts"]["acct1"]["access_token"] == "oauth:rawtoken"
def test_account_channels_normalized(self):
config = {
"accounts": {
"acct1": {"bot_username": "b1", "access_token": "tok", "channels": ["#CH1", "@CH2"]},
},
}
refined = super_refine_twitch_config(config)
assert refined["accounts"]["acct1"]["channels"] == ["ch1", "ch2"]
def test_account_inherits_parent_fields(self):
config = {
"client_id": "parent_cid",
"rate_limit": 50,
"accounts": {
"acct1": {"bot_username": "b1", "access_token": "tok"},
},
}
refined = super_refine_twitch_config(config)
assert refined["accounts"]["acct1"]["client_id"] == "parent_cid"
assert refined["accounts"]["acct1"]["rate_limit"] == 50
def test_account_own_field_not_overwritten(self):
config = {
"client_id": "parent_cid",
"accounts": {
"acct1": {"bot_username": "b1", "access_token": "tok", "client_id": "own_cid"},
},
}
refined = super_refine_twitch_config(config)
assert refined["accounts"]["acct1"]["client_id"] == "own_cid"
def test_wildcard_allow_from_with_open_policy(self):
config = {"group_policy": "open", "group_allow_from": ["*"]}
refined = super_refine_twitch_config(config)
assert refined["group_policy"] == "open"
def test_skip_non_dict_account(self):
config = {"accounts": {"acct1": "not_a_dict"}}
refined = super_refine_twitch_config(config)
assert refined["accounts"]["acct1"] == "not_a_dict"