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