summaryrefslogtreecommitdiffstats
path: root/tests/version.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-08 03:29:35 +0100
committersalmonik <salmonik@tuta.io>2026-11-08 03:29:35 +0100
commit058432130628d00764663ecf819a9adc6793768d (patch)
treed3f49f111fbfaa48647cca2600adcf9017af2d30 /tests/version.rs
parentweb: serve latest.php through PHP and refuse stray PHP files (diff)
downloadzagan-bet-058432130628d00764663ecf819a9adc6793768d.tar.gz
zagan-bet-058432130628d00764663ecf819a9adc6793768d.zip
v5.0.0: protocol v5 and the browser frontend
Protocol v5 replaces newline lines with bounded [u32 len][text] frames and REQ/RES/EVT envelopes. Requests carry correlation ids and the server replays the last 256 replies per connection, so a gateway retry cannot double-debit and a late reply cannot clobber a newer request. HELLO/PONG carry server time; crash rounds announce started_at and push coalesced 10 Hz ticks. Crash now commits sha256(seed) before a round and reveals the seed when it ends, so clients recompute the crash point. Adds the webd/ gateway: one blocking thread, one ClientCore and one pinned upstream TLS connection per session, an HttpOnly session cookie, takeover, and a 60-second grace window. The browser sends Command JSON and renders View JSON; it never speaks the game protocol or stores credentials. Adds the vanilla TypeScript browser app at /play/ (login, lobby, all four games, history, notices, crash verification), the nginx /play and /ws routes, and the headless DOM smoke test. webd and the app stay out of the TUI/GUI/server build graph. The client/server version moves to 5.0.0 in lockstep; v4 peers are refused at HELLO.
Diffstat (limited to 'tests/version.rs')
-rw-r--r--tests/version.rs57
1 files changed, 48 insertions, 9 deletions
diff --git a/tests/version.rs b/tests/version.rs
index af244db..31bc2b6 100644
--- a/tests/version.rs
+++ b/tests/version.rs
@@ -1,5 +1,6 @@
1use zagan_bet::version::{ 1use zagan_bet::version::{
2 compatible, hello_line, is_newer, parse_hello, Version, VERSION, 2 VERSION, Version, compatible, hello_line, is_newer, parse_hello, parse_pong, pong_line,
3 unix_time_ms,
3}; 4};
4 5
5#[test] 6#[test]
@@ -24,16 +25,16 @@ fn versions_parse_and_reject_nonsense() {
24 Version::parse("4.0.0-rc1").map(|v| (v.major, v.minor, v.patch)), 25 Version::parse("4.0.0-rc1").map(|v| (v.major, v.minor, v.patch)),
25 Some((4, 0, 0)) 26 Some((4, 0, 0))
26 ); 27 );
27 assert_eq!( 28 assert_eq!(Version::parse("4.0.0+build7").map(|v| v.patch), Some(0));
28 Version::parse("4.0.0+build7").map(|v| v.patch),
29 Some(0)
30 );
31 29
32 for bad in ["", "4", "4.0", "4.0.0.1", "x.0.0", "4.x.0", "4.0.0-"] { 30 for bad in ["", "4", "4.0", "4.0.0.1", "x.0.0", "4.x.0", "4.0.0-"] {
33 assert!(Version::parse(bad).is_none(), "{bad:?} should not parse"); 31 assert!(Version::parse(bad).is_none(), "{bad:?} should not parse");
34 } 32 }
35 33
36 assert!(Version::parse(VERSION).is_some(), "the build version must parse"); 34 assert!(
35 Version::parse(VERSION).is_some(),
36 "the build version must parse"
37 );
37} 38}
38 39
39#[test] 40#[test]
@@ -57,19 +58,45 @@ fn newer_versions_are_ordered_by_major_minor_patch() {
57 58
58#[test] 59#[test]
59fn the_hello_reply_round_trips() { 60fn the_hello_reply_round_trips() {
60 let line = hello_line("4.0.0", "4.1.2", "https://zagan.example/"); 61 let line = hello_line(
62 "4.0.0",
63 "4.1.2",
64 "https://zagan.example/",
65 1_700_000_000_123,
66 );
61 let reply = parse_hello(&line).expect("parse a generated reply"); 67 let reply = parse_hello(&line).expect("parse a generated reply");
62 68
63 assert_eq!(reply.version, "4.0.0"); 69 assert_eq!(reply.version, "4.0.0");
64 assert_eq!(reply.latest, "4.1.2"); 70 assert_eq!(reply.latest, "4.1.2");
65 assert_eq!(reply.url, "https://zagan.example/"); 71 assert_eq!(reply.url, "https://zagan.example/");
72 assert_eq!(reply.time, 1_700_000_000_123);
66 73
67 assert!(parse_hello("HELLO 4.0.0 url=https://x/").is_none(), "latest is required"); 74 assert!(
68 assert!(parse_hello("HELLO 4.0.0 latest=4.0.0").is_none(), "url is required"); 75 parse_hello("HELLO 4.0.0 url=https://x/ time=1").is_none(),
76 "latest is required"
77 );
78 assert!(
79 parse_hello("HELLO 4.0.0 latest=4.0.0 time=1").is_none(),
80 "url is required"
81 );
82 assert!(
83 parse_hello("HELLO 4.0.0 latest=4.0.0 url=https://x/").is_none(),
84 "time is required"
85 );
69 assert!(parse_hello("PONG").is_none()); 86 assert!(parse_hello("PONG").is_none());
70 assert!(parse_hello("HELLO").is_none()); 87 assert!(parse_hello("HELLO").is_none());
71} 88}
72 89
90#[test]
91fn pong_carries_the_server_time() {
92 let line = pong_line(1_700_000_000_456);
93 assert_eq!(line, "PONG 1700000000456");
94 assert_eq!(parse_pong(&line), Some(1_700_000_000_456));
95 assert!(parse_pong("PONG").is_none());
96 assert!(parse_pong("RES 1 PONG 1700000000456").is_none());
97 assert!(unix_time_ms() > 1_600_000_000_000);
98}
99
73/// The GUI is a client, so it must ship in lockstep with the TUI and server. 100/// The GUI is a client, so it must ship in lockstep with the TUI and server.
74/// Keep `gui/Cargo.toml` at the same version as the root package. 101/// Keep `gui/Cargo.toml` at the same version as the root package.
75#[test] 102#[test]
@@ -83,6 +110,18 @@ fn the_gui_member_uses_the_same_version() {
83 assert_eq!(gui_version, VERSION); 110 assert_eq!(gui_version, VERSION);
84} 111}
85 112
113/// The gateway is a frontend too; keep it in lockstep with the core.
114#[test]
115fn the_webd_member_uses_the_same_version() {
116 let manifest = include_str!("../webd/Cargo.toml");
117 let version = manifest
118 .lines()
119 .find_map(|line| line.trim().strip_prefix("version = "))
120 .expect("webd/Cargo.toml declares a version")
121 .trim_matches('"');
122 assert_eq!(version, VERSION);
123}
124
86/// egui's dependency tree must never enter the TUI or server build graph. 125/// egui's dependency tree must never enter the TUI or server build graph.
87/// The GUI is a workspace member that depends on this package, never the 126/// The GUI is a workspace member that depends on this package, never the
88/// other way round. 127/// other way round.