Skip to content

Commit 4aaa14f

Browse files
committed
Increasing BPA test coverage
1 parent f5c1ce0 commit 4aaa14f

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

tests/test_bpa.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from pathlib import Path
99
from io import BytesIO
1010
from typing import Dict, Any
11+
import logging
12+
import requests
1113

1214
import pandas as pd
1315
import pytest
@@ -168,6 +170,21 @@ def test_make_request_all_failures_returns_none(self, client: BPAClient):
168170
# should have tried max_retries times
169171
assert client.session.get.call_count == client.config.max_retries
170172

173+
def test_make_request_handles_request_exception(self, client, caplog):
174+
client.config.max_retries = 2
175+
176+
# avoid real sleep between retries
177+
with patch("time.sleep", autospec=True) as _sleep:
178+
client.session.get = Mock(side_effect=requests.RequestException("boom")) # type: ignore[assignment]
179+
180+
caplog.set_level(logging.ERROR)
181+
content = client._make_request("https://example.com/file.xlsx")
182+
183+
assert content is None
184+
assert "Request error:" in caplog.text
185+
assert client.session.get.call_count == 2
186+
_sleep.assert_called_once() # since retries=2 => one sleep between attempts
187+
171188

172189
# ---------------------------------------------------------------------------
173190
# Excel parsing tests
@@ -216,6 +233,21 @@ def test_parse_excel_file_failure_returns_none(self, client: BPAClient):
216233
df = client._parse_excel_file(b"not-an-excel-file", BPADataType.WIND_GEN_TOTAL_LOAD)
217234
assert df is None
218235

236+
def test_parse_excel_file_datetime_parse_exception_logs_warning(self, client, caplog):
237+
# Build a simple df that _parse_excel_file will produce after read_excel
238+
df = pd.DataFrame({"Date": ["2024-01-01"], "Time": ["00:05"], "Value": [1.0]})
239+
240+
caplog.set_level(logging.WARNING)
241+
242+
with (
243+
patch("lib.iso.bpa.pd.read_excel", return_value=df),
244+
patch("lib.iso.bpa.pd.to_datetime", side_effect=Exception("bad dt")),
245+
):
246+
out = client._parse_excel_file(b"fake-excel-bytes", data_type=None) # type: ignore[arg-type]
247+
248+
assert isinstance(out, pd.DataFrame)
249+
assert "Could not parse datetime column" in caplog.text
250+
219251

220252
# ---------------------------------------------------------------------------
221253
# Date-range filtering tests
@@ -319,6 +351,40 @@ def test_request_failure_returns_false(
319351
output_file = client.config.data_dir / "2024_BPA_WindGenTotalLoad.csv"
320352
assert not output_file.exists()
321353

354+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
355+
@patch.object(BPAClient, "_parse_excel_file", return_value=pd.DataFrame())
356+
def test_wind_parse_returns_empty_df_returns_false(
357+
self, mock_parse, mock_req, client, tmp_path
358+
):
359+
client.config.data_dir = tmp_path
360+
assert client.get_wind_gen_total_load(2024) is False
361+
362+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
363+
@patch.object(BPAClient, "_parse_excel_file", return_value=None)
364+
def test_wind_parse_returns_none_returns_false(self, mock_parse, mock_req, client, tmp_path):
365+
client.config.data_dir = tmp_path
366+
assert client.get_wind_gen_total_load(2024) is False
367+
368+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
369+
@patch.object(BPAClient, "_parse_excel_file")
370+
@patch.object(BPAClient, "_filter_by_date_range", return_value=pd.DataFrame())
371+
def test_wind_date_filter_makes_empty_returns_false(
372+
self, mock_filter, mock_parse, mock_req, client, tmp_path
373+
):
374+
client.config.data_dir = tmp_path
375+
mock_parse.return_value = pd.DataFrame(
376+
{"DateTime": pd.date_range("2024-01-01", periods=3, freq="h"), "Value": [1, 2, 3]}
377+
)
378+
379+
assert client.get_wind_gen_total_load(2024, start_date=date(2024, 1, 2)) is False
380+
381+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
382+
@patch.object(BPAClient, "_parse_excel_file", side_effect=RuntimeError("boom"))
383+
def test_wind_processing_exception_returns_false(self, mock_parse, mock_req, client, caplog):
384+
caplog.set_level(logging.ERROR)
385+
assert client.get_wind_gen_total_load(2024) is False
386+
assert "Error processing data:" in caplog.text
387+
322388

323389
class TestReservesDeployed:
324390
@patch.object(BPAClient, "_make_request")
@@ -361,6 +427,34 @@ def test_request_failure_returns_false(
361427
output_file = client.config.data_dir / "2024_BPA_Reserves_Deployed.csv"
362428
assert not output_file.exists()
363429

430+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
431+
@patch.object(BPAClient, "_parse_excel_file", return_value=pd.DataFrame())
432+
def test_reserves_parse_empty_returns_false(self, mock_parse, mock_req, client, tmp_path):
433+
client.config.data_dir = tmp_path
434+
assert client.get_reserves_deployed(2024) is False
435+
436+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
437+
@patch.object(BPAClient, "_parse_excel_file")
438+
@patch.object(BPAClient, "_filter_by_date_range", return_value=pd.DataFrame())
439+
def test_reserves_date_filter_makes_empty_returns_false(
440+
self, mock_filter, mock_parse, mock_req, client, tmp_path
441+
):
442+
client.config.data_dir = tmp_path
443+
mock_parse.return_value = pd.DataFrame(
444+
{"DateTime": pd.date_range("2024-01-01", periods=3, freq="h"), "Value": [1, 2, 3]}
445+
)
446+
447+
assert client.get_reserves_deployed(2024, start_date=date(2024, 1, 2)) is False
448+
449+
@patch.object(BPAClient, "_make_request", return_value=b"excel-content")
450+
@patch.object(BPAClient, "_parse_excel_file", side_effect=RuntimeError("boom"))
451+
def test_reserves_processing_exception_returns_false(
452+
self, mock_parse, mock_req, client, caplog
453+
):
454+
caplog.set_level(logging.ERROR)
455+
assert client.get_reserves_deployed(2024) is False
456+
assert "Error processing data:" in caplog.text
457+
364458

365459
class TestGetAllData:
366460
def test_get_all_data_combines_results(self, client: BPAClient):

0 commit comments

Comments
 (0)