diff --git a/coremain/run_test.go b/coremain/run_test.go new file mode 100644 index 000000000..7285aaf3c --- /dev/null +++ b/coremain/run_test.go @@ -0,0 +1,302 @@ +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() + if err := os.Chdir(tmpDir); err != nil { + t.Fatalf("Failed to change to temp directory: %v", err) + } + + // 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) + } + } + + // 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) + } + + 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) + } +}