package logging import ( "encoding/json" "os" "path/filepath" "strings" "testing" "go.uber.org/zap" ) func TestFileOutputAndLevel(t *testing.T) { dir := t.TempDir() logger, closeLogs, err := New(Options{dir, "warn", 1, 2, 1}) if err != nil { t.Fatal(err) } logger.Info("filtered") logger.Warn("request rejected", zap.String("request_id", "test-request"), zap.Int("status", 409)) closeLogs() data, err := os.ReadFile(filepath.Join(dir, "veyra.log")) if err != nil { t.Fatal(err) } var row struct { Level, Message, RequestID string Status int } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { t.Fatal(err) } _ = json.Unmarshal(fields["level"], &row.Level) _ = json.Unmarshal(fields["message"], &row.Message) _ = json.Unmarshal(fields["request_id"], &row.RequestID) _ = json.Unmarshal(fields["status"], &row.Status) if row.Level != "warn" || row.Message != "request rejected" || row.RequestID != "test-request" || row.Status != 409 || strings.Contains(string(data), "filtered") { t.Fatalf("invalid structured log: %s", data) } info, err := os.Stat(filepath.Join(dir, "veyra.log")) if err != nil || info.Mode().Perm() != 0600 { t.Fatal("log file must be private") } } func TestLogRotation(t *testing.T) { dir := t.TempDir() stdout := os.Stdout discard, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) if err != nil { t.Fatal(err) } defer discard.Close() os.Stdout = discard logger, closeLogs, err := New(Options{dir, "info", 1, 2, 1}) os.Stdout = stdout if err != nil { t.Fatal(err) } defer closeLogs() for i := 0; i < 3; i++ { logger.Info("rotation", zap.String("payload", strings.Repeat("x", 400000))) } entries, err := os.ReadDir(dir) if err != nil { t.Fatal(err) } found := false for _, entry := range entries { if strings.HasPrefix(entry.Name(), "veyra-") { found = true } } if !found { t.Fatal("exceeding size must rotate the log") } } func TestCannotOpenLogs(t *testing.T) { path := filepath.Join(t.TempDir(), "file") if err := os.WriteFile(path, nil, 0600); err != nil { t.Fatal(err) } if _, _, err := New(Options{path, "info", 1, 1, 1}); err == nil { t.Fatal("unwritable log directory must fail startup") } }