|
2 | 2 | import unittest |
3 | 3 | from datetime import datetime |
4 | 4 | from uuid import uuid4 |
| 5 | +from posthog.scopes import get_context_session_id, set_context_session, new_context |
5 | 6 |
|
6 | 7 | import mock |
7 | 8 | import six |
@@ -939,6 +940,255 @@ def test_advanced_page(self): |
939 | 940 | self.assertEqual(msg["uuid"], "new-uuid") |
940 | 941 | self.assertEqual(msg["distinct_id"], "distinct_id") |
941 | 942 |
|
| 943 | + @parameterized.expand( |
| 944 | + [ |
| 945 | + # test_name, session_id, additional_properties, expected_properties |
| 946 | + ("basic_session_id", "test-session-123", {}, {}), |
| 947 | + ( |
| 948 | + "session_id_with_other_properties", |
| 949 | + "test-session-456", |
| 950 | + { |
| 951 | + "custom_prop": "custom_value", |
| 952 | + "$process_person_profile": False, |
| 953 | + "$current_url": "https://example.com", |
| 954 | + }, |
| 955 | + { |
| 956 | + "custom_prop": "custom_value", |
| 957 | + "$process_person_profile": False, |
| 958 | + "$current_url": "https://example.com", |
| 959 | + }, |
| 960 | + ), |
| 961 | + ("session_id_uuid_format", str(uuid4()), {}, {}), |
| 962 | + ("session_id_numeric_string", "1234567890", {}, {}), |
| 963 | + ("session_id_empty_string", "", {}, {}), |
| 964 | + ("session_id_with_special_chars", "session-123_test.id", {}, {}), |
| 965 | + ] |
| 966 | + ) |
| 967 | + def test_capture_with_session_id_variations( |
| 968 | + self, test_name, session_id, additional_properties, expected_properties |
| 969 | + ): |
| 970 | + client = self.client |
| 971 | + |
| 972 | + properties = {"$session_id": session_id, **additional_properties} |
| 973 | + success, msg = client.capture( |
| 974 | + "distinct_id", "python test event", properties=properties |
| 975 | + ) |
| 976 | + client.flush() |
| 977 | + |
| 978 | + self.assertTrue(success) |
| 979 | + self.assertFalse(self.failed) |
| 980 | + self.assertEqual(msg["event"], "python test event") |
| 981 | + self.assertEqual(msg["distinct_id"], "distinct_id") |
| 982 | + self.assertEqual(msg["properties"]["$session_id"], session_id) |
| 983 | + self.assertEqual(msg["properties"]["$lib"], "posthog-python") |
| 984 | + self.assertEqual(msg["properties"]["$lib_version"], VERSION) |
| 985 | + |
| 986 | + # Check additional expected properties |
| 987 | + for key, value in expected_properties.items(): |
| 988 | + self.assertEqual(msg["properties"][key], value) |
| 989 | + |
| 990 | + def test_session_id_preserved_with_groups(self): |
| 991 | + client = self.client |
| 992 | + session_id = "group-session-101" |
| 993 | + |
| 994 | + success, msg = client.capture( |
| 995 | + "distinct_id", |
| 996 | + "test_event", |
| 997 | + properties={"$session_id": session_id}, |
| 998 | + groups={"company": "id:5", "instance": "app.posthog.com"}, |
| 999 | + ) |
| 1000 | + client.flush() |
| 1001 | + |
| 1002 | + self.assertTrue(success) |
| 1003 | + self.assertEqual(msg["properties"]["$session_id"], session_id) |
| 1004 | + self.assertEqual( |
| 1005 | + msg["properties"]["$groups"], |
| 1006 | + {"company": "id:5", "instance": "app.posthog.com"}, |
| 1007 | + ) |
| 1008 | + |
| 1009 | + def test_session_id_with_anonymous_event(self): |
| 1010 | + client = self.client |
| 1011 | + session_id = "anonymous-session-202" |
| 1012 | + |
| 1013 | + success, msg = client.capture( |
| 1014 | + "distinct_id", |
| 1015 | + "anonymous_event", |
| 1016 | + properties={"$session_id": session_id, "$process_person_profile": False}, |
| 1017 | + ) |
| 1018 | + client.flush() |
| 1019 | + |
| 1020 | + self.assertTrue(success) |
| 1021 | + self.assertEqual(msg["properties"]["$session_id"], session_id) |
| 1022 | + self.assertEqual(msg["properties"]["$process_person_profile"], False) |
| 1023 | + |
| 1024 | + def test_page_with_session_id(self): |
| 1025 | + client = self.client |
| 1026 | + session_id = "page-session-303" |
| 1027 | + |
| 1028 | + success, msg = client.page( |
| 1029 | + "distinct_id", |
| 1030 | + "https://posthog.com/contact", |
| 1031 | + properties={"$session_id": session_id, "page_type": "contact"}, |
| 1032 | + ) |
| 1033 | + client.flush() |
| 1034 | + |
| 1035 | + self.assertTrue(success) |
| 1036 | + self.assertFalse(self.failed) |
| 1037 | + self.assertEqual(msg["event"], "$pageview") |
| 1038 | + self.assertEqual(msg["distinct_id"], "distinct_id") |
| 1039 | + self.assertEqual(msg["properties"]["$session_id"], session_id) |
| 1040 | + self.assertEqual( |
| 1041 | + msg["properties"]["$current_url"], "https://posthog.com/contact" |
| 1042 | + ) |
| 1043 | + self.assertEqual(msg["properties"]["page_type"], "contact") |
| 1044 | + |
| 1045 | + @parameterized.expand( |
| 1046 | + [ |
| 1047 | + # test_name, event_name, session_id, additional_properties, expected_additional_properties |
| 1048 | + ( |
| 1049 | + "screen_event", |
| 1050 | + "$screen", |
| 1051 | + "special-session-505", |
| 1052 | + {"$screen_name": "HomeScreen"}, |
| 1053 | + {"$screen_name": "HomeScreen"}, |
| 1054 | + ), |
| 1055 | + ( |
| 1056 | + "survey_event", |
| 1057 | + "survey sent", |
| 1058 | + "survey-session-606", |
| 1059 | + { |
| 1060 | + "$survey_id": "survey_123", |
| 1061 | + "$survey_questions": [ |
| 1062 | + {"id": "q1", "question": "How likely are you to recommend us?"} |
| 1063 | + ], |
| 1064 | + }, |
| 1065 | + {"$survey_id": "survey_123"}, |
| 1066 | + ), |
| 1067 | + ( |
| 1068 | + "complex_properties_event", |
| 1069 | + "complex_event", |
| 1070 | + "mixed-session-707", |
| 1071 | + { |
| 1072 | + "$current_url": "https://example.com/page", |
| 1073 | + "$process_person_profile": True, |
| 1074 | + "custom_property": "custom_value", |
| 1075 | + "numeric_property": 42, |
| 1076 | + "boolean_property": True, |
| 1077 | + }, |
| 1078 | + { |
| 1079 | + "$current_url": "https://example.com/page", |
| 1080 | + "$process_person_profile": True, |
| 1081 | + "custom_property": "custom_value", |
| 1082 | + "numeric_property": 42, |
| 1083 | + "boolean_property": True, |
| 1084 | + }, |
| 1085 | + ), |
| 1086 | + ( |
| 1087 | + "csp_violation", |
| 1088 | + "$csp_violation", |
| 1089 | + "csp-session-789", |
| 1090 | + { |
| 1091 | + "$csp_version": "1.0", |
| 1092 | + "$current_url": "https://example.com/page", |
| 1093 | + "$process_person_profile": False, |
| 1094 | + "$raw_user_agent": "Mozilla/5.0 Test Agent", |
| 1095 | + "$csp_document_url": "https://example.com/page", |
| 1096 | + "$csp_blocked_url": "https://malicious.com/script.js", |
| 1097 | + "$csp_violated_directive": "script-src", |
| 1098 | + }, |
| 1099 | + { |
| 1100 | + "$csp_version": "1.0", |
| 1101 | + "$current_url": "https://example.com/page", |
| 1102 | + "$process_person_profile": False, |
| 1103 | + "$raw_user_agent": "Mozilla/5.0 Test Agent", |
| 1104 | + "$csp_document_url": "https://example.com/page", |
| 1105 | + "$csp_blocked_url": "https://malicious.com/script.js", |
| 1106 | + "$csp_violated_directive": "script-src", |
| 1107 | + }, |
| 1108 | + ), |
| 1109 | + ] |
| 1110 | + ) |
| 1111 | + def test_session_id_with_different_event_types( |
| 1112 | + self, |
| 1113 | + test_name, |
| 1114 | + event_name, |
| 1115 | + session_id, |
| 1116 | + additional_properties, |
| 1117 | + expected_additional_properties, |
| 1118 | + ): |
| 1119 | + client = self.client |
| 1120 | + |
| 1121 | + properties = {"$session_id": session_id, **additional_properties} |
| 1122 | + success, msg = client.capture("distinct_id", event_name, properties=properties) |
| 1123 | + client.flush() |
| 1124 | + |
| 1125 | + self.assertTrue(success) |
| 1126 | + self.assertEqual(msg["event"], event_name) |
| 1127 | + self.assertEqual(msg["properties"]["$session_id"], session_id) |
| 1128 | + |
| 1129 | + # Check additional expected properties |
| 1130 | + for key, value in expected_additional_properties.items(): |
| 1131 | + self.assertEqual(msg["properties"][key], value) |
| 1132 | + |
| 1133 | + # Verify system properties are still added |
| 1134 | + self.assertEqual(msg["properties"]["$lib"], "posthog-python") |
| 1135 | + self.assertEqual(msg["properties"]["$lib_version"], VERSION) |
| 1136 | + |
| 1137 | + @parameterized.expand( |
| 1138 | + [ |
| 1139 | + # test_name, super_properties, event_session_id, expected_session_id, expected_super_props |
| 1140 | + ( |
| 1141 | + "super_properties_override_session_id", |
| 1142 | + {"$session_id": "super-session", "source": "test"}, |
| 1143 | + "event-session-808", |
| 1144 | + "super-session", |
| 1145 | + {"source": "test"}, |
| 1146 | + ), |
| 1147 | + ( |
| 1148 | + "no_super_properties_conflict", |
| 1149 | + {"source": "test", "version": "1.0"}, |
| 1150 | + "event-session-909", |
| 1151 | + "event-session-909", |
| 1152 | + {"source": "test", "version": "1.0"}, |
| 1153 | + ), |
| 1154 | + ( |
| 1155 | + "empty_super_properties", |
| 1156 | + {}, |
| 1157 | + "event-session-111", |
| 1158 | + "event-session-111", |
| 1159 | + {}, |
| 1160 | + ), |
| 1161 | + ( |
| 1162 | + "super_properties_with_other_dollar_props", |
| 1163 | + {"$current_url": "https://super.com", "source": "test"}, |
| 1164 | + "event-session-222", |
| 1165 | + "event-session-222", |
| 1166 | + {"$current_url": "https://super.com", "source": "test"}, |
| 1167 | + ), |
| 1168 | + ] |
| 1169 | + ) |
| 1170 | + def test_session_id_with_super_properties_variations( |
| 1171 | + self, |
| 1172 | + test_name, |
| 1173 | + super_properties, |
| 1174 | + event_session_id, |
| 1175 | + expected_session_id, |
| 1176 | + expected_super_props, |
| 1177 | + ): |
| 1178 | + client = Client(FAKE_TEST_API_KEY, super_properties=super_properties) |
| 1179 | + |
| 1180 | + success, msg = client.capture( |
| 1181 | + "distinct_id", "test_event", properties={"$session_id": event_session_id} |
| 1182 | + ) |
| 1183 | + client.flush() |
| 1184 | + |
| 1185 | + self.assertTrue(success) |
| 1186 | + self.assertEqual(msg["properties"]["$session_id"], expected_session_id) |
| 1187 | + |
| 1188 | + # Check expected super properties are present |
| 1189 | + for key, value in expected_super_props.items(): |
| 1190 | + self.assertEqual(msg["properties"][key], value) |
| 1191 | + |
942 | 1192 | def test_flush(self): |
943 | 1193 | client = self.client |
944 | 1194 | # set up the consumer with more requests than a single batch will allow |
@@ -1397,3 +1647,75 @@ def test_get_decide_returns_normalized_decide_response(self, patch_flags): |
1397 | 1647 | "errorsWhileComputingFlags": False, |
1398 | 1648 | "requestId": "test-id", |
1399 | 1649 | } |
| 1650 | + |
| 1651 | + def test_set_context_session_with_capture(self): |
| 1652 | + with new_context(): |
| 1653 | + set_context_session("context-session-123") |
| 1654 | + |
| 1655 | + success, msg = self.client.capture( |
| 1656 | + "distinct_id", "test_event", {"custom_prop": "value"} |
| 1657 | + ) |
| 1658 | + self.client.flush() |
| 1659 | + |
| 1660 | + self.assertTrue(success) |
| 1661 | + self.assertEqual(msg["properties"]["$session_id"], "context-session-123") |
| 1662 | + |
| 1663 | + def test_set_context_session_with_page(self): |
| 1664 | + with new_context(): |
| 1665 | + set_context_session("page-context-session-456") |
| 1666 | + |
| 1667 | + success, msg = self.client.page("distinct_id", "https://example.com/page") |
| 1668 | + self.client.flush() |
| 1669 | + |
| 1670 | + self.assertTrue(success) |
| 1671 | + self.assertEqual( |
| 1672 | + msg["properties"]["$session_id"], "page-context-session-456" |
| 1673 | + ) |
| 1674 | + |
| 1675 | + def test_set_context_session_with_page_explicit_properties(self): |
| 1676 | + with new_context(): |
| 1677 | + set_context_session("page-explicit-session-789") |
| 1678 | + |
| 1679 | + properties = { |
| 1680 | + "$session_id": get_context_session_id(), |
| 1681 | + "page_type": "landing", |
| 1682 | + } |
| 1683 | + success, msg = self.client.page( |
| 1684 | + "distinct_id", "https://example.com/landing", properties |
| 1685 | + ) |
| 1686 | + self.client.flush() |
| 1687 | + |
| 1688 | + self.assertTrue(success) |
| 1689 | + self.assertEqual( |
| 1690 | + msg["properties"]["$session_id"], "page-explicit-session-789" |
| 1691 | + ) |
| 1692 | + |
| 1693 | + def test_set_context_session_override_in_capture(self): |
| 1694 | + """Test that explicit session ID overrides context session ID in capture""" |
| 1695 | + from posthog.scopes import set_context_session, new_context |
| 1696 | + |
| 1697 | + with new_context(): |
| 1698 | + set_context_session("context-session-override") |
| 1699 | + |
| 1700 | + success, msg = self.client.capture( |
| 1701 | + "distinct_id", |
| 1702 | + "test_event", |
| 1703 | + {"$session_id": "explicit-session-override", "custom_prop": "value"}, |
| 1704 | + ) |
| 1705 | + self.client.flush() |
| 1706 | + |
| 1707 | + self.assertTrue(success) |
| 1708 | + self.assertEqual( |
| 1709 | + msg["properties"]["$session_id"], "explicit-session-override" |
| 1710 | + ) |
| 1711 | + |
| 1712 | + def test_set_context_session_with_identify(self): |
| 1713 | + with new_context(capture_exceptions=False): |
| 1714 | + set_context_session("identify-session-555") |
| 1715 | + |
| 1716 | + success, msg = self.client.identify("distinct_id", {"trait": "value"}) |
| 1717 | + self.client.flush() |
| 1718 | + |
| 1719 | + self.assertTrue(success) |
| 1720 | + # In identify, the session ID is added to the $set payload |
| 1721 | + self.assertEqual(msg["$set"]["$session_id"], "identify-session-555") |
0 commit comments