lean_ctx/core/context_kernel/
client_e2e.rs1#[cfg(test)]
4mod tests {
5 use super::super::client_profile::ProfileBuilder;
6 use super::super::context_broker::{ContextBroker, ContextMode, OutputFormat, ToolDescriptor};
7 use super::super::coverage_class::{self, CoverageClass};
8 use super::super::etpao_live::{EtpaoLive, OutcomeMetrics, RequestMetrics};
9
10 fn tool(index: usize) -> ToolDescriptor {
11 ToolDescriptor {
12 name: format!("tool-{index}"),
13 schema_tokens: 10,
14 priority: index as u8,
15 }
16 }
17
18 fn request(client_id: &str, tokens: usize, coverage_class: CoverageClass) -> RequestMetrics {
19 RequestMetrics {
20 input_tokens: tokens,
21 output_tokens: 0,
22 reasoning_tokens: 0,
23 schema_tokens: 0,
24 cache_write_tokens: 0,
25 retry_count: 0,
26 client_id: client_id.to_owned(),
27 coverage_class,
28 }
29 }
30
31 fn outcome(client_id: &str, accepted: bool) -> OutcomeMetrics {
32 OutcomeMetrics {
33 accepted,
34 quality_score: 1.0,
35 first_pass: accepted,
36 client_id: client_id.to_owned(),
37 }
38 }
39
40 #[test]
41 fn coverage_detection_full_inline() {
42 assert_eq!(
43 coverage_class::detect_coverage(true, false, false),
44 CoverageClass::FullInline
45 );
46 }
47
48 #[test]
49 fn coverage_detection_mcp_only() {
50 assert_eq!(
51 coverage_class::detect_coverage(false, true, false),
52 CoverageClass::ContextControlled
53 );
54 }
55
56 #[test]
57 fn profile_builder_defaults() {
58 let profile = ProfileBuilder::new("test").build();
59 assert_eq!(profile.client_id, "test");
60 assert!(profile.context_window > 0);
61 }
62
63 #[test]
64 fn broker_filters_tools_to_budget() {
65 let mut profile = ProfileBuilder::new("budgeted").build();
66 profile.tool_budget.max_tools = 5;
67 let broker = ContextBroker::new(profile);
68 let tools = (0..20).map(tool).collect::<Vec<_>>();
69
70 assert!(broker.select_tools(&tools).len() <= 5);
71 }
72
73 #[test]
74 fn broker_selects_handles_for_small_window() {
75 let profile = ProfileBuilder::new("small-window")
76 .context_window(16_000)
77 .build();
78 let broker = ContextBroker::new(profile);
79
80 assert!(broker.should_use_handles());
81 }
82
83 #[test]
84 fn etpao_records_and_computes() {
85 let mut etpao = EtpaoLive::new();
86 for index in 0..10 {
87 let client_id = format!("client-{index}");
88 etpao.record_request(request(&client_id, 1_000, CoverageClass::FullInline));
89 if index < 8 {
90 etpao.record_outcome(outcome(&client_id, true));
91 }
92 }
93
94 assert!((etpao.current_etpao() - 1_250.0).abs() < f64::EPSILON);
95 }
96
97 #[test]
98 fn etpao_by_coverage_class() {
99 let mut etpao = EtpaoLive::new();
100 etpao.record_request(request("inline", 1_000, CoverageClass::FullInline));
101 etpao.record_request(request(
102 "controlled",
103 1_000,
104 CoverageClass::ContextControlled,
105 ));
106 etpao.record_outcome(outcome("inline", true));
107 etpao.record_outcome(outcome("controlled", true));
108
109 assert_eq!(etpao.summary().by_coverage_class.len(), 2);
110 }
111
112 #[test]
113 fn full_pipeline_profile_to_etpao() {
114 let coverage = coverage_class::detect_coverage(true, false, false);
115 let mut profile = ProfileBuilder::new("pipeline")
116 .coverage(coverage)
117 .context_window(16_000)
118 .build();
119 profile.tool_budget.max_tools = 2;
120 let broker = ContextBroker::new(profile);
121 let selected = broker.select_tools(&(0..4).map(tool).collect::<Vec<_>>());
122
123 assert!(!selected.is_empty());
124 assert_eq!(broker.select_context_mode(), ContextMode::ManifestOnly);
125 assert_eq!(broker.select_output_format(), OutputFormat::TypedResult);
126
127 let mut etpao = EtpaoLive::new();
128 etpao.record_request(request("pipeline", 500, coverage));
129 etpao.record_outcome(outcome("pipeline", true));
130
131 assert!(etpao.summary().etpao > 0.0);
132 }
133}