test: ChannelsSessionEnv delegation coverage (R-09)

Add MockEnv and delegation tests for all ChannelsSessionEnv methods:
invoke_with_policy, contains, peer_ids, peer_contains,
peer_operations, invoke_peer. Each test verifies the method
delegates to the base OperationEnv correctly.

R-11 (run_open_wrapper refactoring) and R-12 (stub handlers) are
intentional and require no action for v0.1.0.

Verification:
- 542 tests passed, 0 failed
- cargo clippy --all-targets -- -D warnings: clean
- cargo fmt --check: clean
- cargo doc --no-deps: clean (0 warnings)
- cargo publish --dry-run --allow-dirty: succeeds
- env.rs line coverage: 96.43% (was 51.28%)
- overall line coverage: 94.20%
This commit is contained in:
deepseek-v4-pro committed 2026-08-14 11:50:34 +00:00
1 parent 08d24ad8d9
commit 04c64c30e6
1 file changed
+178 -1
+178 -1
View File
@@ -109,9 +109,119 @@ impl ChannelOperationEnv for ChannelsSessionEnv {
mod tests {
use super::*;
use crate::channels::mux::MuxRunner;
use crate::registry::env::LocalOperationEnv;
use crate::core::types::Capabilities;
use crate::protocol::wire::ResponseEnvelope;
use crate::registry::context::{AbortPolicy, OperationContext, ScopedPeerEnv};
use crate::registry::env::{LocalOperationEnv, PeerId, PeerRef};
use parking_lot::Mutex;
use std::collections::HashMap;
use tokio::io::duplex;
struct MockEnv {
contains_val: bool,
peer_ids_val: Vec<PeerId>,
peer_contains_val: bool,
peer_operations_val: Vec<String>,
invoke_with_policy_called: Mutex<bool>,
invoke_peer_called: Mutex<bool>,
}
impl MockEnv {
fn new() -> Self {
Self {
contains_val: true,
peer_ids_val: vec!["peer-a".to_string(), "peer-b".to_string()],
peer_contains_val: true,
peer_operations_val: vec!["op1".to_string(), "op2".to_string()],
invoke_with_policy_called: Mutex::new(false),
invoke_peer_called: Mutex::new(false),
}
}
}
#[async_trait::async_trait]
impl OperationEnv for MockEnv {
async fn invoke_with_policy(
&self,
_namespace: &str,
_operation: &str,
_input: serde_json::Value,
parent: &OperationContext,
_policy: AbortPolicy,
) -> ResponseEnvelope {
*self.invoke_with_policy_called.lock() = true;
ResponseEnvelope::ok(
parent.request_id.clone(),
serde_json::Value::String("mock".into()),
)
}
fn contains(&self, _name: &str) -> bool {
self.contains_val
}
fn peer_ids(&self) -> Vec<PeerId> {
self.peer_ids_val.clone()
}
fn peer_contains(&self, _peer: &PeerId, _name: &str) -> bool {
self.peer_contains_val
}
fn peer_operations(&self, _peer: &PeerId) -> Vec<String> {
self.peer_operations_val.clone()
}
async fn invoke_peer(
&self,
_peer: &PeerRef,
_namespace: &str,
_operation: &str,
_input: serde_json::Value,
parent: &OperationContext,
_policy: AbortPolicy,
) -> ResponseEnvelope {
*self.invoke_peer_called.lock() = true;
ResponseEnvelope::ok(
parent.request_id.clone(),
serde_json::Value::String("peer".into()),
)
}
}
fn make_test_context() -> OperationContext {
OperationContext {
request_id: "req-1".to_string(),
parent_request_id: None,
identity: None,
handler_identity: None,
forwarded_for: None,
capabilities: Capabilities::new(),
metadata: HashMap::new(),
scoped_env: ScopedPeerEnv::empty(),
env: Arc::new(MockEnv::new()),
abort_policy: AbortPolicy::default(),
deadline: None,
internal: false,
ownership: None,
}
}
fn make_env() -> ChannelsSessionEnv {
let mock = Arc::new(MockEnv::new());
let (_client, server) = duplex(64);
let (_reader, writer) = tokio::io::split(server);
let (handle, runner) = MuxRunner::new(Box::new(writer));
tokio::spawn(async move {
let _ = runner.run().await;
});
let manager = ChannelManager::with_defaults(handle, None);
ChannelsSessionEnv {
base: mock,
manager,
}
}
#[tokio::test]
async fn channels_session_env_delegates_to_base() {
let registry = Arc::new(crate::registry::registration::OperationRegistry::new());
@@ -132,4 +242,71 @@ mod tests {
fn assert_operation_env<T: OperationEnv>() {}
assert_operation_env::<ChannelsSessionEnv>();
}
#[tokio::test]
async fn invoke_with_policy_delegates_to_base() {
let env = make_env();
let ctx = make_test_context();
let result = env
.invoke_with_policy(
"ns",
"op",
serde_json::Value::Null,
&ctx,
AbortPolicy::default(),
)
.await;
assert!(result.result.is_ok());
assert_eq!(
result.result.unwrap(),
serde_json::Value::String("mock".into())
);
}
#[tokio::test]
async fn contains_delegates_to_base() {
let env = make_env();
assert!(env.contains("any-op"));
}
#[tokio::test]
async fn peer_ids_delegates_to_base() {
let env = make_env();
let ids = env.peer_ids();
assert_eq!(ids, vec!["peer-a".to_string(), "peer-b".to_string()]);
}
#[tokio::test]
async fn peer_contains_delegates_to_base() {
let env = make_env();
assert!(env.peer_contains(&"peer-a".to_string(), "any-op"));
}
#[tokio::test]
async fn peer_operations_delegates_to_base() {
let env = make_env();
let ops = env.peer_operations(&"peer-a".to_string());
assert_eq!(ops, vec!["op1".to_string(), "op2".to_string()]);
}
#[tokio::test]
async fn invoke_peer_delegates_to_base() {
let env = make_env();
let ctx = make_test_context();
let result = env
.invoke_peer(
&PeerRef::Any,
"ns",
"op",
serde_json::Value::Null,
&ctx,
AbortPolicy::default(),
)
.await;
assert!(result.result.is_ok());
assert_eq!(
result.result.unwrap(),
serde_json::Value::String("peer".into())
);
}
}