Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/vorta/borg/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def prepare(cls, profile):
)
if wifi_is_disallowed.count() > 0 and profile.repo.is_remote_repo():
ret['message'] = trans_late('messages', 'Current Wifi is not allowed.')
ret['level'] = 'info'
return ret

if (
Expand All @@ -130,6 +131,7 @@ def prepare(cls, profile):
and network_status_monitor.is_network_metered()
):
ret['message'] = trans_late('messages', 'Not running backup over metered connection.')
ret['level'] = 'info'
return ret

ret['profile'] = profile
Expand Down
20 changes: 13 additions & 7 deletions src/vorta/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,19 @@ def create_backup(self, profile_id: int) -> None:
job.result.connect(self.notify)
self.app.jobs_manager.add_job(job)
else:
logger.error('Conditions for backup not met. Aborting.')
logger.error(msg['message'])
notifier.deliver(
self.tr('Vorta Backup'),
translate('messages', msg['message']),
level='error',
)
# Default to 'error': unexpected failures notify.
# Expected skips (WiFi/metered) use 'info' to suppress.
level = msg.get('level', 'error')
if level == 'error':
logger.error('Conditions for backup not met. Aborting.')
logger.error(msg['message'])
notifier.deliver(
self.tr('Vorta Backup'),
translate('messages', msg['message']),
level='error',
)
else:
logger.info('Backup skipped: %s', msg['message'])
self.pause(profile_id)

def notify(self, result: dict[str, Any]) -> None:
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,29 @@ def test_create_paths_from_command():
'echo',
TEST_SOURCE_DIR,
]


def test_prepare_returns_info_level_when_wifi_disallowed(mocker):
"""Test that prepare() returns level='info' when WiFi is not allowed."""
default_profile = BackupProfileModel.get()
mock_monitor = mocker.MagicMock()
mock_monitor.get_current_wifi.return_value = 'blocked_wifi'
mocker.patch('vorta.borg.create.get_network_status_monitor', return_value=mock_monitor)
mocker.patch(
'vorta.borg.create.WifiSettingModel.select',
return_value=mocker.MagicMock(where=lambda *a, **kw: mocker.MagicMock(count=lambda: 1)),
)
result = BorgCreateJob.prepare(default_profile)
assert result.get('level') == 'info'


def test_prepare_returns_info_level_when_metered_connection(mocker):
"""Test that prepare() returns level='info' for metered connections."""
default_profile = BackupProfileModel.get()
default_profile.dont_run_on_metered_networks = True
mock_monitor = mocker.MagicMock()
mock_monitor.get_current_wifi.return_value = None
mock_monitor.is_network_metered.return_value = True
mocker.patch('vorta.borg.create.get_network_status_monitor', return_value=mock_monitor)
result = BorgCreateJob.prepare(default_profile)
assert result.get('level') == 'info'
22 changes: 22 additions & 0 deletions tests/unit/test_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,25 @@ def test_missed_startup(qapp, qtbot, window_load, clockmock, now, hour, minute,
assert len(event_times) == 2
else:
assert len(event_times) == 1


@prepare
def test_create_backup_no_error_notification_on_info_level(qapp, qtbot, mocker, borg_json_output):
"""Test that notifier.deliver() is not called with level='error' when
prepare() returns level='info' (e.g. WiFi disallowed or metered connection)."""
mocker.patch(
'vorta.scheduler.BorgCreateJob.prepare',
return_value={
'ok': False,
'message': 'Current Wifi is not allowed.',
'level': 'info',
},
)
notifier_mock = mocker.patch('vorta.notifications.VortaNotifications.pick')
mock_notifier = mocker.MagicMock()
notifier_mock.return_value = mock_notifier

qapp.scheduler.create_backup(1)
# The error notification should be suppressed for an expected skip.
assert mock_notifier.deliver.call_count == 1
assert mock_notifier.deliver.call_args.kwargs.get('level') != 'error'
Loading