Skip to content

Commit f4c57f0

Browse files
committed
Add initial unit tests for get_and_store_user_stats
- Introduced comprehensive test suite to validate functionality of the `get_and_store_user_stats` method. - Covered core scenarios including: - Correct data aggregation and storage. - Handling cases with no trips or missing data. - Verifying behavior with partial data and multiple invocations. - handling of invalid UUID inputs. - setup and teardown to ensure test isolation and clean up user data. - Included data insertion for confirmed trips, composite trips, and server API timestamps to simulate realistic scenarios. This initial test suite establishes a baseline for ensuring reliability of the `get_and_store_user_stats` function. remove
1 parent 8faafe1 commit f4c57f0

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
from __future__ import unicode_literals, print_function, division, absolute_import
2+
import unittest
3+
import uuid
4+
import logging
5+
from datetime import datetime
6+
7+
import emission.analysis.result.user_stat as eaurs
8+
import emission.storage.timeseries.abstract_timeseries as esta
9+
import emission.core.wrapper.user as ecwu
10+
import emission.core.get_database as edb
11+
import emission.tests.common as etc
12+
13+
class TestGetAndStoreUserStats(unittest.TestCase):
14+
def setUp(self):
15+
"""
16+
Register a test user and insert initial time series data.
17+
"""
18+
etc.configLogging()
19+
self.test_email = f'testuser_{uuid.uuid4()}@example.com'
20+
self.user = ecwu.User.register(self.test_email)
21+
self.test_uuid = self.user.uuid
22+
23+
# Ensure the user profile exists
24+
if not self.user.getProfile():
25+
ecwu.User.createProfile(self.test_uuid, datetime.now())
26+
27+
ts = esta.TimeSeries.get_time_series(self.test_uuid)
28+
29+
# Insert 10 'analysis/confirmed_trip' entries
30+
for i in range(10):
31+
trip_entry = {
32+
"metadata": {"key": "analysis/confirmed_trip", "write_ts": datetime.now().timestamp()},
33+
"data": {
34+
"trip_id": str(uuid.uuid4()),
35+
"user_input": {"input": "test"} if i < 7 else {}
36+
}
37+
}
38+
ts.insert(trip_entry)
39+
40+
# Insert a single 'analysis/composite_trip' entry
41+
composite_trip = {
42+
"metadata": {"key": "analysis/composite_trip", "write_ts": datetime.now().timestamp()},
43+
"data": {"start_ts": 1609459200, "end_ts": 1612137600}
44+
}
45+
ts.insert(composite_trip)
46+
47+
# Insert a 'stats/server_api_time' entry
48+
server_api_time = {
49+
"metadata": {"key": "stats/server_api_time", "write_ts": datetime.now().timestamp()},
50+
"data": {"ts": 1614556800}
51+
}
52+
ts.insert(server_api_time)
53+
54+
def tearDown(self):
55+
"""
56+
Unregister the test user to clean up the database.
57+
"""
58+
try:
59+
ecwu.User.unregister(self.test_email)
60+
except Exception as e:
61+
logging.error(f"Failed to unregister user {self.test_email}: {e}")
62+
63+
def test_correct_data(self):
64+
"""
65+
Verify that statistics are correctly aggregated when all data is present.
66+
"""
67+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
68+
profile = self.user.getProfile()
69+
70+
self.assertIn("pipeline_range", profile, "Missing 'pipeline_range' in profile.")
71+
self.assertEqual(profile["pipeline_range"]["start_ts"], 1609459200, "Incorrect 'start_ts'.")
72+
self.assertEqual(profile["pipeline_range"]["end_ts"], 1612137600, "Incorrect 'end_ts'.")
73+
74+
self.assertEqual(profile.get("total_trips", None), 10, "'total_trips' should be 10.")
75+
self.assertEqual(profile.get("labeled_trips", None), 7, "'labeled_trips' should be 7.")
76+
77+
self.assertEqual(profile.get("last_call_ts", None), 1614556800, "'last_call_ts' mismatch.")
78+
79+
def test_no_trips(self):
80+
"""
81+
Ensure that statistics are zeroed out when there are no trips.
82+
"""
83+
tsdb = edb.get_timeseries_db()
84+
tsdb.delete_many({"user_id": self.test_uuid, "metadata.key": "analysis/confirmed_trip"})
85+
86+
# Confirm deletion
87+
remaining_trips = tsdb.count_documents({"user_id": self.test_uuid, "metadata.key": "analysis/confirmed_trip"})
88+
self.assertEqual(remaining_trips, 0, "Confirmed trips were not deleted.")
89+
90+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
91+
profile = self.user.getProfile()
92+
93+
self.assertEqual(profile.get("total_trips", None), 0, "'total_trips' should be 0.")
94+
self.assertEqual(profile.get("labeled_trips", None), 0, "'labeled_trips' should be 0.")
95+
96+
def test_no_last_call(self):
97+
"""
98+
Check that 'last_call_ts' is None when there is no server API time entry.
99+
"""
100+
tsdb = edb.get_timeseries_db()
101+
tsdb.delete_many({"user_id": self.test_uuid, "metadata.key": "stats/server_api_time"})
102+
103+
# Confirm deletion
104+
remaining_api_times = tsdb.count_documents({"user_id": self.test_uuid, "metadata.key": "stats/server_api_time"})
105+
self.assertEqual(remaining_api_times, 0, "Server API time entries were not deleted.")
106+
107+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
108+
profile = self.user.getProfile()
109+
110+
self.assertIsNone(profile.get("last_call_ts", None), "'last_call_ts' should be None.")
111+
112+
def test_partial_data(self):
113+
"""
114+
Verify behavior when 'analysis/composite_trip' data is missing.
115+
"""
116+
tsdb = edb.get_timeseries_db()
117+
tsdb.delete_many({"user_id": self.test_uuid, "metadata.key": "analysis/composite_trip"})
118+
119+
# Confirm deletion
120+
remaining_composite_trips = tsdb.count_documents({"user_id": self.test_uuid, "metadata.key": "analysis/composite_trip"})
121+
self.assertEqual(remaining_composite_trips, 0, "Composite trips were not deleted.")
122+
123+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
124+
profile = self.user.getProfile()
125+
126+
self.assertIsNone(profile["pipeline_range"].get("start_ts"), "'start_ts' should be None.")
127+
self.assertIsNone(profile["pipeline_range"].get("end_ts"), "'end_ts' should be None.")
128+
129+
self.assertEqual(profile.get("total_trips", None), 10, "'total_trips' should remain 10.")
130+
self.assertEqual(profile.get("labeled_trips", None), 7, "'labeled_trips' should remain 7.")
131+
132+
def test_multiple_calls(self):
133+
"""
134+
Ensure that multiple invocations correctly update statistics without duplication.
135+
"""
136+
# Initial call
137+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
138+
139+
ts = esta.TimeSeries.get_time_series(self.test_uuid)
140+
141+
# Insert additional trips
142+
for i in range(5):
143+
trip_entry = {
144+
"metadata": {"key": "analysis/confirmed_trip", "write_ts": datetime.now().timestamp()},
145+
"data": {
146+
"trip_id": str(uuid.uuid4()),
147+
"user_input": {"input": "additional_test"} if i < 3 else {}
148+
}
149+
}
150+
ts.insert(trip_entry)
151+
152+
# Insert new server API time entry
153+
new_server_api_time = {
154+
"metadata": {"key": "stats/server_api_time", "write_ts": datetime.now().timestamp()},
155+
"data": {"ts": 1617235200}
156+
}
157+
ts.insert(new_server_api_time)
158+
159+
# Second call
160+
eaurs.get_and_store_user_stats(self.test_uuid, "analysis/composite_trip")
161+
profile = self.user.getProfile()
162+
163+
self.assertEqual(profile.get("total_trips", None), 15, "'total_trips' should be 15 after additional inserts.")
164+
self.assertEqual(profile.get("labeled_trips", None), 10, "'labeled_trips' should be 10 after additional inserts.")
165+
self.assertEqual(profile.get("last_call_ts", None), 1617235200, "'last_call_ts' should be updated to 1617235200.")
166+
167+
def test_exception_handling(self):
168+
"""
169+
Test handling of invalid UUID inputs.
170+
"""
171+
invalid_uuid = "invalid-uuid-string"
172+
try:
173+
eaurs.get_and_store_user_stats(invalid_uuid, "analysis/composite_trip")
174+
except Exception as e:
175+
self.fail(f"get_and_store_user_stats raised an exception with invalid UUID: {e}")
176+
else:
177+
logging.debug("Handled invalid UUID without raising exceptions.")
178+
179+
if __name__ == '__main__':
180+
logging.basicConfig(level=logging.DEBUG)
181+
unittest.main()

0 commit comments

Comments
 (0)