Skip to content

Commit a88000f

Browse files
authored
Merge pull request #1207 from puneetdixit200/tests/schema-compatibility
tests: check client server schema compatibility
2 parents d2ce064 + dedca17 commit a88000f

4 files changed

Lines changed: 137 additions & 0 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import dataclasses
2+
import importlib.util
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
from carbonserver.api import schemas as server_schemas
8+
9+
10+
def load_client_schemas():
11+
repo_root = Path(__file__).resolve().parents[3]
12+
client_schema_path = repo_root / "codecarbon" / "core" / "schemas.py"
13+
spec = importlib.util.spec_from_file_location(
14+
"codecarbon_client_schemas", client_schema_path
15+
)
16+
module = importlib.util.module_from_spec(spec)
17+
spec.loader.exec_module(module)
18+
return module
19+
20+
21+
client_schemas = load_client_schemas()
22+
23+
24+
CREATE_SCHEMA_PAIRS = [
25+
(client_schemas.EmissionCreate, server_schemas.EmissionCreate),
26+
(client_schemas.RunCreate, server_schemas.RunCreate),
27+
(client_schemas.ExperimentCreate, server_schemas.ExperimentCreate),
28+
(client_schemas.ProjectCreate, server_schemas.ProjectCreate),
29+
(client_schemas.OrganizationCreate, server_schemas.OrganizationCreate),
30+
]
31+
32+
33+
@pytest.mark.parametrize(("client_schema", "server_schema"), CREATE_SCHEMA_PAIRS)
34+
def test_client_create_schemas_match_server_fields(client_schema, server_schema):
35+
client_fields = {field.name for field in dataclasses.fields(client_schema)}
36+
server_fields = set(server_schema.model_fields)
37+
38+
assert client_fields == server_fields
39+
40+
41+
@pytest.mark.parametrize(
42+
("client_payload", "server_schema"),
43+
[
44+
(
45+
client_schemas.EmissionCreate(
46+
timestamp="2021-04-04T08:43:00+02:00",
47+
run_id="40088f1a-d28e-4980-8d80-bf5600056a14",
48+
duration=98745,
49+
emissions_sum=1544.54,
50+
emissions_rate=1.548444,
51+
cpu_power=0.3,
52+
gpu_power=0.0,
53+
ram_power=0.15,
54+
cpu_energy=55.21874,
55+
gpu_energy=0.0,
56+
ram_energy=2.0,
57+
energy_consumed=57.21874,
58+
cpu_utilization_percent=12.5,
59+
gpu_utilization_percent=34.5,
60+
ram_utilization_percent=56.5,
61+
wue=0.8,
62+
),
63+
server_schemas.EmissionCreate,
64+
),
65+
(
66+
client_schemas.RunCreate(
67+
timestamp="2021-04-04T08:43:00+02:00",
68+
experiment_id="8edb03e1-9a28-452a-9c93-a3b6560136d7",
69+
os="macOS-10.15.7-x86_64-i386-64bit",
70+
python_version="3.8.0",
71+
codecarbon_version="2.1.3",
72+
cpu_count=12,
73+
cpu_model="Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz",
74+
gpu_count=4,
75+
gpu_model="NVIDIA",
76+
longitude=-7.6174,
77+
latitude=33.5822,
78+
region="EUROPE",
79+
provider="AWS",
80+
ram_total_size=83948.22,
81+
tracking_mode="Machine",
82+
),
83+
server_schemas.RunCreate,
84+
),
85+
(
86+
client_schemas.ExperimentCreate(
87+
timestamp="2021-04-04T08:43:00+02:00",
88+
name="Run on AWS",
89+
description="AWS API for Code Carbon",
90+
country_name="France",
91+
country_iso_code="FRA",
92+
region="france",
93+
on_cloud=True,
94+
cloud_provider="aws",
95+
cloud_region="eu-west-1a",
96+
project_id="8edb03e1-9a28-452a-9c93-a3b6560136d7",
97+
),
98+
server_schemas.ExperimentCreate,
99+
),
100+
(
101+
client_schemas.ProjectCreate(
102+
name="API Code Carbon",
103+
description="API for Code Carbon",
104+
organization_id="8edb03e1-9a28-452a-9c93-a3b6560136d7",
105+
),
106+
server_schemas.ProjectCreate,
107+
),
108+
(
109+
client_schemas.OrganizationCreate(
110+
name="Code Carbon",
111+
description="Save the world, one run at a time.",
112+
),
113+
server_schemas.OrganizationCreate,
114+
),
115+
],
116+
)
117+
def test_client_create_payloads_validate_against_server_schemas(
118+
client_payload, server_schema
119+
):
120+
server_schema.model_validate(dataclasses.asdict(client_payload))

codecarbon/core/api_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ def add_emission(self, carbon_emission: dict):
227227
gpu_energy=carbon_emission["gpu_energy"],
228228
ram_energy=carbon_emission["ram_energy"],
229229
energy_consumed=carbon_emission["energy_consumed"],
230+
cpu_utilization_percent=carbon_emission.get("cpu_utilization_percent"),
231+
gpu_utilization_percent=carbon_emission.get("gpu_utilization_percent"),
232+
ram_utilization_percent=carbon_emission.get("ram_utilization_percent"),
233+
wue=carbon_emission.get("wue", 0),
230234
)
231235
try:
232236
payload = dataclasses.asdict(emission)

codecarbon/core/schemas.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class EmissionBase:
2222
gpu_energy: float
2323
ram_energy: float
2424
energy_consumed: float
25+
cpu_utilization_percent: Optional[float] = None
26+
gpu_utilization_percent: Optional[float] = None
27+
ram_utilization_percent: Optional[float] = None
28+
wue: Optional[float] = 0
2529

2630

2731
class EmissionCreate(EmissionBase):

tests/test_api_call.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,17 @@ def test_call_api(self):
125125
latitude=33.5822,
126126
ram_total_size=83948.22,
127127
tracking_mode="Machine",
128+
cpu_utilization_percent=12.5,
129+
gpu_utilization_percent=34.5,
130+
ram_utilization_percent=56.5,
131+
wue=0.8,
128132
)
129133
assert api.add_emission(dataclasses.asdict(carbon_emission))
134+
payload = m.last_request.json()
135+
assert payload["cpu_utilization_percent"] == 12.5
136+
assert payload["gpu_utilization_percent"] == 34.5
137+
assert payload["ram_utilization_percent"] == 56.5
138+
assert payload["wue"] == 0.8
130139

131140
def test_check_auth_returns_none_on_error(self):
132141
with requests_mock.Mocker() as m:

0 commit comments

Comments
 (0)