Files
bworld/tests/handshake_test.ts
2026-09-25 00:08:01 -03:00

73 lines
2.8 KiB
TypeScript

import { assert, assertEquals } from "@std/assert";
import { PROTOCOL_VERSION } from "$/common/protocol.ts";
import { TICKS_PER_SECOND } from "$/common/constants.ts";
import { test_game } from "./helpers.ts";
Deno.test("a different protocol version is rejected before anything else", async () => {
const { game, take, send, closed } = await test_game("mods");
game.on_connect(1);
send(1, { type: "hello", name: "old", protocol: PROTOCOL_VERSION - 1 });
const [message] = take(1);
assertEquals(message.type, "rejected");
assert(message.reason.includes(`protocol ${PROTOCOL_VERSION}`), message.reason);
assert(closed.has(1));
game.on_connect(2);
send(2, { type: "hello", name: "ancient" });
assertEquals(take(2)[0].type, "rejected");
});
Deno.test("welcome lists what to download, and nothing happens until ready", async () => {
const { game, take, send, join } = await test_game("mods");
join(1, "alice");
take(1);
let joined = 0;
game.mods.after.player_join.for_mod("test").subscribe(() => joined++);
game.on_connect(2);
send(2, { type: "hello", name: "bob", protocol: PROTOCOL_VERSION });
const [welcome] = take(2);
assertEquals(welcome.type, "welcome");
assertEquals(welcome.mods.map((m: { id: string }) => m.id), ["bworld"]);
assert(welcome.atlas.png && welcome.atlas.sha256);
assert(!("players" in welcome) && !("changes" in welcome), "welcome shouldn't have world state");
// not in the world yet: others don't hear about bob, and bob can't act
send(2, { type: "chat", text: "am I here?" });
send(2, { type: "break_block", x: 0, y: 60, z: 0 });
assertEquals(take(1), []);
assertEquals(take(2), []);
assertEquals(joined, 0);
send(2, { type: "ready" });
const messages = take(2);
assertEquals(messages[0].type, "join");
assertEquals(messages[0].name, "bob");
assertEquals(messages[0].players.map((p: { name: string }) => p.name), ["alice"]);
assert(messages.some((m) => m.type === "container" && m.container === "inventory"));
assertEquals(joined, 1);
assert(take(1).some((m) => m.type === "player_join" && m.player.name === "bob"));
// a second ready or hello does nothing
send(2, { type: "ready" });
send(2, { type: "hello", name: "bob", protocol: PROTOCOL_VERSION });
assertEquals(take(2).filter((m) => m.type === "join" || m.type === "welcome"), []);
assertEquals(joined, 1);
});
Deno.test("clients that never get ready are dropped", async () => {
const { game, take, send, closed } = await test_game("mods");
game.on_connect(1);
send(1, { type: "hello", name: "slow", protocol: PROTOCOL_VERSION });
take(1);
for (let i = 0; i < 59 * TICKS_PER_SECOND; i++) game.tick();
assert(!closed.has(1), "dropped too early");
for (let i = 0; i < 2 * TICKS_PER_SECOND; i++) game.tick();
assert(closed.has(1));
assertEquals(take(1)[0].type, "rejected");
// too late now
send(1, { type: "ready" });
assertEquals(take(1), []);
});