From 8ece708fe9d34b761c64ad70ad5e58d297b2cdcb Mon Sep 17 00:00:00 2001 From: Kwitsch Date: Sat, 11 Nov 2023 17:58:31 +0100 Subject: [PATCH] devcontainer & unit test refactoring (#1220) * extension cleanup & added ginkgo watch * added gcov2lcov * added test explorer and reworked scripts * go mod tidy * use package cache volume * script rework * defined tasks * defined launch * don't try to convert if test was canceld * generate lcov only in devcontainer * disable coverage upload on forks * wip: make lcov * fixed unit tests for parallel * parallel test for lists * fix serve test for parallel * parallel test fixes * deleted accident commit * wip: make lcov * restructured settings location * start script refactoring * added GetProcessPort * fixed parallel ports * race fix * changed port for github runner binding * fixed local list var in test * more local vars in tests fix * less local vars * run test & race parallel * removed invalid error check * fixed error check * less local variables * fixed timing problem * removed gcov2lcov * added generate-lcov * added GINKGO_PROCS to makefile * fixed workflow * run generate-lcov on save *.go * added tooltitude --- .devcontainer/devcontainer.json | 54 +++------ .devcontainer/scripts/generate-lcov.sh | 5 + .devcontainer/scripts/postStart.sh | 27 +++++ .github/workflows/makefile.yml | 11 +- .gitignore | 7 +- .vscode/launch.json | 12 ++ .vscode/settings.json | 31 +++++ .vscode/tasks.json | 74 ++++++++++++ Makefile | 6 +- .../stringcache/chained_grouped_cache_test.go | 49 +++++--- .../in_memory_grouped_cache_test.go | 78 +++++++----- cache/stringcache/string_caches_test.go | 38 +++--- cmd/healthcheck_test.go | 12 +- cmd/lists_test.go | 25 ++-- cmd/serve_test.go | 26 ++-- helpertest/helper.go | 15 +++ lists/list_cache_test.go | 58 +++++---- resolver/hosts_file_resolver_test.go | 26 ++-- resolver/parallel_best_resolver_test.go | 9 +- resolver/strict_resolver_test.go | 8 +- server/server_test.go | 111 +++++++++++------- 21 files changed, 452 insertions(+), 230 deletions(-) create mode 100644 .devcontainer/scripts/generate-lcov.sh create mode 100644 .devcontainer/scripts/postStart.sh create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 72a27de5..51a6be18 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,47 +9,29 @@ }, "ghcr.io/devcontainers/features/python:1": {} }, + "remoteEnv": { + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}", + "WORKSPACE_FOLDER": "${containerWorkspaceFolder}", + "GENERATE_LCOV": "true" + }, "customizations": { "vscode": { "extensions": [ - "golang.go", - "ms-vscode.makefile-tools", - "usernamehw.errorlens", - "esbenp.prettier-vscode", - "yzhang.markdown-all-in-one" - ], + "golang.go", + "esbenp.prettier-vscode", + "yzhang.markdown-all-in-one", + "joselitofilho.ginkgotestexplorer", + "fsevenm.run-it-on", + "markis.code-coverage", + "tooltitudeteam.tooltitude" + ], "settings": { - "editor.tabSize": 2, - "editor.insertSpaces": true, - "editor.detectIndentation": false, - "editor.formatOnSave": true, - "go.showWelcome": false, - "go.survey.prompt": false, - "go.useLanguageServer": true, - "go.formatTool": "gofumpt", - "go.lintTool": "golangci-lint", - "go.lintOnSave": "file", + "go.lintFlags": ["--config=${containerWorkspaceFolder}/.golangci.yml"], "go.alternateTools": { "go-langserver": "gopls" }, - "gopls": { - "ui.semanticTokens": true, - "formatting.gofumpt": true, - "build.standaloneTags": ["ignore", "tools"] - }, - "errorLens.excludePatterns": ["go.{mod,sum}", "tools.go"], "[go]": { - "editor.defaultFormatter": "golang.go", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true - } - }, - "[go.mod]": { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true - } + "editor.defaultFormatter": "golang.go" }, "[json][jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode" @@ -71,7 +53,9 @@ }, "mounts": [ "type=bind,readonly,source=/etc/localtime,target=/usr/share/host/localtime", - "type=bind,readonly,source=/etc/timezone,target=/usr/share/host/timezone" + "type=bind,readonly,source=/etc/timezone,target=/usr/share/host/timezone", + "type=volume,source=blocky-pkg_cache,target=/go/pkg" ], - "postStartCommand": "sudo sh -c \"ln -sf /usr/share/host/localtime /etc/localtime && ln -sf /usr/share/host/timezone /etc/timezone\"" + "postCreateCommand": "sudo chmod +x .devcontainer/scripts/*.sh", + "postStartCommand": "sh .devcontainer/scripts/postStart.sh" } diff --git a/.devcontainer/scripts/generate-lcov.sh b/.devcontainer/scripts/generate-lcov.sh new file mode 100644 index 00000000..7e7675ef --- /dev/null +++ b/.devcontainer/scripts/generate-lcov.sh @@ -0,0 +1,5 @@ +#!/bin/bash -e + +cd "${WORKSPACE_FOLDER}" + +nohup bash -c 'ginkgo --label-filter="!e2e" --no-color --keep-going --timeout=5m --coverprofile=lcov.work --covermode=set --cover -r -p && gcov2lcov -infile=coverage.txt -outfile=lcov.info' > lcov.log 2>&1 \ No newline at end of file diff --git a/.devcontainer/scripts/postStart.sh b/.devcontainer/scripts/postStart.sh new file mode 100644 index 00000000..cdca35b3 --- /dev/null +++ b/.devcontainer/scripts/postStart.sh @@ -0,0 +1,27 @@ +#!/bin/bash -e + +echo "Setting up go environment..." +# Use the host's timezone and time +sudo ln -sf /usr/share/host/localtime /etc/localtime +sudo ln -sf /usr/share/host/timezone /etc/timezone +# Change permission on pkg volume +sudo chown -R vscode:golang /go/pkg +echo "" + +echo "Downloading Go modules..." +go mod download -x +echo "" + +echo "Tidying Go modules..." +go mod tidy -x +echo "" + +echo "Installing Go tools..." +echo " - ginkgo" +go install github.com/onsi/ginkgo/v2/ginkgo@latest +echo " - golangci-lint" +go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest +echo " - gofumpt" +go install mvdan.cc/gofumpt@latest +echo " - gcov2lcov" +go install github.com/jandelgado/gcov2lcov@latest \ No newline at end of file diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 7a5ec02b..f7d078a3 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -9,10 +9,13 @@ permissions: actions: read contents: read -concurrency: +concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + GINKGO_PROCS: --procs=1 + jobs: make: name: make @@ -58,16 +61,16 @@ jobs: - name: make ${{ matrix.make }} run: make ${{ matrix.make }} - if: matrix.make != 'goreleaser' + if: matrix.make != 'goreleaser' env: GO_SKIP_GENERATE: 1 - name: Upload results to codecov uses: codecov/codecov-action@v3 - if: matrix.make == 'test' + if: matrix.make == 'test' && github.repository_owner == '0xERR0R' - name: Check GoReleaser configuration uses: goreleaser/goreleaser-action@v5 - if: matrix.make == 'goreleaser' + if: matrix.make == 'goreleaser' with: args: check diff --git a/.gitignore b/.gitignore index 0d27db6d..df8b9c97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .idea/ -.vscode/ *.iml *.test /*.pem @@ -8,10 +7,10 @@ dist/ docs/docs.go site/ config.yml -coverage.txt todo.txt !docs/config.yml node_modules package-lock.json -.vscode/ -vendor/ \ No newline at end of file +vendor/ +coverage.txt +lcov.* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ad462591 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..1f22d135 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,31 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true, + "source.fixAll": true + }, + "go.showWelcome": false, + "go.survey.prompt": false, + "go.useLanguageServer": true, + "go.formatTool": "gofumpt", + "go.lintTool": "golangci-lint", + "go.lintOnSave": "workspace", + "gopls": { + "ui.semanticTokens": true, + "formatting.gofumpt": true, + "build.standaloneTags": ["ignore", "tools"] + }, + "runItOn": { + "commands": [ + { + "match": "\\.go$", + "cmd": "./.devcontainer/scripts/generate-lcov.sh", + "silent": true + } + ] + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..3e124638 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,74 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Test", + "type": "shell", + "command": "make test", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always" + } + }, + { + "label": "Race", + "type": "shell", + "command": "make race", + "group": { + "kind": "test", + "isDefault": false + }, + "presentation": { + "reveal": "always" + } + }, + { + "label": "e2e - Test", + "type": "shell", + "command": "make e2e-test", + "group": { + "kind": "test", + "isDefault": false + }, + "presentation": { + "reveal": "always" + } + }, + { + "label": "Build", + "type": "shell", + "command": "make build", + "group": { + "group": { + "kind": "build", + "isDefault": true + }, + "isDefault": true + }, + "presentation": { + "reveal": "always" + } + }, + { + "label": "FMT", + "type": "shell", + "command": "make fmt", + "group": "none", + "presentation": { + "reveal": "always" + } + }, + { + "label": "Tidy", + "type": "shell", + "command": "go mod tidy", + "group": "none", + "presentation": { + "reveal": "always" + } + } + ] +} diff --git a/Makefile b/Makefile index dc6a1d0d..248582cd 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,8 @@ GO_BUILD_OUTPUT:=$(BIN_OUT_DIR)/$(BINARY_NAME)$(BINARY_SUFFIX) # define version of golangci-lint here. If defined in tools.go, go mod perfoms automatically downgrade to older version which doesn't work with golang >=1.18 GOLANG_LINT_VERSION=v1.54.2 +GINKGO_PROCS?=-p + export PATH=$(shell go env GOPATH)/bin:$(shell echo $$PATH) all: build test lint ## Build binary (with tests) @@ -55,7 +57,7 @@ ifdef BIN_AUTOCAB endif test: ## run tests - go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic -cover ./... + go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic --cover -r ${GINKGO_PROCS} e2e-test: ## run e2e tests docker buildx build \ @@ -67,7 +69,7 @@ e2e-test: ## run e2e tests go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="e2e" --timeout 15m --flake-attempts 1 e2e race: ## run tests with race detector - go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --race ./... + go run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --race -r ${GINKGO_PROCS} lint: fmt ## run golangcli-lint checks go run github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANG_LINT_VERSION) run --timeout 5m diff --git a/cache/stringcache/chained_grouped_cache_test.go b/cache/stringcache/chained_grouped_cache_test.go index e83f9560..9a04e917 100644 --- a/cache/stringcache/chained_grouped_cache_test.go +++ b/cache/stringcache/chained_grouped_cache_test.go @@ -7,9 +7,15 @@ import ( ) var _ = Describe("Chained grouped cache", func() { + var ( + cache *stringcache.ChainedGroupedCache + factory stringcache.GroupFactory + ) Describe("Empty cache", func() { When("empty cache was created", func() { - cache := stringcache.NewChainedGroupedCache() + BeforeEach(func() { + cache = stringcache.NewChainedGroupedCache() + }) It("should have element count of 0", func() { Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) @@ -22,14 +28,16 @@ var _ = Describe("Chained grouped cache", func() { }) Describe("Delegation", func() { When("Chained cache contains delegates", func() { - inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() - inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() - cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) + BeforeEach(func() { + inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() + inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() + cache = stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) - factory := cache.Refresh("group1") + factory = cache.Refresh("group1") - factory.AddEntry("string1") - factory.AddEntry("string2") + factory.AddEntry("string1") + factory.AddEntry("string2") + }) It("cache should still have 0 element, since finish was not executed", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) @@ -45,6 +53,7 @@ var _ = Describe("Chained grouped cache", func() { }) It("should find strings", func() { + factory.Finish() Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) }) @@ -53,20 +62,22 @@ var _ = Describe("Chained grouped cache", func() { Describe("Cache refresh", func() { When("cache with 2 groups was created", func() { - inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() - inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() - cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) + BeforeEach(func() { + inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() + inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() + cache = stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) - factory := cache.Refresh("group1") + factory = cache.Refresh("group1") - factory.AddEntry("g1") - factory.AddEntry("both") - factory.Finish() + factory.AddEntry("g1") + factory.AddEntry("both") + factory.Finish() - factory = cache.Refresh("group2") - factory.AddEntry("g2") - factory.AddEntry("both") - factory.Finish() + factory = cache.Refresh("group2") + factory.AddEntry("g2") + factory.AddEntry("both") + factory.Finish() + }) It("should contain 4 elements in 2 groups", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 4)) @@ -77,7 +88,7 @@ var _ = Describe("Chained grouped cache", func() { }) It("Should replace group content on refresh", func() { - factory := cache.Refresh("group1") + factory = cache.Refresh("group1") factory.AddEntry("newString") factory.Finish() diff --git a/cache/stringcache/in_memory_grouped_cache_test.go b/cache/stringcache/in_memory_grouped_cache_test.go index 7692935a..bddb7d4b 100644 --- a/cache/stringcache/in_memory_grouped_cache_test.go +++ b/cache/stringcache/in_memory_grouped_cache_test.go @@ -7,10 +7,16 @@ import ( ) var _ = Describe("In-Memory grouped cache", func() { - Describe("Empty cache", func() { - When("empty cache was created", func() { - cache := stringcache.NewInMemoryGroupedStringCache() + var ( + cache *stringcache.InMemoryGroupedCache + factory stringcache.GroupFactory + ) + Describe("Empty cache", func() { + BeforeEach(func() { + cache = stringcache.NewInMemoryGroupedStringCache() + }) + When("empty cache was created", func() { It("should have element count of 0", func() { Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) }) @@ -20,9 +26,10 @@ var _ = Describe("In-Memory grouped cache", func() { }) }) When("cache with one empty group", func() { - cache := stringcache.NewInMemoryGroupedStringCache() - factory := cache.Refresh("group1") - factory.Finish() + BeforeEach(func() { + factory = cache.Refresh("group1") + factory.Finish() + }) It("should have element count of 0", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) @@ -35,12 +42,13 @@ var _ = Describe("In-Memory grouped cache", func() { }) Describe("Cache creation", func() { When("cache with 1 group was created", func() { - cache := stringcache.NewInMemoryGroupedStringCache() + BeforeEach(func() { + cache = stringcache.NewInMemoryGroupedStringCache() + factory = cache.Refresh("group1") - factory := cache.Refresh("group1") - - factory.AddEntry("string1") - factory.AddEntry("string2") + factory.AddEntry("string1") + factory.AddEntry("string2") + }) It("cache should still have 0 element, since finish was not executed", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) @@ -56,17 +64,20 @@ var _ = Describe("In-Memory grouped cache", func() { }) It("should find strings", func() { + factory.Finish() Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) }) }) When("String grouped cache is used", func() { - cache := stringcache.NewInMemoryGroupedStringCache() - factory := cache.Refresh("group1") + BeforeEach(func() { + cache = stringcache.NewInMemoryGroupedStringCache() + factory = cache.Refresh("group1") - factory.AddEntry("string1") - factory.AddEntry("/string2/") - factory.Finish() + factory.AddEntry("string1") + factory.AddEntry("/string2/") + factory.Finish() + }) It("should ignore regex", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) @@ -74,12 +85,14 @@ var _ = Describe("In-Memory grouped cache", func() { }) }) When("Regex grouped cache is used", func() { - cache := stringcache.NewInMemoryGroupedRegexCache() - factory := cache.Refresh("group1") + BeforeEach(func() { + cache = stringcache.NewInMemoryGroupedRegexCache() + factory = cache.Refresh("group1") - factory.AddEntry("string1") - factory.AddEntry("/string2/") - factory.Finish() + factory.AddEntry("string1") + factory.AddEntry("/string2/") + factory.Finish() + }) It("should ignore non-regex", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) @@ -92,18 +105,19 @@ var _ = Describe("In-Memory grouped cache", func() { Describe("Cache refresh", func() { When("cache with 2 groups was created", func() { - cache := stringcache.NewInMemoryGroupedStringCache() + BeforeEach(func() { + cache = stringcache.NewInMemoryGroupedStringCache() + factory = cache.Refresh("group1") - factory := cache.Refresh("group1") + factory.AddEntry("g1") + factory.AddEntry("both") + factory.Finish() - factory.AddEntry("g1") - factory.AddEntry("both") - factory.Finish() - - factory = cache.Refresh("group2") - factory.AddEntry("g2") - factory.AddEntry("both") - factory.Finish() + factory = cache.Refresh("group2") + factory.AddEntry("g2") + factory.AddEntry("both") + factory.Finish() + }) It("should contain 4 elements in 2 groups", func() { Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) @@ -114,7 +128,7 @@ var _ = Describe("In-Memory grouped cache", func() { }) It("Should replace group content on refresh", func() { - factory := cache.Refresh("group1") + factory = cache.Refresh("group1") factory.AddEntry("newString") factory.Finish() diff --git a/cache/stringcache/string_caches_test.go b/cache/stringcache/string_caches_test.go index 23b19b6a..201e2c34 100644 --- a/cache/stringcache/string_caches_test.go +++ b/cache/stringcache/string_caches_test.go @@ -6,16 +6,22 @@ import ( ) var _ = Describe("Caches", func() { + var ( + cache stringCache + factory cacheFactory + ) Describe("String StringCache", func() { When("string StringCache was created", func() { - factory := newStringCacheFactory() - factory.addEntry("google.com") - factory.addEntry("apple.com") - factory.addEntry("") - factory.addEntry("google.com") - factory.addEntry("APPLe.com") + BeforeEach(func() { + factory = newStringCacheFactory() + factory.addEntry("google.com") + factory.addEntry("apple.com") + factory.addEntry("") + factory.addEntry("google.com") + factory.addEntry("APPLe.com") - cache := factory.create() + cache = factory.create() + }) It("should match if StringCache contains exact string", func() { Expect(cache.contains("apple.com")).Should(BeTrue()) @@ -37,14 +43,16 @@ var _ = Describe("Caches", func() { Describe("Regex StringCache", func() { When("regex StringCache was created", func() { - factory := newRegexCacheFactory() - factory.addEntry("/.*google.com/") - factory.addEntry("/^apple\\.(de|com)$/") - factory.addEntry("/amazon/") - // this is not a regex, will be ignored - factory.addEntry("/(wrongRegex/") - factory.addEntry("plaintext") - cache := factory.create() + BeforeEach(func() { + factory = newRegexCacheFactory() + factory.addEntry("/.*google.com/") + factory.addEntry("/^apple\\.(de|com)$/") + factory.addEntry("/amazon/") + // this is not a regex, will be ignored + factory.addEntry("/(wrongRegex/") + factory.addEntry("plaintext") + cache = factory.create() + }) It("should match if one regex in StringCache matches string", func() { Expect(cache.contains("google.com")).Should(BeTrue()) Expect(cache.contains("google.coma")).Should(BeTrue()) diff --git a/cmd/healthcheck_test.go b/cmd/healthcheck_test.go index 37f3f739..8938d026 100644 --- a/cmd/healthcheck_test.go +++ b/cmd/healthcheck_test.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" + "github.com/0xERR0R/blocky/helpertest" "github.com/miekg/dns" . "github.com/onsi/ginkgo/v2" @@ -13,7 +14,7 @@ var _ = Describe("Healthcheck command", func() { Describe("Call healthcheck command", func() { It("should fail", func() { c := NewHealthcheckCommand() - c.SetArgs([]string{"-p", "5344"}) + c.SetArgs([]string{"-p", "533"}) err := c.Execute() @@ -21,7 +22,8 @@ var _ = Describe("Healthcheck command", func() { }) It("shoul succeed", func() { - srv := createMockServer() + port := helpertest.GetStringPort(5100) + srv := createMockServer(port) go func() { defer GinkgoRecover() err := srv.ListenAndServe() @@ -31,7 +33,7 @@ var _ = Describe("Healthcheck command", func() { Eventually(func() error { c := NewHealthcheckCommand() - c.SetArgs([]string{"-p", "5333"}) + c.SetArgs([]string{"-p", port}) return c.Execute() }, "1s").Should(Succeed()) @@ -39,9 +41,9 @@ var _ = Describe("Healthcheck command", func() { }) }) -func createMockServer() *dns.Server { +func createMockServer(port string) *dns.Server { res := &dns.Server{ - Addr: "127.0.0.1:5333", + Addr: "127.0.0.1:" + port, Net: "tcp", Handler: dns.NewServeMux(), NotifyStartedFunc: func() { diff --git a/cmd/lists_test.go b/cmd/lists_test.go index dc69df80..d29af1aa 100644 --- a/cmd/lists_test.go +++ b/cmd/lists_test.go @@ -6,6 +6,7 @@ import ( "github.com/0xERR0R/blocky/log" "github.com/sirupsen/logrus/hooks/test" + "github.com/spf13/cobra" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -16,6 +17,8 @@ var _ = Describe("Lists command", func() { ts *httptest.Server mockFn func(w http.ResponseWriter, _ *http.Request) loggerHook *test.Hook + c *cobra.Command + err error ) JustBeforeEach(func() { ts = testHTTPAPIServer(mockFn) @@ -33,10 +36,12 @@ var _ = Describe("Lists command", func() { }) Describe("Call list refresh command", func() { When("list refresh is executed", func() { - It("should print result", func() { - c := NewListsCommand() + BeforeEach(func() { + c = NewListsCommand() c.SetArgs([]string{"refresh"}) - err := c.Execute() + }) + It("should print result", func() { + err = c.Execute() Expect(err).Should(Succeed()) Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("OK")) @@ -44,24 +49,26 @@ var _ = Describe("Lists command", func() { }) When("Server returns 500", func() { BeforeEach(func() { + c = newRefreshCommand() + c.SetArgs(make([]string, 0)) mockFn = func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusInternalServerError) } }) It("should end with error", func() { - c := newRefreshCommand() - c.SetArgs(make([]string, 0)) - err := c.Execute() + err = c.Execute() Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("500 Internal Server Error")) }) }) When("Url is wrong", func() { + BeforeEach(func() { + c = newRefreshCommand() + c.SetArgs(make([]string, 0)) + }) It("should end with error", func() { apiPort = 0 - c := newRefreshCommand() - c.SetArgs(make([]string, 0)) - err := c.Execute() + err = c.Execute() Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("connection refused")) }) diff --git a/cmd/serve_test.go b/cmd/serve_test.go index a1594927..3ae38fbc 100644 --- a/cmd/serve_test.go +++ b/cmd/serve_test.go @@ -12,9 +12,17 @@ import ( . "github.com/onsi/gomega" ) +const ( + basePort = 5000 +) + var _ = Describe("Serve command", func() { - var tmpDir *helpertest.TmpFolder + var ( + tmpDir *helpertest.TmpFolder + port string + ) BeforeEach(func() { + port = helpertest.GetStringPort(basePort) tmpDir = helpertest.NewTmpFolder("config") Expect(tmpDir.Error).Should(Succeed()) DeferCleanup(tmpDir.Clean) @@ -30,7 +38,7 @@ var _ = Describe("Serve command", func() { " default:", " - 1.1.1.1", "ports:", - " dns: 55555") + " dns: "+port) Expect(cfgFile.Error).Should(Succeed()) os.Setenv(configFileEnvVar, cfgFile.Path) DeferCleanup(func() { os.Unsetenv(configFileEnvVar) }) @@ -47,7 +55,7 @@ var _ = Describe("Serve command", func() { By("check DNS port is open", func() { Eventually(func(g Gomega) { - conn, err := net.DialTimeout("tcp", "127.0.0.1:55555", 200*time.Millisecond) + conn, err := net.DialTimeout("tcp", "127.0.0.1:"+port, 200*time.Millisecond) g.Expect(err).Should(Succeed()) defer conn.Close() }).Should(Succeed()) @@ -64,19 +72,19 @@ var _ = Describe("Serve command", func() { When("Serve command is called with valid config", func() { It("should fail if server start fails", func() { - By("start http server on port 5555", func() { - go func() { - Expect(http.ListenAndServe(":55555", nil)).Should(Succeed()) - }() + By("start http server on port "+port, func() { + go func(p string) { + Expect(http.ListenAndServe(":"+p, nil)).Should(Succeed()) + }(port) }) - By("initialize config with blocked port 55555", func() { + By("initialize config with blocked port "+port, func() { cfgFile := tmpDir.CreateStringFile("config.yaml", "upstreams:", " groups:", " default:", " - 1.1.1.1", "ports:", - " dns: 55555") + " dns: "+port) Expect(cfgFile.Error).Should(Succeed()) os.Setenv(configFileEnvVar, cfgFile.Path) DeferCleanup(func() { os.Unsetenv(configFileEnvVar) }) diff --git a/helpertest/helper.go b/helpertest/helper.go index f213e7af..7a1c00e4 100644 --- a/helpertest/helper.go +++ b/helpertest/helper.go @@ -11,6 +11,7 @@ import ( "github.com/0xERR0R/blocky/model" "github.com/miekg/dns" + "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/onsi/gomega/gcustom" "github.com/onsi/gomega/types" @@ -27,6 +28,20 @@ const ( DS = dns.Type(dns.TypeDS) ) +// GetIntPort returns an port for the current testing +// process by adding the current ginkgo parallel process to +// the base port and returning it as int +func GetIntPort(port int) int { + return port + ginkgo.GinkgoParallelProcess() +} + +// GetStringPort returns an port for the current testing +// process by adding the current ginkgo parallel process to +// the base port and returning it as string +func GetStringPort(port int) string { + return fmt.Sprintf("%d", GetIntPort(port)) +} + // TempFile creates temp file with passed data func TempFile(data string) *os.File { f, err := os.CreateTemp("", "prefix") diff --git a/lists/list_cache_test.go b/lists/list_cache_test.go index acbda197..e39ffbaa 100644 --- a/lists/list_cache_test.go +++ b/lists/list_cache_test.go @@ -38,11 +38,12 @@ var _ = Describe("ListCache", func() { mockDownloader *MockDownloader ctx context.Context cancelFn context.CancelFunc + err error + expectFail bool ) BeforeEach(func() { - var err error - + expectFail = false ctx, cancelFn = context.WithCancel(context.Background()) DeferCleanup(cancelFn) @@ -81,8 +82,6 @@ var _ = Describe("ListCache", func() { }) JustBeforeEach(func() { - var err error - Expect(lists).ShouldNot(BeNil(), "bad test: forgot to set `lists`") if mockDownloader != nil { @@ -90,7 +89,11 @@ var _ = Describe("ListCache", func() { } sut, err = NewListCache(ctx, listCacheType, sutConfig, lists, downloader) - Expect(err).Should(Succeed()) + if expectFail { + Expect(err).Should(HaveOccurred()) + } else { + Expect(err).Should(Succeed()) + } }) Describe("List cache and matching", func() { @@ -301,15 +304,20 @@ var _ = Describe("ListCache", func() { }) }) When("group with bigger files", func() { - It("should match", func() { - file1, lines1 := createTestListFile(GinkgoT().TempDir(), 10000) - file2, lines2 := createTestListFile(GinkgoT().TempDir(), 15000) - file3, lines3 := createTestListFile(GinkgoT().TempDir(), 13000) - lists := map[string][]config.BytesSource{ + var ( + file1, file2, file3 string + lines1, lines2, lines3 int + ) + BeforeEach(func() { + file1, lines1 = createTestListFile(GinkgoT().TempDir(), 10000) + file2, lines2 = createTestListFile(GinkgoT().TempDir(), 15000) + file3, lines3 = createTestListFile(GinkgoT().TempDir(), 13000) + lists = map[string][]config.BytesSource{ "gr1": config.NewBytesSources(file1, file2, file3), } - - sut, err := NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) + }) + It("should match", func() { + sut, err = NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) Expect(err).Should(Succeed()) Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(lines1 + lines2 + lines3)) @@ -356,16 +364,14 @@ var _ = Describe("ListCache", func() { BeforeEach(func() { sutConfig.MaxErrorsPerSource = 0 sutConfig.Strategy = config.StartStrategyTypeFailOnError - }) - It("should fail parsing", func() { - lists := map[string][]config.BytesSource{ + lists = map[string][]config.BytesSource{ "gr1": { config.TextBytesSource("invaliddomain!"), // too many errors since `maxErrorsPerSource` is 0 }, } - - _, err := NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) - Expect(err).ShouldNot(Succeed()) + expectFail = true + }) + It("should fail parsing", func() { Expect(err).Should(MatchError(parsers.ErrTooManyErrors)) }) }) @@ -405,15 +411,15 @@ var _ = Describe("ListCache", func() { BeforeEach(func() { logger, hook = log.NewMockEntry() - }) - It("should print list configuration", func() { - lists := map[string][]config.BytesSource{ + lists = map[string][]config.BytesSource{ "gr1": config.NewBytesSources(server1.URL, server2.URL), "gr2": {config.TextBytesSource("inline", "definition")}, } + }) - sut, err := NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) + It("should print list configuration", func() { + sut, err = NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) Expect(err).Should(Succeed()) sut.LogConfig(logger) @@ -428,13 +434,13 @@ var _ = Describe("ListCache", func() { When("async load is enabled", func() { BeforeEach(func() { sutConfig.Strategy = config.StartStrategyTypeFast + + lists = map[string][]config.BytesSource{ + "gr1": config.NewBytesSources("doesnotexist"), + } }) It("should never return an error", func() { - lists := map[string][]config.BytesSource{ - "gr1": config.NewBytesSources("doesnotexist"), - } - _, err := NewListCache(ctx, ListCacheTypeBlacklist, sutConfig, lists, downloader) Expect(err).Should(Succeed()) }) diff --git a/resolver/hosts_file_resolver_test.go b/resolver/hosts_file_resolver_test.go index 69341311..79fead56 100644 --- a/resolver/hosts_file_resolver_test.go +++ b/resolver/hosts_file_resolver_test.go @@ -23,6 +23,8 @@ var _ = Describe("HostsFileResolver", func() { m *mockResolver tmpDir *TmpFolder tmpFile *TmpFile + err error + resp *Response ) Describe("Type", func() { @@ -51,8 +53,6 @@ var _ = Describe("HostsFileResolver", func() { }) JustBeforeEach(func() { - var err error - ctx, cancelFn := context.WithCancel(context.Background()) DeferCleanup(cancelFn) sut, err = NewHostsFileResolver(ctx, sutConfig, systemResolverBootstrap) @@ -109,14 +109,10 @@ var _ = Describe("HostsFileResolver", func() { When("Hosts file is not set", func() { BeforeEach(func() { sutConfig.Deprecated.Filepath = new(config.BytesSource) - sutConfig.Sources = nil - - m = &mockResolver{} - m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil) - sut.Next(m) + sutConfig.Sources = make([]config.BytesSource, 0) }) - It("should not return an error", func() { - err := sut.loadSources(context.Background()) + JustBeforeEach(func() { + err = sut.loadSources(context.Background()) Expect(err).Should(Succeed()) }) It("should go to next resolver on query", func() { @@ -236,7 +232,7 @@ var _ = Describe("HostsFileResolver", func() { When("the domain is not known", func() { It("calls the next resolver", func() { - resp, err := sut.Resolve(newRequest("not-in-hostsfile.tld.", A)) + resp, err = sut.Resolve(newRequest("not-in-hostsfile.tld.", A)) Expect(err).Should(Succeed()) Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) m.AssertExpectations(GinkgoT()) @@ -245,7 +241,7 @@ var _ = Describe("HostsFileResolver", func() { When("the question type is not handled", func() { It("calls the next resolver", func() { - resp, err := sut.Resolve(newRequest("localhost.", MX)) + resp, err = sut.Resolve(newRequest("localhost.", MX)) Expect(err).Should(Succeed()) Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) m.AssertExpectations(GinkgoT()) @@ -294,7 +290,7 @@ var _ = Describe("HostsFileResolver", func() { }) It("should ignore invalid PTR", func() { - resp, err := sut.Resolve(newRequest("2.0.0.10.in-addr.fail.arpa.", PTR)) + resp, err = sut.Resolve(newRequest("2.0.0.10.in-addr.fail.arpa.", PTR)) Expect(err).Should(Succeed()) Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) m.AssertExpectations(GinkgoT()) @@ -302,7 +298,7 @@ var _ = Describe("HostsFileResolver", func() { When("filterLoopback is true", func() { It("calls the next resolver", func() { - resp, err := sut.Resolve(newRequest("1.0.0.127.in-addr.arpa.", PTR)) + resp, err = sut.Resolve(newRequest("1.0.0.127.in-addr.arpa.", PTR)) Expect(err).Should(Succeed()) Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) m.AssertExpectations(GinkgoT()) @@ -311,7 +307,7 @@ var _ = Describe("HostsFileResolver", func() { When("the IP is not known", func() { It("calls the next resolver", func() { - resp, err := sut.Resolve(newRequest("255.255.255.255.in-addr.arpa.", PTR)) + resp, err = sut.Resolve(newRequest("255.255.255.255.in-addr.arpa.", PTR)) Expect(err).Should(Succeed()) Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) m.AssertExpectations(GinkgoT()) @@ -342,7 +338,7 @@ var _ = Describe("HostsFileResolver", func() { Describe("Delegating to next resolver", func() { When("no hosts file is provided", func() { It("should delegate to next resolver", func() { - _, err := sut.Resolve(newRequest("example.com.", A)) + _, err = sut.Resolve(newRequest("example.com.", A)) Expect(err).Should(Succeed()) // delegate was executed m.AssertExpectations(GinkgoT()) diff --git a/resolver/parallel_best_resolver_test.go b/resolver/parallel_best_resolver_test.go index 3c25b69c..3ebb06b3 100644 --- a/resolver/parallel_best_resolver_test.go +++ b/resolver/parallel_best_resolver_test.go @@ -184,9 +184,9 @@ var _ = Describe("ParallelBestResolver", Label("parallelBestResolver"), func() { }) }) When("one resolver is slow, but another returns an error", func() { + var slowTestUpstream *MockUDPUpstreamServer BeforeEach(func() { - withErrorUpstream := config.Upstream{Host: "wrong"} - slowTestUpstream := NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { + slowTestUpstream = NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { response, err := util.NewMsgWithAnswer("example.com.", 123, A, "123.124.122.123") time.Sleep(50 * time.Millisecond) @@ -196,9 +196,8 @@ var _ = Describe("ParallelBestResolver", Label("parallelBestResolver"), func() { }) DeferCleanup(slowTestUpstream.Close) sutMapping = config.UpstreamGroups{ - upstreamDefaultCfgName: {withErrorUpstream, slowTestUpstream.Start()}, + upstreamDefaultCfgName: {config.Upstream{Host: "wrong"}, slowTestUpstream.Start()}, } - Expect(err).Should(Succeed()) }) It("Should use result from successful resolver", func() { request := newRequest("example.com.", A) @@ -220,9 +219,9 @@ var _ = Describe("ParallelBestResolver", Label("parallelBestResolver"), func() { sutMapping = config.UpstreamGroups{ upstreamDefaultCfgName: {withError1, withError2}, } - Expect(err).Should(Succeed()) }) It("Should return error", func() { + Expect(err).Should(Succeed()) request := newRequest("example.com.", A) _, err = sut.Resolve(request) diff --git a/resolver/strict_resolver_test.go b/resolver/strict_resolver_test.go index 84719c80..c35a9d15 100644 --- a/resolver/strict_resolver_test.go +++ b/resolver/strict_resolver_test.go @@ -263,17 +263,13 @@ var _ = Describe("StrictResolver", Label("strictResolver"), func() { }) When("None are working", func() { BeforeEach(func() { - testUpstream1 := config.Upstream{Host: "wrong"} - testUpstream2 := config.Upstream{Host: "wrong"} - sutMapping = config.UpstreamGroups{ - upstreamDefaultCfgName: {testUpstream1, testUpstream2}, + upstreamDefaultCfgName: {config.Upstream{Host: "wrong"}, config.Upstream{Host: "wrong"}}, } - Expect(err).Should(Succeed()) }) It("Should return error", func() { request := newRequest("example.com.", A) - _, err := sut.Resolve(request) + _, err = sut.Resolve(request) Expect(err).Should(HaveOccurred()) }) }) diff --git a/server/server_test.go b/server/server_test.go index a346655c..8943e191 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/base64" + "fmt" "io" "net" "net/http" @@ -25,17 +26,28 @@ import ( "github.com/miekg/dns" ) +const ( + httpBasePort = 4000 + dnsBasePort = 5000 + dnsBasePort2 = 55000 + httpsBasePort = 6000 + tlsBasePort = 8000 +) + var ( - mockClientName atomic.Value - sut *Server - err error + mockClientName atomic.Value + sut *Server + err error + baseURL string + googleMockUpstream, fritzboxMockUpstream, clientMockUpstream *resolver.MockUDPUpstreamServer ) var _ = BeforeSuite(func() { + baseURL = "http://localhost:" + GetStringPort(httpBasePort) + "/" var upstreamGoogle, upstreamFritzbox, upstreamClient config.Upstream ctx, cancelFn := context.WithCancel(context.Background()) DeferCleanup(cancelFn) - googleMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { + googleMockUpstream = resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { if request.Question[0].Name == "error." { return nil } @@ -49,7 +61,7 @@ var _ = BeforeSuite(func() { }) DeferCleanup(googleMockUpstream.Close) - fritzboxMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { + fritzboxMockUpstream = resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { response, err := util.NewMsgWithAnswer( util.ExtractDomain(request.Question[0]), 3600, A, "192.168.178.2", ) @@ -60,7 +72,7 @@ var _ = BeforeSuite(func() { }) DeferCleanup(fritzboxMockUpstream.Close) - clientMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { + clientMockUpstream = resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { var clientName string client := mockClientName.Load() @@ -153,10 +165,10 @@ var _ = BeforeSuite(func() { }, Ports: config.PortsConfig{ - DNS: config.ListenConfig{"55555"}, - TLS: config.ListenConfig{"8853"}, - HTTP: config.ListenConfig{"4000"}, - HTTPS: config.ListenConfig{"4443"}, + DNS: config.ListenConfig{GetStringPort(dnsBasePort)}, + TLS: config.ListenConfig{GetStringPort(tlsBasePort)}, + HTTP: config.ListenConfig{GetStringPort(httpBasePort)}, + HTTPS: config.ListenConfig{GetStringPort(httpsBasePort)}, }, CertFile: certPem.Path, KeyFile: keyPem.Path, @@ -365,7 +377,7 @@ var _ = Describe("Running DNS server", func() { Describe("Prometheus endpoint", func() { When("Prometheus URL is called", func() { It("should return prometheus data", func() { - resp, err := http.Get("http://localhost:4000/metrics") + resp, err := http.Get(baseURL + "metrics") Expect(err).Should(Succeed()) Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) }) @@ -374,7 +386,7 @@ var _ = Describe("Running DNS server", func() { Describe("Root endpoint", func() { When("Root URL is called", func() { It("should return root page", func() { - resp, err := http.Get("http://localhost:4000/") + resp, err := http.Get(baseURL) Expect(err).Should(Succeed()) Expect(resp).Should( SatisfyAll( @@ -387,7 +399,7 @@ var _ = Describe("Running DNS server", func() { Describe("Docs endpoints", func() { When("OpenApi URL is called", func() { It("should return openAPI definition file", func() { - resp, err := http.Get("http://localhost:4000/docs/openapi.yaml") + resp, err := http.Get(baseURL + "docs/openapi.yaml") Expect(err).Should(Succeed()) Expect(resp).Should( SatisfyAll( @@ -403,7 +415,7 @@ var _ = Describe("Running DNS server", func() { Context("DOH over GET (RFC 8484)", func() { When("DOH get request with 'example.com' is performed", func() { It("should get a valid response", func() { - resp, err := http.Get("http://localhost:4000/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB") + resp, err := http.Get(baseURL + "dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB") Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -422,7 +434,7 @@ var _ = Describe("Running DNS server", func() { }) When("Request does not contain a valid DNS message", func() { It("should return 'Bad Request'", func() { - resp, err := http.Get("http://localhost:4000/dns-query?dns=xxxx") + resp, err := http.Get(baseURL + "dns-query?dns=xxxx") Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -431,7 +443,7 @@ var _ = Describe("Running DNS server", func() { }) When("Request's parameter does not contain a valid base64'", func() { It("should return 'Bad Request'", func() { - resp, err := http.Get("http://localhost:4000/dns-query?dns=äöä") + resp, err := http.Get(baseURL + "dns-query?dns=äöä") Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -440,7 +452,7 @@ var _ = Describe("Running DNS server", func() { }) When("Request does not contain a dns parameter", func() { It("should return 'Bad Request'", func() { - resp, err := http.Get("http://localhost:4000/dns-query?test") + resp, err := http.Get(baseURL + "dns-query?test") Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -451,7 +463,7 @@ var _ = Describe("Running DNS server", func() { It("should return 'URI Too Long'", func() { longBase64msg := base64.StdEncoding.EncodeToString([]byte(strings.Repeat("t", 513))) - resp, err := http.Get("http://localhost:4000/dns-query?dns=" + longBase64msg) + resp, err := http.Get(baseURL + "dns-query?dns=" + longBase64msg) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -460,13 +472,17 @@ var _ = Describe("Running DNS server", func() { }) }) Context("DOH over POST (RFC 8484)", func() { + var ( + resp *http.Response + msg *dns.Msg + ) When("DOH post request with 'example.com' is performed", func() { It("should get a valid response", func() { - msg := util.NewMsgWithQuestion("www.example.com.", A) + msg = util.NewMsgWithQuestion("www.example.com.", A) rawDNSMessage, err := msg.Pack() Expect(err).Should(Succeed()) - resp, err := http.Post("http://localhost:4000/dns-query", + resp, err = http.Post(baseURL+"dns-query", "application/dns-message", bytes.NewReader(rawDNSMessage)) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -487,11 +503,11 @@ var _ = Describe("Running DNS server", func() { Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) }) It("should get a valid response, clientId is passed", func() { - msg := util.NewMsgWithQuestion("www.example.com.", A) + msg = util.NewMsgWithQuestion("www.example.com.", A) rawDNSMessage, err := msg.Pack() Expect(err).Should(Succeed()) - resp, err := http.Post("http://localhost:4000/dns-query/client123", + resp, err = http.Post(baseURL+"dns-query/client123", "application/dns-message", bytes.NewReader(rawDNSMessage)) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -515,7 +531,7 @@ var _ = Describe("Running DNS server", func() { It("should return 'Payload Too Large'", func() { largeMessage := []byte(strings.Repeat("t", 513)) - resp, err := http.Post("http://localhost:4000/dns-query", "application/dns-message", bytes.NewReader(largeMessage)) + resp, err = http.Post(baseURL+"dns-query", "application/dns-message", bytes.NewReader(largeMessage)) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -524,7 +540,7 @@ var _ = Describe("Running DNS server", func() { }) When("Request has wrong type", func() { It("should return 'Unsupported Media Type'", func() { - resp, err := http.Post("http://localhost:4000/dns-query", "application/text", bytes.NewReader([]byte("a"))) + resp, err = http.Post(baseURL+"dns-query", "application/text", bytes.NewReader([]byte("a"))) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -533,11 +549,11 @@ var _ = Describe("Running DNS server", func() { }) When("Internal error occurs", func() { It("should return 'Internal server error'", func() { - msg := util.NewMsgWithQuestion("error.", A) + msg = util.NewMsgWithQuestion("error.", A) rawDNSMessage, err := msg.Pack() Expect(err).Should(Succeed()) - resp, err := http.Post("http://localhost:4000/dns-query", + resp, err = http.Post(baseURL+"dns-query", "application/dns-message", bytes.NewReader(rawDNSMessage)) Expect(err).Should(Succeed()) DeferCleanup(resp.Body.Close) @@ -566,14 +582,14 @@ var _ = Describe("Running DNS server", func() { }) When("Server is created", func() { It("is created without redis connection", func() { - _, err := NewServer(ctx, &cfg) + _, err = NewServer(ctx, &cfg) Expect(err).Should(Succeed()) }) It("can't be created if redis server is unavailable", func() { cfg.Redis.Required = true - _, err := NewServer(ctx, &cfg) + _, err = NewServer(ctx, &cfg) Expect(err).ShouldNot(Succeed()) }) @@ -582,9 +598,13 @@ var _ = Describe("Running DNS server", func() { Describe("Server start", Label("XX"), func() { When("Server start is called", func() { - It("start was called 2 times, start should fail", func() { + var ( + server *Server + errChan chan error + ) + BeforeEach(func() { // create server - server, err := NewServer(ctx, &config.Config{ + server, err = NewServer(ctx, &config.Config{ Upstreams: config.UpstreamsConfig{ Groups: map[string][]config.Upstream{ "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, @@ -600,19 +620,19 @@ var _ = Describe("Running DNS server", func() { }, Blocking: config.BlockingConfig{BlockType: "zeroIp"}, Ports: config.PortsConfig{ - DNS: config.ListenConfig{":55556"}, + DNS: config.ListenConfig{"127.0.0.1:" + GetStringPort(dnsBasePort2)}, }, }) Expect(err).Should(Succeed()) - errChan := make(chan error, 10) - + errChan = make(chan error, 10) // start server go server.Start(ctx, errChan) DeferCleanup(server.Stop) - + }) + It("start was called 2 times, start should fail", func() { Consistently(errChan, "1s").ShouldNot(Receive()) // start again -> should fail @@ -624,9 +644,13 @@ var _ = Describe("Running DNS server", func() { }) Describe("Server stop", func() { When("Stop is called", func() { - It("stop was called 2 times, start should fail", func() { + var ( + server *Server + errChan chan error + ) + BeforeEach(func() { // create server - server, err := NewServer(ctx, &config.Config{ + server, err = NewServer(ctx, &config.Config{ Upstreams: config.UpstreamsConfig{ Groups: map[string][]config.Upstream{ "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, @@ -642,18 +666,17 @@ var _ = Describe("Running DNS server", func() { }, Blocking: config.BlockingConfig{BlockType: "zeroIp"}, Ports: config.PortsConfig{ - DNS: config.ListenConfig{"127.0.0.1:55557"}, + DNS: config.ListenConfig{"127.0.0.1:" + GetStringPort(dnsBasePort2)}, }, }) Expect(err).Should(Succeed()) - errChan := make(chan error, 10) - + errChan = make(chan error, 10) + }) + It("stop was called 2 times, start should fail", func() { // start server - go func() { - server.Start(ctx, errChan) - }() + go server.Start(ctx, errChan) time.Sleep(100 * time.Millisecond) @@ -745,7 +768,7 @@ var _ = Describe("Running DNS server", func() { cfg.KeyFile = "" cfg.CertFile = "" cfg.Ports = config.PortsConfig{ - HTTPS: []string{":14443"}, + HTTPS: []string{fmt.Sprintf(":%d", GetIntPort(httpsBasePort)+100)}, } sut, err := NewServer(ctx, &cfg) Expect(err).Should(Succeed()) @@ -755,7 +778,7 @@ var _ = Describe("Running DNS server", func() { }) func requestServer(request *dns.Msg) *dns.Msg { - conn, err := net.Dial("udp", ":55555") + conn, err := net.Dial("udp", ":"+GetStringPort(dnsBasePort)) if err != nil { Log().Fatal("could not connect to server: ", err) }