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

Catch duplicate API key specified (plus scope creep) #226

Open
wants to merge 36 commits into
base: main
Choose a base branch
from

Conversation

autoSteve
Copy link
Collaborator

Why anyone of sound mind would do this is beyond me. But it does result in exceptions that want heading off at the pass...

@autoSteve autoSteve requested a review from BJReplay December 5, 2024 08:56
Copy link
Owner

@BJReplay BJReplay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most polite. No "WTAF?".

@autoSteve
Copy link
Collaborator Author

🤣🤣🤣

@autoSteve
Copy link
Collaborator Author

Long may the changes in the last two PRs hide dormant. Prepped for next anyways.

@BJReplay
Copy link
Owner

BJReplay commented Dec 5, 2024

Long may the changes in the last two PRs hide dormant. Prepped for next anyways.

While I was reviewing and approving your PR, I was sitting in the Palais waiting for...

20241205_220716 1

@autoSteve
Copy link
Collaborator Author

Here's an example for you of how smart Copilot can be.

Scenario: I've copied a unit test function for invalid API limit, and am modifying it to test for invalid hard limit.
Result: The clever bugger has worked out exactly what I am doing and is suggesting absolutely correct lines of code (in grey italic, just press tab...)

image

@autoSteve
Copy link
Collaborator Author

autoSteve commented Dec 6, 2024

We now meet (well, far exceed) the minimum requirements for becoming a core component. Unit testing of config_flow.py is must-ride.

I worked out how to shoehorn pytests for a custom into the dev container environment, with minimal alterations required when transitioned as a core component...

In devcontainer.json...

  "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",

from tests/components/solcast_solar run pytest.

(ha-venv) vscode ➜ /workspaces/…/tests/components/solcast_solar $ pytest
Test session starts (platform: linux, Python 3.12.7, pytest 8.3.3, pytest-sugar 1.0.0)
rootdir: /workspaces/homeAssistant-core
configfile: pyproject.toml
plugins: github-actions-annotate-failures-0.2.0, sugar-1.0.0, pytest_freezer-0.4.8, cov-5.0.0, syrupy-4.7.1, picked-0.5.0, timeout-2.3.1, socket-0.7.0, respx-0.21.1, aiohttp-1.0.5, xdist-3.6.1, asyncio-0.24.0, requests-mock-1.12.1, unordered-0.6.1, anyio-4.6.0
asyncio: mode=Mode.AUTO, default_loop_scope=function
collected 7 items                                                                                                                                                                                                                                                                        

 tests/components/solcast_solar/test_config_flow.py ✓✓✓✓✓✓✓                                                                                                                                                                                                                100% ██████████

Results (0.21s):
       7 passed

@autoSteve autoSteve changed the title Catch duplicate API key specified Catch duplicate API key specified (plus scope creep) Dec 6, 2024
Copy link
Owner

@BJReplay BJReplay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@BJReplay
Copy link
Owner

BJReplay commented Dec 6, 2024

We now meet (well, far exceed) the minimum requirements for becoming a core component. Unit testing of config_flow.py is must-ride.

OK, I'll try to have a look over the weekend.

Very tired, now, so off to bed, but maybe we throw it at the wall and see if it sticks.

Will read up on the process.

@autoSteve
Copy link
Collaborator Author

Sounds like a journey, but I'm betting it's a shorter one than HACS at the mo'...

We got this.

@autoSteve
Copy link
Collaborator Author

I've removed the self-signed certs to stop GitGuardian complaining about them. The sim creates the cert if required on startup.

@autoSteve
Copy link
Collaborator Author

The hard limit validation oopsie would have been caught by the unit test had I also looked for an expected positive outcome going wrong instead of expecting the worst from bad input. I did not. The unit test failed everyone.

It sailed through without a care in the world. It does not now.

@autoSteve
Copy link
Collaborator Author

So I am kind-of guessing re. #227. I am only led by the exception.

The latest commit catches the very first exception regarding 'index' and then bluntly refuses to start the integration with an inferance of a corrupt solcast.json file reported. It might prevent issues raised, but more likely will improve sit. rep. and avoid an exploded log with a bunch of knock-on bad stuff happening.

I thought about doing something fancier, but fancier would have required a LOT more input as to the situation, and a LOT more testing. I am not in the mood for testing. And I have no input. So it is what it is for now.

@BJReplay
Copy link
Owner

BJReplay commented Dec 9, 2024

So I am kind-of guessing re. #227.

I am kind-of guessing that some ancient installs - possibly manual, non-HACS, have been upgraded, and they are the cause of the last few issues like this.

@autoSteve
Copy link
Collaborator Author

Kind-of not, I'm tipping.

The log indicated a usage cache load, with a count of two for API used, so must be a relatively recent version. Last reset was within twenty-four hours. This might have been from a prior start attempt, but there are two sites, so if anything API used should be four calls, given history load on fresh start. Unless the second site failed to load...

I got nothin' but conjecture.

2024-12-08 19:54:24.881 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Usage cache exists for ******Zr-mpU
2024-12-08 19:54:24.888 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Usage cache for ******Zr-mpU last reset 2024-12-08 01:00:00
2024-12-08 19:54:24.888 INFO (MainThread) [custom_components.solcast_solar.solcastapi] Usage loaded
2024-12-08 19:54:24.889 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] API counter for ******Zr-mpU is 2/10
2024-12-08 19:54:24.889 DEBUG (MainThread) [custom_components.solcast_solar] UTC times are converted to Europe/Berlin

@BJReplay
Copy link
Owner

BJReplay commented Dec 9, 2024

Kind-of not, I'm tipping.

Ahh, I did squint at the log on my phone after I carefully picked up my specs case, left home, and discovered that I had left me specs at home, but didn't spot that.

@autoSteve
Copy link
Collaborator Author

Further fun with unit tests. test_solcastapi.py.

Just uncovered a bug: Turning off detailed half-hourly attribute with detailed hourly enabled results in a puff of virtual magic smoke.

(ha-venv) vscode ➜ /workspaces/…/tests/components/solcast_solar $ pytest -o log_cli=true --log-cli-level=DEBUG -vv
Test session starts (platform: linux, Python 3.12.7, pytest 8.3.3, pytest-sugar 1.0.0)
cachedir: .pytest_cache
rootdir: /workspaces/homeAssistant-core
configfile: pyproject.toml
plugins: github-actions-annotate-failures-0.2.0, sugar-1.0.0, pytest_freezer-0.4.8, cov-5.0.0, syrupy-4.7.1, picked-0.5.0, timeout-2.3.1, socket-0.7.0, respx-0.21.1, aiohttp-1.0.5, xdist-3.6.1, asyncio-0.24.0, requests-mock-1.12.1, unordered-0.6.1, anyio-4.6.0
asyncio: mode=Mode.AUTO, default_loop_scope=function
collected 16 items                                                                                                                                                                                                                                                                                                         

 tests/components/solcast_solar/test_config_flow.py::test_create_entry ✓                                                                                                                                                                                                                                       6% ▋         
 tests/components/solcast_solar/test_config_flow.py::test_api_key ✓                                                                                                                                                                                                                                           12% █▍        
 tests/components/solcast_solar/test_config_flow.py::test_api_quota ✓                                                                                                                                                                                                                                         19% █▉        
 tests/components/solcast_solar/test_config_flow.py::test_option_api_key ✓                                                                                                                                                                                                                                    25% ██▌       
 tests/components/solcast_solar/test_config_flow.py::test_option_api_quota ✓                                                                                                                                                                                                                                  31% ███▎      
 tests/components/solcast_solar/test_config_flow.py::test_option_custom_hour_sensor ✓                                                                                                                                                                                                                         38% ███▊      
 tests/components/solcast_solar/test_config_flow.py::test_option_hard_limit ✓                                                                                                                                                                                                                                 44% ████▍     
 tests/components/solcast_solar/test_solcastapi.py::test_forecast_update ✓                                                                                                                                                                                                                                    50% █████     
 tests/components/solcast_solar/test_solcastapi.py::test_build_splines ✓                                                                                                                                                                                                                                      56% █████▋    
 tests/components/solcast_solar/test_solcastapi.py::test_get_total_energy_forecast ✓                                                                                                                                                                                                                          62% ██████▍   
 tests/components/solcast_solar/test_solcastapi.py::test_get_peaks ✓                                                                                                                                                                                                                                          69% ██████▉   
 tests/components/solcast_solar/test_solcastapi.py::test_get_power_n_minutes ✓                                                                                                                                                                                                                                75% ███████▌  
 tests/components/solcast_solar/test_solcastapi.py::test_get_forecast_n_hour ✓                                                                                                                                                                                                                                81% ████████▎ 
 tests/components/solcast_solar/test_solcastapi.py::test_get_forecast_custom_hours ✓                                                                                                                                                                                                                          88% ████████▊ 
 tests/components/solcast_solar/test_solcastapi.py::test_get_forecast_remaining_today ✓                                                                                                                                                                                                                       94% █████████▍
 tests/components/solcast_solar/test_solcastapi.py::test_get_forecast_day ✓                                                                                                                                                                                                                                  100% ██████████

Results (0.63s):
      16 passed

@BJReplay
Copy link
Owner

Thanks for all your amazing efforts, @autoSteve - I would have just been picking up pieces from the floor every time it broke without you.

I just checked my logs - no 429s, but I did have a cache reset stale.

That said, it could be because I've now got watchtower somewhat aggressively updating images, and it did update homeassistant so that might be the cause - but I only notices because I just went looking for 429s:

homeassistant  | 2024-12-19 11:00:14.818 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Create task pending_update_239
homeassistant  | 2024-12-19 11:03:48.984 DEBUG (MainThread) [custom_components.epa_victoria_air_quality.coordinator] Finished fetching epa_victoria_air_quality data in 0.103 seconds (success: True)
homeassistant  | 2024-12-19 11:04:25.137 INFO (MainThread) [custom_components.solcast_solar.coordinator] Auto update forecast
homeassistant  | 2024-12-19 11:04:25.138 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Started task pending_update_239
homeassistant  | 2024-12-19 11:04:25.138 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Checking for stale usage cache
homeassistant  | 2024-12-19 11:04:25.138 WARNING (MainThread) [custom_components.solcast_solar.coordinator] Usage cache reset time is stale, last reset was more than 24-hours ago, resetting API usage
homeassistant  | 2024-12-19 11:04:25.146 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Writing API usage cache file: /config/solcast-usage.json
homeassistant  | 2024-12-19 11:04:25.154 WARNING (MainThread) [custom_components.solcast_solar.coordinator] Restarting midnight UTC timer
homeassistant  | 2024-12-19 11:04:25.154 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Cancelled task midnight_update
homeassistant  | 2024-12-19 11:04:25.154 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Started task midnight_update
homeassistant  | 2024-12-19 11:04:25.155 INFO (MainThread) [custom_components.solcast_solar.solcastapi] Getting forecast update for site a546-98c5-53c5-d101
homeassistant  | 2024-12-19 11:04:25.155 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Polling API for site a546-98c5-53c5-d101, last day 2024-12-26, 181 hours
homeassistant  | 2024-12-19 11:04:25.155 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Fetching forecast
homeassistant  | 2024-12-19 11:04:25.804 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Fetch data url https://api.solcast.com.au/rooftop_sites/a546-98c5-53c5-d101/forecasts?format=json&api_key=******bvvHxW&hours=181
homeassistant  | 2024-12-19 11:04:25.804 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] API returned data, API counter incremented from 0 to 1
homeassistant  | 2024-12-19 11:04:25.804 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Writing API usage cache file: /config/solcast-usage.json
homeassistant  | 2024-12-19 11:04:25.826 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] HTTP session status 200/Success
homeassistant  | 2024-12-19 11:04:25.827 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task fetch_data took 0.672 seconds
homeassistant  | 2024-12-19 11:04:25.827 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] 363 records returned
homeassistant  | 2024-12-19 11:04:25.843 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task load_new_data took 0.016 seconds
homeassistant  | 2024-12-19 11:04:25.846 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task apply_dampening took 0.003 seconds
homeassistant  | 2024-12-19 11:04:25.989 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task sort_and_prune took 0.143 seconds
homeassistant  | 2024-12-19 11:04:25.989 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Forecasts dictionary length 5805 (1056 un-dampened)
homeassistant  | 2024-12-19 11:04:26.066 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task build_data took 0.075 seconds
homeassistant  | 2024-12-19 11:04:26.097 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Forecast data from 2024-12-19 to 2024-12-26 contains all intervals
homeassistant  | 2024-12-19 11:04:26.105 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Task recalculate_splines took 0.008 seconds
homeassistant  | 2024-12-19 11:04:26.137 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Saved dampened forecast cache
homeassistant  | 2024-12-19 11:04:26.145 DEBUG (MainThread) [custom_components.solcast_solar.solcastapi] Saved un-dampened forecast cache
homeassistant  | 2024-12-19 11:04:26.145 INFO (MainThread) [custom_components.solcast_solar.solcastapi] Forecast update completed successfully, next auto update at 11:48:34
homeassistant  | 2024-12-19 11:04:26.165 DEBUG (MainThread) [custom_components.solcast_solar.coordinator] Completed task pending_update_239

Enjoy your festivus however you choose to. I'm just finishing up writing a PIR because there is no rest for the wicked.

@autoSteve
Copy link
Collaborator Author

Caches during testing get created at tests/testing_config and not config. They are cleaned up at the conclusion of each test using __init__.async_cleanup_integration_tests().

I am still on the hunt for code that is not exercised. The current set of tests hit heaps of code paths (excepting Solcast API failure), and where specific asserts might be missing there are catch-all assertions that the log is error free.

Me like.

@autoSteve
Copy link
Collaborator Author

The pytest coverage report is your friend to find un-exercised code, BTW.

(ha-venv) vscode ➜ /workspaces/…/tests/components/solcast_solar $ pytest  --cov=homeassistant.components.solcast_solar --cov-report term-missing -vv
Test session starts (platform: linux, Python 3.12.8, pytest 8.3.3, pytest-sugar 1.0.0)
cachedir: .pytest_cache
rootdir: /workspaces/homeAssistant-core
configfile: pyproject.toml
plugins: github-actions-annotate-failures-0.2.0, sugar-1.0.0, pytest_freezer-0.4.8, cov-5.0.0, syrupy-4.7.1, picked-0.5.0, timeout-2.3.1, socket-0.7.0, respx-0.21.1, aiohttp-1.0.5, xdist-3.6.1, asyncio-0.24.0, requests-mock-1.12.1, unordered-0.6.1, anyio-4.6.0
asyncio: mode=Mode.AUTO, default_loop_scope=function
collected 19 items                                                                                                                                                                                                                                                                                                                            

 tests/components/solcast_solar/test_config_flow.py::test_create_entry ✓                                                                                                                                                                                                                                                          5% ▌         
 tests/components/solcast_solar/test_config_flow.py::test_api_key ✓                                                                                                                                                                                                                                                              11% █▏        
 tests/components/solcast_solar/test_config_flow.py::test_api_quota ✓                                                                                                                                                                                                                                                            16% █▋        
 tests/components/solcast_solar/test_config_flow.py::test_option_api_key ✓                                                                                                                                                                                                                                                       21% ██▏       
 tests/components/solcast_solar/test_config_flow.py::test_option_api_quota ✓                                                                                                                                                                                                                                                     26% ██▋       
 tests/components/solcast_solar/test_config_flow.py::test_option_custom_hour_sensor ✓                                                                                                                                                                                                                                            32% ███▎      
 tests/components/solcast_solar/test_config_flow.py::test_option_hard_limit ✓                                                                                                                                                                                                                                                    37% ███▊      
 tests/components/solcast_solar/test_config_flow.py::test_entry_options_upgrade ✓                                                                                                                                                                                                                                                42% ████▎     
 tests/components/solcast_solar/test_diagnostics.py::test_diagnostics ✓                                                                                                                                                                                                                                                          47% ████▊     
 tests/components/solcast_solar/test_energy.py::test_energy_data ✓                                                                                                                                                                                                                                                               53% █████▍    
 tests/components/solcast_solar/test_init.py::test_init[input0] ✓                                                                                                                                                                                                                                                                58% █████▊    
 tests/components/solcast_solar/test_init.py::test_init[input1] ✓                                                                                                                                                                                                                                                                63% ██████▍   
 tests/components/solcast_solar/test_init.py::test_init[input2] ✓                                                                                                                                                                                                                                                                68% ██████▉   
 tests/components/solcast_solar/test_init.py::test_remaining_actions ✓                                                                                                                                                                                                                                                           74% ███████▍  
 tests/components/solcast_solar/test_select.py::test_select_change_value[0-estimate-forecast_today-42.552] ✓                                                                                                                                                                                                                     79% ███████▉  
 tests/components/solcast_solar/test_select.py::test_select_change_value[1-estimate10-forecast_today-35.46] ✓                                                                                                                                                                                                                    84% ████████▌ 
 tests/components/solcast_solar/test_select.py::test_select_change_value[2-estimate90-forecast_today-47.28] ✓                                                                                                                                                                                                                    89% ████████▉ 
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[1-settings0] ✓                                                                                                                                                                                                                                                95% █████████▌
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[2-settings1] ✓                                                                                                                                                                                                                                               100% ██████████

---------- coverage: platform linux, python 3.12.8-final-0 -----------
Name                                                                                     Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------------------------------------------------
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/__init__.py          412     76    82%   114-115, 128-129, 132, 197, 225-238, 254-259, 262-265, 307-308, 317, 321, 384-385, 390, 410, 413, 423, 430-432, 434, 455-459, 463, 476-477, 482, 500, 505, 511, 524, 526, 545-546, 596, 607, 624-625, 639-640, 645, 648-650, 681, 717, 745-749, 800-806, 836-838
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/config_flow.py       175     43    75%   85, 100-102, 108-122, 136, 139, 185-197, 258, 262, 281, 306-309, 371-386
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/const.py              46      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/coordinator.py       295     81    73%   127-129, 135, 138, 143-146, 153, 157-169, 177-185, 188-199, 208-218, 220, 223-228, 232-238, 242-246, 265-266, 322, 352-353, 362-364, 401, 411, 470, 472, 495, 497, 518-519, 526-527
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/diagnostics.py        17      1    94%   36
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/energy.py             15      3    80%   29-30, 35
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/recorder.py            5      1    80%   10
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/select.py             46      2    96%   71-72
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sensor.py            172     28    84%   378-380, 383, 412-414, 426-428, 462, 466-468, 470, 473, 527-529, 561, 578-580, 611, 615-618
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sim/__init__.py        0      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sim/simulate.py       27      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sim/wsgi.py          197    197     0%   42-354
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/solcastapi.py       1595    471    70%   84-86, 134, 142-148, 152-154, 158, 174, 176, 508-509, 513-517, 519-521, 530-532, 550, 600-603, 617-621, 623-624, 631-637, 641-663, 686-737, 762-764, 769-770, 787-788, 797, 799-805, 820-832, 843-845, 854-859, 878-879, 883-887, 917-925, 967-968, 1000-1003, 1024-1032, 1038-1039, 1056-1078, 1096, 1125-1130, 1132-1137, 1139-1140, 1151-1158, 1162-1163, 1180-1181, 1218-1235, 1249, 1265, 1341-1362, 1390-1392, 1397-1398, 1431-1432, 1472-1481, 1499, 1503-1504, 1507-1509, 1533, 1547-1549, 1600, 1615, 1660, 1669, 1678, 1716-1726, 1743, 1766, 1782-1783, 2013-2014, 2046, 2048, 2130-2131, 2137-2138, 2163-2165, 2183-2185, 2225-2237, 2239, 2251-2257, 2289, 2307-2313, 2339-2354, 2387-2408, 2424-2426, 2445, 2452, 2470-2493, 2495, 2517-2526, 2528-2530, 2540, 2571-2586, 2601-2609, 2621-2622, 2655, 2664-2665, 2677-2678, 2680, 2683-2684, 2686, 2742-2743, 2759-2760, 2762-2766, 2771-2775, 2784-2788, 2802-2803, 2819-2820, 2823-2824, 2828-2829, 2839-2843, 2916, 2918-2919, 2943-3107, 3134-3135, 3143, 3168, 3233, 3269-3275, 3366-3367, 3394-3397, 3450, 3466, 3471, 3481, 3483-3493, 3501-3505
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/spline.py             64      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/system_health.py      10     10     0%   3-22
----------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                     3076    913    70%


Results (10.09s):
      19 passed

@BJReplay
Copy link
Owner

BJReplay commented Dec 26, 2024

Is it reasonable to expect to get to 100% coverage? Or even "expected" in terms of form?

For example, I wouldn't have thought that 3-13 in system_health.py needed any testing coverage, nor 29-30 (assuming 28 does) or 35 (assuming 34 does) in energy.py. As I couldn't see recorder.py at all in the branch on github, I assume that yet isn't committed 🤣

@autoSteve
Copy link
Collaborator Author

couldn't see recorder.py

Lols. That's right... I got rid of it. It's still on me dev repo. 😂

It is reasonable to have good coverage because it saves you and I and others testing time.

  • Bronze: 100% coverage for the config/options flows
  • Silver: Above 95% test coverage according to one bit of doco. Above average test coverage noted elsewhere.
  • Gold: Full automated test coverage of its codebase.
  • Platinum: Per gold.

An assigned quality scale is a technicality. My aim is to address the glaring gaps that represent a higher risk, and improve the coverage over time.

A good example of this is that our sensors are rigged to return zero should things turn to custard, which is not the way things should be. We have both seen this reported many times. "It broke and now all my values are zero!" The sensors should instead show as 'unavailable' if a value cannot be returned. Testing so far has highlighted this by not being able to test certain exception conditions because the test method I tried blows up because the code "works", but is dodgy from an HA POV.

@BJReplay
Copy link
Owner

The sensors should instead show as 'unavailable' if a value cannot be returned.

Yeah, I sort of get that, but at the same time, I'm not sure that I agree, completely.

I sort of prefer a boolean sensor / diagnostic which can be used to know if all is good or not.

I guess it depends on what the sensor is.

But having said all that, I'm neither a python nor a home assistant style expert.

However, this is the side effect of a sensor becoming unavailable instead of an empty string or a zero count on the warnings entity:

Code that attempts to access warnings.count fails if warnings is unavailable, which it sometimes is (but not always - sometimes it is there, but with a zero count), so the ugly template has three tests queued up before the one to actually look for the one that should be true most of the time - is the number of weather warnings < 1 - if so, report "No Warnings".

{% if (states("sensor.st_kilda_west_warnings") not in ["unavailable", "none", "unknown"]) and (states("sensor.st_kilda_west_warnings") and ((state_attr("sensor.st_kilda_west_warnings", "warnings") | count) < 1 )) %}
  {{"No Warnings"}}
{% else %}
  {{ state_attr("sensor.st_kilda_west_warnings" , "warnings") [0].short_title }}
{% endif %}

@autoSteve
Copy link
Collaborator Author

This is pretty satisfying.

Near 100% code test coverage. So to-do is improve the scenarios over time instead if there are gaps. I'm pretty sure there are very few gaps now...

There are two lines that fail to be exercised. These relate to sensors never becoming unavailable. I'm yet to further consider the implications of that design choice by our predecessors.

There are many except blocks that I have excluded from coverage because they're only going to be hit if there is a code defect. These would be hit during a test on encountering a code defect, so coverage reporting is unnecessary noise.

I also needed to exclude code that is substituted under testing conditions. Things like getting the current date/time, and the forecast fetch itself because no requests calls can be made using pytest. This code gets tested when running with the wsgi "live" REST simulator instead. (A future possibility is to extend the approach used to test system_health.py to simulate requests responses, which would be cool, but would get gnarly. Deprecation warning for that approach until I can think of a better way...)

(ha-venv) vscode ➜ /workspaces/…/tests/components/solcast_solar $ pytest --cov=homeassistant.components.solcast_solar --cov-report term-missing -vv
Test session starts (platform: linux, Python 3.12.8, pytest 8.3.3, pytest-sugar 1.0.0)
cachedir: .pytest_cache
rootdir: /workspaces/homeAssistant-core
configfile: pyproject.toml
plugins: github-actions-annotate-failures-0.2.0, sugar-1.0.0, pytest_freezer-0.4.8, cov-5.0.0, syrupy-4.7.1, picked-0.5.0, timeout-2.3.1, socket-0.7.0, respx-0.21.1, aiohttp-1.0.5, xdist-3.6.1, asyncio-0.24.0, requests-mock-1.12.1, unordered-0.6.1, anyio-4.6.0
asyncio: mode=Mode.AUTO, default_loop_scope=function
collected 24 items                                                                                                                                                                                                                                                                                                           

 tests/components/solcast_solar/test_config_flow.py::test_single_instance ✓                                                                                                                                                                                                                                      4% ▌         
 tests/components/solcast_solar/test_config_flow.py::test_create_entry ✓                                                                                                                                                                                                                                         8% ▉         
 tests/components/solcast_solar/test_config_flow.py::test_api_key ✓                                                                                                                                                                                                                                             12% █▍        
 tests/components/solcast_solar/test_config_flow.py::test_api_quota ✓                                                                                                                                                                                                                                           17% █▋        
 tests/components/solcast_solar/test_config_flow.py::test_option_api_key ✓                                                                                                                                                                                                                                      21% ██▏       
 tests/components/solcast_solar/test_config_flow.py::test_option_api_quota ✓                                                                                                                                                                                                                                    25% ██▌       
 tests/components/solcast_solar/test_config_flow.py::test_option_custom_hour_sensor ✓                                                                                                                                                                                                                           29% ██▉       
 tests/components/solcast_solar/test_config_flow.py::test_option_hard_limit ✓                                                                                                                                                                                                                                   33% ███▍      
 tests/components/solcast_solar/test_config_flow.py::test_step_to_dampen ✓                                                                                                                                                                                                                                      38% ███▊      
 tests/components/solcast_solar/test_config_flow.py::test_dampen ✓                                                                                                                                                                                                                                              42% ████▎     
 tests/components/solcast_solar/test_config_flow.py::test_entry_options_upgrade ✓                                                                                                                                                                                                                               46% ████▋     
 tests/components/solcast_solar/test_diagnostics.py::test_diagnostics ✓                                                                                                                                                                                                                                         50% █████     
 tests/components/solcast_solar/test_energy.py::test_energy_data ✓                                                                                                                                                                                                                                              54% █████▌    
 tests/components/solcast_solar/test_init.py::test_init[options0] ✓                                                                                                                                                                                                                                             58% █████▉    
 tests/components/solcast_solar/test_init.py::test_init[options1] ✓                                                                                                                                                                                                                                             62% ██████▍   
 tests/components/solcast_solar/test_init.py::test_init[options2] ✓                                                                                                                                                                                                                                             67% ██████▋   
 tests/components/solcast_solar/test_init.py::test_remaining_actions ✓                                                                                                                                                                                                                                          71% ███████▏  
 tests/components/solcast_solar/test_init.py::test_scenarios ✓                                                                                                                                                                                                                                                  75% ███████▌  
 tests/components/solcast_solar/test_select.py::test_select_change_value[0-estimate-forecast_today-42.552] ✓                                                                                                                                                                                                    79% ███████▉  
 tests/components/solcast_solar/test_select.py::test_select_change_value[1-estimate10-forecast_today-35.46] ✓                                                                                                                                                                                                   83% ████████▍ 
 tests/components/solcast_solar/test_select.py::test_select_change_value[2-estimate90-forecast_today-47.28] ✓                                                                                                                                                                                                   88% ████████▊ 
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[1-settings0] ✓                                                                                                                                                                                                                               92% █████████▎
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[2-settings1] ✓                                                                                                                                                                                                                               96% █████████▋
 tests/components/solcast_solar/test_system_health.py::test_system_health ✓                                                                                                                                                                                                                                    100% ██████████
====================================================================================================================================================== warnings summary ======================================================================================================================================================
tests/components/solcast_solar/test_system_health.py::test_system_health
  /workspaces/homeAssistant-core/tests/components/solcast_solar/__init__.py:276: DeprecationWarning: Setting custom ClientSession._request attribute is discouraged
    base._request = _request

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------- coverage: platform linux, python 3.12.8-final-0 -----------
Name                                                                                     Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------------------------------------------------
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/__init__.py          347      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/config_flow.py       132      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/const.py              46      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/coordinator.py       213      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/diagnostics.py        17      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/energy.py             13      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/select.py             42      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sensor.py            145      2    99%   375, 457
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/solcastapi.py       1050      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/spline.py             64      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/system_health.py      11      0   100%
----------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                     2080      2    99%


Results (12.83s):
      24 passed

@autoSteve
Copy link
Collaborator Author

While test coverage may now be 💯% without "cheating" with pragma: notest for the outstanding misses, I am still to naval-gaze unavailable sensors in case of exceptions.

Test scenarios have been bolstered as well.

Name                                                                                     Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------------------------------------------------
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/__init__.py          347      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/config_flow.py       132      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/const.py              46      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/coordinator.py       213      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/diagnostics.py        17      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/energy.py             13      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/select.py             42      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sensor.py            147      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/solcastapi.py       1048      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/spline.py             64      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/system_health.py      11      0   100%
----------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                     2080      0   100%

Copy link
Owner

@BJReplay BJReplay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL at pv_power_advanced possible future enhancement.

That is a metric shit-tonne of code.

@autoSteve
Copy link
Collaborator Author

autoSteve commented Dec 30, 2024

Deprecation warning for the patch-aiohttp-client-session approach be damned. I can't think of a better way right now...

All API calls are now tested without monkey-patching in substitute functions in SolcastApi. It only got a little bit gnarly. 😂

Now tested for are exceptions in sites load, 429s on forecast fetch, 401 invalid key responses, plus API limit exhaustion. And misc other goodies.

Next thing on the list is to remove the retry mechanism in get sites. I changed the init sequence a while back to prevent integration load if the sites fail to get, and Home Assistant automatically retries a load with a back-off mechanism. All retrying in the integration does is to slow down the Home Assistant restart sequence should a dodgy integration config be in place and forgotten about/ignored.

@BJReplay
Copy link
Owner

Deprecation warning for the patch-aiohttp-client-session approach be damned.

I hadn't seen that (at least in debug logs) - I assume it is a ruff warning?

I have seen 429s at 20:00 ADST last two days, (two retries each night) and cache stale warnings at UTC midnight last two days, which is interesting, but then again, I'm running old code 🤣

@autoSteve
Copy link
Collaborator Author

cache stale warnings

This is very interesting. Almost never happens to my prod rig, and never dev. You have weirdo scheduling (because Docker?), with stuff not happening exactly when it should and I wonder if that is somehow implicated. Unlikely, but it's the only thing I can think of.

Feeling quite smug that I incorporated a stale check, as it sounds like you are my # 1 customer...

Deprecation warning

Only seen under pytest.

If the core folk get ansey then they can tell me how to avoid it!

(ha-venv) vscode ➜ /workspaces/…/tests/components/solcast_solar $ pytest --cov=homeassistant.components.solcast_solar --cov-report term-missing -vv
Test session starts (platform: linux, Python 3.12.8, pytest 8.3.3, pytest-sugar 1.0.0)
cachedir: .pytest_cache
rootdir: /workspaces/homeAssistant-core
configfile: pyproject.toml
plugins: github-actions-annotate-failures-0.2.0, sugar-1.0.0, pytest_freezer-0.4.8, cov-5.0.0, syrupy-4.7.1, picked-0.5.0, timeout-2.3.1, socket-0.7.0, respx-0.21.1, aiohttp-1.0.5, xdist-3.6.1, asyncio-0.24.0, requests-mock-1.12.1, unordered-0.6.1, anyio-4.6.0
asyncio: mode=Mode.AUTO, default_loop_scope=function
collected 27 items                                                                                                                                                                                                                                                                                                           

 tests/components/solcast_solar/test_config_flow.py::test_single_instance ✓                                                                                                                                                                                                                                      4% ▍         
 tests/components/solcast_solar/test_config_flow.py::test_create_entry ✓                                                                                                                                                                                                                                         7% ▊         
 tests/components/solcast_solar/test_config_flow.py::test_api_key ✓                                                                                                                                                                                                                                             11% █▎        
 tests/components/solcast_solar/test_config_flow.py::test_api_quota ✓                                                                                                                                                                                                                                           15% █▌        
 tests/components/solcast_solar/test_config_flow.py::test_option_api_key ✓                                                                                                                                                                                                                                      19% █▉        
 tests/components/solcast_solar/test_config_flow.py::test_option_api_quota ✓                                                                                                                                                                                                                                    22% ██▎       
 tests/components/solcast_solar/test_config_flow.py::test_option_custom_hour_sensor ✓                                                                                                                                                                                                                           26% ██▋       
 tests/components/solcast_solar/test_config_flow.py::test_option_hard_limit ✓                                                                                                                                                                                                                                   30% ██▉       
 tests/components/solcast_solar/test_config_flow.py::test_step_to_dampen ✓                                                                                                                                                                                                                                      33% ███▍      
 tests/components/solcast_solar/test_config_flow.py::test_dampen ✓                                                                                                                                                                                                                                              37% ███▊      
 tests/components/solcast_solar/test_config_flow.py::test_entry_options_upgrade ✓                                                                                                                                                                                                                               41% ████▏     
 tests/components/solcast_solar/test_diagnostics.py::test_diagnostics ✓                                                                                                                                                                                                                                         44% ████▌     
 tests/components/solcast_solar/test_energy.py::test_energy_data ✓                                                                                                                                                                                                                                              48% ████▊     
 tests/components/solcast_solar/test_init.py::test_api_failure ✓                                                                                                                                                                                                                                                52% █████▎    
 tests/components/solcast_solar/test_init.py::test_init[options0] ✓                                                                                                                                                                                                                                             56% █████▋    
 tests/components/solcast_solar/test_init.py::test_init[options1] ✓                                                                                                                                                                                                                                             59% █████▉    
 tests/components/solcast_solar/test_init.py::test_init[options2] ✓                                                                                                                                                                                                                                             63% ██████▍   
 tests/components/solcast_solar/test_init.py::test_init[options3] ✓                                                                                                                                                                                                                                             67% ██████▋   
 tests/components/solcast_solar/test_init.py::test_remaining_actions ✓                                                                                                                                                                                                                                          70% ███████▏  
 tests/components/solcast_solar/test_init.py::test_scenarios ✓                                                                                                                                                                                                                                                  74% ███████▌  
 tests/components/solcast_solar/test_select.py::test_select_change_value[0-estimate-forecast_today-42.552] ✓                                                                                                                                                                                                    78% ███████▊  
 tests/components/solcast_solar/test_select.py::test_select_change_value[1-estimate10-forecast_today-35.46] ✓                                                                                                                                                                                                   81% ████████▎ 
 tests/components/solcast_solar/test_select.py::test_select_change_value[2-estimate90-forecast_today-47.28] ✓                                                                                                                                                                                                   85% ████████▌ 
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[1-settings0] ✓                                                                                                                                                                                                                               89% ████████▉ 
 tests/components/solcast_solar/test_sensor.py::test_sensor_states[2-settings1] ✓                                                                                                                                                                                                                               93% █████████▍
 tests/components/solcast_solar/test_sensor.py::test_sensor_unknown ✓                                                                                                                                                                                                                                           96% █████████▋
 tests/components/solcast_solar/test_system_health.py::test_system_health ✓                                                                                                                                                                                                                                    100% ██████████
====================================================================================================================================================== warnings summary ======================================================================================================================================================
tests/components/solcast_solar/test_config_flow.py: 2 warnings
tests/components/solcast_solar/test_diagnostics.py: 1 warning
tests/components/solcast_solar/test_energy.py: 1 warning
tests/components/solcast_solar/test_init.py: 16 warnings
tests/components/solcast_solar/test_select.py: 3 warnings
tests/components/solcast_solar/test_sensor.py: 3 warnings
tests/components/solcast_solar/test_system_health.py: 1 warning
  /workspaces/homeAssistant-core/tests/components/solcast_solar/__init__.py:327: DeprecationWarning: Setting custom ClientSession._request attribute is discouraged
    base._request = _request  # Will generate a deprecation warning

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------- coverage: platform linux, python 3.12.8-final-0 -----------
Name                                                                                     Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------------------------------------------------
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/__init__.py          346      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/config_flow.py       130      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/const.py              46      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/coordinator.py       211      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/diagnostics.py        17      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/energy.py             13      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/select.py             42      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/sensor.py            147      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/solcastapi.py       1141      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/spline.py             64      0   100%
/workspaces/homeAssistant-core/homeassistant/components/solcast_solar/system_health.py      11      0   100%
----------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                     2168      0   100%


Results (15.63s):
      27 passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants