saddle-framework 0.3.32

The single business-facing facade for Saddle applications
//! Compiles the formal application graph, separate descriptor identities, and
//! route-specific managed calls without a legacy contract directory.
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(&timestamp);
    let response = match capability
        .grpc::<protocol::methods::mirror::Echo>(&fields)
        .await
    {
        Ok(response) => response,
        Err(_) => return failed(),
    };
    // Author-only held-response scenario: the formal original deadline drops
    // this future while the native response remains owned and charged.
    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();
}