race_test/
client_helpers.rs1use std::{collections::HashMap, sync::Arc};
2
3use async_trait::async_trait;
4use race_client::Client;
5use race_api::error::Result;
6use race_api::event::{CustomEvent, Event};
7use race_core::{
8 connection::ConnectionT,
9 context::GameContext,
10 secret::SecretState,
11 types::{AttachGameParams, ClientMode, DecisionId, ExitGameParams, SubmitEventParams},
12};
13use race_encryptor::Encryptor;
14use tokio::sync::{mpsc, Mutex};
15
16use crate::{transport_helpers::DummyTransport, account_helpers::test_game_addr};
17
18pub struct TestClient {
19 client: Client,
20}
21
22pub struct DummyConnection {
23 rx: Mutex<mpsc::Receiver<Event>>,
24 tx: mpsc::Sender<Event>,
25 pub attached: Mutex<bool>,
26}
27
28impl Default for DummyConnection {
29 fn default() -> Self {
30 let (tx, rx) = mpsc::channel(1);
31 Self {
32 tx,
33 rx: Mutex::new(rx),
34 attached: Mutex::new(false),
35 }
36 }
37}
38
39impl DummyConnection {
40 pub async fn take(&self) -> Option<Event> {
41 self.rx.lock().await.recv().await
42 }
43
44 pub async fn is_attached(&self) -> bool {
45 *self.attached.lock().await
46 }
47}
48
49#[async_trait]
50impl ConnectionT for DummyConnection {
51 async fn attach_game(&self, _game_addr: &str, _params: AttachGameParams) -> Result<()> {
52 let mut attached = self.attached.lock().await;
53 *attached = true;
54 Ok(())
55 }
56 async fn submit_event(&self, _game_addr: &str, params: SubmitEventParams) -> Result<()> {
57 self.tx.send(params.event).await.unwrap();
58 Ok(())
59 }
60 async fn exit_game(&self, _game_addr: &str, _params: ExitGameParams) -> Result<()> {
61 Ok(())
62 }
63}
64
65impl TestClient {
66 pub fn new<S: Into<String>>(addr: S, mode: ClientMode) -> Self {
67 let addr = addr.into();
68 let transport = Arc::new(DummyTransport::default());
69 let encryptor = Arc::new(Encryptor::default());
70 let connection = Arc::new(DummyConnection::default());
71 Self {
72 client: Client::new(
73 addr,
74 test_game_addr(),
75 mode,
76 transport,
77 encryptor,
78 connection,
79 ),
80 }
81 }
82
83 pub fn player<S: Into<String>>(addr: S) -> Self {
84 Self::new(addr, ClientMode::Player)
85 }
86
87 pub fn transactor<S: Into<String>>(addr: S) -> Self {
88 Self::new(addr, ClientMode::Transactor)
89 }
90
91 pub fn validator<S: Into<String>>(addr: S) -> Self {
92 Self::new(addr, ClientMode::Validator)
93 }
94
95 pub fn handle_updated_context(&mut self, ctx: &GameContext) -> Result<Vec<Event>> {
96 self.client.handle_updated_context(ctx)
97 }
98
99 pub fn get_mode(&self) -> ClientMode {
100 self.client.mode.clone()
101 }
102
103 pub fn get_addr(&self) -> String {
104 self.client.addr.clone()
105 }
106
107 pub fn decrypt(
108 &mut self,
109 ctx: &GameContext,
110 random_id: usize,
111 ) -> Result<HashMap<usize, String>> {
112 self.client.decrypt(ctx, random_id)
113 }
114
115 pub fn secret_state(&self) -> &SecretState {
116 &self.client.secret_state
117 }
118
119 pub fn custom_event<E: CustomEvent>(&self, custom_event: E) -> Event {
120 Event::Custom {
121 sender: self.client.addr.to_owned(),
122 raw: custom_event.try_to_vec().unwrap(),
123 }
124 }
125
126 pub fn answer(&mut self, decision_id: DecisionId, answer: String) -> Result<Event> {
127 self.client.answer_event(decision_id, answer)
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[tokio::test]
136 async fn test_dummy_connection() -> Result<()> {
137 let conn = DummyConnection::default();
138 let event = Event::GameStart { access_version: 1 };
139 conn.submit_event(
140 "",
141 SubmitEventParams {
142 event: event.clone(),
143 },
144 )
145 .await?;
146 let event_1 = conn.take().await.unwrap();
147 assert_eq!(event, event_1);
148 Ok(())
149 }
150}