use aion_proto::{ProtoWireError, WireError};
use prost::Message as _;
use tonic::Status;
#[must_use]
pub fn owner_refusal(status: &Status) -> Option<WireError> {
if status.details().is_empty() {
return None;
}
let proto = ProtoWireError::decode(status.details()).ok()?;
match WireError::try_from(proto) {
Ok(wire) | Err(wire) => Some(wire),
}
}
#[must_use]
pub fn not_owner_wire(shard: usize) -> WireError {
WireError::not_owner(format!(
"workflow shard {shard} is owned by another cluster node"
))
.with_error_type("NotOwner")
}
#[cfg(test)]
mod tests {
use aion_proto::{WireError, WireErrorCode};
use tonic::{Code, Status};
use super::{not_owner_wire, owner_refusal};
fn owner_status(error: WireError) -> Status {
crate::api::grpc::status_from_wire_error(error)
}
#[test]
fn an_authored_refusal_decodes_back_to_the_owners_own_error() {
let cases = [
WireError::not_found("workflow 7 has no recorded history"),
WireError::invalid_input("display_name must not be blank"),
WireError::namespace_denied("tenant-b is not visible to this caller"),
WireError::invalid_state("run is not resident on this node")
.with_error_type("Resident"),
];
for expected in cases {
let decoded = owner_refusal(&owner_status(expected.clone()))
.unwrap_or_else(|| WireError::backend("no detail decoded"));
assert_eq!(decoded.code, expected.code, "the owner's code must survive");
assert_eq!(decoded.message, expected.message);
assert_eq!(decoded.error_type, expected.error_type);
}
}
#[test]
fn a_transport_status_carries_no_owner_answer() {
assert!(owner_refusal(&Status::unavailable("forward dial failed")).is_none());
assert!(owner_refusal(&Status::internal("connection reset")).is_none());
}
#[test]
fn undecodable_details_are_not_an_owner_answer() {
let details: Vec<u8> = vec![0x0a, 0x7f];
let status = Status::with_details(Code::Aborted, "opaque", details.into());
assert!(owner_refusal(&status).is_none());
}
#[test]
fn the_shared_not_owner_refusal_is_typed_and_names_the_shard() {
let wire = not_owner_wire(7);
assert_eq!(wire.code, WireErrorCode::NotOwner);
assert_eq!(wire.error_type.as_deref(), Some("NotOwner"));
assert!(wire.message.contains("shard 7"), "{}", wire.message);
}
}