Skip to content

Commit

Permalink
Fix more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robbie-c committed Jun 19, 2024
1 parent e787fae commit 0621875
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 22 deletions.
25 changes: 25 additions & 0 deletions posthog/hogql/database/schema/test/test_sessions_v1.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import pytest
from parameterized import parameterized

from posthog.hogql import ast
from posthog.hogql.database.schema.sessions_v1 import get_lazy_session_table_properties
from posthog.hogql.parser import parse_select
from posthog.hogql.query import execute_hogql_query
from posthog.models.property_definition import PropertyType
from posthog.models.utils import uuid7
from posthog.schema import HogQLQueryModifiers, BounceRatePageViewMode, SessionTableVersion
from posthog.test.base import (
APIBaseTest,
Expand Down Expand Up @@ -45,6 +47,29 @@ def test_select_star(self):
1,
)

@pytest.mark.skip(reason="doesn't work, let's fix in V2")
def test_select_event_sessions_star(self):
session_id = str(uuid7())

_create_event(
event="$pageview",
team=self.team,
distinct_id="d1",
properties={"$current_url": "https://example.com", "$session_id": session_id},
)

response = self.__execute(
parse_select(
"select session.* from events where session_id = {session_id}",
placeholders={"session_id": ast.Constant(value=session_id)},
),
)

self.assertEqual(
len(response.results or []),
1,
)

def test_channel_type(self):
session_id = "session_test_channel_type"

Expand Down
3 changes: 3 additions & 0 deletions posthog/hogql/database/schema/test/test_sessions_v2.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from time import time_ns

import pytest

from posthog.hogql import ast
from posthog.hogql.database.schema.sessions_v2 import get_lazy_session_table_properties
from posthog.hogql.parser import parse_select
Expand Down Expand Up @@ -41,6 +43,7 @@ def test_select_star(self):
1,
)

@pytest.mark.skip(reason="doesn't work, didn't in V1 either so not a regression but should still be fixed")
def test_select_event_sessions_star(self):
session_id = str(uuid7())

Expand Down
70 changes: 53 additions & 17 deletions posthog/hogql_queries/web_analytics/test/test_web_overview.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from typing import Optional
from unittest.mock import MagicMock, patch

from freezegun import freeze_time
from parameterized import parameterized

from posthog.clickhouse.client.execute import sync_execute
from posthog.hogql.constants import LimitContext
from posthog.hogql_queries.web_analytics.web_overview import WebOverviewQueryRunner
from posthog.schema import WebOverviewQuery, DateRange
from posthog.models.utils import uuid7
from posthog.schema import WebOverviewQuery, DateRange, SessionTableVersion, HogQLQueryModifiers
from posthog.settings import HOGQL_INCREASED_MAX_EXECUTION_TIME
from posthog.test.base import (
APIBaseTest,
Expand Down Expand Up @@ -44,34 +47,47 @@ def _run_web_overview_query(
self,
date_from: str,
date_to: str,
use_sessions_table: bool = False,
session_table_version: SessionTableVersion = SessionTableVersion.V1,
compare: bool = True,
limit_context: Optional[LimitContext] = None,
):
modifiers = HogQLQueryModifiers(sessionTableVersion=session_table_version)
query = WebOverviewQuery(
dateRange=DateRange(date_from=date_from, date_to=date_to),
properties=[],
compare=compare,
modifiers=modifiers,
)
runner = WebOverviewQueryRunner(team=self.team, query=query, limit_context=limit_context)
return runner.calculate()

def test_no_crash_when_no_data(self):
@parameterized.expand([[SessionTableVersion.V1], [SessionTableVersion.V2]])
def test_no_crash_when_no_data(self, session_table_version: SessionTableVersion):
results = self._run_web_overview_query(
"2023-12-08",
"2023-12-15",
session_table_version=session_table_version,
).results
self.assertEqual(5, len(results))

def test_increase_in_users(self):
@parameterized.expand([[SessionTableVersion.V1], [SessionTableVersion.V2]])
def test_increase_in_users(self, session_table_version: SessionTableVersion):
s1a = str(uuid7("2023-12-02"))
s1b = str(uuid7("2023-12-12"))
s2 = str(uuid7("2023-12-11"))

self._create_events(
[
("p1", [("2023-12-02", "s1a"), ("2023-12-03", "s1a"), ("2023-12-12", "s1b")]),
("p2", [("2023-12-11", "s2")]),
("p1", [("2023-12-02", s1a), ("2023-12-03", s1a), ("2023-12-12", s1b)]),
("p2", [("2023-12-11", s2)]),
]
)

results = self._run_web_overview_query("2023-12-08", "2023-12-15").results
results = self._run_web_overview_query(
"2023-12-08",
"2023-12-15",
session_table_version=session_table_version,
).results

visitors = results[0]
self.assertEqual("visitors", visitors.key)
Expand Down Expand Up @@ -103,15 +119,24 @@ def test_increase_in_users(self):
self.assertEqual(0, bounce.previous)
self.assertEqual(None, bounce.changeFromPreviousPct)

def test_all_time(self):
@parameterized.expand([[SessionTableVersion.V1], [SessionTableVersion.V2]])
def test_all_time(self, session_table_version: SessionTableVersion):
s1a = str(uuid7("2023-12-02"))
s1b = str(uuid7("2023-12-12"))
s2 = str(uuid7("2023-12-11"))
self._create_events(
[
("p1", [("2023-12-02", "s1a"), ("2023-12-03", "s1a"), ("2023-12-12", "s1b")]),
("p2", [("2023-12-11", "s2")]),
("p1", [("2023-12-02", s1a), ("2023-12-03", s1a), ("2023-12-12", s1b)]),
("p2", [("2023-12-11", s2)]),
]
)

results = self._run_web_overview_query("all", "2023-12-15", compare=False).results
results = self._run_web_overview_query(
"all",
"2023-12-15",
compare=False,
session_table_version=session_table_version,
).results

visitors = results[0]
self.assertEqual("visitors", visitors.key)
Expand Down Expand Up @@ -143,11 +168,16 @@ def test_all_time(self):
self.assertEqual(None, bounce.previous)
self.assertEqual(None, bounce.changeFromPreviousPct)

def test_filter_test_accounts(self):
@parameterized.expand([[SessionTableVersion.V1], [SessionTableVersion.V2]])
def test_filter_test_accounts(self, session_table_version: SessionTableVersion):
# Create 1 test account
self._create_events([("test", [("2023-12-02", "s1"), ("2023-12-03", "s1")])])

results = self._run_web_overview_query("2023-12-01", "2023-12-03").results
results = self._run_web_overview_query(
"2023-12-01",
"2023-12-03",
session_table_version=session_table_version,
).results

visitors = results[0]
self.assertEqual(0, visitors.value)
Expand All @@ -165,15 +195,21 @@ def test_filter_test_accounts(self):
self.assertEqual("bounce rate", bounce.key)
self.assertEqual(None, bounce.value)

def test_correctly_counts_pageviews_in_long_running_session(self):
# this test is important when using the sessions table as the raw sessions table will have 3 entries, one per day
@parameterized.expand([[SessionTableVersion.V1], [SessionTableVersion.V2]])
def test_correctly_counts_pageviews_in_long_running_session(self, session_table_version: SessionTableVersion):
# this test is important when using the v1 sessions table as the raw sessions table will have 3 entries, one per day
s1 = str(uuid7("2023-12-01"))
self._create_events(
[
("p1", [("2023-12-01", "s1"), ("2023-12-02", "s1"), ("2023-12-03", "s1")]),
("p1", [("2023-12-01", s1), ("2023-12-02", s1), ("2023-12-03", s1)]),
]
)

results = self._run_web_overview_query("2023-12-01", "2023-12-03").results
results = self._run_web_overview_query(
"2023-12-01",
"2023-12-03",
session_table_version=session_table_version,
).results

visitors = results[0]
self.assertEqual(1, visitors.value)
Expand Down
15 changes: 15 additions & 0 deletions posthog/models/test/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
from random import Random
from uuid import UUID

from posthog.models.utils import uuid7
from posthog.test.base import BaseTest


class TestUUIDv7(BaseTest):
def test_has_version_of_7(self):
self.assertEqual(uuid7().version, 7)

def test_can_be_deterministic(self):
time_component = 1718800371653
pnrg = Random(42)
uuid = uuid7(unix_ms_time=time_component, seeded_random=pnrg)
self.assertEqual(uuid, UUID("0190307c-4fc5-7a3b-8006-671a1c80317f"))

def test_can_parse_date_string(self):
time_component = "2024-06-19T13:33:37"
pnrg = Random(42)
uuid = uuid7(unix_ms_time=time_component, seeded_random=pnrg)
self.assertEqual(uuid, UUID("019030b3-ef68-7a3b-8006-671a1c80317f"))
24 changes: 19 additions & 5 deletions posthog/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
from collections import defaultdict, namedtuple
from contextlib import contextmanager
from time import time, time_ns
from typing import TYPE_CHECKING, Any, Optional, TypeVar
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
from collections.abc import Callable, Iterator
from django.db import IntegrityError, connections, models, transaction
from django.db.backends.utils import CursorWrapper
from django.db.backends.ddl_references import Statement
from django.db.models.constraints import BaseConstraint
from django.utils.text import slugify

from posthog import datetime
from posthog.constants import MAX_SLUG_LENGTH

if TYPE_CHECKING:
Expand Down Expand Up @@ -95,19 +96,32 @@ def is_valid_uuid(cls, candidate: Any) -> bool:


# Delete this when we can use the version from the stdlib directly, see https://github.com/python/cpython/issues/102461
def uuid7(unix_ms_time: Optional[int] = None, seeded_random: Optional["Random"] = None) -> uuid.UUID:
if unix_ms_time is None:
unix_ms_time = time_ns() // (10**6)
def uuid7(unix_ms_time: Optional[Union[int, str]] = None, seeded_random: Optional["Random"] = None) -> uuid.UUID:
# timestamp part
unix_ms_time_int: int
if isinstance(unix_ms_time, str):
date = datetime.datetime.fromisoformat(unix_ms_time)
unix_ms_time_int = int(date.timestamp() * 1000)
elif unix_ms_time is None:
unix_ms_time_int = time_ns() // (10**6)
else:
unix_ms_time_int = unix_ms_time

# random part
if seeded_random is not None:
rand_a = seeded_random.getrandbits(12)
rand_b = seeded_random.getrandbits(56)
else:
rand_bytes = int.from_bytes(secrets.token_bytes(10), byteorder="little")
rand_a = rand_bytes & 0x0FFF
rand_b = (rand_bytes >> 12) & 0x03FFFFFFFFFFFFFFF

# fixed constants
ver = 7
var = 0b10
uuid_int = (unix_ms_time & 0x0FFFFFFFFFFFF) << 80

# construct the UUID int
uuid_int = (unix_ms_time_int & 0x0FFFFFFFFFFFF) << 80
uuid_int |= ver << 76
uuid_int |= rand_a << 64
uuid_int |= var << 62
Expand Down

0 comments on commit 0621875

Please sign in to comment.