summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 21:36:26 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 21:36:26 +0100
commit772727b0ef7d63144bf629d774f8b6c1c996bf78 (patch)
tree1680dbbd61fce2aaf383ee81ad04ff0705ffe985 /tests
parentv2.3.0: add crash with local multiplier and pushed crash event (diff)
downloadzagan-bet-772727b0ef7d63144bf629d774f8b6c1c996bf78.tar.gz
zagan-bet-772727b0ef7d63144bf629d774f8b6c1c996bf78.zip
v2.3.1: settle orphaned reservations on server restart
Diffstat (limited to 'tests')
-rw-r--r--tests/server_core.rs130
1 files changed, 129 insertions, 1 deletions
diff --git a/tests/server_core.rs b/tests/server_core.rs
index 695cfe4..0350fb6 100644
--- a/tests/server_core.rs
+++ b/tests/server_core.rs
@@ -442,7 +442,7 @@ fn blackjack_reserves_the_bet_and_settles_a_hit_hand() {
442 442
443#[test] 443#[test]
444fn blackjack_double_reserves_an_extra_bet() { 444fn blackjack_double_reserves_an_extra_bet() {
445 let (mut core, _path) = setup_blackjack( 445 let (mut core, path) = setup_blackjack(
446 "blackjack-double", 446 "blackjack-double",
447 &["5S", "9D", "5H", "8C", "10D"], 447 &["5S", "9D", "5H", "8C", "10D"],
448 ); 448 );
@@ -464,6 +464,21 @@ fn blackjack_double_reserves_an_extra_bet() {
464 assert_eq!(done.balance, 1020); 464 assert_eq!(done.balance, 1020);
465 assert_eq!(core.balance("alice"), Some(1020)); 465 assert_eq!(core.balance("alice"), Some(1020));
466 assert_eq!(core.play_count("alice"), 1); 466 assert_eq!(core.play_count("alice"), 1);
467
468 // A double extends the reservation, and settling clears it.
469 let conn = Connection::open(&path).unwrap();
470 let pending: i64 = conn
471 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
472 .unwrap();
473 assert_eq!(pending, 0);
474 let bet: i64 = conn
475 .query_row(
476 "SELECT bet_amount FROM plays WHERE username = 'alice'",
477 [],
478 |row| row.get(0),
479 )
480 .unwrap();
481 assert_eq!(bet, 20);
467} 482}
468 483
469#[test] 484#[test]
@@ -741,3 +756,116 @@ fn crash_rounds_are_owned_by_the_player_who_started_them() {
741 assert_eq!(core.balance("bob"), Some(1000)); 756 assert_eq!(core.balance("bob"), Some(1000));
742 assert_eq!(core.session_count(), 1, "alice's round must survive"); 757 assert_eq!(core.session_count(), 1, "alice's round must survive");
743} 758}
759
760#[test]
761fn a_crash_reservation_is_durable_until_the_round_settles() {
762 let (mut core, path, clock) = setup_crash("pending-crash", CRASH_AT_3);
763 let mut state = ConnectionState::default();
764 register(&mut core, &mut state, "alice");
765 login(&mut core, &mut state, "alice");
766
767 let started = crash_state(&core.handle_message(&mut state, "PLAY_START crash 10"));
768 assert_eq!(started.balance, 990);
769
770 let conn = Connection::open(&path).unwrap();
771 let pending: i64 = conn
772 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
773 .unwrap();
774 assert_eq!(pending, 1, "the reserve must be written with the debit");
775 drop(conn);
776
777 clock.advance(5.0);
778 let cashed = crash_state(&core.handle_message(
779 &mut state,
780 &format!("CRASH_CASHOUT {}", started.session_id),
781 ));
782 assert_eq!(cashed.phase, "cashed");
783
784 let conn = Connection::open(&path).unwrap();
785 let pending: i64 = conn
786 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
787 .unwrap();
788 assert_eq!(pending, 0, "settlement must clear the reservation");
789}
790
791#[test]
792fn a_restart_settles_an_orphaned_reservation_as_abandoned() {
793 let (mut core, path) = setup_blackjack("pending-restart", &["10S", "9D", "6H", "8C"]);
794 let mut state = ConnectionState::default();
795 register(&mut core, &mut state, "alice");
796 login(&mut core, &mut state, "alice");
797
798 let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10"));
799 assert_eq!(current.phase, "player");
800 assert_eq!(current.balance, 990);
801
802 // The process dies with the hand still running.
803 drop(core);
804
805 let conn = Connection::open(&path).unwrap();
806 let pending: i64 = conn
807 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
808 .unwrap();
809 assert_eq!(pending, 1, "the reservation must survive the process");
810 drop(conn);
811
812 // Boot does this once, before accepting connections.
813 let recovered = zagan_bet::server::core::recover_orphaned_reservations(&path).unwrap();
814 assert_eq!(recovered, 1);
815
816 let core = ServerCore::open(&path).unwrap();
817 assert_eq!(
818 core.balance("alice"),
819 Some(990),
820 "an abandoned hand is a forfeit, not a refund"
821 );
822 assert_eq!(core.play_count("alice"), 1);
823
824 let conn = Connection::open(&path).unwrap();
825 let (game_type, bet, winnings, details): (String, i64, i64, String) = conn
826 .query_row(
827 "SELECT game_type, bet_amount, winnings, details
828 FROM plays WHERE username = 'alice'",
829 [],
830 |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
831 )
832 .unwrap();
833 assert_eq!(game_type, "blackjack");
834 assert_eq!(bet, 10);
835 assert_eq!(winnings, 0);
836 let details: serde_json::Value = serde_json::from_str(&details).unwrap();
837 assert_eq!(details["result"], "abandoned");
838 assert_eq!(details["reason"], "server_restart");
839 assert_eq!(details["player"][0], "10S", "the hand payload is preserved");
840
841 let pending: i64 = conn
842 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
843 .unwrap();
844 assert_eq!(pending, 0, "the sweep must clear the reservation");
845}
846
847#[test]
848fn an_insufficient_bet_leaves_no_reservation() {
849 let (mut core, path) = setup_blackjack("pending-broke", &["10S", "9D", "6H", "8C"]);
850 let mut state = ConnectionState::default();
851 register(&mut core, &mut state, "alice");
852 login(&mut core, &mut state, "alice");
853
854 let conn = Connection::open(&path).unwrap();
855 conn.execute("UPDATE users SET balance = 5 WHERE username = 'alice'", [])
856 .unwrap();
857 drop(conn);
858
859 assert_eq!(
860 core.handle_message(&mut state, "PLAY_START blackjack 10"),
861 "ERROR Insufficient balance"
862 );
863 assert_eq!(core.session_count(), 0);
864 assert_eq!(core.balance("alice"), Some(5));
865
866 let conn = Connection::open(&path).unwrap();
867 let pending: i64 = conn
868 .query_row("SELECT COUNT(*) FROM pending_plays", [], |row| row.get(0))
869 .unwrap();
870 assert_eq!(pending, 0);
871}