Skip to content

Commit

Permalink
fix: handle more errors with mailbox listing (moralmunky#935)
Browse files Browse the repository at this point in the history
* handle more errors with mailbox listing

* formatting

* refactor: clean up code that did nothing

* update tests
  • Loading branch information
firstof9 authored Jul 4, 2024
1 parent e78fd30 commit 4f5fdb9
Show file tree
Hide file tree
Showing 3 changed files with 331 additions and 9 deletions.
16 changes: 7 additions & 9 deletions custom_components/mail_and_packages/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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


Expand All @@ -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

Expand All @@ -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,
}
)

Expand Down
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"[email protected] 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."""
Expand Down
302 changes: 302 additions & 0 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": "[email protected]",
"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": "[email protected]",
"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()
Expand Down Expand Up @@ -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": "[email protected]",
"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": "[email protected]",
"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",
# [
Expand Down

0 comments on commit 4f5fdb9

Please sign in to comment.