diff options
| author | Paul Buetow <paul@buetow.org> | 2026-07-22 23:51:18 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-07-22 23:51:18 +0300 |
| commit | 849951be1d1a7ee9f9302006ccb187bf5b4e36f3 (patch) | |
| tree | 496c924a03a9ea6212e29bb4699e268066ebad81 /internal/io/dlog/rawlog_test.go | |
| parent | bf78b3abffee6d49c08ca2980156afc455994969 (diff) | |
feat: DTail fork — server/client feature development
Squashed development of the snonux/dtail fork's product code (internal/, cmd/)
since diverging from mimecast/dtail. Major areas:
- Read/output path: the former "turbo" channel-less path is now the single,
default server-side read/output path for cat/grep/tail and MapReduce; the old
channel-based path and its config/env toggles were removed.
- MapReduce: single aggregate implementation (server + serverless) fed directly
by a processor pipeline, with input-exhausted finalization via the shutdown
coordinator; high-concurrency and data-race fixes.
- Journal source reads (journal:unit.service) via journalctl, Linux-gated behind
a journal-v1 capability.
- Auth-key fast reconnect: in-memory per-user public-key cache with TTL/max-keys,
registered over an authenticated session (AUTHKEY), checked before
authorized_keys.
- Interactive query reload (--interactive-query) with SESSION START/UPDATE
generation boundaries and capability negotiation.
- Client-side deadlines: --timeout / --shutdownAfter as context deadlines;
follow shutdown handling.
- Client logging: diagnostics-only daily log by default, opt-in payload tee via
--log-payload.
- Numerous correctness fixes (buffer-pool double-recycle races, EOF-sentinel
leaks, glob-expansion cap, TOCTOU in CSV parsing) with accompanying unit tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/io/dlog/rawlog_test.go')
| -rw-r--r-- | internal/io/dlog/rawlog_test.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/internal/io/dlog/rawlog_test.go b/internal/io/dlog/rawlog_test.go new file mode 100644 index 0000000..7fb7a05 --- /dev/null +++ b/internal/io/dlog/rawlog_test.go @@ -0,0 +1,76 @@ +package dlog + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/mimecast/dtail/internal/config" + "github.com/mimecast/dtail/internal/io/dlog/loggers" +) + +// recordingLogger records whether a message arrived via the diagnostic (Log) +// path or the payload (Raw) path, so the test can assert how RawLog vs Raw route +// their messages. It reports SupportsColors()=false so the callers take their +// non-color branch (logger.Log / logger.Raw), which is what the routing test +// needs to observe. +type recordingLogger struct { + mutex sync.Mutex + logs []string + raws []string +} + +func (r *recordingLogger) Log(now time.Time, message string) { + r.mutex.Lock() + defer r.mutex.Unlock() + r.logs = append(r.logs, message) +} +func (r *recordingLogger) LogWithColors(now time.Time, message, colored string) { r.Log(now, message) } +func (r *recordingLogger) Raw(now time.Time, message string) { + r.mutex.Lock() + defer r.mutex.Unlock() + r.raws = append(r.raws, message) +} +func (r *recordingLogger) RawWithColors(now time.Time, message, colored string) { r.Raw(now, message) } +func (r *recordingLogger) Start(ctx context.Context, wg *sync.WaitGroup) { wg.Done() } +func (r *recordingLogger) Flush() {} +func (r *recordingLogger) Pause() {} +func (r *recordingLogger) Resume() {} +func (r *recordingLogger) Rotate() {} +func (r *recordingLogger) SupportsColors() bool { return false } + +var _ loggers.Logger = (*recordingLogger)(nil) + +// TestRawLogUsesDiagnosticSink is the regression guard for the ReportServerError +// footgun: a server-error audit line must go through the diagnostic (Log) sink, +// not the payload (Raw) sink. Only the Log sink is written to the client log file +// by default (Client.LogPayload=false gates the Raw/payload sink out of the file), +// so a server error routed via Raw would silently vanish from the on-disk audit +// trail. This asserts RawLog -> Log and, for contrast, Raw -> Raw. +func TestRawLogUsesDiagnosticSink(t *testing.T) { + prevClient := config.Client + config.Client = &config.ClientConfig{TermColorsEnable: false} + t.Cleanup(func() { config.Client = prevClient }) + + rec := &recordingLogger{} + d := &DLog{logger: rec} + + const serverError = "SERVER|srv1|ERROR|journal file targets require server capability journal-v1" + d.RawLog(serverError) + + if len(rec.logs) != 1 || rec.logs[0] != serverError { + t.Fatalf("RawLog must reach the diagnostic (Log) sink verbatim; got logs=%v raws=%v", + rec.logs, rec.raws) + } + if len(rec.raws) != 0 { + t.Fatalf("RawLog must NOT use the payload (Raw) sink (it would be gated out of the file); got raws=%v", + rec.raws) + } + + // Contrast: bulk payload still goes through the Raw/payload sink. + d.Raw("payload-line\n") + if len(rec.raws) != 1 || rec.raws[0] != "payload-line\n" { + t.Fatalf("Raw must reach the payload (Raw) sink; got raws=%v", rec.raws) + } +} |
