Amberelectric (#56448)

* Add Amber Electric integration

* Linting

* Fixing some type hinting

* Adding docstrings

* Removing files that shouldn't have been changed

* Splitting out test helpers

* Testing the price sensor

* Testing Controlled load and feed in channels

* Refactoring mocks

* switching state for native_value and unit_of_measurement for native_unit_of_measurement

* Fixing docstrings

* Fixing requiremennts_all.txt

* isort fixes

* Fixing pylint errors

* Omitting __init__.py from test coverage

* Add missing config_flow tests

* Adding more sensor tests

* Applying suggested changes to __init.py__

* Refactor coordinator to return the data object with all of the relevent data already setup

* Another coordinator refactor - Better use the dictionary for when we build the sensors

* Removing first function

* Refactoring sensor files to use entity descriptions, remove factory

* Rounding renewable percentage, return icons correctly

* Cleaning up translation strings

* Fixing relative path, removing TODO

* Coordintator tests now accept new (more accurate) fixtures

* Using a description placeholder

* Putting missing translations strings back in

* tighten up the no site error logic - self._site_id should never be None at the point of loading async_step_site

* Removing DEVICE_CLASS, replacing the units with AUD/kWh

* Settings _attr_unique_id

* Removing icon function (it's already the default)

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Adding strings.json

* Tighter wrapping for try/except

* Generating translations

* Removing update_method - not needed as it's being overriden

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Fixing tests

* Add missing description placeholder

* Fix warning

* changing name from update to update_data to match async_update_data

* renaming [async_]update_data => [async_]update_price_data to avoid confusion

* Creating too man renewable sensors

* Override update method

* Coordinator tests use _async_update_data

* Using $/kWh as the units

* Using isinstance instead of __class__ test. Removing a zero len check

* Asserting self._sites in second step

* Linting

* Remove useless tests

Co-authored-by: jan iversen <jancasacondor@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
Myles Eftos 2021-09-28 17:03:51 +10:00 committed by GitHub
parent f93539ef4c
commit 412ecacca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1326 additions and 0 deletions

View file

@ -0,0 +1,148 @@
"""Tests for the Amber config flow."""
from typing import Generator
from unittest.mock import Mock, patch
from amberelectric import ApiException
from amberelectric.model.site import Site
import pytest
from homeassistant import data_entry_flow
from homeassistant.components.amberelectric.const import (
CONF_SITE_ID,
CONF_SITE_NAME,
CONF_SITE_NMI,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_API_TOKEN
from homeassistant.core import HomeAssistant
API_KEY = "psk_123456789"
@pytest.fixture(name="invalid_key_api")
def mock_invalid_key_api() -> Generator:
"""Return an authentication error."""
instance = Mock()
instance.get_sites.side_effect = ApiException(status=403)
with patch("amberelectric.api.AmberApi.create", return_value=instance):
yield instance
@pytest.fixture(name="api_error")
def mock_api_error() -> Generator:
"""Return an authentication error."""
instance = Mock()
instance.get_sites.side_effect = ApiException(status=500)
with patch("amberelectric.api.AmberApi.create", return_value=instance):
yield instance
@pytest.fixture(name="single_site_api")
def mock_single_site_api() -> Generator:
"""Return a single site."""
instance = Mock()
site = Site("01FG0AGP818PXK0DWHXJRRT2DH", "11111111111", [])
instance.get_sites.return_value = [site]
with patch("amberelectric.api.AmberApi.create", return_value=instance):
yield instance
@pytest.fixture(name="no_site_api")
def mock_no_site_api() -> Generator:
"""Return no site."""
instance = Mock()
instance.get_sites.return_value = []
with patch("amberelectric.api.AmberApi.create", return_value=instance):
yield instance
async def test_single_site(hass: HomeAssistant, single_site_api: Mock) -> None:
"""Test single site."""
initial_result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert initial_result.get("type") == data_entry_flow.RESULT_TYPE_FORM
assert initial_result.get("step_id") == "user"
# Test filling in API key
enter_api_key_result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_API_TOKEN: API_KEY},
)
assert enter_api_key_result.get("type") == data_entry_flow.RESULT_TYPE_FORM
assert enter_api_key_result.get("step_id") == "site"
select_site_result = await hass.config_entries.flow.async_configure(
enter_api_key_result["flow_id"],
{CONF_SITE_NMI: "11111111111", CONF_SITE_NAME: "Home"},
)
# Show available sites
assert select_site_result.get("type") == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert select_site_result.get("title") == "Home"
data = select_site_result.get("data")
assert data
assert data[CONF_API_TOKEN] == API_KEY
assert data[CONF_SITE_ID] == "01FG0AGP818PXK0DWHXJRRT2DH"
assert data[CONF_SITE_NMI] == "11111111111"
async def test_no_site(hass: HomeAssistant, no_site_api: Mock) -> None:
"""Test no site."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_API_TOKEN: "psk_123456789"},
)
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
# Goes back to the user step
assert result.get("step_id") == "user"
assert result.get("errors") == {"api_token": "no_site"}
async def test_invalid_key(hass: HomeAssistant, invalid_key_api: Mock) -> None:
"""Test invalid api key."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
assert result.get("step_id") == "user"
# Test filling in API key
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_API_TOKEN: "psk_123456789"},
)
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
# Goes back to the user step
assert result.get("step_id") == "user"
assert result.get("errors") == {"api_token": "invalid_api_token"}
async def test_unknown_error(hass: HomeAssistant, api_error: Mock) -> None:
"""Test invalid api key."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
assert result.get("step_id") == "user"
# Test filling in API key
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_API_TOKEN: "psk_123456789"},
)
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
# Goes back to the user step
assert result.get("step_id") == "user"
assert result.get("errors") == {"api_token": "unknown_error"}