mateclaw/mateclaw-server/src/test/java/vip/mate/channel/ChannelErrorClassifierTest.java
matevip 0ffc224623 chore(test): backfill mateclaw-server/src/test/ that earlier PRIVATE_ITEMS pattern accidentally excluded
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.
2026-05-12 17:38:08 +08:00

59 lines
2.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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));
}
}