## Summary

- Add per-host rsync bandwidth limit overrides with inherit/unlimited semantics.
- Store the effective bwlimit in run metadata/results and show it in host/run detail views.
- Document recommended starting values for VPN and remote backups.

## Tests
- `.venv/bin/python manage.py makemigrations --check --dry-run`
- `.venv/bin/python manage.py test src.pobsync_backend.tests.test_django_config_source.DjangoConfigSourceTests.test_returns_effective_config_from_database src.pobsync_backend.tests.test_django_config_source.DjangoConfigSourceTests.test_host_can_disable_global_rsync_bandwidth_limit src.pobsync_backend.tests.test_configure_commands.ConfigureCommandsTests.test_configure_host_uses_global_retention_defaults src.pobsync_backend.tests.test_run_scheduled_config_source.RunScheduledConfigSourceTests.test_dry_run_applies_configured_bandwidth_limit src.pobsync_backend.tests.test_run_scheduled_config_source.RunScheduledConfigSourceTests.test_real_run_can_request_verbose_output_args --verbosity 2`
- `.venv/bin/python manage.py test src.pobsync_backend.tests.test_views.ViewTests.test_create_host_config_form_creates_host src.pobsync_backend.tests.test_views.ViewTests.test_host_detail_renders_effective_config_preview src.pobsync_backend.tests.test_views.ViewTests.test_run_detail_renders_result_payload src.pobsync_backend.tests.test_views.ViewTests.test_host_config_form_updates_host_config --verbosity 2`
- `.venv/bin/python manage.py check`

Closes #51
This commit is contained in:
2026-05-23 00:59:55 +02:00
parent fdf401a0be
commit 515330c436
16 changed files with 136 additions and 13 deletions

View File

@@ -12,8 +12,9 @@ from pobsync.rsync import RsyncResult
class FakeConfigSource:
def __init__(self, backup_root: str = "/tmp/pobsync-test-backups") -> None:
def __init__(self, backup_root: str = "/tmp/pobsync-test-backups", bwlimit_kbps: int = 0) -> None:
self.backup_root = backup_root
self.bwlimit_kbps = bwlimit_kbps
def effective_config_for_host(self, host: str) -> dict:
return {
@@ -25,7 +26,7 @@ class FakeConfigSource:
"binary": "rsync",
"args_effective": ["--archive"],
"timeout_seconds": 0,
"bwlimit_kbps": 0,
"bwlimit_kbps": self.bwlimit_kbps,
},
"source_root": "/",
"includes": [],
@@ -54,6 +55,21 @@ class RunScheduledConfigSourceTests(SimpleTestCase):
self.assertEqual(result["host"], "web-01")
run_rsync.assert_called_once()
def test_dry_run_applies_configured_bandwidth_limit(self) -> None:
with patch("pobsync.commands.run_scheduled.run_rsync") as run_rsync:
run_rsync.return_value = RsyncResult(exit_code=0, command=["rsync", "--bwlimit=4096"])
result = run_scheduled(
prefix=Path("/missing-prefix"),
host="web-01",
dry_run=True,
config_source=FakeConfigSource(bwlimit_kbps=4096),
)
command = run_rsync.call_args.args[0]
self.assertIn("--bwlimit=4096", command)
self.assertEqual(result["rsync"]["bwlimit_kbps"], 4096)
def test_failed_dry_run_includes_log_tail(self) -> None:
def fake_run_rsync(command, log_path, timeout_seconds, cancel_check=None):
log_path.parent.mkdir(parents=True, exist_ok=True)
@@ -186,11 +202,13 @@ class RunScheduledConfigSourceTests(SimpleTestCase):
host="web-01",
dry_run=False,
verbose_output=True,
config_source=FakeConfigSource(backup_root=str(Path(tmp) / "backups")),
config_source=FakeConfigSource(backup_root=str(Path(tmp) / "backups"), bwlimit_kbps=2048),
)
command = run_rsync.call_args.args[0]
self.assertTrue(result["ok"])
self.assertIn("--bwlimit=2048", command)
self.assertEqual(result["rsync"]["bwlimit_kbps"], 2048)
self.assertIn("--stats", command)
self.assertIn("--itemize-changes", command)
self.assertIn("--info=flist2,progress2,stats2", command)