def test_can_get_retention_week_interval(self): organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) update_or_create_person(distinct_ids=["person 1"], team_id=team.pk) update_or_create_person(distinct_ids=["person 2"], team_id=team.pk) setup_user_activity_by_day( daily_activity={ "2020-01-01": { "person 1": [{ "event": "target event" }] }, "2020-01-08": { "person 2": [{ "event": "target event" }] }, }, team=team, ) retention = get_retention_ok( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={ "id": "target event", "type": "events" }, returning_entity={ "id": "target event", "type": "events" }, date_from="2020-01-01", total_intervals=2, date_to="2020-01-08", period="Week", retention_type="retention_first_time", ), ) retention_by_cohort_by_period = get_by_cohort_by_period_for_response( client=self.client, response=retention) assert retention_by_cohort_by_period == { "Week 0": { "1": ["person 1"], "2": [], }, "Week 1": { "1": ["person 2"] }, }
def test_can_get_actors_and_use_percent_char_filter(self): """ References https://github.com/PostHog/posthog/issues/7747 Essentially we were performing a double string substitution, which causes issues if, in that case, we use a string substitution that includes a '%' character, and then run substitution again. This was the case for instance when you wanted to filter out test users e.g. by postgres LIKE matching '%posthog.com%' """ organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) response = get_retention_people( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={"id": "target event", "type": "events"}, returning_entity={"id": "target event", "type": "events"}, date_from="2020-01-01", total_intervals=2, date_to="2020-01-08", period="Week", retention_type="retention_first_time", properties=[{"key": "email", "value": "posthog.com", "operator": "not_icontains", "type": "person"}], ), ) assert response.status_code == 200
def test_can_specify_breakdown_person_property(self): """ By default, we group users together by the first time they perform the `target_event`. However, we should also be able to specify, e.g. the users OS to be able to compare retention between the OSs. """ organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) update_or_create_person(distinct_ids=["person 1"], team_id=team.pk, properties={"os": "Chrome"}) update_or_create_person(distinct_ids=["person 2"], team_id=team.pk, properties={"os": "Safari"}) setup_user_activity_by_day( daily_activity={ "2020-01-01": {"person 1": [{"event": "target event"}]}, "2020-01-02": {"person 1": [{"event": "target event"}], "person 2": [{"event": "target event"}]}, # IMPORTANT: we include data past the end of the requested # window, as we want to ensure that we pick up all retention # periods for a user. e.g. for "person 2" we do not want to miss # the count from 2020-01-03 e.g. the second period, otherwise we # will skew results for users that didn't perform their target # event right at the beginning of the requested range. "2020-01-03": {"person 1": [{"event": "target event"}], "person 2": [{"event": "target event"}]}, }, team=team, ) retention = get_retention_ok( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={"id": "target event", "type": "events"}, returning_entity={"id": "target event", "type": "events"}, date_from="2020-01-01", total_intervals=2, date_to="2020-01-02", period="Day", retention_type="retention_first_time", breakdowns=[Breakdown(type="person", property="os")], # NOTE: we need to specify breakdown_type as well, as the # breakdown logic currently does not support multiple differing # types breakdown_type="person", ), ) retention_by_cohort_by_period = get_by_cohort_by_period_for_response(client=self.client, response=retention) assert retention_by_cohort_by_period, { "Chrome": {"1": ["person 1"], "2": ["person 1"]}, "Safari": { "1": ["person 2"], "2": ["person 2"], }, # IMPORTANT: the "2" value is from past the requested `date_to` }
def test_can_specify_breakdown_event_property_and_retrieve_people(self): """ This test is slightly different from the get_by_cohort_by_period_for_response based tests in that here we are checking a cohort/period specific people url that does not include the "appearances" detail. This is used, e.g. for the frontend retentions trend graph """ organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) update_or_create_person(distinct_ids=["person 1"], team_id=team.pk) update_or_create_person(distinct_ids=["person 2"], team_id=team.pk) setup_user_activity_by_day( daily_activity={ "2020-01-01": { "person 1": [{"event": "target event", "properties": {"os": "Chrome"}}], "person 2": [{"event": "target event", "properties": {"os": "Safari"}}], }, "2020-01-02": {"person 1": [{"event": "target event"}], "person 2": [{"event": "target event"}],}, }, team=team, ) retention = get_retention_ok( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={"id": "target event", "type": "events"}, returning_entity={"id": "target event", "type": "events"}, date_from="2020-01-01", total_intervals=2, date_to="2020-01-02", period="Day", retention_type="retention_first_time", breakdowns=[Breakdown(type="event", property="os")], # NOTE: we need to specify breakdown_type as well, as the # breakdown logic currently does not support multiple differing # types breakdown_type="event", ), ) chrome_cohort = [cohort for cohort in retention["result"] if cohort["label"] == "Chrome"][0] people_url = chrome_cohort["values"][0]["people_url"] people_response = self.client.get(people_url) assert people_response.status_code == 200 people = people_response.json()["result"] assert [distinct_id for person in people for distinct_id in person["distinct_ids"]] == ["person 1"]
def test_retention_test_account_filters(self): organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) team.test_account_filters = [ {"key": "email", "type": "person", "value": "posthog.com", "operator": "not_icontains"} ] team.save() update_or_create_person(distinct_ids=["person 1"], team_id=team.pk, properties={"email": "posthog.com"}) update_or_create_person(distinct_ids=["person 2"], team_id=team.pk) update_or_create_person(distinct_ids=["person 3"], team_id=team.pk) setup_user_activity_by_day( daily_activity={ "2020-01-01": {"person 1": [{"event": "target event"}], "person 2": [{"event": "target event"}]}, "2020-01-02": {"person 1": [{"event": "target event"}], "person 3": [{"event": "target event"}]}, "2020-01-03": {"person 1": [{"event": "target event"}], "person 3": [{"event": "target event"}]}, }, team=team, ) retention = get_retention_ok( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={"id": "target event", "type": "events"}, returning_entity={"id": "target event", "type": "events"}, date_from="2020-01-01", total_intervals=2, date_to="2020-01-02", period="Day", retention_type="retention_first_time", filter_test_accounts="true", ), ) retention_by_cohort_by_period = get_by_cohort_by_period_for_response(client=self.client, response=retention) assert retention_by_cohort_by_period == { "Day 0": {"1": ["person 2"], "2": [],}, "Day 1": {"1": ["person 3"]}, }
def setUpTestData(cls): cls.organization = create_organization(name="test org") cls.demo_team = create_team(organization=cls.organization) cls.user = create_user("user", "pass", cls.organization) for event_definition in cls.EXPECTED_EVENT_DEFINITIONS: create_event_definitions(event_definition["name"], team_id=cls.demo_team.pk) for _ in range(event_definition["volume_30_day"]): capture_event(event=EventData( event=event_definition["name"], team_id=cls.demo_team.pk, distinct_id="abc", timestamp=datetime(2020, 1, 1), properties={}, )) # To ensure `volume_30_day` and `query_usage_30_day` are returned non # None, we need to call this task to have them calculated. calculate_event_property_usage_for_team(cls.demo_team.pk)
def test_retention_aggregation_by_distinct_id_and_retrieve_people(self): organization = create_organization(name="test") team = create_team(organization=organization) user = create_user(email="*****@*****.**", password="******", organization=organization) self.client.force_login(user) p1 = update_or_create_person(distinct_ids=["person 1", "another one"], team_id=team.pk) p2 = update_or_create_person(distinct_ids=["person 2"], team_id=team.pk) setup_user_activity_by_day( daily_activity={ "2020-01-01": { "person 1": [{ "event": "target event", }], "another one": [{ "event": "target event", }], }, "2020-01-02": { "person 1": [{ "event": "target event" }], "person 2": [{ "event": "target event" }] }, "2020-01-03": { "another one": [{ "event": "target event" }], }, }, team=team, ) with override_instance_config("AGGREGATE_BY_DISTINCT_IDS_TEAMS", f"{team.pk}"): retention = get_retention_ok( client=self.client, team_id=team.pk, request=RetentionRequest( target_entity={ "id": "target event", "type": "events" }, returning_entity={ "id": "target event", "type": "events" }, date_from="2020-01-01", total_intervals=3, date_to="2020-01-03", period="Day", retention_type="retention_first_time", ), ) assert retention["result"][0]["values"][0][ "count"] == 2 # person 1 and another one assert retention["result"][0]["values"][1]["count"] == 1 # person 1 assert retention["result"][0]["values"][2][ "count"] == 1 # another one # person 2 assert retention["result"][1]["values"][0]["count"] == 1 assert retention["result"][1]["values"][1]["count"] == 0 people_url = retention["result"][0]["values"][0]["people_url"] people_response = self.client.get(people_url) assert people_response.status_code == 200 people = people_response.json()["result"] # person1 and another one are the same person assert len(people) == 1 assert people[0]["id"] == str(p1.uuid) people_url = retention["result"][1]["values"][0]["people_url"] people_response = self.client.get(people_url) assert people_response.status_code == 200 people = people_response.json()["result"] assert len(people) == 1 assert people[0]["id"] == str(p2.uuid)