package models
import (
"bufio"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
)
type capTestStep struct{}
func (capTestStep) Name() string { return "build" }
func (capTestStep) Command() string { return "make" }
func (capTestStep) Kind() StepKind { return StepKindUser }
func TestLogPastTheCapIsDroppedWithOneMarker(t *testing.T) {
dir := t.TempDir()
wid := testWorkflowId("capped")
const maxBytes = 100 << 10
logger, err := NewFileWorkflowLogger(dir, wid, nil, WithMaxLogBytes(maxBytes))
if err != nil {
t.Fatal(err)
}
out := logger.DataWriter(0, "stdout")
line := []byte(strings.Repeat("x", 1000) + "\n")
for range 1000 {
if _, err := out.Write(line); err != nil {
t.Fatal(err)
}
}
if _, err := logger.EndWriter(0, capTestStep{}, StepOutcomeSuccess).Write(nil); err != nil {
t.Fatal(err)
}
if err := logger.Close(); err != nil {
t.Fatal(err)
}
path := filepath.Join(dir, wid.String()+".log")
info, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
if info.Size() > maxBytes+4<<10 {
t.Fatalf("log is %d bytes, want at most %d plus a line and a marker", info.Size(), maxBytes)
}
f, err := os.Open(path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
var markers int
var last LogLine
sc := bufio.NewScanner(f)
for sc.Scan() {
last = LogLine{}
if err := json.Unmarshal(sc.Bytes(), &last); err != nil {
t.Fatal(err)
}
if strings.HasPrefix(last.Content, "log truncated") {
markers++
}
}
if markers != 1 {
t.Fatalf("%d truncation markers, want 1", markers)
}
if last.Kind != LogKindControl || last.StepStatus != StepStatusEnd {
t.Fatalf("last line = %+v, want the step end line to survive the cap", last)
}
}
func TestWriterDropsOutputPastTheCapWithoutBufferingIt(t *testing.T) {
logger, err := NewFileWorkflowLogger(t.TempDir(), testWorkflowId("cap-buffer"), nil, WithMaxLogBytes(1<<10))
if err != nil {
t.Fatal(err)
}
w := logger.DataWriter(0, "stdout").(*dataWriter)
if _, err := w.Write([]byte(strings.Repeat("x", 2<<10) + "\n")); err != nil {
t.Fatal(err)
}
if _, err := w.Write([]byte("no newline yet")); err != nil {
t.Fatal(err)
}
if len(w.pending) != 0 {
t.Fatalf("%d bytes are buffered after the log hit its cap, want none", len(w.pending))
}
if err := logger.Close(); err != nil {
t.Fatal(err)
}
}