package models
import (
"path/filepath"
"strings"
"testing"
)
func TestDataWriterBoundsPendingWithoutNewlines(t *testing.T) {
dir := t.TempDir()
wid := testWorkflowId("no-newline")
logger, err := NewFileWorkflowLogger(dir, wid, []string{"a-secret-with-a-long-window"})
if err != nil {
t.Fatal(err)
}
w := logger.DataWriter(0, "stdout").(*dataWriter)
const total = 4 << 20
const bound = 128 << 10
chunk := []byte(strings.Repeat("x", 16))
for written := 0; written < total; written += len(chunk) {
if _, err := w.Write(chunk); err != nil {
t.Fatal(err)
}
if len(w.pending) > bound {
t.Fatalf("pending grew to %d bytes after %d bytes with no newline, want at most %d", len(w.pending), written+len(chunk), bound)
}
}
if err := logger.Close(); err != nil {
t.Fatal(err)
}
got := strings.Join(readDataContents(t, filepath.Join(dir, wid.String()+".log")), "")
if got != strings.Repeat("x", total) {
t.Fatalf("split lines lost or changed output: got %d bytes, want %d", len(got), total)
}
}
func TestDataWriterKeepsLinesAfterAVeryLongOne(t *testing.T) {
dir := t.TempDir()
wid := testWorkflowId("long-line")
logger, err := NewFileWorkflowLogger(dir, wid, nil)
if err != nil {
t.Fatal(err)
}
w := logger.DataWriter(0, "stdout")
long := strings.Repeat("a", 200<<10)
if _, err := w.Write([]byte(long + "\nsecond\nthird")); err != nil {
t.Fatal(err)
}
if err := logger.Close(); err != nil {
t.Fatal(err)
}
got := readDataContents(t, filepath.Join(dir, wid.String()+".log"))
if len(got) < 3 || got[len(got)-2] != "second" || got[len(got)-1] != "third" {
t.Fatalf("lines after the long one changed, got %d lines", len(got))
}
if joined := strings.Join(got[:len(got)-2], ""); joined != long {
t.Fatalf("long line changed: got %d bytes, want %d", len(joined), len(long))
}
}
func TestDataWriterMasksSecretAcrossForcedSplit(t *testing.T) {
dir := t.TempDir()
secret := "hunter2-super-secret-token"
wid := testWorkflowId("forced-split")
logger, err := NewFileWorkflowLogger(dir, wid, []string{secret})
if err != nil {
t.Fatal(err)
}
w := logger.DataWriter(0, "stdout")
input := strings.Repeat("x", 64<<10-10) + secret + strings.Repeat("y", 1000)
for i := 0; i < len(input); i += 7 {
if _, err := w.Write([]byte(input[i:min(i+7, len(input))])); err != nil {
t.Fatal(err)
}
}
if err := logger.Close(); err != nil {
t.Fatal(err)
}
got := strings.Join(readDataContents(t, filepath.Join(dir, wid.String()+".log")), "")
if strings.Contains(got, secret[:8]) {
t.Fatalf("a piece of the secret reached the log")
}
if want := strings.Repeat("x", 64<<10-10) + "***" + strings.Repeat("y", 1000); got != want {
t.Fatalf("masked output changed: got %d bytes, want %d", len(got), len(want))
}
}