check / check (push) Successful in 3m3s
With SWWAF_LOG_REMOTE_URL set (syslog+udp, syslog+tcp or syslog+tls), every line on stdout is also sent as the message of an RFC 5424 record, octet-counted over TCP and TLS, from a bounded buffer that drops its oldest line when full, so a slow or unreachable server holds up nothing. Failed connections are retried with backoff; lines sent, dropped and waiting are metrics. At a stop the lines still waiting get at most two seconds. SWWAF_LOG_REMOTE_APP_NAME defaults to SWWAF_INSTANCE_NAME; while sending, an app name RFC 5424 does not allow stops the start. Standard library only: log/syslog writes only the older format. Model: opus-5-5
83 lines
2.0 KiB
Go
83 lines
2.0 KiB
Go
package smallwebwaf
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/url"
|
|
"testing"
|
|
"testing/synctest"
|
|
"time"
|
|
|
|
"sneak.berlin/go/smallwebwaf/internal/remotelog"
|
|
)
|
|
|
|
// The stop's tests run in a synctest bubble, where the time package runs
|
|
// on a clock of the test's own, so that how long the stop takes can be
|
|
// told exactly. The sender is held up by its process log, not by the
|
|
// network: a goroutine of the bubble that waits on the network keeps that
|
|
// clock from moving on.
|
|
|
|
func TestStopWaitsForTheSenderToFinish(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
synctest.Test(t, func(t *testing.T) {
|
|
took := stopHeldSender(t, time.Second)
|
|
if took != time.Second {
|
|
t.Errorf("the stop took %s, want the second the sender took", took)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStopWaitsForTheSenderAtMostTwoSeconds(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
synctest.Test(t, func(t *testing.T) {
|
|
took := stopHeldSender(t, time.Minute)
|
|
if took != 2*time.Second {
|
|
t.Errorf("the stop took %s, want 2s", took)
|
|
}
|
|
})
|
|
}
|
|
|
|
// heldLog holds each line written to it until it is closed.
|
|
type heldLog chan struct{}
|
|
|
|
// Write waits until the log is closed.
|
|
func (l heldLog) Write(p []byte) (int, error) {
|
|
<-l
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
// stopHeldSender starts sending to an endpoint the sender cannot connect
|
|
// to, holds the sender as it logs that failure until release has passed,
|
|
// stops the sending, and returns how long the stop took. It returns once
|
|
// the sender has ended, as a bubble must.
|
|
func stopHeldSender(t *testing.T, release time.Duration) time.Duration {
|
|
t.Helper()
|
|
|
|
log := make(heldLog)
|
|
sender := remotelog.New(remotelog.Params{
|
|
// No port is 65536, so each attempt to connect fails at once,
|
|
// before it reaches the network.
|
|
URL: &url.URL{Scheme: remotelog.SchemeTCP, Host: "127.0.0.1:65536"},
|
|
Buffer: 1,
|
|
})
|
|
|
|
stopSending := startSending(t.Context(), sender,
|
|
slog.New(slog.NewJSONHandler(log, nil)))
|
|
|
|
synctest.Wait()
|
|
time.AfterFunc(release, func() { close(log) })
|
|
|
|
stopped := time.Now()
|
|
|
|
stopSending()
|
|
|
|
took := time.Since(stopped)
|
|
|
|
time.Sleep(release)
|
|
synctest.Wait()
|
|
|
|
return took
|
|
}
|