carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package activator
2
3import (
4 "net"
5 "os"
6 "path/filepath"
7 "strings"
8 "sync"
9 "testing"
10 "time"
11)
12
13func TestLogListenerTeesOneConnectionAndRefusesASecond(t *testing.T) {
14 dir, err := os.MkdirTemp("", "ll")
15 if err != nil {
16 t.Fatal(err)
17 }
18 t.Cleanup(func() { os.RemoveAll(dir) })
19 path := filepath.Join(dir, "h.run.sock")
20 var mu sync.Mutex
21 var lines []string
22 l, err := listenLogs(path, func(s string) { mu.Lock(); lines = append(lines, s); mu.Unlock() })
23 if err != nil {
24 t.Skipf("cannot bind here (%v); run with TMPDIR=/tmp/g outside the sandbox", err)
25 }
26 defer l.Close()
27 c, err := net.Dial("unix", path)
28 if err != nil {
29 t.Fatal(err)
30 }
31 if _, err := c.Write([]byte("hello\nworld\n")); err != nil {
32 t.Fatal(err)
33 }
34 c.Close()
35 deadline := time.Now().Add(2 * time.Second)
36 for {
37 mu.Lock()
38 n := len(lines)
39 mu.Unlock()
40 if n == 2 || time.Now().After(deadline) {
41 break
42 }
43 time.Sleep(10 * time.Millisecond)
44 }
45 mu.Lock()
46 got := strings.Join(lines, "|")
47 mu.Unlock()
48 if got != "hello|world" {
49 t.Fatalf("lines = %q", got)
50 }
51 // A second connection during the same invocation is closed unread.
52 c2, err := net.Dial("unix", path)
53 if err != nil {
54 t.Fatal(err)
55 }
56 c2.SetReadDeadline(time.Now().Add(time.Second))
57 buf := make([]byte, 1)
58 if _, err := c2.Read(buf); err == nil {
59 t.Fatal("second connection was not closed")
60 }
61 c2.Close()
62 if l.Exited() {
63 t.Error("EOF on the log connection must not mark the process exited")
64 }
65}
66
67// Close must shut the accepted connection and wait for the tee: a line
68// written after Close returns must not reach the sink, and the tee
69// goroutine must not outlive the listener.
70func TestLogListenerCloseShutsTheConnectionAndWaitsForTheTee(t *testing.T) {
71 t.Parallel()
72 dir, err := os.MkdirTemp("", "ll")
73 if err != nil {
74 t.Fatal(err)
75 }
76 t.Cleanup(func() { os.RemoveAll(dir) })
77 path := filepath.Join(dir, "h.run.sock")
78 var mu sync.Mutex
79 var lines []string
80 l, err := listenLogs(path, func(s string) { mu.Lock(); lines = append(lines, s); mu.Unlock() })
81 if err != nil {
82 t.Skipf("cannot bind here (%v); run with TMPDIR=/tmp/g outside the sandbox", err)
83 }
84 c, err := net.Dial("unix", path)
85 if err != nil {
86 t.Fatal(err)
87 }
88 defer c.Close()
89 if _, err := c.Write([]byte("before\n")); err != nil {
90 t.Fatal(err)
91 }
92 deadline := time.Now().Add(2 * time.Second)
93 for {
94 mu.Lock()
95 n := len(lines)
96 mu.Unlock()
97 if n == 1 || time.Now().After(deadline) {
98 break
99 }
100 time.Sleep(10 * time.Millisecond)
101 }
102 done := make(chan error, 1)
103 go func() { done <- l.Close() }()
104 select {
105 case err := <-done:
106 if err != nil {
107 t.Fatalf("Close: %v", err)
108 }
109 case <-time.After(2 * time.Second):
110 t.Fatal("Close blocked on the open connection instead of shutting it")
111 }
112 // The peer sees its end closed and a late line goes nowhere.
113 c.SetReadDeadline(time.Now().Add(time.Second))
114 if _, err := c.Read(make([]byte, 1)); err == nil {
115 t.Fatal("accepted connection still open after Close")
116 }
117 _, _ = c.Write([]byte("after\n"))
118 time.Sleep(50 * time.Millisecond)
119 mu.Lock()
120 got := strings.Join(lines, "|")
121 mu.Unlock()
122 if got != "before" {
123 t.Fatalf("lines after Close = %q, want only the line written before it", got)
124 }
125}
126