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) } }