diff --git a/changelog/unreleased/issue-4437 b/changelog/unreleased/issue-4437 new file mode 100644 index 000000000..199c04cbf --- /dev/null +++ b/changelog/unreleased/issue-4437 @@ -0,0 +1,9 @@ +Enhancement: `check` command creates cache directory if it does not exist + +If a custom cache directory was specified for the `check` command but the directory did not exist, +then `check` continued with cache disabled. + +The `check` command now attempts to create the cache directory before initializing the cache. + +https://github.com/restic/restic/issues/4437 +https://github.com/restic/restic/pull/4805 diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index 671cab0e6..d953f1bc9 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -173,6 +173,12 @@ func prepareCheckCache(opts CheckOptions, gopts *GlobalOptions) (cleanup func()) } // use a cache in a temporary directory + err := os.MkdirAll(cachedir, 0755) + if err != nil { + Warnf("unable to create cache directory %s, disabling cache: %v\n", cachedir, err) + gopts.NoCache = true + return cleanup + } tempdir, err := os.MkdirTemp(cachedir, "restic-check-cache-") if err != nil { // if an error occurs, don't use any cache diff --git a/cmd/restic/cmd_check_test.go b/cmd/restic/cmd_check_test.go index 4d54488cd..15003ee48 100644 --- a/cmd/restic/cmd_check_test.go +++ b/cmd/restic/cmd_check_test.go @@ -1,8 +1,11 @@ package main import ( + "io/fs" "math" + "os" "reflect" + "strings" "testing" "github.com/restic/restic/internal/restic" @@ -163,3 +166,65 @@ func TestSelectNoRandomPacksByFileSize(t *testing.T) { selectedPacks := selectRandomPacksByFileSize(testPacks, 10, 500) rtest.Assert(t, len(selectedPacks) == 0, "Expected 0 selected packs") } + +func checkIfFileWithSimilarNameExists(files []fs.DirEntry, fileName string) bool { + found := false + for _, file := range files { + if file.IsDir() { + dirName := file.Name() + if strings.Contains(dirName, fileName) { + found = true + } + } + } + return found +} + +func TestPrepareCheckCache(t *testing.T) { + // Create a temporary directory for the cache + tmpDirBase := t.TempDir() + + testCases := []struct { + opts CheckOptions + withValidCache bool + }{ + {CheckOptions{WithCache: true}, true}, // Shouldn't create temp directory + {CheckOptions{WithCache: false}, true}, // Should create temp directory + {CheckOptions{WithCache: false}, false}, // Should create cache directory first, then temp directory + } + + for _, testCase := range testCases { + t.Run("", func(t *testing.T) { + if !testCase.withValidCache { + // remove tmpDirBase to simulate non-existing cache directory + err := os.Remove(tmpDirBase) + rtest.OK(t, err) + } + gopts := GlobalOptions{CacheDir: tmpDirBase} + cleanup := prepareCheckCache(testCase.opts, &gopts) + files, err := os.ReadDir(tmpDirBase) + rtest.OK(t, err) + + if !testCase.opts.WithCache { + // If using a temporary cache directory, the cache directory should exist + // listing all directories inside tmpDirBase (cacheDir) + // one directory should be tmpDir created by prepareCheckCache with 'restic-check-cache-' in path + found := checkIfFileWithSimilarNameExists(files, "restic-check-cache-") + if !found { + t.Errorf("Expected temporary directory to exist, but it does not") + } + } else { + // If not using the cache, the temp directory should not exist + rtest.Assert(t, len(files) == 0, "expected cache directory not to exist, but it does: %v", files) + } + + // Call the cleanup function to remove the temporary cache directory + cleanup() + + // Verify that the cache directory has been removed + files, err = os.ReadDir(tmpDirBase) + rtest.OK(t, err) + rtest.Assert(t, len(files) == 0, "Expected cache directory to be removed, but it still exists: %v", files) + }) + } +}