mirror of https://github.com/0xERR0R/blocky.git
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
This commit is contained in:
parent
42d6f21ceb
commit
8ece708fe9
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
vendor/
|
||||
coverage.txt
|
||||
lcov.*
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
6
Makefile
6
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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"))
|
||||
})
|
||||
|
|
|
@ -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) })
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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())
|
||||
})
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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())
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue