use saddle::ingress::{
FailureMessage, ProfuseGwCode, ProfuseGwContext, ProfuseGwFailure, ProfuseGwResponse as Outcome,
};
saddle::grpc_bindings! {
pub mod protocol {
proto_root "../../tests/fixtures/standard-grpc";
dependency mirror { service "alpha.Mirror"; methods { Echo => "Echo"; Numbers => "Numbers"; } }
dependency alternate { service "beta.Alternate"; methods { Echo => "Echo"; } }
}
}
saddle::business_types! {
#[derive(Deserialize, saddle::Input)] pub struct Input { value: u64 }
#[derive(Serialize)] pub struct Output { value: u64 }
}
pub enum Code {
Dependency,
}
impl ProfuseGwCode for Code {
const REGISTERED_CODES: &'static [&'static str] = &["DEPENDENCY"];
fn stable_code(&self) -> &'static str {
"DEPENDENCY"
}
}
fn failed() -> Outcome<Output, Code> {
Outcome::failure(ProfuseGwFailure::new(
Code::Dependency,
FailureMessage::new("dependency unavailable").unwrap(),
))
}
async fn alpha_handler(
input: &Input,
_: ProfuseGwContext,
mut capability: External<Alpha>,
_: saddle::BusinessConfig<()>,
) -> Outcome<Output, Code> {
if input.value == 19 {
let mut fields = protocol::types::alpha::Scalars_Fields::default();
fields.double_value = -1.5;
fields.float_value = 2.25;
fields.int32_value = -3;
fields.int64_value = -4;
fields.uint32_value = u32::MAX;
fields.uint64_value = 19;
fields.sint32_value = i32::MIN;
fields.sint64_value = i64::MIN;
fields.fixed32_value = 5;
fields.fixed64_value = 6;
fields.sfixed32_value = -7;
fields.sfixed64_value = -8;
fields.bool_value = true;
let response = match capability
.grpc::<protocol::methods::mirror::Numbers>(&fields)
.await
{
Ok(response) => response,
Err(_) => return failed(),
};
let message = response.message();
assert_eq!(
(message.double_value(), message.float_value()),
(-1.5, 2.25)
);
assert_eq!((message.int32_value(), message.int64_value()), (-3, -4));
assert_eq!(
(message.uint32_value(), message.uint64_value()),
(u32::MAX, 19)
);
assert_eq!(
(message.sint32_value(), message.sint64_value()),
(i32::MIN, i64::MIN)
);
assert_eq!((message.fixed32_value(), message.fixed64_value()), (5, 6));
assert_eq!(
(message.sfixed32_value(), message.sfixed64_value()),
(-7, -8)
);
assert!(message.bool_value());
return match capability.managed_response_data(|_| Ok(Output { value: 19 })) {
Ok(owner) => Outcome::success_managed(owner),
Err(_) => failed(),
};
}
let mut nested = protocol::types::alpha::Value_types::Nested_Fields::default();
nested.id = input.value;
let mut fields = protocol::types::alpha::Value_Fields::default();
fields.child = Some(&nested);
fields.text = "independent oracle";
fields.data = &[0, 255];
fields.limit = Some(0);
fields.numbers = &[i64::MIN, -1, 0, i64::MAX];
let mut first = protocol::types::alpha::Value_types::LabelsEntry_Fields::default();
first.key = "same";
first.value = 1;
let mut second = protocol::types::alpha::Value_types::LabelsEntry_Fields::default();
second.key = "same";
second.value = 2;
let labels = [first, second];
fields.labels = &labels;
fields.children = std::slice::from_ref(&nested);
fields.choice = Some(protocol::types::alpha::Value_choice_Fields::selected(
"chosen",
));
fields.kind = 77;
let mut timestamp = protocol::types::google::protobuf::Timestamp_Fields::default();
timestamp.seconds = -1;
timestamp.nanos = 456;
fields.created = Some(×tamp);
if input.value == 27 {
if capability.grpc::<protocol::methods::mirror::Echo>(&fields).await.is_err() {
return failed();
}
}
let response = match capability
.grpc::<protocol::methods::mirror::Echo>(&fields)
.await
{
Ok(response) => response,
Err(_) => return failed(),
};
if input.value == 17 {
std::future::pending::<()>().await;
}
let message = response.message();
assert_eq!(message.text(), "independent oracle");
assert_eq!(message.data(), [0, 255]);
assert_eq!(message.limit(), Some(0));
let mut numbers = message.numbers();
for expected in [i64::MIN, -1, 0, i64::MAX] {
assert_eq!(numbers.next(), Some(expected));
}
assert_eq!(numbers.next(), None);
assert_eq!(message.labels().next().unwrap().value(), 2);
assert_eq!(message.children().next().unwrap().id(), input.value);
assert_eq!(message.kind(), 77);
assert_eq!(
message.created().map(|v| (v.seconds(), v.nanos())),
Some((-1, 456))
);
assert!(matches!(
message.choice(),
Some(protocol::types::alpha::Value_choice::selected("chosen"))
));
let value = message.child().unwrap().id();
match capability.managed_response_data(|_| Ok(Output { value })) {
Ok(owner) => Outcome::success_managed(owner),
Err(_) => failed(),
}
}
async fn beta_handler(
input: &Input,
_: ProfuseGwContext,
mut capability: External<Beta>,
_: saddle::BusinessConfig<()>,
) -> Outcome<Output, Code> {
let mut fields = protocol::types::beta::Value_Fields::default();
fields.value = input.value as i64;
let response = match capability
.grpc::<protocol::methods::alternate::Echo>(&fields)
.await
{
Ok(response) => response,
Err(_) => return failed(),
};
let value = response.message().value() as u64;
match capability.managed_response_data(|_| Ok(Output { value })) {
Ok(owner) => Outcome::success_managed(owner),
Err(_) => failed(),
}
}
saddle::application! {
schema "saddle-application/2";
application StandardApplication;
deployment_app "standard-unary-fixture";
business_config ();
external_grpc {
bindings protocol;
capability External;
response_code Code;
business_unit "fixture";
}
service Alpha { ingress profusegw; operation_type "alpha"; request Input; response Output; handler alpha_handler; uses_grpc (protocol::methods::mirror::Echo); uses_grpc (protocol::methods::mirror::Numbers); }
service Beta { ingress profusegw; operation_type "beta"; request Input; response Output; handler beta_handler; uses_grpc (protocol::methods::alternate::Echo); }
}
#[test]
fn formal_graph_freezes_standard_descriptor_and_routes() {
let _: fn() -> saddle::Result<()> = StandardApplication::run;
assert_eq!(
StandardApplication::__PROFUSECONTRACT_DESCRIPTOR,
protocol::DESCRIPTOR
);
assert_eq!(
StandardApplication::dispatch_profusegw_operation("alpha"),
Some(ProfuseGwDispatch::Alpha)
);
assert_eq!(
StandardApplication::dispatch_profusegw_operation("beta"),
Some(ProfuseGwDispatch::Beta)
);
assert!(StandardApplication::dispatch_profusegw_operation("undeclared").is_none());
}
#[test]
fn standard_startup_requires_only_registered_aliases_not_legacy_authority() {
let root = std::env::temp_dir().join(format!("saddle-standard-startup-{}", std::process::id()));
std::fs::create_dir(&root).unwrap();
let path = root.join("saddle.toml");
let source = "[framework]\nlisten=\"127.0.0.1:39001\"\n[framework.management]\nbind=\"127.0.0.1:39002\"\n[framework.admission]\ncpuCores=2\nmemoryMb=512\n[framework.admission.dependencies]\ndatabaseConcurrency=1\nprofusecontractConcurrency=2\n[framework.grpc.mirror]\nauthority=\"http://mirror-{zone}:50051\"\n[framework.grpc.alternate]\nauthority=\"http://127.0.0.1:50052\"\n[secrets]\n";
std::fs::write(&path, source).unwrap();
let mut config = saddle::ProcessConfig::<()>::load(&path).unwrap();
assert!(config.__freeze_standard_grpc(protocol::METHODS).is_ok());
std::fs::write(
&path,
source.replace("[framework.grpc.alternate]", "[framework.grpc.wrong_alias]"),
)
.unwrap();
let mut config = saddle::ProcessConfig::<()>::load(&path).unwrap();
assert!(config.__freeze_standard_grpc(protocol::METHODS).is_err());
std::fs::write(
&path,
source.replace(
"[secrets]",
"[framework.profusecontract]\nauthority=\"http://legacy:50051\"\n[secrets]",
),
)
.unwrap();
let mut config = saddle::ProcessConfig::<()>::load(&path).unwrap();
assert!(config.__freeze_standard_grpc(protocol::METHODS).is_err());
std::fs::remove_dir_all(root).unwrap();
}