package nginx_log import ( "sync" "testing" "time" ) // TestForceReindexFileGroupSingleNotification tests that ForceReindexFileGroup only sends one completion notification per log group func TestForceReindexFileGroupSingleNotification(t *testing.T) { // This test simulates what happens in real scenario from your logs mainLogPath := "/var/log/nginx/access.log" // Test that IndexLogFileFull called with main log path works correctly // This mimics what ForceReindexFileGroup should do: queue one task per log group, not per file // Create a mock scenario where IndexLogFileFull is called directly with mainLogPath // This simulates the fix where ForceReindexFileGroup queues a single task logFiles := []struct { path string compressed bool lines int64 }{ {"/var/log/nginx/access.log", false, 1210}, {"/var/log/nginx/access.log.1", false, 1505}, {"/var/log/nginx/access.log.2.gz", true, 2975}, {"/var/log/nginx/access.log.3.gz", true, 1541}, {"/var/log/nginx/access.log.4.gz", true, 5612}, {"/var/log/nginx/access.log.5.gz", true, 2389}, } // This test validates that processing a complete log group results in only one completion notification // Test scenario: Single call to process entire log group // This is what should happen with the fix tracker := GetProgressTracker(mainLogPath) // Add all files to the progress tracker (simulating IndexLogFileFull discovery) for _, file := range logFiles { tracker.AddFile(file.path, file.compressed) tracker.SetFileEstimate(file.path, file.lines) } // Simulate concurrent processing of all files (like indexSingleFileForGroup would do) var wg sync.WaitGroup for i, file := range logFiles { wg.Add(1) go func(f struct { path string compressed bool lines int64 }, index int) { defer wg.Done() // Simulate processing delay time.Sleep(time.Duration(index*50) * time.Millisecond) tracker.StartFile(f.path) // Simulate processing for progress := int64(100); progress <= f.lines; progress += 100 { tracker.UpdateFileProgress(f.path, progress) time.Sleep(time.Millisecond) } tracker.CompleteFile(f.path, f.lines) t.Logf("Completed processing file: %s (%d lines)", f.path, f.lines) }(file, i) } wg.Wait() // Allow time for all notifications to be processed time.Sleep(50 * time.Millisecond) // Verify final state percentage, stats := tracker.GetProgress() if percentage != 100 { t.Errorf("Expected 100%% progress, got %.2f%%", percentage) } if stats.CompletedFiles != 6 { t.Errorf("Expected 6 completed files, got %d", stats.CompletedFiles) } if !stats.IsCompleted { t.Errorf("Expected IsCompleted to be true") } expectedTotalLines := int64(1210 + 1505 + 2975 + 1541 + 5612 + 2389) if stats.ProcessedLines != expectedTotalLines { t.Errorf("Expected %d processed lines, got %d", expectedTotalLines, stats.ProcessedLines) } RemoveProgressTracker(mainLogPath) t.Logf("✅ SUCCESS: Single completion notification verified for log group with %d files", len(logFiles)) }