refactor: update recording filename format to include date

- Update `getRecordingPath` to use a timestamp format that includes the date (`20060102-150405.000`).
- Update `parseInteractionFile` and `getFullTimestamp` to handle both the new filename format and the legacy format for backward compatibility.
- Improved parsing logic to reliably extract date, time, and HTTP method from interaction filenames.
This commit is contained in:
Tobias Gesellchen
2026-02-24 11:49:04 +01:00
parent be762dbc22
commit 0090746b89
3 changed files with 329 additions and 23 deletions
+52 -23
View File
@@ -215,7 +215,7 @@ func (r *Recorder) getRecordingDir(category string, sanitizedSegments []string)
}
func (r *Recorder) getRecordingPath(dir, method string) string {
timestamp := time.Now().Format("15-04-05.000")
timestamp := time.Now().Format("20060102-150405.000")
count := atomic.AddUint64(&r.counter, 1)
filename := fmt.Sprintf("%04d-%s-%s.http", count, timestamp, method)
@@ -441,20 +441,44 @@ func (r *Recorder) parseInteractionFile(rel, path string, parts []string) (Inter
filename := parts[len(parts)-1]
fnParts := strings.Split(strings.TrimSuffix(filename, ".http"), "-")
date := ""
if len(sessionID) >= 8 {
date = sessionID[0:4] + "-" + sessionID[4:6] + "-" + sessionID[6:8]
timestamp := ""
method, counter := "UNKNOWN", 0
if len(fnParts) >= 1 {
_, _ = fmt.Sscanf(fnParts[0], "%d", &counter)
}
timestamp := ""
// Check if this is the new format: count-yyyyMMdd-HHMMSS.sss-method.http
// New format has 4 parts and the second part is 8 digits (yyyyMMdd)
if len(fnParts) == 4 && len(fnParts[1]) == 8 {
dateStr := fnParts[1] // yyyyMMdd
timeStr := fnParts[2] // HHMMSS.sss
method = fnParts[3]
// Format date: yyyyMMdd -> yyyy-MM-dd
date := dateStr[0:4] + "-" + dateStr[4:6] + "-" + dateStr[6:8]
// Format time: HHMMSS.sss -> HH:MM:SS.sss
if len(timeStr) >= 6 {
time := timeStr[0:2] + ":" + timeStr[2:4] + ":" + timeStr[4:]
timestamp = date + " " + time
}
} else if len(fnParts) >= 5 {
// Legacy format: count-HH-MM-SS.sss-method.http
// Extract date from sessionID for backward compatibility
date := ""
if len(sessionID) >= 8 {
date = sessionID[0:4] + "-" + sessionID[4:6] + "-" + sessionID[6:8]
}
if len(fnParts) >= 4 {
timeStr := fnParts[1] + ":" + fnParts[2] + ":" + fnParts[3]
timestamp = timeStr
if date != "" {
timestamp = date + " " + timeStr
}
method = fnParts[4]
}
requestPath := "/" + strings.Join(parts[2:len(parts)-1], "/")
@@ -462,15 +486,6 @@ func (r *Recorder) parseInteractionFile(rel, path string, parts []string) (Inter
requestPath = "/"
}
method, counter := "UNKNOWN", 0
if len(fnParts) >= 1 {
_, _ = fmt.Sscanf(fnParts[0], "%d", &counter)
}
if len(fnParts) >= 5 {
method = fnParts[4]
}
return Interaction{
ID: filename,
Session: sessionID,
@@ -485,18 +500,32 @@ func (r *Recorder) parseInteractionFile(rel, path string, parts []string) (Inter
}
func (r *Recorder) getFullTimestamp(sessionID, filename string) string {
if len(sessionID) < 8 {
return ""
}
date := sessionID[0:4] + "-" + sessionID[4:6] + "-" + sessionID[6:8]
fnParts := strings.Split(strings.TrimSuffix(filename, ".http"), "-")
if len(fnParts) < 4 {
return ""
// Check if this is the new format: count-yyyyMMdd-HHMMSS.sss-method.http
// New format has 4 parts and the second part is 8 digits (yyyyMMdd)
if len(fnParts) == 4 && len(fnParts[1]) == 8 {
dateStr := fnParts[1] // yyyyMMdd
timeStr := fnParts[2] // HHMMSS.sss
if len(timeStr) >= 6 {
date := dateStr[0:4] + "-" + dateStr[4:6] + "-" + dateStr[6:8]
time := timeStr[0:2] + "-" + timeStr[2:4] + "-" + timeStr[4:]
return date + "-" + time
}
} else if len(fnParts) >= 5 {
// Legacy format: count-HH-MM-SS.sss-method.http
if len(sessionID) < 8 {
return ""
}
date := sessionID[0:4] + "-" + sessionID[4:6] + "-" + sessionID[6:8]
return date + "-" + fnParts[1] + "-" + fnParts[2] + "-" + fnParts[3]
}
return date + "-" + fnParts[1] + "-" + fnParts[2] + "-" + fnParts[3]
return ""
}
func (r *Recorder) peekStatus(path string) int {
+96
View File
@@ -847,3 +847,99 @@ func TestRecorder_ListInteractions_FullTimestamp(t *testing.T) {
}
})
}
func TestRecorder_NewFilenameFormat_WithDate(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "recorder-new-format-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
r := NewRecorder(tmpDir)
sessionID := "20260223-150000-12345"
r.SessionID = sessionID
// Create recordings with the new format that includes date in filename
basePath := filepath.Join(tmpDir, "interactions", sessionID, "self", "test")
os.MkdirAll(basePath, 0755)
files := []string{
"0047-20260223-215306.128-GET.http",
"0048-20260223-215306.417-POST.http",
"0049-20260223-080034.500-GET.http",
"0050-20260223-080034.507-PUT.http",
}
for _, f := range files {
os.WriteFile(filepath.Join(basePath, f), []byte("test content"), 0644)
}
t.Run("Parse_New_Format_Timestamps", func(t *testing.T) {
interactions, err := r.ListInteractions(sessionID, "", "")
if err != nil {
t.Fatalf("ListInteractions failed: %v", err)
}
if len(interactions) != 4 {
t.Fatalf("Expected 4 interactions, got %d", len(interactions))
}
// Check that timestamps include both date and time from filename
expectedTimestamps := []string{
"2026-02-23 21:53:06.128",
"2026-02-23 21:53:06.417",
"2026-02-23 08:00:34.500",
"2026-02-23 08:00:34.507",
}
for i, interaction := range interactions {
if interaction.Timestamp != expectedTimestamps[i] {
t.Errorf("Expected timestamp %s, got %s for interaction %d",
expectedTimestamps[i], interaction.Timestamp, i)
}
}
})
t.Run("Parse_Methods_From_New_Format", func(t *testing.T) {
interactions, err := r.ListInteractions(sessionID, "", "")
if err != nil {
t.Fatalf("ListInteractions failed: %v", err)
}
expectedMethods := []string{"GET", "POST", "GET", "PUT"}
for i, interaction := range interactions {
if interaction.Method != expectedMethods[i] {
t.Errorf("Expected method %s, got %s for interaction %d",
expectedMethods[i], interaction.Method, i)
}
}
})
t.Run("Filter_By_New_Format_Timestamp", func(t *testing.T) {
// Filter for interactions after 10:00:00 on that day
interactions, err := r.ListInteractions(sessionID, "", "2026-02-23 10:00:00")
if err != nil {
t.Fatalf("ListInteractions failed: %v", err)
}
// Should get the two evening interactions (21:53:06.xxx)
if len(interactions) != 2 {
t.Fatalf("Expected 2 interactions after 10:00:00, got %d", len(interactions))
}
for _, interaction := range interactions {
if !strings.Contains(interaction.Timestamp, "21:53:06") {
t.Errorf("Expected evening timestamp, got %s", interaction.Timestamp)
}
}
})
t.Run("GetFullTimestamp_New_Format", func(t *testing.T) {
// Test the getFullTimestamp function directly
fullTS := r.getFullTimestamp(sessionID, "0047-20260223-215306.128-GET.http")
expected := "2026-02-23-21-53-06.128"
if fullTS != expected {
t.Errorf("Expected full timestamp %s, got %s", expected, fullTS)
}
})
}