diff --git a/cogs/voice.py b/cogs/voice.py index d62d1d9..56578ad 100644 --- a/cogs/voice.py +++ b/cogs/voice.py @@ -120,16 +120,19 @@ async def check_and_cleanup_channel(self, channel): return try: - self.bot.bot_created_channels.discard(channel.id) - self.bot.channel_creators.pop(channel.id, None) - await self.bot.save_channels() - await channel_obj.delete(reason="Пустой канал созданный ботом") log.info("Удален пустой канал: %s", channel.name) except discord.errors.NotFound: log.info("Канал %s уже удален.", channel.name) except Exception: + # канал не удалился — оставляем его в отслеживаемых, + # фоновая очистка попробует ещё раз log.exception("Cleanup error") + return + + self.bot.bot_created_channels.discard(channel.id) + self.bot.channel_creators.pop(channel.id, None) + await self.bot.save_channels() async def cleanup_empty_home_channels(self, guild): """Удаляет все пустые войсы созданные ботом.""" diff --git a/tests/test_voice.py b/tests/test_voice.py new file mode 100644 index 0000000..b422aab --- /dev/null +++ b/tests/test_voice.py @@ -0,0 +1,74 @@ +import asyncio +from types import SimpleNamespace + +import discord + +from cogs.voice import VoiceCog + + +class FakeChannel: + def __init__(self, error=None): + self.id = 123 + self.name = "/home/test" + self.members = [] + self.error = error + self.deleted = False + + async def delete(self, reason=None): + if self.error: + raise self.error + self.deleted = True + + +def _make_cog(channel): + cog = VoiceCog.__new__(VoiceCog) + + async def save_channels(): + pass + + cog.bot = SimpleNamespace( + bot_created_channels={channel.id}, + channel_creators={channel.id: 1}, + get_channel=lambda cid: channel, + save_channels=save_channels, + ) + return cog + + +def _run_cleanup(cog, channel): + asyncio.run(cog.check_and_cleanup_channel(channel)) + + +def test_cleanup_removes_tracking_on_success(): + channel = FakeChannel() + cog = _make_cog(channel) + _run_cleanup(cog, channel) + assert channel.deleted + assert channel.id not in cog.bot.bot_created_channels + assert channel.id not in cog.bot.channel_creators + + +def test_cleanup_removes_tracking_on_not_found(): + response = SimpleNamespace(status=404, reason="Not Found") + channel = FakeChannel(error=discord.errors.NotFound(response, "gone")) + cog = _make_cog(channel) + _run_cleanup(cog, channel) + assert channel.id not in cog.bot.bot_created_channels + assert channel.id not in cog.bot.channel_creators + + +def test_cleanup_keeps_tracking_on_delete_error(): + channel = FakeChannel(error=RuntimeError("api down")) + cog = _make_cog(channel) + _run_cleanup(cog, channel) + assert channel.id in cog.bot.bot_created_channels + assert channel.id in cog.bot.channel_creators + + +def test_cleanup_skips_channel_with_members(): + channel = FakeChannel() + channel.members = [object()] + cog = _make_cog(channel) + _run_cleanup(cog, channel) + assert not channel.deleted + assert channel.id in cog.bot.bot_created_channels