ratelimit_test.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package logging
  2. import (
  3. "bytes"
  4. "errors"
  5. "io"
  6. "log/slog"
  7. "net/netip"
  8. "strings"
  9. "testing"
  10. "time"
  11. "github.com/slackhq/nebula/ratelimit"
  12. )
  13. type fakeLimiter struct {
  14. denied uint64
  15. ok bool
  16. }
  17. func (f fakeLimiter) Allow() (uint64, bool) { return f.denied, f.ok }
  18. func TestRateLimited(t *testing.T) {
  19. var buf bytes.Buffer
  20. base := NewLogger(&buf)
  21. if l, ok := RateLimited(base, fakeLimiter{ok: false}); ok || l != nil {
  22. t.Fatalf("denied call: ok=%v logger=%v", ok, l)
  23. }
  24. if l, ok := RateLimited(base, fakeLimiter{ok: true}); !ok || l != base {
  25. t.Fatal("nothing denied should hand back the same logger")
  26. }
  27. if l, ok := RateLimited(base, nil); !ok || l != base {
  28. t.Fatal("a nil limiter should allow with the same logger")
  29. }
  30. l, ok := RateLimited(base, fakeLimiter{denied: 7, ok: true})
  31. if !ok {
  32. t.Fatal("allowed call denied")
  33. }
  34. l.Info("hello", "k", "v")
  35. if !strings.Contains(buf.String(), "suppressed=7") {
  36. t.Fatalf("want suppressed=7, got %q", buf.String())
  37. }
  38. }
  39. // The benchmarks compare a log line through slog directly against the same line behind RateLimited: logged with
  40. // nothing denied, denied, and logged after denials.
  41. var (
  42. benchErr = errors.New("sendto: no buffer space available")
  43. benchAddr = netip.MustParseAddrPort("192.0.2.1:4242")
  44. )
  45. func benchLogger() *slog.Logger {
  46. return NewLogger(io.Discard).With("localIndex", 1234, "remoteIndex", 5678)
  47. }
  48. func BenchmarkRateLimitedBaseline(b *testing.B) {
  49. lg := benchLogger()
  50. b.ReportAllocs()
  51. for i := 0; i < b.N; i++ {
  52. lg.Error("Failed to write outgoing packet", "error", benchErr, "udpAddr", benchAddr)
  53. }
  54. }
  55. func BenchmarkRateLimitedAllowed(b *testing.B) {
  56. lg, lim := benchLogger(), mustLimiter(b, 1, 0)
  57. b.ReportAllocs()
  58. for i := 0; i < b.N; i++ {
  59. if l, ok := RateLimited(lg, lim); ok {
  60. l.Error("Failed to write outgoing packet", "error", benchErr, "udpAddr", benchAddr)
  61. }
  62. }
  63. }
  64. func BenchmarkRateLimitedDenied(b *testing.B) {
  65. lg, lim := benchLogger(), mustLimiter(b, 1, time.Hour)
  66. lim.Allow()
  67. b.ReportAllocs()
  68. for i := 0; i < b.N; i++ {
  69. if l, ok := RateLimited(lg, lim); ok {
  70. l.Error("Failed to write outgoing packet", "error", benchErr, "udpAddr", benchAddr)
  71. }
  72. }
  73. }
  74. func BenchmarkRateLimitedAfterDenied(b *testing.B) {
  75. lg, lim := benchLogger(), fakeLimiter{denied: 5, ok: true}
  76. b.ReportAllocs()
  77. for i := 0; i < b.N; i++ {
  78. if l, ok := RateLimited(lg, lim); ok {
  79. l.Error("Failed to write outgoing packet", "error", benchErr, "udpAddr", benchAddr)
  80. }
  81. }
  82. }
  83. func mustLimiter(b *testing.B, burst int, every time.Duration) *ratelimit.Limiter {
  84. l, err := ratelimit.New(burst, every)
  85. if err != nil {
  86. b.Fatal(err)
  87. }
  88. return l
  89. }