diff --git a/homeassistant/components/onedrive/services.py b/homeassistant/components/onedrive/services.py index 1e579b82a0fc2..87539a032822f 100644 --- a/homeassistant/components/onedrive/services.py +++ b/homeassistant/components/onedrive/services.py @@ -42,7 +42,7 @@ def _read_file_contents( hass: HomeAssistant, filenames: list[str] ) -> list[tuple[str, bytes]]: """Return the mime types and file contents for each file.""" - results = [] + missing: list[str] = [] for filename in filenames: if not hass.config.is_allowed_path(filename): raise HomeAssistantError( @@ -50,20 +50,27 @@ def _read_file_contents( translation_key="no_access_to_path", translation_placeholders={"filename": filename}, ) + if not Path(filename).exists(): + missing.append(filename) + if missing: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="filenames_do_not_exist", + translation_placeholders={ + "filenames": ", ".join(f"`{f}`" for f in missing) + }, + ) + results = [] + for filename in filenames: filename_path = Path(filename) - if not filename_path.exists(): - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="filename_does_not_exist", - translation_placeholders={"filename": filename}, - ) - if filename_path.stat().st_size > CONTENT_SIZE_LIMIT: + file_size = filename_path.stat().st_size + if file_size > CONTENT_SIZE_LIMIT: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="file_too_large", translation_placeholders={ "filename": filename, - "size": str(filename_path.stat().st_size), + "size": str(file_size), "limit": str(CONTENT_SIZE_LIMIT), }, ) diff --git a/homeassistant/components/onedrive/strings.json b/homeassistant/components/onedrive/strings.json index 028d41d8bcc6e..1f1aa5ec38924 100644 --- a/homeassistant/components/onedrive/strings.json +++ b/homeassistant/components/onedrive/strings.json @@ -102,8 +102,8 @@ "file_too_large": { "message": "`{filename}` is too large ({size} > {limit})" }, - "filename_does_not_exist": { - "message": "`{filename}` does not exist" + "filenames_do_not_exist": { + "message": "The following files do not exist: {filenames}" }, "no_access_to_path": { "message": "Cannot read {filename}, no access to path; `allowlist_external_dirs` may need to be adjusted in `configuration.yaml`" diff --git a/tests/components/onedrive/test_services.py b/tests/components/onedrive/test_services.py index df50a32b6877c..cb0bb8721ed44 100644 --- a/tests/components/onedrive/test_services.py +++ b/tests/components/onedrive/test_services.py @@ -194,7 +194,7 @@ async def test_filename_does_not_exist( ) -> None: """Test upload service call with a filename path that does not exist.""" await setup_integration(hass, mock_config_entry) - with pytest.raises(HomeAssistantError, match="does not exist"): + with pytest.raises(HomeAssistantError) as exc_info: await hass.services.async_call( DOMAIN, UPLOAD_SERVICE, @@ -206,6 +206,33 @@ async def test_filename_does_not_exist( blocking=True, return_response=True, ) + assert exc_info.value.translation_key == "filenames_do_not_exist" + assert TEST_FILENAME in exc_info.value.translation_placeholders["filenames"] + + +@pytest.mark.parametrize("upload_file", [MockUploadFile(exists=False)]) +async def test_multiple_filenames_do_not_exist( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """Test upload service reports all missing files, not just the first one.""" + await setup_integration(hass, mock_config_entry) + second_filename = "other_snapshot.jpg" + with pytest.raises(HomeAssistantError) as exc_info: + await hass.services.async_call( + DOMAIN, + UPLOAD_SERVICE, + { + CONF_CONFIG_ENTRY_ID: mock_config_entry.entry_id, + CONF_FILENAME: [TEST_FILENAME, second_filename], + CONF_DESTINATION_FOLDER: DESINATION_FOLDER, + }, + blocking=True, + return_response=True, + ) + assert exc_info.value.translation_key == "filenames_do_not_exist" + assert TEST_FILENAME in exc_info.value.translation_placeholders["filenames"] + assert second_filename in exc_info.value.translation_placeholders["filenames"] async def test_upload_service_fails_upload(