Skip to content

Commit 58631cb

Browse files
authored
Merge pull request #2339 from PolicyEngine/test_set_policy_service
Refactored tests for set policy service (Fixes: #2392)
2 parents 5d86531 + f52d4f5 commit 58631cb

5 files changed

Lines changed: 176 additions & 2 deletions

File tree

changelog_entry.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- bump: minor
2+
changes:
3+
added:
4+
- Refactored tests for set_policy_service

policyengine_api/services/policy_service.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ def set_policy(
9696
print("Setting new policy")
9797

9898
try:
99+
# Convert country_id to lowercase
100+
if not country_id.islower():
101+
country_id = country_id.lower()
102+
103+
# Validate country_id
104+
if country_id not in COUNTRY_PACKAGE_VERSIONS:
105+
raise ValueError(f"Invalid country_id: {country_id}")
99106

100107
policy_hash = hash_object(policy_json)
101108
api_version = COUNTRY_PACKAGE_VERSIONS.get(country_id)

tests/fixtures/services/policy_service.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
}
2222

2323

24+
@pytest.fixture
25+
def mock_database():
26+
"""Mock the database module."""
27+
with patch("policyengine_api.services.policy_service.database") as mock_db:
28+
yield mock_db
29+
30+
2431
@pytest.fixture
2532
def mock_hash_object():
2633
"""Mock the hash_object function."""

tests/to_refactor/python/test_policy_service_old.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_set_policy_new(self, policy_service, mock_database):
9090

9191
test_policy = {"param": "value"}
9292
test_label = "new_policy"
93-
test_country_id = "US"
93+
test_country_id = "us"
9494

9595
expected_calls = [
9696
# First call - check if policy exists

tests/unit/services/test_policy_service.py

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import pytest
22
import json
3-
3+
from unittest.mock import call
44
from policyengine_api.services.policy_service import PolicyService
55

66
from tests.fixtures.services.policy_service import (
77
valid_policy_data,
8+
valid_hash_value,
9+
mock_hash_object,
10+
mock_database,
811
existing_policy_record,
912
)
1013

@@ -167,3 +170,156 @@ def test_get_policy_json_given_negative_int_id(self, test_db):
167170
# WHEN we call get_policy_json with the invalid ID...
168171
# THEN an exception should be raised
169172
service.get_policy_json("us", INVALID_RECORD_ID)
173+
174+
175+
class TestSetPolicy:
176+
def test_set_policy_new(self, mock_database, mock_hash_object):
177+
# GIVEN a new policy to insert
178+
new_policy_id = 12 # Different from existing fixture ID
179+
test_policy = {"param": "value"}
180+
test_label = "new_policy"
181+
test_country_id = "us"
182+
183+
# Get current API version dynamically
184+
from policyengine_api.constants import COUNTRY_PACKAGE_VERSIONS
185+
186+
current_api_version = COUNTRY_PACKAGE_VERSIONS.get(test_country_id)
187+
188+
# Setup mocks
189+
mock_database.query.return_value.fetchone.side_effect = [
190+
None, # First call: policy does not exist
191+
{"id": new_policy_id}, # Second call: fetch newly inserted policy
192+
]
193+
194+
# Define expected database calls
195+
expected_calls = [
196+
# First call - check if policy exists
197+
call(
198+
"SELECT * FROM policy WHERE country_id = ? AND policy_hash = ? AND label = ?",
199+
(test_country_id, valid_hash_value, test_label),
200+
),
201+
# Second call - insert new policy
202+
call(
203+
"INSERT INTO policy (country_id, policy_json, policy_hash, label, api_version) VALUES (?, ?, ?, ?, ?)",
204+
(
205+
test_country_id,
206+
json.dumps(test_policy),
207+
valid_hash_value,
208+
test_label,
209+
current_api_version, # From COUNTRY_PACKAGE_VERSIONS for 'us'
210+
),
211+
),
212+
# Third call - fetch the newly created policy
213+
call(
214+
"SELECT * FROM policy WHERE country_id = ? AND policy_hash = ? AND label = ?",
215+
(test_country_id, valid_hash_value, test_label),
216+
),
217+
]
218+
219+
# WHEN we call set_policy
220+
policy_id, message, exists = service.set_policy(
221+
test_country_id, test_label, test_policy
222+
)
223+
224+
# THEN the result should indicate a new policy was created
225+
assert policy_id == new_policy_id
226+
assert message == "Policy created"
227+
assert exists is False
228+
229+
# Verify the database queries were called as expected
230+
assert mock_database.query.call_args_list == expected_calls
231+
232+
def test_set_policy_existing(
233+
self, mock_database, mock_hash_object, existing_policy_record
234+
):
235+
# GIVEN an existing policy record
236+
existing_policy = existing_policy_record
237+
238+
# Setup mock
239+
mock_database.query.return_value.fetchone.return_value = (
240+
existing_policy
241+
)
242+
243+
# Define expected database calls - matches actual implementation
244+
expected_calls = [
245+
call(
246+
"SELECT * FROM policy WHERE country_id = ? AND policy_hash = ? AND label IS NULL",
247+
(
248+
existing_policy["country_id"],
249+
valid_hash_value,
250+
), # No None parameter for IS NULL
251+
),
252+
]
253+
254+
# WHEN we call set_policy with existing policy data
255+
policy_id, message, exists = service.set_policy(
256+
existing_policy["country_id"],
257+
existing_policy["label"],
258+
json.loads(existing_policy["policy_json"]),
259+
)
260+
261+
# THEN the result should indicate the policy already exists
262+
assert policy_id == existing_policy["id"]
263+
assert message == "Policy already exists"
264+
assert exists is True
265+
266+
# Verify the database query was called as expected
267+
assert mock_database.query.call_args_list == expected_calls
268+
269+
def test_set_policy_given_database_insert_failure(
270+
self, mock_database, mock_hash_object
271+
):
272+
# GIVEN a database insertion failure
273+
test_policy = {"param": "value"}
274+
test_label = "test_policy"
275+
test_country_id = "us"
276+
277+
# Setup mock to raise exception on insert
278+
mock_database.query.return_value.fetchone.side_effect = [
279+
None, # First call: policy does not exist
280+
Exception(
281+
"Database insertion failed"
282+
), # Second call: insertion fails
283+
]
284+
285+
# WHEN we call set_policy
286+
with pytest.raises(Exception, match="Database insertion failed"):
287+
# THEN an exception should be raised
288+
service.set_policy(test_country_id, test_label, test_policy)
289+
290+
def test_set_policy_given_invalid_country_id(self, mock_hash_object):
291+
# GIVEN an invalid country_id
292+
INVALID_COUNTRY_ID = "xx" # Unsupported country code
293+
test_policy = {"param": "value"}
294+
test_label = "test_policy"
295+
296+
# WHEN we call set_policy with an invalid country_id
297+
with pytest.raises(
298+
ValueError, match=f"Invalid country_id: {INVALID_COUNTRY_ID}"
299+
):
300+
# THEN an exception should be raised
301+
service.set_policy(INVALID_COUNTRY_ID, test_label, test_policy)
302+
303+
def test_set_policy_given_empty_label(
304+
self, mock_database, mock_hash_object
305+
):
306+
# GIVEN an empty label
307+
EMPTY_LABEL = ""
308+
test_policy = {"param": "value"}
309+
test_country_id = "us"
310+
311+
# Setup mock
312+
mock_database.query.return_value.fetchone.side_effect = [
313+
None, # Policy does not exist
314+
{"id": 13}, # Return mock policy after creation
315+
]
316+
317+
# WHEN we call set_policy with an empty label
318+
policy_id, message, exists = service.set_policy(
319+
test_country_id, EMPTY_LABEL, test_policy
320+
)
321+
322+
# THEN the result should indicate a new policy was created
323+
assert policy_id == 13
324+
assert message == "Policy created"
325+
assert exists is False

0 commit comments

Comments
 (0)