cli/flightrecorder_internal_test.go
Rama main · réplica de lectura del repositorio original.
package cli
import (
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"cdr.dev/slog/v3"
"cdr.dev/slog/v3/sloggers/sloghuman"
)
func TestClampFlightRecorderSize(t *testing.T) {
t.Parallel()
cases := []struct {
in int64
want int64
}{
{in: -1, want: 0},
{in: 0, want: 0},
{in: 1000, want: 1000},
{in: maxCLIFlightRecorderSize, want: maxCLIFlightRecorderSize},
{in: maxCLIFlightRecorderSize + 1, want: maxCLIFlightRecorderSize},
}
for _, c := range cases {
require.Equal(t, c.want, clampFlightRecorderSize(c.in))
}
}
func TestPruneSessionLogs(t *testing.T) {
t.Parallel()
dir := t.TempDir()
base := time.Now()
const total = 55
for i := 0; i < total; i++ {
path := filepath.Join(dir, fmt.Sprintf("coder-ssh-%03d.log", i))
require.NoError(t, os.WriteFile(path, []byte("x"), 0o600))
// Older index => older modtime, so the highest indexes are newest.
modTime := base.Add(time.Duration(i) * time.Minute)
require.NoError(t, os.Chtimes(path, modTime, modTime))
}
// A non-matching file should never be pruned.
other := filepath.Join(dir, "unrelated.txt")
require.NoError(t, os.WriteFile(other, []byte("x"), 0o600))
pruneErr := pruneSessionLogs(dir, keepSessionLogFiles)
require.NoError(t, pruneErr)
remaining, err := filepath.Glob(filepath.Join(dir, "coder-*.log"))
require.NoError(t, err)
require.Len(t, remaining, keepSessionLogFiles)
// The oldest (lowest index) files were removed; the newest were kept.
require.NoFileExists(t, filepath.Join(dir, "coder-ssh-000.log"))
require.FileExists(t, filepath.Join(dir, fmt.Sprintf("coder-ssh-%03d.log", total-1)))
require.FileExists(t, other)
}
func TestPruneSessionLogs_ReturnsRemoveErrors(t *testing.T) {
t.Parallel()
if runtime.GOOS == "windows" {
t.Skip("a read-only directory does not prevent file removal on Windows, so os.Remove would not fail")
}
if os.Geteuid() == 0 {
t.Skip("root ignores directory permissions, so os.Remove would not fail")
}
dir := t.TempDir()
base := time.Now()
const total = 3
for i := 0; i < total; i++ {
path := filepath.Join(dir, fmt.Sprintf("coder-ssh-%03d.log", i))
require.NoError(t, os.WriteFile(path, []byte("x"), 0o600))
modTime := base.Add(time.Duration(i) * time.Minute)
require.NoError(t, os.Chtimes(path, modTime, modTime))
}
// Removing a file requires write permission on the containing directory, so a
// read-only dir forces os.Remove to fail. Restore perms before t.TempDir's
// cleanup (which runs after this LIFO-ordered cleanup) tries to remove it.
require.NoError(t, os.Chmod(dir, 0o500))
t.Cleanup(func() { _ = os.Chmod(dir, 0o700) })
err := pruneSessionLogs(dir, 1)
require.Error(t, err, "prune should return the remove failures")
}
func TestDefaultSessionLogDir(t *testing.T) {
t.Parallel()
require.True(t, strings.HasSuffix(
filepath.ToSlash(defaultSessionLogDir()), "coder/logs"),
"got %q", defaultSessionLogDir())
}
func TestFlightRecorder_RecordsUntilError(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &RootCmd{}
logger := r.flightRecorder(slog.Make(), sloghuman.Sink(&buf), 10)
ctx := context.Background()
logger.Debug(ctx, "recorded-debug")
logger.Sync()
require.NotContains(t, buf.String(), "recorded-debug",
"debug entry should be recorded, not written")
// Logging an error flushes the recorded history before the error entry.
logger.Error(ctx, "command failed for test")
logger.Sync()
got := buf.String()
require.Contains(t, got, "recorded-debug")
require.Contains(t, got, "command failed for test")
}
func TestFlightRecorder_FlushEmitsHistory(t *testing.T) {
t.Parallel()
// Flush is the path flightRecorderMiddleware uses to emit the recorded
// history on a returned error without logging a duplicate error line.
var buf bytes.Buffer
r := &RootCmd{}
logger := r.flightRecorder(slog.Make(), sloghuman.Sink(&buf), 10)
ctx := context.Background()
logger.Debug(ctx, "recorded-debug")
logger.Sync()
require.NotContains(t, buf.String(), "recorded-debug")
logger.Flush(ctx)
logger.Sync()
require.Contains(t, buf.String(), "recorded-debug")
}
func TestFlightRecorder_VerboseWritesDebug(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &RootCmd{verbose: true}
logger := r.flightRecorder(slog.Make(), sloghuman.Sink(&buf), 10)
logger.Debug(context.Background(), "verbose-debug")
logger.Sync()
require.Contains(t, buf.String(), "verbose-debug",
"verbose should write debug entries directly")
}