async def test_session_exists_profile_exists_conflict(): # Create Profile for Tracker tracker_profile = Profile.new() await tracker_profile.storage().save() # Create Profile for Session session_profile = Profile.new() await session_profile.storage().save() # Create Session session_id = str(uuid4()) session = Session(id=session_id) session.profile = session_profile await session.storage().save() tracker_payload = TrackerPayload(session=Entity(id=session.id), profile=Entity(id=tracker_profile.id), source=Entity(id="scope")) profile, session = await tracker_payload._get_profile_and_session() assert isinstance(profile, Profile) assert isinstance(session, Session) assert profile.id == session_profile.id # profile id must be form session assert session.id == session_id # Remove await session.storage().delete() await tracker_profile.storage().delete() await session_profile.storage().delete()
def test_value_read(): profile = Profile(id="1") session = Session(id="2") payload = {"a": 3} source = Source(id="3", type="event") context = Context() event = Event(id="event-id", type="type", source=source, context=context, profile=profile, session=session) flow = Flow(id="flow-id", name="flow") dot = DotAccessor(profile, session, payload, event, flow) assert dot['profile@id'] == "1" assert dot['session@id'] == "2" assert dot['payload@a'] == 3 assert dot['flow@id'] == "flow-id" assert dot['event@id'] == "event-id" try: _ = dot['profile@none'] assert False except KeyError: assert True dot['payload@b'] = 2 assert dot['payload@b'] == 2 dot['[email protected]'] = 2 assert dot['[email protected]'] == 2 assert dot.profile['other']['a'] == 2
async def run(self, payload: dict): dot = DotAccessor(self.profile, self.session, payload, self.event, self.flow) for destination, value in self.mapping.items(): if destination in dot: if not isinstance(dot[destination], list): dot[destination] = [dot[destination]] if value not in dot[destination]: dot[destination].append(value) else: dot[destination] = value if not isinstance(dot.profile['traits']['private'], dict): raise ValueError( "Error when appending [email protected] to value `{}`. Private must have key:value pair. " "E.g. `name`: `{}`".format(dot.profile['traits']['private'], dot.profile['traits']['private'])) if not isinstance(dot.profile['traits']['public'], dict): raise ValueError( "Error when appending [email protected] to value `{}`. Public must have key:value pair. " "E.g. `name`: `{}`".format(dot.profile['traits']['public'], dot.profile['traits']['public'])) profile = Profile(**dot.profile) event = Event(**dot.event) session = Session(**dot.session) self.profile.replace(profile) self.session.replace(session) self.event.replace(event) return Result(port="payload", value=payload)
async def run(self, payload): dot = DotAccessor(self.profile, self.session, payload, self.event, self.flow) try: value = dot[self.field] if value is None: value = 0 except KeyError: value = 0 if type(value) != int: raise ValueError("Filed `{}` value is not numeric.".format( self.field)) value += self.increment dot[self.field] = value self.profile.replace(Profile(**dot.profile)) return Result(port="payload", value=payload)
def __init__(self, profile: Profile, session: Session, payload: dict, event: Event, flow: Flow): self.flow = dotty(flow.dict()) self.event = dotty(event.dict()) self.payload = dotty(payload) self.session = dotty(session.dict()) self.profile = dotty(profile.dict())
async def test_session_exists_profile_not_exists(): non_existent_profile_id = str(uuid4()) # Create Session session_id = str(uuid4()) session = Session(id=session_id) await session.storage().save() # Profile does not exist session.profile = Profile(id=non_existent_profile_id) # Session exists and has profile equal to some random profile that do not exists tracker_payload = TrackerPayload(session=Entity(id=session_id), profile=None, source=Entity(id="scope")) profile, session = await tracker_payload._get_profile_and_session() assert isinstance(profile, Profile) assert isinstance(session, Session) assert profile.id != non_existent_profile_id # profile can not be generated from non existent profile_id assert session.id == session_id await session.storage().delete() await profile.storage().delete()
async def test_session_not_exists_profile_exists(): # Session does not exist # Profile exists # Create Profile for Session profile_id = str(uuid4()) profile = Profile(id=profile_id) await profile.storage().save() # Create Session session_id = str(uuid4()) session = Session(id=session_id) session.profile = profile tracker_payload = TrackerPayload(session=Entity(id=session.id), profile=Entity(id=profile.id), source=Entity(id="scope")) profile, session = await tracker_payload._get_profile_and_session() assert isinstance(profile, Profile) assert isinstance(session, Session) assert profile.id == profile_id assert session.id == session_id # Remove await session.storage().delete() await profile.storage().delete()
async def test_save_events(): tracker_payload = TrackerPayload( session=Entity(id="12345"), profile=Profile.new(), source=Entity(id="scope"), events=[ EventPayload(type="click", properties={"btn": [1, 2, 3]}, options={"save": True}), EventPayload(type="click", properties={"btn": [3, 4, 5]}, options={"save": True}) ]) events = tracker_payload.get_events(Session.new(), Profile.new()) result = await events.bulk().save() assert result.saved == 2 # profile id must be form session for id in result.ids: entity = Entity(id=id) await entity.storage("event").delete()
def test_value_exists(): profile = Profile(id="1") session = Session(id="2") payload = {"a": 3} source = Source(id="3", type="event") context = Context() event = Event(id="event-id", type="type", source=source, context=context, profile=profile, session=session) flow = Flow(id="flow-id", name="flow") dot = DotAccessor(profile, session, payload, event, flow) assert 'profile@id' in dot assert 'profile@missing' not in dot
async def run(self, payload: dict): dot = DotAccessor(self.profile, self.session, payload, self.event, self.flow) for value in self.delete: del dot[value] profile = Profile(**dot.profile) self.profile.replace(profile) return Result(port="payload", value=payload)
async def test_session_not_exists_profile_not_exists(): # Create Profile for Session profile_id = str(uuid4()) profile = Profile(id=profile_id) # Create Session session_id = str(uuid4()) session = Session(id=session_id) session.profile = profile tracker_payload = TrackerPayload(session=Entity(id=session.id), profile=Entity(id=profile.id), source=Entity(id="scope")) profile, session = await tracker_payload._get_profile_and_session() assert profile.id != profile_id # Must generate new profile, this may be forged assert session.id == session_id # Remove await session.storage().delete() await profile.storage().delete()
def test_profile_merge(): p1 = Profile( id="1", stats=ProfileStats(views=1, visits=2), traits={ "private": { "a": 1, "b": 2 }, "public": { "a": 1, "b": 2 } }, pii=PII( name="john", surname="doe" ), segments=['segment-1'], consents={"all": "granted"} ) p2 = Profile( id="2", stats=ProfileStats(views=2, visits=4), traits={ "private": { "a": 2, "c": 1 } }, pii=PII( name="jonathan", surname="doe" ) ) p3 = Profile( id="3", traits={ "private": { "a": [3], "c": 1 }, "public": { "a": 1, "b": 3 } }, segments=['segment-2'], consents={"all": "not-granted"} ) profiles = [p1, p2] p = Profiles.merge(profiles, p3) assert p.consents == {'all': 'not-granted'} assert p.traits.private == {'b': 2, 'a': [1, 2, 3], 'c': 1} assert p.traits.public == {'b': [2, 3], 'a': 1} assert set(p.pii.name).intersection({'john', 'jonathan'}) == {'john', 'jonathan'} assert p.pii.surname == 'doe' assert p.mergedWith is None assert p.stats.views == 3 assert p.stats.visits == 6
async def main(): source = NamedEntity(id="mobile-app", name="mobile-app") # Create profile, rule needs it p = Profile.new() await p.storage().save() profile = await p.storage().load() assert p.id == profile.id assert isinstance(profile, Profile) flow_record = FlowRecord(id="1", name="flow-1") await flow_record.storage().save() rule = Rule(id="string", source=source, name="my-rule", event=Type(type="xxx1"), flow=flow_record) await rule.storage().save() saved_rule = await rule.storage().load() assert saved_rule.id == rule.id x = await RulesEngine.load_rules("xxx2") pprint(x) payload = { "id": str(uuid4()), "event_server": Context(), "source": source.dict(), "profile": p.dict(), "context": {}, "session": { "id": "0e6121a5-3ea0-45ed-a9ad-552e1765167f", "event_server": { "page": { "url": "http://localhost:8002/tracker/", "path": "/tracker/", "hash": "", "title": "My title", "referer": { "host": None, "query": None }, "history": { "length": 2 } } }, }, "properties": { "a": "tak" }, "type": "xxx1", "user": { "id": "user-id-2" } } event = Event(**payload) events = Events() events.append(event) events.append(event) session = Session(id="session-id") profile = Profile(id="profile-id") rules_engine = RulesEngine(session, profile, events) flow_result, segmentation_result = await rules_engine.execute(source.id ) # print(stats.to_json()) print(flow_result, segmentation_result) await rule.storage().delete()
"target": "763cbc92-5236-4d30-bff2-a10dbbf8c83f", "targetHandle": "payload", "id": "reactflow__edge-9f95ad82-9d7c-4f61-a439-580ba4c730e3payload-763cbc92-5236-4d30-bff2-a10dbbf8c83fpayload", "type": "default" } ] } converter = FlowGraphConverter(flow) x = converter.convert_to_dag_graph() print(x) dag = DagProcessor(x) exec_dag = dag.make_execution_dag() # print(exec_dag.data) print() print(exec_dag.serialize()) print() # exit() event = Event( id="event-id", source=Entity(id="1"), session=Entity(id="2"), context=Context(), type="xxx" ) session = Session(id="session-id") profile = Profile(id="profile-id") init = exec_dag.init(event, session, profile) asyncio.run(exec_dag.run({}, "flow-1", "event-1"))