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:
1 parent
08d24ad8d9
commit
04c64c30e6
1 file changed
+178
-1
+178
-1
@@ -109,9 +109,119 @@ impl ChannelOperationEnv for ChannelsSessionEnv {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::channels::mux::MuxRunner;
|
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;
|
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]
|
#[tokio::test]
|
||||||
async fn channels_session_env_delegates_to_base() {
|
async fn channels_session_env_delegates_to_base() {
|
||||||
let registry = Arc::new(crate::registry::registration::OperationRegistry::new());
|
let registry = Arc::new(crate::registry::registration::OperationRegistry::new());
|
||||||
@@ -132,4 +242,71 @@ mod tests {
|
|||||||
fn assert_operation_env<T: OperationEnv>() {}
|
fn assert_operation_env<T: OperationEnv>() {}
|
||||||
assert_operation_env::<ChannelsSessionEnv>();
|
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())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user