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_remove_duplicate_count(self, create_core): 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, 1) assert member.duplicate_counter == 4 assert member.duplicate_channel_counter_dict == {15: 2} create_core._remove_duplicate_count(member, 1, 2) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 2} create_core.options = Options(per_channel_spam=True) create_core._remove_duplicate_count(member, 15) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 1} create_core._remove_duplicate_count(member, 1) assert member.duplicate_counter == 2 assert member.duplicate_channel_counter_dict == {15: 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_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
async def test_delete_member_messages(self, create_dpy_lib_handler): member = Member(1, 2) member.messages = [ Message(1, 2, 3, 4, "First"), Message(2, 2, 3, 4, "second", is_duplicate=True), Message(3, 2, 3, 4, "third", is_duplicate=True), ] with patch("antispam.libs.dpy.DPY.delete_message", new_callable=AsyncMock) as delete_call: await create_dpy_lib_handler.delete_member_messages(member) assert delete_call.call_count == 2
def test_get_duplicate_count(self, create_core): member = Member(1, 1) member.duplicate_counter = 5 member.duplicate_channel_counter_dict = {15: 2} assert create_core._get_duplicate_count(member, 1) == 5 create_core.options = Options(per_channel_spam=True) assert create_core._get_duplicate_count(member) == 1 assert create_core._get_duplicate_count(member, 5) == 1 assert create_core._get_duplicate_count(member, 15) == 2
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
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_calculate_ratios_per_channel(self, create_core): member = Member(1, 1) member.messages = [ Message(1, 1, 1, 1, "Hello world", datetime.datetime.now()) ] message = Message(2, 2, 1, 1, "Hello world", datetime.datetime.now()) guild = Guild(1, options=Options(per_channel_spam=True)) assert member.duplicate_counter == 1 create_core._calculate_ratios(message, member, guild) assert member.duplicate_counter == 1 assert message.is_duplicate is False
async def test_set_member(self, create_redis_cache): await create_redis_cache.set_member(Member(1, 1)) await create_redis_cache.set_member(Member(2, 1)) r_1 = await create_redis_cache.get_guild(1) assert len(r_1.members) == 2 await create_redis_cache.set_guild(Guild(1, Options())) r_2 = await create_redis_cache.get_guild(1) assert len(r_2.members) == 0 await create_redis_cache.set_member(Member(1, 1)) r_3 = await create_redis_cache.get_guild(1) assert len(r_3.members) == 1
async def test_clean_cache_strict_member(self, create_handler): """Tests clean_cache on members with strict mode""" await create_handler.cache.set_member(Member(1, 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_member( Member(1, 1, messages=[Message(1, 2, 3, 4, "Hello")]) ) assert bool(create_handler.cache.cache) await create_handler.clean_cache(strict=True) assert bool(create_handler.cache.cache)
async def test_add_message_filled(self, create_memory_cache): """Test with a pre-filled member""" await create_memory_cache.set_member(Member(4, 3)) await create_memory_cache.add_message(Message(1, 2, 3, 4, "Content")) assert len(create_memory_cache.cache[3].members) == 1 assert len(create_memory_cache.cache[3].members[4].messages) == 1
async def test_get_member_data_fails_on_member_addon( self, create_plugin_cache: PluginCache, create_handler): """Test the cache raises MemberNotFound""" await create_handler.cache.set_member(Member(1, 1)) with pytest.raises(MemberAddonNotFound): await create_plugin_cache.get_member_data(1, 1)
async def test_remove_punishment(self, create_anti_spam_tracker): # TODO Uncomment #68 # with pytest.raises(TypeError): # await create_anti_spam_tracker.remove_punishments(MockClass) # Skip non guild messages await create_anti_spam_tracker.remove_punishments( MockedMessage(is_in_guild=False).to_mock()) # Return since guild wasnt found await create_anti_spam_tracker.remove_punishments( MockedMessage(author_id=1, guild_id=1).to_mock()) await create_anti_spam_tracker.anti_spam_handler.cache.set_member( Member(1, 1)) await create_anti_spam_tracker.update_cache( MockedMessage(author_id=1, guild_id=1).to_mock(), CorePayload(member_should_be_punished_this_message=True), ) result = await create_anti_spam_tracker.member_tracking.get_member_data( 1, 1) assert len(result) == 1 await create_anti_spam_tracker.remove_punishments( MockedMessage(author_id=1, guild_id=1).to_mock()) result = await create_anti_spam_tracker.member_tracking.get_member_data( 1, 1) assert len(result) == 0
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_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
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 test_propagate_kicks(self, create_core): member = Member(1, 1) member.warn_count = 3 create_core._increment_duplicate_count(member, Guild(1), 1, 7) await create_core.cache.set_member(member) guild = await create_core.cache.get_guild(1) 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 kicked", member_was_kicked=True, member_warn_count=3, member_kick_count=1, member_duplicate_count=7, )
async def test_add_message_filled(self, create_redis_cache): """Test with a pre-filled member""" await create_redis_cache.set_member(Member(4, 3)) await create_redis_cache.add_message(Message(1, 2, 3, 4, "Content")) r_1 = await create_redis_cache.get_guild(3) assert len(r_1.members) == 1 assert len(r_1.members[4].messages) == 1
async def test_delete_spam(self, create_core): bulk_delete = AsyncMock() singular_delete = AsyncMock() create_core.handler.lib_handler.delete_message = singular_delete create_core.handler.lib_handler.delete_member_messages = bulk_delete member = Member(1, 1) member.warn_count = 3 create_core._increment_duplicate_count(member, Guild(1), 1, 7) await create_core.cache.set_member(member) guild = await create_core.cache.get_guild(1) guild.options.delete_spam = True await create_core.cache.set_guild(guild) await create_core.propagate_user( MockedMessage(guild_id=1, author_id=1).to_mock(), guild) assert bulk_delete.call_count == 1 assert singular_delete.call_count == 1
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)
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_reset_member_count(self, create_handler): with pytest.raises(ValueError): await create_handler.reset_member_count(1, 1, 1) await create_handler.reset_member_count(1, 1, ResetType.WARN_COUNTER) await create_handler.cache.set_guild(Guild(id=1, options=Options())) await create_handler.reset_member_count(1, 1, ResetType.WARN_COUNTER) await create_handler.cache.set_member(Member(1, 1, warn_count=5, kick_count=6)) await create_handler.reset_member_count(1, 1, ResetType.WARN_COUNTER) assert await create_handler.cache.get_member(1, 1) == Member( 1, 1, warn_count=0, kick_count=6 ) await create_handler.cache.set_member(Member(1, 1, warn_count=5, kick_count=6)) await create_handler.reset_member_count(1, 1, ResetType.KICK_COUNTER) assert await create_handler.cache.get_member(1, 1) == Member( 1, 1, warn_count=5, kick_count=0 )
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_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" )
def create_mongo_cache(create_handler) -> MockedMongoCache: guild_data: List[Dict[str, Any]] = [asdict(Guild(1))] member_data: List[Dict[str, Any]] = [ asdict( Member( 1, 1, warn_count=2, kick_count=1, messages=[ Message(1, 1, 1, 1, content="Foo"), Message(2, 1, 1, 1, content="Bar"), Message(3, 1, 1, 1, content="Baz"), ], ), recurse=True, ), asdict(Member(2, 1)), ] return MockedMongoCache(create_handler, member_data, guild_data)
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
async def update_cache(self, message, data: CorePayload) -> None: """ Takes the data returned from `propagate` and updates this Class's internal cache Parameters ---------- message The message related to `data's` propagation data : CorePayload The data returned from `propagate` """ # TODO Check with stubs when possible from #68 if not isinstance(data, CorePayload): raise TypeError("Expected data of type: CorePayload") if not message.guild: return member_id = message.author.id guild_id = await self.anti_spam_handler.lib_handler.get_guild_id( message) timestamp = get_aware_time() if not data.member_should_be_punished_this_message: # They shouldn't be punished so don't increase cache return # We now need to increase their cache try: addon_data = await self.member_tracking.get_member_data( member_id=member_id, guild_id=guild_id) except (MemberNotFound, GuildNotFound): # Store the new member member = Member(id=member_id, guild_id=guild_id) await self.anti_spam_handler.cache.set_member(member) addon_data = [] except MemberAddonNotFound: # Member exists, just an addon doesnt addon_data = [] addon_data.append(timestamp) await self.member_tracking.set_member_data(member_id, guild_id, addon_data=addon_data) log.debug("Cache updated for Member(id=%s) in Guild(id%s)", member_id, guild_id)