check / check (push) Waiting to run
Every backup now writes vaultik-destination.txt at the root of the backup destination store. While the local index holds snapshots, a destination without it is not present: snapshot create refuses before writing, prune and snapshot purge fail, and snapshot list and snapshot remove warn, as for a destination that cannot be listed. remote nuke deletes the marker last. The file:// backend no longer creates its destination directory and checks for it on every write. Tests that backed up into a directory they never created now use an existing one; fixtures standing for a written destination carry the marker. Judgement call: the marker is rewritten on every backup. Deviation: snapshot name selection moved out of CreateSnapshot unchanged, for the complexity limit. Model: opus-5-5
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package vaultik_test
|
|
|
|
import (
|
|
"context"
|
|
"maps"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/vaultik/internal/config"
|
|
"sneak.berlin/go/vaultik/internal/database"
|
|
"sneak.berlin/go/vaultik/internal/log"
|
|
"sneak.berlin/go/vaultik/internal/storage"
|
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
|
)
|
|
|
|
// A backup without --cron runs the progress reporter while one scanner
|
|
// scans each path of the snapshot in turn. See
|
|
// https://git.eeqj.de/sneak/vaultik/issues/253.
|
|
func TestBackupWithoutCronOfTwoPathSnapshotRestoresBothPaths(t *testing.T) {
|
|
log.Initialize(log.Config{})
|
|
t.Parallel()
|
|
|
|
const snapshotName = "data"
|
|
|
|
fs := afero.NewOsFs()
|
|
tempDir := t.TempDir()
|
|
firstDir := filepath.Join(tempDir, "first")
|
|
secondDir := filepath.Join(tempDir, "second")
|
|
storeDir := t.TempDir()
|
|
restoreDir := filepath.Join(tempDir, "restored")
|
|
dbPath := filepath.Join(tempDir, "index.sqlite")
|
|
|
|
ctx := context.Background()
|
|
files := writeFaultSourceTree(t, fs, firstDir)
|
|
maps.Copy(files, writeFaultSourceTree(t, fs, secondDir))
|
|
|
|
cfg := faultTestConfig()
|
|
cfg.IndexPath = dbPath
|
|
cfg.ChunkSize = config.Size(faultChunkSize)
|
|
cfg.Snapshots = map[string]config.SnapshotConfig{
|
|
snapshotName: {Paths: []string{firstDir, secondDir}},
|
|
}
|
|
|
|
store, err := storage.NewFileStorer(storeDir)
|
|
require.NoError(t, err)
|
|
|
|
db, err := database.New(ctx, dbPath)
|
|
require.NoError(t, err)
|
|
|
|
repos := database.NewRepositories(db)
|
|
v := newBackupVaultik(ctx, cfg, store, repos, db, fs)
|
|
|
|
require.NoError(t, v.CreateSnapshot(&vaultik.SnapshotCreateOptions{
|
|
Snapshots: []string{snapshotName},
|
|
}))
|
|
|
|
id := localSnapshotID(ctx, t, repos, snapshotName)
|
|
require.NoError(t, db.Close())
|
|
|
|
reader := newReaderVaultik(ctx, cfg, store, nil, fs)
|
|
require.NoError(t, reader.Restore(&vaultik.RestoreOptions{
|
|
SnapshotID: id,
|
|
TargetDir: restoreDir,
|
|
Verify: true,
|
|
}))
|
|
|
|
assertRestoredTree(t, fs, restoreDir, files)
|
|
}
|