mirror of
https://github.com/hanzoai/dns.git
synced 2026-10-30 18:40:55 +00:00
proxyproto is declared in plugin.cfg and implemented under plugin/proxyproto,
and appears in NEITHER generated file — not the imports in
core/plugin/zplugin.go, not the directive order in
core/dnsserver/zdirectives.go. Both were generated before it was added, so
the plugin has never been reachable: a Corefile naming it gets "Unknown
directive 'proxyproto'", which is what TestReadme found while checking that
plugin's own README. Added to both, and to the directive list between tls
and quic, where plugin.cfg orders it — position there is plugin chain
order, not decoration. Checked every other plugin.cfg entry the same way;
these two were the only gaps.
TestDefaultLoader and TestTLSKeyLog/Bad_Path chmod a path to 0000 and expect
the permission error. Root does not get one, and CI runs as root in a
container, so both skip there now with the reason.
Whole repo green with the Makefile's tags. proxyproto verified by starting a
server with it in the Corefile, not only by the README test going quiet.
309 lines
7.6 KiB
Go
309 lines
7.6 KiB
Go
package coremain
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/coredns/caddy"
|
|
)
|
|
|
|
func TestConfLoader(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
conf string
|
|
contents []byte
|
|
serverType string
|
|
expectedError bool
|
|
expectedInput bool
|
|
checkContents bool
|
|
}{
|
|
{
|
|
name: "empty conf",
|
|
conf: "",
|
|
serverType: "dns",
|
|
expectedError: false,
|
|
expectedInput: false,
|
|
},
|
|
{
|
|
name: "non-existent file",
|
|
conf: "non-existent-file",
|
|
serverType: "dns",
|
|
expectedError: true,
|
|
expectedInput: false,
|
|
},
|
|
{
|
|
name: "stdin input",
|
|
conf: "stdin",
|
|
serverType: "dns",
|
|
expectedError: false,
|
|
expectedInput: false,
|
|
},
|
|
{
|
|
name: "valid config file",
|
|
contents: []byte("example.org:53 {\n whoami\n}\n"),
|
|
serverType: "dns",
|
|
expectedError: false,
|
|
expectedInput: true,
|
|
checkContents: true,
|
|
},
|
|
{
|
|
name: "empty config file",
|
|
conf: "",
|
|
contents: []byte(""),
|
|
serverType: "dns",
|
|
expectedError: false,
|
|
expectedInput: false,
|
|
checkContents: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if len(tc.contents) > 0 {
|
|
tmpDir := t.TempDir()
|
|
tmpFile := filepath.Join(tmpDir, "corefile-test")
|
|
if err := os.WriteFile(tmpFile, tc.contents, 0o644); err != nil {
|
|
t.Fatalf("Failed to write to temp file: %v", err)
|
|
}
|
|
conf = tmpFile
|
|
} else {
|
|
conf = tc.conf
|
|
}
|
|
|
|
input, err := confLoader(tc.serverType)
|
|
|
|
// Check error
|
|
if tc.expectedError && err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
}
|
|
if !tc.expectedError && err != nil {
|
|
t.Errorf("Expected no error but got: %v", err)
|
|
}
|
|
|
|
// Check input
|
|
if !tc.expectedInput && input != nil {
|
|
t.Errorf("Expected nil input but got: %v", input)
|
|
}
|
|
if tc.expectedInput && input == nil {
|
|
t.Errorf("Expected non-nil input but got nil")
|
|
}
|
|
|
|
// Check contents if needed
|
|
if tc.checkContents && input != nil {
|
|
caddyInput, ok := input.(caddy.CaddyfileInput)
|
|
if !ok {
|
|
t.Errorf("Expected input to be caddy.CaddyfileInput")
|
|
}
|
|
if string(caddyInput.Contents) != string(tc.contents) {
|
|
t.Errorf("Expected contents %q, got %q", tc.contents, caddyInput.Contents)
|
|
}
|
|
if caddyInput.ServerTypeName != tc.serverType {
|
|
t.Errorf("Expected ServerTypeName to be %q, got %q", tc.serverType, caddyInput.ServerTypeName)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultLoader(t *testing.T) {
|
|
// The working directory matters because defaultLoader() looks for "Corefile" in the current directory
|
|
tmpDir := t.TempDir()
|
|
t.Chdir(tmpDir)
|
|
|
|
// Test without Corefile
|
|
input, err := defaultLoader("dns")
|
|
if err != nil {
|
|
t.Errorf("Expected no error for missing Corefile, got: %v", err)
|
|
}
|
|
if input != nil {
|
|
t.Errorf("Expected nil input for missing Corefile, got: %v", input)
|
|
}
|
|
|
|
// Test with Corefile
|
|
testContents := []byte("example.org:53 {\n whoami\n}\n")
|
|
if err := os.WriteFile(filepath.Join(tmpDir, "Corefile"), testContents, 0o644); err != nil {
|
|
t.Fatalf("Failed to write Corefile: %v", err)
|
|
}
|
|
|
|
input, err = defaultLoader("dns")
|
|
if err != nil {
|
|
t.Errorf("Expected no error for valid Corefile, got: %v", err)
|
|
}
|
|
if input == nil {
|
|
t.Errorf("Expected non-nil input for valid Corefile")
|
|
} else {
|
|
caddyInput, ok := input.(caddy.CaddyfileInput)
|
|
if !ok {
|
|
t.Errorf("Expected input to be caddy.CaddyfileInput")
|
|
}
|
|
if string(caddyInput.Contents) != string(testContents) {
|
|
t.Errorf("Expected contents %q, got %q", testContents, caddyInput.Contents)
|
|
}
|
|
if caddyInput.ServerTypeName != "dns" {
|
|
t.Errorf("Expected ServerTypeName to be %q, got %q", "dns", caddyInput.ServerTypeName)
|
|
}
|
|
}
|
|
|
|
if runtime.GOOS != "windows" {
|
|
// Create a file but make it unreadable
|
|
tmpFile := filepath.Join(tmpDir, "Corefile")
|
|
if err := os.WriteFile(tmpFile, []byte("test"), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file: %v", err)
|
|
}
|
|
if err := os.Chmod(tmpFile, 0000); err != nil {
|
|
t.Fatalf("Failed to change permissions: %v", err)
|
|
}
|
|
|
|
// Root reads a 0000 file regardless of its mode, so there is no error
|
|
// to expect. CI runs as root in a container.
|
|
if os.Geteuid() == 0 {
|
|
t.Skip("running as root: file permissions deny nothing")
|
|
}
|
|
|
|
input, err = defaultLoader("dns")
|
|
if err == nil {
|
|
t.Error("Expected error for unreadable Corefile but got none")
|
|
}
|
|
if input != nil {
|
|
t.Error("Expected nil input for unreadable Corefile")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVersionString(t *testing.T) {
|
|
caddy.AppName = "TestApp"
|
|
caddy.AppVersion = "1.0.0"
|
|
|
|
expected := "TestApp-1.0.0\n"
|
|
result := versionString()
|
|
|
|
if result != expected {
|
|
t.Errorf("Expected version string %q, got %q", expected, result)
|
|
}
|
|
}
|
|
|
|
func TestReleaseString(t *testing.T) {
|
|
GitCommit = "a6d2d7b5"
|
|
|
|
expected := runtime.GOOS + "/" + runtime.GOARCH + ", " + runtime.Version() + ", " + GitCommit + "\n"
|
|
result := releaseString()
|
|
|
|
if result != expected {
|
|
t.Errorf("Expected release string %q, got %q", expected, result)
|
|
}
|
|
}
|
|
|
|
func TestSetVersion(t *testing.T) {
|
|
// Test case 1: Development build with nearest tag
|
|
gitTag = ""
|
|
gitNearestTag = "v1.2.3"
|
|
gitShortStat = "1 file changed"
|
|
GitCommit = "abcdef"
|
|
buildDate = "2023-05-01"
|
|
|
|
setVersion()
|
|
|
|
if !devBuild {
|
|
t.Errorf("Expected devBuild to be true with empty gitTag and non-empty gitShortStat")
|
|
}
|
|
|
|
expectedAppVersion := "1.2.3 (+abcdef 2023-05-01)"
|
|
if appVersion != expectedAppVersion {
|
|
t.Errorf("Expected appVersion to be %q, got %q", expectedAppVersion, appVersion)
|
|
}
|
|
|
|
// Test case 2: Release build with tag
|
|
gitTag = "v2.0.0"
|
|
gitNearestTag = "v1.9.0"
|
|
gitShortStat = ""
|
|
|
|
setVersion()
|
|
|
|
if devBuild {
|
|
t.Errorf("Expected devBuild to be false with non-empty gitTag and empty gitShortStat")
|
|
}
|
|
|
|
expectedAppVersion = "2.0.0"
|
|
if appVersion != expectedAppVersion {
|
|
t.Errorf("Expected appVersion to be %q, got %q", expectedAppVersion, appVersion)
|
|
}
|
|
|
|
// Test case 3: No tags available
|
|
gitTag = ""
|
|
gitNearestTag = ""
|
|
gitShortStat = ""
|
|
appVersion = "(untracked dev build)" // Reset to default
|
|
|
|
setVersion()
|
|
|
|
if !devBuild {
|
|
t.Errorf("Expected devBuild to be true with empty gitTag")
|
|
}
|
|
|
|
expectedAppVersion = "(untracked dev build)"
|
|
if appVersion != expectedAppVersion {
|
|
t.Errorf("Expected appVersion to be %q, got %q", expectedAppVersion, appVersion)
|
|
}
|
|
}
|
|
|
|
func TestShowVersion(t *testing.T) {
|
|
// Capture stdout
|
|
oldStdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
// Set test values
|
|
caddy.AppName = "TestApp"
|
|
caddy.AppVersion = "1.0.0"
|
|
GitCommit = "abc123"
|
|
|
|
// Test case 1: Non-dev build
|
|
devBuild = false
|
|
gitShortStat = ""
|
|
gitFilesModified = ""
|
|
|
|
showVersion()
|
|
|
|
// Restore stdout
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
|
|
var buf bytes.Buffer
|
|
io.Copy(&buf, r)
|
|
result := buf.String()
|
|
|
|
expected := fmt.Sprintf("TestApp-1.0.0\n%s/%s, %s, abc123\n", runtime.GOOS, runtime.GOARCH, runtime.Version())
|
|
if result != expected {
|
|
t.Errorf("Expected version output %q, got %q", expected, result)
|
|
}
|
|
|
|
// Test case 2: Dev build with modified files
|
|
oldStdout = os.Stdout
|
|
r, w, _ = os.Pipe()
|
|
os.Stdout = w
|
|
|
|
devBuild = true
|
|
gitShortStat = "1 file changed, 10 insertions(+), 5 deletions(-)"
|
|
gitFilesModified = "path/to/modified/file.go"
|
|
|
|
showVersion()
|
|
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
|
|
buf.Reset()
|
|
io.Copy(&buf, r)
|
|
result = buf.String()
|
|
|
|
expected = fmt.Sprintf("TestApp-1.0.0\n%s/%s, %s, abc123\n1 file changed, 10 insertions(+), 5 deletions(-)\npath/to/modified/file.go\n",
|
|
runtime.GOOS, runtime.GOARCH, runtime.Version())
|
|
if result != expected {
|
|
t.Errorf("Expected version output with dev build info:\n%q\ngot:\n%q", expected, result)
|
|
}
|
|
}
|