Skip to content

Commit 9fd41c1

Browse files
authored
test/doc: Chain (#66)
1 parent e5726be commit 9fd41c1

File tree

6 files changed

+266
-60
lines changed

6 files changed

+266
-60
lines changed

src/pipelines/events.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@ mod tests {
106106
reth::node::builder::BuiltPayload,
107107
};
108108

109-
#[derive(Clone, Debug, PartialEq, Eq)]
110-
struct StringEvent(String);
111-
112109
#[derive(Clone, Debug, PartialEq, Eq)]
113110
struct UInt32Event(u32);
114111

src/steps/combinator/atomic.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use {super::*, crate::platform::types::BuiltPayload};
22

3-
combinator!(Atomic, and);
3+
combinator!(
4+
/// TODO
5+
, Atomic, and
6+
);
47

58
impl<P: Platform> Step<P> for Atomic<P> {
69
async fn before_job(

src/steps/combinator/chain.rs

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
11
use {super::*, crate::platform::types::BuiltPayload};
22

3-
combinator!(Chain, then);
3+
combinator!(
4+
/// The [`Chain`] combinator executes a sequence of steps in order. Each step
5+
/// receives the output checkpoint from the previous step.
6+
///
7+
/// # Execution Semantics
8+
///
9+
/// - If a step returns [`ControlFlow::Ok`], execution continues with the next
10+
/// step
11+
/// - If a step returns [`ControlFlow::Break`], execution stops and returns
12+
/// [`ControlFlow::Break`]
13+
/// - If a step returns [`ControlFlow::Fail`], execution stops and returns
14+
/// [`ControlFlow::Fail`]
15+
/// - The final result is either the last successful checkpoint or the first
16+
/// non-Ok control flow
17+
///
18+
/// # Example
19+
///
20+
/// ```rust
21+
/// use rblib::prelude::*;
22+
///
23+
/// # fn example<P: Platform>(
24+
/// # step1: impl Step<P>,
25+
/// # step2: impl Step<P>,
26+
/// # step3: impl Step<P>
27+
/// # ) {
28+
/// let chain = Chain::of(step1).then(step2).then(step3);
29+
/// // or using macro:
30+
/// let chain = chain!(step1, step2, step3);
31+
/// # }
32+
/// ```
33+
, Chain, then
34+
);
435

536
impl<P: Platform> Step<P> for Chain<P> {
637
async fn before_job(
@@ -71,3 +102,122 @@ macro_rules! chain {
71102
c
72103
}};
73104
}
105+
106+
#[cfg(test)]
107+
mod tests {
108+
use {
109+
super::*,
110+
crate::{
111+
platform::{Ethereum, Optimism},
112+
steps::CombinatorStep,
113+
test_utils::*,
114+
},
115+
futures::StreamExt,
116+
};
117+
118+
fake_step!(OkEvent2, emit_events, noop_ok);
119+
120+
#[rblib_test(Ethereum, Optimism)]
121+
async fn chain_ok_one_step<P: TestablePlatform>() {
122+
let chain = Chain::of(OkWithEventStep);
123+
124+
let step = OneStep::<P>::new(chain);
125+
let mut event_sub = step.subscribe::<StringEvent>();
126+
127+
let output = step.run().await.unwrap();
128+
assert!(output.is_ok());
129+
130+
assert_eq!(
131+
event_sub.next().await,
132+
Some(StringEvent("OkWithEventStep: before_job".to_string()))
133+
);
134+
assert_eq!(
135+
event_sub.next().await,
136+
Some(StringEvent("OkWithEventStep: step".to_string()))
137+
);
138+
assert_eq!(
139+
event_sub.next().await,
140+
Some(StringEvent("OkWithEventStep: after_job".to_string()))
141+
);
142+
}
143+
144+
#[rblib_test(Ethereum, Optimism)]
145+
async fn chain_execute_in_order<P: TestablePlatform>() {
146+
let chain = Chain::of(OkWithEventStep).then(OkEvent2);
147+
148+
let step = OneStep::<P>::new(chain);
149+
let mut event_sub = step.subscribe::<StringEvent>();
150+
151+
let output = step.run().await.unwrap();
152+
assert!(output.is_ok());
153+
154+
assert_eq!(
155+
event_sub.next().await,
156+
Some(StringEvent("OkWithEventStep: before_job".to_string()))
157+
);
158+
assert_eq!(
159+
event_sub.next().await,
160+
Some(StringEvent("OkEvent2: before_job".to_string()))
161+
);
162+
163+
assert_eq!(
164+
event_sub.next().await,
165+
Some(StringEvent("OkWithEventStep: step".to_string()))
166+
);
167+
assert_eq!(
168+
event_sub.next().await,
169+
Some(StringEvent("OkEvent2: step".to_string()))
170+
);
171+
172+
assert_eq!(
173+
event_sub.next().await,
174+
Some(StringEvent("OkWithEventStep: after_job".to_string()))
175+
);
176+
assert_eq!(
177+
event_sub.next().await,
178+
Some(StringEvent("OkEvent2: after_job".to_string()))
179+
);
180+
}
181+
182+
#[rblib_test(Ethereum, Optimism)]
183+
async fn chain_break_stops_execution<P: TestablePlatform>() {
184+
let chain = Chain::of(AlwaysBreakStep).then(OkWithEventStep);
185+
186+
let step = OneStep::<P>::new(chain);
187+
let mut event_sub = step.subscribe::<StringEvent>();
188+
189+
let output = step.run().await.unwrap();
190+
assert!(output.is_break());
191+
192+
assert_eq!(
193+
event_sub.next().await,
194+
Some(StringEvent("OkWithEventStep: before_job".to_string()))
195+
);
196+
// step is not called
197+
assert_eq!(
198+
event_sub.next().await,
199+
Some(StringEvent("OkWithEventStep: after_job".to_string()))
200+
);
201+
}
202+
203+
#[rblib_test(Ethereum, Optimism)]
204+
async fn chain_fail_stops_execution<P: TestablePlatform>() {
205+
let chain = Chain::of(AlwaysFailStep).then(OkWithEventStep);
206+
207+
let step = OneStep::<P>::new(chain);
208+
let mut event_sub = step.subscribe::<StringEvent>();
209+
210+
let output = step.run().await.unwrap();
211+
assert!(output.is_fail());
212+
213+
assert_eq!(
214+
event_sub.next().await,
215+
Some(StringEvent("OkWithEventStep: before_job".to_string()))
216+
);
217+
// step is not called
218+
assert_eq!(
219+
event_sub.next().await,
220+
Some(StringEvent("OkWithEventStep: after_job".to_string()))
221+
);
222+
}
223+
}

src/steps/combinator/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ pub trait CombinatorStep<P: Platform>: Step<P> {
4848
/// - `$append()` method to append a step to the collection
4949
/// - `steps()` method to get a slice of the steps for the `Step` implementation
5050
macro_rules! combinator {
51+
// meta is rustdoc for the combinator struct,
5152
// name is the combinator struct name,
5253
// append the method name of adding a step (optional)
53-
($name:ident, $append:ident) => {
54-
/// Combinator step that executes a sequence of steps in order.
54+
($(#[$meta:meta])*, $name:ident, $append:ident) => {
55+
$(#[$meta])*
5556
pub struct $name<P: Platform>(pub Steps<P>);
5657

5758
impl<P: Platform> CombinatorStep<P> for $name<P> {
@@ -89,8 +90,8 @@ macro_rules! combinator {
8990
};
9091

9192
// default method name for adding a step: append
92-
($name:ident) => {
93-
combinator!($name, append);
93+
($(#[$meta:meta])*, $name:ident) => {
94+
combinator!($(#[$meta])*, $name, append);
9495
};
9596
}
9697

@@ -122,7 +123,10 @@ impl<P: Platform, S: Step<P>> IntoSteps<P> for S {
122123
pub mod tests {
123124
use {super::*, crate::test_utils::*};
124125

125-
combinator!(TestCombinator, test_append);
126+
combinator!(
127+
/// `TestCombinator` doc
128+
, TestCombinator, test_append
129+
);
126130
impl<P: Platform> Step<P> for TestCombinator<P> {
127131
async fn step(
128132
self: Arc<Self>,

src/test_utils/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ mod platform;
2222
mod step;
2323
mod transactions;
2424

25-
#[allow(unused_imports)]
2625
pub(crate) use step::fake_step;
2726
pub use {
2827
accounts::{FundedAccounts, WithFundedAccounts},
@@ -32,7 +31,14 @@ pub use {
3231
node::{ConsensusDriver, LocalNode},
3332
platform::{TestNodeFactory, TestablePlatform},
3433
rblib_tests_macros::{assert_is_dyn_safe, if_platform, rblib_test},
35-
step::{AlwaysBreakStep, AlwaysFailStep, AlwaysOkStep, OneStep},
34+
step::{
35+
AlwaysBreakStep,
36+
AlwaysFailStep,
37+
AlwaysOkStep,
38+
OkWithEventStep,
39+
OneStep,
40+
StringEvent,
41+
},
3642
transactions::{
3743
invalid_tx,
3844
reverting_tx,

0 commit comments

Comments
 (0)