diff --git a/samcli/lib/telemetry/event.py b/samcli/lib/telemetry/event.py index 450eef6666..60635172a3 100644 --- a/samcli/lib/telemetry/event.py +++ b/samcli/lib/telemetry/event.py @@ -34,7 +34,7 @@ class EventType: @staticmethod def get_accepted_values(event_name: EventName) -> List[str]: - """Get all acceptable values for a given Event.""" + """Get all acceptable values for a given Event name.""" if event_name not in EventType._events: return [] return EventType._events[event_name] @@ -54,6 +54,12 @@ def __init__(self, event_name: str, event_value: str): def __eq__(self, other): return self.event_name == other.event_name and self.event_value == other.event_value + def __repr__(self): + return f"Event(event_name={self.event_name.value}, event_value={self.event_value})" + + def to_json(self): + return {"event_name": self.event_name.value, "event_value": self.event_value} + @staticmethod def _verify_event(event_name: str, event_value: str) -> None: """Raise an EventCreationError if either the event name or value is not valid.""" @@ -68,5 +74,50 @@ def _get_event_names() -> List[str]: return [event.value for event in EventName] +class EventTracker: + """Class to track and recreate Events as they occur.""" + + _events: List[Event] = [] + + @staticmethod + def track_event(event_name: str, event_value: str): + """Method to track an event where and when it occurs. + + Place this method in the codepath of the event that you would + like to track. For instance, if you would like to track when + FeatureX is used, append this method to the end of that function. + + Parameters + ---------- + event_name: str + The name of the Event. Must be a valid EventName value, or an + EventCreationError will be thrown. + event_value: str + The value of the Event. Must be a valid EventType value for the + passed event_name, or an EventCreationError will be thrown. + + Examples + -------- + >>> def feature_x(...): + # do things + EventTracker.track_event("UsedFeature", "FeatureX") + + >>> def feature_y(...) -> Any: + # do things + EventTracker.track_event("UsedFeature", "FeatureY") + return some_value + """ + EventTracker._events.append(Event(event_name, event_value)) + + @staticmethod + def get_tracked_events() -> List[Event]: + return EventTracker._events + + @staticmethod + def clear_trackers(): + """Clear the current list of tracked Events before the next session.""" + EventTracker._events = [] + + class EventCreationError(Exception): """Exception called when an Event is not properly created.""" diff --git a/tests/unit/lib/telemetry/test_event.py b/tests/unit/lib/telemetry/test_event.py index 74ca23d7dc..b9d6f58c2f 100644 --- a/tests/unit/lib/telemetry/test_event.py +++ b/tests/unit/lib/telemetry/test_event.py @@ -6,7 +6,7 @@ from unittest import TestCase from unittest.mock import Mock, patch -from samcli.lib.telemetry.event import Event, EventCreationError +from samcli.lib.telemetry.event import Event, EventCreationError, EventTracker class DummyEventName(Enum): @@ -48,3 +48,33 @@ def test_create_event_name_doesnt_exist(self): Event("SomeEventThatDoesn'tExist", "value1") self.assertEqual(e.exception.args[0], "Event 'SomeEventThatDoesn'tExist' does not exist.") + + @patch("samcli.lib.telemetry.event.Event._verify_event") + @patch("samcli.lib.telemetry.event.EventType") + @patch("samcli.lib.telemetry.event.EventName") + def test_event_to_json(self, name_mock, type_mock, verify_mock): + name_mock.return_value = Mock(value="Testing") + type_mock.get_accepted_values.return_value = ["value1"] + verify_mock.return_value = None + + test_event = Event("Testing", "value1") + + self.assertEqual(test_event.to_json(), {"event_name": "Testing", "event_value": "value1"}) + + +class TestEventTracker(TestCase): + @patch("samcli.lib.telemetry.event.Event") + def test_track_event(self, event_mock): + # Test that an event can be tracked + dummy_event = Mock(event_name="Test", event_value="SomeValue") + event_mock.return_value = dummy_event + + EventTracker.track_event("Test", "SomeValue") + + self.assertEqual(len(EventTracker._events), 1) + self.assertEqual(EventTracker._events[0], dummy_event) + + # Test that the Event list will be cleared + EventTracker.clear_trackers() + + self.assertEqual(len(EventTracker._events), 0)