diff --git a/cmd/restic/cmd_forget_integration_test.go b/cmd/restic/cmd_forget_integration_test.go index e4cdb744e..06487a841 100644 --- a/cmd/restic/cmd_forget_integration_test.go +++ b/cmd/restic/cmd_forget_integration_test.go @@ -2,18 +2,65 @@ package main import ( "context" + "path/filepath" + "strings" "testing" + "github.com/restic/restic/internal/restic" rtest "github.com/restic/restic/internal/test" "github.com/restic/restic/internal/ui/termstatus" ) -func testRunForget(t testing.TB, gopts GlobalOptions, args ...string) { - opts := ForgetOptions{} +func testRunForgetMayFail(gopts GlobalOptions, opts ForgetOptions, args ...string) error { pruneOpts := PruneOptions{ MaxUnused: "5%", } - rtest.OK(t, withTermStatus(gopts, func(ctx context.Context, term *termstatus.Terminal) error { + return withTermStatus(gopts, func(ctx context.Context, term *termstatus.Terminal) error { return runForget(context.TODO(), opts, pruneOpts, gopts, term, args) - })) + }) +} + +func testRunForget(t testing.TB, gopts GlobalOptions, opts ForgetOptions, args ...string) { + rtest.OK(t, testRunForgetMayFail(gopts, opts, args...)) +} + +func TestRunForgetSafetyNet(t *testing.T) { + env, cleanup := withTestEnvironment(t) + defer cleanup() + + testSetupBackupData(t, env) + + opts := BackupOptions{ + Host: "example", + } + testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts) + testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts) + testListSnapshots(t, env.gopts, 2) + + // --keep-tags invalid + err := testRunForgetMayFail(env.gopts, ForgetOptions{ + KeepTags: restic.TagLists{restic.TagList{"invalid"}}, + GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true}, + }) + rtest.Assert(t, strings.Contains(err.Error(), `refusing to delete last snapshot of snapshot group "host example, path`), "wrong error message got %v", err) + + // disallow `forget --unsafe-allow-remove-all` + err = testRunForgetMayFail(env.gopts, ForgetOptions{ + UnsafeAllowRemoveAll: true, + }) + rtest.Assert(t, strings.Contains(err.Error(), `--unsafe-allow-remove-all is not allowed unless a snapshot filter option is specified`), "wrong error message got %v", err) + + // disallow `forget` without options + err = testRunForgetMayFail(env.gopts, ForgetOptions{}) + rtest.Assert(t, strings.Contains(err.Error(), `no policy was specified, no snapshots will be removed`), "wrong error message got %v", err) + + // `forget --host example --unsafe-allow-remmove-all` should work + testRunForget(t, env.gopts, ForgetOptions{ + UnsafeAllowRemoveAll: true, + GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true}, + SnapshotFilter: restic.SnapshotFilter{ + Hosts: []string{opts.Host}, + }, + }) + testListSnapshots(t, env.gopts, 0) } diff --git a/cmd/restic/cmd_prune_integration_test.go b/cmd/restic/cmd_prune_integration_test.go index 715adea9a..5eb16a2ea 100644 --- a/cmd/restic/cmd_prune_integration_test.go +++ b/cmd/restic/cmd_prune_integration_test.go @@ -75,7 +75,7 @@ func createPrunableRepo(t *testing.T, env *testEnvironment) { testListSnapshots(t, env.gopts, 3) testRunForgetJSON(t, env.gopts) - testRunForget(t, env.gopts, firstSnapshot.String()) + testRunForget(t, env.gopts, ForgetOptions{}, firstSnapshot.String()) } func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) { @@ -129,7 +129,7 @@ func TestPruneWithDamagedRepository(t *testing.T) { // create and delete snapshot to create unused blobs testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts) firstSnapshot := testListSnapshots(t, env.gopts, 1)[0] - testRunForget(t, env.gopts, firstSnapshot.String()) + testRunForget(t, env.gopts, ForgetOptions{}, firstSnapshot.String()) oldPacks := listPacks(env.gopts, t) diff --git a/cmd/restic/cmd_repair_snapshots_integration_test.go b/cmd/restic/cmd_repair_snapshots_integration_test.go index 34cd186d3..9f65c9328 100644 --- a/cmd/restic/cmd_repair_snapshots_integration_test.go +++ b/cmd/restic/cmd_repair_snapshots_integration_test.go @@ -62,7 +62,7 @@ func TestRepairSnapshotsWithLostData(t *testing.T) { testRunCheckMustFail(t, env.gopts) // repository must be ok after removing the broken snapshots - testRunForget(t, env.gopts, snapshotIDs[0].String(), snapshotIDs[1].String()) + testRunForget(t, env.gopts, ForgetOptions{}, snapshotIDs[0].String(), snapshotIDs[1].String()) testListSnapshots(t, env.gopts, 2) _, err := testRunCheckOutput(env.gopts, false) rtest.OK(t, err) @@ -86,7 +86,7 @@ func TestRepairSnapshotsWithLostTree(t *testing.T) { // remove tree for foo/bar and the now completely broken first snapshot removePacks(env.gopts, t, restic.NewIDSet(oldPacks...)) - testRunForget(t, env.gopts, oldSnapshot[0].String()) + testRunForget(t, env.gopts, ForgetOptions{}, oldSnapshot[0].String()) testRunCheckMustFail(t, env.gopts) // repair