Trading card city builder game?

tests for deck watcher

eldridge.cam 43bbb55d 7a967673

verified
+200 -6
+32
.sqlx/query-47112e0da87c653526acf007a188f3c08ed6249f1f1788d83cadda77c1e492d4.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "\n WITH inserted_card AS (\n INSERT INTO cards (card_type_id) VALUES ('bread-bakery') RETURNING *\n ),\n\n inserted_card_account AS (\n INSERT INTO card_accounts (card_id, account_id)\n SELECT id, 'foxfriends'\n FROM inserted_card\n )\n\n INSERT INTO tiles (id, tile_type_id, name)\n SELECT id, card_type_id, card_type_id\n FROM inserted_card\n RETURNING id, tile_type_id, name\n ", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "id", 9 + "type_info": "Int8" 10 + }, 11 + { 12 + "ordinal": 1, 13 + "name": "tile_type_id", 14 + "type_info": "Text" 15 + }, 16 + { 17 + "ordinal": 2, 18 + "name": "name", 19 + "type_info": "Text" 20 + } 21 + ], 22 + "parameters": { 23 + "Left": [] 24 + }, 25 + "nullable": [ 26 + false, 27 + false, 28 + false 29 + ] 30 + }, 31 + "hash": "47112e0da87c653526acf007a188f3c08ed6249f1f1788d83cadda77c1e492d4" 32 + }
+32
.sqlx/query-e94fb2129b480b98c28887db72173c4222b3475cfc445f85c911fadc3557e014.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "\n WITH inserted_card AS (\n INSERT INTO cards (card_type_id) VALUES ('rabbit') RETURNING *\n ),\n\n inserted_card_account AS (\n INSERT INTO card_accounts (card_id, account_id)\n SELECT id, 'foxfriends'\n FROM inserted_card\n )\n\n INSERT INTO citizens (id, species_id, name)\n SELECT id, card_type_id, card_type_id\n FROM inserted_card\n RETURNING id, species_id, name\n ", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "id", 9 + "type_info": "Int8" 10 + }, 11 + { 12 + "ordinal": 1, 13 + "name": "species_id", 14 + "type_info": "Text" 15 + }, 16 + { 17 + "ordinal": 2, 18 + "name": "name", 19 + "type_info": "Text" 20 + } 21 + ], 22 + "parameters": { 23 + "Left": [] 24 + }, 25 + "nullable": [ 26 + false, 27 + false, 28 + false 29 + ] 30 + }, 31 + "hash": "e94fb2129b480b98c28887db72173c4222b3475cfc445f85c911fadc3557e014" 32 + }
+134 -4
packages/cartography/src/actor/deck_state/mod.rs
··· 3 3 use crate::bus::{Bus, BusExt}; 4 4 use crate::db::CardClass; 5 5 use kameo::prelude::*; 6 - use serde::{Deserialize, Serialize}; 7 6 use sqlx::PgPool; 8 7 use tokio::sync::mpsc::UnboundedSender; 9 8 10 - #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] 9 + #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] 11 10 pub struct Tile { 12 11 pub id: i64, 13 12 pub tile_type_id: String, 14 13 pub name: String, 15 14 } 16 15 17 - #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] 16 + #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] 18 17 pub struct Citizen { 19 18 pub id: i64, 20 19 pub species_id: String, 21 20 pub name: String, 22 21 } 23 22 24 - #[derive(Serialize, Deserialize, Clone, Debug)] 23 + #[derive(PartialEq, Clone, Default, Debug, kameo::Reply, serde::Serialize, serde::Deserialize)] 25 24 pub struct DeckState { 26 25 pub tiles: Vec<Tile>, 27 26 pub citizens: Vec<Citizen>, ··· 168 167 ctx.stop(); 169 168 } 170 169 } 170 + 171 + #[cfg(test)] 172 + mod tests { 173 + use super::*; 174 + use crate::actor::AddCardToDeck; 175 + use crate::actor::player_socket::Response; 176 + use crate::bus::{Bus, BusExt}; 177 + use crate::test::prelude::*; 178 + use kameo::actor::Spawn; 179 + use sqlx::PgPool; 180 + use tokio::sync::mpsc::unbounded_channel; 181 + 182 + struct GetState; 183 + impl Message<GetState> for DeckWatcher { 184 + type Reply = DeckState; 185 + 186 + async fn handle( 187 + &mut self, 188 + _msg: GetState, 189 + _ctx: &mut Context<Self, Self::Reply>, 190 + ) -> Self::Reply { 191 + self.state.clone() 192 + } 193 + } 194 + 195 + #[sqlx::test( 196 + migrator = "MIGRATOR", 197 + fixtures(path = "../../../fixtures", scripts("seed", "account")) 198 + )] 199 + async fn add_card_to_deck_tile(pool: PgPool) { 200 + let (tx, mut rx) = unbounded_channel(); 201 + let bus = Bus::spawn_default(); 202 + let deck_watcher = 203 + DeckWatcher::spawn((pool.clone(), tx, bus.clone(), "foxfriends".to_owned())); 204 + 205 + matches!(rx.recv().await.unwrap(), Response::PutDeckState(..)); 206 + 207 + let card = sqlx::query_as!( 208 + Tile, 209 + r#" 210 + WITH inserted_card AS ( 211 + INSERT INTO cards (card_type_id) VALUES ('bread-bakery') RETURNING * 212 + ), 213 + 214 + inserted_card_account AS ( 215 + INSERT INTO card_accounts (card_id, account_id) 216 + SELECT id, 'foxfriends' 217 + FROM inserted_card 218 + ) 219 + 220 + INSERT INTO tiles (id, tile_type_id, name) 221 + SELECT id, card_type_id, card_type_id 222 + FROM inserted_card 223 + RETURNING id, tile_type_id, name 224 + "# 225 + ) 226 + .fetch_one(&pool) 227 + .await 228 + .unwrap(); 229 + 230 + bus.notify(AddCardToDeck { 231 + account_id: "foxfriends".to_owned(), 232 + card_id: card.id, 233 + }) 234 + .await 235 + .unwrap(); 236 + 237 + matches!(rx.recv().await.unwrap(), Response::PatchState(..)); 238 + 239 + assert_eq!( 240 + deck_watcher.ask(GetState).await.unwrap(), 241 + DeckState { 242 + tiles: vec![card], 243 + citizens: vec![], 244 + } 245 + ) 246 + } 247 + 248 + #[sqlx::test( 249 + migrator = "MIGRATOR", 250 + fixtures(path = "../../../fixtures", scripts("seed", "account")) 251 + )] 252 + async fn add_card_to_deck_citizen(pool: PgPool) { 253 + let (tx, mut rx) = unbounded_channel(); 254 + let bus = Bus::spawn_default(); 255 + let deck_watcher = 256 + DeckWatcher::spawn((pool.clone(), tx, bus.clone(), "foxfriends".to_owned())); 257 + 258 + matches!(rx.recv().await.unwrap(), Response::PutDeckState(..)); 259 + 260 + let card = sqlx::query_as!( 261 + Citizen, 262 + r#" 263 + WITH inserted_card AS ( 264 + INSERT INTO cards (card_type_id) VALUES ('rabbit') RETURNING * 265 + ), 266 + 267 + inserted_card_account AS ( 268 + INSERT INTO card_accounts (card_id, account_id) 269 + SELECT id, 'foxfriends' 270 + FROM inserted_card 271 + ) 272 + 273 + INSERT INTO citizens (id, species_id, name) 274 + SELECT id, card_type_id, card_type_id 275 + FROM inserted_card 276 + RETURNING id, species_id, name 277 + "# 278 + ) 279 + .fetch_one(&pool) 280 + .await 281 + .unwrap(); 282 + 283 + bus.notify(AddCardToDeck { 284 + account_id: "foxfriends".to_owned(), 285 + card_id: card.id, 286 + }) 287 + .await 288 + .unwrap(); 289 + 290 + matches!(rx.recv().await.unwrap(), Response::PatchState(..)); 291 + 292 + assert_eq!( 293 + deck_watcher.ask(GetState).await.unwrap(), 294 + DeckState { 295 + tiles: vec![], 296 + citizens: vec![card], 297 + } 298 + ) 299 + } 300 + }
+1 -1
packages/cartography/src/api/ws.rs
··· 60 60 .unwrap_or(JSON_PROTOCOL) 61 61 .to_owned(); 62 62 ws.on_upgrade(move |socket: WebSocket| async move { 63 - let _span = tracing::info_span!("websocket connection"); 63 + let _span = tracing::info_span!("websocket connection", protocol); 64 64 tracing::debug!("websocket connected"); 65 65 let (ws_sender, ws_receiver) = socket.split(); 66 66 futures::pin_mut!(ws_sender);
+1 -1
packages/cartography/src/bus.rs
··· 43 43 .flatten() 44 44 .filter_map(|entry| entry.as_any().downcast_ref::<Recipient<T>>()) 45 45 { 46 - if let Err(error) = dbg!(recipient.tell(notification.clone()).await) { 46 + if let Err(error) = recipient.tell(notification.clone()).await { 47 47 tracing::error!("bus failed to notify: {}", error); 48 48 } 49 49 }