Skip to content

Commit bdecd48

Browse files
CopilotMaxG87
andcommitted
Add test to reproduce BtrFS backup permission error with empty Files
Co-authored-by: MaxG87 <5477952+MaxG87@users.noreply.github.com>
1 parent 7564eb4 commit bdecd48

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

tests/test_backup_backends.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,62 @@ def test_do_backup_for_restic_adapts_ownership(
281281
}
282282
assert found_user == {expected_user}
283283
assert found_group == {expected_group}
284+
285+
286+
def test_do_backup_for_btrfs_with_empty_files_creates_directory(
287+
mounted_device,
288+
) -> None:
289+
"""Test that reproduces the permission error when Files is empty.
290+
291+
This test exercises the code path that causes a PermissionError in production
292+
when creating a backup with empty Files set.
293+
294+
The issue in production:
295+
1. First backup works (initial subvolume is owned by user after chown)
296+
2. Second backup fails with PermissionError because:
297+
- A new snapshot is created with 'sudo btrfs subvolume snapshot'
298+
- In production, the snapshot is owned by root
299+
- files_dest.mkdir() is called without sudo (line 53 in backup_backends.py)
300+
- mkdir fails with PermissionError when trying to create directory in
301+
root-owned snapshot
302+
303+
Note: This test may pass in CI environments where sudo preserves user
304+
ownership, but it reproduces the production error scenario where Files is
305+
empty and multiple backups are performed.
306+
"""
307+
empty_config, device = mounted_device
308+
if not isinstance(empty_config, cp.BtrFSRsyncConfig):
309+
# This test is specific to BtrFS backend
310+
return
311+
312+
# Create config with empty Files set (this is the key to reproducing the bug)
313+
folder_dest_dir = "some-folder-name"
314+
config = empty_config.model_copy(
315+
update={
316+
"Folders": {FIRST_BACKUP: folder_dest_dir},
317+
"Files": set(), # Empty Files set triggers the bug
318+
"FilesDest": "Einzeldateien",
319+
}
320+
)
321+
322+
# First backup - creates first snapshot
323+
backend = bb.BtrFSRsyncBackend(config)
324+
backend.do_backup(device)
325+
326+
# Verify the FilesDest directory was created in the first snapshot
327+
backup_repository = device / config.BackupRepositoryFolder
328+
first_snapshot = sorted(backup_repository.iterdir())[-1]
329+
files_dest_first = first_snapshot / config.FilesDest
330+
assert files_dest_first.exists()
331+
assert files_dest_first.is_dir()
332+
333+
# Second backup - creates snapshot from first snapshot
334+
# In production with root-owned snapshots, this would raise PermissionError
335+
# at the files_dest.mkdir() call because the snapshot is owned by root
336+
backend.do_backup(device)
337+
338+
# Verify the FilesDest directory was created in the second snapshot
339+
second_snapshot = sorted(backup_repository.iterdir())[-1]
340+
files_dest_second = second_snapshot / config.FilesDest
341+
assert files_dest_second.exists()
342+
assert files_dest_second.is_dir()

0 commit comments

Comments
 (0)