|
1 | 1 | import datetime as dt |
| 2 | +import itertools |
2 | 3 | import os |
3 | 4 | from collections import Counter |
4 | 5 | from pathlib import Path |
@@ -230,6 +231,51 @@ def test_do_backup_removes_existing_files_in_exclude_list( |
230 | 231 | assert result_content == expected_content |
231 | 232 |
|
232 | 233 |
|
| 234 | +@pytest.mark.xfail(reason="Reproduces a bug for which no fix is yet available.") |
| 235 | +@pytest.mark.parametrize( |
| 236 | + "first_source, second_source", |
| 237 | + [(FIRST_BACKUP, SECOND_BACKUP)], |
| 238 | +) |
| 239 | +def test_btrfs_backend_gracefully_handles_existing_snapshots_owned_by_root( |
| 240 | + first_source, second_source, mounted_device |
| 241 | +) -> None: |
| 242 | + # THIS IS A REGRESSION TEST! |
| 243 | + # |
| 244 | + # After the improvements on the handling of single files backups a weird error |
| 245 | + # ocurred. Sometimes backups would fail due to "PermissionError"s. This happened |
| 246 | + # when the existing snapshot was owned by root and was missing the single files |
| 247 | + # target folder. This test reproduces this scenario and ensures that the backup |
| 248 | + # works correctly, even in this case. |
| 249 | + empty_config, device = mounted_device |
| 250 | + if not isinstance(empty_config, cp.BtrFSRsyncConfig): |
| 251 | + # This test works for BtrfsConfig only. However, encrypted_device on |
| 252 | + # which mounted_device depends on, is parameterised over all backends. |
| 253 | + # Since this simplifies many other tests it seemed to be an acceptable |
| 254 | + # tradeoff to short-circuit the test here. |
| 255 | + return |
| 256 | + |
| 257 | + first_config = complement_configuration(empty_config, first_source) |
| 258 | + first_backend = bb.BackupBackend.from_config(first_config) |
| 259 | + first_backend.do_backup(device) |
| 260 | + |
| 261 | + snapshot_root = device / first_config.BackupRepositoryFolder |
| 262 | + latest_snapshot = sorted(snapshot_root.iterdir())[-1] |
| 263 | + for cur in itertools.chain(snapshot_root.glob("*"), snapshot_root.glob("*/*")): |
| 264 | + print(f"Changing ownership of {cur} to root:root") |
| 265 | + sh.run_cmd(cmd=["sudo", "chown", "root:root", cur]) |
| 266 | + sh.run_cmd(cmd=["sudo", "rm", "-rf", latest_snapshot / first_config.FilesDest]) |
| 267 | + |
| 268 | + second_config = complement_configuration(empty_config, second_source).model_copy( |
| 269 | + update={"ExcludePatternsFile": EXCLUDE_FILE} |
| 270 | + ) |
| 271 | + second_backend = bb.BackupBackend.from_config(second_config) |
| 272 | + second_backend.do_backup(device) |
| 273 | + |
| 274 | + result_content = get_result_content(second_config, device) |
| 275 | + expected_content = get_expected_content(second_config, exclude_to_ignore_file=True) |
| 276 | + assert result_content == expected_content |
| 277 | + |
| 278 | + |
233 | 279 | def test_do_backup_for_btrfs_creates_snapshots_with_timestamp_names( |
234 | 280 | mounted_device, |
235 | 281 | ) -> None: |
|
0 commit comments