Skip to main content

autoagents_core/actor/
transport.rs

1use crate::actor::AnyActor;
2use async_trait::async_trait;
3use std::any::Any;
4use std::fmt::Debug;
5use std::sync::Arc;
6
7#[async_trait]
8pub trait Transport: Send + Sync + Debug {
9    async fn send(
10        &self,
11        actor: &dyn AnyActor,
12        msg: Arc<dyn Any + Send + Sync>,
13    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
14}
15
16#[derive(Debug)]
17pub struct LocalTransport;
18
19#[async_trait]
20impl Transport for LocalTransport {
21    async fn send(
22        &self,
23        actor: &dyn AnyActor,
24        msg: Arc<dyn Any + Send + Sync>,
25    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
26        actor.send_any(msg).await
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33    use crate::actor::{ActorMessage, CloneableMessage};
34    use async_trait::async_trait;
35    use std::sync::{Arc, Mutex};
36
37    // Test message types
38    #[derive(Debug, Clone, PartialEq)]
39    struct TestMessage {
40        content: String,
41    }
42    impl ActorMessage for TestMessage {}
43    impl CloneableMessage for TestMessage {}
44
45    // Mock actor for testing
46    struct MockActor {
47        received_messages: Arc<Mutex<Vec<String>>>,
48        should_fail: bool,
49    }
50
51    impl MockActor {
52        fn new() -> Self {
53            Self {
54                received_messages: Arc::new(Mutex::new(Vec::new())),
55                should_fail: false,
56            }
57        }
58
59        fn with_failure() -> Self {
60            Self {
61                received_messages: Arc::new(Mutex::new(Vec::new())),
62                should_fail: true,
63            }
64        }
65
66        fn received_messages(&self) -> Vec<String> {
67            self.received_messages.lock().unwrap().clone()
68        }
69    }
70
71    impl std::fmt::Debug for MockActor {
72        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73            f.debug_struct("MockActor")
74                .field("should_fail", &self.should_fail)
75                .finish()
76        }
77    }
78
79    #[async_trait]
80    impl AnyActor for MockActor {
81        async fn send_any(
82            &self,
83            msg: Arc<dyn Any + Send + Sync>,
84        ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
85            if self.should_fail {
86                return Err("Mock actor failure".into());
87            }
88
89            if let Some(test_msg) = msg.downcast_ref::<TestMessage>() {
90                self.received_messages
91                    .lock()
92                    .unwrap()
93                    .push(test_msg.content.clone());
94                Ok(())
95            } else {
96                Err("Type mismatch in mock actor".into())
97            }
98        }
99    }
100
101    #[tokio::test]
102    async fn test_local_transport_successful_send() {
103        let transport = LocalTransport;
104        let actor = MockActor::new();
105        let msg = TestMessage {
106            content: "test_message".to_string(),
107        };
108        let arc_msg: Arc<dyn Any + Send + Sync> = Arc::new(msg);
109
110        let result = transport.send(&actor, arc_msg).await;
111
112        assert!(result.is_ok());
113        assert_eq!(actor.received_messages(), vec!["test_message"]);
114    }
115
116    #[tokio::test]
117    async fn test_local_transport_failed_send() {
118        let transport = LocalTransport;
119        let actor = MockActor::with_failure();
120        let msg = TestMessage {
121            content: "failing_message".to_string(),
122        };
123        let arc_msg: Arc<dyn Any + Send + Sync> = Arc::new(msg);
124
125        let result = transport.send(&actor, arc_msg).await;
126
127        assert!(result.is_err());
128        assert_eq!(actor.received_messages().len(), 0);
129    }
130
131    #[tokio::test]
132    async fn test_local_transport_multiple_sends() {
133        let transport = LocalTransport;
134        let actor = MockActor::new();
135
136        let msg1 = TestMessage {
137            content: "message_1".to_string(),
138        };
139        let msg2 = TestMessage {
140            content: "message_2".to_string(),
141        };
142        let msg3 = TestMessage {
143            content: "message_3".to_string(),
144        };
145
146        let arc_msg1: Arc<dyn Any + Send + Sync> = Arc::new(msg1);
147        let arc_msg2: Arc<dyn Any + Send + Sync> = Arc::new(msg2);
148        let arc_msg3: Arc<dyn Any + Send + Sync> = Arc::new(msg3);
149
150        let result1 = transport.send(&actor, arc_msg1).await;
151        let result2 = transport.send(&actor, arc_msg2).await;
152        let result3 = transport.send(&actor, arc_msg3).await;
153
154        assert!(result1.is_ok());
155        assert!(result2.is_ok());
156        assert!(result3.is_ok());
157
158        let received = actor.received_messages();
159        assert_eq!(received.len(), 3);
160        assert_eq!(received[0], "message_1");
161        assert_eq!(received[1], "message_2");
162        assert_eq!(received[2], "message_3");
163    }
164
165    #[tokio::test]
166    async fn test_transport_trait_object() {
167        let transport: Box<dyn Transport> = Box::new(LocalTransport);
168        let actor = MockActor::new();
169        let msg = TestMessage {
170            content: "trait_object_test".to_string(),
171        };
172        let arc_msg: Arc<dyn Any + Send + Sync> = Arc::new(msg);
173
174        let result = transport.send(&actor, arc_msg).await;
175
176        assert!(result.is_ok());
177        assert_eq!(actor.received_messages(), vec!["trait_object_test"]);
178    }
179
180    #[tokio::test]
181    async fn test_transport_concurrent_sends() {
182        let transport = Arc::new(LocalTransport);
183        let actor = Arc::new(MockActor::new());
184
185        let handles = (0..10)
186            .map(|i| {
187                let transport = Arc::clone(&transport);
188                let actor = Arc::clone(&actor);
189
190                tokio::spawn(async move {
191                    let msg = TestMessage {
192                        content: format!("concurrent_message_{i}"),
193                    };
194                    let arc_msg: Arc<dyn Any + Send + Sync> = Arc::new(msg);
195                    transport.send(actor.as_ref(), arc_msg).await
196                })
197            })
198            .collect::<Vec<_>>();
199
200        let results = futures::future::join_all(handles).await;
201
202        // All sends should succeed
203        for result in results {
204            assert!(result.is_ok());
205            assert!(result.unwrap().is_ok());
206        }
207
208        // Should have received 10 messages
209        assert_eq!(actor.received_messages().len(), 10);
210    }
211
212    #[test]
213    fn test_local_transport_creation() {
214        let _transport = LocalTransport;
215        // LocalTransport is a unit struct, so creation should be trivial
216    }
217
218    #[test]
219    fn test_local_transport_debug() {
220        let transport = LocalTransport;
221
222        // Should be able to debug print (though it's a unit struct)
223        let _debug_str = format!("{transport:?}");
224    }
225
226    #[test]
227    fn test_local_transport_clone() {
228        let transport1 = LocalTransport;
229        let transport2 = LocalTransport;
230
231        // Unit structs should be equal
232        // Note: We can't directly compare because LocalTransport doesn't implement PartialEq
233        let _t1_debug = format!("{transport1:?}");
234        let _t2_debug = format!("{transport2:?}");
235    }
236
237    #[tokio::test]
238    async fn test_transport_with_wrong_message_type() {
239        let transport = LocalTransport;
240        let actor = MockActor::new();
241
242        // Send a different type of message
243        #[allow(dead_code)]
244        #[derive(Debug)]
245        struct WrongMessage {
246            data: i32,
247        }
248
249        let msg = WrongMessage { data: 42 };
250        let arc_msg: Arc<dyn Any + Send + Sync> = Arc::new(msg);
251
252        let result = transport.send(&actor, arc_msg).await;
253
254        // Should fail due to type mismatch in mock actor
255        assert!(result.is_err());
256        assert_eq!(actor.received_messages().len(), 0);
257    }
258}