package streamcap
import (
"net/http/httptest"
"testing"
)
// One address may hold only its share; the next is refused until one
// of its streams ends.
func TestAnAddressIsCappedAndGetsItsSlotBack(t *testing.T) {
l := New(2, 10)
r1, ok1 := l.Acquire("a")
_, ok2 := l.Acquire("a")
if !ok1 || !ok2 {
t.Fatal("FAIL: an address was refused below its cap")
}
if _, ok := l.Acquire("a"); ok {
t.Fatal("FAIL: an address was admitted past its cap")
}
if _, ok := l.Acquire("b"); !ok {
t.Fatal("FAIL: a second address was refused for the first one's streams")
}
r1()
if _, ok := l.Acquire("a"); !ok {
t.Fatal("FAIL: an ended stream did not give its address the slot back")
}
t.Log("ok: per-address cap refuses at N+1 and releases")
}
// The total holds however many addresses the streams come from.
func TestTheTotalHoldsAcrossAddresses(t *testing.T) {
l := New(5, 3)
var releases []func()
for _, a := range []string{"a", "b", "c"} {
r, ok := l.Acquire(a)
if !ok {
t.Fatalf("FAIL: %s refused below the total", a)
}
releases = append(releases, r)
}
if _, ok := l.Acquire("d"); ok {
t.Fatal("FAIL: a fourth address was admitted past the total")
}
releases[0]()
releases[0]() // a second release must not free a slot it does not hold
if _, ok := l.Acquire("d"); !ok {
t.Fatal("FAIL: an ended stream did not return its slot to the total")
}
if _, ok := l.Acquire("e"); ok {
t.Fatal("FAIL: releasing twice freed two slots")
}
t.Log("ok: total cap holds across addresses; release is idempotent")
}
// The address is the host alone: two connections from one machine
// differ only by port and must count as one reader.
func TestTheAddressIsTheHostWithoutItsPort(t *testing.T) {
a := httptest.NewRequest("GET", "/", nil)
a.RemoteAddr = "203.0.113.9:5000"
b := httptest.NewRequest("GET", "/", nil)
b.RemoteAddr = "203.0.113.9:6000"
if Addr(a) != Addr(b) {
t.Fatalf("FAIL: one host read as two addresses: %q %q", Addr(a), Addr(b))
}
t.Log("ok: ports do not split an address")
}
// Behind the forge's TLS proxy every socket is the proxy's, so readers
// are told apart by the address the proxy forwards. Without that, the
// per-address cap would be one cap for every anonymous reader at once.
func TestReadersBehindTheProxyAreToldApart(t *testing.T) {
a := httptest.NewRequest("GET", "/", nil)
a.RemoteAddr = "127.0.0.1:5000"
a.Header.Set("X-Forwarded-For", "198.51.100.1")
b := httptest.NewRequest("GET", "/", nil)
b.RemoteAddr = "127.0.0.1:5001"
b.Header.Set("X-Forwarded-For", "198.51.100.2")
if Addr(a) == Addr(b) {
t.Fatalf("FAIL: two readers behind the proxy read as one address %q", Addr(a))
}
t.Log("ok: the forwarded address tells readers apart")
}