diff --git a/apps/predbat/futurerate.py b/apps/predbat/futurerate.py index 50b996a5b..6ff1d9b83 100644 --- a/apps/predbat/futurerate.py +++ b/apps/predbat/futurerate.py @@ -412,7 +412,7 @@ def download_futurerate_data(self, url): def download_futurerate_data_func(self, url): try: - r = requests.get(url) + r = requests.get(url, timeout=120) except Exception as e: self.log("Warn: Error downloading futurerate data from URL {}, request exception {}".format(url, e)) self.record_status("Warn: Error downloading futurerate data from cloud", debug=url, had_errors=True) diff --git a/apps/predbat/octopus.py b/apps/predbat/octopus.py index b62525b2b..2e4951711 100644 --- a/apps/predbat/octopus.py +++ b/apps/predbat/octopus.py @@ -2066,7 +2066,7 @@ def download_octopus_free_func(self, url): Download octopus free session data directly from a URL, no caching. """ try: - r = requests.get(url) + r = requests.get(url, timeout=120) except requests.exceptions.ConnectionError: self.log("Warn: Octopus: Unable to download Octopus data from URL {} (ConnectionError)".format(url)) self.record_status("Warn: Unable to download Octopus free session data", debug=url, had_errors=True) diff --git a/apps/predbat/tests/test_nordpool.py b/apps/predbat/tests/test_nordpool.py index 5c751d976..fa9be8444 100644 --- a/apps/predbat/tests/test_nordpool.py +++ b/apps/predbat/tests/test_nordpool.py @@ -11,6 +11,7 @@ import json import os from datetime import datetime, timedelta +from unittest.mock import MagicMock, patch from futurerate import FutureRate @@ -75,6 +76,18 @@ def run_nordpool_test(my_predbat): my_predbat.args["futurerate_peak_premium_export"] = 6.5 failed = False + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.text = json.dumps({"multiAreaEntries": []}) + with patch("futurerate.requests.get", return_value=mock_response) as mock_get: + FutureRate(my_predbat).download_futurerate_data_func("https://example.com/nordpool") + if mock_get.call_count != 1: + print("ERROR: Expected 1 Nord Pool HTTP call for timeout coverage, got {}".format(mock_get.call_count)) + failed = True + elif mock_get.call_args.kwargs.get("timeout") != 120: + print("ERROR: Expected Nord Pool download timeout 120, got {}".format(mock_get.call_args.kwargs.get("timeout"))) + failed = True + fixture = _load_fixture() if fixture: print("Using saved nordpool fixture (no network calls)") diff --git a/apps/predbat/tests/test_octopus_free.py b/apps/predbat/tests/test_octopus_free.py index 89f293971..0fd1fd460 100644 --- a/apps/predbat/tests/test_octopus_free.py +++ b/apps/predbat/tests/test_octopus_free.py @@ -76,6 +76,20 @@ def test_octopus_free(my_predbat): temp_dir = tempfile.mkdtemp() original_config_root = getattr(my_predbat, "config_root", None) try: + with patch("octopus.requests.get", return_value=_mock_http_response(_JSON_BODY)) as mock_get: + body = my_predbat.download_octopus_free_func(_URL) + if mock_get.call_count != 1: + print("FAIL: Expected 1 HTTP call when covering free-session timeout, got {}".format(mock_get.call_count)) + failed = True + elif mock_get.call_args.kwargs.get("timeout") != 120: + print("FAIL: Expected Octopus free-session timeout 120, got {}".format(mock_get.call_args.kwargs.get("timeout"))) + failed = True + elif body != _JSON_BODY: + print("FAIL: Expected Octopus free-session body to round-trip unchanged") + failed = True + else: + print("PASS: Free-session direct download uses the configured timeout") + # --- Test 1: no storage (components=None) — no exception, returns sessions --- _reset_free_cache(my_predbat) my_predbat.components = None