check / check (push) Successful in 26m13s
The status and progress lines of remote info and snapshot verify (shallow and deep) were written with stdoutf, so they had no marker and no color, unlike every other command's. They now go through Beginf, Completef and Progressf, as the README's output style section says. The reports stay plain, and --quiet and --json still drop these lines. Model: opus-5-5
151 lines
4.4 KiB
Go
151 lines
4.4 KiB
Go
package vaultik_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/vaultik/internal/log"
|
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
|
"sneak.berlin/go/vaultik/internal/ui"
|
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
|
)
|
|
|
|
// TestVerify_QuietSuppressesReport is the --quiet contract for
|
|
// `snapshot verify`: neither shallow nor deep verify writes its report,
|
|
// a failed verify still returns its error (which the cli layer prints
|
|
// on stderr), and the --json document still emits.
|
|
func TestVerify_QuietSuppressesReport(t *testing.T) {
|
|
log.Initialize(log.Config{})
|
|
t.Parallel()
|
|
|
|
fs := afero.NewOsFs()
|
|
tempDir := t.TempDir()
|
|
|
|
dataDir := filepath.Join(tempDir, "source")
|
|
storeDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "index.sqlite")
|
|
|
|
chunkSize := int64(32 * 1024)
|
|
maxBlobSize := int64(128 * 1024)
|
|
|
|
require.NoError(t, fs.MkdirAll(dataDir, 0o755))
|
|
require.NoError(t, afero.WriteFile(fs,
|
|
filepath.Join(dataDir, "data.bin"),
|
|
bytesPattern("quiet-", int(maxBlobSize*2)), 0o644))
|
|
|
|
ctx := context.Background()
|
|
|
|
cfg, storer, snapshotID := runFileStorageBackup(
|
|
ctx, t, fs, dataDir, storeDir, dbPath, chunkSize, maxBlobSize)
|
|
|
|
// The UI writes to the same buffer as Stdout, as both write to the
|
|
// process's stdout in production.
|
|
var stdout bytes.Buffer
|
|
|
|
newQuietVerifier := func() *vaultik.Vaultik {
|
|
v := &vaultik.Vaultik{
|
|
Config: cfg,
|
|
Storage: storer,
|
|
Fs: fs,
|
|
Stdout: &stdout,
|
|
Stderr: io.Discard,
|
|
UI: ui.NewWithColor(&stdout, false),
|
|
}
|
|
v.SetContext(ctx)
|
|
v.UI.SetQuiet(true)
|
|
|
|
return v
|
|
}
|
|
|
|
require.NoError(t, newQuietVerifier().VerifySnapshotWithOptions(
|
|
snapshotID, &vaultik.VerifyOptions{}))
|
|
require.Empty(t, stdout.String(),
|
|
"shallow verify must write no report under --quiet")
|
|
|
|
require.NoError(t, newQuietVerifier().VerifySnapshotWithOptions(
|
|
snapshotID, &vaultik.VerifyOptions{Deep: true}))
|
|
require.Empty(t, stdout.String(),
|
|
"deep verify must write no report under --quiet")
|
|
|
|
require.NoError(t, newQuietVerifier().VerifySnapshotWithOptions(
|
|
snapshotID, &vaultik.VerifyOptions{JSON: true}))
|
|
require.Equal(t, "ok", decodeVerifyResult(t, stdout.Bytes()).Status,
|
|
"the --json document must still emit under --quiet")
|
|
|
|
// A snapshot without its encrypted database fails shallow verify. A
|
|
// failed report also lists each missing blob and each blob of the
|
|
// wrong size, so remove one blob and grow another.
|
|
require.NoError(t, os.Remove(filepath.Join(storeDir, "metadata",
|
|
snapshot.RemoteSnapshotKey(snapshotID), "db.zst.age")))
|
|
|
|
blobFiles, err := filepath.Glob(
|
|
filepath.Join(storeDir, "blobs", "*", "*", "*"))
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(blobFiles), 2,
|
|
"the snapshot must span two blobs, one to remove and one to grow")
|
|
require.NoError(t, os.Remove(blobFiles[0]))
|
|
growOneBlob(t, fs, filepath.Join(storeDir, "blobs"))
|
|
|
|
stdout.Reset()
|
|
|
|
require.Error(t, newQuietVerifier().VerifySnapshotWithOptions(
|
|
snapshotID, &vaultik.VerifyOptions{}),
|
|
"--quiet must not change the outcome of a failed verify")
|
|
require.Empty(t, stdout.String(),
|
|
"a failed verify must write no report under --quiet")
|
|
}
|
|
|
|
// TestVerify_DeepStatusLineUsesUIMarker checks that the deep verify
|
|
// status lines go through internal/ui: marker-prefixed, and silenced by
|
|
// --quiet.
|
|
func TestVerify_DeepStatusLineUsesUIMarker(t *testing.T) {
|
|
log.Initialize(log.Config{})
|
|
t.Parallel()
|
|
|
|
fs := afero.NewOsFs()
|
|
tempDir := t.TempDir()
|
|
|
|
dataDir := filepath.Join(tempDir, "source")
|
|
storeDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "index.sqlite")
|
|
|
|
require.NoError(t, fs.MkdirAll(dataDir, 0o755))
|
|
require.NoError(t, afero.WriteFile(fs,
|
|
filepath.Join(dataDir, "data.bin"),
|
|
bytesPattern("marker-", 64*1024), 0o644))
|
|
|
|
ctx := context.Background()
|
|
|
|
cfg, storer, snapshotID := runFileStorageBackup(
|
|
ctx, t, fs, dataDir, storeDir, dbPath, 32*1024, 128*1024)
|
|
|
|
var stdout bytes.Buffer
|
|
|
|
v := &vaultik.Vaultik{
|
|
Config: cfg,
|
|
Storage: storer,
|
|
Fs: fs,
|
|
Stdout: &stdout,
|
|
Stderr: io.Discard,
|
|
UI: ui.NewWithColor(&stdout, false),
|
|
}
|
|
v.SetContext(ctx)
|
|
|
|
opts := &vaultik.VerifyOptions{Deep: true}
|
|
|
|
require.NoError(t, v.VerifySnapshotWithOptions(snapshotID, opts))
|
|
require.Contains(t, stdout.String(),
|
|
"\n"+ui.Marker+" Downloading manifest...\n")
|
|
|
|
stdout.Reset()
|
|
v.UI.SetQuiet(true)
|
|
require.NoError(t, v.VerifySnapshotWithOptions(snapshotID, opts))
|
|
require.NotContains(t, stdout.String(), "Downloading manifest")
|
|
}
|