use crate::prelude::*;
use beet_core::prelude::*;
use beet_flow::prelude::*;
impl ExchangeSpawner {
pub fn new_flow(func: impl BundleFunc) -> Self {
Self::new(move |world: &mut World| {
let func = func.clone();
let agent = world.spawn(Name::new("Flow Exchange Agent")).id();
let action_root = world
.spawn((
Name::new("Flow Exchange Action"),
ActionOf(agent),
OnSpawn::observe(
|ev: On<Outcome>,
agents: AgentQuery,
mut commands: Commands,
has_response: Query<(), With<ResponseMarker>>| {
let action = ev.target();
let agent = agents.entity(action);
if !has_response.contains(agent) {
let status = match ev.event() {
Outcome::Pass => StatusCode::Ok,
Outcome::Fail => StatusCode::InternalError,
};
commands
.entity(agent)
.insert(Response::from_status(status));
}
commands
.entity(agent)
.trigger_target(ExchangeComplete);
},
),
func.bundle_func(),
))
.id();
world.entity_mut(agent).insert(OnSpawn::observe(
move |_ev: On<Insert, Request>, mut commands: Commands| {
commands.entity(action_root).trigger_target(GetOutcome);
},
));
agent
})
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
#[beet_core::test]
#[cfg(feature = "http")]
async fn flow_inserts_response() {
use beet_flow::prelude::*;
ServerPlugin::world()
.spawn(ExchangeSpawner::new_flow(|| {
OnSpawn::observe(
|ev: On<GetOutcome>,
agents: AgentQuery,
mut commands: Commands| {
let action = ev.target();
let agent = agents.entity(action);
commands.entity(agent).insert(Response::from_status(
StatusCode::ImATeapot,
));
commands.entity(action).trigger_target(Outcome::Pass);
},
)
}))
.oneshot(Request::get("foo"))
.await
.status()
.xpect_eq(StatusCode::ImATeapot);
}
#[beet_core::test]
async fn flow_outcome_pass() {
use beet_flow::prelude::*;
ServerPlugin::world()
.spawn(ExchangeSpawner::new_flow(|| EndWith(Outcome::Pass)))
.oneshot(Request::get("foo"))
.await
.status()
.xpect_eq(StatusCode::Ok);
}
#[beet_core::test]
async fn flow_outcome_fail() {
use beet_flow::prelude::*;
ServerPlugin::world()
.spawn(ExchangeSpawner::new_flow(|| EndWith(Outcome::Fail)))
.oneshot(Request::get("foo"))
.await
.status()
.xpect_eq(StatusCode::InternalError);
}
#[beet_core::test]
#[cfg(feature = "http")]
async fn agent_is_separate_from_action_root() {
use beet_flow::prelude::*;
let mut world = ServerPlugin::world();
world.spawn(ExchangeSpawner::new_flow(|| {
OnSpawn::observe(
|ev: On<GetOutcome>,
agents: AgentQuery,
mut commands: Commands| {
let action = ev.target();
let agent = agents.entity(action);
agent.xpect_not_eq(action);
agent.xpect_not_eq(agents.parents.root_ancestor(action));
commands
.entity(agent)
.insert(Response::from_status(StatusCode::ImATeapot));
commands.entity(action).trigger_target(Outcome::Pass);
},
)
}));
world
.oneshot(Request::get("foo"))
.await
.status()
.xpect_eq(StatusCode::ImATeapot);
}
}