|
@@ -7,14 +7,12 @@ import (
|
|
|
"testing"
|
|
"testing"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// writeAccessLogConfig points bin/config.json at the given access log path (use
|
|
|
|
|
-// "none" to disable), so GetAccessLogPath resolves it the way the job does.
|
|
|
|
|
-func writeAccessLogConfig(t *testing.T, accessPath string) {
|
|
|
|
|
|
|
+func writeLogConfig(t *testing.T, accessPath string, errorPath string) {
|
|
|
t.Helper()
|
|
t.Helper()
|
|
|
binDir := t.TempDir()
|
|
binDir := t.TempDir()
|
|
|
t.Setenv("XUI_BIN_FOLDER", binDir)
|
|
t.Setenv("XUI_BIN_FOLDER", binDir)
|
|
|
configData, err := json.Marshal(map[string]any{
|
|
configData, err := json.Marshal(map[string]any{
|
|
|
- "log": map[string]any{"access": accessPath},
|
|
|
|
|
|
|
+ "log": map[string]any{"access": accessPath, "error": errorPath},
|
|
|
})
|
|
})
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
t.Fatalf("marshal xray config: %v", err)
|
|
t.Fatalf("marshal xray config: %v", err)
|
|
@@ -24,32 +22,71 @@ func writeAccessLogConfig(t *testing.T, accessPath string) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func TestWipeAccessLog_TruncatesEnabledLog(t *testing.T) {
|
|
|
|
|
|
|
+func TestWipeXrayLogs_TruncatesEnabledLogs(t *testing.T) {
|
|
|
accessLog := filepath.Join(t.TempDir(), "access.log")
|
|
accessLog := filepath.Join(t.TempDir(), "access.log")
|
|
|
|
|
+ errorLog := filepath.Join(t.TempDir(), "error.log")
|
|
|
if err := os.WriteFile(accessLog, []byte("2026/06/23 12:00:00 from tcp:203.0.113.10:443 accepted\n"), 0o644); err != nil {
|
|
if err := os.WriteFile(accessLog, []byte("2026/06/23 12:00:00 from tcp:203.0.113.10:443 accepted\n"), 0o644); err != nil {
|
|
|
t.Fatalf("seed access log: %v", err)
|
|
t.Fatalf("seed access log: %v", err)
|
|
|
}
|
|
}
|
|
|
- writeAccessLogConfig(t, accessLog)
|
|
|
|
|
|
|
+ if err := os.WriteFile(errorLog, []byte("xray warning\n"), 0o644); err != nil {
|
|
|
|
|
+ t.Fatalf("seed error log: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ writeLogConfig(t, accessLog, errorLog)
|
|
|
|
|
|
|
|
- wipeAccessLog()
|
|
|
|
|
|
|
+ wipeXrayLogs()
|
|
|
|
|
|
|
|
- info, err := os.Stat(accessLog)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- t.Fatalf("access log should still exist: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
- if info.Size() != 0 {
|
|
|
|
|
- t.Fatalf("access log should be truncated to 0, got %d bytes", info.Size())
|
|
|
|
|
|
|
+ for _, logPath := range []string{accessLog, errorLog} {
|
|
|
|
|
+ info, err := os.Stat(logPath)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatalf("%s should still exist: %v", logPath, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if info.Size() != 0 {
|
|
|
|
|
+ t.Fatalf("%s should be truncated to 0, got %d bytes", logPath, info.Size())
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func TestWipeAccessLog_LeavesDisabledLogAlone(t *testing.T) {
|
|
|
|
|
- writeAccessLogConfig(t, "none")
|
|
|
|
|
|
|
+func TestWipeXrayLogs_LeavesDisabledLogsAlone(t *testing.T) {
|
|
|
|
|
+ writeLogConfig(t, "none", "none")
|
|
|
|
|
|
|
|
- // Must not panic or create a file literally named "none".
|
|
|
|
|
- wipeAccessLog()
|
|
|
|
|
|
|
+ wipeXrayLogs()
|
|
|
|
|
|
|
|
if _, err := os.Stat("none"); err == nil {
|
|
if _, err := os.Stat("none"); err == nil {
|
|
|
os.Remove("none")
|
|
os.Remove("none")
|
|
|
- t.Fatal(`wipeAccessLog must not create a file named "none"`)
|
|
|
|
|
|
|
+ t.Fatal(`wipeXrayLogs must not create a file named "none"`)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func TestPruneXrayLogs_TruncatesOnlyOversizedLogs(t *testing.T) {
|
|
|
|
|
+ oldMax := maxXrayLogBytes
|
|
|
|
|
+ maxXrayLogBytes = 8
|
|
|
|
|
+ defer func() { maxXrayLogBytes = oldMax }()
|
|
|
|
|
+
|
|
|
|
|
+ dir := t.TempDir()
|
|
|
|
|
+ accessLog := filepath.Join(dir, "access.log")
|
|
|
|
|
+ errorLog := filepath.Join(dir, "error.log")
|
|
|
|
|
+ if err := os.WriteFile(accessLog, []byte("small"), 0o644); err != nil {
|
|
|
|
|
+ t.Fatalf("seed access log: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := os.WriteFile(errorLog, []byte("large log line"), 0o644); err != nil {
|
|
|
|
|
+ t.Fatalf("seed error log: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ writeLogConfig(t, accessLog, errorLog)
|
|
|
|
|
+
|
|
|
|
|
+ NewPruneXrayLogsJob().Run()
|
|
|
|
|
+
|
|
|
|
|
+ accessInfo, err := os.Stat(accessLog)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatalf("access log should still exist: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if accessInfo.Size() != 5 {
|
|
|
|
|
+ t.Fatalf("small access log should be left alone, got %d bytes", accessInfo.Size())
|
|
|
|
|
+ }
|
|
|
|
|
+ errorInfo, err := os.Stat(errorLog)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatalf("error log should still exist: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if errorInfo.Size() != 0 {
|
|
|
|
|
+ t.Fatalf("oversized error log should be truncated, got %d bytes", errorInfo.Size())
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|