|
3 | 3 | package btrfs |
4 | 4 |
|
5 | 5 | import ( |
6 | | - "bytes" |
7 | | - "fmt" |
8 | 6 | "os" |
9 | | - "os/exec" |
10 | 7 | "path" |
11 | | - "strings" |
12 | 8 | "testing" |
13 | 9 |
|
14 | 10 | graphdriver "go.podman.io/storage/drivers" |
@@ -81,123 +77,3 @@ func TestBtrfsListLayers(t *testing.T) { |
81 | 77 | func TestBtrfsTeardown(t *testing.T) { |
82 | 78 | graphtest.PutDriver(t) |
83 | 79 | } |
84 | | - |
85 | | -// dependencies: btrfs-progs, libbtrfs-dev |
86 | | -// permission: root, loop device |
87 | | -func TestSubVolDelete(t *testing.T) { |
88 | | - if os.Getuid() != 0 { |
89 | | - t.Skip("test requires root") |
90 | | - } |
91 | | - |
92 | | - // Helpers |
93 | | - runCmd := func(name string, arg ...string) error { |
94 | | - cmd := exec.Command(name, arg...) |
95 | | - var stderr bytes.Buffer |
96 | | - cmd.Stderr = &stderr |
97 | | - if err := cmd.Run(); err != nil { |
98 | | - return fmt.Errorf("command '%s %s' failed: %v, stderr: %s", name, strings.Join(arg, " "), err, stderr.String()) |
99 | | - } |
100 | | - return nil |
101 | | - } |
102 | | - qgroupShow := func(mountPath string) string { |
103 | | - cmd := exec.Command("btrfs", "qgroup", "show", mountPath) |
104 | | - var out bytes.Buffer |
105 | | - cmd.Stdout = &out |
106 | | - cmd.Run() |
107 | | - return out.String() |
108 | | - } |
109 | | - |
110 | | - // parepare btrfs using loop device |
111 | | - baseDir, err := os.MkdirTemp("/mnt", "btrfs-test-") |
112 | | - if err != nil { |
113 | | - t.Fatalf("Failed to create base temp dir: %v", err) |
114 | | - } |
115 | | - defer os.RemoveAll(baseDir) |
116 | | - |
117 | | - mnt := path.Join(baseDir, "mountpoint") |
118 | | - if err := os.Mkdir(mnt, 0o755); err != nil { |
119 | | - t.Fatalf("Failed to create mountpoint dir: %v", err) |
120 | | - } |
121 | | - |
122 | | - blockFile := path.Join(baseDir, "btrfs.img") |
123 | | - if err := runCmd("dd", "if=/dev/zero", "of="+blockFile, "bs=1M", "count=120", "status=none"); err != nil { |
124 | | - t.Skipf("Failed to create block file: %v", err) |
125 | | - } |
126 | | - |
127 | | - if err := runCmd("mkfs.btrfs", "-f", blockFile); err != nil { |
128 | | - t.Skipf("Failed to format to btrfs: %v", err) |
129 | | - } |
130 | | - |
131 | | - findLoopCmd := exec.Command("losetup", "-f") |
132 | | - var loopDevBytes bytes.Buffer |
133 | | - findLoopCmd.Stdout = &loopDevBytes |
134 | | - if err := findLoopCmd.Run(); err != nil { |
135 | | - t.Skipf("Failed to find a loop device with 'losetup -f': %v", err) |
136 | | - } |
137 | | - loopDev := strings.TrimSpace(loopDevBytes.String()) |
138 | | - if loopDev == "" { |
139 | | - t.Skip("No available loop devices found") |
140 | | - } |
141 | | - |
142 | | - if err := runCmd("losetup", loopDev, blockFile); err != nil { |
143 | | - t.Skipf("Failed to setup loop device with 'losetup %s %s': %v", loopDev, blockFile, err) |
144 | | - } |
145 | | - defer runCmd("losetup", "-d", loopDev) |
146 | | - |
147 | | - if err := runCmd("mount", loopDev, mnt); err != nil { |
148 | | - t.Skipf("Failed to mount loop device %s: %v", loopDev, err) |
149 | | - } |
150 | | - defer runCmd("umount", mnt) |
151 | | - |
152 | | - d := &Driver{home: mnt} |
153 | | - if err := d.enableQuota(); err != nil { |
154 | | - t.Skipf("Failed to enable qgroup using API: %v", err) |
155 | | - } |
156 | | - |
157 | | - t.Run("subVolDelete", func(t *testing.T) { |
158 | | - subvolName := "subvol1" |
159 | | - subvolPath := path.Join(mnt, subvolName) |
160 | | - if err := subvolCreate(mnt, subvolName); err != nil { |
161 | | - t.Fatalf("Failed to create subvolume using API: %v", err) |
162 | | - } |
163 | | - |
164 | | - if err := d.subvolRescanQuota(); err != nil { |
165 | | - t.Fatalf("Failed to rescan quota using API: %v", err) |
166 | | - } |
167 | | - |
168 | | - qtreeid, err := subvolLookupQgroup(subvolPath) |
169 | | - if err != nil { |
170 | | - t.Fatalf("Failed to lookup qgroup for subvolume using API: %v", err) |
171 | | - } |
172 | | - qgroupID := fmt.Sprintf("0/%d", qtreeid) |
173 | | - t.Logf("subvolume %s has qgroup ID %s", subvolPath, qgroupID) |
174 | | - |
175 | | - if !strings.Contains(qgroupShow(mnt), qgroupID) { |
176 | | - t.Fatalf("qgroup %s was not created for subvolume %s", qgroupID, subvolPath) |
177 | | - } |
178 | | - |
179 | | - if err := subvolDelete(mnt, subvolName, true); err != nil { |
180 | | - t.Fatalf("Failed to delete subvolume using API: %v", err) |
181 | | - } |
182 | | - |
183 | | - if err := d.subvolRescanQuota(); err != nil { |
184 | | - t.Fatalf("Failed to rescan quota after delete using API: %v", err) |
185 | | - } |
186 | | - |
187 | | - qgroupInfo := qgroupShow(mnt) |
188 | | - t.Logf("Current qgroup info:\n%s", qgroupInfo) |
189 | | - |
190 | | - if strings.Contains(qgroupInfo, qgroupID) && !strings.Contains(qgroupInfo, "under deletion") { |
191 | | - t.Fatalf("qgroup %s was not marked as 'under deletion' for subvolume %s", qgroupID, subvolPath) |
192 | | - } |
193 | | - |
194 | | - runCmd("btrfs", "qgroup", "clear-stale", mnt) |
195 | | - |
196 | | - qgroupInfo = qgroupShow(mnt) |
197 | | - t.Logf("Current qgroup info after clearing stale:\n%s", qgroupInfo) |
198 | | - |
199 | | - if strings.Contains(qgroupInfo, qgroupID) { |
200 | | - t.Fatalf("qgroup %s was not deleted for subvolume %s", qgroupID, subvolPath) |
201 | | - } |
202 | | - }) |
203 | | -} |
0 commit comments