From fdaa640c8ec41589eacf292bfd7335bbdd12d61e Mon Sep 17 00:00:00 2001 From: Josef Zweck Date: Sat, 15 Feb 2025 21:44:59 +0100 Subject: [PATCH] Add issues for data cap to onedrive (#138411) * Add issues for data cap to onedrive * brackets * Fix double space Co-authored-by: Daniel O'Connor --------- Co-authored-by: Daniel O'Connor --- .../components/onedrive/coordinator.py | 25 ++++++++++++ .../components/onedrive/strings.json | 10 +++++ tests/components/onedrive/test_init.py | 39 ++++++++++++++++++- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/onedrive/coordinator.py b/homeassistant/components/onedrive/coordinator.py index cc759437c07..7b2dbaab87a 100644 --- a/homeassistant/components/onedrive/coordinator.py +++ b/homeassistant/components/onedrive/coordinator.py @@ -8,12 +8,14 @@ from datetime import timedelta import logging from onedrive_personal_sdk import OneDriveClient +from onedrive_personal_sdk.const import DriveState from onedrive_personal_sdk.exceptions import AuthenticationError, OneDriveException from onedrive_personal_sdk.models.items import Drive from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DOMAIN @@ -67,4 +69,27 @@ class OneDriveUpdateCoordinator(DataUpdateCoordinator[Drive]): raise UpdateFailed( translation_domain=DOMAIN, translation_key="update_failed" ) from err + + # create an issue if the drive is almost full + if drive.quota and (state := drive.quota.state) in ( + DriveState.CRITICAL, + DriveState.EXCEEDED, + ): + key = "drive_full" if state is DriveState.EXCEEDED else "drive_almost_full" + ir.async_create_issue( + self.hass, + DOMAIN, + key, + is_fixable=False, + severity=( + ir.IssueSeverity.ERROR + if state is DriveState.EXCEEDED + else ir.IssueSeverity.WARNING + ), + translation_key=key, + translation_placeholders={ + "total": str(drive.quota.total), + "used": str(drive.quota.used), + }, + ) return drive diff --git a/homeassistant/components/onedrive/strings.json b/homeassistant/components/onedrive/strings.json index c3087d435b8..3a9f6d06594 100644 --- a/homeassistant/components/onedrive/strings.json +++ b/homeassistant/components/onedrive/strings.json @@ -29,6 +29,16 @@ "default": "[%key:common::config_flow::create_entry::authenticated%]" } }, + "issues": { + "drive_full": { + "title": "OneDrive data cap exceeded", + "description": "Your OneDrive has exceeded your quota limit. This means your next backup will fail. Please free up some space or upgrade your OneDrive plan. Currently using {used} GB of {total} GB." + }, + "drive_almost_full": { + "title": "OneDrive near data cap", + "description": "Your OneDrive is near your quota limit. If you go over this limit your drive will be temporarily frozen and your backups will start failing. Please free up some space or upgrade your OneDrive plan. Currently using {used} GB of {total} GB." + } + }, "exceptions": { "authentication_failed": { "message": "Authentication failed" diff --git a/tests/components/onedrive/test_init.py b/tests/components/onedrive/test_init.py index 65c3e62629c..b4ec138ebf4 100644 --- a/tests/components/onedrive/test_init.py +++ b/tests/components/onedrive/test_init.py @@ -1,9 +1,11 @@ """Test the OneDrive setup.""" +from copy import deepcopy from html import escape from json import dumps from unittest.mock import MagicMock +from onedrive_personal_sdk.const import DriveState from onedrive_personal_sdk.exceptions import AuthenticationError, OneDriveException import pytest from syrupy import SnapshotAssertion @@ -11,7 +13,7 @@ from syrupy import SnapshotAssertion from homeassistant.components.onedrive.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, issue_registry as ir from . import setup_integration from .const import BACKUP_METADATA, MOCK_BACKUP_FILE, MOCK_DRIVE @@ -131,3 +133,38 @@ async def test_device( device = device_registry.async_get_device({(DOMAIN, MOCK_DRIVE.id)}) assert device assert device == snapshot + + +@pytest.mark.parametrize( + ( + "drive_state", + "issue_key", + "issue_exists", + ), + [ + (DriveState.NORMAL, "drive_full", False), + (DriveState.NORMAL, "drive_almost_full", False), + (DriveState.CRITICAL, "drive_almost_full", True), + (DriveState.CRITICAL, "drive_full", False), + (DriveState.EXCEEDED, "drive_almost_full", False), + (DriveState.EXCEEDED, "drive_full", True), + ], +) +async def test_data_cap_issues( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_onedrive_client: MagicMock, + drive_state: DriveState, + issue_key: str, + issue_exists: bool, +) -> None: + """Make sure we get issues for high data usage.""" + mock_drive = deepcopy(MOCK_DRIVE) + assert mock_drive.quota + mock_drive.quota.state = drive_state + mock_onedrive_client.get_drive.return_value = mock_drive + await setup_integration(hass, mock_config_entry) + + issue_registry = ir.async_get(hass) + issue = issue_registry.async_get_issue(DOMAIN, issue_key) + assert (issue is not None) == issue_exists