package vaultik_test import ( "bytes" "context" "path/filepath" "testing" "time" "github.com/spf13/afero" "github.com/stretchr/testify/require" "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 file rewritten with its size unchanged and a new mtime in the same // second as the mtime the index holds must still be backed up. See // https://git.eeqj.de/sneak/vaultik/issues/226. func TestBackupOfSameSecondRewriteRestoresNewContent(t *testing.T) { log.Initialize(log.Config{}) t.Parallel() fs := afero.NewOsFs() tempDir := t.TempDir() dataDir := filepath.Join(tempDir, "src") storeDir := filepath.Join(tempDir, "remote") restoreDir := filepath.Join(tempDir, "restored") dbPath := filepath.Join(tempDir, "index.sqlite") rewrittenPath := filepath.Join(dataDir, "small.txt") ctx := context.Background() files := writeFaultSourceTree(t, fs, dataDir) cfg := changedFileConfig(dataDir, dbPath) firstMTime := time.Date(2026, time.January, 2, 3, 4, 5, 0, time.UTC). Add(100 * time.Millisecond) secondMTime := firstMTime.Add(800 * time.Millisecond) require.NoError(t, fs.Chtimes(rewrittenPath, firstMTime, firstMTime)) 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, backUp(v, "first")) // Upper-casing ASCII text keeps its size. files[rewrittenPath] = bytes.ToUpper(files[rewrittenPath]) require.NoError(t, afero.WriteFile(fs, rewrittenPath, files[rewrittenPath], 0o644)) require.NoError(t, fs.Chtimes(rewrittenPath, secondMTime, secondMTime)) require.NoError(t, backUp(v, "second")) id := localSnapshotID(ctx, t, repos, "second") 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) }