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 := filepath.Join(tempDir, "remote") 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") }