async def test_get_all_guilds(self, create_redis_cache): guilds = await FactoryBuilder.get_all_guilds_as_list(create_redis_cache) assert len(guilds) == 0 await create_redis_cache.set_guild(Guild(1, Options())) guilds = await FactoryBuilder.get_all_guilds_as_list(create_redis_cache) assert len(guilds) == 1 await create_redis_cache.set_guild(Guild(2, Options())) guilds = await FactoryBuilder.get_all_guilds_as_list(create_redis_cache) assert len(guilds) == 2 assert guilds == [Guild(1, Options()), Guild(2, Options())]
async def test_user_propagate_skip_guild(self, create_core): """Tests if the member gets skipped if not 'in guild'""" msg = MockedMessage(author_id=1, guild_id=1).to_mock() guild = Guild(1, Options) guild.members[1] = Member(1, 1, internal_is_in_guild=False) payload = await create_core.propagate(msg, guild) assert payload == CorePayload( member_status= "Bypassing message check since the member doesn't seem to be in a guild" )
async def test_clean_cache_strict_guild(self, create_handler): """Tests clean_cache on guilds with strict mode""" await create_handler.cache.set_guild(Guild(1)) assert bool(create_handler.cache.cache) await create_handler.clean_cache(strict=True) assert not bool(create_handler.cache.cache) await create_handler.cache.set_guild(Guild(1, Options(no_punish=True))) assert bool(create_handler.cache.cache) await create_handler.clean_cache(strict=True) assert bool(create_handler.cache.cache)
async def test_set_get_guild_valid_interval(self, create_anti_spam_tracker): await create_anti_spam_tracker.anti_spam_handler.cache.set_guild( Guild(1, Options())) result = await create_anti_spam_tracker.anti_spam_handler.cache.get_guild( 1) assert len(result.addons) == 0 await create_anti_spam_tracker._set_guild_valid_interval(1, 15) result = await create_anti_spam_tracker.anti_spam_handler.cache.get_guild( 1) assert len(result.addons) == 1 get_result = await create_anti_spam_tracker._get_guild_valid_interval(1 ) assert get_result == 15 # Code coverage to ensure it works within try await create_anti_spam_tracker._set_guild_valid_interval(1, 25) result = await create_anti_spam_tracker.anti_spam_handler.cache.get_guild( 1) assert len(result.addons) == 1 get_result = await create_anti_spam_tracker._get_guild_valid_interval(1 ) assert get_result == 25
async def test_get_guild_data_fails_on_guild_addon( self, create_plugin_cache: PluginCache, create_handler): """Test the cache raises GuildAddonNotFound""" await create_handler.cache.set_guild(Guild(1, Options())) with pytest.raises(GuildAddonNotFound): await create_plugin_cache.get_guild_data(1)
def test_remove_duplicate_count(self, create_core): guild = Guild(1) member = Member(1, 1) member.duplicate_counter = 5 member.duplicate_channel_counter_dict = {15: 2} assert member.duplicate_counter == 5 assert member.duplicate_channel_counter_dict == {15: 2} create_core._remove_duplicate_count(member, guild, 1) assert member.duplicate_counter == 4 assert member.duplicate_channel_counter_dict == {15: 2} create_core._remove_duplicate_count(member, guild, 1, 2) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 2} guild.options.per_channel_spam = True create_core._remove_duplicate_count(member, guild, 15) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 1} create_core._remove_duplicate_count(member, guild, 1) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 1}
async def test_propagate_warn_only(self, create_core): member = Member(1, 1) await create_core.cache.set_member(member) create_core._increment_duplicate_count(member, Guild(1), 1, 15) guild = await create_core.cache.get_guild(1) create_core.options.warn_only = True return_data = await create_core.propagate_user( MockedMessage(guild_id=1, author_id=1).to_mock(), guild) assert return_data == CorePayload( member_should_be_punished_this_message=True, member_status="Member was warned", member_was_warned=True, member_warn_count=1, member_duplicate_count=15, ) # Test embed coverage create_core.options.guild_log_warn_message = {"title": "test"} return_data = await create_core.propagate_user( MockedMessage(guild_id=1, author_id=1, message_id=2).to_mock(), guild) assert return_data == CorePayload( member_should_be_punished_this_message=True, member_status="Member was warned", member_was_warned=True, member_warn_count=2, member_duplicate_count=16, )
def test_calculate_ratio_edge_case(self, create_core): """Tests calculate ratios correctly marks an edge case as spam See: https://mystb.in/HarderTournamentsPrimary.properties Previously it would not mark all "Spam tho" as spam when it should have """ member = Member(1, 1) member.messages = [ Message(1, 1, 1, 1, "This is a test", datetime.datetime.now()), Message(2, 1, 1, 1, "Heres another message", datetime.datetime.now()), Message(3, 1, 1, 1, "Spam tho", datetime.datetime.now()), Message(4, 1, 1, 1, "Spam tho", datetime.datetime.now()), Message(5, 1, 1, 1, "Spam tho", datetime.datetime.now()), ] message = Message(6, 1, 1, 1, "Spam tho", datetime.datetime.now()) create_core._calculate_ratios(message, member, Guild(1)) assert message.is_duplicate is True assert member.messages[0].is_duplicate is False assert member.messages[1].is_duplicate is False assert member.messages[2].is_duplicate is True assert member.messages[3].is_duplicate is True assert member.messages[4].is_duplicate is True
def test_increment_duplicate_existing(self, create_core): """Tests the count increments even when already existing""" member = Member(1, 1, duplicate_channel_counter_dict={5: 1}) g = Guild(1) g.options.per_channel_spam = True create_core._increment_duplicate_count(member, g, 5) assert member.duplicate_channel_counter_dict[5] == 2
async def add_guild_log_channel(self, log_channel: int, guild_id: int) -> None: """ Registers a log channel on a guild internally Parameters ---------- log_channel : int The channel id you wish to use for logging guild_id : int The id of the guild to store this on Notes ----- Not setting a log channel means it will not send any punishment messages """ if not isinstance(log_channel, int): raise ValueError("Expected log_channel with correct type") try: guild = await self.cache.get_guild(guild_id=guild_id) guild.log_channel_id = log_channel except GuildNotFound: guild = Guild( id=guild_id, options=self.options, log_channel_id=log_channel, ) await self.cache.set_guild(guild)
def test_calculate_ratios_does_nothing(self, create_core): """Tests the loop does nothing on different messages""" member = Member(1, 1, messages=[Message(1, 2, 3, 4, "Hello I am the world")]) create_core._calculate_ratios(Message(2, 2, 3, 4, "My name is Ethan!"), member, Guild(1))
async def set_guild(self, guild: Guild) -> None: log.debug("Attempting to set Guild(id=%s)", guild.id) # Store members separate for member in guild.members.values(): await self.set_member(member) guild.members = [member.id for member in guild.members.values()] as_json = json.dumps(asdict(guild, recurse=True)) await self.redis.set(f"GUILD:{guild.id}", as_json)
async def test_get_member(self, create_memory_cache): await create_memory_cache.set_guild(Guild(1, Options())) with pytest.raises(MemberNotFound): await create_memory_cache.get_member(1, 1) create_memory_cache.cache[1].members[1] = 2 val = await create_memory_cache.get_member(1, 1) assert val == 2
async def test_save_to_dict(self, create_handler: AntiSpamHandler): await create_handler.save_to_dict() await create_handler.cache.set_guild(Guild(1, Options())) data = await create_handler.save_to_dict() with open("tests/raw.json", "r") as file: stored_data = json.load(file) assert data == stored_data
async def set_guild(self, guild: Guild) -> None: log.debug("Attempting to set Guild(id=%s)", guild.id) # Since self.members exists members: List[Member] = list(guild.members.values()) guild.members = {} iters = [self.set_member(m) for m in members] await asyncio.gather(*iters) await self.guilds.upsert({"id": guild.id}, asdict(guild, recurse=True))
async def test_add_message_filled_guild(self, create_redis_cache): """Test with an existing guild""" await create_redis_cache.set_guild(Guild(3, Options())) await create_redis_cache.add_message(Message(1, 2, 3, 4, "Content")) r_1 = await create_redis_cache.get_member(4, 3) r_2 = await create_redis_cache.get_guild(3) assert len(r_2.members) == 1 assert len(r_1.messages) == 1
async def test_set_guild(self, create_mongo_cache): with pytest.raises(GuildNotFound): await create_mongo_cache.get_guild(2) set_guild = Guild(2, log_channel_id=12345) await create_mongo_cache.set_guild(set_guild) r_1 = await create_mongo_cache.get_guild(2) assert isinstance(r_1, Guild) assert r_1 == set_guild
async def test_remove_guild_log_channel(self, create_handler: AntiSpamHandler): await create_handler.remove_guild_log_channel(1) # shouldnt raise await create_handler.cache.set_guild(Guild(1, Options(), log_channel_id=1)) result = await create_handler.cache.get_guild(1) assert result.log_channel_id == 1 await create_handler.remove_guild_log_channel(1) result = await create_handler.cache.get_guild(1) assert result.log_channel_id is None
async def test_punish_member(self, create_dpy_lib_handler): """Adds test coverage""" await create_dpy_lib_handler.punish_member( MockedMessage(author_id=1, guild_id=1).to_mock(), Member(1, 1), Guild(1, Options()), "test user", "test guild", True, )
async def test_get_member(self, create_redis_cache): await create_redis_cache.set_guild(Guild(1, Options())) with pytest.raises(MemberNotFound): await create_redis_cache.get_member(1, 1) await create_redis_cache.set_member(Member(1, 1)) val = await create_redis_cache.get_member(1, 1) assert val assert isinstance(val, Member)
async def test_set_member(self, create_memory_cache): await create_memory_cache.set_member(Member(1, 1)) await create_memory_cache.set_member(Member(2, 1)) assert len(create_memory_cache.cache[1].members) == 2 await create_memory_cache.set_guild(Guild(1, Options())) assert len(create_memory_cache.cache[1].members) == 0 await create_memory_cache.set_member(Member(1, 1)) assert len(create_memory_cache.cache[1].members) == 1
def test_calculate_ratios_raises(self, create_core): member = Member( 1, 1, messages=[Message(1, 2, 3, 4, "One"), Message(2, 2, 3, 4, "Two")]) m = Message(1, 2, 3, 4, "One") m.creation_time = member.messages[0].creation_time with pytest.raises(DuplicateObject): create_core._calculate_ratios(m, member, Guild(1))
async def test_get_guild(self, create_redis_cache): with pytest.raises(GuildNotFound): await create_redis_cache.get_guild(1) create_redis_cache.redis.cache["GUILD:1"] = json.dumps( asdict(Guild(1), recurse=True) ) val = await create_redis_cache.get_guild(1) assert val assert isinstance(val, Guild)
def create_guild_from_dict(guild_data: dict) -> Guild: guild: Guild = Guild(id=guild_data["id"], options=Options(**guild_data["options"])) for member in guild_data["members"]: guild.members[ member["id"]] = FactoryBuilder.create_member_from_dict(member) log.info("Created Guild(id=%s) from dict", guild.id) return guild
async def test_basic_timeout_func(self, create_core): create_core.handler.lib_handler = Nextcord(create_core.handler) g = Guild(1, options=Options(use_timeouts=True)) member = Member(1, 1, duplicate_counter=5) # Force a punishment g.members[member.id] = member await create_core.cache.set_guild(g) r_1 = await create_core.propagate( MockedMessage(author_id=1, guild_id=1).to_mock(), g) assert r_1.member_was_timed_out is True assert r_1.member_should_be_punished_this_message is True
async def test_punish_member_raises(self, create_dpy_lib_handler): with pytest.raises(MissingGuildPermissions): # Test kick has kick perms message = MockedMessage(author_id=1, guild_id=1).to_mock() message.guild.me.guild_permissions.kick_members = False await create_dpy_lib_handler.punish_member( message, Member(1, 1), Guild(1, Options()), "test user", "test guild", True, ) with pytest.raises(MissingGuildPermissions): # Test ban has ban perms message = MockedMessage(author_id=1, guild_id=1).to_mock() message.guild.me.guild_permissions.ban_members = False await create_dpy_lib_handler.punish_member( message, Member(1, 1), Guild(1, Options()), "test user", "test guild", False, ) with pytest.raises(MissingGuildPermissions): # Check errors on guild owner message = MockedMessage(author_id=1, guild_id=1).to_mock() message.guild.owner_id = 1 await create_dpy_lib_handler.punish_member( message, Member(1, 1), Guild(1, Options()), "test user", "test guild", True, )
async def test_delete_member(self, create_memory_cache): await create_memory_cache.delete_member(1, 2) await create_memory_cache.set_guild(Guild(2)) await create_memory_cache.delete_member(1, 2) guild = await create_memory_cache.get_guild(2) guild.members[1] = Member(1, 2) await create_memory_cache.set_guild(guild) assert len(guild.members) == 1 await create_memory_cache.delete_member(1, 2) g = await create_memory_cache.get_guild(2) assert len(g.members) == 0
def test_calculate_ratios(self, create_core): member = Member(1, 1) member.messages = [ Message(1, 1, 1, 1, "Hello world", datetime.datetime.now()) ] message = Message(2, 1, 1, 1, "Hello world", datetime.datetime.now()) assert member.duplicate_counter == 1 create_core._calculate_ratios(message, member, Guild(1)) assert member.duplicate_counter == 2 assert message.is_duplicate is True
def test_get_duplicate_count(self, create_core): guild = Guild(1) member = Member(1, 1) member.duplicate_counter = 5 member.duplicate_channel_counter_dict = {15: 2} assert create_core._get_duplicate_count(member, guild, 1) == 5 guild.options.per_channel_spam = True assert create_core._get_duplicate_count(member, guild) == 1 assert create_core._get_duplicate_count(member, guild, 5) == 1 assert create_core._get_duplicate_count(member, guild, 15) == 2
async def add_guild_options(self, guild_id: int, options: Options) -> None: """ Set a guild's options to a custom set, rather then the base level set used and defined in ASH initialization Warnings -------- If using/modifying ``AntiSpamHandler.options`` to give to this method you will **also** be modifying the overall options. To get an options item you can modify freely call :py:meth:`antispam.AntiSpamHandler.get_options` this method will give you an instance of the current options you are free to modify however you like. Notes ===== This will override any current settings, if you wish to continue using existing settings and merely change some I suggest using the ``get_options`` method first and then giving those values back to this method with the changed arguments """ if not isinstance(options, Options): raise ValueError("Expected options of type Options") try: guild = await self.cache.get_guild(guild_id=guild_id) except GuildNotFound: log.warning( "I cannot ensure I have permissions to kick/ban ban people in Guild(id=%s)", guild_id, ) guild = Guild(id=guild_id, options=options) await self.cache.set_guild(guild) log.info("Created Guild(id=%s)", guild.id) else: guild.options = options log.info("Set custom options for guild(%s)", guild_id)