bastion 0.56.0
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// One person cannot take every slot: past their own share they are told the
|
||||
// daemon is busy at once, while slots remain for everyone else. Before, one
|
||||
// user's idle connections, re-dialled as each deadline ran out, held all of
|
||||
// them and every other user's ask was refused.
|
||||
func TestOneUserCannotHoldEveryContextSockSlot(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("no unix-socket peer credentials on windows; contextsock_windows.go says why")
|
||||
}
|
||||
const share = 4 // contextSockMaxPerUser
|
||||
// A test before this one may still be releasing its slots.
|
||||
if n := contextSockSlotsHeld(t, 0); n != 0 {
|
||||
t.Fatalf("%d slots still held from an earlier test", n)
|
||||
}
|
||||
sock := filepath.Join(t.TempDir(), "s.sock")
|
||||
ln, err := net.Listen("unix", sock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
go contextSockAccept(ln)
|
||||
|
||||
var held []net.Conn
|
||||
defer func() {
|
||||
for _, h := range held {
|
||||
_ = h.Close()
|
||||
}
|
||||
}()
|
||||
for i := 0; i < share; i++ {
|
||||
h, err := net.Dial("unix", sock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
held = append(held, h)
|
||||
}
|
||||
// Wait until the daemon has given those four their slots (a fixed sleep
|
||||
// lost this race on a loaded machine and handed the 5th one first).
|
||||
if n := contextSockSlotsHeld(t, share); n != share {
|
||||
t.Fatalf("the daemon gave %d slots to %d idle connections of one user", n, share)
|
||||
}
|
||||
|
||||
extra, err := net.Dial("unix", sock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer extra.Close()
|
||||
_ = extra.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||
buf := make([]byte, 512)
|
||||
n, rerr := extra.Read(buf)
|
||||
if ne, ok := rerr.(net.Error); ok && ne.Timeout() {
|
||||
t.Fatalf("one user held %d idle connections and a %dth was still given a slot: "+
|
||||
"one user can take all %d", share, share+1, contextSockMaxInFlight)
|
||||
}
|
||||
if !strings.Contains(string(buf[:n]), "busy") {
|
||||
t.Fatalf("past one user's share the ask got %q; it must be told the daemon is busy", buf[:n])
|
||||
}
|
||||
}
|
||||
|
||||
// contextSockSlotsHeld waits up to 10 s for the per-user slots held across
|
||||
// all users to reach want, and returns the count it last saw.
|
||||
func contextSockSlotsHeld(t *testing.T, want int) int {
|
||||
t.Helper()
|
||||
n := -1
|
||||
for deadline := time.Now().Add(10 * time.Second); time.Now().Before(deadline); time.Sleep(10 * time.Millisecond) {
|
||||
contextSockUsers.Lock()
|
||||
n = 0
|
||||
for _, k := range contextSockUsers.held {
|
||||
n += k
|
||||
}
|
||||
contextSockUsers.Unlock()
|
||||
if n == want {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
Reference in New Issue
Block a user