mirror of https://github.com/0xERR0R/blocky.git
build(tests): e2e integration tests with docker and testcontainers (#753)
This commit is contained in:
parent
d4813a6448
commit
fb0810f18d
|
@ -10,4 +10,5 @@ node_modules
|
|||
.gitignore
|
||||
*.md
|
||||
LICENSE
|
||||
vendor
|
||||
vendor
|
||||
e2e/
|
|
@ -0,0 +1,27 @@
|
|||
name: Run e2e tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
e2e-test:
|
||||
name: Build Docker image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
id: go
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Run e2e
|
||||
run: make e2e-test
|
|
@ -1,6 +1,7 @@
|
|||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
*.test
|
||||
/*.pem
|
||||
bin/
|
||||
dist/
|
||||
|
|
|
@ -77,3 +77,4 @@ issues:
|
|||
linters:
|
||||
- gochecknoglobals
|
||||
- dupl
|
||||
- gosec
|
||||
|
|
|
@ -76,4 +76,4 @@ ENV BLOCKY_CONFIG_FILE=/app/config.yml
|
|||
|
||||
ENTRYPOINT ["/app/blocky"]
|
||||
|
||||
HEALTHCHECK --interval=1m --timeout=3s CMD ["/app/blocky", "healthcheck"]
|
||||
HEALTHCHECK --start-period=1m --timeout=3s CMD ["/app/blocky", "healthcheck"]
|
||||
|
|
19
Makefile
19
Makefile
|
@ -1,4 +1,4 @@
|
|||
.PHONY: all clean build swagger test lint run fmt docker-build help
|
||||
.PHONY: all clean build swagger test e2e-test lint run fmt docker-build help
|
||||
.DEFAULT_GOAL:=help
|
||||
|
||||
VERSION?=$(shell git describe --always --tags)
|
||||
|
@ -54,11 +54,20 @@ ifdef BIN_AUTOCAB
|
|||
setcap 'cap_net_bind_service=+ep' $(GO_BUILD_OUTPUT)
|
||||
endif
|
||||
|
||||
test: ## run tests
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -v --coverprofile=coverage.txt --covermode=atomic -cover ./...
|
||||
test: ## run tests
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic -cover ./...
|
||||
|
||||
e2e-test: ## run e2e tests
|
||||
docker buildx build \
|
||||
--build-arg VERSION=blocky-e2e \
|
||||
--network=host \
|
||||
-o type=docker \
|
||||
-t blocky-e2e \
|
||||
.
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="e2e" ./...
|
||||
|
||||
race: ## run tests with race detector
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo --race ./...
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --race ./...
|
||||
|
||||
lint: ## run golangcli-lint checks
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1
|
||||
|
@ -81,4 +90,4 @@ docker-build: ## Build docker image
|
|||
.
|
||||
|
||||
help: ## Shows help
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var _ = Describe("Basic functional tests", func() {
|
||||
var blocky, moka testcontainers.Container
|
||||
var err error
|
||||
|
||||
Describe("Container start", func() {
|
||||
BeforeEach(func() {
|
||||
moka, err = createDNSMokkaContainer("moka1", `A google/NOERROR("A 1.2.3.4 123")`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(moka.Terminate)
|
||||
})
|
||||
When("Minimal configuration is provided", func() {
|
||||
BeforeEach(func() {
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("Should start and answer DNS queries", func() {
|
||||
msg := util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA))
|
||||
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 123, "1.2.3.4"))
|
||||
})
|
||||
It("should return 'healthy' container status (healthcheck)", func() {
|
||||
Eventually(func(g Gomega) string {
|
||||
state, err := blocky.State(context.Background())
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return state.Health.Status
|
||||
}, "2m", "1s").Should(Equal("healthy"))
|
||||
})
|
||||
})
|
||||
Context("http port configuration", func() {
|
||||
When("'httpPort' is not defined", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
|
||||
It("should not open http port", func() {
|
||||
host, port, err := getContainerHostPort(blocky, "4000/tcp")
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
_, err = http.Get(fmt.Sprintf("http://%s", net.JoinHostPort(host, port)))
|
||||
Expect(err).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
When("'httpPort' is defined", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"httpPort: 4000",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("should serve http content", func() {
|
||||
host, port, err := getContainerHostPort(blocky, "4000/tcp")
|
||||
Expect(err).Should(Succeed())
|
||||
url := fmt.Sprintf("http://%s", net.JoinHostPort(host, port))
|
||||
|
||||
By("serve static html content", func() {
|
||||
Eventually(http.Get).WithArguments(url).Should(HaveHTTPStatus(http.StatusOK))
|
||||
})
|
||||
By("serve pprof endpoint", func() {
|
||||
Eventually(http.Get).WithArguments(url + "/debug/").Should(HaveHTTPStatus(http.StatusOK))
|
||||
})
|
||||
By("prometheus endpoint should be disabled", func() {
|
||||
Eventually(http.Get).WithArguments(url + "/metrics").Should(HaveHTTPStatus(http.StatusNotFound))
|
||||
})
|
||||
By("serve DoH endpoint", func() {
|
||||
Eventually(http.Get).WithArguments(url +
|
||||
"/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB").Should(HaveHTTPStatus(http.StatusOK))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
|
@ -0,0 +1,117 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var _ = Describe("External lists and query blocking", func() {
|
||||
var blocky, httpServer, moka testcontainers.Container
|
||||
var err error
|
||||
BeforeEach(func() {
|
||||
moka, err = createDNSMokkaContainer("moka", `A google/NOERROR("A 1.2.3.4 123")`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(moka.Terminate)
|
||||
})
|
||||
Describe("List download on startup", func() {
|
||||
When("external blacklist ist not available", func() {
|
||||
Context("startStrategy = blocking", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka",
|
||||
"blocking:",
|
||||
" startStrategy: blocking",
|
||||
" blackLists:",
|
||||
" ads:",
|
||||
" - http://wrong.domain.url/list.txt",
|
||||
" clientGroupsBlock:",
|
||||
" default:",
|
||||
" - ads",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
|
||||
It("should start with warning in log work without errors", func() {
|
||||
|
||||
msg := util.NewMsgWithQuestion("google.com.", dns.Type(dns.TypeA))
|
||||
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("google.com.", dns.TypeA, 123, "1.2.3.4"))
|
||||
|
||||
Expect(getContainerLogs(blocky)).Should(ContainElement(ContainSubstring("error during file processing")))
|
||||
})
|
||||
})
|
||||
Context("startStrategy = failOnError", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka",
|
||||
"blocking:",
|
||||
" startStrategy: failOnError",
|
||||
" blackLists:",
|
||||
" ads:",
|
||||
" - http://wrong.domain.url/list.txt",
|
||||
" clientGroupsBlock:",
|
||||
" default:",
|
||||
" - ads",
|
||||
)
|
||||
|
||||
Expect(err).Should(HaveOccurred())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
|
||||
It("should fail to start", func() {
|
||||
Expect(blocky.IsRunning()).Should(BeFalse())
|
||||
|
||||
Expect(getContainerLogs(blocky)).
|
||||
Should(ContainElement(ContainSubstring("Error: can't start server: 1 error occurred")))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("Query blocking against external blacklists", func() {
|
||||
When("external blacklists are defined and available", func() {
|
||||
BeforeEach(func() {
|
||||
httpServer, err = createHTTPServerContainer("httpserver", tmpDir, "list.txt", "blockeddomain.com")
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(httpServer.Terminate)
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka",
|
||||
"blocking:",
|
||||
" blackLists:",
|
||||
" ads:",
|
||||
" - http://httpserver:8080/list.txt",
|
||||
" clientGroupsBlock:",
|
||||
" default:",
|
||||
" - ads",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("should download external list on startup and block queries", func() {
|
||||
msg := util.NewMsgWithQuestion("blockeddomain.com.", dns.Type(dns.TypeA))
|
||||
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("blockeddomain.com.", dns.TypeA, 6*60*60, "0.0.0.0"))
|
||||
|
||||
Expect(getContainerLogs(blocky)).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,252 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var NetworkName = fmt.Sprintf("blocky-e2e-network_%d", time.Now().Unix())
|
||||
|
||||
const (
|
||||
redisImage = "redis:7"
|
||||
postgresImage = "postgres:15"
|
||||
mariaDBImage = "mariadb:10"
|
||||
mokaImage = "ghcr.io/0xerr0r/dns-mokka:0.2.0"
|
||||
staticServerImage = "halverneus/static-file-server:latest"
|
||||
blockyImage = "blocky-e2e"
|
||||
)
|
||||
|
||||
func createDNSMokkaContainer(alias string, rules ...string) (testcontainers.Container, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
mokaRules := make(map[string]string)
|
||||
|
||||
for i, rule := range rules {
|
||||
mokaRules[fmt.Sprintf("MOKKA_RULE_%d", i)] = rule
|
||||
}
|
||||
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: mokaImage,
|
||||
Networks: []string{NetworkName},
|
||||
ExposedPorts: []string{"53/tcp", "53/udp"},
|
||||
NetworkAliases: map[string][]string{NetworkName: {alias}},
|
||||
WaitingFor: wait.ForExposedPort(),
|
||||
Env: mokaRules,
|
||||
}
|
||||
|
||||
return testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
}
|
||||
|
||||
func createHTTPServerContainer(alias string, tmpDir *helpertest.TmpFolder,
|
||||
filename string, lines ...string) (testcontainers.Container, error) {
|
||||
f1 := tmpDir.CreateStringFile(filename,
|
||||
lines...,
|
||||
)
|
||||
if f1.Error != nil {
|
||||
return nil, f1.Error
|
||||
}
|
||||
|
||||
const modeOwner = 700
|
||||
|
||||
ctx := context.Background()
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: staticServerImage,
|
||||
Networks: []string{NetworkName},
|
||||
NetworkAliases: map[string][]string{NetworkName: {alias}},
|
||||
|
||||
ExposedPorts: []string{"8080/tcp"},
|
||||
Env: map[string]string{"FOLDER": "/"},
|
||||
Files: []testcontainers.ContainerFile{
|
||||
{
|
||||
HostFilePath: f1.Path,
|
||||
ContainerFilePath: fmt.Sprintf("/%s", filename),
|
||||
FileMode: modeOwner,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
}
|
||||
|
||||
func createRedisContainer() (testcontainers.Container, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: redisImage,
|
||||
Networks: []string{NetworkName},
|
||||
ExposedPorts: []string{"6379/tcp"},
|
||||
NetworkAliases: map[string][]string{NetworkName: {"redis"}},
|
||||
WaitingFor: wait.ForExposedPort(),
|
||||
}
|
||||
|
||||
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
|
||||
return container, err
|
||||
}
|
||||
|
||||
func createPostgresContainer() (testcontainers.Container, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: postgresImage,
|
||||
Networks: []string{NetworkName},
|
||||
ExposedPorts: []string{"5432/tcp"},
|
||||
NetworkAliases: map[string][]string{NetworkName: {"postgres"}},
|
||||
Env: map[string]string{
|
||||
"POSTGRES_USER": "user",
|
||||
"POSTGRES_PASSWORD": "user",
|
||||
},
|
||||
WaitingFor: wait.ForExposedPort(),
|
||||
}
|
||||
|
||||
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
|
||||
return container, err
|
||||
}
|
||||
|
||||
func createMariaDBContainer() (testcontainers.Container, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: mariaDBImage,
|
||||
Networks: []string{NetworkName},
|
||||
ExposedPorts: []string{"3306/tcp"},
|
||||
NetworkAliases: map[string][]string{NetworkName: {"mariaDB"}},
|
||||
Env: map[string]string{
|
||||
"MARIADB_USER": "user",
|
||||
"MARIADB_PASSWORD": "user",
|
||||
"MARIADB_DATABASE": "user",
|
||||
"MARIADB_ROOT_PASSWORD": "user",
|
||||
},
|
||||
WaitingFor: wait.ForAll(wait.ForLog("ready for connections"), wait.ForExposedPort()),
|
||||
}
|
||||
|
||||
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
|
||||
return container, err
|
||||
}
|
||||
|
||||
func createBlockyContainer(tmpDir *helpertest.TmpFolder, lines ...string) (testcontainers.Container, error) {
|
||||
f1 := tmpDir.CreateStringFile("config1.yaml",
|
||||
lines...,
|
||||
)
|
||||
if f1.Error != nil {
|
||||
return nil, f1.Error
|
||||
}
|
||||
|
||||
const modeOwner = 700
|
||||
|
||||
ctx := context.Background()
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: blockyImage,
|
||||
Networks: []string{NetworkName},
|
||||
|
||||
ExposedPorts: []string{"53/tcp", "53/udp", "4000/tcp"},
|
||||
|
||||
Files: []testcontainers.ContainerFile{
|
||||
{
|
||||
HostFilePath: f1.Path,
|
||||
ContainerFilePath: "/app/config.yml",
|
||||
FileMode: modeOwner,
|
||||
},
|
||||
},
|
||||
WaitingFor: wait.NewExecStrategy([]string{"/app/blocky", "healthcheck"}),
|
||||
}
|
||||
|
||||
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// attach container log if error occurs
|
||||
if r, err := container.Logs(context.Background()); err == nil {
|
||||
if b, err := io.ReadAll(r); err == nil {
|
||||
ginkgo.AddReportEntry("blocky container log", string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return container, err
|
||||
}
|
||||
|
||||
func doDNSRequest(blocky testcontainers.Container, message *dns.Msg) (*dns.Msg, error) {
|
||||
const timeout = 5 * time.Second
|
||||
|
||||
c := &dns.Client{
|
||||
Net: "tcp",
|
||||
Timeout: timeout,
|
||||
}
|
||||
|
||||
host, port, err := getContainerHostPort(blocky, "53/tcp")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg, _, err := c.Exchange(message, net.JoinHostPort(host, port))
|
||||
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func getContainerHostPort(c testcontainers.Container, p nat.Port) (host string, port string, err error) {
|
||||
res, err := c.MappedPort(context.Background(), p)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
host, err = c.Host(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return host, res.Port(), err
|
||||
}
|
||||
|
||||
func getContainerLogs(c testcontainers.Container) (lines []string, err error) {
|
||||
if r, err := c.Logs(context.Background()); err == nil {
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if len(strings.TrimSpace(line)) > 0 {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/0xERR0R/blocky/helpertest"
|
||||
|
||||
"github.com/0xERR0R/blocky/log"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
func TestLists(t *testing.T) {
|
||||
log.Silence()
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "e2e Suite", Label("e2e"))
|
||||
}
|
||||
|
||||
var (
|
||||
network testcontainers.Network
|
||||
tmpDir *helpertest.TmpFolder
|
||||
)
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
var err error
|
||||
|
||||
network, err = testcontainers.GenericNetwork(context.Background(), testcontainers.GenericNetworkRequest{
|
||||
NetworkRequest: testcontainers.NetworkRequest{
|
||||
Name: NetworkName,
|
||||
CheckDuplicate: false,
|
||||
Attachable: true,
|
||||
},
|
||||
})
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
DeferCleanup(func() {
|
||||
err := network.Remove(context.Background())
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
|
||||
tmpDir = helpertest.NewTmpFolder("config")
|
||||
Expect(tmpDir.Error).Should(Succeed())
|
||||
DeferCleanup(tmpDir.Clean)
|
||||
})
|
|
@ -0,0 +1,134 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var _ = Describe("Metrics functional tests", func() {
|
||||
var blocky, moka, httpServer1, httpServer2 testcontainers.Container
|
||||
var err error
|
||||
var metricsURL string
|
||||
|
||||
Describe("Metrics", func() {
|
||||
BeforeEach(func() {
|
||||
moka, err = createDNSMokkaContainer("moka1", `A google/NOERROR("A 1.2.3.4 123")`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(moka.Terminate)
|
||||
|
||||
httpServer1, err = createHTTPServerContainer("httpserver1", tmpDir, "list1.txt", "domain1.com")
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(httpServer1.Terminate)
|
||||
|
||||
httpServer2, err = createHTTPServerContainer("httpserver2", tmpDir, "list2.txt", "domain1.com", "domain2", "domain3")
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(httpServer2.Terminate)
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"blocking:",
|
||||
" blackLists:",
|
||||
" group1:",
|
||||
" - http://httpserver1:8080/list1.txt",
|
||||
" group2:",
|
||||
" - http://httpserver2:8080/list2.txt",
|
||||
"httpPort: 4000",
|
||||
"prometheus:",
|
||||
" enable: true",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
|
||||
host, port, err := getContainerHostPort(blocky, "4000/tcp")
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
metricsURL = fmt.Sprintf("http://%s/metrics", net.JoinHostPort(host, port))
|
||||
})
|
||||
When("Blocky is started", func() {
|
||||
It("Should provide 'blocky_build_info' prometheus metrics", func() {
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement(ContainSubstring("blocky_build_info")))
|
||||
})
|
||||
|
||||
It("Should provide 'blocky_blocking_enabled' prometheus metrics", func() {
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_blocking_enabled 1"))
|
||||
})
|
||||
})
|
||||
|
||||
When("Some query results are cached", func() {
|
||||
BeforeEach(func() {
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_entry_count 0"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_hit_count 0"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_miss_count 0"))
|
||||
})
|
||||
|
||||
It("Should increment cache counts", func() {
|
||||
msg := util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA))
|
||||
|
||||
By("first query, should increment the cache miss count and the total count", func() {
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 123, "1.2.3.4"))
|
||||
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_entry_count 1"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_hit_count 0"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_miss_count 1"))
|
||||
})
|
||||
|
||||
By("Same query again, should increment the cache hit count", func() {
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 0, "1.2.3.4"))
|
||||
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_entry_count 1"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_hit_count 1"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_cache_miss_count 1"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("Lists are loaded", func() {
|
||||
It("Should expose list cache sizes per group as metrics", func() {
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_blacklist_cache{group=\"group1\"} 1"))
|
||||
Expect(fetchBlockyMetrics(metricsURL)).Should(ContainElement("blocky_blacklist_cache{group=\"group2\"} 3"))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func fetchBlockyMetrics(url string) ([]string, error) {
|
||||
var metrics []string
|
||||
|
||||
r, err := http.Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
scanner := bufio.NewScanner(r.Body)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "blocky_") {
|
||||
metrics = append(metrics, line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var _ = Describe("Query logs functional tests", func() {
|
||||
var blocky, moka, database testcontainers.Container
|
||||
var db *gorm.DB
|
||||
var err error
|
||||
|
||||
BeforeEach(func() {
|
||||
moka, err = createDNSMokkaContainer("moka1", `A google/NOERROR("A 1.2.3.4 123")`, `A unknown/NXDOMAIN()`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(moka.Terminate)
|
||||
})
|
||||
|
||||
Describe("Query logging into the mariaDB database", func() {
|
||||
BeforeEach(func() {
|
||||
|
||||
database, err = createMariaDBContainer()
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(database.Terminate)
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"queryLog:",
|
||||
" type: mysql",
|
||||
" target: user:user@tcp(mariaDB:3306)/user?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
|
||||
dbHost, dbPort, err := getContainerHostPort(database, "3306/tcp")
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
dsn := fmt.Sprintf("user:user@tcp(%s)/user?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
net.JoinHostPort(dbHost, dbPort))
|
||||
|
||||
// database might be slow on first start, retry here if necessary
|
||||
Eventually(gorm.Open, "10s", "1s").WithArguments(mysql.Open(dsn), &gorm.Config{}).Should(Not(BeNil()))
|
||||
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
Eventually(countEntries).WithArguments(db).Should(BeNumerically("==", 0))
|
||||
|
||||
})
|
||||
When("Some queries were performed", func() {
|
||||
It("Should store query log in the mariaDB database", func() {
|
||||
By("Performing 2 queries", func() {
|
||||
Expect(doDNSRequest(blocky, util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA)))).Should(Not(BeNil()))
|
||||
Expect(doDNSRequest(blocky, util.NewMsgWithQuestion("unknown.domain.", dns.Type(dns.TypeA)))).Should(Not(BeNil()))
|
||||
})
|
||||
|
||||
By("check entries count asynchronously, since blocky flushes log entries in bulk", func() {
|
||||
Eventually(countEntries, "60s", "1s").WithArguments(db).Should(BeNumerically("==", 2))
|
||||
})
|
||||
|
||||
By("check entry content", func() {
|
||||
entries, err := queryEntries(db)
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
Expect(entries).Should(HaveLen(2))
|
||||
|
||||
Expect(entries[0]).Should(SatisfyAll(
|
||||
HaveField("ResponseType", "RESOLVED"),
|
||||
HaveField("QuestionType", "A"),
|
||||
HaveField("QuestionName", "google.de"),
|
||||
HaveField("Answer", "A (1.2.3.4)"),
|
||||
HaveField("ResponseCode", "NOERROR"),
|
||||
))
|
||||
|
||||
Expect(entries[1]).Should(SatisfyAll(
|
||||
HaveField("ResponseType", "RESOLVED"),
|
||||
HaveField("QuestionType", "A"),
|
||||
HaveField("QuestionName", "unknown.domain"),
|
||||
HaveField("Answer", ""),
|
||||
HaveField("ResponseCode", "NXDOMAIN"),
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Query logging into the postgres database", func() {
|
||||
BeforeEach(func() {
|
||||
|
||||
database, err = createPostgresContainer()
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(database.Terminate)
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"queryLog:",
|
||||
" type: postgresql",
|
||||
" target: postgres://user:user@postgres:5432/user",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
|
||||
dbHost, dbPort, err := getContainerHostPort(database, "5432/tcp")
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
dsn := fmt.Sprintf("postgres://user:user@%s/user", net.JoinHostPort(dbHost, dbPort))
|
||||
|
||||
// database might be slow on first start, retry here if necessary
|
||||
Eventually(gorm.Open, "10s", "1s").WithArguments(postgres.Open(dsn), &gorm.Config{}).Should(Not(BeNil()))
|
||||
|
||||
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
Eventually(countEntries).WithArguments(db).Should(BeNumerically("==", 0))
|
||||
|
||||
})
|
||||
When("Some queries were performed", func() {
|
||||
msg := util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA))
|
||||
It("Should store query log in the postgres database", func() {
|
||||
By("Performing 2 queries", func() {
|
||||
Expect(doDNSRequest(blocky, msg)).Should(Not(BeNil()))
|
||||
Expect(doDNSRequest(blocky, msg)).Should(Not(BeNil()))
|
||||
})
|
||||
|
||||
By("check entries count asynchronously, since blocky flushes log entries in bulk", func() {
|
||||
Eventually(countEntries, "60s", "1s").WithArguments(db).Should(BeNumerically("==", 2))
|
||||
})
|
||||
|
||||
By("check entry content", func() {
|
||||
entries, err := queryEntries(db)
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
Expect(entries).Should(HaveLen(2))
|
||||
|
||||
Expect(entries[0]).Should(SatisfyAll(
|
||||
HaveField("ResponseType", "RESOLVED"),
|
||||
HaveField("QuestionType", "A"),
|
||||
HaveField("QuestionName", "google.de"),
|
||||
HaveField("Answer", "A (1.2.3.4)"),
|
||||
HaveField("ResponseCode", "NOERROR"),
|
||||
))
|
||||
|
||||
Expect(entries[1]).Should(SatisfyAll(
|
||||
HaveField("ResponseType", "CACHED"),
|
||||
HaveField("QuestionType", "A"),
|
||||
HaveField("QuestionName", "google.de"),
|
||||
HaveField("Answer", "A (1.2.3.4)"),
|
||||
HaveField("ResponseCode", "NOERROR"),
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
type logEntry struct {
|
||||
ResponseType string
|
||||
QuestionType string
|
||||
QuestionName string
|
||||
Answer string
|
||||
ResponseCode string
|
||||
}
|
||||
|
||||
func queryEntries(db *gorm.DB) ([]logEntry, error) {
|
||||
var entries []logEntry
|
||||
|
||||
return entries, db.Find(&entries).Order("request_ts DESC").Error
|
||||
}
|
||||
|
||||
func countEntries(db *gorm.DB) (int64, error) {
|
||||
var cnt int64
|
||||
|
||||
return cnt, db.Table("log_entries").Count(&cnt).Error
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var _ = Describe("Redis configuration tests", func() {
|
||||
var blocky1, blocky2, redisDB, moka testcontainers.Container
|
||||
var redisClient *redis.Client
|
||||
var err error
|
||||
|
||||
BeforeEach(func() {
|
||||
redisDB, err = createRedisContainer()
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(redisDB.Terminate)
|
||||
|
||||
dbHost, dbPort, err := getContainerHostPort(redisDB, "6379/tcp")
|
||||
Expect(err).Should(Succeed())
|
||||
|
||||
redisClient = redis.NewClient(&redis.Options{
|
||||
Addr: net.JoinHostPort(dbHost, dbPort),
|
||||
})
|
||||
|
||||
Expect(dbSize(redisClient)).Should(BeNumerically("==", 0))
|
||||
|
||||
moka, err = createDNSMokkaContainer("moka1", `A google/NOERROR("A 1.2.3.4 123")`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(func() {
|
||||
_ = moka.Terminate(context.Background())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Cache sharing between blocky instances", func() {
|
||||
When("Redis and 2 blocky instances are configured", func() {
|
||||
BeforeEach(func() {
|
||||
blocky1, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"redis:",
|
||||
" address: redis:6379",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky1.Terminate)
|
||||
|
||||
blocky2, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"redis:",
|
||||
" address: redis:6379",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky2.Terminate)
|
||||
})
|
||||
It("2nd instance of blocky should use cache from redis", func() {
|
||||
msg := util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA))
|
||||
By("Query first blocky instance, should store cache in redis", func() {
|
||||
Expect(doDNSRequest(blocky1, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 123, "1.2.3.4"))
|
||||
})
|
||||
|
||||
By("Check redis, must contain one cache entry", func() {
|
||||
Eventually(dbSize).WithArguments(redisClient).Should(BeNumerically("==", 1))
|
||||
})
|
||||
|
||||
By("Shutdown the upstream DNS server", func() {
|
||||
Expect(moka.Terminate(context.Background())).Should(Succeed())
|
||||
})
|
||||
|
||||
By("Query second blocky instance, should use cache from redis", func() {
|
||||
Expect(doDNSRequest(blocky2, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 0, "1.2.3.4"))
|
||||
})
|
||||
|
||||
By("No warnings/errors in log", func() {
|
||||
Expect(getContainerLogs(blocky1)).Should(BeEmpty())
|
||||
Expect(getContainerLogs(blocky2)).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Cache loading on startup", func() {
|
||||
When("Redis and 1 blocky instance are configured", func() {
|
||||
BeforeEach(func() {
|
||||
blocky1, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"redis:",
|
||||
" address: redis:6379",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky1.Terminate)
|
||||
})
|
||||
It("should load cache from redis after start", func() {
|
||||
msg := util.NewMsgWithQuestion("google.de.", dns.Type(dns.TypeA))
|
||||
By("Query first blocky instance, should store cache in redis\"", func() {
|
||||
Expect(doDNSRequest(blocky1, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 123, "1.2.3.4"))
|
||||
})
|
||||
|
||||
By("Check redis, must contain one cache entry", func() {
|
||||
Eventually(dbSize).WithArguments(redisClient).Should(BeNumerically("==", 1))
|
||||
})
|
||||
|
||||
By("start other instance of blocky now -> it should load the cache from redis", func() {
|
||||
blocky2, err = createBlockyContainer(tmpDir,
|
||||
"logLevel: warn",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"redis:",
|
||||
" address: redis:6379",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky2.Terminate)
|
||||
})
|
||||
|
||||
By("Shutdown the upstream DNS server", func() {
|
||||
Expect(moka.Terminate(context.Background())).Should(Succeed())
|
||||
})
|
||||
|
||||
By("Query second blocky instance", func() {
|
||||
Expect(doDNSRequest(blocky2, msg)).Should(BeDNSRecord("google.de.", dns.TypeA, 0, "1.2.3.4"))
|
||||
})
|
||||
|
||||
By("No warnings/errors in log", func() {
|
||||
Expect(getContainerLogs(blocky1)).Should(BeEmpty())
|
||||
Expect(getContainerLogs(blocky2)).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func dbSize(redisClient *redis.Client) (int64, error) {
|
||||
return redisClient.DBSize(context.Background()).Result()
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
"github.com/0xERR0R/blocky/util"
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var _ = Describe("Upstream resolver configuration tests", func() {
|
||||
var blocky testcontainers.Container
|
||||
var err error
|
||||
|
||||
Describe("'startVerifyUpstream' parameter handling", func() {
|
||||
When("'startVerifyUpstream' is false and upstream server is not reachable", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - 192.192.192.192",
|
||||
"startVerifyUpstream: false",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("should start even if upstream server is not reachable", func() {
|
||||
Expect(blocky.IsRunning()).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
When("'startVerifyUpstream' is true and upstream server is not reachable", func() {
|
||||
BeforeEach(func() {
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - 192.192.192.192",
|
||||
"startVerifyUpstream: true",
|
||||
)
|
||||
|
||||
Expect(err).Should(HaveOccurred())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("should not start", func() {
|
||||
Expect(blocky.IsRunning()).Should(BeFalse())
|
||||
Expect(getContainerLogs(blocky)).
|
||||
Should(ContainElement(ContainSubstring("unable to reach any DNS resolvers configured for resolver group default")))
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("'upstreamTimeout' parameter handling", func() {
|
||||
var moka testcontainers.Container
|
||||
BeforeEach(func() {
|
||||
moka, err = createDNSMokkaContainer("moka1",
|
||||
`A example.com/NOERROR("A 1.2.3.4 123")`,
|
||||
`A delay.com/delay(NOERROR("A 1.1.1.1 100"), "300ms")`)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(moka.Terminate)
|
||||
|
||||
blocky, err = createBlockyContainer(tmpDir,
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - moka1",
|
||||
"upstreamTimeout: 200ms",
|
||||
)
|
||||
|
||||
Expect(err).Should(Succeed())
|
||||
DeferCleanup(blocky.Terminate)
|
||||
})
|
||||
It("should consider the timeout parameter", func() {
|
||||
By("query without timeout", func() {
|
||||
msg := util.NewMsgWithQuestion("example.com.", dns.Type(dns.TypeA))
|
||||
|
||||
Expect(doDNSRequest(blocky, msg)).Should(BeDNSRecord("example.com.", dns.TypeA, 123, "1.2.3.4"))
|
||||
})
|
||||
|
||||
By("query with timeout", func() {
|
||||
msg := util.NewMsgWithQuestion("delay.com/.", dns.Type(dns.TypeA))
|
||||
|
||||
resp, err := doDNSRequest(blocky, msg)
|
||||
Expect(err).Should(Succeed())
|
||||
Expect(resp.Rcode).Should(Equal(dns.RcodeServerFailure))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
32
go.mod
32
go.mod
|
@ -35,13 +35,40 @@ require (
|
|||
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755
|
||||
)
|
||||
|
||||
require github.com/dosgo/zigtool v0.0.0-20210923085854-9c6fc1d62198
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/dosgo/zigtool v0.0.0-20210923085854-9c6fc1d62198
|
||||
github.com/testcontainers/testcontainers-go v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/containerd/containerd v1.6.8 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.17+incompatible // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/lib/pq v1.10.6 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/moby/sys/mount v0.3.3 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/runc v1.1.3 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect
|
||||
google.golang.org/grpc v1.47.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -55,7 +82,6 @@ require (
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
|
@ -86,7 +112,7 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/mattn/goveralls v0.0.11 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
|
|
@ -92,10 +92,16 @@ func (matcher *dnsRecordMatcher) matchSingle(rr dns.RR) (success bool, err error
|
|||
// Match checks the DNS record
|
||||
func (matcher *dnsRecordMatcher) Match(actual interface{}) (success bool, err error) {
|
||||
switch i := actual.(type) {
|
||||
case *dns.Msg:
|
||||
return matcher.Match(i.Answer)
|
||||
case dns.RR:
|
||||
return matcher.matchSingle(i)
|
||||
case []dns.RR:
|
||||
return matcher.matchSingle(i[0])
|
||||
if len(i) == 1 {
|
||||
return matcher.matchSingle(i[0])
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("DNSRecord matcher expects []dns.RR with len == 1")
|
||||
default:
|
||||
return false, fmt.Errorf("DNSRecord matcher expects an dns.RR or []dns.RR")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue