Skip to content

Commit

Permalink
fix(descriptors): make operators section optional (#193)
Browse files Browse the repository at this point in the history
Conceptually, a data flow does not need an Operator to be valid.

This change allows omitting the `operators` section.

Signed-off-by: Julien Loudet <julien.loudet@zettascale.tech>
  • Loading branch information
J-Loudet authored Feb 26, 2024
1 parent c1c3a70 commit bfe337d
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 5 deletions.
61 changes: 56 additions & 5 deletions zenoh-flow-descriptors/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,16 @@ use zenoh_flow_commons::{Configuration, NodeId, RuntimeId};
///
/// In Zenoh-Flow, we divide a descriptor into sections, each responsible for a single aspect of the applications.
///
/// The **required** sections are:
/// The *main* sections are:
/// - `name` : A short human-readable summary of what your data flow will do.
/// - `sources` : A non-empty list of Source(s) to feed data into your data flow.
/// - `operators`: A list of Operator(s) to perform transformation on the data.
/// - `operators`: A list of Operator(s) to perform transformation on the data. A data flow can have no Operator, in
/// which case this section can be omitted.
/// - `sinks` : A non-empty list of Sink(s) to output the result of the transformation(s) performed in your data
/// flow.
/// - `links` : How the different nodes of your data flow are connected.
///
/// Special, **optional**, sections can also be added to tweak a data flow:
/// Special, *optional*, sections can also be added to tweak a data flow:
/// - `uuid`: The unique identifier to give to an instance of this data flow.
/// If not provided, Zenoh-Flow will generate a random one when instantiating the flow.
///
Expand All @@ -71,13 +72,13 @@ use zenoh_flow_commons::{Configuration, NodeId, RuntimeId};
///
/// The three types of nodes -- Sources, Sinks and Operators -- share a similar structure.
///
/// The **required** sections are:
/// The *required* sections are:
/// - `id` : A unique name -- within your data flow.
/// - `library`: A [Url](url::Url) pointing at the implementation of the node's logic.
/// - `inputs` : The entry points of the node (i.e. to receive data). ⚠️ Only for **Sinks** and **Operators**.
/// - `outputs`: The exit points of the node (i.e. to forward data). ⚠️ Only for **Sources** and **Operators**.
///
/// The **optional** sections are:
/// The *optional* sections are:
/// - `description` : A human-readable description of what the node does.
/// - `configuration`: To pass down values to the node when Zenoh-Flow creates it. Values in a node's section will
/// *overwrite* that of the data flow.
Expand Down Expand Up @@ -248,6 +249,7 @@ pub struct DataFlowDescriptor {
#[serde(default)]
pub(crate) configuration: Configuration,
/// *(optional)* A list of Operator(s), the nodes that manipulate and / or produce data.
#[serde(default)]
pub(crate) operators: Vec<OperatorDescriptor>,
/// A non-empty list of Source(s), the nodes that provide data to the data flow.
pub(crate) sources: Vec<SourceDescriptor>,
Expand Down Expand Up @@ -333,6 +335,55 @@ mod tests {
}
]
}
"#;
let data_flow_json = serde_json::from_str::<DataFlowDescriptor>(flow_json_str)
.expect("Failed to deserialize flow from JSON");
assert!(serde_json::to_string(&data_flow_json).is_ok());
}

#[test]
fn test_serialization_deserialization_no_operators() {
let flow_json_str = r#"
{
"name": "DataFlow",
"configuration": {
"foo": "bar"
},
"sources": [
{
"id": "Source",
"descriptor": "file:///home/zenoh-flow/nodes/source.yaml",
"configuration": {
"answer": 0
}
}
],
"sinks": [
{
"id": "Sink",
"descriptor": "file:///home/zenoh-flow/nodes/sink.yaml",
"configuration": {
"answer": 2
}
}
],
"links": [
{
"from": {
"node": "Source",
"output": "o-source"
},
"to": {
"node": "Sink",
"input": "i-sink"
}
}
]
}
"#;
let data_flow_json = serde_json::from_str::<DataFlowDescriptor>(flow_json_str)
.expect("Failed to deserialize flow from JSON");
Expand Down
1 change: 1 addition & 0 deletions zenoh-flow-descriptors/src/flattened/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct FlattenedDataFlowDescriptor {
/// A non-empty list of Sources.
pub sources: Vec<FlattenedSourceDescriptor>,
/// A list of Operators.
#[serde(default)]
pub operators: Vec<FlattenedOperatorDescriptor>,
/// A non-empty list of Sinks.
pub sinks: Vec<FlattenedSinkDescriptor>,
Expand Down
47 changes: 47 additions & 0 deletions zenoh-flow-descriptors/src/flattened/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,50 @@ links:
assert!(flat_flow_json.uuid.is_none());
assert!(flat_flow_yaml.mapping.is_empty());
}

#[test]
fn test_serialize_deserialize_no_operators() {
let flow_yaml = r#"
name: test-flow
sources:
- id: source-0
description: source-0
library: "file:///home/zenoh-flow/libsource.so"
outputs:
- out-1
configuration:
id: source-0
sinks:
- id: sink-2
description: sink-2
library: "file:///home/zenoh-flow/libsink.so"
inputs:
- in-1
configuration:
id: sink-2
links:
- from:
node: source-0
output: out-1
to:
node: sink-2
input: in-1
"#;

let flat_flow_yaml = serde_yaml::from_str::<FlattenedDataFlowDescriptor>(flow_yaml)
.expect("Failed to deserialize flow from YAML");

let json_string_flow =
serde_json::to_string(&flat_flow_yaml).expect("Failed to serialize flow as JSON");

let flat_flow_json =
serde_json::from_str::<FlattenedDataFlowDescriptor>(json_string_flow.as_str())
.expect("Failed to deserialize flow from JSON");

assert_eq!(flat_flow_yaml, flat_flow_json);
assert!(flat_flow_json.uuid.is_none());
assert!(flat_flow_yaml.mapping.is_empty());
}

0 comments on commit bfe337d

Please sign in to comment.