check / check (push) Waiting to run
One progress reporter spans every path of a snapshot. Its counts of files and bytes processed run across all the paths, while the totals they were divided by were reset to each path's own, so a second path smaller than the first showed more than 100% and an ETA of `unknown`. The totals now add up over the paths scanned so far. The rate behind the ETA is measured from the bytes processed since the current path's scan phase ended, so a later path's scan phase does not lower it. SetTotalSize is renamed AddTotalSize because it now adds. The issue says the ETA went negative; it was computed negative and printed as `unknown`. Model: opus-5-5
95 lines
2.4 KiB
Go
95 lines
2.4 KiB
Go
package snapshot_test
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/spf13/afero"
|
|
"sneak.berlin/go/vaultik/internal/database"
|
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
|
)
|
|
|
|
// TestProgressPercentWithSecondPathSmaller backs up two paths with one
|
|
// scanner, as a snapshot with two paths does, the second path smaller
|
|
// than the first. The progress line divides the bytes processed by the
|
|
// total size, so both must count both paths to stay within 100%.
|
|
func TestProgressPercentWithSecondPathSmaller(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fs := afero.NewMemMapFs()
|
|
files := map[string]string{
|
|
"/large/one.txt": strings.Repeat("1", 4000),
|
|
"/large/two.txt": strings.Repeat("2", 4000),
|
|
"/small/three.txt": strings.Repeat("3", 1000),
|
|
}
|
|
|
|
for path, content := range files {
|
|
err := fs.MkdirAll(filepath.Dir(path), 0755)
|
|
if err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
|
|
err = afero.WriteFile(fs, path, []byte(content), 0644)
|
|
if err != nil {
|
|
t.Fatalf("write %s: %v", path, err)
|
|
}
|
|
}
|
|
|
|
db, err := database.NewTestDB()
|
|
if err != nil {
|
|
t.Fatalf("create test db: %v", err)
|
|
}
|
|
|
|
t.Cleanup(func() {
|
|
cerr := db.Close()
|
|
if cerr != nil {
|
|
t.Errorf("close db: %v", cerr)
|
|
}
|
|
})
|
|
|
|
repos := database.NewRepositories(db)
|
|
|
|
scanner := snapshot.NewScanner(snapshot.ScannerConfig{
|
|
FS: fs,
|
|
ChunkSize: int64(1024 * 16),
|
|
Repositories: repos,
|
|
MaxBlobSize: int64(1024 * 1024),
|
|
CompressionLevel: 3,
|
|
AgeRecipients: []string{testAgePublicKey},
|
|
EnableProgress: true,
|
|
})
|
|
|
|
// Never started, but Stop releases its tickers and signal handler.
|
|
progress := scanner.GetProgress()
|
|
defer progress.Stop()
|
|
|
|
ctx := context.Background()
|
|
snapshotID := "test-snapshot-progress"
|
|
createTestSnapshotRecord(ctx, t, repos, snapshotID)
|
|
|
|
for _, path := range []string{"/large", "/small"} {
|
|
_, err := scanner.Scan(ctx, path, snapshotID)
|
|
if err != nil {
|
|
t.Fatalf("scanning %s: %v", path, err)
|
|
}
|
|
}
|
|
|
|
stats := progress.GetStats()
|
|
|
|
// Directories count toward the total size but produce no chunks, so
|
|
// the percentage ends just under 100%.
|
|
percent := float64(stats.BytesProcessed.Load()) /
|
|
float64(stats.TotalSize.Load()) * 100
|
|
if percent > 100 {
|
|
t.Errorf("progress after both paths is %.1f%%, want at most 100%%",
|
|
percent)
|
|
}
|
|
|
|
if stats.FilesProcessed.Load() != stats.TotalFiles.Load() {
|
|
t.Errorf("progress after both paths is %d of %d files, want all",
|
|
stats.FilesProcessed.Load(), stats.TotalFiles.Load())
|
|
}
|
|
}
|