mirror of
https://github.com/AdguardTeam/dnsproxy.git
synced 2026-10-12 02:01:26 +00:00
263 lines
7.3 KiB
Go
263 lines
7.3 KiB
Go
package proxy_test
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/AdguardTeam/dnsproxy/dnsproxytest"
|
|
proxytest "github.com/AdguardTeam/dnsproxy/internal/dnsproxytest"
|
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
|
"github.com/AdguardTeam/dnsproxy/upstream"
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/testutil"
|
|
"github.com/miekg/dns"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestDNSContext_QueryStatistics(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testReq := &dns.Msg{
|
|
Question: []dns.Question{{
|
|
Name: "test.",
|
|
Qtype: dns.TypeA,
|
|
Qclass: dns.ClassINET,
|
|
}},
|
|
}
|
|
|
|
ups := &dnsproxytest.Upstream{
|
|
OnExchange: func(req *dns.Msg) (resp *dns.Msg, err error) {
|
|
return (&dns.Msg{}).SetReply(req), nil
|
|
},
|
|
OnAddress: func() (addr string) { return "upstream" },
|
|
OnClose: func() (err error) { return nil },
|
|
}
|
|
|
|
failUps := &dnsproxytest.Upstream{
|
|
OnExchange: func(req *dns.Msg) (resp *dns.Msg, err error) {
|
|
return nil, errors.Error("exchange error")
|
|
},
|
|
OnAddress: func() (addr string) { return "fail.upstream" },
|
|
OnClose: func() (err error) { return nil },
|
|
}
|
|
|
|
conf := &proxy.Config{
|
|
Logger: testLogger,
|
|
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
|
|
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
|
|
TrustedProxies: proxytest.DefaultTrustedProxies,
|
|
}
|
|
|
|
testCases := []struct {
|
|
wantErr assert.ErrorAssertionFunc
|
|
wantMainErr assert.BoolAssertionFunc
|
|
wantFallbackErr assert.BoolAssertionFunc
|
|
config *proxy.UpstreamConfig
|
|
fallbackConfig *proxy.UpstreamConfig
|
|
name string
|
|
mode proxy.UpstreamMode
|
|
wantMainCount int
|
|
wantFallbackCount int
|
|
}{{
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.False,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "load_balance_success",
|
|
mode: proxy.UpstreamModeLoadBalance,
|
|
wantMainCount: 1,
|
|
wantFallbackCount: 0,
|
|
}, {
|
|
wantErr: assert.Error,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.True,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps},
|
|
},
|
|
name: "load_balance_bad",
|
|
mode: proxy.UpstreamModeLoadBalance,
|
|
wantMainCount: 1,
|
|
wantFallbackCount: 2,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.False,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups, failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "parallel_success",
|
|
mode: proxy.UpstreamModeParallel,
|
|
wantMainCount: 1,
|
|
wantFallbackCount: 0,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "parallel_bad_fallback_success",
|
|
mode: proxy.UpstreamModeParallel,
|
|
wantMainCount: 1,
|
|
wantFallbackCount: 1,
|
|
}, {
|
|
wantErr: assert.Error,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.True,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps, failUps},
|
|
},
|
|
name: "parallel_bad",
|
|
mode: proxy.UpstreamModeParallel,
|
|
wantMainCount: 2,
|
|
wantFallbackCount: 3,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.False,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "fastest_single_success",
|
|
mode: proxy.UpstreamModeFastestAddr,
|
|
wantMainCount: 1,
|
|
wantFallbackCount: 0,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.False,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups, ups},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "fastest_multiple_success",
|
|
mode: proxy.UpstreamModeFastestAddr,
|
|
wantMainCount: 2,
|
|
wantFallbackCount: 0,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups, failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "fastest_mixed_success",
|
|
mode: proxy.UpstreamModeFastestAddr,
|
|
wantMainCount: 2,
|
|
wantFallbackCount: 0,
|
|
}, {
|
|
wantErr: assert.Error,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.True,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps, failUps},
|
|
},
|
|
name: "fastest_multiple_bad",
|
|
mode: proxy.UpstreamModeFastestAddr,
|
|
wantMainCount: 2,
|
|
wantFallbackCount: 3,
|
|
}, {
|
|
wantErr: assert.NoError,
|
|
wantMainErr: assert.True,
|
|
wantFallbackErr: assert.False,
|
|
config: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{failUps, failUps},
|
|
},
|
|
fallbackConfig: &proxy.UpstreamConfig{
|
|
Upstreams: []upstream.Upstream{ups},
|
|
},
|
|
name: "fastest_bad_fallback_success",
|
|
mode: proxy.UpstreamModeFastestAddr,
|
|
wantMainCount: 2,
|
|
wantFallbackCount: 1,
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
conf.UpstreamConfig = tc.config
|
|
conf.Fallbacks = tc.fallbackConfig
|
|
conf.UpstreamMode = tc.mode
|
|
|
|
p, err := proxy.New(conf)
|
|
require.NoError(t, err)
|
|
|
|
d := &proxy.DNSContext{Req: testReq}
|
|
|
|
err = p.Resolve(testutil.ContextWithTimeout(t, defaultTimeout), d)
|
|
tc.wantErr(t, err)
|
|
|
|
stats := d.QueryStatistics()
|
|
assertQueryStats(
|
|
t,
|
|
stats,
|
|
tc.wantMainCount,
|
|
tc.wantMainErr,
|
|
tc.wantFallbackCount,
|
|
tc.wantFallbackErr,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// assertQueryStats asserts the statistics using the provided parameters.
|
|
func assertQueryStats(
|
|
tb testing.TB,
|
|
stats *proxy.QueryStatistics,
|
|
wantMainCount int,
|
|
wantMainErr assert.BoolAssertionFunc,
|
|
wantFallbackCount int,
|
|
wantFallbackErr assert.BoolAssertionFunc,
|
|
) {
|
|
tb.Helper()
|
|
|
|
main := stats.Main()
|
|
assert.Lenf(tb, main, wantMainCount, "main stats count")
|
|
|
|
fallback := stats.Fallback()
|
|
assert.Lenf(tb, fallback, wantFallbackCount, "fallback stats count")
|
|
|
|
wantMainErr(tb, isErrorInStats(main), "main err")
|
|
wantFallbackErr(tb, isErrorInStats(fallback), "fallback err")
|
|
}
|
|
|
|
// isErrorInStats is a helper function for tests that returns true if the
|
|
// upstream statistics contain an DNS lookup error.
|
|
func isErrorInStats(stats []*proxy.UpstreamStatistics) (ok bool) {
|
|
for _, u := range stats {
|
|
if u.Error != nil {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|