check / check (push) Canceled after 0s
The file and rclone listings skip an object whose name ends in `.partial`, the temporary name a `file://` or rclone upload writes before moving the object into place. `remote nuke` deletes only what the listings return, so it left the `.partial` objects killed uploads leave behind and still reported the destination store empty. Storer gains DeletePartialUploads. The file and rclone backends remove every `.partial` object under the prefix; S3 has none to remove, since it shows an object only once its upload completes. `remote nuke` calls it for `metadata/` and `blobs/` as its last step. Empty directories under a `file://` destination are still left behind. Model: opus-5-5
65 lines
1.6 KiB
Go
65 lines
1.6 KiB
Go
package vaultik_test
|
|
|
|
import (
|
|
"context"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/vaultik/internal/log"
|
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
|
)
|
|
|
|
// TestNukeRemoteLeavesNoFiles checks that remote nuke leaves no file
|
|
// under a file:// destination, including the `.partial` files uploads
|
|
// killed part-way leave next to a snapshot's metadata and next to where a
|
|
// blob would have been.
|
|
func TestNukeRemoteLeavesNoFiles(t *testing.T) {
|
|
log.Initialize(log.Config{})
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
storeDir := filepath.Join(t.TempDir(), "store")
|
|
v, repos, _ := backUpToFileDestination(ctx, t, storeDir)
|
|
|
|
snapshots, err := repos.Snapshots.ListRecent(ctx, listRecentTestLimit)
|
|
require.NoError(t, err)
|
|
require.Len(t, snapshots, 1)
|
|
|
|
snapshotKey := snapshot.RemoteSnapshotKey(snapshots[0].ID.String())
|
|
hash := testBlobHashA
|
|
leftovers := []string{
|
|
filepath.Join(storeDir, "metadata", snapshotKey,
|
|
"db.zst.age-123456.partial"),
|
|
filepath.Join(storeDir, "blobs", hash[:2], hash[2:4],
|
|
hash+"-123456.partial"),
|
|
}
|
|
|
|
for _, leftover := range leftovers {
|
|
require.NoError(t, os.MkdirAll(filepath.Dir(leftover), 0o750))
|
|
require.NoError(t, os.WriteFile(leftover, []byte("half an upload"), 0o600))
|
|
}
|
|
|
|
require.NoError(t, v.NukeRemote(true))
|
|
|
|
var files []string
|
|
|
|
err = filepath.WalkDir(storeDir,
|
|
func(path string, entry fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !entry.IsDir() {
|
|
files = append(files, path)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Empty(t, files)
|
|
}
|