badguardhome/internal/home/authratelimiter_test.go
Eugene Burkov f603c21b55 Pull request: 2826 auth block
Merge in DNS/adguard-home from 2826-auth-block to master

Updates #2826.

Squashed commit of the following:

commit ae87360379270012869ad2bc4e528e07eb9af91e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:35:49 2021 +0300

    home: fix mistake

commit dfa2ab05e9a8e70ac1bec36c4eb8ef3b02283b92
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:31:53 2021 +0300

    home: imp code

commit ff4220d3c3d92ae604e92a0c5c274d9527350d99
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 15:14:20 2021 +0300

    home: imp authratelimiter

commit c73a407d8652d64957e35046dbae7168aa45202f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Apr 27 14:20:17 2021 +0300

    home: fix authratelimiter

commit 724db4380928b055f9995006cf421cbe9c5363e7
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Apr 23 12:15:48 2021 +0300

    home: introduce auth blocker
2021-04-27 18:56:32 +03:00

208 lines
3.6 KiB
Go

package home
import (
"net"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAuthRateLimiter_Cleanup(t *testing.T) {
const key = "some-key"
now := time.Now()
testCases := []struct {
name string
att failedAuth
wantExp bool
}{{
name: "expired",
att: failedAuth{
until: now.Add(-100 * time.Hour),
},
wantExp: true,
}, {
name: "nope_yet",
att: failedAuth{
until: now.Add(failedAuthTTL / 2),
},
wantExp: false,
}, {
name: "blocked",
att: failedAuth{
until: now.Add(100 * time.Hour),
},
wantExp: false,
}}
for _, tc := range testCases {
ab := &authRateLimiter{
failedAuths: map[string]failedAuth{
key: tc.att,
},
}
t.Run(tc.name, func(t *testing.T) {
ab.cleanupLocked(now)
if tc.wantExp {
assert.Empty(t, ab.failedAuths)
return
}
require.Len(t, ab.failedAuths, 1)
_, ok := ab.failedAuths[key]
require.True(t, ok)
})
}
}
func TestAuthRateLimiter_Check(t *testing.T) {
key := string(net.IP{127, 0, 0, 1})
const maxAtt = 1
now := time.Now()
testCases := []struct {
until time.Time
name string
num uint
wantExp bool
}{{
until: now.Add(-100 * time.Hour),
name: "expired",
num: 0,
wantExp: true,
}, {
until: now.Add(failedAuthTTL),
name: "not_blocked_but_tracked",
num: 0,
wantExp: true,
}, {
until: now,
name: "expired_but_stayed",
num: 2,
wantExp: true,
}, {
until: now.Add(100 * time.Hour),
name: "blocked",
num: 2,
wantExp: false,
}}
for _, tc := range testCases {
failedAuths := map[string]failedAuth{
key: {
num: tc.num,
until: tc.until,
},
}
ab := &authRateLimiter{
maxAttempts: maxAtt,
failedAuths: failedAuths,
}
t.Run(tc.name, func(t *testing.T) {
until := ab.check(key)
if tc.wantExp {
assert.LessOrEqual(t, until, time.Duration(0))
} else {
assert.Greater(t, until, time.Duration(0))
}
})
}
t.Run("non-existent", func(t *testing.T) {
ab := &authRateLimiter{
failedAuths: map[string]failedAuth{
key + "smthng": {},
},
}
until := ab.check(key)
assert.Zero(t, until)
})
}
func TestAuthRateLimiter_Inc(t *testing.T) {
ip := net.IP{127, 0, 0, 1}
key := string(ip)
now := time.Now()
const maxAtt = 2
const blockDur = 15 * time.Minute
testCases := []struct {
until time.Time
wantUntil time.Time
name string
num uint
wantNum uint
}{{
name: "only_inc",
until: now,
wantUntil: now,
num: maxAtt - 1,
wantNum: maxAtt,
}, {
name: "inc_and_block",
until: now,
wantUntil: now.Add(failedAuthTTL),
num: maxAtt,
wantNum: maxAtt + 1,
}}
for _, tc := range testCases {
failedAuths := map[string]failedAuth{
key: {
num: tc.num,
until: tc.until,
},
}
ab := &authRateLimiter{
blockDur: blockDur,
maxAttempts: maxAtt,
failedAuths: failedAuths,
}
t.Run(tc.name, func(t *testing.T) {
ab.inc(key)
a, ok := ab.failedAuths[key]
require.True(t, ok)
assert.Equal(t, tc.wantNum, a.num)
assert.LessOrEqual(t, tc.wantUntil.Unix(), a.until.Unix())
})
}
t.Run("non-existent", func(t *testing.T) {
ab := &authRateLimiter{
blockDur: blockDur,
maxAttempts: maxAtt,
failedAuths: map[string]failedAuth{},
}
ab.inc(key)
a, ok := ab.failedAuths[key]
require.True(t, ok)
assert.EqualValues(t, 1, a.num)
})
}
func TestAuthRateLimiter_Remove(t *testing.T) {
const key = "some-key"
failedAuths := map[string]failedAuth{
key: {},
}
ab := &authRateLimiter{
failedAuths: failedAuths,
}
ab.remove(key)
assert.Empty(t, ab.failedAuths)
}