blob: 94de4ba30e42fa521c037b101946a39fa7b95ba2 (
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package net
import (
stdnet "net"
"testing"
"time"
"thehouseoficarus/internal/config"
)
// TestEnqueueAfterCloseDoesNotPanic: a broadcast racing Close() must drop
// the message, never panic on a send to the closed outbound queue.
func TestEnqueueAfterCloseDoesNotPanic(t *testing.T) {
conn := &testConn{}
sess := &Session{Conn: conn}
sess.StartWriter()
sess.Close()
defer func() {
if r := recover(); r != nil {
t.Fatalf("write after Close panicked: %v", r)
}
// Wait for the writer goroutine to drain and exit cleanly.
select {
case <-sess.writeDone:
case <-time.After(time.Second):
t.Fatal("writer goroutine never exited after close")
}
}()
for i := 0; i < 3; i++ {
sess.WriteLine("late broadcast")
}
}
// TestTelnetSessionUsesQueuedWriter: production telnet sessions must start
// the queued writer like the websocket transport, so slow clients get
// per-message write deadlines and can never block game code.
func TestTelnetSessionUsesQueuedWriter(t *testing.T) {
cfg := config.Default()
cfg.Telnet.Enabled = true
cfg.Telnet.Port = 0
s, err := NewServer(cfg)
if err != nil {
t.Fatal(err)
}
defer s.Shutdown()
observed := make(chan bool, 1)
s.handler = func(sess *Session, _ string) { observed <- sess.outbox != nil }
go s.serveTelnet()
conn, err := stdnet.Dial("tcp", s.telnetLn.Addr().String())
if err != nil {
t.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("hello\n"))
select {
case queued := <-observed:
if !queued {
t.Fatal("telnet session has no outbound queue; writes are synchronous and can stall the world")
}
case <-time.After(time.Second):
t.Fatal("session handler was not invoked")
}
}
|