Files

129 lines
4.4 KiB
Rust

#![cfg(feature = "http")]
//! Wire budgets are adapter-only and failed encoding must not acquire state.
use std::collections::BTreeMap;
use wip_client::{Client, ClientErrorKind, ClientLimits, ObservationState, SecurityContext};
use wip_http::{Limits, encode_fetch_interface_response, encode_observe_response};
use wip_protocol::{
FetchInterfaceRequest, FetchInterfaceResponse, INTERFACE_FORMAT_V1, InterfaceDescriptor,
InterfaceReference, Object, ObjectObservation, ObserveRequest, OperationDeclaration,
ReturnDeclaration, TypeExpr,
};
fn state_limits() -> ClientLimits {
ClientLimits::new(2, 8, 8, 8, 8).unwrap()
}
#[test]
fn request_encoding_failure_leaves_retrieval_cache_and_inflight_unchanged() {
let mut client = Client::new(state_limits(), Limits::new(1, 4096, 32).unwrap());
let session = client
.open_session("https://example.test/wip", SecurityContext::new("alice"))
.unwrap();
assert_eq!(
client.refresh_object(&session, "/item").unwrap_err().kind,
ClientErrorKind::InvalidRequest
);
let reference = InterfaceReference {
scope: "/".into(),
name: "test".into(),
};
assert_eq!(
client
.prepare_interface(&session, reference.clone())
.unwrap_err()
.kind,
ClientErrorKind::InvalidRequest
);
assert!(client.object(&session, "/item").is_none());
assert!(client.interface(&session, &reference).is_none());
assert_eq!(client.in_flight_len(), 0);
}
#[test]
fn call_encoding_failure_keeps_fresh_observations_and_no_pending_call() {
let limits = Limits::new(80, 4096, 32).unwrap();
let mut client = Client::new(state_limits(), limits);
let session = client
.open_session("https://example.test/wip", SecurityContext::new("alice"))
.unwrap();
let reference = InterfaceReference {
scope: "/".into(),
name: "test".into(),
};
let observe = client.refresh_object(&session, "/item").unwrap();
client
.complete(
observe.id,
encode_observe_response(
&ObserveRequest {
path: "/item".into(),
depth: 0,
},
&ObjectObservation {
object: Object {
name: "item".into(),
description: None,
interfaces: vec![reference.clone()],
r#ref: None,
validator: None,
},
children: None,
},
limits,
)
.unwrap(),
)
.unwrap();
let fetch = client
.prepare_interface(&session, reference.clone())
.unwrap();
client
.complete(
fetch.id,
encode_fetch_interface_response(
&FetchInterfaceRequest {
interface: reference.clone(),
},
&FetchInterfaceResponse {
interface: reference.clone(),
scope_ref: None,
validator: None,
descriptor: InterfaceDescriptor {
format: INTERFACE_FORMAT_V1.into(),
documentation: None,
types: vec![],
operations: vec![OperationDeclaration {
name: "run".into(),
documentation: None,
parameters: vec![],
returns: ReturnDeclaration {
documentation: None,
r#type: TypeExpr::Integer,
},
}],
},
},
limits,
)
.unwrap(),
)
.unwrap();
assert_eq!(
client
.prepare_call(&session, "/item", &reference, "run", BTreeMap::new())
.unwrap_err()
.kind,
ClientErrorKind::InvalidRequest
);
assert_eq!(
client.object(&session, "/item").unwrap().state,
ObservationState::Fresh
);
assert_eq!(
client.interface(&session, &reference).unwrap().state,
ObservationState::Fresh
);
assert!(client.call_history(&session).unwrap().is_empty());
assert_eq!(client.in_flight_len(), 0);
}