Borg/cmd/repair_test.go
google-labs-jules[bot] dea068ec23 feat: Add initial implementation of archive verification and repair
This commit introduces the `borg verify` and `borg repair` commands to check the integrity of archives and repair them from a source URL.

Key changes:
- Added `cmd/verify.go` and `cmd/repair.go` with the new commands.
- Modified `pkg/datanode/datanode.go` to include a `manifest.json` file with SHA256 checksums for all files in the archive.
- Implemented archive structure validation, checksum verification, decryption testing for `.stim` files, and manifest completeness checks in the `verify` command.
- Implemented logic in the `repair` command to identify corrupted files and re-download them from a source URL.
- Added unit tests for the `verify` and `repair` commands.

The current implementation has known issues that were identified during a code review, including a critical bug that causes data corruption when repairing encrypted archives. A new plan has been created to address these issues. The code is being submitted in its current state to save progress.

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

66 lines
1.7 KiB
Go

package cmd
import (
"bytes"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/Snider/Borg/pkg/datanode"
"github.com/stretchr/testify/assert"
)
func TestRepairCmd_Good(t *testing.T) {
// Create a temporary directory for the test
tempDir := t.TempDir()
archivePath := filepath.Join(tempDir, "test.dat")
// Create a DataNode and add a file
dn := datanode.New()
dn.AddData("hello.txt", []byte("hello world"))
// Serialize the DataNode to a tarball
tarball, err := dn.ToTar()
assert.NoError(t, err)
// Corrupt the tarball
corruptedTarball := bytes.Replace(tarball, []byte("hello world"), []byte("hello mars!"), 1)
// Write the corrupted tarball to the archive file
err = os.WriteFile(archivePath, corruptedTarball, 0644)
assert.NoError(t, err)
// Create a mock HTTP server to serve the correct file
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/hello.txt" {
w.Write([]byte("hello world"))
} else {
http.NotFound(w, r)
}
}))
defer server.Close()
// Execute the repair command
cmd := NewRepairCmd()
b := bytes.NewBufferString("")
cmd.SetOut(b)
cmd.SetArgs([]string{archivePath, "--source", server.URL})
err = cmd.Execute()
// Assert that the command was successful
assert.NoError(t, err)
// Verify that the archive is now valid
verifyCmd := NewVerifyCmd()
b.Reset()
verifyCmd.SetOut(b)
verifyCmd.SetArgs([]string{archivePath})
err = verifyCmd.Execute()
assert.NoError(t, err)
output := b.String()
assert.Contains(t, output, "✓ Structure: valid")
assert.Contains(t, output, "✓ Checksums: 1/1 files OK")
assert.Contains(t, output, "✓ Manifest: complete")
}