Run the disk-full restore test again #210
@@ -680,18 +680,10 @@ func faultScannerFactory(
|
|||||||
|
|
||||||
// Scenario 5: the restore target runs out of space mid-file. Restore
|
// Scenario 5: the restore target runs out of space mid-file. Restore
|
||||||
// must fail with an out-of-space error, and must not leave a truncated
|
// must fail with an out-of-space error, and must not leave a truncated
|
||||||
// file at the target path presenting as a complete restore. Restore
|
// file at the target path presenting as a complete restore.
|
||||||
// today writes each file straight to its final path and does not remove
|
|
||||||
// it when a write fails, so the truncated file survives; deleting it is
|
|
||||||
// tracked by https://git.eeqj.de/sneak/vaultik/issues/163. Skipped until
|
|
||||||
// that lands, so the destination assertion below is recorded rather than
|
|
||||||
// dropped.
|
|
||||||
//
|
//
|
||||||
//nolint:paralleltest // installs the global logger via log.Initialize
|
//nolint:paralleltest // installs the global logger via log.Initialize
|
||||||
func TestRestoreReportsDiskFull(t *testing.T) {
|
func TestRestoreReportsDiskFull(t *testing.T) {
|
||||||
t.Skip("blocked on https://git.eeqj.de/sneak/vaultik/issues/163: " +
|
|
||||||
"a disk-full write leaves a truncated file at the target path " +
|
|
||||||
"instead of removing it")
|
|
||||||
log.Initialize(log.Config{})
|
log.Initialize(log.Config{})
|
||||||
|
|
||||||
osFS := afero.NewOsFs()
|
osFS := afero.NewOsFs()
|
||||||
@@ -717,10 +709,10 @@ func TestRestoreReportsDiskFull(t *testing.T) {
|
|||||||
id := fullFaultBackup(ctx, t, osFS, inner, cfg, repos, dataDir, dbPath, "diskfull")
|
id := fullFaultBackup(ctx, t, osFS, inner, cfg, repos, dataDir, dbPath, "diskfull")
|
||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
|
|
||||||
// Restore onto a filesystem that allows only a few bytes of file
|
// Restore onto a target that allows only a few bytes of file content:
|
||||||
// content: enough to create files, far too little to hold them.
|
// enough to create files, far too little to hold them.
|
||||||
budget := int64(8)
|
budget := int64(8)
|
||||||
quota := "aFS{Fs: osFS, remaining: &budget}
|
quota := "aFS{Fs: osFS, dir: restoreDir, remaining: &budget}
|
||||||
|
|
||||||
v := newReaderVaultik(ctx, cfg, inner, nil, quota)
|
v := newReaderVaultik(ctx, cfg, inner, nil, quota)
|
||||||
err = v.Restore(&vaultik.RestoreOptions{SnapshotID: id, TargetDir: restoreDir})
|
err = v.Restore(&vaultik.RestoreOptions{SnapshotID: id, TargetDir: restoreDir})
|
||||||
@@ -754,21 +746,26 @@ func assertRestoredTree(
|
|||||||
// budget is exhausted, mirroring a real ENOSPC.
|
// budget is exhausted, mirroring a real ENOSPC.
|
||||||
var errNoSpace = errors.New("no space left on device")
|
var errNoSpace = errors.New("no space left on device")
|
||||||
|
|
||||||
// quotaFS is an afero.Fs whose files may write only a fixed total number
|
// quotaFS is an afero.Fs on which files opened under dir may write only
|
||||||
// of content bytes before failing, simulating a full restore target. It
|
// a fixed total number of content bytes before failing, simulating a full
|
||||||
// wraps the interface so every method except Create delegates to the
|
// restore target. Every other method, and every file outside dir, goes
|
||||||
// real filesystem; only file writes are capped.
|
// straight to the real filesystem: restore also writes the decrypted
|
||||||
|
// metadata database under $TMPDIR through this filesystem, and capping
|
||||||
|
// that would fail the restore before it wrote anything to the target.
|
||||||
type quotaFS struct {
|
type quotaFS struct {
|
||||||
afero.Fs
|
afero.Fs
|
||||||
|
|
||||||
|
dir string
|
||||||
remaining *int64
|
remaining *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:ireturn // afero.Fs.Create's signature requires returning afero.File.
|
//nolint:ireturn // afero.Fs.OpenFile's signature requires returning afero.File.
|
||||||
func (q *quotaFS) Create(name string) (afero.File, error) {
|
func (q *quotaFS) OpenFile(
|
||||||
f, err := q.Fs.Create(name)
|
name string, flag int, perm os.FileMode,
|
||||||
if err != nil {
|
) (afero.File, error) {
|
||||||
return nil, err
|
f, err := q.Fs.OpenFile(name, flag, perm)
|
||||||
|
if err != nil || !strings.HasPrefix(name, q.dir) {
|
||||||
|
return f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return "aFile{File: f, remaining: q.remaining}, nil
|
return "aFile{File: f, remaining: q.remaining}, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user