From 4f5fdb98208ace20d521b1633d007c462d6c8c01 Mon Sep 17 00:00:00 2001 From: Chris <1105672+firstof9@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:20:52 -0700 Subject: [PATCH] fix: handle more errors with mailbox listing (#935) * handle more errors with mailbox listing * formatting * refactor: clean up code that did nothing * update tests --- .../mail_and_packages/config_flow.py | 16 +- tests/conftest.py | 22 ++ tests/test_config_flow.py | 302 ++++++++++++++++++ 3 files changed, 331 insertions(+), 9 deletions(-) diff --git a/custom_components/mail_and_packages/config_flow.py b/custom_components/mail_and_packages/config_flow.py index e3ce823d..7c6dda13 100644 --- a/custom_components/mail_and_packages/config_flow.py +++ b/custom_components/mail_and_packages/config_flow.py @@ -47,6 +47,7 @@ ) from .helpers import _check_ffmpeg, _test_login, get_resources, login +ERROR_MAILBOX_FAIL = "Problem getting mailbox listing using 'INBOX' message" IMAP_SECURITY = ["none", "startTLS", "SSL"] _LOGGER = logging.getLogger(__name__) @@ -115,14 +116,6 @@ async def _validate_user_input(user_input: dict) -> tuple: if not valid: errors[CONF_CUSTOM_IMG_FILE] = "file_not_found" - # validate scan interval - if user_input[CONF_SCAN_INTERVAL] < 5: - errors[CONF_SCAN_INTERVAL] = "scan_too_low" - - # validate imap timeout - if user_input[CONF_IMAP_TIMEOUT] < 10: - errors[CONF_IMAP_TIMEOUT] = "timeout_too_low" - return errors, user_input @@ -149,6 +142,9 @@ def _get_mailboxes( except IndexError: _LOGGER.error("Error creating folder array, using INBOX") mailboxes.append(DEFAULT_FOLDER) + except Exception as err: + _LOGGER.error("%s: %s", ERROR_MAILBOX_FAIL, err) + mailboxes.append(DEFAULT_FOLDER) return mailboxes @@ -171,7 +167,9 @@ def _get_default(key: str, fallback_default: Any = None) -> None: vol.Required( CONF_IMAP_SECURITY, default=_get_default(CONF_IMAP_SECURITY) ): vol.In(IMAP_SECURITY), - vol.Required(CONF_VERIFY_SSL, default=_get_default(CONF_VERIFY_SSL)): bool, + vol.Required( + CONF_VERIFY_SSL, default=_get_default(CONF_VERIFY_SSL) + ): cv.boolean, } ) diff --git a/tests/conftest.py b/tests/conftest.py index ff821595..b8783e69 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -364,6 +364,28 @@ def mock_imap_mailbox_format2(): yield mock_conn +@pytest.fixture() +def mock_imap_mailbox_format3(): + """Mock imap class values.""" + with patch( + "custom_components.mail_and_packages.helpers.imaplib" + ) as mock_imap_mailbox_format3: + mock_conn = mock.Mock(spec=imaplib.IMAP4_SSL) + mock_imap_mailbox_format3.IMAP4_SSL.return_value = mock_conn + + mock_conn.login.return_value = ( + "OK", + [b"user@fake.email authenticated (Success)"], + ) + mock_conn.list.return_value = ( + "ERR", + [b'(\\HasNoChildren) "%" "INBOX"'], + ) + mock_conn.search.return_value = ("OK", [b"0"]) + mock_conn.uid.return_value = ("OK", [b"0"]) + yield mock_conn + + @pytest.fixture() def mock_imap_usps_informed_digest(): """Mock imap class values.""" diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index 4d54fa3f..0953f89a 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -1141,6 +1141,155 @@ async def test_form_mailbox_format2( assert len(mock_setup_entry.mock_calls) == 1 +@pytest.mark.parametrize( + "input_1,step_id_2,input_2,title,data", + [ + ( + { + "host": "imap.test.email", + "port": "993", + "username": "test@test.email", + "password": "notarealpassword", + "imap_security": "SSL", + "verify_ssl": False, + }, + "config_2", + { + "allow_external": False, + "amazon_days": 3, + "amazon_fwds": "", + "folder": '"INBOX"', + "generate_mp4": False, + "gif_duration": 5, + "imap_timeout": 30, + "scan_interval": 20, + "resources": [ + "amazon_packages", + "fedex_delivered", + "fedex_delivering", + "fedex_packages", + "mail_updated", + "ups_delivered", + "ups_delivering", + "ups_packages", + "usps_delivered", + "usps_delivering", + "usps_mail", + "usps_packages", + "zpackages_delivered", + "zpackages_transit", + "dhl_delivered", + "dhl_delivering", + "dhl_packages", + "amazon_delivered", + "auspost_delivered", + "auspost_delivering", + "auspost_packages", + "poczta_polska_delivering", + "poczta_polska_packages", + "inpost_pl_delivered", + "inpost_pl_delivering", + "inpost_pl_packages", + ], + }, + "imap.test.email", + { + "allow_external": False, + "custom_img": False, + "amazon_days": 3, + "amazon_fwds": [], + "host": "imap.test.email", + "port": 993, + "username": "test@test.email", + "password": "notarealpassword", + "folder": '"INBOX"', + "generate_mp4": False, + "gif_duration": 5, + "imap_security": "SSL", + "imap_timeout": 30, + "scan_interval": 20, + "resources": [ + "amazon_packages", + "fedex_delivered", + "fedex_delivering", + "fedex_packages", + "mail_updated", + "ups_delivered", + "ups_delivering", + "ups_packages", + "usps_delivered", + "usps_delivering", + "usps_mail", + "usps_packages", + "zpackages_delivered", + "zpackages_transit", + "dhl_delivered", + "dhl_delivering", + "dhl_packages", + "amazon_delivered", + "auspost_delivered", + "auspost_delivering", + "auspost_packages", + "poczta_polska_delivering", + "poczta_polska_packages", + "inpost_pl_delivered", + "inpost_pl_delivering", + "inpost_pl_packages", + ], + "verify_ssl": False, + }, + ), + ], +) +@pytest.mark.asyncio +async def test_form_mailbox_format3( + input_1, + step_id_2, + input_2, + title, + data, + hass, + mock_imap_mailbox_format3, +): + """Test we get the form.""" + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + # assert result["title"] == title_1 + + with patch( + "custom_components.mail_and_packages.config_flow._test_login", return_value=True + ), patch( + "custom_components.mail_and_packages.config_flow._check_ffmpeg", + return_value=True, + ), patch( + "custom_components.mail_and_packages.async_setup", return_value=True + ) as mock_setup, patch( + "custom_components.mail_and_packages.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], input_1 + ) + assert result2["type"] == "form" + assert result2["step_id"] == step_id_2 + + result3 = await hass.config_entries.flow.async_configure( + result["flow_id"], input_2 + ) + + assert result3["type"] == "create_entry" + assert result3["title"] == title + assert result3["data"] == data + + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + @pytest.mark.asyncio async def test_valid_ffmpeg(test_valid_ffmpeg): result = await _check_ffmpeg() @@ -2203,6 +2352,159 @@ async def test_options_flow_mailbox_format2( await hass.async_block_till_done() +@pytest.mark.parametrize( + "input_1,step_id_2,input_2,title,data", + [ + ( + { + "host": "imap.test.email", + "port": "993", + "username": "test@test.email", + "password": "notarealpassword", + "imap_security": "SSL", + "verify_ssl": False, + }, + "options_2", + { + "allow_external": False, + "amazon_days": 3, + "amazon_fwds": "", + "custom_img": False, + "folder": '"INBOX"', + "generate_mp4": False, + "gif_duration": 5, + "imap_timeout": 30, + "scan_interval": 20, + "resources": [ + "amazon_packages", + "fedex_delivered", + "fedex_delivering", + "fedex_packages", + "mail_updated", + "ups_delivered", + "ups_delivering", + "ups_packages", + "usps_delivered", + "usps_delivering", + "usps_mail", + "usps_packages", + "zpackages_delivered", + "zpackages_transit", + "dhl_delivered", + "dhl_delivering", + "dhl_packages", + "amazon_delivered", + "auspost_delivered", + "auspost_delivering", + "auspost_packages", + "poczta_polska_delivering", + "poczta_polska_packages", + "inpost_pl_delivered", + "inpost_pl_delivering", + "inpost_pl_packages", + ], + }, + "imap.test.email", + { + "allow_external": False, + "amazon_days": 3, + "amazon_fwds": [], + "custom_img": False, + "host": "imap.test.email", + "port": 993, + "username": "test@test.email", + "password": "notarealpassword", + "folder": '"INBOX"', + "generate_mp4": False, + "gif_duration": 5, + "imap_security": "SSL", + "imap_timeout": 30, + "scan_interval": 20, + "resources": [ + "amazon_packages", + "fedex_delivered", + "fedex_delivering", + "fedex_packages", + "mail_updated", + "ups_delivered", + "ups_delivering", + "ups_packages", + "usps_delivered", + "usps_delivering", + "usps_mail", + "usps_packages", + "zpackages_delivered", + "zpackages_transit", + "dhl_delivered", + "dhl_delivering", + "dhl_packages", + "amazon_delivered", + "auspost_delivered", + "auspost_delivering", + "auspost_packages", + "poczta_polska_delivering", + "poczta_polska_packages", + "inpost_pl_delivered", + "inpost_pl_delivering", + "inpost_pl_packages", + ], + "verify_ssl": False, + }, + ), + ], +) +@pytest.mark.asyncio +async def test_options_flow_mailbox_format3( + input_1, + step_id_2, + input_2, + title, + data, + hass, + mock_imap_mailbox_format3, +): + """Test config flow options.""" + entry = MockConfigEntry( + domain=DOMAIN, + title="imap.test.email", + data=FAKE_CONFIG_DATA, + ) + + entry.add_to_hass(hass) + + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.options.async_init(entry.entry_id) + + assert result["type"] == "form" + assert result["errors"] == {} + # assert result["title"] == title_1 + + with patch( + "custom_components.mail_and_packages.config_flow._test_login", return_value=True + ), patch( + "custom_components.mail_and_packages.config_flow._check_ffmpeg", + return_value=True, + ), patch( + "custom_components.mail_and_packages.async_setup", return_value=True + ) as mock_setup, patch( + "custom_components.mail_and_packages.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.options.async_configure( + result["flow_id"], input_1 + ) + assert result2["type"] == "form" + assert result2["step_id"] == step_id_2 + + result3 = await hass.config_entries.options.async_configure( + result["flow_id"], input_2 + ) + + assert result3["type"] == "create_entry" + assert entry.options == data + await hass.async_block_till_done() + + # @pytest.mark.parametrize( # "input_1,step_id_2,input_2,title,data", # [