Skip to content

Commit cb9b32b

Browse files
committed
DBC22-6067: added extra test cases to satisfy coverage
1 parent 628df8e commit cb9b32b

4 files changed

Lines changed: 166 additions & 15 deletions

File tree

src/backend/apps/webcam/enums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
CAMERA_FIELD_MAPPING = {
1010
'name': 'cam_internetname',
1111
'caption': 'cam_internetcaption',
12-
'is_on': 'cam_controldisabled',
13-
'should_appear': 'cam_controldisappear',
12+
'is_on': 'isOn',
13+
'should_appear': 'should_appear',
1414
}

src/backend/apps/webcam/tasks.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from django.contrib.gis.db.models.functions import Distance
2929
from django.contrib.gis.geos import LineString, MultiLineString, Point
3030
from django.core.exceptions import ObjectDoesNotExist
31-
from django.db.models import F
31+
from django.db.models import F, BooleanField
3232
from huey.exceptions import CancelExecution
3333
from PIL import Image, ImageDraw, ImageFile, ImageFont
3434
from psycopg import IntegrityError
@@ -103,14 +103,14 @@ def update_cam_from_sql_db(id: int, current_time: datetime.datetime):
103103
orientation=F('cam_locationsorientation'),
104104
elevation=F('cam_locationselevation'),
105105
isOn=Case(
106-
When(cam_controldisabled=False, then=Value(1)),
107-
default=Value(0),
108-
output_field=IntegerField()
106+
When(cam_controldisabled=0, then=Value(True)),
107+
default=Value(False),
108+
output_field=BooleanField()
109109
),
110110
should_appear=Case(
111-
When(cam_controldisappear=False, then=Value(1)),
112-
default=Value(0),
113-
output_field=IntegerField()
111+
When(cam_controldisappear=0, then=Value(True)),
112+
default=Value(False),
113+
output_field=BooleanField()
114114
),
115115
isOnDemand=F('cam_maintenanceis_on_demand'),
116116
credit=F('cam_internetcredit'),
@@ -126,6 +126,7 @@ def update_cam_from_sql_db(id: int, current_time: datetime.datetime):
126126
'orientation',
127127
'elevation',
128128
'isOn',
129+
'should_appear',
129130
'isOnDemand',
130131
'credit',
131132
'dbc_mark',
@@ -158,31 +159,33 @@ def format_region_name(region_name):
158159
return ''.join(result)
159160

160161
def update_webcam_db(cam_id: int, cam_data: dict):
162+
is_updated = False
161163
time_now_utc = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%d%H%M%S%f")[:-3]
162164
camera_status = calculate_camera_status(time_now_utc)
163165
ts_seconds = int(camera_status["timestamp"])
164166
dt_utc = datetime.datetime.fromtimestamp(ts_seconds, tz=ZoneInfo("UTC"))
165167

166168
existing_webcam = Webcam.objects.filter(id=cam_id).first()
167169
if not existing_webcam:
168-
return False
170+
return is_updated
169171
else:
170172
for field in CAMERA_DIFF_FIELDS:
171173
source_field = CAMERA_FIELD_MAPPING.get(field, field)
172174
webcam_value = getattr(existing_webcam, field)
173-
source_value = cam_data.get(source_field)
175+
source_value = cam_data.get(source_field)
174176
if webcam_value != source_value:
175177
updated_count = Webcam.objects.filter(id=cam_id).update(
176178
is_on=True if cam_data.get("isOn") == 1 else False,
179+
should_appear=True if cam_data.get("should_appear") == 1 else False,
177180
name=cam_data.get("cam_internetname"),
178181
caption=cam_data.get("cam_internetcaption"),
179182
is_new=cam_data.get("isNew"),
180183
is_on_demand=cam_data.get("isOnDemand"),
181184
last_update_attempt=dt_utc,
182185
last_update_modified=dt_utc
183186
)
184-
return updated_count
185-
187+
is_updated = True
188+
return is_updated
186189

187190
def create_webcam_db(cam_data: dict):
188191
cam_id = cam_data.id

src/backend/apps/webcam/tests/test_webcam_populate.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import logging
44
from http.client import INTERNAL_SERVER_ERROR
55
from pathlib import Path
6-
from unittest.mock import patch
7-
6+
from unittest.mock import MagicMock, patch
87
from apps.shared.tests import BaseTest, MockResponse
98
from apps.webcam.models import Webcam
109
from apps.webcam.tests.test_data.webcam_parsed_feed import parsed_feed
1110
from django.contrib.gis.geos import Point
1211
from apps.webcam.tests.test_webcam_ordering import side_effect_populate
12+
from django.core.exceptions import ObjectDoesNotExist
13+
from apps.webcam.tasks import populate_webcam_from_data
14+
from apps.webcam.tasks import update_webcam_db_stale_delayed, update_cam_from_sql_db
1315

1416
# suppress logged error messages to reduce noise
1517
logging.getLogger().setLevel(logging.CRITICAL)
@@ -121,3 +123,46 @@ def test_populate_webcam_with_validation_error(self, mock_populate):
121123
webcam_id_list = sorted(Webcam.objects.all().values_list("id", flat=True))
122124
assert webcam_id_list == [1, 2]
123125

126+
@patch("apps.webcam.tasks.populate_all_webcam_data")
127+
def test_populate_webcam_from_data_success(self, mock_populate):
128+
fake_data = MagicMock()
129+
fake_data.id = 1
130+
131+
with patch("apps.webcam.tasks.create_webcam_db") as mock_create:
132+
mock_create.return_value = (None, False)
133+
134+
populate_webcam_from_data(fake_data)
135+
136+
mock_create.assert_called_once_with(fake_data)
137+
138+
def test_populate_webcam_from_data_exception(self):
139+
fake_data = MagicMock()
140+
fake_data.id = 999
141+
142+
with patch("apps.webcam.tasks.create_webcam_db") as mock_create, \
143+
patch("apps.webcam.tasks.logger") as mock_logger:
144+
145+
mock_create.side_effect = ObjectDoesNotExist()
146+
147+
populate_webcam_from_data(fake_data)
148+
149+
mock_logger.error.assert_called_once()
150+
151+
@patch("apps.webcam.tasks.populate_all_webcam_data")
152+
def test_update_webcam_db_stale_delayed(self, mock_populate):
153+
mock_populate.side_effect = lambda *args, **kwargs: side_effect_populate(self.mock_webcam_feed_result_2)
154+
from apps.webcam import tasks
155+
tasks.populate_all_webcam_data()
156+
157+
# Call the function
158+
webcam = Webcam.objects.first()
159+
update_webcam_db_stale_delayed(webcam)
160+
161+
# Refresh from DB
162+
webcam.refresh_from_db()
163+
164+
# Assertions
165+
self.assertFalse(webcam.marked_stale)
166+
self.assertFalse(webcam.marked_delayed)
167+
self.assertIsInstance(webcam.last_update_attempt, datetime.datetime)
168+
self.assertIsInstance(webcam.last_update_modified, datetime.datetime)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import datetime
2+
import json
3+
from django.test import TestCase
4+
from unittest.mock import MagicMock, patch
5+
from apps.webcam.tasks import update_cam_from_sql_db, update_webcam_db
6+
from apps.webcam.tests.test_webcam_ordering import side_effect_populate
7+
from apps.webcam.models import Webcam
8+
from pathlib import Path
9+
10+
webcam_feed_data_1 = open(
11+
str(Path(__file__).parent) + "/test_data/webcam_feed_list_of_two.json"
12+
)
13+
mock_webcam_feed_result_1 = json.load(webcam_feed_data_1)
14+
15+
def _make_existing_webcam(mock_populate, mock_webcam_feed):
16+
mock_populate.side_effect = lambda *args, **kwargs: side_effect_populate(mock_webcam_feed)
17+
from apps.webcam import tasks
18+
tasks.populate_all_webcam_data()
19+
20+
class TestUpdateCamFromSqlDb(TestCase):
21+
22+
@patch("apps.webcam.tasks.populate_all_webcam_data")
23+
@patch("apps.webcam.tasks.update_webcam_db")
24+
@patch("apps.webcam.tasks.CameraSource")
25+
def test_cam_found_calls_update_webcam_db_and_returns_true(
26+
self, mock_camera_source, mock_update_webcam_db, mock_populate
27+
):
28+
29+
_make_existing_webcam(mock_populate, mock_webcam_feed_result_1)
30+
31+
mock_cam = Webcam.objects.get(id=1)
32+
33+
# Wire up the full ORM chain so .using("mssql") never hits the real DB
34+
(mock_camera_source.objects
35+
.using.return_value
36+
.filter.return_value
37+
.annotate.return_value
38+
.values.return_value
39+
.first.return_value) = mock_cam
40+
41+
mock_update_webcam_db.return_value = 1
42+
43+
result = update_cam_from_sql_db(id=1, current_time=datetime.datetime.now())
44+
45+
self.assertTrue(result)
46+
mock_update_webcam_db.assert_called_once_with(1, mock_cam)
47+
mock_camera_source.objects.using.assert_called_once_with("mssql")
48+
49+
@patch("apps.webcam.tasks.CameraSource")
50+
def test_orm_exception_returns_empty_dict(self, mock_camera_source):
51+
# Simulates a DB connection failure
52+
mock_camera_source.objects.using.side_effect = Exception("mssql unreachable")
53+
54+
result = update_cam_from_sql_db(id=1, current_time=datetime.datetime.now())
55+
56+
self.assertEqual(result, {})
57+
58+
59+
60+
class TestUpdateWebcamDb(TestCase):
61+
62+
@patch("apps.webcam.tasks.populate_all_webcam_data")
63+
@patch("apps.webcam.tasks.calculate_camera_status")
64+
def test_webcam_not_found_returns_false(self, mock_calc_status, mock_populate):
65+
_make_existing_webcam(mock_populate, mock_webcam_feed_result_1)
66+
webcam = Webcam.objects.filter(id=1).first()
67+
68+
camera_source_data = {
69+
"id": 1,
70+
"cam_internetname": "Test Cam",
71+
"cam_internetcaption": "Test Caption",
72+
"isOn": True,
73+
"should_appear": True,
74+
"isNew": 0,
75+
"isOnDemand": 0,
76+
}
77+
78+
result = update_webcam_db(cam_id=1, cam_data=camera_source_data)
79+
webcam.refresh_from_db()
80+
self.assertEqual(webcam.name, "Test Cam")
81+
self.assertEqual(webcam.caption, "Test Caption")
82+
self.assertEqual(webcam.is_on, True)
83+
self.assertEqual(webcam.should_appear, True)
84+
self.assertEqual(result, True)
85+
86+
result = update_webcam_db(cam_id=1, cam_data=camera_source_data)
87+
webcam.refresh_from_db()
88+
self.assertEqual(webcam.name, "Test Cam")
89+
self.assertEqual(webcam.caption, "Test Caption")
90+
self.assertEqual(webcam.is_on, True)
91+
self.assertEqual(webcam.should_appear, True)
92+
self.assertEqual(result, False)
93+
94+
camera_source_data["cam_internetcaption"] = "Updated Caption"
95+
result = update_webcam_db(cam_id=1, cam_data=camera_source_data)
96+
webcam.refresh_from_db()
97+
self.assertEqual(webcam.caption, "Updated Caption")
98+
self.assertEqual(result, True)
99+
100+
# Ensure DB has NO webcam
101+
Webcam.objects.all().delete()
102+
result = update_webcam_db(cam_id=1, cam_data=camera_source_data)
103+
self.assertEqual(result, False)

0 commit comments

Comments
 (0)