aboutsummaryrefslogtreecommitdiff
path: root/hotline/server_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'hotline/server_test.go')
-rw-r--r--hotline/server_test.go42
1 files changed, 42 insertions, 0 deletions
diff --git a/hotline/server_test.go b/hotline/server_test.go
index a6c5e19..ebcd073 100644
--- a/hotline/server_test.go
+++ b/hotline/server_test.go
@@ -10,6 +10,7 @@ import (
"net"
"os"
"strings"
+ "sync"
"testing"
"time"
@@ -18,6 +19,7 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/charmap"
+ "golang.org/x/time/rate"
)
type mockReadWriter struct {
@@ -1036,3 +1038,43 @@ func TestServer_Shutdown_stopsListenAndServe(t *testing.T) {
t.Fatal("ListenAndServe did not return after Shutdown")
}
}
+
+func TestServer_Banner(t *testing.T) {
+ srv := &Server{}
+ assert.Nil(t, srv.Banner())
+
+ srv.SetBanner([]byte("banner-data"))
+ assert.Equal(t, []byte("banner-data"), srv.Banner())
+
+ // Concurrent reads and writes; run with -race.
+ var wg sync.WaitGroup
+ for range 4 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := range 100 {
+ srv.SetBanner([]byte{byte(i)})
+ _ = srv.Banner()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func TestServer_sweepRateLimiters(t *testing.T) {
+ srv := &Server{rateLimiters: make(map[string]*rateLimiterEntry)}
+
+ srv.rateLimiters["10.0.0.1"] = &rateLimiterEntry{
+ limiter: rate.NewLimiter(perIPRateLimit, 1),
+ lastSeen: time.Now().Add(-rateLimiterTTL - time.Minute), // stale
+ }
+ srv.rateLimiters["10.0.0.2"] = &rateLimiterEntry{
+ limiter: rate.NewLimiter(perIPRateLimit, 1),
+ lastSeen: time.Now(), // fresh
+ }
+
+ srv.sweepRateLimiters()
+
+ assert.NotContains(t, srv.rateLimiters, "10.0.0.1", "stale rate limiter should be evicted")
+ assert.Contains(t, srv.rateLimiters, "10.0.0.2", "fresh rate limiter should be retained")
+}