@@ -97,6 +97,55 @@ async def test_speak_filters_banned_keywords(beanie_fixture):
9797 reply_dict .clear ()
9898
9999
100+ @pytest .mark .asyncio
101+ async def test_speak_skips_remote_bot_when_sharded (beanie_fixture ):
102+ from src .plugins .repeater .message_store import MessageStore
103+ from src .plugins .repeater .speaker import Speaker
104+
105+ MessageStore ._message_dict = defaultdict (list )
106+ Speaker ._recent_speak = defaultdict (lambda : deque (maxlen = Speaker .DUPLICATE_REPLY ))
107+
108+ reply_dict = defaultdict (lambda : defaultdict (list ))
109+ reply_lock = asyncio .Lock ()
110+ recent_topics = defaultdict (lambda : deque (maxlen = 16 ))
111+ topics_lock = asyncio .Lock ()
112+
113+ group_id = 30004
114+ local_bot_id = 10001
115+ remote_bot_id = 10002
116+ msg_list = [_build_message (group_id , 20001 + i , f"warmup-{ i } " , f"warmup-{ i } " , i + 1 ) for i in range (10 )]
117+ MessageStore ._message_dict [group_id ] = msg_list
118+ reply_dict [group_id ][remote_bot_id ] = [{"time" : 1 , "reply" : "x" , "reply_keywords" : "x" }]
119+ reply_dict [group_id ][local_bot_id ] = [{"time" : 1 , "reply" : "y" , "reply_keywords" : "y" }]
120+
121+ chosen_msg = msg_list [- 1 ]
122+ try :
123+ with (
124+ patch ("src.platform.shard.registry.config.is_sharding_active" , return_value = True ),
125+ patch ("src.plugins.repeater.shard_opt.local_connected_bot_ids" , return_value = frozenset ({local_bot_id })),
126+ patch ("src.plugins.repeater.speaker.time.time" , return_value = 10000 ),
127+ patch (
128+ "src.plugins.repeater.speaker.random.choice" ,
129+ side_effect = [local_bot_id , [chosen_msg ], chosen_msg ],
130+ ),
131+ patch ("src.plugins.repeater.speaker.random.random" , return_value = 1.0 ),
132+ patch (
133+ "src.plugins.repeater.speaker.BanManager.find_ban_keywords" ,
134+ new_callable = AsyncMock ,
135+ return_value = set (),
136+ ),
137+ patch ("src.plugins.repeater.speaker.BotConfig.taken_name" , new_callable = AsyncMock , return_value = - 1 ),
138+ patch ("src.plugins.repeater.reply_record_sync.publish_reply_record" ),
139+ ):
140+ result = await Speaker .speak (reply_dict , reply_lock , recent_topics , topics_lock )
141+ assert result is not None
142+ assert result [0 ] == local_bot_id
143+ finally :
144+ MessageStore ._message_dict .clear ()
145+ Speaker ._recent_speak .clear ()
146+ reply_dict .clear ()
147+
148+
100149@pytest .mark .asyncio
101150async def test_speak_recent_dedup_avoids_same_message_twice (beanie_fixture ):
102151 from src .plugins .repeater .message_store import MessageStore
0 commit comments