use super::bindings::bindings;
use super::depth::ceil_ratio;
use super::v1;
use crate::v2;
const DEFAULT_SLOTS: u32 = 16;
pub fn lower_deployment(
system: &v2::System,
name: &str,
packages: &[&v2::Package],
) -> Option<v1::Deployment> {
lower_with_bindings(system, name, packages, bindings())
}
fn lower_with_bindings(
system: &v2::System,
name: &str,
packages: &[&v2::Package],
bindings: Vec<v1::Binding>,
) -> Option<v1::Deployment> {
let deployment = system
.deployments
.iter()
.find(|candidate| candidate.name == name)?;
Some(v1::Deployment {
system: system.qualified_name(),
name: deployment.name.clone(),
regions: regions(system),
instances: instances(system, deployment),
channels: channels(system, deployment, packages),
bindings,
})
}
fn regions(system: &v2::System) -> Vec<v1::Region> {
system
.regions
.iter()
.map(|region| v1::Region {
catalog: region.catalog.clone(),
hash: region.hash.clone(),
interfaces: region
.interfaces
.iter()
.map(|interface| v1::RegionInterface {
name: interface.name.clone(),
number: interface.number,
inline: interface.inline,
provisional: interface.provisional,
service: interface.service.clone(),
})
.collect(),
})
.collect()
}
fn instances(system: &v2::System, deployment: &v2::Deployment) -> Vec<v1::Instance> {
deployment
.placements
.iter()
.map(|placement| {
let component = system
.components
.iter()
.find(|component| component.qualified_name() == placement.component);
let offered: Vec<&str> = component
.map(|component| {
component
.offers
.iter()
.map(|offer| offer.service.as_str())
.collect()
})
.unwrap_or_default();
let offers = system
.regions
.iter()
.flat_map(|region| {
region
.interfaces
.iter()
.filter(|interface| offered.contains(&interface.service.as_str()))
.map(|interface| v1::InterfaceKey {
catalog: region.catalog.clone(),
number: interface.number,
name: interface.name.clone(),
inline: interface.inline,
})
})
.collect();
let maps = system
.grants
.iter()
.find(|grant| grant.component == placement.component)
.map(|grant| grant.regions.clone())
.unwrap_or_default();
v1::Instance {
component: placement.component.clone(),
instance: placement.instance.clone(),
machine: placement.machine.clone(),
external: component.is_some_and(|component| component.external),
offers,
maps,
}
})
.collect()
}
fn channels(
system: &v2::System,
deployment: &v2::Deployment,
packages: &[&v2::Package],
) -> Vec<v1::Channel> {
let mut channels = Vec::new();
for route in &deployment.routes {
let (kind, timing) = member_kind(packages, route);
let inline = inline_of(system, route);
let bound = matches!(kind, v1::Kind::Event).then(|| depth_of(timing));
let call = matches!(kind, v1::Kind::Command | v1::Kind::Query);
let mut producers: Vec<&v2::Endpoint> = route.producers.iter().collect();
producers.sort_by(|left, right| {
(&left.component, &left.instance).cmp(&(&right.component, &right.instance))
});
for producer in producers {
let mut links: Vec<&v2::Link> = deployment
.links
.iter()
.filter(|link| {
link.interface.as_ref().is_some_and(|interface| {
interface.catalog == route.catalog
&& interface.name == route.interface
&& interface.inline == inline
})
})
.filter(|link| link.producer.as_ref() == Some(producer))
.collect();
links.sort_by_key(|link| {
link.consumer
.as_ref()
.map(|consumer| (consumer.component.clone(), consumer.instance.clone()))
});
let consumers: Vec<v1::Consumer> = links
.iter()
.filter_map(|link| {
let consumer = link.consumer.as_ref()?;
let declared = declared_sizing(deployment, consumer);
let depth = bound.map(|bound| match declared.depth {
Some(value) => v1::Depth {
value: Some(value),
source: v1::ValueSource::Declared as i32,
},
None => bound,
});
let (slots, slots_source) = match declared.slots {
Some(value) if call => (Some(value), v1::ValueSource::Declared as i32),
None if call => (Some(DEFAULT_SLOTS), v1::ValueSource::Default as i32),
_ => (None, v1::ValueSource::Unspecified as i32),
};
let (budget, budget_source) = match declared.budget {
Some(value) if call => (Some(value), v1::ValueSource::Declared as i32),
_ => (None, v1::ValueSource::Unspecified as i32),
};
Some(v1::Consumer {
component: consumer.component.clone(),
instance: consumer.instance.clone(),
machine: consumer.machine.clone(),
crossing: crossing_of(link.crossing),
encoding: encoding_of(link.crossing),
depth,
slots,
slots_source,
budget,
budget_source,
})
})
.collect();
channels.push(v1::Channel {
catalog: route.catalog.clone(),
interface_number: route.interface_number,
interface: route.interface.clone(),
inline,
member_ordinal: route.member_ordinal,
member: route.member.clone(),
kind: kind as i32,
producer: Some(v1::Endpoint {
component: producer.component.clone(),
instance: producer.instance.clone(),
machine: producer.machine.clone(),
}),
depth: bound.map(|bound| ring_depth(&consumers, bound)),
consumers,
});
}
}
channels
}
fn declared_sizing(deployment: &v2::Deployment, consumer: &v2::Endpoint) -> v2::Sizing {
let placed = deployment
.placements
.iter()
.find(|placement| {
placement.component == consumer.component && placement.instance == consumer.instance
})
.and_then(|placement| placement.sizing.as_ref());
let sites = [placed, deployment.sizing.as_ref()];
v2::Sizing {
depth: sites.iter().flatten().find_map(|sizing| sizing.depth),
slots: sites.iter().flatten().find_map(|sizing| sizing.slots),
budget: sites.iter().flatten().find_map(|sizing| sizing.budget),
}
}
fn crossing_of(crossing: i32) -> i32 {
let value = match v2::Crossing::try_from(crossing) {
Ok(v2::Crossing::SameMachine) => v1::Crossing::SameMachine,
Ok(v2::Crossing::DifferentMachine) => v1::Crossing::DifferentMachine,
Ok(v2::Crossing::OffBoard) => v1::Crossing::OffBoard,
Ok(v2::Crossing::Unspecified) | Err(_) => v1::Crossing::Unspecified,
};
value as i32
}
fn encoding_of(crossing: i32) -> i32 {
let encoding = match v2::Crossing::try_from(crossing) {
Ok(v2::Crossing::SameMachine) => v1::Encoding::Flatbuffers,
Ok(v2::Crossing::DifferentMachine | v2::Crossing::OffBoard) => v1::Encoding::Proto3,
Ok(v2::Crossing::Unspecified) | Err(_) => v1::Encoding::Unspecified,
};
encoding as i32
}
fn inline_of(system: &v2::System, route: &v2::Route) -> bool {
system
.regions
.iter()
.filter(|region| region.catalog == route.catalog)
.flat_map(|region| ®ion.interfaces)
.find(|interface| {
interface.number == route.interface_number && interface.name == route.interface
})
.is_some_and(|interface| interface.inline)
}
fn member_kind<'a>(
packages: &[&'a v2::Package],
route: &v2::Route,
) -> (v1::Kind, Option<&'a v2::Timing>) {
let found = packages
.iter()
.copied()
.filter(|package| package.name == route.catalog)
.flat_map(v2::Package::shapes)
.find(|shape| shape.name == route.interface);
let Some(shape) = found else {
return (v1::Kind::Unspecified, None);
};
let member = shape
.interface
.interactions
.iter()
.find(|decl| decl.ordinal == route.member_ordinal);
match member.and_then(|decl| decl.kind.as_ref()) {
Some(v2::decl::Kind::SignalDef(signal)) => (v1::Kind::Signal, signal.timing.as_ref()),
Some(v2::decl::Kind::EventDef(event)) => (v1::Kind::Event, event.timing.as_ref()),
Some(v2::decl::Kind::CommandDef(command)) => (v1::Kind::Command, command.timing.as_ref()),
Some(v2::decl::Kind::QueryDef(query)) => (v1::Kind::Query, query.timing.as_ref()),
Some(v2::decl::Kind::FixedDef(_)) => (v1::Kind::Fixed, None),
Some(
v2::decl::Kind::TypeDef(_)
| v2::decl::Kind::ConstDef(_)
| v2::decl::Kind::StructDef(_)
| v2::decl::Kind::EnumDef(_)
| v2::decl::Kind::EnumSetDef(_)
| v2::decl::Kind::UnionDef(_)
| v2::decl::Kind::ReservedSlot(_),
)
| None => (v1::Kind::Unspecified, None),
}
}
fn depth_of(timing: Option<&v2::Timing>) -> v1::Depth {
let derived =
timing.and_then(|timing| ceil_ratio(timing.max_us.as_deref()?, timing.min_us.as_deref()?));
match derived {
Some(value) => v1::Depth {
value: Some(value),
source: v1::ValueSource::Derived as i32,
},
None => v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
},
}
}
fn ring_depth(consumers: &[v1::Consumer], bound: v1::Depth) -> v1::Depth {
if consumers.is_empty() {
return bound;
}
let mut deepest: Option<v1::Depth> = None;
for consumer in consumers {
let Some(depth) = consumer.depth.filter(|depth| depth.value.is_some()) else {
return v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
};
};
let rank = |depth: v1::Depth| {
(
depth.value,
depth.source == v1::ValueSource::Declared as i32,
)
};
if deepest.is_none_or(|held| rank(held) < rank(depth)) {
deepest = Some(depth);
}
}
deepest.unwrap_or(bound)
}
#[cfg(test)]
mod tests {
use super::{lower_deployment, lower_with_bindings};
use crate::codegen::bindings::{KNOWN, Known, bindings, render};
use crate::codegen::v1;
use crate::v2;
const EVENT_ORDINAL: u32 = 1;
const QUERY_ORDINAL: u32 = 2;
const SIGNAL_ORDINAL: u32 = 3;
const HALF_OPEN_ORDINAL: u32 = 4;
const SECOND_EVENT_ORDINAL: u32 = 5;
const CATALOG: &str = "veh.cabin";
const INTERFACE: &str = "Climate";
const SERVICE: &str = "veh.cabin.climate";
const PROVIDER: &str = "veh.cabin.Provider";
const DASH: &str = "veh.cabin.Dash";
const LOGGER: &str = "veh.cabin.Logger";
const FLEET: &str = "veh.cabin.Fleet";
fn timing(min_us: Option<&str>, max_us: Option<&str>) -> v2::Timing {
v2::Timing {
mode: v2::TimingMode::Range as i32,
min_us: min_us.map(str::to_string),
max_us: max_us.map(str::to_string),
default_applied: false,
}
}
fn member(name: &str, ordinal: u32, kind: v2::decl::Kind) -> v2::Decl {
v2::Decl {
name: name.to_string(),
ordinal,
kind: Some(kind),
..Default::default()
}
}
fn package() -> v2::Package {
v2::Package {
name: CATALOG.to_string(),
interfaces: vec![v2::Interface {
name: INTERFACE.to_string(),
number: 1,
interactions: vec![
member(
"TempChanged",
EVENT_ORDINAL,
v2::decl::Kind::EventDef(v2::EventDef {
payload: "Temp".to_string(),
timing: Some(timing(Some("100000"), Some("1000000"))),
}),
),
member(
"GetTemp",
QUERY_ORDINAL,
v2::decl::Kind::QueryDef(v2::QueryDef::default()),
),
member(
"Level",
SIGNAL_ORDINAL,
v2::decl::Kind::SignalDef(v2::SignalDef::default()),
),
member(
"FanSpeedChanged",
HALF_OPEN_ORDINAL,
v2::decl::Kind::EventDef(v2::EventDef {
payload: "Speed".to_string(),
timing: Some(timing(Some("100000"), None)),
}),
),
member(
"HumidityChanged",
SECOND_EVENT_ORDINAL,
v2::decl::Kind::EventDef(v2::EventDef {
payload: "Humidity".to_string(),
timing: Some(timing(Some("400000"), Some("1000000"))),
}),
),
],
..Default::default()
}],
..Default::default()
}
}
fn component(name: &str, instances: &[&str], external: bool) -> v2::Component {
v2::Component {
name: name.to_string(),
instances: instances.iter().map(|name| (*name).to_string()).collect(),
external,
..Default::default()
}
}
fn endpoint(component: &str, instance: &str, machine: &str) -> v2::Endpoint {
v2::Endpoint {
component: component.to_string(),
instance: instance.to_string(),
machine: machine.to_string(),
}
}
fn placement(
component: &str,
instance: &str,
machine: &str,
sizing: Option<v2::Sizing>,
) -> v2::Placement {
v2::Placement {
component: component.to_string(),
instance: instance.to_string(),
machine: machine.to_string(),
attributes: Vec::new(),
sizing,
}
}
fn interface_ref() -> v2::InterfaceRef {
v2::InterfaceRef {
catalog: CATALOG.to_string(),
name: INTERFACE.to_string(),
inline: false,
}
}
fn link(consumer: v2::Endpoint, producer: v2::Endpoint, crossing: v2::Crossing) -> v2::Link {
v2::Link {
interface: Some(interface_ref()),
service: SERVICE.to_string(),
consumer: Some(consumer),
producer: Some(producer),
crossing: crossing as i32,
}
}
fn route(member: &str, ordinal: u32) -> v2::Route {
v2::Route {
catalog: CATALOG.to_string(),
interface_number: 1,
member_ordinal: ordinal,
interface: INTERFACE.to_string(),
member: member.to_string(),
service: SERVICE.to_string(),
producers: vec![
endpoint(PROVIDER, "primary", "head"),
endpoint(PROVIDER, "backup", "zone"),
],
}
}
fn grant(component: &str, external: bool, regions: &[&str]) -> v2::Grant {
v2::Grant {
component: component.to_string(),
external,
regions: regions.iter().map(|name| (*name).to_string()).collect(),
}
}
fn system() -> v2::System {
let mut provider = component("Provider", &["primary", "backup"], false);
provider.package = CATALOG.to_string();
provider.offers = vec![v2::Offer {
service: SERVICE.to_string(),
..Default::default()
}];
let consumer = |name: &str, external: bool| {
let mut component = component(name, &["Unit"], external);
component.package = CATALOG.to_string();
component.requires = vec![v2::Require {
interface: Some(interface_ref()),
service: SERVICE.to_string(),
producer: PROVIDER.to_string(),
..Default::default()
}];
component
};
v2::System {
name: "Cabin".to_string(),
package: CATALOG.to_string(),
components: vec![
provider,
consumer("Dash", false),
consumer("Logger", false),
consumer("Fleet", true),
],
producers: vec![v2::Producer {
service: SERVICE.to_string(),
component: PROVIDER.to_string(),
instances: vec!["primary".to_string(), "backup".to_string()],
not_yet_realizable: true,
}],
grants: vec![
grant(PROVIDER, false, &[]),
grant(DASH, false, &[CATALOG]),
grant(LOGGER, false, &[CATALOG]),
grant(FLEET, true, &[CATALOG]),
],
regions: vec![v2::Region {
catalog: CATALOG.to_string(),
interfaces: vec![v2::RegionInterface {
name: INTERFACE.to_string(),
inline: false,
number: 1,
provisional: false,
service: SERVICE.to_string(),
}],
hash: vec![7; 32],
}],
deployments: vec![v2::Deployment {
name: "prod".to_string(),
package: CATALOG.to_string(),
machines: vec![
v2::Machine {
name: "head".to_string(),
..Default::default()
},
v2::Machine {
name: "zone".to_string(),
..Default::default()
},
v2::Machine {
name: "cloud".to_string(),
external: true,
..Default::default()
},
],
placements: vec![
placement(PROVIDER, "primary", "head", None),
placement(PROVIDER, "backup", "zone", None),
placement(DASH, "Unit", "head", None),
placement(LOGGER, "Unit", "zone", None),
placement(FLEET, "Unit", "cloud", None),
],
links: vec![
link(
endpoint(DASH, "Unit", "head"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::SameMachine,
),
link(
endpoint(DASH, "Unit", "head"),
endpoint(PROVIDER, "backup", "zone"),
v2::Crossing::DifferentMachine,
),
link(
endpoint(LOGGER, "Unit", "zone"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::DifferentMachine,
),
link(
endpoint(LOGGER, "Unit", "zone"),
endpoint(PROVIDER, "backup", "zone"),
v2::Crossing::SameMachine,
),
link(
endpoint(FLEET, "Unit", "cloud"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::OffBoard,
),
link(
endpoint(FLEET, "Unit", "cloud"),
endpoint(PROVIDER, "backup", "zone"),
v2::Crossing::OffBoard,
),
],
routes: vec![
route("TempChanged", EVENT_ORDINAL),
route("GetTemp", QUERY_ORDINAL),
route("Level", SIGNAL_ORDINAL),
route("FanSpeedChanged", HALF_OPEN_ORDINAL),
route("HumidityChanged", SECOND_EVENT_ORDINAL),
],
..Default::default()
}],
..Default::default()
}
}
fn section() -> v1::Deployment {
let package = package();
let system = system();
lower_deployment(&system, "prod", &[&package]).expect("the deployment is named prod")
}
fn channels_of(section: &v1::Deployment, ordinal: u32) -> Vec<v1::Channel> {
section
.channels
.iter()
.filter(|channel| channel.member_ordinal == ordinal)
.cloned()
.collect()
}
fn channel_of(section: &v1::Deployment, ordinal: u32, instance: &str) -> v1::Channel {
channels_of(section, ordinal)
.into_iter()
.find(|channel| {
channel
.producer
.as_ref()
.is_some_and(|producer| producer.instance == instance)
})
.expect("the member has a channel for that producer instance")
}
#[test]
fn the_binding_list_is_the_known_table_in_name_order() {
assert!(KNOWN.is_empty());
assert_eq!(section().bindings, bindings());
assert_eq!(bindings().len(), KNOWN.len());
}
#[test]
fn the_emitter_writes_the_rendered_table_it_is_given() {
let table = [
Known {
name: "websocket",
version: "1",
frame_header_max_bytes: Some(14),
envelope_bytes: None,
},
Known {
name: "tcp",
version: "2",
frame_header_max_bytes: None,
envelope_bytes: Some(8),
},
];
let package = package();
let system = system();
let section = lower_with_bindings(&system, "prod", &[&package], render(&table))
.expect("the deployment is named prod");
assert_eq!(section.bindings, render(&table));
let names: Vec<&str> = section.bindings.iter().map(|b| b.name.as_str()).collect();
assert_eq!(names, ["tcp", "websocket"]);
}
#[test]
fn an_unknown_deployment_name_gives_none() {
let package = package();
let system = system();
assert!(lower_deployment(&system, "staging", &[&package]).is_none());
assert!(lower_deployment(&system, "", &[&package]).is_none());
}
#[test]
fn each_producer_instance_of_a_route_is_one_channel() {
let section = section();
assert_eq!(section.system, "veh.cabin.Cabin");
assert_eq!(section.name, "prod");
assert_eq!(section.channels.len(), 10);
let event = channels_of(§ion, EVENT_ORDINAL);
assert_eq!(event.len(), 2);
let instances: Vec<&str> = event
.iter()
.map(|channel| {
channel
.producer
.as_ref()
.expect("every channel carries a producer")
.instance
.as_str()
})
.collect();
assert_eq!(instances, ["backup", "primary"]);
for channel in &event {
assert_eq!(channel.catalog, CATALOG);
assert_eq!(channel.interface_number, 1);
assert_eq!(channel.interface, INTERFACE);
assert!(!channel.inline);
assert_eq!(channel.member, "TempChanged");
assert_eq!(channel.kind, v1::Kind::Event as i32);
assert_eq!(channel.consumers.len(), 3);
}
let primary = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
primary.producer,
Some(v1::Endpoint {
component: PROVIDER.to_string(),
instance: "primary".to_string(),
machine: "head".to_string(),
})
);
let machines: Vec<&str> = primary
.consumers
.iter()
.map(|consumer| consumer.machine.as_str())
.collect();
assert_eq!(machines, ["head", "cloud", "zone"]);
let backup = channel_of(§ion, EVENT_ORDINAL, "backup");
let machines: Vec<&str> = backup
.consumers
.iter()
.map(|consumer| consumer.machine.as_str())
.collect();
assert_eq!(machines, ["head", "cloud", "zone"]);
}
#[test]
fn a_same_machine_link_is_flatbuffers_and_a_different_machine_link_is_proto3() {
let channel = channel_of(§ion(), EVENT_ORDINAL, "primary");
let seen: Vec<(&str, i32, i32)> = channel
.consumers
.iter()
.map(|consumer| {
(
consumer.component.as_str(),
consumer.crossing,
consumer.encoding,
)
})
.collect();
assert_eq!(
seen,
[
(
DASH,
v1::Crossing::SameMachine as i32,
v1::Encoding::Flatbuffers as i32
),
(
FLEET,
v1::Crossing::OffBoard as i32,
v1::Encoding::Proto3 as i32
),
(
LOGGER,
v1::Crossing::DifferentMachine as i32,
v1::Encoding::Proto3 as i32
),
]
);
let backup = channel_of(§ion(), EVENT_ORDINAL, "backup");
let logger = backup
.consumers
.iter()
.find(|consumer| consumer.component == LOGGER)
.expect("the logger consumes from the backup instance");
assert_eq!(logger.crossing, v1::Crossing::SameMachine as i32);
assert_eq!(logger.encoding, v1::Encoding::Flatbuffers as i32);
}
#[test]
fn an_event_channel_derives_its_depth_and_the_ring_depth_is_the_max() {
let derived = v1::Depth {
value: Some(10),
source: v1::ValueSource::Derived as i32,
};
for instance in ["primary", "backup"] {
let channel = channel_of(§ion(), EVENT_ORDINAL, instance);
assert_eq!(channel.depth, Some(derived));
for consumer in &channel.consumers {
assert_eq!(consumer.depth, Some(derived));
assert_eq!(consumer.slots, None);
assert_eq!(consumer.slots_source, v1::ValueSource::Unspecified as i32);
assert_eq!(consumer.budget, None);
assert_eq!(consumer.budget_source, v1::ValueSource::Unspecified as i32);
}
}
}
#[test]
fn a_half_open_event_has_an_absent_underivable_depth() {
let underivable = v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
};
let channel = channel_of(§ion(), HALF_OPEN_ORDINAL, "primary");
assert_eq!(channel.kind, v1::Kind::Event as i32);
assert_eq!(channel.depth, Some(underivable));
for consumer in &channel.consumers {
assert_eq!(consumer.depth, Some(underivable));
}
}
#[test]
fn a_call_channel_carries_sixteen_default_slots_and_no_budget() {
let channel = channel_of(§ion(), QUERY_ORDINAL, "primary");
assert_eq!(channel.kind, v1::Kind::Query as i32);
assert_eq!(channel.member, "GetTemp");
assert_eq!(channel.depth, None);
assert_eq!(channel.consumers.len(), 3);
for consumer in &channel.consumers {
assert_eq!(consumer.depth, None);
assert_eq!(consumer.slots, Some(16));
assert_eq!(consumer.slots_source, v1::ValueSource::Default as i32);
assert_eq!(consumer.budget, None);
assert_eq!(consumer.budget_source, v1::ValueSource::Unspecified as i32);
}
}
#[test]
fn a_signal_channel_carries_no_sizing() {
let system = sized_system(
Some(sizing(Some(3), Some(8), Some(4096))),
&[(DASH, "Unit", sizing(Some(5), Some(32), Some(65536)))],
);
let channel = channel_of(§ion_of(&system), SIGNAL_ORDINAL, "primary");
assert_eq!(channel.kind, v1::Kind::Signal as i32);
assert_eq!(channel.member, "Level");
assert_eq!(channel.depth, None);
assert_eq!(channel.consumers.len(), 3);
for consumer in &channel.consumers {
assert_eq!(consumer.depth, None);
assert_eq!(consumer.slots, None);
assert_eq!(consumer.slots_source, v1::ValueSource::Unspecified as i32);
assert_eq!(consumer.budget, None);
assert_eq!(consumer.budget_source, v1::ValueSource::Unspecified as i32);
}
}
fn sizing(depth: Option<u32>, slots: Option<u32>, budget: Option<u64>) -> v2::Sizing {
v2::Sizing {
depth,
slots,
budget,
}
}
fn sized_system(
deployment: Option<v2::Sizing>,
placed: &[(&str, &str, v2::Sizing)],
) -> v2::System {
let mut system = system();
let prod = &mut system.deployments[0];
prod.sizing = deployment;
for (component, instance, sizing) in placed {
let placement = prod
.placements
.iter_mut()
.find(|placement| {
placement.component == *component && placement.instance == *instance
})
.expect("the instance is placed");
placement.sizing = Some(*sizing);
}
system
}
fn section_of(system: &v2::System) -> v1::Deployment {
let package = package();
lower_deployment(system, "prod", &[&package]).expect("the deployment is named prod")
}
fn depth_rows(channel: &v1::Channel) -> Vec<(&str, Option<u32>, i32)> {
channel
.consumers
.iter()
.map(|consumer| {
let (value, source) = consumer
.depth
.map_or((None, -1), |depth| (depth.value, depth.source));
(consumer.component.as_str(), value, source)
})
.collect()
}
type CallRow<'a> = (&'a str, Option<u32>, i32, Option<u64>, i32);
fn call_rows(channel: &v1::Channel) -> Vec<CallRow<'_>> {
channel
.consumers
.iter()
.map(|consumer| {
(
consumer.component.as_str(),
consumer.slots,
consumer.slots_source,
consumer.budget,
consumer.budget_source,
)
})
.collect()
}
const DECLARED: i32 = v1::ValueSource::Declared as i32;
const DERIVED: i32 = v1::ValueSource::Derived as i32;
const DEFAULT: i32 = v1::ValueSource::Default as i32;
const UNDERIVABLE: i32 = v1::ValueSource::Underivable as i32;
const UNSPECIFIED: i32 = v1::ValueSource::Unspecified as i32;
#[test]
fn a_placement_value_takes_precedence_over_the_deployment_value() {
let system = sized_system(
Some(sizing(Some(3), Some(8), Some(4096))),
&[(DASH, "Unit", sizing(Some(5), Some(32), Some(65536)))],
);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(5), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(3), DECLARED),
]
);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query),
[
(DASH, Some(32), DECLARED, Some(65536), DECLARED),
(FLEET, Some(8), DECLARED, Some(4096), DECLARED),
(LOGGER, Some(8), DECLARED, Some(4096), DECLARED),
]
);
}
#[test]
fn a_deployment_value_applies_to_every_link() {
let system = sized_system(Some(sizing(Some(3), Some(8), Some(4096))), &[]);
let section = section_of(&system);
for instance in ["primary", "backup"] {
let event = channel_of(§ion, EVENT_ORDINAL, instance);
assert_eq!(
depth_rows(&event),
[
(DASH, Some(3), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(3), DECLARED),
]
);
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(3),
source: DECLARED
})
);
let query = channel_of(§ion, QUERY_ORDINAL, instance);
assert_eq!(
call_rows(&query),
[
(DASH, Some(8), DECLARED, Some(4096), DECLARED),
(FLEET, Some(8), DECLARED, Some(4096), DECLARED),
(LOGGER, Some(8), DECLARED, Some(4096), DECLARED),
]
);
}
}
#[test]
fn a_declared_depth_replaces_the_derived_one_and_the_ring_depth_is_the_max() {
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(25), None, None))]);
let section = section_of(&system);
for instance in ["primary", "backup"] {
let event = channel_of(§ion, EVENT_ORDINAL, instance);
assert_eq!(
depth_rows(&event),
[
(DASH, Some(25), DECLARED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(25),
source: DECLARED
})
);
}
}
#[test]
fn a_declared_budget_has_source_declared() {
let system = sized_system(Some(sizing(None, None, Some(4096))), &[]);
let section = section_of(&system);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query),
[
(DASH, Some(16), DEFAULT, Some(4096), DECLARED),
(FLEET, Some(16), DEFAULT, Some(4096), DECLARED),
(LOGGER, Some(16), DEFAULT, Some(4096), DECLARED),
]
);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
call_rows(&event),
[
(DASH, None, UNSPECIFIED, None, UNSPECIFIED),
(FLEET, None, UNSPECIFIED, None, UNSPECIFIED),
(LOGGER, None, UNSPECIFIED, None, UNSPECIFIED),
]
);
}
#[test]
fn each_key_is_resolved_independently_of_the_others() {
let system = sized_system(None, &[(DASH, "Unit", sizing(None, Some(32), None))]);
let section = section_of(&system);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query)[0],
(DASH, Some(32), DECLARED, None, UNSPECIFIED)
);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(depth_rows(&event)[0], (DASH, Some(10), DERIVED));
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(5), None, None))]);
let section = section_of(&system);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query)[0],
(DASH, Some(16), DEFAULT, None, UNSPECIFIED)
);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(depth_rows(&event)[0], (DASH, Some(5), DECLARED));
let system = sized_system(None, &[(DASH, "Unit", sizing(None, None, Some(4096)))]);
let section = section_of(&system);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query)[0],
(DASH, Some(16), DEFAULT, Some(4096), DECLARED)
);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(depth_rows(&event)[0], (DASH, Some(10), DERIVED));
}
#[test]
fn a_link_with_no_placement_takes_the_deployment_values() {
let mut system = sized_system(
Some(sizing(Some(3), Some(8), Some(4096))),
&[(LOGGER, "Unit", sizing(Some(5), Some(32), Some(65536)))],
);
system.deployments[0]
.placements
.retain(|placement| placement.component != DASH);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(3), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(5), DECLARED),
]
);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query),
[
(DASH, Some(8), DECLARED, Some(4096), DECLARED),
(FLEET, Some(8), DECLARED, Some(4096), DECLARED),
(LOGGER, Some(32), DECLARED, Some(65536), DECLARED),
]
);
}
#[test]
fn a_deployment_value_reaches_a_link_whose_placement_declares_another_key() {
let system = sized_system(
Some(sizing(Some(3), None, Some(4096))),
&[(DASH, "Unit", sizing(None, Some(32), None))],
);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(3), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(3), DECLARED),
]
);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query),
[
(DASH, Some(32), DECLARED, Some(4096), DECLARED),
(FLEET, Some(16), DEFAULT, Some(4096), DECLARED),
(LOGGER, Some(16), DEFAULT, Some(4096), DECLARED),
]
);
}
#[test]
fn every_value_source_is_written_for_its_case() {
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(5), Some(32), None))]);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(5), DECLARED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
let half_open = channel_of(§ion, HALF_OPEN_ORDINAL, "primary");
assert_eq!(
depth_rows(&half_open),
[
(DASH, Some(5), DECLARED),
(FLEET, None, UNDERIVABLE),
(LOGGER, None, UNDERIVABLE),
]
);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(
call_rows(&query),
[
(DASH, Some(32), DECLARED, None, UNSPECIFIED),
(FLEET, Some(16), DEFAULT, None, UNSPECIFIED),
(LOGGER, Some(16), DEFAULT, None, UNSPECIFIED),
]
);
}
#[test]
fn a_declared_depth_below_the_bound_replaces_it() {
let system = sized_system(
Some(sizing(Some(3), None, None)),
&[(DASH, "Unit", sizing(Some(2), None, None))],
);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(2), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(3), DECLARED),
]
);
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(3),
source: DECLARED
})
);
}
#[test]
fn the_ring_depth_is_the_derived_link_when_it_is_deeper_than_the_declared_one() {
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(4), None, None))]);
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "backup");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(4), DECLARED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(10),
source: DERIVED
})
);
}
#[test]
fn a_ring_depth_is_absent_while_one_link_is_underivable() {
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(5), None, None))]);
let section = section_of(&system);
let half_open = channel_of(§ion, HALF_OPEN_ORDINAL, "primary");
assert_eq!(
depth_rows(&half_open),
[
(DASH, Some(5), DECLARED),
(FLEET, None, UNDERIVABLE),
(LOGGER, None, UNDERIVABLE),
]
);
assert_eq!(
half_open.depth,
Some(v1::Depth {
value: None,
source: UNDERIVABLE
})
);
}
#[test]
fn a_declared_depth_replaces_an_underivable_one() {
let system = sized_system(Some(sizing(Some(3), None, None)), &[]);
let section = section_of(&system);
let half_open = channel_of(§ion, HALF_OPEN_ORDINAL, "primary");
assert_eq!(
depth_rows(&half_open),
[
(DASH, Some(3), DECLARED),
(FLEET, Some(3), DECLARED),
(LOGGER, Some(3), DECLARED),
]
);
assert_eq!(
half_open.depth,
Some(v1::Depth {
value: Some(3),
source: DECLARED
})
);
}
#[test]
fn call_keys_on_a_placement_that_consumes_only_events_are_ignored() {
let mut system = sized_system(None, &[(DASH, "Unit", sizing(None, Some(32), Some(4096)))]);
system.deployments[0].routes = vec![route("TempChanged", EVENT_ORDINAL)];
let section = section_of(&system);
assert_eq!(section.channels.len(), 2);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(
call_rows(&event),
[
(DASH, None, UNSPECIFIED, None, UNSPECIFIED),
(FLEET, None, UNSPECIFIED, None, UNSPECIFIED),
(LOGGER, None, UNSPECIFIED, None, UNSPECIFIED),
]
);
assert_eq!(
depth_rows(&event),
[
(DASH, Some(10), DERIVED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
}
#[test]
fn a_depth_on_a_placement_that_consumes_only_calls_is_ignored() {
let mut system = sized_system(None, &[(DASH, "Unit", sizing(Some(5), None, None))]);
system.deployments[0].routes = vec![route("GetTemp", QUERY_ORDINAL)];
let section = section_of(&system);
assert_eq!(section.channels.len(), 2);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
assert_eq!(query.depth, None);
assert_eq!(
depth_rows(&query),
[(DASH, None, -1), (FLEET, None, -1), (LOGGER, None, -1)]
);
assert_eq!(
call_rows(&query),
[
(DASH, Some(16), DEFAULT, None, UNSPECIFIED),
(FLEET, Some(16), DEFAULT, None, UNSPECIFIED),
(LOGGER, Some(16), DEFAULT, None, UNSPECIFIED),
]
);
}
#[test]
fn a_placement_value_reaches_only_the_instance_it_places() {
let mut system = sized_system(Some(sizing(Some(3), None, None)), &[]);
let dash = system
.components
.iter_mut()
.find(|component| component.qualified_name() == DASH)
.expect("Dash is a component of the fixture");
dash.instances = vec!["left".to_string(), "right".to_string()];
let deployment = &mut system.deployments[0];
deployment
.placements
.retain(|placed| placed.component != DASH);
deployment.placements.push(placement(
DASH,
"left",
"head",
Some(sizing(Some(25), Some(32), Some(4096))),
));
deployment
.placements
.push(placement(DASH, "right", "head", None));
deployment.links.retain(|link| {
link.consumer
.as_ref()
.is_some_and(|consumer| consumer.component != DASH)
});
for instance in ["left", "right"] {
deployment.links.push(link(
endpoint(DASH, instance, "head"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::SameMachine,
));
}
let section = section_of(&system);
let event = channel_of(§ion, EVENT_ORDINAL, "primary");
let rows: Vec<(&str, Option<u32>, i32)> = event
.consumers
.iter()
.map(|consumer| {
let depth = consumer.depth.expect("an event link carries a depth");
(consumer.instance.as_str(), depth.value, depth.source)
})
.collect();
assert_eq!(
rows,
[
("left", Some(25), DECLARED),
("right", Some(3), DECLARED),
("Unit", Some(3), DECLARED),
("Unit", Some(3), DECLARED),
]
);
let query = channel_of(§ion, QUERY_ORDINAL, "primary");
let rows: Vec<CallRow<'_>> = query
.consumers
.iter()
.map(|consumer| {
(
consumer.instance.as_str(),
consumer.slots,
consumer.slots_source,
consumer.budget,
consumer.budget_source,
)
})
.collect();
assert_eq!(
rows,
[
("left", Some(32), DECLARED, Some(4096), DECLARED),
("right", Some(16), DEFAULT, None, UNSPECIFIED),
("Unit", Some(16), DEFAULT, None, UNSPECIFIED),
("Unit", Some(16), DEFAULT, None, UNSPECIFIED),
]
);
}
#[test]
fn a_declared_depth_equal_to_the_bound_gives_the_ring_depth_the_declared_source() {
let declared = Some(v1::Depth {
value: Some(10),
source: DECLARED,
});
let system = sized_system(None, &[(LOGGER, "Unit", sizing(Some(10), None, None))]);
let event = channel_of(§ion_of(&system), EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(10), DERIVED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DECLARED),
]
);
assert_eq!(event.depth, declared);
let system = sized_system(None, &[(DASH, "Unit", sizing(Some(10), None, None))]);
let event = channel_of(§ion_of(&system), EVENT_ORDINAL, "primary");
assert_eq!(
depth_rows(&event),
[
(DASH, Some(10), DECLARED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
assert_eq!(event.depth, declared);
}
#[test]
fn each_event_channel_has_its_own_ring_depth() {
let section = section();
for instance in ["primary", "backup"] {
let first = channel_of(§ion, EVENT_ORDINAL, instance);
assert_eq!(
depth_rows(&first),
[
(DASH, Some(10), DERIVED),
(FLEET, Some(10), DERIVED),
(LOGGER, Some(10), DERIVED),
]
);
assert_eq!(
first.depth,
Some(v1::Depth {
value: Some(10),
source: DERIVED
})
);
let second = channel_of(§ion, SECOND_EVENT_ORDINAL, instance);
assert_eq!(second.member, "HumidityChanged");
assert_eq!(
depth_rows(&second),
[
(DASH, Some(3), DERIVED),
(FLEET, Some(3), DERIVED),
(LOGGER, Some(3), DERIVED),
]
);
assert_eq!(
second.depth,
Some(v1::Depth {
value: Some(3),
source: DERIVED
})
);
}
}
#[test]
fn instances_list_what_they_offer_and_what_they_map() {
let section = section();
assert_eq!(
section.regions,
[v1::Region {
catalog: CATALOG.to_string(),
hash: vec![7; 32],
interfaces: vec![v1::RegionInterface {
name: INTERFACE.to_string(),
number: 1,
inline: false,
provisional: false,
service: SERVICE.to_string(),
}],
}]
);
let key = v1::InterfaceKey {
catalog: CATALOG.to_string(),
number: 1,
name: INTERFACE.to_string(),
inline: false,
};
let expected = [
(
PROVIDER,
"primary",
"head",
false,
vec![key.clone()],
vec![],
),
(PROVIDER, "backup", "zone", false, vec![key], vec![]),
(DASH, "Unit", "head", false, vec![], vec![CATALOG]),
(LOGGER, "Unit", "zone", false, vec![], vec![CATALOG]),
(FLEET, "Unit", "cloud", true, vec![], vec![CATALOG]),
];
assert_eq!(section.instances.len(), expected.len());
for (instance, (component, name, machine, external, offers, maps)) in
section.instances.iter().zip(expected)
{
assert_eq!(instance.component, component);
assert_eq!(instance.instance, name);
assert_eq!(instance.machine, machine);
assert_eq!(instance.external, external);
assert_eq!(instance.offers, offers);
assert_eq!(
instance.maps,
maps.iter()
.map(|name| (*name).to_string())
.collect::<Vec<_>>()
);
}
}
fn bytes(section: &v1::Deployment) -> String {
let request = v1::CodegenRequest {
deployment: Some(section.clone()),
..Default::default()
};
crate::codegen::request_to_json(&request).expect("the request renders")
}
#[test]
fn the_emitted_order_does_not_depend_on_the_order_of_the_inputs() {
let package = package();
let system = system();
let first = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let mut permuted = system.clone();
let deployment = &mut permuted.deployments[0];
deployment.links.reverse();
for route in &mut deployment.routes {
route.producers.reverse();
}
let second = lower_deployment(&permuted, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(bytes(&first), bytes(&second));
let producers: Vec<String> = channels_of(&second, EVENT_ORDINAL)
.iter()
.map(|channel| {
channel
.producer
.as_ref()
.expect("every channel carries a producer")
.instance
.clone()
})
.collect();
assert_eq!(producers, ["backup", "primary"]);
let consumers: Vec<String> = channel_of(&second, EVENT_ORDINAL, "primary")
.consumers
.iter()
.map(|consumer| consumer.component.clone())
.collect();
assert_eq!(consumers, [DASH, FLEET, LOGGER]);
let mut reordered = system.clone();
reordered.deployments[0].placements.reverse();
let third = lower_deployment(&reordered, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(third.instances.len(), 5);
assert_ne!(third.instances, first.instances);
let rest = v1::Deployment {
instances: first.instances.clone(),
..third
};
assert_eq!(bytes(&rest), bytes(&first));
}
#[test]
fn a_route_whose_interface_is_not_among_the_packages_keeps_its_channel() {
let system = system();
let section = lower_deployment(&system, "prod", &[]).expect("the fixture lowers");
assert_eq!(section.channels.len(), 10);
for channel in §ion.channels {
assert_eq!(channel.catalog, CATALOG);
assert_eq!(channel.interface_number, 1);
assert_eq!(channel.interface, INTERFACE);
assert!(channel.producer.is_some());
assert_eq!(channel.consumers.len(), 3);
assert_eq!(channel.kind, v1::Kind::Unspecified as i32);
assert_eq!(channel.depth, None);
for consumer in &channel.consumers {
assert_ne!(consumer.encoding, v1::Encoding::Unspecified as i32);
assert_eq!(consumer.depth, None);
assert_eq!(consumer.slots, None);
assert_eq!(consumer.slots_source, v1::ValueSource::Unspecified as i32);
assert_eq!(consumer.budget, None);
assert_eq!(consumer.budget_source, v1::ValueSource::Unspecified as i32);
}
}
assert!(section.channels.iter().all(|channel| !channel.inline));
}
#[test]
fn a_route_matches_its_interface_whatever_number_the_package_carries() {
let mut package = package();
package.interfaces[0].number = 0;
package.interfaces[0].provisional = true;
let system = system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let channel = channel_of(§ion, EVENT_ORDINAL, "primary");
assert_eq!(channel.kind, v1::Kind::Event as i32);
assert_eq!(channel.interface_number, 1);
assert_eq!(
channel.depth,
Some(v1::Depth {
value: Some(10),
source: v1::ValueSource::Derived as i32,
})
);
}
#[test]
fn a_producer_instance_no_link_names_has_a_channel_with_no_consumer() {
let package = package();
let mut system = system();
system.deployments[0].links.retain(|link| {
link.producer
.as_ref()
.is_some_and(|end| end.instance != "backup")
});
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(section.channels.len(), 10);
let event = channel_of(§ion, EVENT_ORDINAL, "backup");
assert!(event.consumers.is_empty());
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(10),
source: v1::ValueSource::Derived as i32,
})
);
let half_open = channel_of(§ion, HALF_OPEN_ORDINAL, "backup");
assert!(half_open.consumers.is_empty());
assert_eq!(
half_open.depth,
Some(v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
})
);
let query = channel_of(§ion, QUERY_ORDINAL, "backup");
assert!(query.consumers.is_empty());
assert_eq!(query.depth, None);
assert_eq!(
channel_of(§ion, EVENT_ORDINAL, "primary")
.consumers
.len(),
3
);
}
#[test]
fn an_inline_service_shape_is_matched_by_its_dotted_name() {
let mut package = package();
let mut interface = package.interfaces.remove(0);
interface.name = String::new();
package.services = vec![v2::Service {
name: SERVICE.to_string(),
shapes: vec![v2::ServiceShape {
kind: Some(v2::service_shape::Kind::Inline(interface)),
}],
..Default::default()
}];
let mut system = system();
let inline_ref = v2::InterfaceRef {
catalog: CATALOG.to_string(),
name: SERVICE.to_string(),
inline: true,
};
system.regions[0].interfaces[0].name = SERVICE.to_string();
system.regions[0].interfaces[0].inline = true;
for component in &mut system.components {
for require in &mut component.requires {
require.interface = Some(inline_ref.clone());
}
}
let deployment = &mut system.deployments[0];
for link in &mut deployment.links {
link.interface = Some(inline_ref.clone());
}
for route in &mut deployment.routes {
route.interface = SERVICE.to_string();
}
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let channel = channel_of(§ion, EVENT_ORDINAL, "primary");
assert!(channel.inline);
assert_eq!(channel.interface, SERVICE);
assert_eq!(channel.kind, v1::Kind::Event as i32);
assert_eq!(channel.consumers.len(), 3);
assert_eq!(
section.instances[0].offers,
[v1::InterfaceKey {
catalog: CATALOG.to_string(),
number: 1,
name: SERVICE.to_string(),
inline: true,
}]
);
}
const HORN: &str = "Horn";
const HORN_SERVICE: &str = "veh.cabin.horn";
const PANEL: &str = "veh.cabin.Panel";
const TELEMETRY: &str = "veh.cabin.Telemetry";
const SET_LEVEL_ORDINAL: u32 = 7;
fn interface_ref_of(name: &str, inline: bool) -> v2::InterfaceRef {
v2::InterfaceRef {
catalog: CATALOG.to_string(),
name: name.to_string(),
inline,
}
}
fn two_interface_package() -> v2::Package {
v2::Package {
name: CATALOG.to_string(),
interfaces: vec![
v2::Interface {
name: INTERFACE.to_string(),
number: 1,
interactions: vec![
member(
"TempChanged",
EVENT_ORDINAL,
v2::decl::Kind::EventDef(v2::EventDef {
payload: "Temp".to_string(),
timing: Some(timing(Some("100000"), Some("1000000"))),
}),
),
member(
"setLevel",
SET_LEVEL_ORDINAL,
v2::decl::Kind::CommandDef(v2::CommandDef::default()),
),
],
..Default::default()
},
v2::Interface {
name: HORN.to_string(),
number: 2,
interactions: vec![member(
"active",
EVENT_ORDINAL,
v2::decl::Kind::EventDef(v2::EventDef {
payload: "Flag".to_string(),
timing: Some(timing(Some("100000"), Some("500000"))),
}),
)],
..Default::default()
},
],
..Default::default()
}
}
fn two_interface_link(consumer: &str, interface: &str, service: &str) -> v2::Link {
v2::Link {
interface: Some(interface_ref_of(interface, false)),
service: service.to_string(),
consumer: Some(endpoint(consumer, "Unit", "head")),
producer: Some(endpoint(PROVIDER, "primary", "head")),
crossing: v2::Crossing::SameMachine as i32,
}
}
fn two_interface_route(
interface: &str,
number: u32,
name: &str,
ordinal: u32,
service: &str,
) -> v2::Route {
v2::Route {
catalog: CATALOG.to_string(),
interface_number: number,
member_ordinal: ordinal,
interface: interface.to_string(),
member: name.to_string(),
service: service.to_string(),
producers: vec![endpoint(PROVIDER, "primary", "head")],
}
}
fn two_interface_system() -> v2::System {
let mut provider = component("Provider", &["primary"], false);
provider.package = CATALOG.to_string();
provider.offers = vec![
v2::Offer {
service: SERVICE.to_string(),
..Default::default()
},
v2::Offer {
service: HORN_SERVICE.to_string(),
..Default::default()
},
];
let consumer = |name: &str, interface: &str, service: &str| {
let mut component = component(name, &["Unit"], false);
component.package = CATALOG.to_string();
component.requires = vec![v2::Require {
interface: Some(interface_ref_of(interface, false)),
service: service.to_string(),
producer: PROVIDER.to_string(),
..Default::default()
}];
component
};
v2::System {
name: "Cabin".to_string(),
package: CATALOG.to_string(),
components: vec![
provider,
consumer("Panel", INTERFACE, SERVICE),
consumer("Telemetry", HORN, HORN_SERVICE),
],
grants: vec![
grant(PROVIDER, false, &[]),
grant(PANEL, false, &[CATALOG]),
grant(TELEMETRY, false, &[CATALOG]),
],
regions: vec![v2::Region {
catalog: CATALOG.to_string(),
interfaces: vec![
v2::RegionInterface {
name: INTERFACE.to_string(),
inline: false,
number: 1,
provisional: false,
service: SERVICE.to_string(),
},
v2::RegionInterface {
name: HORN.to_string(),
inline: false,
number: 2,
provisional: true,
service: HORN_SERVICE.to_string(),
},
],
hash: vec![3; 32],
}],
deployments: vec![v2::Deployment {
name: "prod".to_string(),
package: CATALOG.to_string(),
machines: vec![v2::Machine {
name: "head".to_string(),
..Default::default()
}],
placements: vec![
placement(PROVIDER, "primary", "head", None),
placement(PANEL, "Unit", "head", None),
placement(TELEMETRY, "Unit", "head", None),
],
links: vec![
two_interface_link(PANEL, INTERFACE, SERVICE),
two_interface_link(TELEMETRY, HORN, HORN_SERVICE),
],
routes: vec![
two_interface_route(INTERFACE, 1, "TempChanged", EVENT_ORDINAL, SERVICE),
two_interface_route(INTERFACE, 1, "setLevel", SET_LEVEL_ORDINAL, SERVICE),
two_interface_route(HORN, 2, "active", EVENT_ORDINAL, HORN_SERVICE),
],
..Default::default()
}],
..Default::default()
}
}
fn consumer_rows(section: &v1::Deployment) -> Vec<(&str, u32, Vec<&str>)> {
section
.channels
.iter()
.map(|channel| {
(
channel.interface.as_str(),
channel.member_ordinal,
channel
.consumers
.iter()
.map(|consumer| consumer.component.as_str())
.collect(),
)
})
.collect()
}
fn kind_rows(section: &v1::Deployment) -> Vec<(&str, i32)> {
section
.channels
.iter()
.map(|channel| (channel.member.as_str(), channel.kind))
.collect()
}
#[test]
fn a_channel_lists_only_the_links_of_its_own_interface() {
let package = two_interface_package();
let system = two_interface_system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(
consumer_rows(§ion),
[
(INTERFACE, EVENT_ORDINAL, vec![PANEL]),
(INTERFACE, SET_LEVEL_ORDINAL, vec![PANEL]),
(HORN, EVENT_ORDINAL, vec![TELEMETRY]),
]
);
}
#[test]
fn a_command_channel_carries_sixteen_default_slots() {
let package = two_interface_package();
let system = two_interface_system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let channel = section
.channels
.iter()
.find(|channel| channel.member_ordinal == SET_LEVEL_ORDINAL)
.expect("the command member has a channel");
assert_eq!(channel.kind, v1::Kind::Command as i32);
assert_eq!(channel.member, "setLevel");
assert_eq!(channel.depth, None);
assert_eq!(channel.consumers.len(), 1);
let consumer = &channel.consumers[0];
assert_eq!(consumer.slots, Some(16));
assert_eq!(consumer.slots_source, v1::ValueSource::Default as i32);
assert_eq!(consumer.depth, None);
assert_eq!(consumer.budget, None);
assert_eq!(consumer.budget_source, v1::ValueSource::Unspecified as i32);
}
#[test]
fn a_region_interface_carries_its_own_provisional_flag() {
let package = two_interface_package();
let system = two_interface_system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let rows: Vec<(&str, u32, bool)> = section.regions[0]
.interfaces
.iter()
.map(|interface| {
(
interface.name.as_str(),
interface.number,
interface.provisional,
)
})
.collect();
assert_eq!(rows, [(INTERFACE, 1, false), (HORN, 2, true)]);
}
#[test]
fn one_inline_interface_does_not_make_its_sibling_inline() {
let mut package = two_interface_package();
let mut horn = package.interfaces.remove(1);
horn.name = String::new();
package.services = vec![v2::Service {
name: HORN_SERVICE.to_string(),
shapes: vec![v2::ServiceShape {
kind: Some(v2::service_shape::Kind::Inline(horn)),
}],
..Default::default()
}];
let mut system = two_interface_system();
system.regions[0].interfaces[1].name = HORN_SERVICE.to_string();
system.regions[0].interfaces[1].inline = true;
let deployment = &mut system.deployments[0];
deployment.links[1].interface = Some(interface_ref_of(HORN_SERVICE, true));
deployment.routes[2].interface = HORN_SERVICE.to_string();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let rows: Vec<(&str, bool, Vec<&str>)> = section
.channels
.iter()
.map(|channel| {
(
channel.interface.as_str(),
channel.inline,
channel
.consumers
.iter()
.map(|consumer| consumer.component.as_str())
.collect(),
)
})
.collect();
assert_eq!(
rows,
[
(INTERFACE, false, vec![PANEL]),
(INTERFACE, false, vec![PANEL]),
(HORN_SERVICE, true, vec![TELEMETRY]),
]
);
assert_eq!(
kind_rows(§ion),
[
("TempChanged", v1::Kind::Event as i32),
("setLevel", v1::Kind::Command as i32),
("active", v1::Kind::Event as i32),
]
);
}
#[test]
fn an_interface_of_the_same_name_in_another_catalog_supplies_nothing() {
let mut decoy = two_interface_package();
decoy.name = "veh.other".to_string();
for interface in &mut decoy.interfaces {
for interaction in &mut interface.interactions {
interaction.kind = Some(v2::decl::Kind::SignalDef(v2::SignalDef::default()));
}
}
let package = two_interface_package();
let system = two_interface_system();
let section =
lower_deployment(&system, "prod", &[&decoy, &package]).expect("the fixture lowers");
assert_eq!(
kind_rows(§ion),
[
("TempChanged", v1::Kind::Event as i32),
("setLevel", v1::Kind::Command as i32),
("active", v1::Kind::Event as i32),
]
);
let event = §ion.channels[0];
assert_eq!(
event.depth,
Some(v1::Depth {
value: Some(10),
source: v1::ValueSource::Derived as i32,
})
);
}
#[test]
fn the_member_is_found_by_ordinal_and_not_by_name() {
let mut package = two_interface_package();
package.interfaces[0].interactions[0].ordinal = SET_LEVEL_ORDINAL;
package.interfaces[0].interactions[1].ordinal = EVENT_ORDINAL;
let system = two_interface_system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(
kind_rows(§ion),
[
("TempChanged", v1::Kind::Command as i32),
("setLevel", v1::Kind::Event as i32),
("active", v1::Kind::Event as i32),
]
);
}
#[test]
fn a_fixed_member_and_a_member_that_is_not_an_interaction_carry_no_sizing() {
let mut package = two_interface_package();
package.interfaces[0].interactions = vec![
member(
"vin",
EVENT_ORDINAL,
v2::decl::Kind::FixedDef(v2::FixedDef::default()),
),
member(
"Temp",
SET_LEVEL_ORDINAL,
v2::decl::Kind::StructDef(v2::StructDef::default()),
),
];
let system = two_interface_system();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(
kind_rows(§ion),
[
("TempChanged", v1::Kind::Fixed as i32),
("setLevel", v1::Kind::Unspecified as i32),
("active", v1::Kind::Event as i32),
]
);
for channel in §ion.channels[..2] {
assert_eq!(channel.depth, None);
for consumer in &channel.consumers {
assert_eq!(consumer.depth, None);
assert_eq!(consumer.slots, None);
assert_eq!(consumer.slots_source, v1::ValueSource::Unspecified as i32);
}
}
}
#[test]
fn an_unspecified_or_unknown_crossing_is_written_as_unspecified() {
let package = two_interface_package();
let mut system = two_interface_system();
system.deployments[0].links[0].crossing = v2::Crossing::Unspecified as i32;
system.deployments[0].links[1].crossing = 99;
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let rows: Vec<(i32, i32)> = section
.channels
.iter()
.flat_map(|channel| &channel.consumers)
.map(|consumer| (consumer.crossing, consumer.encoding))
.collect();
assert_eq!(
rows,
[(
v1::Crossing::Unspecified as i32,
v1::Encoding::Unspecified as i32
); 3]
);
bytes(§ion);
}
#[test]
fn an_instances_external_flag_is_the_components_and_not_the_machines() {
let package = package();
let mut system = system();
for placed in &mut system.deployments[0].placements {
if placed.component == FLEET {
placed.machine = "head".to_string();
} else if placed.component == DASH {
placed.machine = "cloud".to_string();
}
}
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let rows: Vec<(&str, &str, bool)> = section
.instances
.iter()
.map(|instance| {
(
instance.component.as_str(),
instance.machine.as_str(),
instance.external,
)
})
.collect();
assert_eq!(
rows,
[
(PROVIDER, "head", false),
(PROVIDER, "zone", false),
(DASH, "cloud", false),
(LOGGER, "zone", false),
(FLEET, "head", true),
]
);
}
#[test]
fn a_placement_outside_the_closure_and_a_component_with_no_grant_are_listed() {
let package = package();
let mut system = system();
system.grants.retain(|grant| grant.component != DASH);
system.deployments[0]
.placements
.push(placement("veh.cabin.Ghost", "Unit", "head", None));
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(section.instances.len(), 6);
let dash = section
.instances
.iter()
.find(|instance| instance.component == DASH)
.expect("a component with no grant is still listed");
assert!(dash.maps.is_empty());
assert!(dash.offers.is_empty());
let ghost = section
.instances
.iter()
.find(|instance| instance.component == "veh.cabin.Ghost")
.expect("a placement outside the closure is still listed");
assert!(!ghost.external);
assert!(ghost.offers.is_empty());
assert!(ghost.maps.is_empty());
}
#[test]
fn consumer_links_of_one_component_are_sorted_by_instance() {
let package = package();
let mut system = system();
let dash = system
.components
.iter_mut()
.find(|component| component.qualified_name() == DASH)
.expect("Dash is a component of the fixture");
dash.instances = vec!["right".to_string(), "left".to_string()];
let deployment = &mut system.deployments[0];
deployment
.placements
.retain(|placed| placed.component != DASH);
deployment
.placements
.push(placement(DASH, "right", "head", None));
deployment
.placements
.push(placement(DASH, "left", "head", None));
deployment.links.retain(|link| {
link.consumer
.as_ref()
.is_some_and(|consumer| consumer.component != DASH)
});
deployment.links.insert(
0,
link(
endpoint(DASH, "right", "head"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::SameMachine,
),
);
deployment.links.insert(
1,
link(
endpoint(DASH, "left", "head"),
endpoint(PROVIDER, "primary", "head"),
v2::Crossing::SameMachine,
),
);
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
let channel = channel_of(§ion, EVENT_ORDINAL, "primary");
let rows: Vec<(&str, &str)> = channel
.consumers
.iter()
.map(|consumer| (consumer.component.as_str(), consumer.instance.as_str()))
.collect();
assert_eq!(
rows,
[
(DASH, "left"),
(DASH, "right"),
(FLEET, "Unit"),
(LOGGER, "Unit"),
]
);
}
#[test]
fn the_ring_depth_is_the_deepest_link_and_absent_when_any_link_is() {
let derived = |value: u32| v1::Depth {
value: Some(value),
source: v1::ValueSource::Derived as i32,
};
let underivable = v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
};
let declared = v1::Depth {
value: Some(9),
source: v1::ValueSource::Declared as i32,
};
let at = |depth: v1::Depth| v1::Consumer {
depth: Some(depth),
..Default::default()
};
let bound = derived(4);
assert_eq!(super::ring_depth(&[], bound), bound);
assert_eq!(
super::ring_depth(&[at(derived(2)), at(derived(7)), at(derived(5))], bound),
derived(7)
);
assert_eq!(
super::ring_depth(&[at(derived(7)), at(derived(2))], bound),
derived(7)
);
assert_eq!(
super::ring_depth(&[at(derived(2)), at(underivable), at(derived(7))], bound),
underivable
);
assert_eq!(super::ring_depth(&[at(underivable)], bound), underivable);
assert_eq!(
super::ring_depth(&[at(derived(3)), at(declared)], bound),
declared
);
assert_eq!(
super::ring_depth(&[v1::Consumer::default()], bound),
underivable
);
}
#[test]
fn a_depth_is_derived_only_from_two_bounds_neither_of_which_defaults() {
let underivable = v1::Depth {
value: None,
source: v1::ValueSource::Underivable as i32,
};
let derived = v1::Depth {
value: Some(10),
source: v1::ValueSource::Derived as i32,
};
let both = timing(Some("100000"), Some("1000000"));
assert_eq!(super::depth_of(Some(&both)), derived);
let no_max = timing(Some("100000"), None);
assert_eq!(super::depth_of(Some(&no_max)), underivable);
let no_min = timing(None, Some("1000000"));
assert_eq!(super::depth_of(Some(&no_min)), underivable);
let neither = timing(None, None);
assert_eq!(super::depth_of(Some(&neither)), underivable);
assert_eq!(super::depth_of(None), underivable);
let zero_min = timing(Some("0"), Some("1000000"));
assert_eq!(super::depth_of(Some(&zero_min)), underivable);
}
#[test]
fn inline_is_read_from_the_entry_matching_catalog_number_and_name() {
let mut system = two_interface_system();
system.regions[0].interfaces[1].inline = true;
system.regions.insert(
0,
v2::Region {
catalog: "veh.aaa".to_string(),
interfaces: vec![v2::RegionInterface {
name: INTERFACE.to_string(),
inline: true,
number: 1,
provisional: false,
service: "veh.aaa.climate".to_string(),
}],
hash: vec![9; 32],
},
);
let at = |interface: &str, number: u32| {
let route = two_interface_route(interface, number, "m", EVENT_ORDINAL, SERVICE);
super::inline_of(&system, &route)
};
assert!(!at(INTERFACE, 1));
assert!(at(HORN, 2));
assert!(!at(INTERFACE, 2));
assert!(!at(HORN, 1));
}
#[test]
fn what_an_instance_offers_is_in_region_order_then_interface_number_order() {
const AUX: &str = "Aux";
const AUX_CATALOG: &str = "veh.zzz";
const AUX_SERVICE: &str = "veh.zzz.aux";
let package = two_interface_package();
let mut system = two_interface_system();
system.regions.push(v2::Region {
catalog: AUX_CATALOG.to_string(),
interfaces: vec![v2::RegionInterface {
name: AUX.to_string(),
inline: false,
number: 1,
provisional: false,
service: AUX_SERVICE.to_string(),
}],
hash: vec![5; 32],
});
let provider = &mut system.components[0];
provider.offers = [AUX_SERVICE, HORN_SERVICE, SERVICE]
.iter()
.map(|service| v2::Offer {
service: (*service).to_string(),
..Default::default()
})
.collect();
let section = lower_deployment(&system, "prod", &[&package]).expect("the fixture lowers");
assert_eq!(
section.instances[0].offers,
[
v1::InterfaceKey {
catalog: CATALOG.to_string(),
number: 1,
name: INTERFACE.to_string(),
inline: false,
},
v1::InterfaceKey {
catalog: CATALOG.to_string(),
number: 2,
name: HORN.to_string(),
inline: false,
},
v1::InterfaceKey {
catalog: AUX_CATALOG.to_string(),
number: 1,
name: AUX.to_string(),
inline: false,
},
]
);
}
}