test(uninstaller): verify flatpak missing ref fallback and fatal failure handling

swadhinbiswas committed 2 months ago
6cdb216
1 parent abdcc64
commit 6cdb216
1 file changed
+66 -12
Showing 1 changed file+66-12
▼internal/uninstaller/uninstaller_test.go
+66-12
14
14
// fakeCmder records commands and simulates failures on demand.
15
15
type fakeCmder struct {
16
16
ran []string
17
- fail map[string]bool // tool name -> always fail
17
+ fail map[string]bool // tool name -> always fail
18
+ errs map[string]error // specific command or tool -> custom error
18
19
hasSudo bool
19
20
}
20
21
26
27
}
27
28
28
29
func (f *fakeCmder) Run(ctx context.Context, name string, args ...string) error {
29
- f.ran = append(f.ran, name+" "+strings.Join(args, " "))
30
+ fullCmd := name + " " + strings.Join(args, " ")
31
+ f.ran = append(f.ran, fullCmd)
32
+ if f.errs != nil {
33
+ if err, ok := f.errs[fullCmd]; ok {
34
+ return err
35
+ }
36
+ if err, ok := f.errs[name]; ok {
37
+ return err
38
+ }
39
+ }
30
40
if f.fail != nil && f.fail[name] {
31
41
return errors.New("command failed")
32
42
}
249
259
250
260
func TestRemovePackageNotFoundCleansResidualFiles(t *testing.T) {
251
261
u, cmder := testUninstaller(t)
252
- // Simulate flatpak failing with "No installed refs found"
253
- cmder.fail = map[string]bool{"flatpak": true}
254
- // Custom Run implementation for this test
262
+ // Seed a leftover config and cache directory before staging
263
+ seed(t, u.FS, "/home/u/.config/ai.jan.Jan/config.json", "{}")
264
+ seed(t, u.FS, "/home/u/.cache/ai.jan.Jan/cache.dat", "data")
265
+
255
266
app := model.AppInfo{Name: "ai.jan.Jan", Source: "flatpak", InstallSizeKB: 100}
256
267
if err := u.StageRemoval(&app); err != nil {
257
268
t.Fatal(err)
258
269
}
259
- // Seed a leftover config and cache directory
260
- seed(t, u.FS, "/home/u/.config/ai.jan.Jan/config.json", "{}")
261
- seed(t, u.FS, "/home/u/.cache/ai.jan.Jan/cache.dat", "data")
262
270
263
- // Set custom error
264
- cmder.fail = nil // We test through StageRemoval
271
+ // Simulate system-level flatpak failing with "No installed refs found"
272
+ cmder.errs = map[string]error{
273
+ "flatpak uninstall --noninteractive -y --delete-data ai.jan.Jan": errors.New("error: No installed refs found for ai.jan.Jan"),
274
+ }
275
+
265
276
freed, files, err := u.Remove(context.Background(), &app, nil)
266
277
if err != nil {
267
278
t.Fatalf("expected success with residual cleanup, got: %v", err)
268
279
}
269
- if freed == 0 && files == 0 {
270
- t.Fatal("expected files to be cleaned")
280
+ if freed == 0 || files == 0 {
281
+ t.Fatalf("expected files to be cleaned, freed=%d files=%d", freed, files)
282
+ }
283
+
284
+ // Verify that the user-scope fallback command ran
285
+ foundUserFallback := false
286
+ for _, cmd := range cmder.ran {
287
+ if cmd == "flatpak uninstall --user --noninteractive -y ai.jan.Jan" {
288
+ foundUserFallback = true
289
+ break
290
+ }
291
+ }
292
+ if !foundUserFallback {
293
+ t.Fatalf("expected flatpak --user fallback to run, ran: %v", cmder.ran)
294
+ }
295
+
296
+ // Config files should have been removed
297
+ if exists, _ := afero.DirExists(u.FS, "/home/u/.config/ai.jan.Jan"); exists {
298
+ t.Fatal("config directory should have been purged")
299
+ }
300
+}
301
+
302
+func TestRemoveFlatpakFatalFailureAborts(t *testing.T) {
303
+ u, cmder := testUninstaller(t)
304
+ seed(t, u.FS, "/home/u/.config/ai.jan.Jan/config.json", "{}")
305
+
306
+ app := model.AppInfo{Name: "ai.jan.Jan", Source: "flatpak", InstallSizeKB: 100}
307
+ if err := u.StageRemoval(&app); err != nil {
308
+ t.Fatal(err)
309
+ }
310
+
311
+ // Fatal uninstaller failure that is not a missing reference
312
+ cmder.errs = map[string]error{
313
+ "flatpak uninstall --noninteractive -y --delete-data ai.jan.Jan": errors.New("error: DBus connection timed out"),
314
+ }
315
+
316
+ _, files, err := u.Remove(context.Background(), &app, nil)
317
+ if err == nil {
318
+ t.Fatal("expected Remove to return error on fatal flatpak failure")
319
+ }
320
+ if files != 0 {
321
+ t.Fatalf("expected no files to be removed on fatal failure, removed %d", files)
322
+ }
323
+ if exists, _ := afero.DirExists(u.FS, "/home/u/.config/ai.jan.Jan"); !exists {
324
+ t.Fatal("config directory must survive a fatal package failure")
271
325
}
272
326
}
273
327