Skip to content

Commit c60c2de

Browse files
committed
fix: add tests for review
1 parent bcf72f1 commit c60c2de

11 files changed

Lines changed: 574 additions & 268 deletions

tests/conftest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
import subprocess
33
import time
44
import requests
5+
import os
56

67
from frost_sta_client.service.sensorthingsservice import SensorThingsService
78

89
@pytest.fixture(scope='session')
910
def frost_server():
11+
if os.environ.get('RUN_INTEGRATION') != '1':
12+
# Skip starting server if not requested
13+
yield
14+
return
1015
# Start FROST-Server using Podman
1116
subprocess.run(['podman', 'compose', '-f', 'frost_server/docker-compose.yaml', 'up', '-d'])
1217
# Wait for server to start
@@ -21,7 +26,7 @@ def frost_server():
2126
else:
2227
raise RuntimeError('FROST-Server failed to start')
2328
yield
24-
subprocess.run(['podman', 'compose', '-f', '../frost_server/docker-compose.yaml', 'down'])
29+
subprocess.run(['podman', 'compose', '-f', 'frost_server/docker-compose.yaml', 'down'])
2530

2631
@pytest.fixture
2732
def sensorthings_service(frost_server):

tests/test_dao_base.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import pytest
2+
import requests
3+
from frost_sta_client.service.sensorthingsservice import SensorThingsService
4+
from frost_sta_client.model.thing import Thing
5+
6+
7+
class MockResponse:
8+
def __init__(self, status_code=200, json_data=None, headers=None):
9+
self.status_code = status_code
10+
self._json = json_data if json_data is not None else {}
11+
self.headers = headers or {}
12+
13+
def json(self):
14+
return self._json
15+
16+
def raise_for_status(self):
17+
if self.status_code >= 400:
18+
raise requests.exceptions.HTTPError(response=self)
19+
20+
21+
class DummyService(SensorThingsService):
22+
def __init__(self):
23+
super().__init__('http://example.org/FROST-Server/v1.1')
24+
self.calls = []
25+
26+
def execute(self, method, url, **kwargs):
27+
self.calls.append((method, str(url), kwargs))
28+
if method == 'post':
29+
return MockResponse(201, {}, headers={'location': 'Things(42)'})
30+
if method == 'get':
31+
return MockResponse(200, {"@iot.id": 5, "name": "MyThing"})
32+
return MockResponse(200, {})
33+
34+
35+
def test_base_dao_create_sets_id_and_service():
36+
svc = DummyService()
37+
t = Thing(name='X')
38+
svc.create(t)
39+
assert t.id == 42
40+
assert t.service is svc
41+
42+
43+
def test_base_dao_find_returns_entity():
44+
svc = DummyService()
45+
found = svc.things().find(5)
46+
assert found.id == 5
47+
assert found.name == 'MyThing'
48+
assert found.service is svc
49+
50+
51+
def test_base_dao_update_without_id_raises():
52+
svc = DummyService()
53+
t = Thing(name='noid')
54+
with pytest.raises(AttributeError):
55+
svc.update(t)
56+
57+
58+
def test_base_dao_patch_validates_and_sends_headers():
59+
svc = DummyService()
60+
t = Thing(id=7)
61+
patches = [{"op": "replace", "path": "/name", "value": "new"}]
62+
svc.patch(t, patches)
63+
method, url, kwargs = svc.calls[-1]
64+
assert method == 'patch'
65+
assert kwargs['headers']['Content-type'] == 'application/json-patch+json'
66+
67+
68+
def test_entity_path_formats_string_and_int():
69+
svc = DummyService()
70+
assert svc.things().entity_path(1) == 'Things(1)'
71+
assert svc.things().entity_path('abc') == "Things('abc')"

tests/test_entity_behaviour.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from frost_sta_client.service.sensorthingsservice import SensorThingsService
2+
from frost_sta_client.model.thing import Thing
3+
from frost_sta_client.model.location import Location
4+
from frost_sta_client.model.ext.entity_list import EntityList
5+
from frost_sta_client.model.ext.entity_type import EntityTypes
6+
7+
8+
def test_entity_equality_by_id():
9+
a = Thing(id=1, name='A')
10+
b = Thing(id=1, name='B')
11+
assert a == b
12+
13+
14+
def test_set_service_propagates_to_children():
15+
t = Thing(name='T')
16+
loc = Location(name='L')
17+
t.locations = EntityList(entity_class=EntityTypes['Location']['class'], entities=[loc])
18+
svc = SensorThingsService('http://example.org/FROST-Server/v1.1')
19+
t.set_service(svc)
20+
assert t.service is svc
21+
assert t.locations.entities[0].service is svc

tests/test_entity_list.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from frost_sta_client.utils import transform_json_to_entity_list
2+
from frost_sta_client.service.sensorthingsservice import SensorThingsService
3+
4+
5+
class MockResponse:
6+
def __init__(self, json_data):
7+
self._json = json_data
8+
self.status_code = 200
9+
10+
def json(self):
11+
return self._json
12+
13+
def raise_for_status(self):
14+
pass
15+
16+
17+
class DummyService(SensorThingsService):
18+
def __init__(self, url, page2):
19+
super().__init__(url)
20+
self.page2 = page2
21+
self.calls = 0
22+
23+
def execute(self, method, url, **kwargs):
24+
self.calls += 1
25+
return MockResponse(self.page2)
26+
27+
28+
def test_entity_list_iterates_across_pages():
29+
page1 = {
30+
"value": [
31+
{"@iot.id": 1, "name": "A"},
32+
{"@iot.id": 2, "name": "B"},
33+
],
34+
"@iot.nextLink": "http://example.org/FROST-Server/v1.1/Things?$skip=2"
35+
}
36+
page2 = {
37+
"value": [
38+
{"@iot.id": 3, "name": "C"},
39+
{"@iot.id": 4, "name": "D"},
40+
]
41+
}
42+
elist = transform_json_to_entity_list(page1, 'frost_sta_client.model.thing.Thing')
43+
svc = DummyService('http://example.org/FROST-Server/v1.1', page2)
44+
elist.set_service(svc)
45+
called = []
46+
elist.step_size = 2
47+
elist.callback = lambda idx: called.append(idx)
48+
names = [e.name for e in elist]
49+
assert names == ['A', 'B', 'C', 'D']
50+
assert called == [0, 2]

0 commit comments

Comments
 (0)