Borg/pkg/failures/manager_test.go
google-labs-jules[bot] 46ffec7071 feat: Implement failure reporting and dead letter queue
This change introduces a new failure handling system for collection tasks.

- Created a new package `pkg/failures` to manage failure reporting, including a `Manager` to handle the lifecycle of a failure report, and `Failure` and `FailureReport` structs for storing failure data. The manager creates a `.borg-failures/<timestamp>` directory for each run, containing a `failures.json` report and a `retry.sh` script.
- Added a `borg failures` command with `show` and `clear` subcommands to manage failure reports.
- Added a `borg retry` command to retry failed collections.
- Added `--on-failure` and `--failures-dir` flags to the `collect` command.
- Refactored the `collect github repo` command to make the single-repository cloning logic reusable.
- Updated the `collect github repos` command to use the reusable cloning function and implement failure handling, including the `--on-failure=stop` and `--on-failure=prompt` options.
- Implemented failure categorization to distinguish between retryable and permanent failures.
- Implemented tracking of the number of attempts for each failed item.
- Created a placeholder file for a missing asset to fix the build.

Co-authored-by: Snider <631881+Snider@users.noreply.github.com>
2026-02-02 00:53:35 +00:00

74 lines
1.8 KiB
Go

package failures
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
)
func TestManager(t *testing.T) {
tempDir, err := os.MkdirTemp("", "borg-failures-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
manager, err := NewManager(tempDir, "test-collection")
if err != nil {
t.Fatalf("failed to create manager: %v", err)
}
manager.SetTotal(1)
manager.RecordFailure(&Failure{
URL: "http://example.com/failed",
Error: "test error",
Retryable: true,
})
if err := manager.Finalize(); err != nil {
t.Fatalf("failed to finalize manager: %v", err)
}
// Verify failures.json
reportPath := filepath.Join(manager.runDir, "failures.json")
if _, err := os.Stat(reportPath); os.IsNotExist(err) {
t.Fatalf("failures.json was not created")
}
data, err := os.ReadFile(reportPath)
if err != nil {
t.Fatalf("failed to read failures.json: %v", err)
}
var report FailureReport
if err := json.Unmarshal(data, &report); err != nil {
t.Fatalf("failed to unmarshal failures.json: %v", err)
}
if report.Collection != "test-collection" {
t.Errorf("expected collection 'test-collection', got '%s'", report.Collection)
}
if len(report.Failures) != 1 {
t.Fatalf("expected 1 failure, got %d", len(report.Failures))
}
if report.Failures[0].URL != "http://example.com/failed" {
t.Errorf("unexpected failure URL: %s", report.Failures[0].URL)
}
// Verify retry.sh
retryPath := filepath.Join(manager.runDir, "retry.sh")
if _, err := os.Stat(retryPath); os.IsNotExist(err) {
t.Fatalf("retry.sh was not created")
}
retryScript, err := os.ReadFile(retryPath)
if err != nil {
t.Fatalf("failed to read retry.sh: %v", err)
}
if !strings.Contains(string(retryScript), "http://example.com/failed") {
t.Errorf("retry.sh does not contain the failed URL")
}
}