hotshot_testing/
test_task.rs1use std::{sync::Arc, time::Duration};
8
9use async_broadcast::{Receiver, Sender};
10use async_lock::RwLock;
11use async_trait::async_trait;
12use futures::future::select_all;
13use hotshot::{
14 traits::TestableNodeImplementation,
15 types::{Event, Message},
16};
17use hotshot_task_impls::{events::HotShotEvent, network::NetworkMessageTaskState};
18use hotshot_types::{
19 message::UpgradeLock,
20 traits::{network::ConnectedNetwork, node_implementation::NodeType},
21};
22use tokio::{
23 spawn,
24 task::JoinHandle,
25 time::{sleep, timeout},
26};
27use tracing::error;
28
29use crate::test_runner::Node;
30
31pub enum TestResult {
33 Pass,
35 Fail(Box<dyn std::fmt::Debug + Send + Sync>),
37}
38
39pub fn spawn_timeout_task(test_sender: Sender<TestEvent>, timeout: Duration) -> JoinHandle<()> {
40 tokio::spawn(async move {
41 sleep(timeout).await;
42
43 error!("Decide timeout triggered.");
44 let _ = test_sender.broadcast(TestEvent::Shutdown).await;
45 })
46}
47
48#[async_trait]
49pub trait TestTaskState: Send {
51 type Event: Clone + Send + Sync;
53 type Error: std::fmt::Display;
55
56 async fn handle_event(
58 &mut self,
59 (event, id): (Self::Event, usize),
60 ) -> std::result::Result<(), Self::Error>;
61
62 async fn check(&self) -> TestResult;
64}
65
66pub type AnyTestTaskState<TYPES> = Box<
69 dyn TestTaskState<Event = hotshot_types::event::Event<TYPES>, Error = anyhow::Error>
70 + Send
71 + Sync,
72>;
73
74#[async_trait]
75impl<TYPES: NodeType> TestTaskState for AnyTestTaskState<TYPES> {
76 type Event = Event<TYPES>;
77 type Error = anyhow::Error;
78
79 async fn handle_event(
80 &mut self,
81 event: (Self::Event, usize),
82 ) -> std::result::Result<(), anyhow::Error> {
83 (**self).handle_event(event).await
84 }
85
86 async fn check(&self) -> TestResult {
87 (**self).check().await
88 }
89}
90
91#[async_trait]
92pub trait TestTaskStateSeed<TYPES, I>: Send
93where
94 TYPES: NodeType,
95 I: TestableNodeImplementation<TYPES>,
96{
97 async fn into_state(
98 self: Box<Self>,
99 handles: Arc<RwLock<Vec<Node<TYPES, I>>>>,
100 ) -> AnyTestTaskState<TYPES>;
101}
102
103pub struct TestTask<S: TestTaskState> {
109 state: S,
113 receivers: Vec<Receiver<S::Event>>,
115 test_receiver: Receiver<TestEvent>,
117}
118
119#[derive(Clone, Debug)]
120pub enum TestEvent {
121 Shutdown,
122}
123
124impl std::fmt::Display for TestEvent {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 match self {
127 TestEvent::Shutdown => write!(f, "Shutdown"),
128 }
129 }
130}
131
132impl<S: TestTaskState + Send + 'static> TestTask<S> {
133 pub fn new(
135 state: S,
136 receivers: Vec<Receiver<S::Event>>,
137 test_receiver: Receiver<TestEvent>,
138 ) -> Self {
139 TestTask {
140 state,
141 receivers,
142 test_receiver,
143 }
144 }
145
146 pub fn run(mut self) -> JoinHandle<TestResult> {
149 spawn(async move {
150 loop {
151 if let Ok(TestEvent::Shutdown) = self.test_receiver.try_recv() {
152 break self.state.check().await;
153 }
154
155 self.receivers.retain(|receiver| !receiver.is_closed());
156
157 if self.receivers.is_empty() {
160 sleep(Duration::from_millis(500)).await;
161 continue;
162 }
163
164 let mut messages = Vec::new();
165
166 for receiver in &mut self.receivers {
167 messages.push(receiver.recv());
168 }
169
170 match timeout(Duration::from_millis(2500), select_all(messages)).await {
171 Ok((Ok(input), id, _)) => {
172 let _ = S::handle_event(&mut self.state, (input, id))
173 .await
174 .inspect_err(|e| tracing::error!("{e}"));
175 },
176 Ok((Err(e), _id, _)) => {
177 error!("Error from one channel in test task {e:?}");
178 sleep(Duration::from_millis(4000)).await;
179 },
180 _ => {},
181 };
182 }
183 })
184 }
185}
186
187pub async fn add_network_message_test_task<
189 TYPES: NodeType,
190 NET: ConnectedNetwork<TYPES::SignatureKey>,
191>(
192 internal_event_stream: Sender<Arc<HotShotEvent<TYPES>>>,
193 external_event_stream: Sender<Event<TYPES>>,
194 upgrade_lock: UpgradeLock<TYPES>,
195 channel: Arc<NET>,
196 public_key: TYPES::SignatureKey,
197 id: u64,
198) -> JoinHandle<()> {
199 let net = Arc::clone(&channel);
200 let network_state: NetworkMessageTaskState<_> = NetworkMessageTaskState {
201 internal_event_stream: internal_event_stream.clone(),
202 external_event_stream: external_event_stream.clone(),
203 public_key,
204 upgrade_lock: upgrade_lock.clone(),
205 id,
206 };
207
208 let network = Arc::clone(&net);
209 let mut state = network_state.clone();
210
211 spawn(async move {
212 loop {
213 let message = match network.recv_message().await {
215 Ok(message) => message,
216 Err(e) => {
217 error!("Failed to receive message: {e:?}");
218 continue;
219 },
220 };
221
222 let deserialized_message: Message<TYPES> = match upgrade_lock.deserialize(&message) {
224 Ok((message, _)) => message,
225 Err(e) => {
226 tracing::error!("Failed to deserialize message: {e:?}");
227 continue;
228 },
229 };
230
231 state.handle_message(deserialized_message).await;
233 }
234 })
235}