mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 11:13:43 +08:00
The PRIVATE_ITEMS list contained the bare 'test' entry, which rsync interprets as 'any directory named test at any depth' — so it caught the root-level /test/ scratch directory (intended) AND every src/test/ under each module (not intended). Pattern is already anchored to /test (root-only). This commit rsyncs the accumulated src/test/ tree forward so opensource has the unit tests that have been written / updated against existing src/main/ code since the pattern regression. Going forward each per-commit sync will carry src/test/ files along with the main change.
59 lines
2.5 KiB
Java
59 lines
2.5 KiB
Java
package vip.mate.channel;
|
||
|
||
import org.junit.jupiter.api.Test;
|
||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||
|
||
/**
|
||
* Pin the error-detection heuristic so a future tweak in
|
||
* {@code NodeStreamingChatHelper} that renames an error template doesn't
|
||
* silently regress IM channels back into the self-replicating 400 loop.
|
||
*/
|
||
class ChannelErrorClassifierTest {
|
||
|
||
private final ChannelErrorClassifier classifier = new ChannelErrorClassifier();
|
||
|
||
@Test
|
||
void normal_reply_is_not_error() {
|
||
assertFalse(classifier.isErrorReply("好的,我已经为您完成了任务。"));
|
||
assertFalse(classifier.isErrorReply(""));
|
||
assertFalse(classifier.isErrorReply(null));
|
||
assertFalse(classifier.isErrorReply("⏰ 定时任务已就绪:每天 00:18"));
|
||
}
|
||
|
||
@Test
|
||
void error_prefix_is_detected() {
|
||
assertTrue(classifier.isErrorReply("[错误] Bad request: Bad request, please check input"));
|
||
assertTrue(classifier.isErrorReply("[错误] 工具调用失败"));
|
||
}
|
||
|
||
@Test
|
||
void error_substrings_emitted_by_NodeStreamingChatHelper_are_detected() {
|
||
// Mirrors templates in NodeStreamingChatHelper.buildErrorResultWithType
|
||
assertTrue(classifier.isErrorReply("Bad request: invalid_request_error"));
|
||
assertTrue(classifier.isErrorReply("LLM 调用失败: connection reset"));
|
||
assertTrue(classifier.isErrorReply("LLM 调用超时"));
|
||
assertTrue(classifier.isErrorReply("LLM 调用被中断"));
|
||
assertTrue(classifier.isErrorReply("Prompt 过长: token limit exceeded"));
|
||
assertTrue(classifier.isErrorReply("认证失败: 401 Unauthorized"));
|
||
assertTrue(classifier.isErrorReply("LLM 返回空响应"));
|
||
}
|
||
|
||
@Test
|
||
void status_for_maps_correctly() {
|
||
assertEquals("error", classifier.statusFor("[错误] Bad request"));
|
||
assertEquals("completed", classifier.statusFor("Hello world"));
|
||
assertEquals("completed", classifier.statusFor(""));
|
||
}
|
||
|
||
@Test
|
||
void aicard_partial_with_error_prefix_is_detected() {
|
||
// The DingTalk AICard catch path now wraps partial output with a
|
||
// [错误] prefix; verify the classifier catches that compound shape.
|
||
String reply = "[错误] AI Card streaming failed: timeout\n\n(已生成的部分内容,已忽略)\n部分回答 ...";
|
||
assertTrue(classifier.isErrorReply(reply));
|
||
}
|
||
}
|