aboutsummaryrefslogtreecommitdiff
path: root/internal/game/hardening_purge_session_reset_test.go
blob: c3462a6b0aae117911145d5a47b3e62145902a64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package game

// Regression (P0): a purged account must leave every one of its sessions in a
// safe protocol state. A queued-mode Close only drops the transport after the
// writer drains its outbox, so input already buffered in the connection can
// still be dispatched to the owner after the purge; a session left in the
// character menu with a nil account then dereferences sess.Account and kills
// the owner goroutine (and with it every session and all unsaved state).

import (
	"testing"

	"thehouseoficarus/internal/net"
)

func TestPurgeResetsEveryAccountSession(t *testing.T) {
	h := newHarness(t)
	h.seedAccount("alice")
	h.seedCharacter("alice", "alice")

	other := h.connectMenu("alice")
	purger := h.connectMenu("alice")

	h.g.RunOnOwner(func() { h.g.handlePurgeAccount(purger, "PURGE alice") })

	for name, sess := range map[string]*net.Session{"other": other, "purger": purger} {
		if got := sess.State(); got != net.StateAccountName {
			t.Errorf("%s session state = %v, want StateAccountName", name, got)
		}
		if sess.Account != nil {
			t.Errorf("%s session retained the purged account: %+v", name, sess.Account)
		}
	}

	// Input already buffered in either transport is still routed to the owner:
	// it must land on the account-name prompt instead of faulting.
	before := h.g.owner.panics.Load()
	h.g.RunOnOwner(func() {
		h.g.handleMenu(other, "c")
		h.g.handleMenu(other, "l")
		h.g.handlePurgeAccount(purger, "PURGE alice")
		h.g.handleNewCharName(purger, "bob")
	})
	if got := h.g.owner.panics.Load(); got != before {
		t.Fatalf("post-purge input panicked the owner (panic count %d -> %d)", before, got)
	}
	if got := other.State(); got != net.StateAccountName {
		t.Errorf("state = %v after post-purge input, want StateAccountName", got)
	}
}