Skip to content

Commit 930f489

Browse files
committed
Add moveAll helper
1 parent ae5874e commit 930f489

File tree

2 files changed

+170
-1
lines changed

2 files changed

+170
-1
lines changed

pbm/restore/physical.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os/exec"
1414
"path"
1515
"path/filepath"
16+
"slices"
1617
"strconv"
1718
"strings"
1819
"sync"
@@ -2349,6 +2350,32 @@ func (r *PhysRestore) MarkFailed(meta *RestoreMeta, e error, markCluster bool) {
23492350
}
23502351
}
23512352

2353+
// moveAll moves fromDir content (files and dirs) to toDir content.
2354+
// It ignores all files/dirs specified within toIgnore slice.
2355+
func moveAll(fromDir, toDir string, toIgnore []string, l log.LogEvent) error {
2356+
d, err := os.Open(fromDir)
2357+
if err != nil {
2358+
return errors.Wrap(err, "open dir")
2359+
}
2360+
defer d.Close()
2361+
2362+
names, err := d.Readdirnames(-1)
2363+
if err != nil {
2364+
return errors.Wrap(err, "read file names")
2365+
}
2366+
for _, n := range names {
2367+
if slices.Contains(toIgnore, n) {
2368+
continue
2369+
}
2370+
err = os.Rename(filepath.Join(fromDir, n), filepath.Join(toDir, n))
2371+
if err != nil {
2372+
return errors.Wrapf(err, "move %s", n)
2373+
}
2374+
l.Debug("move to %s dir: %s", toDir, n)
2375+
}
2376+
return nil
2377+
}
2378+
23522379
func removeAll(dir string, l log.LogEvent) error {
23532380
d, err := os.Open(dir)
23542381
if err != nil {
@@ -2361,7 +2388,7 @@ func removeAll(dir string, l log.LogEvent) error {
23612388
return errors.Wrap(err, "read file names")
23622389
}
23632390
for _, n := range names {
2364-
if n == internalMongodLog {
2391+
if n == internalMongodLog || n == fallbackDir {
23652392
continue
23662393
}
23672394
err = os.RemoveAll(filepath.Join(dir, n))

pbm/restore/physical_test.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package restore
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
10+
"github.com/percona/percona-backup-mongodb/pbm/log"
11+
)
12+
13+
func TestMoveAll(t *testing.T) {
14+
t.Run("move all files and dir", func(t *testing.T) {
15+
tempSrc, _ := os.MkdirTemp("", "src")
16+
defer os.RemoveAll(tempSrc)
17+
18+
tempDst, _ := os.MkdirTemp("", "dst")
19+
defer os.RemoveAll(tempDst)
20+
21+
testFiles := []string{"file1", "file2", "file3"}
22+
for i, file := range testFiles {
23+
_ = os.WriteFile(
24+
filepath.Join(tempSrc, file),
25+
[]byte(fmt.Sprintf("test content %d", i)), 0644)
26+
}
27+
28+
subDir := filepath.Join(tempSrc, "subdir")
29+
_ = os.Mkdir(subDir, 0755)
30+
31+
err := moveAll(tempSrc, tempDst, nil, log.DiscardLogger.NewDefaultEvent())
32+
if err != nil {
33+
t.Fatalf("moveAll failed: %v", err)
34+
}
35+
36+
// files are moved
37+
for _, file := range testFiles {
38+
if _, err := os.Stat(filepath.Join(tempDst, file)); os.IsNotExist(err) {
39+
t.Errorf("file %s not found in destination directory", file)
40+
}
41+
if _, err := os.Stat(filepath.Join(tempSrc, file)); !os.IsNotExist(err) {
42+
t.Errorf("file %s still exists in source directory", file)
43+
}
44+
}
45+
46+
// subdir is moved
47+
if _, err := os.Stat(filepath.Join(tempDst, "subdir")); os.IsNotExist(err) {
48+
t.Errorf("subdirectory not found in destination directory")
49+
}
50+
if _, err := os.Stat(filepath.Join(tempSrc, "subdir")); !os.IsNotExist(err) {
51+
t.Errorf("subdirectory still exists in source directory")
52+
}
53+
})
54+
55+
t.Run("ignore files and dirs", func(t *testing.T) {
56+
tempSrc, _ := os.MkdirTemp("", "src")
57+
defer os.RemoveAll(tempSrc)
58+
59+
tempDst, _ := os.MkdirTemp("", "dst")
60+
defer os.RemoveAll(tempDst)
61+
62+
testFiles := []string{"file1", "file2", "ignore_me"}
63+
for i, file := range testFiles {
64+
_ = os.WriteFile(
65+
filepath.Join(tempSrc, file),
66+
[]byte(fmt.Sprintf("test content %d", i)), 0644)
67+
}
68+
69+
_ = os.Mkdir(filepath.Join(tempSrc, "ignore_dir"), 0755)
70+
_ = os.Mkdir(filepath.Join(tempSrc, "normal_dir"), 0755)
71+
72+
toIgnore := []string{"ignore_me", "ignore_dir"}
73+
74+
err := moveAll(tempSrc, tempDst, toIgnore, log.DiscardLogger.NewDefaultEvent())
75+
if err != nil {
76+
t.Fatalf("moveAll failed: %v", err)
77+
}
78+
79+
// non-ignored files are moved
80+
movedFiles := []string{"file1", "file2"}
81+
for _, file := range movedFiles {
82+
if _, err := os.Stat(filepath.Join(tempDst, file)); os.IsNotExist(err) {
83+
t.Errorf("file %s not found in destination directory", file)
84+
}
85+
}
86+
87+
// ignored items remain in source
88+
for _, item := range toIgnore {
89+
if _, err := os.Stat(filepath.Join(tempSrc, item)); os.IsNotExist(err) {
90+
t.Errorf("ignored item %s not found in source directory", item)
91+
}
92+
if _, err := os.Stat(filepath.Join(tempDst, item)); !os.IsNotExist(err) {
93+
t.Errorf("ignored item %s was moved to destination directory", item)
94+
}
95+
}
96+
97+
// non-ignored directory is moved
98+
if _, err := os.Stat(filepath.Join(tempDst, "normal_dir")); os.IsNotExist(err) {
99+
t.Errorf("normal directory not found in destination directory")
100+
}
101+
})
102+
103+
t.Run("source dir doesn't exist", func(t *testing.T) {
104+
tempDst, _ := os.MkdirTemp("", "dst")
105+
defer os.RemoveAll(tempDst)
106+
107+
nonExistentDir := "/path/not/exist"
108+
109+
err := moveAll(nonExistentDir, tempDst, nil, log.DiscardLogger.NewDefaultEvent())
110+
if err == nil {
111+
t.Fatal("want error")
112+
}
113+
if !strings.Contains(err.Error(), "open dir") {
114+
t.Errorf("want:'open dir', got:%v", err)
115+
}
116+
})
117+
118+
t.Run("write permission error", func(t *testing.T) {
119+
tempSrc, _ := os.MkdirTemp("", "src")
120+
defer os.RemoveAll(tempSrc)
121+
122+
tempDst, _ := os.MkdirTemp("", "dst")
123+
defer os.RemoveAll(tempDst)
124+
125+
_ = os.Chmod(tempDst, 0500) // read-only
126+
defer os.Chmod(tempDst, 0700) // Restore permissions for cleanup
127+
128+
// Create test file in source
129+
_ = os.WriteFile(
130+
filepath.Join(tempSrc, "test"),
131+
[]byte("test content"), 0644)
132+
133+
err := moveAll(tempSrc, tempDst, nil, log.DiscardLogger.NewDefaultEvent())
134+
if err == nil {
135+
t.Fatal("want perm error")
136+
}
137+
138+
if !strings.Contains(err.Error(), "move test") {
139+
t.Errorf("want:'move test', got:%v", err)
140+
}
141+
})
142+
}

0 commit comments

Comments
 (0)