- Batches that fail go to /data/spool (SPOOL_MAX_MB, 1 GiB by default) and are sent again oldest first; retries no longer block the store loop and follow the shutdown context. - Docker and host logs wait for room in a full queue instead of being dropped; the Docker position only moves once a line is stored or spooled. - Reverse DNS no longer holds up the syslog listeners, with an LRU cache and a cap on concurrent lookups. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// slowDNS never answers before the context ends.
|
|
func slowDNS() *ReverseDNS {
|
|
d := NewReverseDNS(true, "")
|
|
d.r = &net.Resolver{PreferGo: true, Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
|
<-ctx.Done()
|
|
return nil, errors.New("timeout")
|
|
}}
|
|
return d
|
|
}
|
|
|
|
func TestResolveDoesNotBlock(t *testing.T) {
|
|
d := slowDNS()
|
|
got := make(chan string, 1)
|
|
start := time.Now()
|
|
d.Resolve("192.0.2.1", 50*time.Millisecond, func(name string) { got <- name })
|
|
if time.Since(start) > 20*time.Millisecond {
|
|
t.Fatal("Resolve waited for the DNS server")
|
|
}
|
|
if name := <-got; name != "" {
|
|
t.Errorf("name %q, want none", name)
|
|
}
|
|
|
|
// Not an IP address: the callback runs at once.
|
|
called := false
|
|
d.Resolve("router", time.Second, func(name string) { called = name == "" })
|
|
if !called {
|
|
t.Error("callback not called synchronously for a host name")
|
|
}
|
|
}
|
|
|
|
func TestReverseDNSLimits(t *testing.T) {
|
|
d := slowDNS()
|
|
// Lookups beyond the limit are not started (and not cached).
|
|
for i := 0; i < rdnsMaxLookups+10; i++ {
|
|
d.Lookup(net.IPv4(10, 0, byte(i>>8), byte(i)).String(), 0)
|
|
}
|
|
if n := d.lru.Len(); n != rdnsMaxLookups {
|
|
t.Errorf("%d entries, want %d", n, rdnsMaxLookups)
|
|
}
|
|
}
|
|
|
|
func TestReverseDNSEvictsLeastRecentlyUsed(t *testing.T) {
|
|
d := slowDNS()
|
|
done := make(chan struct{})
|
|
close(done)
|
|
add := func(ip string) {
|
|
e := &rdnsEntry{ip: ip, name: ip + ".lan", expires: time.Now().Add(time.Hour), done: done}
|
|
d.cache[ip] = d.lru.PushFront(e)
|
|
}
|
|
for i := 0; i < rdnsMaxEntries; i++ {
|
|
add(net.IPv4(10, 1, byte(i>>8), byte(i)).String())
|
|
}
|
|
first := net.IPv4(10, 1, 0, 0).String()
|
|
if name := d.Lookup(first, 0); name != first+".lan" { // now the most recent
|
|
t.Fatalf("cached name %q", name)
|
|
}
|
|
d.entry("192.0.2.9")
|
|
if d.lru.Len() != rdnsMaxEntries {
|
|
t.Errorf("%d entries, want %d", d.lru.Len(), rdnsMaxEntries)
|
|
}
|
|
if d.cache[first] == nil {
|
|
t.Error("recently used entry evicted")
|
|
}
|
|
if d.cache[net.IPv4(10, 1, 0, 1).String()] != nil {
|
|
t.Error("least recently used entry kept")
|
|
}
|
|
}
|