mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-25 11:17:50 +01:00
299 lines
10 KiB
Python
299 lines
10 KiB
Python
from datetime import datetime, timedelta
|
|
|
|
from django.utils.timezone import now
|
|
from freezegun.api import freeze_time
|
|
|
|
from posthog.constants import FILTER_TEST_ACCOUNTS, TRENDS_LIFECYCLE
|
|
from posthog.models.filters.filter import Filter
|
|
from posthog.models.group.util import create_group
|
|
from posthog.models.group_type_mapping import GroupTypeMapping
|
|
from posthog.models.person import Person
|
|
from posthog.queries.test.test_lifecycle import TestLifecycleBase
|
|
from posthog.queries.trends.trends import Trends
|
|
from posthog.test.base import (
|
|
also_test_with_materialized_columns,
|
|
snapshot_clickhouse_queries,
|
|
)
|
|
from posthog.test.test_journeys import journeys_for
|
|
|
|
|
|
class TestClickhouseLifecycle(TestLifecycleBase):
|
|
@snapshot_clickhouse_queries
|
|
def test_test_account_filters_with_groups(self):
|
|
self.team.test_account_filters = [{"key": "key", "type": "group", "value": "value", "group_type_index": 0}]
|
|
self.team.save()
|
|
|
|
GroupTypeMapping.objects.create(
|
|
team=self.team, project_id=self.team.project_id, group_type="organization", group_type_index=0
|
|
)
|
|
create_group(
|
|
self.team.pk,
|
|
group_type_index=0,
|
|
group_key="in",
|
|
properties={"key": "value"},
|
|
)
|
|
create_group(
|
|
self.team.pk,
|
|
group_type_index=0,
|
|
group_key="out",
|
|
properties={"key": "othervalue"},
|
|
)
|
|
|
|
with freeze_time("2020-01-11T12:00:00Z"):
|
|
Person.objects.create(distinct_ids=["person1"], team_id=self.team.pk)
|
|
|
|
with freeze_time("2020-01-09T12:00:00Z"):
|
|
Person.objects.create(distinct_ids=["person2"], team_id=self.team.pk)
|
|
|
|
journeys_for(
|
|
{
|
|
"person1": [
|
|
{
|
|
"event": "$pageview",
|
|
"timestamp": datetime(2020, 1, 11, 12),
|
|
"properties": {"$group_0": "out"},
|
|
}
|
|
],
|
|
"person2": [
|
|
{
|
|
"event": "$pageview",
|
|
"timestamp": datetime(2020, 1, 9, 12),
|
|
"properties": {"$group_0": "in"},
|
|
},
|
|
{
|
|
"event": "$pageview",
|
|
"timestamp": datetime(2020, 1, 12, 12),
|
|
"properties": {"$group_0": "in"},
|
|
},
|
|
{
|
|
"event": "$pageview",
|
|
"timestamp": datetime(2020, 1, 15, 12),
|
|
"properties": {"$group_0": "in"},
|
|
},
|
|
],
|
|
},
|
|
self.team,
|
|
)
|
|
result = Trends().run(
|
|
Filter(
|
|
data={
|
|
"date_from": "2020-01-12T00:00:00Z",
|
|
"date_to": "2020-01-19T00:00:00Z",
|
|
"events": [{"id": "$pageview", "type": "events", "order": 0}],
|
|
"shown_as": TRENDS_LIFECYCLE,
|
|
FILTER_TEST_ACCOUNTS: True,
|
|
},
|
|
team=self.team,
|
|
),
|
|
self.team,
|
|
)
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0, -1, 0, 0, -1, 0, 0, 0]},
|
|
{"status": "new", "data": [0, 0, 0, 0, 0, 0, 0, 0]},
|
|
{"status": "resurrecting", "data": [1, 0, 0, 1, 0, 0, 0, 0]},
|
|
{"status": "returning", "data": [0, 0, 0, 0, 0, 0, 0, 0]},
|
|
],
|
|
)
|
|
|
|
@snapshot_clickhouse_queries
|
|
def test_lifecycle_edge_cases(self):
|
|
# This test tests behavior when created_at is different from first matching event and dormant/resurrecting/returning logic
|
|
with freeze_time("2020-01-11T12:00:00Z"):
|
|
Person.objects.create(distinct_ids=["person1"], team_id=self.team.pk)
|
|
|
|
journeys_for(
|
|
{
|
|
"person1": [
|
|
{"event": "$pageview", "timestamp": datetime(2020, 1, 12, 12)},
|
|
{"event": "$pageview", "timestamp": datetime(2020, 1, 13, 12)},
|
|
{"event": "$pageview", "timestamp": datetime(2020, 1, 15, 12)},
|
|
{"event": "$pageview", "timestamp": datetime(2020, 1, 16, 12)},
|
|
]
|
|
},
|
|
self.team,
|
|
)
|
|
|
|
result = Trends().run(
|
|
Filter(
|
|
data={
|
|
"date_from": "2020-01-11T00:00:00Z",
|
|
"date_to": "2020-01-18T00:00:00Z",
|
|
"events": [{"id": "$pageview", "type": "events", "order": 0}],
|
|
"shown_as": TRENDS_LIFECYCLE,
|
|
},
|
|
team=self.team,
|
|
),
|
|
self.team,
|
|
)
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0, 0, 0, -1, 0, 0, -1, 0]},
|
|
{"status": "new", "data": [0, 0, 0, 0, 0, 0, 0, 0]},
|
|
{"status": "resurrecting", "data": [0, 1, 0, 0, 1, 0, 0, 0]},
|
|
{"status": "returning", "data": [0, 0, 1, 0, 0, 1, 0, 0]},
|
|
],
|
|
)
|
|
|
|
@snapshot_clickhouse_queries
|
|
def test_interval_dates_days(self):
|
|
with freeze_time("2021-05-05T12:00:00Z"):
|
|
self._setup_returning_lifecycle_data(20)
|
|
|
|
result = self._run_lifecycle({"date_from": "-7d", "interval": "day"})
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0] * 8},
|
|
{"status": "new", "data": [0] * 8},
|
|
{"status": "resurrecting", "data": [0] * 8},
|
|
{"status": "returning", "data": [1] * 8},
|
|
],
|
|
)
|
|
self.assertEqual(
|
|
result[0]["days"],
|
|
[
|
|
"2021-04-28",
|
|
"2021-04-29",
|
|
"2021-04-30",
|
|
"2021-05-01",
|
|
"2021-05-02",
|
|
"2021-05-03",
|
|
"2021-05-04",
|
|
"2021-05-05",
|
|
],
|
|
)
|
|
|
|
@snapshot_clickhouse_queries
|
|
def test_interval_dates_weeks(self):
|
|
with freeze_time("2021-05-06T12:00:00Z"):
|
|
self._setup_returning_lifecycle_data(50)
|
|
|
|
result = self._run_lifecycle({"date_from": "-30d", "interval": "week"})
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0] * 5},
|
|
{"status": "new", "data": [0] * 5},
|
|
{"status": "resurrecting", "data": [0] * 5},
|
|
{"status": "returning", "data": [1] * 5},
|
|
],
|
|
)
|
|
self.assertEqual(
|
|
result[0]["days"],
|
|
["2021-04-05", "2021-04-12", "2021-04-19", "2021-04-26", "2021-05-03"],
|
|
)
|
|
|
|
@snapshot_clickhouse_queries
|
|
def test_interval_dates_months(self):
|
|
with freeze_time("2021-05-05T12:00:00Z"):
|
|
self._setup_returning_lifecycle_data(120)
|
|
|
|
result = self._run_lifecycle({"date_from": "-90d", "interval": "month"})
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0] * 4},
|
|
{"status": "new", "data": [0] * 4},
|
|
{"status": "resurrecting", "data": [0] * 4},
|
|
{"status": "returning", "data": [1] * 4},
|
|
],
|
|
)
|
|
self.assertEqual(result[0]["days"], ["2021-02-01", "2021-03-01", "2021-04-01", "2021-05-01"])
|
|
|
|
@also_test_with_materialized_columns(event_properties=["$current_url"])
|
|
@snapshot_clickhouse_queries
|
|
def test_lifecycle_hogql_event_properties(self):
|
|
with freeze_time("2021-05-05T12:00:00Z"):
|
|
self._setup_returning_lifecycle_data(20)
|
|
result = self._run_lifecycle(
|
|
{
|
|
"date_from": "-7d",
|
|
"interval": "day",
|
|
"properties": [
|
|
{
|
|
"key": "like(properties.$current_url, '%example%') and 'bla' != 'a%sd'",
|
|
"type": "hogql",
|
|
},
|
|
],
|
|
}
|
|
)
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0] * 8},
|
|
{"status": "new", "data": [0] * 8},
|
|
{"status": "resurrecting", "data": [0] * 8},
|
|
{"status": "returning", "data": [1] * 8},
|
|
],
|
|
)
|
|
|
|
@also_test_with_materialized_columns(event_properties=[], person_properties=["email"])
|
|
@snapshot_clickhouse_queries
|
|
def test_lifecycle_hogql_person_properties(self):
|
|
with freeze_time("2021-05-05T12:00:00Z"):
|
|
self._setup_returning_lifecycle_data(20)
|
|
result = self._run_lifecycle(
|
|
{
|
|
"date_from": "-7d",
|
|
"interval": "day",
|
|
"properties": [
|
|
{
|
|
"key": "like(person.properties.email, '%test.com')",
|
|
"type": "hogql",
|
|
},
|
|
],
|
|
}
|
|
)
|
|
|
|
self.assertLifecycleResults(
|
|
result,
|
|
[
|
|
{"status": "dormant", "data": [0] * 8},
|
|
{"status": "new", "data": [0] * 8},
|
|
{"status": "resurrecting", "data": [0] * 8},
|
|
{"status": "returning", "data": [1] * 8},
|
|
],
|
|
)
|
|
|
|
def _setup_returning_lifecycle_data(self, days):
|
|
with freeze_time("2019-01-01T12:00:00Z"):
|
|
Person.objects.create(
|
|
distinct_ids=["person1"],
|
|
team_id=self.team.pk,
|
|
properties={"email": "person@test.com"},
|
|
)
|
|
|
|
journeys_for(
|
|
{
|
|
"person1": [
|
|
{
|
|
"event": "$pageview",
|
|
"timestamp": (now() - timedelta(days=n)).strftime("%Y-%m-%d %H:%M:%S.%f"),
|
|
"properties": {"$current_url": "http://example.com"},
|
|
}
|
|
for n in range(days)
|
|
]
|
|
},
|
|
self.team,
|
|
create_people=False,
|
|
)
|
|
|
|
def _run_lifecycle(self, data):
|
|
filter = Filter(
|
|
data={
|
|
"events": [{"id": "$pageview", "type": "events", "order": 0}],
|
|
"shown_as": TRENDS_LIFECYCLE,
|
|
**data,
|
|
},
|
|
team=self.team,
|
|
)
|
|
return Trends().run(filter, self.team)
|