Skip to content

Commit 957c8fa

Browse files
TeachMeTWshankari
authored andcommitted
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 Modified test Refactored the test and simplified it; validated all new user stats added store to intake Updated Based on requested changes Removed unnecessary wrapper Changed to Aug 21 for the time being
1 parent 39a3358 commit 957c8fa

File tree

3 files changed

+127
-24
lines changed

3 files changed

+127
-24
lines changed

emission/analysis/result/user_stat.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,6 @@
77
import emission.storage.timeseries.abstract_timeseries as esta
88
import emission.core.wrapper.user as ecwu
99

10-
TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
11-
12-
def count_trips(ts: esta.TimeSeries, key_list: list, extra_query_list: Optional[list] = None) -> int:
13-
"""
14-
Counts the number of trips based on the provided query.
15-
16-
:param ts: The time series object.
17-
:type ts: esta.TimeSeries
18-
:param key_list: List of keys to filter trips.
19-
:type key_list: list
20-
:param extra_query_list: Additional queries, defaults to None.
21-
:type extra_query_list: Optional[list], optional
22-
:return: The count of trips.
23-
:rtype: int
24-
"""
25-
count = ts.find_entries_count(key_list=key_list, extra_query_list=extra_query_list)
26-
logging.debug(f"Counted {len(key_list)} trips with additional queries {extra_query_list}: {count}")
27-
return count
28-
29-
3010
def get_last_call_timestamp(ts: esta.TimeSeries) -> Optional[int]:
3111
"""
3212
Retrieves the last API call timestamp.
@@ -81,9 +61,8 @@ def get_and_store_user_stats(user_id: str, trip_key: str) -> None:
8161
end_ts_result = ts.get_first_value_for_field(trip_key, "data.end_ts", pymongo.DESCENDING)
8262
end_ts = None if end_ts_result == -1 else end_ts_result
8363

84-
total_trips = count_trips(ts, key_list=["analysis/confirmed_trip"])
85-
labeled_trips = count_trips(
86-
ts,
64+
total_trips = ts.find_entries_count(key_list=["analysis/confirmed_trip"])
65+
labeled_trips = ts.find_entries_count(
8766
key_list=["analysis/confirmed_trip"],
8867
extra_query_list=[{'data.user_input': {'$ne': {}}}]
8968
)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from __future__ import unicode_literals, print_function, division, absolute_import
2+
import unittest
3+
import uuid
4+
import logging
5+
import json
6+
import os
7+
import time
8+
import pandas as pd
9+
10+
from builtins import *
11+
from future import standard_library
12+
standard_library.install_aliases()
13+
14+
# Standard imports
15+
import emission.storage.json_wrappers as esj
16+
17+
# Our imports
18+
import emission.core.get_database as edb
19+
import emission.storage.timeseries.timequery as estt
20+
import emission.storage.timeseries.abstract_timeseries as esta
21+
import emission.storage.decorations.analysis_timeseries_queries as esda
22+
import emission.core.wrapper.user as ecwu
23+
import emission.net.api.stats as enac
24+
import emission.pipeline.intake_stage as epi
25+
26+
# Test imports
27+
import emission.tests.common as etc
28+
29+
30+
class TestUserStats(unittest.TestCase):
31+
def setUp(self):
32+
"""
33+
Set up the test environment by loading real example data for both Android and users.
34+
"""
35+
# Set up the real example data with entries
36+
self.testUUID = uuid.uuid4()
37+
with open("emission/tests/data/real_examples/shankari_2015-aug-21") as fp:
38+
self.entries = json.load(fp, object_hook = esj.wrapped_object_hook)
39+
# Retrieve the user profile
40+
etc.setupRealExampleWithEntries(self)
41+
profile = edb.get_profile_db().find_one({"user_id": self.testUUID})
42+
if profile is None:
43+
# Initialize the profile if it does not exist
44+
edb.get_profile_db().insert_one({"user_id": self.testUUID})
45+
46+
#etc.runIntakePipeline(self.testUUID)
47+
epi.run_intake_pipeline_for_user(self.testUUID, skip_if_no_new_data = False)
48+
logging.debug("UUID = %s" % (self.testUUID))
49+
50+
def tearDown(self):
51+
"""
52+
Clean up the test environment by removing analysis configuration and deleting test data from databases.
53+
"""
54+
55+
edb.get_timeseries_db().delete_many({"user_id": self.testUUID})
56+
edb.get_pipeline_state_db().delete_many({"user_id": self.testUUID})
57+
edb.get_analysis_timeseries_db().delete_many({"user_id": self.testUUID})
58+
edb.get_profile_db().delete_one({"user_id": self.testUUID})
59+
60+
def testGetAndStoreUserStats(self):
61+
"""
62+
Test get_and_store_user_stats for the user to ensure that user statistics
63+
are correctly aggregated and stored in the user profile.
64+
"""
65+
66+
# Retrieve the updated user profile from the database
67+
profile = edb.get_profile_db().find_one({"user_id": self.testUUID})
68+
69+
# Ensure that the profile exists
70+
self.assertIsNotNone(profile, "User profile should exist after storing stats.")
71+
72+
# Verify that the expected fields are present
73+
self.assertIn("total_trips", profile, "User profile should contain 'total_trips'.")
74+
self.assertIn("labeled_trips", profile, "User profile should contain 'labeled_trips'.")
75+
self.assertIn("pipeline_range", profile, "User profile should contain 'pipeline_range'.")
76+
self.assertIn("last_call_ts", profile, "User profile should contain 'last_call_ts'.")
77+
78+
expected_total_trips = 5
79+
expected_labeled_trips = 0
80+
81+
self.assertEqual(profile["total_trips"], expected_total_trips,
82+
f"Expected total_trips to be {expected_total_trips}, got {profile['total_trips']}")
83+
self.assertEqual(profile["labeled_trips"], expected_labeled_trips,
84+
f"Expected labeled_trips to be {expected_labeled_trips}, got {profile['labeled_trips']}")
85+
86+
# Verify pipeline range
87+
pipeline_range = profile.get("pipeline_range", {})
88+
self.assertIn("start_ts", pipeline_range, "Pipeline range should contain 'start_ts'.")
89+
self.assertIn("end_ts", pipeline_range, "Pipeline range should contain 'end_ts'.")
90+
91+
expected_start_ts = 1440168891.095
92+
expected_end_ts = 1440209488.817
93+
94+
self.assertEqual(pipeline_range["start_ts"], expected_start_ts,
95+
f"Expected start_ts to be {expected_start_ts}, got {pipeline_range['start_ts']}")
96+
self.assertEqual(pipeline_range["end_ts"], expected_end_ts,
97+
f"Expected end_ts to be {expected_end_ts}, got {pipeline_range['end_ts']}")
98+
99+
def testLastCall(self):
100+
# Call the function with all required arguments
101+
test_call_ts = time.time()
102+
enac.store_server_api_time(self.testUUID, "test_call_ts", test_call_ts, 69420)
103+
etc.runIntakePipeline(self.testUUID)
104+
105+
# Retrieve the profile from the database
106+
profile = edb.get_profile_db().find_one({"user_id": self.testUUID})
107+
108+
# Verify that last_call_ts is updated correctly
109+
expected_last_call_ts = test_call_ts
110+
actual_last_call_ts = profile.get("last_call_ts")
111+
112+
self.assertEqual(
113+
actual_last_call_ts,
114+
expected_last_call_ts,
115+
f"Expected last_call_ts to be {expected_last_call_ts}, got {actual_last_call_ts}"
116+
)
117+
118+
if __name__ == '__main__':
119+
# Configure logging for the test
120+
etc.configLogging()
121+
unittest.main()

emission/tests/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def getRealExampleEmail(testObj):
107107
def fillExistingUUID(testObj):
108108
userObj = ecwu.User.fromEmail(getRealExampleEmail(testObj))
109109
print("Setting testUUID to %s" % userObj.uuid)
110-
testObj.testUUID = userObj.uuir
110+
testObj.testUUID = userObj.uuid
111111

112112
def getRegEmailIfPresent(testObj):
113113
if hasattr(testObj, "evaluation") and testObj.evaluation:
@@ -193,6 +193,7 @@ def runIntakePipeline(uuid):
193193
import emission.analysis.userinput.expectations as eaue
194194
import emission.analysis.classification.inference.labels.pipeline as eacilp
195195
import emission.analysis.plotting.composite_trip_creation as eapcc
196+
import emission.analysis.result.user_stat as eaurs
196197

197198
eaum.match_incoming_user_inputs(uuid)
198199
eaicf.filter_accuracy(uuid)
@@ -205,6 +206,8 @@ def runIntakePipeline(uuid):
205206
eaue.populate_expectations(uuid)
206207
eaum.create_confirmed_objects(uuid)
207208
eapcc.create_composite_objects(uuid)
209+
eaurs.get_and_store_user_stats(uuid, "analysis/composite_trip")
210+
208211

209212
def configLogging():
210213
"""

0 commit comments

Comments
 (0)