129 lines
4.4 KiB
Rust
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);
|
|
}
|