feat: unify object observation API
This commit is contained in:
@@ -2,11 +2,11 @@ use std::collections::BTreeMap;
|
||||
|
||||
use wip_protocol::{
|
||||
CallOperationRequest, CallOperationResponse, EnumCase, FetchInterfaceRequest,
|
||||
FetchInterfaceResponse, FetchRequest, FetchTreeRequest, FetchTreeResponse, FieldDeclaration,
|
||||
INTERFACE_FORMAT_V1, InterfaceDescriptor, InterfaceTarget, MAX_SAFE_INTEGER, NameNamespace,
|
||||
Object, ObjectTreeNode, OperationDeclaration, ParameterDeclaration, PathSegment, ProtocolError,
|
||||
ProtocolErrorCode, ProtocolInteraction, ProtocolResult, ReturnDeclaration, Target,
|
||||
TypeDeclaration, TypeExpr, UnionCase, ValidationErrorKind, Value, ValueKind,
|
||||
FetchInterfaceResponse, FieldDeclaration, INTERFACE_FORMAT_V1, InterfaceDescriptor,
|
||||
InterfaceTarget, MAX_SAFE_INTEGER, NameNamespace, Object, ObjectObservation, ObserveRequest,
|
||||
OperationDeclaration, ParameterDeclaration, PathSegment, ProtocolError, ProtocolErrorCode,
|
||||
ProtocolInteraction, ProtocolResult, ReturnDeclaration, Target, TypeDeclaration, TypeExpr,
|
||||
UnionCase, ValidationErrorKind, Value, ValueKind,
|
||||
};
|
||||
|
||||
fn record(entries: impl IntoIterator<Item = (&'static str, Value)>) -> Value {
|
||||
@@ -617,13 +617,26 @@ fn calls_validate_canonical_paths_named_arguments_and_unit_results() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_fetch_interface_dtos_validate_request_response_correspondence() {
|
||||
let fetch = FetchRequest {
|
||||
fn observe_and_fetch_interface_dtos_validate_request_response_correspondence() {
|
||||
let observe = ObserveRequest {
|
||||
path: "/articles/one".into(),
|
||||
depth: 0,
|
||||
};
|
||||
fetch.validate().unwrap();
|
||||
fetch.validate_response(&object("one")).unwrap();
|
||||
assert!(fetch.validate_response(&object("two")).is_err());
|
||||
observe.validate().unwrap();
|
||||
observe
|
||||
.validate_response(&ObjectObservation {
|
||||
object: object("one"),
|
||||
children: None,
|
||||
})
|
||||
.unwrap();
|
||||
assert!(
|
||||
observe
|
||||
.validate_response(&ObjectObservation {
|
||||
object: object("two"),
|
||||
children: None,
|
||||
})
|
||||
.is_err()
|
||||
);
|
||||
|
||||
for invalid in [
|
||||
"",
|
||||
@@ -634,8 +647,9 @@ fn fetch_and_fetch_interface_dtos_validate_request_response_correspondence() {
|
||||
"/a/../b",
|
||||
] {
|
||||
assert!(matches!(
|
||||
FetchRequest {
|
||||
path: invalid.into()
|
||||
ObserveRequest {
|
||||
path: invalid.into(),
|
||||
depth: 0,
|
||||
}
|
||||
.validate()
|
||||
.unwrap_err()
|
||||
@@ -666,61 +680,51 @@ fn fetch_and_fetch_interface_dtos_validate_request_response_correspondence() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_tree_dtos_validate_names_depth_limit_and_siblings() {
|
||||
let request = FetchTreeRequest {
|
||||
fn observe_response_validates_complete_children_and_depth_boundary() {
|
||||
let request = ObserveRequest {
|
||||
path: "/articles".into(),
|
||||
depth: 1,
|
||||
limit: 3,
|
||||
};
|
||||
let leaf = |name: &str| ObjectTreeNode {
|
||||
let leaf = |name: &str| ObjectObservation {
|
||||
object: object(name),
|
||||
children: vec![],
|
||||
children: None,
|
||||
};
|
||||
let response = FetchTreeResponse {
|
||||
root: ObjectTreeNode {
|
||||
object: object("articles"),
|
||||
children: vec![leaf("one"), leaf("two")],
|
||||
},
|
||||
truncated: false,
|
||||
let response = ObjectObservation {
|
||||
object: object("articles"),
|
||||
children: Some(vec![leaf("one"), leaf("two")]),
|
||||
};
|
||||
response.validate_for(&request).unwrap();
|
||||
request.validate_response(&response).unwrap();
|
||||
|
||||
let zero = FetchTreeRequest {
|
||||
limit: 0,
|
||||
..request.clone()
|
||||
let empty = ObjectObservation {
|
||||
object: object("articles"),
|
||||
children: Some(vec![]),
|
||||
};
|
||||
assert_eq!(
|
||||
zero.validate().unwrap_err().kind,
|
||||
ValidationErrorKind::ZeroTreeLimit
|
||||
);
|
||||
request.validate_response(&empty).unwrap();
|
||||
|
||||
let shallow = FetchTreeRequest {
|
||||
let missing = ObjectObservation {
|
||||
object: object("articles"),
|
||||
children: None,
|
||||
};
|
||||
assert!(matches!(
|
||||
request.validate_response(&missing).unwrap_err().kind,
|
||||
ValidationErrorKind::ChildrenMissingBeforeDepth { depth: 0 }
|
||||
));
|
||||
|
||||
let boundary = ObserveRequest {
|
||||
depth: 0,
|
||||
..request.clone()
|
||||
};
|
||||
assert!(matches!(
|
||||
response.validate_for(&shallow).unwrap_err().kind,
|
||||
ValidationErrorKind::TreeDepthExceeded { .. }
|
||||
boundary.validate_response(&response).unwrap_err().kind,
|
||||
ValidationErrorKind::ChildrenAtDepthBoundary { depth: 0 }
|
||||
));
|
||||
|
||||
let small = FetchTreeRequest {
|
||||
limit: 2,
|
||||
..request.clone()
|
||||
let duplicate = ObjectObservation {
|
||||
object: object("articles"),
|
||||
children: Some(vec![leaf("one"), leaf("one")]),
|
||||
};
|
||||
assert!(matches!(
|
||||
response.validate_for(&small).unwrap_err().kind,
|
||||
ValidationErrorKind::TreeLimitExceeded { .. }
|
||||
));
|
||||
|
||||
let duplicate = FetchTreeResponse {
|
||||
root: ObjectTreeNode {
|
||||
object: object("articles"),
|
||||
children: vec![leaf("one"), leaf("one")],
|
||||
},
|
||||
truncated: false,
|
||||
};
|
||||
assert!(matches!(
|
||||
duplicate.validate_for(&request).unwrap_err().kind,
|
||||
request.validate_response(&duplicate).unwrap_err().kind,
|
||||
ValidationErrorKind::DuplicateName {
|
||||
namespace: NameNamespace::ChildObject,
|
||||
..
|
||||
@@ -778,22 +782,9 @@ fn assert_allowed_codes(interaction: ProtocolInteraction, expected: &[ProtocolEr
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_error_codes_are_exhaustive() {
|
||||
fn observe_error_codes_are_exhaustive() {
|
||||
assert_allowed_codes(
|
||||
ProtocolInteraction::Fetch,
|
||||
&[
|
||||
ProtocolErrorCode::InvalidRequest,
|
||||
ProtocolErrorCode::NotFound,
|
||||
ProtocolErrorCode::ResourceLimitExceeded,
|
||||
ProtocolErrorCode::Internal,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_tree_error_codes_are_exhaustive() {
|
||||
assert_allowed_codes(
|
||||
ProtocolInteraction::FetchTree,
|
||||
ProtocolInteraction::Observe,
|
||||
&[
|
||||
ProtocolErrorCode::InvalidRequest,
|
||||
ProtocolErrorCode::NotFound,
|
||||
@@ -840,11 +831,18 @@ fn call_operation_error_codes_are_exhaustive() {
|
||||
|
||||
#[test]
|
||||
fn invalid_success_payloads_remain_client_local_validation_failures() {
|
||||
let fetch = FetchRequest {
|
||||
let observe = ObserveRequest {
|
||||
path: "/articles/one".into(),
|
||||
depth: 0,
|
||||
};
|
||||
assert!(matches!(
|
||||
fetch.validate_response(&object("other")).unwrap_err().kind,
|
||||
observe
|
||||
.validate_response(&ObjectObservation {
|
||||
object: object("other"),
|
||||
children: None,
|
||||
})
|
||||
.unwrap_err()
|
||||
.kind,
|
||||
ValidationErrorKind::ObjectNameMismatch { .. }
|
||||
));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user