Skip to content

Commit

Permalink
test: add vmoto specific tests (wip #3)
Browse files Browse the repository at this point in the history
  • Loading branch information
drakhart committed Apr 14, 2023
1 parent 04eedc2 commit d1e48b4
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 29 deletions.
32 changes: 31 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,44 @@ def bypass_super_soco_get_warning_fixture():

@pytest.fixture(name="bypass_super_soco_login")
def bypass_super_soco_login_fixture():
"""Skip calls to get device from Super Soco API."""
"""Skip calls to login from Super Soco API."""
with patch(
"custom_components.super_soco_custom.SuperSocoAPI.login",
return_value=json.loads(load_fixture("super_soco_login.json")),
):
yield


@pytest.fixture(name="bypass_vmoto_soco_get_login_code")
def bypass_vmoto_soco_get_login_code_fixture():
"""Skip calls to get login code from Vmoto Soco API."""
with patch(
"custom_components.super_soco_custom.VmotoSocoAPI.get_login_code",
return_value=json.loads(load_fixture("vmoto_soco_login_code.json")),
):
yield


@pytest.fixture(name="bypass_vmoto_soco_get_user")
def bypass_vmoto_soco_get_user_fixture():
"""Skip calls to get user from Vmoto Soco API."""
with patch(
"custom_components.super_soco_custom.VmotoSocoAPI.get_user",
return_value=json.loads(load_fixture("vmoto_soco_user.json")),
):
yield


@pytest.fixture(name="bypass_vmoto_soco_login")
def bypass_vmoto_soco_login_fixture():
"""Skip calls to login from Vmoto Soco API."""
with patch(
"custom_components.super_soco_custom.VmotoSocoAPI.login",
return_value=json.loads(load_fixture("vmoto_soco_login.json")),
):
yield


# Fixtures to return exceptions from API calls
@pytest.fixture(name="auth_error_on_login")
def auth_error_login_fixture():
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/vmoto_soco_user.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"data": {
"device": {
"accumulativeRim": 0,
"deviceNo": "1234567890123456",
"ecuElec": 100,
"endurance": 30,
"gps": 12,
Expand Down
71 changes: 59 additions & 12 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from custom_components.super_soco_custom.const import (
CONF_APP_NAME,
CONF_LOGIN_CODE,
CONF_PHONE_NUMBER,
CONF_PHONE_PREFIX,
CONF_PASSWORD,
Expand All @@ -22,7 +23,7 @@
OPT_UPDATE_INTERVAL,
)

from .const import MOCK_SUPER_SOCO_CONFIG
from .const import MOCK_SUPER_SOCO_CONFIG, MOCK_VMOTO_SOCO_CONFIG


# This fixture bypasses the actual setup of the integration
Expand All @@ -41,20 +42,15 @@ def bypass_setup_fixture():
yield


# Here we simiulate a successful config flow from the backend.
# Note that we use the `bypass_super_soco_get_data` fixture here because
# Here we simulate a successful Super Soco config flow from the backend.
# Note that we use the `bypass_super_soco_login` fixture here because
# we want the config flow validation to succeed during the test.
@pytest.mark.asyncio
async def test_successful_config_flow(
async def test_successful_super_soco_config_flow(
hass,
bypass_super_soco_get_device,
bypass_get_mapzen,
bypass_super_soco_get_tracking_history_list,
bypass_super_soco_get_user,
bypass_super_soco_get_warning_list,
bypass_super_soco_login,
bypass_super_soco_login, # pylint: disable=unused-argument
):
"""Test a successful config flow."""
"""Test a successful Super Soco config flow."""
# Initialize a config flow
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
Expand Down Expand Up @@ -92,11 +88,62 @@ async def test_successful_config_flow(
assert result["result"]


# Here we simulate a successful Vmoto Soco config flow from the backend.
# Note that we use the `bypass_vmoto_soco_get_login_code` and
# `bypass_vmoto_soco_login` fixture here because we want the config flow
# validation to succeed during the test.
@pytest.mark.asyncio
async def test_successful_vmoto_soco_config_flow(
hass,
bypass_vmoto_soco_get_login_code, # pylint: disable=unused-argument
bypass_vmoto_soco_login, # pylint: disable=unused-argument
):
"""Test a successful Vmoto Soco config flow."""
# Initialize a config flow
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)

# Check that the config flow shows the user form as the first step
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "app"

# Continue past the app step
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_APP_NAME: MOCK_VMOTO_SOCO_CONFIG[CONF_APP_NAME],
CONF_PHONE_NUMBER: MOCK_VMOTO_SOCO_CONFIG[CONF_PHONE_NUMBER],
CONF_PHONE_PREFIX: MOCK_VMOTO_SOCO_CONFIG[CONF_PHONE_PREFIX],
},
)

# Check that the config flow shows the login form as the next step
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "login"

# Continue past the login step
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_LOGIN_CODE: MOCK_VMOTO_SOCO_CONFIG[CONF_LOGIN_CODE]},
)

# Check that the config flow is complete and a new entry is created with
# the input data
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME
assert result["data"] == MOCK_VMOTO_SOCO_CONFIG
assert result["result"]


# In this case, we want to simulate a failure during the config flow.
# We use the `auth_error_on_login` (note the function parameters) to
# raise an Exception during validation of the input config.
@pytest.mark.asyncio
async def test_failed_config_flow(hass, auth_error_on_login):
async def test_failed_config_flow(
hass,
auth_error_on_login, # pylint: disable=unused-argument
):
"""Test a failed config flow due to credential validation failure."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
Expand Down
54 changes: 44 additions & 10 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
)
from custom_components.super_soco_custom.const import DOMAIN

from .const import MOCK_SUPER_SOCO_CONFIG
from .const import MOCK_SUPER_SOCO_CONFIG, MOCK_VMOTO_SOCO_CONFIG


# We can pass fixtures as defined in conftest.py to tell pytest to use the fixture
Expand All @@ -22,16 +22,12 @@
# side of the assertion matches with the right side.
@pytest.mark.asyncio
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_setup_unload_and_reload_entry(
async def test_setup_reload_and_unload_super_soco_entry(
hass,
bypass_super_soco_get_device,
bypass_get_mapzen,
bypass_super_soco_get_tracking_history_list,
bypass_super_soco_get_user,
bypass_super_soco_get_warning_list,
bypass_super_soco_login,
bypass_super_soco_get_device, # pylint: disable=unused-argument
bypass_super_soco_get_user, # pylint: disable=unused-argument
):
"""Test entry setup and unload."""
"""Test Super Soco entry setup and unload."""
# Create a mock entry so we don't have to go through config flow
config_entry = MockConfigEntry(
domain=DOMAIN, data=MOCK_SUPER_SOCO_CONFIG, entry_id="test"
Expand Down Expand Up @@ -61,7 +57,45 @@ async def test_setup_unload_and_reload_entry(


@pytest.mark.asyncio
async def test_setup_entry_exception(hass, auth_error_on_login):
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_setup_reload_and_unload_vmoto_soco_entry(
hass,
bypass_vmoto_soco_get_user, # pylint: disable=unused-argument
):
"""Test Vmoto Soco entry setup and unload."""
# Create a mock entry so we don't have to go through config flow
config_entry = MockConfigEntry(
domain=DOMAIN, data=MOCK_VMOTO_SOCO_CONFIG, entry_id="test"
)

# Set up the entry and assert that the values set during setup are where we expect
# them to be. Because we have patched the SuperSocoCustomDataUpdateCoordinator.async_get_data
# call, no code from custom_components/super_soco_custom/super_soco_api.py actually runs.
assert await async_setup_entry(hass, config_entry)
assert DOMAIN in hass.data and config_entry.entry_id in hass.data[DOMAIN]
assert (
type(hass.data[DOMAIN][config_entry.entry_id])
== SuperSocoCustomDataUpdateCoordinator
)

# Reload the entry and assert that the data from above is still there
assert await async_reload_entry(hass, config_entry) is None
assert DOMAIN in hass.data and config_entry.entry_id in hass.data[DOMAIN]
assert (
type(hass.data[DOMAIN][config_entry.entry_id])
== SuperSocoCustomDataUpdateCoordinator
)

# Unload the entry and verify that the data has been removed
assert await async_unload_entry(hass, config_entry)
assert config_entry.entry_id not in hass.data[DOMAIN]


@pytest.mark.asyncio
async def test_setup_entry_exception(
hass,
auth_error_on_login, # pylint: disable=unused-argument
):
"""Test ConfigEntryNotReady when API raises an exception during entry setup."""
config_entry = MockConfigEntry(
domain=DOMAIN, data=MOCK_SUPER_SOCO_CONFIG, entry_id="test"
Expand Down
8 changes: 2 additions & 6 deletions tests/test_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_switch_services(
hass,
bypass_super_soco_get_device,
bypass_get_mapzen,
bypass_super_soco_get_tracking_history_list,
bypass_super_soco_get_user,
bypass_super_soco_get_warning_list,
bypass_super_soco_login,
bypass_super_soco_get_device, # pylint: disable=unused-argument
bypass_super_soco_get_user, # pylint: disable=unused-argument
):
"""Test switch services."""
# Create a mock entry so we don't have to go through config flow
Expand Down

0 comments on commit d1e48b4

Please sign in to comment.