Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Achievement of platinum on the integration quality scale #226

Open
wants to merge 151 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
a5d29b1
Catch duplicate API key specified
autoSteve Dec 5, 2024
600550d
Prep for next release
autoSteve Dec 5, 2024
b234597
Add unit tests for config_flow.py
autoSteve Dec 6, 2024
9cb9b33
Moving simulator out of custom_components folder
autoSteve Dec 6, 2024
a14e1ab
Streamline simulator set up
autoSteve Dec 7, 2024
c462eda
Fix hard limit validation
autoSteve Dec 7, 2024
10be9b7
Look for optimism in tests, not just pessimism
autoSteve Dec 7, 2024
1aeb42d
Refactor and enhance test_config_flow.py
autoSteve Dec 7, 2024
4374cad
Move test_option_api_quota()
autoSteve Dec 7, 2024
293fffe
Prevent start on corrupt data avoiding log explosion #227
autoSteve Dec 9, 2024
5b2d7d4
There is method to this illogical change. Unit tests. Hopefully.
autoSteve Dec 9, 2024
6d7bd2e
Unit test solcastapi.py
autoSteve Dec 12, 2024
0f738de
Fix an issue with half-hourly breakdown disabled
autoSteve Dec 12, 2024
07b3495
Add multiple solcastapi scenarios to unit test
autoSteve Dec 12, 2024
18a78b4
Prevent cache file creation when unit testing
autoSteve Dec 13, 2024
fc80900
One environment test improving readability
autoSteve Dec 13, 2024
7a967f3
Update README.md
autoSteve Dec 13, 2024
eb4b2a4
Split simulator to better support unit tests
autoSteve Dec 15, 2024
9009e4e
Remove pointless last reset disagreement
autoSteve Dec 21, 2024
111ab47
Fix some bugs, add some tests
autoSteve Dec 24, 2024
62d3183
Update DEVELOPERS.md
autoSteve Dec 24, 2024
291a0f3
Consistency of api_key
autoSteve Dec 24, 2024
6eaacc8
Extend tests to include cache usage
autoSteve Dec 26, 2024
914b707
Update tests
autoSteve Dec 26, 2024
b09241b
Update test_sensor.py
autoSteve Dec 26, 2024
d43e77f
Much tests improvement
autoSteve Dec 28, 2024
04a9cf6
Test coverage 💯
autoSteve Dec 28, 2024
4804258
Time-of-day test coverage exclusion
autoSteve Dec 28, 2024
2768066
Simulated aiohttp client responses for all tests
autoSteve Dec 30, 2024
ded175f
Re-write load sites without retry
autoSteve Dec 30, 2024
44cd6b0
Remove commented weather code
autoSteve Dec 30, 2024
e3e0764
Fix an issue on stale start with auto-update
autoSteve Dec 30, 2024
192c6f9
Update DEVELOPERS.md
autoSteve Dec 30, 2024
b0bc9fd
Tweak init tests
autoSteve Dec 30, 2024
2744b9d
Minor test tweaks
autoSteve Dec 30, 2024
db610fe
Rename init tests to integration tests
autoSteve Dec 30, 2024
4a3964c
Avoid deprecation warning for tests
autoSteve Jan 1, 2025
3b56f81
Test for ClientConnectionError
autoSteve Jan 1, 2025
c67da3f
Clean up tests init
autoSteve Jan 1, 2025
4315cfe
Add re-config/re-auth flows
autoSteve Jan 2, 2025
6d6bf29
Solve no re-load on config change
autoSteve Jan 2, 2025
65d529f
Parameterise tests for options flow
autoSteve Jan 3, 2025
c03125b
Full test coverage for energy data
autoSteve Jan 3, 2025
bd8a86f
Full test coverage for config flow
autoSteve Jan 4, 2025
ce9dc4e
Full test coverage for sensor
autoSteve Jan 4, 2025
bf8ac7a
Freeze time with freezegun for most tests
autoSteve Jan 4, 2025
c1b63f9
Compact init log and demote cache load to debug
autoSteve Jan 5, 2025
374e903
Update README.md
BJReplay Jan 6, 2025
c81cf89
Improve test coverage for solcastapi.py
autoSteve Jan 6, 2025
118087a
Merge branch 'Catch-duplicate-API-key-specified' of https://github.co…
autoSteve Jan 6, 2025
de8e625
Upgrade solcast.json from v3 #232
autoSteve Jan 6, 2025
bde3640
Update README.md
autoSteve Jan 6, 2025
56b7202
Sensors unavailable when things turn to custard
autoSteve Jan 9, 2025
7828ffe
Improve test coverage for __init__ and coordinator
autoSteve Jan 9, 2025
44f61a5
Improve coordinator test coverage
autoSteve Jan 9, 2025
c824f54
Move simulator to tests folder
autoSteve Jan 9, 2025
5b17c2f
Full test coverage for coordinator
autoSteve Jan 10, 2025
e85c225
Restore full coverage for sensor
autoSteve Jan 10, 2025
c618b45
Restore sensor updates
autoSteve Jan 11, 2025
5870b49
Test for entities not being updated correctly
autoSteve Jan 11, 2025
17f53a5
Fix stale auto-update start transitioning from automation
autoSteve Jan 11, 2025
3d0174e
Update bug_report.yml
BJReplay Jan 12, 2025
f2c9d43
Fix stale start for splines and hourly detail
autoSteve Jan 12, 2025
f851a23
Merge branch 'Catch-duplicate-API-key-specified' of https://github.co…
autoSteve Jan 12, 2025
d7f7d49
Test summer time transition
autoSteve Jan 12, 2025
f29c254
Improve test coverage of solcastapi.py
autoSteve Jan 12, 2025
a20fd67
Improve test performance significantly
autoSteve Jan 12, 2025
27c1db6
Improve test coverage for solcastapi.py and optimise tests
autoSteve Jan 13, 2025
40f3b60
Assert unhandled exceptions in test_integration.py
autoSteve Jan 13, 2025
839c8c1
Fix issue with remaining unavailable and a corner case
autoSteve Jan 14, 2025
cb2104c
Bolster sensor tests with exception check
autoSteve Jan 14, 2025
aaf988b
Translatable init exceptions
autoSteve Jan 14, 2025
44ad4c0
Add caplog.clear() for valid schema upgrade tests
autoSteve Jan 14, 2025
19da717
Add update retry mechanism test
autoSteve Jan 14, 2025
993870c
Full pytest code coverage
autoSteve Jan 14, 2025
78a0c55
API key validation in config/options flow
autoSteve Jan 15, 2025
6bdeffb
Test successful reconfigure API key
autoSteve Jan 15, 2025
9daddbc
Update README.md
autoSteve Jan 15, 2025
dccb587
Flawed ConfigEntryAuthFailed check for now
autoSteve Jan 16, 2025
b4c0c0a
Reset re-auth flag on successful test
autoSteve Jan 16, 2025
724c6a7
Update README.md
autoSteve Jan 17, 2025
1dbec74
Tweak tests
autoSteve Jan 17, 2025
62aefd0
Immediate re-auth required after bad key fetch
autoSteve Jan 17, 2025
9f7b6fd
Adjust wsgi simulator to return 403/forbidden
autoSteve Jan 17, 2025
c5240cc
Refactor config and options flows
autoSteve Jan 18, 2025
64a7ee3
Fix broken reauth and reconfig flows
autoSteve Jan 18, 2025
702a53c
Reconfigure successful not re-auth success 🤦🏻
autoSteve Jan 18, 2025
a6f01d5
Migrate usage on key change
autoSteve Jan 19, 2025
ddb20ee
Restore test coverage to 💯
autoSteve Jan 19, 2025
67f344b
Tidy up re-auth
autoSteve Jan 19, 2025
f1ba868
Strongly typed solcastapi.py public variables
autoSteve Jan 19, 2025
db7c08e
Trigger reauth flow on startup
autoSteve Jan 20, 2025
7d996b9
Fix startup sequence having a bad API key
autoSteve Jan 20, 2025
436c53e
Fix splined attributes
autoSteve Jan 20, 2025
e5fceb4
Disable some sensors by default for a new install
autoSteve Jan 20, 2025
ea7905b
Update icons.json
autoSteve Jan 20, 2025
41605dd
Test coverage back to 100%
autoSteve Jan 21, 2025
c81205b
Because BJ is smarter than a machine
autoSteve Jan 21, 2025
9f15ea6
Close test gap pv_estimate attribute because BJ is smart
autoSteve Jan 21, 2025
2f45fe3
Update DEVELOPERS.md
autoSteve Jan 21, 2025
af2f74b
Add Sample Sites Image
BJReplay Jan 22, 2025
256ef23
Update README.md
BJReplay Jan 22, 2025
b299cc9
Update README.md
BJReplay Jan 22, 2025
eb4403f
Update README.md
BJReplay Jan 22, 2025
b0a5134
Add quality_checklist.md
autoSteve Jan 22, 2025
eb8dd72
Register stub actions in async_init()
autoSteve Jan 22, 2025
55a32fc
Implement default icon translations
autoSteve Jan 22, 2025
74dc92e
Select sun angle as default icon
autoSteve Jan 22, 2025
cf866ef
Mostly strongly typed solcastapi.py
autoSteve Jan 23, 2025
653f99c
Strong type checking config_flow.py and util.py
autoSteve Jan 23, 2025
048aec2
Strong type checking coordinator.py
autoSteve Jan 23, 2025
78fb6a2
Strong type checking diagnostics.py
autoSteve Jan 23, 2025
447f623
String type checking select.py
autoSteve Jan 23, 2025
d44a716
Strong type checking __init__.py
autoSteve Jan 23, 2025
cfaa8b4
Ditch isodate
autoSteve Jan 23, 2025
ab27148
Fix tzinfo 🤦🏻 in solcastapi.py
autoSteve Jan 23, 2025
f8a6705
Strong type checking sensor.py
autoSteve Jan 24, 2025
c051023
Update scheduling debug log show the target time
autoSteve Jan 24, 2025
6e418ce
Improve strict type check coverage
autoSteve Jan 24, 2025
de001cd
Update DEVELOPERS.md
autoSteve Jan 24, 2025
fb47574
Update README.md and quality checklist
autoSteve Jan 25, 2025
f24b7fd
Update README.md and quality checklist
autoSteve Jan 25, 2025
96d7a42
Update README.md
autoSteve Jan 25, 2025
65fac37
Restore 100% pytest cover post 100% strict typing
autoSteve Jan 25, 2025
3eedfbc
Update README.md
autoSteve Jan 25, 2025
c0e0c35
Comment tweaks
autoSteve Jan 25, 2025
01f6d41
Fix an issue when api limit is adjusted
autoSteve Jan 29, 2025
6d641d3
Tests updated to suit data schema 6
autoSteve Jan 29, 2025
7d96329
Improve test coverage
autoSteve Jan 29, 2025
e31497d
Fix 429 startup cache weirdness
autoSteve Jan 30, 2025
4449305
Update wsgi_sim.py
autoSteve Jan 30, 2025
a4959ba
Fix flawed retry termination logic
autoSteve Jan 30, 2025
430e40c
Raise issue when future forecasts are missing #238
autoSteve Jan 31, 2025
111c6cb
Add "learn more" to forecasts not updating issue #238
autoSteve Jan 31, 2025
3e23ba3
Update solcastapi.py
autoSteve Jan 31, 2025
71b6675
Repair to suggest enabling auto-update #238
autoSteve Feb 1, 2025
6baadb6
End repair correctly
autoSteve Feb 1, 2025
a21907a
Badly test repairs.py, more to do
autoSteve Feb 1, 2025
b80793e
Repairs test coverage 100%
autoSteve Feb 2, 2025
7724fe4
Fix strict type checking slippage
autoSteve Feb 2, 2025
9dd8eb3
Update README.md
autoSteve Feb 2, 2025
0cf1b1d
Fix issue corner case, day zero missing data
autoSteve Feb 2, 2025
8c1aa9f
Retrieve forecast past actuals on very stale start
autoSteve Feb 3, 2025
07cb096
Self-labeled an "idiot"
autoSteve Feb 3, 2025
ce93e1b
Restore strict type checking for __init__.py
autoSteve Feb 3, 2025
856399f
Create .gitignore
autoSteve Feb 3, 2025
6ccb1d4
Update README.md
autoSteve Feb 4, 2025
46bc714
Do not re-raise issue after issue repair
autoSteve Feb 5, 2025
eebadf7
Remove code that should never execute
autoSteve Feb 5, 2025
0578c46
Tweak issue removal
autoSteve Feb 5, 2025
3223dc3
Add auto-update attributes to api_last_polled
autoSteve Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Hi community!

A Solcast API simulator and unit tests are available for this custom integration. To set up for both, add these mounts to your HA dev container, adjusting for your local integration fork.

```
"mounts": [
"source=${localEnv:HOME}/Documents/GitHub/ha-solcast-solar/custom_components/solcast_solar,target=${containerWorkspaceFolder}/config/custom_components/solcast_solar,type=bind",
"source=${localEnv:HOME}/Documents/GitHub/ha-solcast-solar/tests,target=${containerWorkspaceFolder}/tests/components/solcast_solar,type=bind",
"source=${localEnv:HOME}/Documents/GitHub/ha-solcast-solar/sim,target=${containerWorkspaceFolder}/config/custom_components/solcast_solar/sim,type=bind"
],
```

To get the simulator to work, the container will need a `pip install flask`, along with modifying `/etc/hosts` to specify `127.0.0.1 localhost api.solcast.com.au`. For a quick start, `cd config/custom_components/solcast_solar/sim` and execute `python3 -u wsgi.py --limit 5000 --no429`, which gets 5,000 API calls max, and no 'too busy' errors generated on the hour. (`python3 -u wsgi.py --help` for options, or inspect `wsgi.py` for doco.) Note that if the integration has never been started in your dev container then dependencies like `isodate` will not yet be installed. Do start the dev container once before trying to execute the simulator, or `pip install` the missing dependencies.

The unit tests will show up at `tests/components/solcast_solar`. `cd` to there and execute `pytest`. Additional test contributions will be most welcome.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,9 @@ series:

## Changes

v4.2.8
* Catch duplicate API key being specified by @autoSteve

v4.2.7
* Fix an issue with API key validation by @autoSteve
* Fix an issue preventing clean integration removal by @autoSteve
Expand Down
16 changes: 12 additions & 4 deletions custom_components/solcast_solar/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,12 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Flo
# Validate API key
api_key = user_input[CONF_API_KEY].replace(" ", "")
api_key = [s for s in api_key.split(",") if s]
for key in api_key:
for index, key in enumerate(api_key):
if re.match(LIKE_SITE_ID, key):
return self.async_abort(reason="API key looks like a site ID")
for i, k in enumerate(api_key):
if index != i and key == k:
return self.async_abort(reason="Duplicate API key specified")
api_count = len(api_key)
api_key = ",".join(api_key)

Expand All @@ -150,9 +153,9 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Flo
if not q.isnumeric():
return self.async_abort(reason="API limit is not a number")
if int(q) < 1:
return self.async_abort(reason="API limit must be one or greater!")
return self.async_abort(reason="API limit must be one or greater")
if len(api_quota) > api_count:
return self.async_abort(reason="There are more API limit counts entered than keys!")
return self.async_abort(reason="There are more API limit counts entered than keys")
api_quota = ",".join(api_quota)

options = {
Expand Down Expand Up @@ -232,9 +235,12 @@ async def async_step_init(self, user_input: dict | None = None) -> Any:
# Validate API key
api_key = user_input[CONF_API_KEY].replace(" ", "")
api_key = [s for s in api_key.split(",") if s]
for key in api_key:
for index, key in enumerate(api_key):
if re.match(LIKE_SITE_ID, key):
return self.async_abort(reason="API key looks like a site ID")
for i, k in enumerate(api_key):
if index != i and key == k:
return self.async_abort(reason="Duplicate API key specified")
api_count = len(api_key)
api_key = ",".join(api_key)
all_config_data[CONF_API_KEY] = api_key
Expand Down Expand Up @@ -269,6 +275,8 @@ async def async_step_init(self, user_input: dict | None = None) -> Any:
if val < 0:
return self.async_abort(reason="Hard limit is not a positive number")
to_set.append(f"{val:.1f}")
if len(hard_limit) > api_count:
return self.async_abort(reason="There are more hard limits entered than keys")
hard_limit = ",".join(to_set)
all_config_data[HARD_LIMIT_API] = hard_limit

Expand Down
2 changes: 1 addition & 1 deletion custom_components/solcast_solar/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/BJReplay/ha-solcast-solar/issues",
"requirements": ["aiohttp>=3.8.5", "aiofiles>=23.2.0", "datetime>=4.3", "isodate>=0.6.1"],
"version": "4.2.7"
"version": "4.2.8"
}
2 changes: 1 addition & 1 deletion custom_components/solcast_solar/solcastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def __init__(self, *args, **kwargs) -> None:
"""Initialise the decoder."""
json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) # noqa: B026

def object_hook(self, o: Any) -> dict: # pylint: disable=method-hidden
def object_hook(self, o: Any) -> dict:
"""Return converted datetimes."""
result = {}
for key, value in o.items():
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Init.py for Solcast Solar tests."""
203 changes: 203 additions & 0 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"""Test the Solcast Solar config flow."""

import copy
import logging
from unittest.mock import AsyncMock

# As a core component, these imports would be homeassistant.components.solcast_solar and not config.custom_components.solcast_solar
from config.custom_components.solcast_solar.config_flow import (
SolcastSolarFlowHandler,
SolcastSolarOptionFlowHandler,
)
from config.custom_components.solcast_solar.const import (
API_QUOTA,
AUTO_UPDATE,
BRK_ESTIMATE,
BRK_ESTIMATE10,
BRK_ESTIMATE90,
BRK_HALFHOURLY,
BRK_HOURLY,
BRK_SITE,
BRK_SITE_DETAILED,
CUSTOM_HOUR_SENSOR,
DOMAIN,
HARD_LIMIT_API,
KEY_ESTIMATE,
SITE_DAMP,
TITLE,
)

from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType

from tests.common import MockConfigEntry

_LOGGER = logging.getLogger(__name__)

KEY = "65sa6d46-sadf876_sd54"
DEFAULT_INPUT = {
CONF_API_KEY: KEY,
API_QUOTA: "10",
AUTO_UPDATE: "1",
CUSTOM_HOUR_SENSOR: 1,
HARD_LIMIT_API: "100.0",
KEY_ESTIMATE: "estimate",
BRK_ESTIMATE: True,
BRK_ESTIMATE10: True,
BRK_ESTIMATE90: True,
BRK_SITE: True,
BRK_HALFHOURLY: True,
BRK_HOURLY: True,
BRK_SITE_DETAILED: False,
SITE_DAMP: False,
}
SITE_DAMP = {f"damp{factor:02d}": 1.0 for factor in range(24)}

MOCK_ENTRY = MockConfigEntry(domain=DOMAIN, data={}, options=DEFAULT_INPUT)


async def test_create_entry(hass: HomeAssistant) -> None:
"""Test that a valid user input creates an entry."""
flow = SolcastSolarFlowHandler()
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = {CONF_API_KEY: "65sa6d46-sadf876_sd54", API_QUOTA: "10", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == TITLE
assert result["data"] == {}
assert result["options"][CONF_API_KEY] == KEY
assert result["options"][API_QUOTA] == "10"
assert result["options"][AUTO_UPDATE] == 1
assert result["options"][CUSTOM_HOUR_SENSOR] == 1
assert result["options"][HARD_LIMIT_API] == "100.0"
assert result["options"][KEY_ESTIMATE] == "estimate"
assert result["options"][BRK_ESTIMATE] is True
assert result["options"][BRK_ESTIMATE10] is True
assert result["options"][BRK_ESTIMATE90] is True
assert result["options"][BRK_SITE] is True
assert result["options"][BRK_HALFHOURLY] is True
assert result["options"][BRK_HOURLY] is True
assert result["options"][BRK_SITE_DETAILED] is False


async def test_invalid_api_key(hass: HomeAssistant) -> None:
"""Test that invalid API key is handled."""
flow = SolcastSolarFlowHandler()
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = {CONF_API_KEY: "1234-5678-8765-4321", API_QUOTA: "10", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API key looks like a site ID"

user_input = {CONF_API_KEY: KEY + "," + KEY, API_QUOTA: "10", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Duplicate API key specified"


async def test_invalid_api_quota(hass: HomeAssistant) -> None:
"""Test that invalid API quota is handled."""
flow = SolcastSolarFlowHandler()
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = {CONF_API_KEY: KEY, API_QUOTA: "invalid", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API limit is not a number"

user_input = {CONF_API_KEY: KEY, API_QUOTA: "0", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API limit must be one or greater"

user_input = {CONF_API_KEY: KEY, API_QUOTA: "10,10", AUTO_UPDATE: "1"}
result = await flow.async_step_user(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "There are more API limit counts entered than keys"


async def test_option_invalid_api_key(hass: HomeAssistant) -> None:
"""Test that invalid API key is handled."""
flow = SolcastSolarOptionFlowHandler(MOCK_ENTRY)
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = {CONF_API_KEY: "1234-5678-8765-4321", API_QUOTA: "10", AUTO_UPDATE: "1"}
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API key looks like a site ID"

user_input[CONF_API_KEY] = KEY + "," + KEY
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Duplicate API key specified"


async def test_option_invalid_custom_hour_sensor(hass: HomeAssistant) -> None:
"""Test that invalid custom hour sensor is handled."""
flow = SolcastSolarOptionFlowHandler(MOCK_ENTRY)
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = copy.deepcopy(DEFAULT_INPUT)
user_input[CUSTOM_HOUR_SENSOR] = 0
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Custom sensor not between 1 and 144"

user_input[CUSTOM_HOUR_SENSOR] = 145
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Custom sensor not between 1 and 144"


async def test_option_invalid_api_quota(hass: HomeAssistant) -> None:
"""Test that invalid API quota is handled."""
flow = SolcastSolarOptionFlowHandler(MOCK_ENTRY)
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = copy.deepcopy(DEFAULT_INPUT)
user_input[API_QUOTA] = "invalid"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API limit is not a number"

user_input[API_QUOTA] = "0"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "API limit must be one or greater"

user_input[API_QUOTA] = "10,10"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "There are more API limit counts entered than keys"


async def test_option_invalid_hard_limit(hass: HomeAssistant) -> None:
"""Test that invalid hard limit is handled."""
flow = SolcastSolarOptionFlowHandler(MOCK_ENTRY)
flow.hass = hass
flow.__conflicting_integration = AsyncMock(return_value=(False, ""))

user_input = copy.deepcopy(DEFAULT_INPUT)
user_input[HARD_LIMIT_API] = "invalid"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Hard limit is not a positive number"

user_input[HARD_LIMIT_API] = "-1"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "Hard limit is not a positive number"

user_input[HARD_LIMIT_API] = "6,6"
result = await flow.async_step_init(user_input)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "There are more hard limits entered than keys"
Loading