blocky/resolver/strict_resolver_test.go

282 lines
7.7 KiB
Go

package resolver
import (
"context"
"time"
"github.com/0xERR0R/blocky/config"
. "github.com/0xERR0R/blocky/helpertest"
"github.com/0xERR0R/blocky/log"
. "github.com/0xERR0R/blocky/model"
"github.com/0xERR0R/blocky/util"
"github.com/miekg/dns"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("StrictResolver", Label("strictResolver"), func() {
const (
verifyUpstreams = true
noVerifyUpstreams = false
)
var (
sut *StrictResolver
upstreams []config.Upstream
sutVerify bool
err error
bootstrap *Bootstrap
ctx context.Context
cancelFn context.CancelFunc
timeout = 2 * time.Second
testUpstream1 *MockUDPUpstreamServer
testUpstream2 *MockUDPUpstreamServer
)
Describe("Type", func() {
It("follows conventions", func() {
expectValidResolverType(sut)
})
})
BeforeEach(func() {
ctx, cancelFn = context.WithCancel(context.Background())
DeferCleanup(cancelFn)
upstreams = []config.Upstream{
{Host: "wrong"},
{Host: "127.0.0.2"},
}
sutVerify = noVerifyUpstreams
bootstrap = systemResolverBootstrap
})
JustBeforeEach(func() {
upstreamsCfg := defaultUpstreamsConfig
upstreamsCfg.StartVerify = sutVerify
sutConfig := config.NewUpstreamGroup("test", upstreamsCfg, upstreams)
sutConfig.Timeout = config.Duration(timeout)
sut, err = NewStrictResolver(ctx, sutConfig, bootstrap)
})
Describe("IsEnabled", func() {
It("is true", func() {
Expect(sut.IsEnabled()).Should(BeTrue())
})
})
Describe("LogConfig", func() {
It("should log something", func() {
logger, hook := log.NewMockEntry()
sut.LogConfig(logger)
Expect(hook.Calls).ShouldNot(BeEmpty())
})
})
Describe("Type", func() {
It("should be correct", func() {
Expect(sut.Type()).ShouldNot(BeEmpty())
Expect(sut.Type()).Should(Equal(strictResolverType))
})
})
Describe("Name", func() {
It("should contain correct resolver", func() {
Expect(sut.Name()).ShouldNot(BeEmpty())
Expect(sut.Name()).Should(ContainSubstring(strictResolverType))
})
})
When("some default upstream resolvers cannot be reached", func() {
BeforeEach(func() {
mockUpstream := NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) {
response, _ = util.NewMsgWithAnswer(request.Question[0].Name, 123, A, "123.124.122.122")
return
})
DeferCleanup(mockUpstream.Close)
upstreams = []config.Upstream{
{Host: "wrong"},
mockUpstream.Start(),
}
})
It("should start normally", func() {
Expect(err).Should(Not(HaveOccurred()))
})
})
When("no upstream resolvers can be reached", func() {
BeforeEach(func() {
upstreams = []config.Upstream{
{Host: "wrong"},
{Host: "127.0.0.2"},
}
})
When("strict checking is enabled", func() {
BeforeEach(func() {
sutVerify = verifyUpstreams
})
It("should fail to start", func() {
Expect(err).Should(HaveOccurred())
})
})
When("strict checking is disabled", func() {
BeforeEach(func() {
sutVerify = noVerifyUpstreams
})
It("should start", func() {
Expect(err).Should(Not(HaveOccurred()))
})
})
})
Describe("Resolving request in strict order", func() {
When("2 Upstream resolvers are defined", func() {
When("Both are responding", func() {
When("they respond in time", func() {
BeforeEach(func() {
testUpstream1 = NewMockUDPUpstreamServer().WithAnswerRR("example.com 123 IN A 123.124.122.122")
DeferCleanup(testUpstream1.Close)
testUpstream2 = NewMockUDPUpstreamServer().WithAnswerRR("example.com 123 IN A 123.124.122.123")
DeferCleanup(testUpstream2.Close)
upstreams = []config.Upstream{testUpstream1.Start(), testUpstream2.Start()}
})
It("Should use result from first one", func() {
request := newRequest("example.com.", A)
Expect(sut.Resolve(ctx, request)).
Should(
SatisfyAll(
BeDNSRecord("example.com.", A, "123.124.122.122"),
HaveTTL(BeNumerically("==", 123)),
HaveResponseType(ResponseTypeRESOLVED),
HaveReturnCode(dns.RcodeSuccess),
))
})
})
When("first upstream exceeds upstreamTimeout", func() {
BeforeEach(func() {
testUpstream1 = NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) {
response, err := util.NewMsgWithAnswer("example.com", 123, A, "123.124.122.1")
time.Sleep(2 * timeout)
Expect(err).To(Succeed())
return response
})
DeferCleanup(testUpstream1.Close)
testUpstream2 = NewMockUDPUpstreamServer().WithAnswerRR("example.com 123 IN A 123.124.122.2")
DeferCleanup(testUpstream2.Close)
upstreams = []config.Upstream{testUpstream1.Start(), testUpstream2.Start()}
})
It("should return response from next upstream", func() {
request := newRequest("example.com", A)
Expect(sut.Resolve(ctx, request)).Should(
SatisfyAll(
BeDNSRecord("example.com.", A, "123.124.122.2"),
HaveTTL(BeNumerically("==", 123)),
HaveResponseType(ResponseTypeRESOLVED),
HaveReturnCode(dns.RcodeSuccess),
))
})
})
When("all upstreams exceed upsteamTimeout", func() {
JustBeforeEach(func() {
testUpstream1 = NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) {
response, err := util.NewMsgWithAnswer("example.com", 123, A, "123.124.122.1")
time.Sleep(2 * timeout)
Expect(err).To(Succeed())
return response
})
DeferCleanup(testUpstream1.Close)
testUpstream2 = NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) {
response, err := util.NewMsgWithAnswer("example.com", 123, A, "123.124.122.2")
time.Sleep(2 * timeout)
Expect(err).To(Succeed())
return response
})
DeferCleanup(testUpstream2.Close)
upstreams = []config.Upstream{testUpstream1.Start(), testUpstream2.Start()}
})
It("should return error", func() {
request := newRequest("example.com", A)
_, err := sut.Resolve(ctx, request)
Expect(err).To(HaveOccurred())
})
})
})
When("Only second is working", func() {
BeforeEach(func() {
testUpstream2 = NewMockUDPUpstreamServer().WithAnswerRR("example.com 123 IN A 123.124.122.123")
DeferCleanup(testUpstream2.Close)
upstreams = []config.Upstream{{Host: "wrong"}, testUpstream2.Start()}
})
It("Should use result from second one", func() {
request := newRequest("example.com.", A)
Expect(sut.Resolve(ctx, request)).
Should(
SatisfyAll(
BeDNSRecord("example.com.", A, "123.124.122.123"),
HaveTTL(BeNumerically("==", 123)),
HaveResponseType(ResponseTypeRESOLVED),
HaveReturnCode(dns.RcodeSuccess),
))
})
})
When("None are working", func() {
BeforeEach(func() {
upstreams = []config.Upstream{{Host: "wrong"}, {Host: "wrong"}}
Expect(err).Should(Succeed())
})
It("Should return error", func() {
request := newRequest("example.com.", A)
_, err = sut.Resolve(ctx, request)
Expect(err).Should(HaveOccurred())
})
})
})
When("only 1 upstream resolvers is defined", func() {
BeforeEach(func() {
mockUpstream := NewMockUDPUpstreamServer().WithAnswerRR("example.com 123 IN A 123.124.122.122")
DeferCleanup(mockUpstream.Close)
upstreams = []config.Upstream{mockUpstream.Start()}
})
It("Should use result from defined resolver", func() {
request := newRequest("example.com.", A)
Expect(sut.Resolve(ctx, request)).
Should(
SatisfyAll(
BeDNSRecord("example.com.", A, "123.124.122.122"),
HaveTTL(BeNumerically("==", 123)),
HaveResponseType(ResponseTypeRESOLVED),
HaveReturnCode(dns.RcodeSuccess),
))
})
})
})
})