Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .

- name: Run tests with coverage
run: |
pytest --cov=iris_gpubench tests/

- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage.xml

15 changes: 9 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@
packages=find_packages(), # Automatically find packages in the current directory
install_requires=[
'pynvml==11.5.3',
'requests==2.32.4',
'pyyaml==6.0.2',
'tabulate==0.9.0',
'matplotlib==3.7.5',
'docker==7.1.0',
'requests>=2.32.4',
'pyyaml>=6.0.2',
'tabulate>=0.9.0',
'matplotlib>=3.7.5',
'docker>=7.1.0',
'pytest>=7.4.2',
'requests-mock>=1.9.3',
'pytest-cov>=4.1.0',
],
entry_points={
'console_scripts': [
'iris-gpubench=iris_gpubench.main:main', # Ensures the script is accessible via `iris-gpubench` command
],
},
python_requires='==3.8.10', # Ensure compatibility with Python 3.8.10
python_requires='>=3.8.10', # Ensure compatibility with Python 3.8.10
)
170 changes: 170 additions & 0 deletions tests/test_carbon_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import pytest
import requests
import requests_mock
from requests.exceptions import Timeout, ConnectionError as RequestsConnectionError


from iris_gpubench.carbon_metrics import (
get_carbon_region_names,
get_carbon_forecast,
CARBON_INTENSITY_URL,
)
from iris_gpubench.utils.globals import DEFAULT_REGION, LOGGER, TIMEOUT_SECONDS

# --- Mock Data for Successful API Calls ---

# Successful response structure for the /regional endpoint
SUCCESS_REGIONAL_RESPONSE = {
"data": [
{
"regions": [
{
"shortname": "South England",
"intensity": {"forecast": 150, "index": "moderate"},
},
{
"shortname": "Scotland",
"intensity": {"forecast": 200, "index": "high"},
},
{
"shortname": "Wales",
"intensity": {"forecast": 50, "index": "low"},
},
]
}
]
}

# Expected region names for get_carbon_region_names test
EXPECTED_REGION_NAMES = ['South England', 'Scotland', 'Wales']

def test_get_carbon_region_names_success(requests_mock):
"""Test successful retrieval of region names."""
requests_mock.get(
CARBON_INTENSITY_URL,
json=SUCCESS_REGIONAL_RESPONSE,
status_code=200 # OK
)
result = get_carbon_region_names()
assert result == EXPECTED_REGION_NAMES

def test_get_carbon_region_names_http_error(requests_mock):
"""Test handling of HTTP errors (e.g., 404, 500)."""
requests_mock.get(
CARBON_INTENSITY_URL,
status_code=500 # Internal Server Error
)
result = get_carbon_region_names()
assert result == []

def test_get_carbon_region_names_timeout(requests_mock, caplog):
"""Test handling of request Timeout."""
requests_mock.get(
CARBON_INTENSITY_URL,
exc=Timeout # Raise a Timeout exception
)
result = get_carbon_region_names()
assert result == []
assert f"Request timed out after {TIMEOUT_SECONDS} seconds." in caplog.text

def test_get_carbon_region_names_connection_error(requests_mock, caplog):
"""Test handling of ConnectionError."""
requests_mock.get(
CARBON_INTENSITY_URL,
exc=RequestsConnectionError # Raise a ConnectionError
)
result = get_carbon_region_names()
assert result == []
assert "Network error occurred" in caplog.text

def test_get_carbon_region_names_invalid_json(requests_mock, caplog):
"""Test handling of invalid JSON response."""
requests_mock.get(
CARBON_INTENSITY_URL,
text="This is not JSON",
status_code=200
)
result = get_carbon_region_names()
assert result == []
assert "Failed to decode JSON response" in caplog.text

# --- Tests for get_carbon_forecast ---

def test_get_carbon_forecast_success(requests_mock):
"""Test successful retrieval of carbon forecast for a specified region."""
target_region = "Wales"
expected_forecast = 50.0
requests_mock.get(
CARBON_INTENSITY_URL,
json=SUCCESS_REGIONAL_RESPONSE,
status_code=200
)
result = get_carbon_forecast(target_region)
assert result == expected_forecast

def test_get_carbon_forecast_default_region(requests_mock, monkeypatch):
"""Test successful retrieval using the default region."""
# Temporarily set DEFAULT_REGION for the test
monkeypatch.setattr('iris_gpubench.utils.globals.DEFAULT_REGION', 'South England')
expected_forecast = 150.0
requests_mock.get(
CARBON_INTENSITY_URL,
json=SUCCESS_REGIONAL_RESPONSE,
status_code=200
)
# Call without argument to use the mocked default
result = get_carbon_forecast()
assert result == expected_forecast

def test_get_carbon_forecast_region_not_found(requests_mock, caplog):
"""Test case where the requested region is not in the response."""
missing_region = "London"
requests_mock.get(
CARBON_INTENSITY_URL,
json=SUCCESS_REGIONAL_RESPONSE,
status_code=200
)
result = get_carbon_forecast(missing_region)
assert result is None
assert f"Region '{missing_region}' not found in the response." in caplog.text

def test_get_carbon_forecast_value_error_non_float(requests_mock, caplog):
"""Test handling of a non-numeric 'forecast' value (raises ValueError on float() conversion)."""
bad_forecast_data = {
"data": [
{
"regions": [
{
"shortname": "Scotland",
"intensity": {"forecast": "not_a_number", "index": "moderate"},
}
]
}
]
}
requests_mock.get(
CARBON_INTENSITY_URL,
json=bad_forecast_data,
status_code=200
)
result = get_carbon_forecast("Scotland")
assert result is None
assert "Failed to decode JSON response" in caplog.text

def test_get_carbon_forecast_http_error(requests_mock):
"""Test handling of HTTP errors (e.g., 401 Unauthorized)."""
requests_mock.get(
CARBON_INTENSITY_URL,
status_code=401
)
result = get_carbon_forecast("Scotland")
assert result is None

def test_get_carbon_forecast_timeout(requests_mock):
"""Test handling of request Timeout."""
requests_mock.get(
CARBON_INTENSITY_URL,
exc=Timeout
)
result = get_carbon_forecast("Scotland")
assert result is None
Loading
Loading