104 lines
2.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package collect
import (
"context"
"os"
"path/filepath"
"sync"
"testing"
"time"
"git.opencomputing.cn/yumoqing/host-metrics-collector/internal/checkpoint"
"git.opencomputing.cn/yumoqing/host-metrics-collector/internal/model"
)
func writeTempLog(t *testing.T, content string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "app.log")
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatalf("write temp log: %v", err)
}
return path
}
func TestLogTailReadOnceEmitsCompleteLines(t *testing.T) {
path := writeTempLog(t, "line one\nline two\n")
var mu sync.Mutex
var got []model.LogRecord
tail := NewLogTail(path, checkpoint.NewMemoryStore(), time.Second, func(r model.LogRecord) {
mu.Lock()
defer mu.Unlock()
got = append(got, r)
})
offset, partial := tail.readOnce(0, nil)
if offset != int64(len("line one\nline two\n")) {
t.Fatalf("offset = %d", offset)
}
if len(partial) != 0 {
t.Fatalf("partial = %q, want empty", partial)
}
mu.Lock()
defer mu.Unlock()
if len(got) != 2 || got[0].Message != "line one" || got[1].Message != "line two" {
t.Fatalf("records = %+v", got)
}
if got[0].Level != "INFO" {
t.Fatalf("level = %q, want INFO", got[0].Level)
}
}
func TestLogTailReadOnceKeepsPartialLine(t *testing.T) {
path := writeTempLog(t, "partial line")
tail := NewLogTail(path, checkpoint.NewMemoryStore(), time.Second, nil)
offset, partial := tail.readOnce(0, nil)
if offset != 0 {
t.Fatalf("offset = %d, want 0 (no newline yet)", offset)
}
if string(partial) != "partial line" {
t.Fatalf("partial = %q", partial)
}
}
func TestLogTailReadOnceHandlesTruncation(t *testing.T) {
path := writeTempLog(t, "old content longer\n")
tail := NewLogTail(path, checkpoint.NewMemoryStore(), time.Second, nil)
// 模拟文件被轮转/截断:offset 超出文件大小,应从头读取。
if err := os.WriteFile(path, []byte("new\n"), 0o644); err != nil {
t.Fatalf("truncate: %v", err)
}
offset, partial := tail.readOnce(100, []byte("tail"))
if offset != int64(len("new\n")) {
t.Fatalf("offset = %d, want %d", offset, len("new\n"))
}
if len(partial) != 0 {
t.Fatalf("partial = %q", partial)
}
}
func TestLogTailRunStopsOnContextCancel(t *testing.T) {
path := writeTempLog(t, "hello\n")
tail := NewLogTail(path, checkpoint.NewMemoryStore(), 10*time.Millisecond, nil)
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
go func() {
tail.Run(ctx)
close(done)
}()
// 等它至少消费一轮,再取消。
time.Sleep(50 * time.Millisecond)
cancel()
select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatalf("LogTail.Run did not stop after cancel")
}
}