Добавлены новые возможности для работы с файловыми логами Docker-сервисов: - Эндпоинты для получения списка логов и хвоста лог-файла. - Очистка лог-файлов с возможностью выбора режима (truncate или delete) и запись в аудит очистки. - Обновлена документация и конфигурация для поддержки новых функций. Co-authored-by: Cursor <[email protected]>
139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package runtimelogs
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"evobgp/internal/store"
|
|
)
|
|
|
|
func testService(t *testing.T) (*Service, string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
svc := NewService(Config{RootDir: dir, ServiceName: ServiceNameAll})
|
|
if !svc.Available() {
|
|
t.Fatal("expected available")
|
|
}
|
|
return svc, dir
|
|
}
|
|
|
|
func TestConfigEnabled(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if (Config{}).Enabled() {
|
|
t.Fatal("empty config")
|
|
}
|
|
if (Config{RootDir: dir, ServiceName: "evobgp-api"}).Enabled() {
|
|
t.Fatal("wrong service")
|
|
}
|
|
if !(Config{RootDir: dir, ServiceName: ServiceNameAll}).Enabled() {
|
|
t.Fatal("expected enabled")
|
|
}
|
|
}
|
|
|
|
func TestListFiles(t *testing.T) {
|
|
svc, dir := testService(t)
|
|
if err := os.WriteFile(filepath.Join(dir, "evobgp-all.log"), []byte("line\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, ".hidden.log"), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "notes.txt"), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Mkdir(filepath.Join(dir, "subdir.log"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
items, err := svc.ListFiles()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(items) != 1 || items[0].Name != "evobgp-all.log" {
|
|
t.Fatalf("list: %+v", items)
|
|
}
|
|
}
|
|
|
|
func TestTailAndCleanup(t *testing.T) {
|
|
svc, dir := testService(t)
|
|
path := filepath.Join(dir, "postgres.log")
|
|
var b strings.Builder
|
|
for i := 0; i < 50; i++ {
|
|
b.WriteString("line\n")
|
|
}
|
|
if err := os.WriteFile(path, []byte(b.String()), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tail, err := svc.Tail("postgres.log", TailOptions{Lines: 3})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tail.LinesReturned != 3 || !strings.Contains(tail.Content, "line") {
|
|
t.Fatalf("tail: %+v", tail)
|
|
}
|
|
|
|
tailGrep, err := svc.Tail("postgres.log", TailOptions{Lines: 100, Grep: "nomatch"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tailGrep.LinesReturned != 0 {
|
|
t.Fatalf("grep filter: %+v", tailGrep)
|
|
}
|
|
|
|
before, after, err := svc.Cleanup("postgres.log", store.RuntimeLogCleanupTruncate)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if before <= 0 || after == nil || *after != 0 {
|
|
t.Fatalf("truncate: before=%d after=%v", before, after)
|
|
}
|
|
st, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if st.Size() != 0 {
|
|
t.Fatalf("expected empty file, size=%d", st.Size())
|
|
}
|
|
|
|
if err := os.WriteFile(path, []byte("again\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, _, err = svc.Cleanup("postgres.log", store.RuntimeLogCleanupDelete)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
t.Fatalf("expected deleted, stat err=%v", err)
|
|
}
|
|
}
|
|
|
|
func TestCleanupFileTooLarge(t *testing.T) {
|
|
svc, dir := testService(t)
|
|
path := filepath.Join(dir, "big.log")
|
|
if err := os.WriteFile(path, make([]byte, 1024), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Patch check by using a tiny max - we test the constant path via stat size.
|
|
// Use a file just over limit only in integration; here verify small file works.
|
|
_, _, err := svc.Cleanup("big.log", store.RuntimeLogCleanupTruncate)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestUnavailableWhenDisabled(t *testing.T) {
|
|
svc := NewService(Config{RootDir: "", ServiceName: ServiceNameAll})
|
|
if _, err := svc.ListFiles(); err != ErrUnavailable {
|
|
t.Fatalf("list: %v", err)
|
|
}
|
|
if _, err := svc.Tail("a.log", TailOptions{}); err != ErrUnavailable {
|
|
t.Fatalf("tail: %v", err)
|
|
}
|
|
if _, _, err := svc.Cleanup("a.log", store.RuntimeLogCleanupTruncate); err != ErrUnavailable {
|
|
t.Fatalf("cleanup: %v", err)
|
|
}
|
|
}
|