Skip to content

Commit 3b2692f

Browse files
author
Mohammod Al Amin Ashik
committed
Add comprehensive Rust test coverage for MCP core flows
- Add 44 new integration tests for feature grants, routing, and MCP flows - Add mock repository infrastructure (mocks.rs) for in-memory testing - Add database tests for feature sets, inbound clients, installed servers, outbound OAuth - Add gateway tests for ServerManager (22 tests) - Add OAuth tests for DCR, flows, and token management (53 tests) - Fix existing tests to account for auto-created builtin feature sets - Total: 217 Rust tests now passing
1 parent 08fafbe commit 3b2692f

20 files changed

Lines changed: 5973 additions & 14 deletions

Cargo.lock

Lines changed: 68 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/rust/Cargo.toml

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ chrono = { version = "0.4", features = ["serde"] }
3232
# Hex encoding for crypto tests
3333
hex = "0.4"
3434

35+
# Dashmap for concurrent collections
36+
dashmap = "6.1"
37+
38+
# Tracing for test output
39+
tracing = "0.1"
40+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
41+
42+
# HTTP mocking for OAuth tests
43+
wiremock = "0.6"
44+
reqwest = { version = "0.12", features = ["json"] }
45+
46+
# URL parsing for OAuth tests
47+
url = "2.5"
48+
49+
# Sync primitives for tests
50+
parking_lot = "0.12"
51+
3552
[lib]
3653
path = "src/lib.rs"
3754

@@ -43,11 +60,14 @@ path = "tests/database/mod.rs"
4360
name = "security"
4461
path = "tests/security/mod.rs"
4562

46-
# Gateway and OAuth tests will be added later when infrastructure is ready
47-
# [[test]]
48-
# name = "gateway"
49-
# path = "tests/gateway/mod.rs"
50-
#
51-
# [[test]]
52-
# name = "oauth"
53-
# path = "tests/oauth/mod.rs"
63+
[[test]]
64+
name = "gateway"
65+
path = "tests/gateway/mod.rs"
66+
67+
[[test]]
68+
name = "oauth"
69+
path = "tests/oauth/mod.rs"
70+
71+
[[test]]
72+
name = "integration"
73+
path = "tests/integration/mod.rs"

tests/rust/src/lib.rs

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,125 @@
11
//! Shared test utilities and fixtures for McpMux integration tests.
22
3-
pub use mcpmux_core::domain::{InstalledServer, Space, FeatureSet, FeatureSetType};
3+
pub use mcpmux_core::domain::{InstalledServer, Space, FeatureSet, FeatureSetType, Client, Credential};
4+
pub use mcpmux_core::{DomainEvent, ConnectionStatus, DiscoveredCapabilities, ServerFeature, FeatureType};
5+
6+
/// Mock repository implementations
7+
pub mod mocks;
8+
pub use mocks::MockRepositories;
9+
10+
/// Service test helpers
11+
pub mod services;
12+
pub use services::ServerManagerTestHarness;
13+
14+
/// Event testing utilities
15+
pub mod events {
16+
use mcpmux_core::DomainEvent;
17+
use tokio::sync::broadcast;
18+
use std::time::Duration;
19+
20+
/// Create a test event channel with sufficient capacity
21+
pub fn test_event_channel() -> (broadcast::Sender<DomainEvent>, broadcast::Receiver<DomainEvent>) {
22+
broadcast::channel(100)
23+
}
24+
25+
/// Collect events from a receiver with a timeout
26+
pub async fn collect_events(
27+
mut rx: broadcast::Receiver<DomainEvent>,
28+
timeout: Duration,
29+
) -> Vec<DomainEvent> {
30+
let mut events = Vec::new();
31+
let deadline = tokio::time::Instant::now() + timeout;
32+
33+
loop {
34+
let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
35+
if remaining.is_zero() {
36+
break;
37+
}
38+
39+
match tokio::time::timeout(remaining, rx.recv()).await {
40+
Ok(Ok(event)) => events.push(event),
41+
Ok(Err(_)) => break, // Channel closed or lagged
42+
Err(_) => break, // Timeout
43+
}
44+
}
45+
46+
events
47+
}
48+
49+
/// Wait for a specific event type
50+
pub async fn wait_for_event<F>(
51+
mut rx: broadcast::Receiver<DomainEvent>,
52+
timeout: Duration,
53+
predicate: F,
54+
) -> Option<DomainEvent>
55+
where
56+
F: Fn(&DomainEvent) -> bool,
57+
{
58+
let deadline = tokio::time::Instant::now() + timeout;
59+
60+
loop {
61+
let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
62+
if remaining.is_zero() {
63+
return None;
64+
}
65+
66+
match tokio::time::timeout(remaining, rx.recv()).await {
67+
Ok(Ok(event)) if predicate(&event) => return Some(event),
68+
Ok(Ok(_)) => continue, // Not the event we want
69+
Ok(Err(_)) => return None, // Channel closed
70+
Err(_) => return None, // Timeout
71+
}
72+
}
73+
}
74+
75+
/// Assert that a ServerStatusChanged event was emitted with expected status
76+
pub fn assert_status_changed(
77+
events: &[DomainEvent],
78+
expected_server_id: &str,
79+
expected_status: mcpmux_core::ConnectionStatus,
80+
) -> bool {
81+
events.iter().any(|e| {
82+
if let DomainEvent::ServerStatusChanged { server_id, status, .. } = e {
83+
server_id == expected_server_id && *status == expected_status
84+
} else {
85+
false
86+
}
87+
})
88+
}
89+
}
90+
91+
/// Server feature fixtures for testing
92+
pub mod features {
93+
use mcpmux_core::ServerFeature;
94+
95+
/// Create a test tool feature
96+
pub fn test_tool(space_id: &str, server_id: &str, name: &str) -> ServerFeature {
97+
ServerFeature::tool(space_id, server_id, name)
98+
.with_description(format!("Test tool: {}", name))
99+
}
100+
101+
/// Create a test prompt feature
102+
pub fn test_prompt(space_id: &str, server_id: &str, name: &str) -> ServerFeature {
103+
ServerFeature::prompt(space_id, server_id, name)
104+
.with_description(format!("Test prompt: {}", name))
105+
}
106+
107+
/// Create a test resource feature
108+
pub fn test_resource(space_id: &str, server_id: &str, uri: &str) -> ServerFeature {
109+
ServerFeature::resource(space_id, server_id, uri)
110+
.with_description(format!("Test resource: {}", uri))
111+
}
112+
113+
/// Create a set of test features for a server
114+
pub fn test_feature_set(space_id: &str, server_id: &str) -> Vec<ServerFeature> {
115+
vec![
116+
test_tool(space_id, server_id, "read_file"),
117+
test_tool(space_id, server_id, "write_file"),
118+
test_prompt(space_id, server_id, "summarize"),
119+
test_resource(space_id, server_id, "file:///test"),
120+
]
121+
}
122+
}
4123

5124
/// Test fixture utilities
6125
pub mod fixtures {

0 commit comments

Comments
 (0)