From 2849f549322818ec8cc165ed1e1de26c37122fab Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 30 Oct 2024 11:25:26 -0400 Subject: [PATCH 01/43] initial pushover commit --- borgmatic/config/schema.yaml | 208 ++++++++++++++++++++++++++++ borgmatic/hooks/dispatch.py | 2 + borgmatic/hooks/monitor.py | 1 + borgmatic/hooks/pushover.py | 82 +++++++++++ docs/how-to/monitor-your-backups.md | 62 +++++++++ tests/unit/hooks/test_pushover.py | 176 +++++++++++++++++++++++ 6 files changed, 531 insertions(+) create mode 100644 borgmatic/hooks/pushover.py create mode 100644 tests/unit/hooks/test_pushover.py diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 4dd7c76f..d7668124 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1609,6 +1609,214 @@ properties: example: - start - finish + pushover: + type: object + additionalProperties: false + properties: + token: + type: string + description: | + Your application's API token. + example: 7ms6TXHpTokTou2P6x4SodDeentHRa + user: + type: string + description: | + Your user/group key (or that of your target user), viewable + when logged into your dashboard: often referred to as + USER_KEY in Pushover documentation and code examples. + example: hwRwoWsXMBWwgrSecfa9EfPey55WSN + start: + type: object + type: object + properties: + message: + type: string + description: | + Message to be sent to the user or group. + example: A backup job has started. + priority: + type: integer + description: | + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. + example: "0" + device: + type: string + description: | + The name of one of your devices to send just to that + device instead of all devices. + example: pixel8 + html: + type: integer + description: | + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. + example: 1 + sound: + type: string + description: | + The name of a supported sound to override your + default sound choice. All options can be + found here: https://pushover.net/api#sounds + example: bike + title: + type: string + description: | + Your message's title, otherwise your app's + name is used. + example: A backup job has started. + ttl: + type: integer + description: | + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority + value of 2. + example: 3600 + url: + type: string + description: | + A supplementary URL to show with your message. + example: https://pushover.net/apps/xxxxx-borgbackup + url_title: + type: string + description: | + A title for the URL specified as the url parameter, + otherwise just the URL is shown. + example: Pushover Link + finish: + type: object + type: object + properties: + message: + type: string + description: | + Message to be sent to the user or group. + example: A backup job has started. + priority: + type: integer + description: | + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. + example: "0" + device: + type: string + description: | + The name of one of your devices to send just to that + device instead of all devices. + example: pixel8 + html: + type: integer + description: | + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. + example: 1 + sound: + type: string + description: | + The name of a supported sound to override your + default sound choice. All options can be + found here: https://pushover.net/api#sounds + example: bike + title: + type: string + description: | + Your message's title, otherwise your app's + name is used. + example: A backup job has started. + ttl: + type: integer + description: | + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority + value of 2. + example: 3600 + url: + type: string + description: | + A supplementary URL to show with your message. + example: https://pushover.net/apps/xxxxx-borgbackup + url_title: + type: string + description: | + A title for the URL specified as the url parameter, + otherwise just the URL is shown. + example: Pushover Link + fail: + type: object + properties: + message: + type: string + description: | + Message to be sent to the user or group. + example: A backup job has started. + priority: + type: integer + description: | + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. + example: "0" + device: + type: string + description: | + The name of one of your devices to send just to that + device instead of all devices. + example: pixel8 + html: + type: integer + description: | + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. + example: 1 + sound: + type: string + description: | + The name of a supported sound to override your + default sound choice. All options can be + found here: https://pushover.net/api#sounds + example: bike + title: + type: string + description: | + Your message's title, otherwise your app's + name is used. + example: A backup job has started. + ttl: + type: integer + description: | + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority + value of 2. + example: 3600 + url: + type: string + description: | + A supplementary URL to show with your message. + example: https://pushover.net/apps/xxxxx-borgbackup + url_title: + type: string + description: | + A title for the URL specified as the url parameter, + otherwise just the URL is shown. + example: Pushover Link + states: + type: array + items: + type: string + enum: + - start + - finish + - fail + uniqueItems: true + description: | + List of one or more monitoring states to ping for: "start", + "finish", and/or "fail". Defaults to pinging for failure + only. + example: + - start + - finish zabbix: type: object additionalProperties: false diff --git a/borgmatic/hooks/dispatch.py b/borgmatic/hooks/dispatch.py index be85af8c..4230ffb9 100644 --- a/borgmatic/hooks/dispatch.py +++ b/borgmatic/hooks/dispatch.py @@ -12,6 +12,7 @@ from borgmatic.hooks import ( ntfy, pagerduty, postgresql, + pushover, sqlite, uptimekuma, zabbix, @@ -31,6 +32,7 @@ HOOK_NAME_TO_MODULE = { 'ntfy': ntfy, 'pagerduty': pagerduty, 'postgresql_databases': postgresql, + 'pushover': pushover, 'sqlite_databases': sqlite, 'uptime_kuma': uptimekuma, 'zabbix': zabbix, diff --git a/borgmatic/hooks/monitor.py b/borgmatic/hooks/monitor.py index de4951b7..db44b567 100644 --- a/borgmatic/hooks/monitor.py +++ b/borgmatic/hooks/monitor.py @@ -8,6 +8,7 @@ MONITOR_HOOK_NAMES = ( 'loki', 'ntfy', 'pagerduty', + 'pushover', 'uptime_kuma', 'zabbix', ) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py new file mode 100644 index 00000000..73a01c89 --- /dev/null +++ b/borgmatic/hooks/pushover.py @@ -0,0 +1,82 @@ +import logging + +import requests + +logger = logging.getLogger(__name__) + + +def initialize_monitor( + ping_url, config, config_filename, monitoring_log_level, dry_run +): # pragma: no cover + ''' + No initialization is necessary for this monitor. + ''' + pass + + +def ping_monitor(hook_config, config, config_filename, state, monitoring_log_level, dry_run): + ''' + Post a message to the configured Pushover application. + If this is a dry run, then don't actually update anything. + ''' + + run_states = hook_config.get('states', ['fail']) + + if state.name.lower() not in run_states: + return + + dry_run_label = ' (dry run; not actually updating)' if dry_run else '' + + state_config = hook_config.get( + state.name.lower(), + { + 'message': state.name.lower(), + }, + ) + + token = hook_config.get('token') + user = hook_config.get('user') + + logger.info(f'{config_filename}: Updating Pushover {dry_run_label}') + + if token is None: + logger.warning(f'{config_filename}: Token missing for Pushover') + return + if user is None: + logger.warning(f'{config_filename}: User missing for Pushover') + return + + data = { + 'token': token, + 'user': user, + 'message': state.name.lower(), # default to state name. Can be overwritten in state_config loop below. + } + + for key in state_config: + data[key] = state_config[key] + if key == 'priority': + if data['priority'] == 2: + data['expire'] = 30 + data['retry'] = 30 + + if not dry_run: + logging.getLogger('urllib3').setLevel(logging.ERROR) + try: + response = requests.post( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data=data, + ) + if not response.ok: + response.raise_for_status() + except requests.exceptions.RequestException as error: + logger.warning(f'{config_filename}: Pushover error: {error}') + + +def destroy_monitor( + ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run +): # pragma: no cover + ''' + No destruction is necessary for this monitor. + ''' + pass diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index f5007401..9069610f 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -46,6 +46,7 @@ them as backups happen: * [Healthchecks](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#healthchecks-hook) * [ntfy](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#ntfy-hook) * [PagerDuty](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook) + * [Pushover](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pushover-hook) * [Uptime Kuma](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#uptime-kuma-hook) * [Zabbix](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook) @@ -290,6 +291,67 @@ If you have any issues with the integration, [please contact us](https://torsion.org/borgmatic/#support-and-contributing). +## Pushover hook + +New in version 1.9.0 +[Pushover](https://pushover.net) makes it easy to get real-time notifications +on your Android, iPhone, iPad, and Desktop (Android Wear and Apple Watch, too!) + +First, create a Pushover account and login on your mobile device. Create an +Application in your Pushover dashboard. + +Then, configure borgmatic with your user's unique "User Key" found in your +Pushover dashboard and the unique "API Token" from the created Application. + +Here's a basic example: + + +```yaml +pushover: + token: 7ms6TXHpTokTou2P6x4SodDeentHRa + user: hwRwoWsXMBWwgrSecfa9EfPey55WSN +``` + + +With this configuration, borgmatic creates a Pushover event for your service +whenever backups fail, but only when any of the `create`, `prune`, `compact`, +or `check` actions are run. Note that borgmatic does not contact Pushover +when a backup starts or when it ends without error. + +You can configure Pushover to have custom parameters declared for borgmatic's +`start`, `fail` and `finish` hooks states. + +Here's a more advanced example: + + +```yaml +pushover: + token: 7ms6TXHpTokTou2P6x4SodDeentHRa + user: hwRwoWsXMBWwgrSecfa9EfPey55WSN + start: + message: "Backup Started" + priority: -2 + device: "pixel8" + title: "Backup Started" + html: 1 + sound: "bike" + ttl: 10 + fail: + message: "Backup Failed" + priority: -2 + device: "pixel8" + title: "Backup Started" + html: 1 + sound: "siren" + url: "https://ticketing-system.example.com/login" + url_title: "Login to ticketing system" + states: + - start + - finish + - fail +``` + + ## ntfy hook New in version 1.6.3 diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py new file mode 100644 index 00000000..8484f5ab --- /dev/null +++ b/tests/unit/hooks/test_pushover.py @@ -0,0 +1,176 @@ +from flexmock import flexmock + +import borgmatic.hooks.monitor +from borgmatic.hooks import pushover as module + + +def test_ping_monitor_config_with_token_only_exit_early(): + # This test should exit early since only providing a token is not enough + # for the hook to work + hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92'} + flexmock(module.logger).should_receive('warning').once() + flexmock(module.requests).should_receive('post').never() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_config_with_user_only_exit_early(): + # This test should exit early since only providing a token is not enough + # for the hook to work + hook_config = {'user': '983hfe0of902lkjfa2amanfgui'} + flexmock(module.logger).should_receive('warning').once() + flexmock(module.requests).should_receive('post').never() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_send_to_pushover(): + # This test should be the minimum working configuration. The "message" + # should be auto populated with the default value which is the state name. + hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'} + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'fail', + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_config_with_minimum_config_start_state_backup_not_send_to_pushover_exit_early(): + # This test should exit early since the hook config does not specify the + # 'start' state. Only the 'fail' state is enabled by default. + hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'} + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').never() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_default_message_successfully_send_to_pushover(): + # This test should send a notification to Pushover on backup start + # since the state has been configured. It should default to sending + # the name of the state as the 'message' since it is not + # explicitly declared in the state config. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pushover(): + # This test should send a notification to Pushover on backup start + # since the state has been configured. It should send a custom + # 'message' since it is explicitly declared in the state config. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': {'message': 'custom start message'}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'custom start message', + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_default_message_with_priority_declared_successfully_send_to_pushover(): + # This test should send a notification to Pushover on backup start + # since the state has been configured. It should default to sending + # the name of the state as the 'message' since it is not + # explicitly declared in the state config. It should also send + # with a priority of 1 (high). + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': {'priority': 1}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + 'priority': 1, + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) From 94db527500a1878c60f41154702442d011266b5e Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 30 Oct 2024 15:43:06 -0400 Subject: [PATCH 02/43] finalized support for Pushover --- README.md | 1 + borgmatic/config/schema.yaml | 126 +++++++----- borgmatic/hooks/pushover.py | 17 +- docs/how-to/monitor-your-backups.md | 20 +- docs/static/pushover.png | Bin 0 -> 6488 bytes tests/unit/hooks/test_pushover.py | 302 +++++++++++++++++++++++++++- 6 files changed, 397 insertions(+), 69 deletions(-) create mode 100644 docs/static/pushover.png diff --git a/README.md b/README.md index 45b48a4e..01151e70 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ borgmatic is powered by [Borg Backup](https://www.borgbackup.org/). Cronitor Cronhub PagerDuty +Pushover ntfy Loki Apprise diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index d7668124..222a141d 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1637,40 +1637,48 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that - indicates the message priority. - example: "0" + A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + example: 0 + expire: + type: integer + description: | + he expire parameter specifies how many seconds + your notification will continue to be retried + for (every retry seconds). + example: 1200 + retry: + type: integer + description: | + The retry parameter specifies how often + (in seconds) the Pushover servers will send the + same notification to the user. + example: 30 device: type: string description: | - The name of one of your devices to send just to that - device instead of all devices. + The name of one of your devices to send just to that device instead of all devices. example: pixel8 html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. example: 1 sound: type: string description: | - The name of a supported sound to override your - default sound choice. All options can be - found here: https://pushover.net/api#sounds + The name of a supported sound to override your default sound choice. All + options can be found here: https://pushover.net/api#sounds example: bike title: type: string description: | - Your message's title, otherwise your app's - name is used. + Your message's title, otherwise your app's name is used. example: A backup job has started. ttl: type: integer description: | - The number of seconds that the message will live, - before being deleted automatically. The ttl - parameter is ignored for messages with a priority + The number of seconds that the message will live, before being deleted + automatically. The ttl parameter is ignored for messages with a priority value of 2. example: 3600 url: @@ -1681,8 +1689,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, - otherwise just the URL is shown. + A title for the URL specified as the url parameter, otherwise just + the URL is shown. example: Pushover Link finish: type: object @@ -1696,40 +1704,48 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that - indicates the message priority. - example: "0" + A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + example: 0 + expire: + type: integer + description: | + he expire parameter specifies how many seconds + your notification will continue to be retried + for (every retry seconds). + example: 1200 + retry: + type: integer + description: | + The retry parameter specifies how often + (in seconds) the Pushover servers will send the + same notification to the user. + example: 30 device: type: string description: | - The name of one of your devices to send just to that - device instead of all devices. + The name of one of your devices to send just to that device instead of all devices. example: pixel8 html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. example: 1 sound: type: string description: | - The name of a supported sound to override your - default sound choice. All options can be - found here: https://pushover.net/api#sounds + The name of a supported sound to override your default sound choice. All + options can be found here: https://pushover.net/api#sounds example: bike title: type: string description: | - Your message's title, otherwise your app's - name is used. + Your message's title, otherwise your app's name is used. example: A backup job has started. ttl: type: integer description: | - The number of seconds that the message will live, - before being deleted automatically. The ttl - parameter is ignored for messages with a priority + The number of seconds that the message will live, before being deleted + automatically. The ttl parameter is ignored for messages with a priority value of 2. example: 3600 url: @@ -1740,8 +1756,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, - otherwise just the URL is shown. + A title for the URL specified as the url parameter, otherwise just + the URL is shown. example: Pushover Link fail: type: object @@ -1754,40 +1770,48 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that - indicates the message priority. - example: "0" + A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + example: 0 + expire: + type: integer + description: | + he expire parameter specifies how many seconds + your notification will continue to be retried + for (every retry seconds). + example: 1200 + retry: + type: integer + description: | + The retry parameter specifies how often + (in seconds) the Pushover servers will send the + same notification to the user. + example: 30 device: type: string description: | - The name of one of your devices to send just to that - device instead of all devices. + The name of one of your devices to send just to that device instead of all devices. example: pixel8 html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. example: 1 sound: type: string description: | - The name of a supported sound to override your - default sound choice. All options can be - found here: https://pushover.net/api#sounds + The name of a supported sound to override your default sound choice. All + options can be found here: https://pushover.net/api#sounds example: bike title: type: string description: | - Your message's title, otherwise your app's - name is used. + Your message's title, otherwise your app's name is used. example: A backup job has started. ttl: type: integer description: | - The number of seconds that the message will live, - before being deleted automatically. The ttl - parameter is ignored for messages with a priority + The number of seconds that the message will live, before being deleted + automatically. The ttl parameter is ignored for messages with a priority value of 2. example: 3600 url: @@ -1798,8 +1822,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, - otherwise just the URL is shown. + A title for the URL specified as the url parameter, otherwise just + the URL is shown. example: Pushover Link states: type: array diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 73a01c89..ecd6ce28 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -46,18 +46,25 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.warning(f'{config_filename}: User missing for Pushover') return + if 'priority' in state_config and state_config['priority'] == 2: + if 'expire' not in state_config: + logger.info(f'{config_filename}: Setting expire to default (10min).') + state_config['expire'] = 1200 + if 'retry' not in state_config: + logger.info(f'{config_filename}: Setting retry to default (30sec).') + state_config['retry'] = 30 + else: + state_config.pop('expire', None) + state_config.pop('retry', None) + data = { 'token': token, 'user': user, 'message': state.name.lower(), # default to state name. Can be overwritten in state_config loop below. } - + for key in state_config: data[key] = state_config[key] - if key == 'priority': - if data['priority'] == 2: - data['expire'] = 30 - data['retry'] = 30 if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 9069610f..82de8c28 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -331,20 +331,28 @@ pushover: start: message: "Backup Started" priority: -2 - device: "pixel8" title: "Backup Started" html: 1 - sound: "bike" - ttl: 10 + ttl: 10 # Message will be deleted after 10 seconds. fail: - message: "Backup Failed" - priority: -2 + message: "Backup Failed" + priority: 2 # Requests acknowledgement for messages. + expire: 1200 # Used only for priority 2. Default is 1200 seconds. + retry: 30 # Used only for priority 2. Default is 30 seconds. device: "pixel8" - title: "Backup Started" + title: "Backup Failed" html: 1 sound: "siren" url: "https://ticketing-system.example.com/login" url_title: "Login to ticketing system" + finish: + message: "Backup Finished" + priority: 0 + title: "Backup Finished" + html: 1 + ttl: 60 + url: "https://ticketing-system.example.com/login" + url_title: "Login to ticketing system" states: - start - finish diff --git a/docs/static/pushover.png b/docs/static/pushover.png new file mode 100644 index 0000000000000000000000000000000000000000..e0ef72a9c069e3d53a658102678966e83c757108 GIT binary patch literal 6488 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 literal 0 HcmV?d00001 diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index 8484f5ab..b709ae4d 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -142,17 +142,115 @@ def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pus ) -def test_ping_monitor_start_state_backup_default_message_with_priority_declared_successfully_send_to_pushover(): - # This test should send a notification to Pushover on backup start - # since the state has been configured. It should default to sending - # the name of the state as the 'message' since it is not - # explicitly declared in the state config. It should also send - # with a priority of 1 (high). +def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_no_expiry_or_retry_success(): + # This simulates priority level 2 being set but expiry and retry are + # not declared. This should set retry and expiry to their defaults. hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', 'states': {'start', 'fail', 'finish'}, - 'start': {'priority': 1}, + 'start': {'priority': 2}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + 'priority': 2, + 'retry': 30, + 'expire': 1200, + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_with_expire_no_retry_success(): + # This simulates priority level 2 and expiry being set but retry is + # not declared. This should set retry to the default. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': {'priority': 2, 'expire': 600}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + 'priority': 2, + 'retry': 30, + 'expire': 600, + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_no_expire_with_retry_success(): + # This simulates priority level 2 and retry being set but expire is + # not declared. This should set expire to the default. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': {'priority': 2, 'expire': 30}, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + 'priority': 2, + 'retry': 30, + 'expire': 30, + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_start_state_backup_default_message_with_priority_high_declared_expire_and_retry_delared_success(): + # This simulates priority level 1, retry and expiry being set. Since expire + # and retry are only used for priority level 2, they should not be included + # in the request sent to Pushover. This test verifies that those are + # stripped from the request. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': {'priority': 1, 'expire': 30, 'retry': 30}, } flexmock(module.logger).should_receive('warning').never() flexmock(module.requests).should_receive('post').with_args( @@ -174,3 +272,193 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_declared_ monitoring_log_level=1, dry_run=False, ) + + +def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example_success(): + # Here is a test of what is provided in the monitor-your-backups.md file + # as an 'advanced example'. This test runs the start state. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': { + 'message': 'Backup Started', + 'priority': -2, + 'title': 'Backup Started', + 'html': 1, + 'ttl': 10, + }, + 'fail': { + 'message': 'Backup Failed', + 'priority': 2, + 'expire': 1200, + 'retry': 30, + 'device': 'pixel8', + 'title': 'Backup Failed', + 'html': 1, + 'sound': 'siren', + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + 'finish': { + 'message': 'Backup Finished', + 'priority': 0, + 'title': 'Backup Finished', + 'html': 1, + 'ttl': 60, + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'Backup Started', + 'priority': -2, + 'title': 'Backup Started', + 'html': 1, + 'ttl': 10, + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_success(): + # Here is a test of what is provided in the monitor-your-backups.md file + # as an 'advanced example'. This test runs the fail state. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': { + 'message': 'Backup Started', + 'priority': -2, + 'title': 'Backup Started', + 'html': 1, + 'ttl': 10, + }, + 'fail': { + 'message': 'Backup Failed', + 'priority': 2, + 'expire': 1200, + 'retry': 30, + 'device': 'pixel8', + 'title': 'Backup Failed', + 'html': 1, + 'sound': 'siren', + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + 'finish': { + 'message': 'Backup Finished', + 'priority': 0, + 'title': 'Backup Finished', + 'html': 1, + 'ttl': 60, + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'Backup Failed', + 'priority': 2, + 'expire': 1200, + 'retry': 30, + 'device': 'pixel8', + 'title': 'Backup Failed', + 'html': 1, + 'sound': 'siren', + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_finish_state_backup_based_on_documentation_advanced_example_success(): + # Here is a test of what is provided in the monitor-your-backups.md file + # as an 'advanced example'. This test runs the finish state. + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'states': {'start', 'fail', 'finish'}, + 'start': { + 'message': 'Backup Started', + 'priority': -2, + 'title': 'Backup Started', + 'html': 1, + 'ttl': 10, + }, + 'fail': { + 'message': 'Backup Failed', + 'priority': 2, + 'expire': 1200, + 'retry': 30, + 'device': 'pixel8', + 'title': 'Backup Failed', + 'html': 1, + 'sound': 'siren', + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + 'finish': { + 'message': 'Backup Finished', + 'priority': 0, + 'title': 'Backup Finished', + 'html': 1, + 'ttl': 60, + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'Backup Finished', + 'priority': 0, + 'title': 'Backup Finished', + 'html': 1, + 'ttl': 60, + 'url': 'https://ticketing-system.example.com/login', + 'url_title': 'Login to ticketing system', + }, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FINISH, + monitoring_log_level=1, + dry_run=False, + ) From d7d6e30178614dc1928e741dc51e27c67d3fe373 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:40:23 -0500 Subject: [PATCH 03/43] moved checks from hook to schema --- borgmatic/config/schema.yaml | 1 + borgmatic/hooks/pushover.py | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 222a141d..e83305bb 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1611,6 +1611,7 @@ properties: - finish pushover: type: object + required: ['token', 'user'] additionalProperties: false properties: token: diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index ecd6ce28..a72d4cf5 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -39,13 +39,6 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.info(f'{config_filename}: Updating Pushover {dry_run_label}') - if token is None: - logger.warning(f'{config_filename}: Token missing for Pushover') - return - if user is None: - logger.warning(f'{config_filename}: User missing for Pushover') - return - if 'priority' in state_config and state_config['priority'] == 2: if 'expire' not in state_config: logger.info(f'{config_filename}: Setting expire to default (10min).') From a45ba8553c9f93ad1b6a5609cc66db8723e0533b Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:42:19 -0500 Subject: [PATCH 04/43] removed duplicate type:object --- borgmatic/config/schema.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index e83305bb..5565bc9d 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1627,7 +1627,6 @@ properties: USER_KEY in Pushover documentation and code examples. example: hwRwoWsXMBWwgrSecfa9EfPey55WSN start: - type: object type: object properties: message: From 1177385e080e40bddd847937f49b3c7c22082e0d Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:44:12 -0500 Subject: [PATCH 05/43] fix expire description --- borgmatic/config/schema.yaml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 5565bc9d..20bbe4c1 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1642,9 +1642,8 @@ properties: expire: type: integer description: | - he expire parameter specifies how many seconds - your notification will continue to be retried - for (every retry seconds). + How many seconds your notification will continue + to be retried (every retry seconds). example: 1200 retry: type: integer @@ -1709,9 +1708,8 @@ properties: expire: type: integer description: | - he expire parameter specifies how many seconds - your notification will continue to be retried - for (every retry seconds). + How many seconds your notification will continue + to be retried (every retry seconds). example: 1200 retry: type: integer @@ -1775,9 +1773,8 @@ properties: expire: type: integer description: | - he expire parameter specifies how many seconds - your notification will continue to be retried - for (every retry seconds). + How many seconds your notification will continue + to be retried (every retry seconds). example: 1200 retry: type: integer From 54884da8fabc63ca23716c69cac14338cfdedb2f Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:46:19 -0500 Subject: [PATCH 06/43] priority word wrap --- borgmatic/config/schema.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 20bbe4c1..98b6b303 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1637,7 +1637,8 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. example: 0 expire: type: integer @@ -1703,7 +1704,8 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. example: 0 expire: type: integer @@ -1768,7 +1770,8 @@ properties: priority: type: integer description: | - A value of -2, -1, 0 (default), 1 or 2 that indicates the message priority. + A value of -2, -1, 0 (default), 1 or 2 that + indicates the message priority. example: 0 expire: type: integer From 009055c61a737900ac392e7e8b1d5f189d7d82f2 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:48:21 -0500 Subject: [PATCH 07/43] device description rewrap --- borgmatic/config/schema.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 98b6b303..38431a6f 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1656,7 +1656,8 @@ properties: device: type: string description: | - The name of one of your devices to send just to that device instead of all devices. + The name of one of your devices to send just to + that device instead of all devices. example: pixel8 html: type: integer @@ -1723,7 +1724,8 @@ properties: device: type: string description: | - The name of one of your devices to send just to that device instead of all devices. + The name of one of your devices to send just to + that device instead of all devices. example: pixel8 html: type: integer @@ -1789,7 +1791,8 @@ properties: device: type: string description: | - The name of one of your devices to send just to that device instead of all devices. + The name of one of your devices to send just to + that device instead of all devices. example: pixel8 html: type: integer From 1817b9a9ea252550a62f5170ccfdb81e54ef1406 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 13:50:22 -0500 Subject: [PATCH 08/43] fix wordwrap for html --- borgmatic/config/schema.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 38431a6f..dd9d459c 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1662,7 +1662,8 @@ properties: html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. example: 1 sound: type: string @@ -1730,7 +1731,8 @@ properties: html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. example: 1 sound: type: string @@ -1797,7 +1799,8 @@ properties: html: type: integer description: | - Set to 1 to enable HTML parsing of the message. Set to 0 for plain text. + Set to 1 to enable HTML parsing of the message. Set + to 0 for plain text. example: 1 sound: type: string From 4b7fbce2915aea724f8de14b1ff252ddd11c3686 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:05:27 -0500 Subject: [PATCH 09/43] fix sound word wrap --- borgmatic/config/schema.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index dd9d459c..9686fb19 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1668,8 +1668,9 @@ properties: sound: type: string description: | - The name of a supported sound to override your default sound choice. All - options can be found here: https://pushover.net/api#sounds + The name of a supported sound to override your + default sound choice. All options can be found + here: https://pushover.net/api#sounds example: bike title: type: string @@ -1737,8 +1738,9 @@ properties: sound: type: string description: | - The name of a supported sound to override your default sound choice. All - options can be found here: https://pushover.net/api#sounds + The name of a supported sound to override your + default sound choice. All options can be found + here: https://pushover.net/api#sounds example: bike title: type: string @@ -1805,8 +1807,9 @@ properties: sound: type: string description: | - The name of a supported sound to override your default sound choice. All - options can be found here: https://pushover.net/api#sounds + The name of a supported sound to override your + default sound choice. All options can be found + here: https://pushover.net/api#sounds example: bike title: type: string From dc78bf4d6ba6b6155bdd8520ae2adc231a3e2134 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:06:39 -0500 Subject: [PATCH 10/43] fix TTL wordwrap --- borgmatic/config/schema.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 9686fb19..1feb7cdd 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1680,8 +1680,9 @@ properties: ttl: type: integer description: | - The number of seconds that the message will live, before being deleted - automatically. The ttl parameter is ignored for messages with a priority + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority. value of 2. example: 3600 url: @@ -1750,8 +1751,9 @@ properties: ttl: type: integer description: | - The number of seconds that the message will live, before being deleted - automatically. The ttl parameter is ignored for messages with a priority + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority. value of 2. example: 3600 url: @@ -1819,8 +1821,9 @@ properties: ttl: type: integer description: | - The number of seconds that the message will live, before being deleted - automatically. The ttl parameter is ignored for messages with a priority + The number of seconds that the message will live, + before being deleted automatically. The ttl + parameter is ignored for messages with a priority. value of 2. example: 3600 url: From 02ce3ba19036cff03dbe41a7339c376cb1527be4 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:07:49 -0500 Subject: [PATCH 11/43] fix url_title word wrap --- borgmatic/config/schema.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 1feb7cdd..d5917846 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1693,8 +1693,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, otherwise just - the URL is shown. + A title for the URL specified as the url parameter, + otherwise just the URL is shown. example: Pushover Link finish: type: object @@ -1764,8 +1764,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, otherwise just - the URL is shown. + A title for the URL specified as the url parameter, + otherwise just the URL is shown. example: Pushover Link fail: type: object @@ -1834,8 +1834,8 @@ properties: url_title: type: string description: | - A title for the URL specified as the url parameter, otherwise just - the URL is shown. + A title for the URL specified as the url parameter, + otherwise just the URL is shown. example: Pushover Link states: type: array From 0dca5eeafc809d9db9518952131605d20b5c811e Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:09:03 -0500 Subject: [PATCH 12/43] fix title wordwrap --- borgmatic/config/schema.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index d5917846..2e9aa4f3 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1675,7 +1675,8 @@ properties: title: type: string description: | - Your message's title, otherwise your app's name is used. + Your message's title, otherwise your app's name is + used. example: A backup job has started. ttl: type: integer @@ -1746,7 +1747,8 @@ properties: title: type: string description: | - Your message's title, otherwise your app's name is used. + Your message's title, otherwise your app's name is + used. example: A backup job has started. ttl: type: integer @@ -1816,7 +1818,8 @@ properties: title: type: string description: | - Your message's title, otherwise your app's name is used. + Your message's title, otherwise your app's name is + used. example: A backup job has started. ttl: type: integer From 0fdee067c76ffce7c1fe186c806964a941123014 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:45:36 -0500 Subject: [PATCH 13/43] double space fix --- borgmatic/hooks/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index a72d4cf5..35c9b241 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -37,7 +37,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev token = hook_config.get('token') user = hook_config.get('user') - logger.info(f'{config_filename}: Updating Pushover {dry_run_label}') + logger.info(f'{config_filename}: Updating Pushover{dry_run_label}') if 'priority' in state_config and state_config['priority'] == 2: if 'expire' not in state_config: From 72b27b08582746e01d4cbb903d24273682998032 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 14:57:44 -0500 Subject: [PATCH 14/43] better message description in schema --- borgmatic/config/schema.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 2e9aa4f3..f1639bd0 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1632,7 +1632,8 @@ properties: message: type: string description: | - Message to be sent to the user or group. + Message to be sent to the user or group. If omitted + the default is the name of the state. example: A backup job has started. priority: type: integer @@ -1704,8 +1705,9 @@ properties: message: type: string description: | - Message to be sent to the user or group. - example: A backup job has started. + Message to be sent to the user or group. If omitted + the default is the name of the state. + example: A backup job has finished. priority: type: integer description: | @@ -1775,8 +1777,9 @@ properties: message: type: string description: | - Message to be sent to the user or group. - example: A backup job has started. + Message to be sent to the user or group. If omitted + the default is the name of the state. + example: A backup job has failed. priority: type: integer description: | From 290559116d2099c7e01dcdefddfa0c299f804717 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 15:01:28 -0500 Subject: [PATCH 15/43] better logic for priority --- borgmatic/hooks/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 35c9b241..88c8d7bf 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -39,7 +39,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.info(f'{config_filename}: Updating Pushover{dry_run_label}') - if 'priority' in state_config and state_config['priority'] == 2: + if state_config.get('priority') == 2: if 'expire' not in state_config: logger.info(f'{config_filename}: Setting expire to default (10min).') state_config['expire'] = 1200 From 85ea8f4f457931b4534a59048278ffbdce953cf2 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 15:03:38 -0500 Subject: [PATCH 16/43] fix 10min in seconds --- borgmatic/hooks/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 88c8d7bf..5bb6fac5 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -42,7 +42,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev if state_config.get('priority') == 2: if 'expire' not in state_config: logger.info(f'{config_filename}: Setting expire to default (10min).') - state_config['expire'] = 1200 + state_config['expire'] = 600 if 'retry' not in state_config: logger.info(f'{config_filename}: Setting retry to default (30sec).') state_config['retry'] = 30 From a4fabb85217e6e57007f32248a5e06eace62f048 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:37:26 -0500 Subject: [PATCH 17/43] fix version --- docs/how-to/monitor-your-backups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 82de8c28..069410d6 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -293,7 +293,7 @@ us](https://torsion.org/borgmatic/#support-and-contributing). ## Pushover hook -New in version 1.9.0 +New in version 1.9.1 [Pushover](https://pushover.net) makes it easy to get real-time notifications on your Android, iPhone, iPad, and Desktop (Android Wear and Apple Watch, too!) From 7eb19cb0a7747b5062b9ed3f8ca1f9e67a4efe20 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:38:20 -0500 Subject: [PATCH 18/43] added period --- docs/how-to/monitor-your-backups.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 069410d6..65f4bd3f 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -295,7 +295,8 @@ us](https://torsion.org/borgmatic/#support-and-contributing). New in version 1.9.1 [Pushover](https://pushover.net) makes it easy to get real-time notifications -on your Android, iPhone, iPad, and Desktop (Android Wear and Apple Watch, too!) +on your Android, iPhone, iPad, and Desktop (Android Wear and Apple Watch, +too!). First, create a Pushover account and login on your mobile device. Create an Application in your Pushover dashboard. From 3b79482b242ecb76c9a638461b4be65b66bd35ce Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:38:58 -0500 Subject: [PATCH 19/43] better wording --- docs/how-to/monitor-your-backups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 65f4bd3f..dbff1025 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -315,7 +315,7 @@ pushover: With this configuration, borgmatic creates a Pushover event for your service -whenever backups fail, but only when any of the `create`, `prune`, `compact`, +whenever borgmatic fail, but only when any of the `create`, `prune`, `compact`, or `check` actions are run. Note that borgmatic does not contact Pushover when a backup starts or when it ends without error. From 4ba42e89053c52ac84489d849ed040ad254b3df8 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:41:18 -0500 Subject: [PATCH 20/43] better wording. Added 'by default' --- docs/how-to/monitor-your-backups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index dbff1025..6242218c 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -317,7 +317,7 @@ pushover: With this configuration, borgmatic creates a Pushover event for your service whenever borgmatic fail, but only when any of the `create`, `prune`, `compact`, or `check` actions are run. Note that borgmatic does not contact Pushover -when a backup starts or when it ends without error. +when a backup starts or when it ends without error by default. You can configure Pushover to have custom parameters declared for borgmatic's `start`, `fail` and `finish` hooks states. From 59f8722e05c30d1f4ef343237bfdb5f0101d6551 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:42:46 -0500 Subject: [PATCH 21/43] better spacing for comments --- docs/how-to/monitor-your-backups.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 6242218c..ba16e1cf 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -334,12 +334,12 @@ pushover: priority: -2 title: "Backup Started" html: 1 - ttl: 10 # Message will be deleted after 10 seconds. + ttl: 10 # Message will be deleted after 10 seconds. fail: message: "Backup Failed" - priority: 2 # Requests acknowledgement for messages. - expire: 1200 # Used only for priority 2. Default is 1200 seconds. - retry: 30 # Used only for priority 2. Default is 30 seconds. + priority: 2 # Requests acknowledgement for messages. + expire: 1200 # Used only for priority 2. Default is 1200 seconds. + retry: 30 # Used only for priority 2. Default is 30 seconds. device: "pixel8" title: "Backup Failed" html: 1 From 3e0fa578603ddd94f02ab2c6a24931eaca17cf68 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 17:44:27 -0500 Subject: [PATCH 22/43] removed tests that are not needed --- tests/unit/hooks/test_pushover.py | 34 ------------------------------- 1 file changed, 34 deletions(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index b709ae4d..bf6396eb 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -4,40 +4,6 @@ import borgmatic.hooks.monitor from borgmatic.hooks import pushover as module -def test_ping_monitor_config_with_token_only_exit_early(): - # This test should exit early since only providing a token is not enough - # for the hook to work - hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92'} - flexmock(module.logger).should_receive('warning').once() - flexmock(module.requests).should_receive('post').never() - - module.ping_monitor( - hook_config, - {}, - 'config.yaml', - borgmatic.hooks.monitor.State.FAIL, - monitoring_log_level=1, - dry_run=False, - ) - - -def test_ping_monitor_config_with_user_only_exit_early(): - # This test should exit early since only providing a token is not enough - # for the hook to work - hook_config = {'user': '983hfe0of902lkjfa2amanfgui'} - flexmock(module.logger).should_receive('warning').once() - flexmock(module.requests).should_receive('post').never() - - module.ping_monitor( - hook_config, - {}, - 'config.yaml', - borgmatic.hooks.monitor.State.FAIL, - monitoring_log_level=1, - dry_run=False, - ) - - def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_send_to_pushover(): # This test should be the minimum working configuration. The "message" # should be auto populated with the default value which is the state name. From 46ebb0cebbebc691d734e3f850a2ee1b7d480c68 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 18:45:46 -0500 Subject: [PATCH 23/43] removed redundant code --- borgmatic/hooks/pushover.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 5bb6fac5..8540e8c5 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -27,12 +27,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev dry_run_label = ' (dry run; not actually updating)' if dry_run else '' - state_config = hook_config.get( - state.name.lower(), - { - 'message': state.name.lower(), - }, - ) + state_config = hook_config.get(state.name.lower()) token = hook_config.get('token') user = hook_config.get('user') From 1781787305b89e498d08d0e0a710313fe271dc17 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 19:43:40 -0500 Subject: [PATCH 24/43] better schema description for retry and expire --- borgmatic/config/schema.yaml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index f1639bd0..7564135d 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1645,14 +1645,15 @@ properties: type: integer description: | How many seconds your notification will continue - to be retried (every retry seconds). - example: 1200 + to be retried (every retry seconds). Defaults to + 600. + example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. + same notification to the user. Defaults to 30. example: 30 device: type: string @@ -1718,14 +1719,15 @@ properties: type: integer description: | How many seconds your notification will continue - to be retried (every retry seconds). - example: 1200 + to be retried (every retry seconds). Defaults to + 600. + example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. + same notification to the user. Defaults to 30. example: 30 device: type: string @@ -1790,14 +1792,15 @@ properties: type: integer description: | How many seconds your notification will continue - to be retried (every retry seconds). - example: 1200 + to be retried (every retry seconds). Defaults to + 600. + example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. + same notification to the user. Defaults to 30. example: 30 device: type: string From 51b885e7db7001de0a63cefb604d7f15058c22d6 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 19:49:23 -0500 Subject: [PATCH 25/43] added global constant for priority --- borgmatic/hooks/pushover.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 8540e8c5..1ce7eaed 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -5,6 +5,8 @@ import requests logger = logging.getLogger(__name__) +EMERGENCY_PRIORITY = 2 + def initialize_monitor( ping_url, config, config_filename, monitoring_log_level, dry_run ): # pragma: no cover @@ -34,7 +36,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.info(f'{config_filename}: Updating Pushover{dry_run_label}') - if state_config.get('priority') == 2: + if state_config.get('priority') == EMERGENCY_PRIORITY: if 'expire' not in state_config: logger.info(f'{config_filename}: Setting expire to default (10min).') state_config['expire'] = 600 From ef66349674c10fec1b84ead129a4028c98340bb6 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Fri, 8 Nov 2024 20:02:29 -0500 Subject: [PATCH 26/43] small fixed for some failing tests --- borgmatic/hooks/pushover.py | 5 +++-- tests/unit/hooks/test_pushover.py | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 1ce7eaed..439f2720 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -7,6 +7,7 @@ logger = logging.getLogger(__name__) EMERGENCY_PRIORITY = 2 + def initialize_monitor( ping_url, config, config_filename, monitoring_log_level, dry_run ): # pragma: no cover @@ -29,7 +30,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev dry_run_label = ' (dry run; not actually updating)' if dry_run else '' - state_config = hook_config.get(state.name.lower()) + state_config = hook_config.get(state.name.lower(), {}) token = hook_config.get('token') user = hook_config.get('user') @@ -52,7 +53,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev 'user': user, 'message': state.name.lower(), # default to state name. Can be overwritten in state_config loop below. } - + for key in state_config: data[key] = state_config[key] diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index bf6396eb..bcb23b7f 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -127,7 +127,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency 'message': 'start', 'priority': 2, 'retry': 30, - 'expire': 1200, + 'expire': 600, }, ).and_return(flexmock(ok=True)).once() @@ -257,7 +257,7 @@ def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example 'fail': { 'message': 'Backup Failed', 'priority': 2, - 'expire': 1200, + 'expire': 600, 'retry': 30, 'device': 'pixel8', 'title': 'Backup Failed', @@ -318,7 +318,7 @@ def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_ 'fail': { 'message': 'Backup Failed', 'priority': 2, - 'expire': 1200, + 'expire': 600, 'retry': 30, 'device': 'pixel8', 'title': 'Backup Failed', @@ -346,7 +346,7 @@ def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_ 'user': '983hfe0of902lkjfa2amanfgui', 'message': 'Backup Failed', 'priority': 2, - 'expire': 1200, + 'expire': 600, 'retry': 30, 'device': 'pixel8', 'title': 'Backup Failed', @@ -384,7 +384,7 @@ def test_ping_monitor_finish_state_backup_based_on_documentation_advanced_exampl 'fail': { 'message': 'Backup Failed', 'priority': 2, - 'expire': 1200, + 'expire': 600, 'retry': 30, 'device': 'pixel8', 'title': 'Backup Failed', From eb8f7e03291718f6ecb4d8421c3cf5c7192324d1 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 09:55:07 -0500 Subject: [PATCH 27/43] better description for expire and retry --- borgmatic/config/schema.yaml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 7564135d..791bdabc 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1646,14 +1646,16 @@ properties: description: | How many seconds your notification will continue to be retried (every retry seconds). Defaults to - 600. + 600. This settings only applies to priority 2 + notifications. example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. Defaults to 30. + same notification to the user. Defaults to 30. This + settings only applies to priority 2 notifications. example: 30 device: type: string @@ -1720,14 +1722,16 @@ properties: description: | How many seconds your notification will continue to be retried (every retry seconds). Defaults to - 600. + 600. This settings only applies to priority 2 + notifications. example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. Defaults to 30. + same notification to the user. Defaults to 30. This + settings only applies to priority 2 notifications. example: 30 device: type: string @@ -1793,14 +1797,16 @@ properties: description: | How many seconds your notification will continue to be retried (every retry seconds). Defaults to - 600. + 600. This settings only applies to priority 2 + notifications. example: 600 retry: type: integer description: | The retry parameter specifies how often (in seconds) the Pushover servers will send the - same notification to the user. Defaults to 30. + same notification to the user. Defaults to 30. This + settings only applies to priority 2 notifications. example: 30 device: type: string From b1af304125ff07bf65ac7eaa71f59e2cfff8a25f Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 09:59:02 -0500 Subject: [PATCH 28/43] better data dict creation --- borgmatic/hooks/pushover.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 439f2720..f6a31030 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -48,14 +48,14 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev state_config.pop('expire', None) state_config.pop('retry', None) - data = { - 'token': token, - 'user': user, - 'message': state.name.lower(), # default to state name. Can be overwritten in state_config loop below. - } - - for key in state_config: - data[key] = state_config[key] + data = dict( + { + 'token': token, + 'user': user, + 'message': state.name.lower(), # default to state name. Can be overwritten in state_config loop below. + }, + **state_config, + ) if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) From 0441e79b41fe202151004c24d8cf9c8955589e0f Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:00:34 -0500 Subject: [PATCH 29/43] "fail" -> "fails" --- docs/how-to/monitor-your-backups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index ba16e1cf..075caaf9 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -315,7 +315,7 @@ pushover: With this configuration, borgmatic creates a Pushover event for your service -whenever borgmatic fail, but only when any of the `create`, `prune`, `compact`, +whenever borgmatic fails, but only when any of the `create`, `prune`, `compact`, or `check` actions are run. Note that borgmatic does not contact Pushover when a backup starts or when it ends without error by default. From 6d9340ebb24de4c9e70ce1576447150ff3c18e5a Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:05:57 -0500 Subject: [PATCH 30/43] better comment blocks --- tests/unit/hooks/test_pushover.py | 76 ++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index bcb23b7f..a5a2f641 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -5,8 +5,10 @@ from borgmatic.hooks import pushover as module def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_send_to_pushover(): - # This test should be the minimum working configuration. The "message" - # should be auto populated with the default value which is the state name. + ''' + This test should be the minimum working configuration. The "message" + should be auto populated with the default value which is the state name. + ''' hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'} flexmock(module.logger).should_receive('warning').never() flexmock(module.requests).should_receive('post').with_args( @@ -30,8 +32,10 @@ def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_ def test_ping_monitor_config_with_minimum_config_start_state_backup_not_send_to_pushover_exit_early(): - # This test should exit early since the hook config does not specify the - # 'start' state. Only the 'fail' state is enabled by default. + ''' + This test should exit early since the hook config does not specify the + 'start' state. Only the 'fail' state is enabled by default. + ''' hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'} flexmock(module.logger).should_receive('warning').never() flexmock(module.requests).should_receive('post').never() @@ -47,10 +51,12 @@ def test_ping_monitor_config_with_minimum_config_start_state_backup_not_send_to_ def test_ping_monitor_start_state_backup_default_message_successfully_send_to_pushover(): - # This test should send a notification to Pushover on backup start - # since the state has been configured. It should default to sending - # the name of the state as the 'message' since it is not - # explicitly declared in the state config. + ''' + This test should send a notification to Pushover on backup start + since the state has been configured. It should default to sending + the name of the state as the 'message' since it is not + explicitly declared in the state config. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -78,9 +84,11 @@ def test_ping_monitor_start_state_backup_default_message_successfully_send_to_pu def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pushover(): - # This test should send a notification to Pushover on backup start - # since the state has been configured. It should send a custom - # 'message' since it is explicitly declared in the state config. + ''' + This test should send a notification to Pushover on backup start + since the state has been configured. It should send a custom + 'message' since it is explicitly declared in the state config. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -109,8 +117,10 @@ def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pus def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_no_expiry_or_retry_success(): - # This simulates priority level 2 being set but expiry and retry are - # not declared. This should set retry and expiry to their defaults. + ''' + This simulates priority level 2 being set but expiry and retry are + not declared. This should set retry and expiry to their defaults. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -142,8 +152,10 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_with_expire_no_retry_success(): - # This simulates priority level 2 and expiry being set but retry is - # not declared. This should set retry to the default. + ''' + This simulates priority level 2 and expiry being set but retry is + not declared. This should set retry to the default. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -175,8 +187,10 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_no_expire_with_retry_success(): - # This simulates priority level 2 and retry being set but expire is - # not declared. This should set expire to the default. + ''' + This simulates priority level 2 and retry being set but expire is + not declared. This should set expire to the default. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -208,10 +222,12 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency def test_ping_monitor_start_state_backup_default_message_with_priority_high_declared_expire_and_retry_delared_success(): - # This simulates priority level 1, retry and expiry being set. Since expire - # and retry are only used for priority level 2, they should not be included - # in the request sent to Pushover. This test verifies that those are - # stripped from the request. + ''' + This simulates priority level 1, retry and expiry being set. Since expire + and retry are only used for priority level 2, they should not be included + in the request sent to Pushover. This test verifies that those are + stripped from the request. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -241,8 +257,10 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_high_decl def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example_success(): - # Here is a test of what is provided in the monitor-your-backups.md file - # as an 'advanced example'. This test runs the start state. + ''' + Here is a test of what is provided in the monitor-your-backups.md file + as an 'advanced example'. This test runs the start state. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -302,8 +320,10 @@ def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_success(): - # Here is a test of what is provided in the monitor-your-backups.md file - # as an 'advanced example'. This test runs the fail state. + ''' + Here is a test of what is provided in the monitor-your-backups.md file + as an 'advanced example'. This test runs the fail state. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', @@ -368,8 +388,10 @@ def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_ def test_ping_monitor_finish_state_backup_based_on_documentation_advanced_example_success(): - # Here is a test of what is provided in the monitor-your-backups.md file - # as an 'advanced example'. This test runs the finish state. + ''' + Here is a test of what is provided in the monitor-your-backups.md file + as an 'advanced example'. This test runs the finish state. + ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', From e69d2385fc06c0b98455e6b7f704c27858210799 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:08:13 -0500 Subject: [PATCH 31/43] better name for test --- tests/unit/hooks/test_pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index a5a2f641..cf1f3966 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -116,7 +116,7 @@ def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pus ) -def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_declared_no_expiry_or_retry_success(): +def test_ping_monitor_start_state_backup_default_message_with_priority_emergency_uses_expire_and_retry_defaults(): ''' This simulates priority level 2 being set but expiry and retry are not declared. This should set retry and expiry to their defaults. From 97949266b372c85e6953a64b3465769a5da98250 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:09:23 -0500 Subject: [PATCH 32/43] fix test --- tests/unit/hooks/test_pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index cf1f3966..b6a9d7ad 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -195,7 +195,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui', 'states': {'start', 'fail', 'finish'}, - 'start': {'priority': 2, 'expire': 30}, + 'start': {'priority': 2, 'retry': 30}, } flexmock(module.logger).should_receive('warning').never() flexmock(module.requests).should_receive('post').with_args( From 96bb402837cd97e574a1ad6cd4a811a436976cd7 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:10:13 -0500 Subject: [PATCH 33/43] fix test 2 --- tests/unit/hooks/test_pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index b6a9d7ad..f31a1379 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -207,7 +207,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency 'message': 'start', 'priority': 2, 'retry': 30, - 'expire': 30, + 'expire': 600, }, ).and_return(flexmock(ok=True)).once() From 4e1f256b483affde6289177b60f57213efe4f254 Mon Sep 17 00:00:00 2001 From: Tony Fernandez Date: Tue, 12 Nov 2024 10:15:19 -0500 Subject: [PATCH 34/43] added dryrun test case with minimum config --- tests/unit/hooks/test_pushover.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index f31a1379..422acdbf 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -450,3 +450,30 @@ def test_ping_monitor_finish_state_backup_based_on_documentation_advanced_exampl monitoring_log_level=1, dry_run=False, ) + + +def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_send_to_pushover_dryrun(): + ''' + This test should be the minimum working configuration. The "message" + should be auto populated with the default value which is the state name. + ''' + hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'} + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'fail', + }, + ).and_return(flexmock(ok=True)).never() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=True, + ) From 3ab4b45041a26cf09ff7b991cb3650bd50a6a43f Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 09:07:47 -0500 Subject: [PATCH 35/43] added test for early exit when state is not in config --- tests/unit/hooks/test_pushover.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index 422acdbf..a62cd9d3 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -477,3 +477,32 @@ def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_ monitoring_log_level=1, dry_run=True, ) + + +def test_ping_monitor_config_incorrect_state_exit_early(): + ''' + This test should exit early since the start state is not declared in the configuration. + ''' + hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + } + flexmock(module.logger).should_receive('warning').never() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'start', + }, + ).and_return(flexmock(ok=True)).never() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=True, + ) From 61e4eeff6ca9b7b0659960a306ba87879832b62a Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 11:52:08 -0500 Subject: [PATCH 36/43] converted html to a boolean and updated documentation and schema --- borgmatic/config/schema.yaml | 24 ++++++++++++------------ borgmatic/hooks/pushover.py | 5 +++++ docs/how-to/monitor-your-backups.md | 6 +++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 791bdabc..a8d81122 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1664,11 +1664,11 @@ properties: that device instead of all devices. example: pixel8 html: - type: integer + type: boolean description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. - example: 1 + Set to True to enable HTML parsing of the message. + Set to False for plain text. + example: True sound: type: string description: | @@ -1740,11 +1740,11 @@ properties: that device instead of all devices. example: pixel8 html: - type: integer + type: boolean description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. - example: 1 + Set to True to enable HTML parsing of the message. + Set to False for plain text. + example: True sound: type: string description: | @@ -1815,11 +1815,11 @@ properties: that device instead of all devices. example: pixel8 html: - type: integer + type: boolean description: | - Set to 1 to enable HTML parsing of the message. Set - to 0 for plain text. - example: 1 + Set to True to enable HTML parsing of the message. + Set to False for plain text. + example: True sound: type: string description: | diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index f6a31030..77ba48c5 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -48,6 +48,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev state_config.pop('expire', None) state_config.pop('retry', None) + state_config = { + key: (1 if value is True and key in 'html' else value) + for key, value in state_config.items() + } + data = dict( { 'token': token, diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 075caaf9..e708c005 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -333,7 +333,7 @@ pushover: message: "Backup Started" priority: -2 title: "Backup Started" - html: 1 + html: True ttl: 10 # Message will be deleted after 10 seconds. fail: message: "Backup Failed" @@ -342,7 +342,7 @@ pushover: retry: 30 # Used only for priority 2. Default is 30 seconds. device: "pixel8" title: "Backup Failed" - html: 1 + html: True sound: "siren" url: "https://ticketing-system.example.com/login" url_title: "Login to ticketing system" @@ -350,7 +350,7 @@ pushover: message: "Backup Finished" priority: 0 title: "Backup Finished" - html: 1 + html: True ttl: 60 url: "https://ticketing-system.example.com/login" url_title: "Login to ticketing system" From ea47704d86b9c3ebe3e412144f1c0d4459e9b79b Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 12:09:25 -0500 Subject: [PATCH 37/43] added missing tests to get 100% test coverage --- tests/unit/hooks/test_pushover.py | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index a62cd9d3..3f14a5f1 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -506,3 +506,39 @@ def test_ping_monitor_config_incorrect_state_exit_early(): monitoring_log_level=1, dry_run=True, ) + + +def test_ping_monitor_push_post_error_exits_early(): + ''' + This test simulates the Pushover servers not responding with a 200 OK. We + should raise for status and warn then exit. + ''' + hook_config = hook_config = { + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + } + + push_response = flexmock(ok=False) + push_response.should_receive('raise_for_status').and_raise( + module.requests.ConnectionError + ).once() + flexmock(module.requests).should_receive('post').with_args( + 'https://api.pushover.net/1/messages.json', + headers={'Content-type': 'application/x-www-form-urlencoded'}, + data={ + 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', + 'user': '983hfe0of902lkjfa2amanfgui', + 'message': 'fail', + }, + ).and_return(push_response).once() + + flexmock(module.logger).should_receive('warning').once() + + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, + ) From a939a66fb44421488332a5060164cefc7335fb50 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 15:20:52 -0500 Subject: [PATCH 38/43] raise ValueError on priprity 2 with retry or expire --- borgmatic/hooks/pushover.py | 6 ++++-- tests/unit/hooks/test_pushover.py | 16 ++++------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 77ba48c5..69801baa 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -45,8 +45,10 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.info(f'{config_filename}: Setting retry to default (30sec).') state_config['retry'] = 30 else: - state_config.pop('expire', None) - state_config.pop('retry', None) + if 'expire' in state_config or 'retry' in state_config: + raise ValueError( + 'The configuration parameters retry and expire should not be set when priority is not equal to 2. Please remove them from the configuration.' + ) state_config = { key: (1 if value is True and key in 'html' else value) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index 3f14a5f1..da750d76 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -225,8 +225,8 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_high_decl ''' This simulates priority level 1, retry and expiry being set. Since expire and retry are only used for priority level 2, they should not be included - in the request sent to Pushover. This test verifies that those are - stripped from the request. + in the request sent to Pushover. This test verifies that a ValueError is + raised. ''' hook_config = { 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', @@ -234,17 +234,9 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_high_decl 'states': {'start', 'fail', 'finish'}, 'start': {'priority': 1, 'expire': 30, 'retry': 30}, } + flexmock(module.logger).should_receive('warning').never() - flexmock(module.requests).should_receive('post').with_args( - 'https://api.pushover.net/1/messages.json', - headers={'Content-type': 'application/x-www-form-urlencoded'}, - data={ - 'token': 'ksdjfwoweijfvwoeifvjmwghagy92', - 'user': '983hfe0of902lkjfa2amanfgui', - 'message': 'start', - 'priority': 1, - }, - ).and_return(flexmock(ok=True)).once() + flexmock(module.requests).should_receive('post').never() module.ping_monitor( hook_config, From 5321301708186ea6733295e1279a8a68b105b0c5 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 15:23:47 -0500 Subject: [PATCH 39/43] fix for true/false to 1/0 --- borgmatic/hooks/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 69801baa..9e6877e3 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -51,7 +51,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev ) state_config = { - key: (1 if value is True and key in 'html' else value) + key: (int(value) if value is True and key in 'html' else value) for key, value in state_config.items() } From 5f3d4f9b03b6832781ebf071952a37a9afecfb97 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Wed, 13 Nov 2024 15:27:25 -0500 Subject: [PATCH 40/43] final fix for true/false and 1/0 --- borgmatic/hooks/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index 9e6877e3..fa3b2b44 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -51,7 +51,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev ) state_config = { - key: (int(value) if value is True and key in 'html' else value) + key: (int(value) if key in 'html' else value) for key, value in state_config.items() } From dab0dfcb32a6658f0d57309b0a87edc62bd825da Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Mon, 18 Nov 2024 07:49:53 -0500 Subject: [PATCH 41/43] added test for value error --- borgmatic/hooks/pushover.py | 3 +-- tests/unit/hooks/test_pushover.py | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/borgmatic/hooks/pushover.py b/borgmatic/hooks/pushover.py index fa3b2b44..65cc636d 100644 --- a/borgmatic/hooks/pushover.py +++ b/borgmatic/hooks/pushover.py @@ -51,8 +51,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev ) state_config = { - key: (int(value) if key in 'html' else value) - for key, value in state_config.items() + key: (int(value) if key in 'html' else value) for key, value in state_config.items() } data = dict( diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index da750d76..daa24260 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -1,3 +1,4 @@ +import pytest from flexmock import flexmock import borgmatic.hooks.monitor @@ -237,15 +238,15 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_high_decl flexmock(module.logger).should_receive('warning').never() flexmock(module.requests).should_receive('post').never() - - module.ping_monitor( - hook_config, - {}, - 'config.yaml', - borgmatic.hooks.monitor.State.START, - monitoring_log_level=1, - dry_run=False, - ) + with pytest.raises(ValueError): + module.ping_monitor( + hook_config, + {}, + 'config.yaml', + borgmatic.hooks.monitor.State.START, + monitoring_log_level=1, + dry_run=False, + ) def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example_success(): From 25572c98d7337386bd875337608cc19ff2ccd278 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Mon, 18 Nov 2024 07:52:19 -0500 Subject: [PATCH 42/43] better fuction name --- tests/unit/hooks/test_pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/hooks/test_pushover.py b/tests/unit/hooks/test_pushover.py index daa24260..2654aac2 100644 --- a/tests/unit/hooks/test_pushover.py +++ b/tests/unit/hooks/test_pushover.py @@ -222,7 +222,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency ) -def test_ping_monitor_start_state_backup_default_message_with_priority_high_declared_expire_and_retry_delared_success(): +def test_ping_monitor_start_state_backup_default_message_with_priority_high_declared_expire_and_retry_ignored_success(): ''' This simulates priority level 1, retry and expiry being set. Since expire and retry are only used for priority level 2, they should not be included From 6bce4c4a0dda0d236ef3912f7c3a04de7547e014 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Mon, 18 Nov 2024 07:56:00 -0500 Subject: [PATCH 43/43] changed version release to 1.9.2 --- docs/how-to/monitor-your-backups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index e708c005..daf1adc6 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -293,7 +293,7 @@ us](https://torsion.org/borgmatic/#support-and-contributing). ## Pushover hook -New in version 1.9.1 +New in version 1.9.2 [Pushover](https://pushover.net) makes it easy to get real-time notifications on your Android, iPhone, iPad, and Desktop (Android Wear and Apple Watch, too!).