mateclaw/mateclaw-server/src/test/java/vip/mate/agent/AgentGraphBuilderPreferenceTest.java
matevip 3d213eb281 chore: sync multiple commits from private dev
Covers 15 upstream commits (private mirror → public):

Multi-provider failover (RFC-009):
- PR-0: extract ChatModelBuilder strategy seam
- PR-1a: AvailableProviderPool data structure
- PR-1b: startup provider liveness probe + 4 protocol strategies
- PR-1c: wire AvailableProviderPool into runtime chat-model selection
- PR-1d: provider pool REST endpoint + UI badges
- PR-1e: manual reprobe trigger + auto-reprobe on provider config change
- PR-3: per-agent provider preferences (agents can override the
  org-wide fallback chain)

Wiki subsystem (RFC-029~033):
- Relation model, resilient background jobs, light-weight processing
  path, retrieval enhancement, frontend redesign (single landing commit)
- Follow-up fixes: null guards + stats query + i18n polish, move
  WikiProcessingJobMapper to repository/ for @MapperScan, align
  implementation with RFC-029~031 spec
- Copy pass: replace "富化 / enrich" wording with clearer "链接 / link"
- Style: switch enrich/repair buttons to @element-plus/icons-vue
2026-04-19 18:37:44 +08:00

79 lines
3.2 KiB
Java

package vip.mate.agent;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import vip.mate.llm.model.ModelProviderEntity;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* RFC-009 PR-3 — verifies the agent-preference reorder used by
* {@link AgentGraphBuilder#buildFallbackChain}: listed providers move to the
* front in their declared order; unlisted providers keep their original
* relative order; missing/duplicate preferences are ignored gracefully.
*/
class AgentGraphBuilderPreferenceTest {
private static ModelProviderEntity p(String id) {
ModelProviderEntity p = new ModelProviderEntity();
p.setProviderId(id);
return p;
}
private static List<String> ids(List<ModelProviderEntity> ps) {
return ps.stream().map(ModelProviderEntity::getProviderId).toList();
}
@Test
@DisplayName("Empty preferences: original order preserved")
void noPreferences() {
var input = List.of(p("openai"), p("anthropic"), p("dashscope"));
var out = AgentGraphBuilder.reorderByPreferences(input, List.of());
assertEquals(List.of("openai", "anthropic", "dashscope"), ids(out));
}
@Test
@DisplayName("Single preference: preferred provider moves to front, rest follow original order")
void singlePreferenceFront() {
var input = List.of(p("openai"), p("anthropic"), p("dashscope"));
var out = AgentGraphBuilder.reorderByPreferences(input, List.of("dashscope"));
assertEquals(List.of("dashscope", "openai", "anthropic"), ids(out));
}
@Test
@DisplayName("Multiple preferences: preferred order matches declaration, rest stable")
void multiplePreferencesOrder() {
var input = List.of(p("openai"), p("anthropic"), p("dashscope"), p("kimi"));
var out = AgentGraphBuilder.reorderByPreferences(input, List.of("kimi", "anthropic"));
// kimi → anthropic → (rest in original order: openai, dashscope)
assertEquals(List.of("kimi", "anthropic", "openai", "dashscope"), ids(out));
}
@Test
@DisplayName("Preference references unknown provider: silently skipped")
void preferenceReferencesUnknown() {
var input = List.of(p("openai"), p("anthropic"));
var out = AgentGraphBuilder.reorderByPreferences(input, List.of("ghost", "anthropic"));
assertEquals(List.of("anthropic", "openai"), ids(out));
}
@Test
@DisplayName("Duplicate preferences: each provider appears at most once")
void duplicatePreferencesDeduped() {
var input = List.of(p("openai"), p("anthropic"));
var out = AgentGraphBuilder.reorderByPreferences(input, List.of("openai", "openai", "anthropic"));
assertEquals(List.of("openai", "anthropic"), ids(out));
}
@Test
@DisplayName("All providers preferred: input pure-reordered, no drops")
void allProvidersPreferred() {
var input = List.of(p("openai"), p("anthropic"), p("dashscope"));
var out = AgentGraphBuilder.reorderByPreferences(input,
List.of("dashscope", "openai", "anthropic"));
assertEquals(List.of("dashscope", "openai", "anthropic"), ids(out));
}
}