def test_select(self): recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:")) recorder.create_table() # Construct notification log. notification_log = LocalNotificationLog(recorder, section_size=5) reader = NotificationLogReader(notification_log, section_size=5) notifications = list(reader.select(start=1)) self.assertEqual(len(notifications), 0) # Write 5 events. originator_id = uuid4() for i in range(5): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events( [stored_event], ) notifications = list(reader.select(start=1)) self.assertEqual(len(notifications), 5) # Write 4 events. originator_id = uuid4() for i in range(4): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events([stored_event]) notifications = list(reader.select(start=1)) self.assertEqual(len(notifications), 9) notifications = list(reader.select(start=2)) self.assertEqual(len(notifications), 8) notifications = list(reader.select(start=3)) self.assertEqual(len(notifications), 7) notifications = list(reader.select(start=4)) self.assertEqual(len(notifications), 6) notifications = list(reader.select(start=8)) self.assertEqual(len(notifications), 2) notifications = list(reader.select(start=9)) self.assertEqual(len(notifications), 1) notifications = list(reader.select(start=10)) self.assertEqual(len(notifications), 0)
def insert_events() -> None: thread_id = get_ident() if thread_id not in threads: threads[thread_id] = len(threads) if thread_id not in counts: counts[thread_id] = 0 if thread_id not in durations: durations[thread_id] = 0 originator_id = uuid4() stored_events = [ StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) for i in range(NUM_EVENTS) ] try: recorder.insert_events(stored_events) except Exception: # pragma: nocover errors_happened.set() tb = traceback.format_exc() print(tb) finally: ended = datetime.now() duration = (ended - started).total_seconds() counts[thread_id] += 1 durations[thread_id] = duration
def create_stack(self, originator_id): return [ StoredEvent( originator_id=originator_id, originator_version=i, topic="", state=b"", ) for i in range(self.insert_num) ]
def insert() -> None: originator_id = uuid4() stored_event = StoredEvent( originator_id=originator_id, originator_version=0, topic="topic1", state=b"state1", ) recorder.insert_events([stored_event])
def test_insert_raises_operational_error_if_table_not_created(self): recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:")) stored_event1 = StoredEvent( originator_id=uuid4(), originator_version=1, topic="topic1", state=b"", ) with self.assertRaises(OperationalError): recorder.insert_events([stored_event1])
def select_events( self, originator_id: UUID, gt: Optional[int] = None, lte: Optional[int] = None, desc: bool = False, limit: Optional[int] = None, ) -> List[StoredEvent]: parts = [self.select_events_statement] params: List[Any] = [originator_id] statement_name = f"select_{self.events_table_name}".replace(".", "_") if gt is not None: params.append(gt) parts.append(f"AND originator_version > ${len(params)}") statement_name += "_gt" if lte is not None: params.append(lte) parts.append(f"AND originator_version <= ${len(params)}") statement_name += "_lte" parts.append("ORDER BY originator_version") if desc is False: parts.append("ASC") else: parts.append("DESC") statement_name += "_desc" if limit is not None: params.append(limit) parts.append(f"LIMIT ${len(params)}") statement_name += "_limit" statement = " ".join(parts) stored_events = [] with self.datastore.get_connection() as conn: alias = self._prepare(conn, statement_name, statement) with conn.transaction(commit=False) as curs: curs.execute( f"EXECUTE {alias}({', '.join(['%s' for _ in params])})", params, ) for row in curs.fetchall(): stored_events.append( StoredEvent( originator_id=row["originator_id"], originator_version=row["originator_version"], topic=row["topic"], state=bytes(row["state"]), )) pass # for Coverage 5.5 bug with CPython 3.10.0rc1 return stored_events
def test_insert_events_raises_programming_error_when_table_not_created( self): # Construct the recorder. recorder = self.create_recorder() # Write a stored event without creating the table. stored_event1 = StoredEvent( originator_id=uuid4(), originator_version=0, topic="topic1", state=b"state1", ) with self.assertRaises(ProgrammingError): recorder.insert_events([stored_event1])
def test_insert_events_raises_programming_error_when_sql_is_broken(self): # Construct the recorder. recorder = self.create_recorder() # Create the table. recorder.create_table() # Write a stored event with broken statement. recorder.insert_events_statement = "BLAH" stored_event1 = StoredEvent( originator_id=uuid4(), originator_version=0, topic="topic1", state=b"state1", ) with self.assertRaises(ProgrammingError): recorder.insert_events([stored_event1])
def test_retry_insert_events_after_closing_connection(self): # Construct the recorder. recorder = self.create_recorder() # Check we have a connection (from create_table). self.assertTrue(self.datastore._connections) # Close connections. pg_close_all_connections() # Write a stored event. stored_event1 = StoredEvent( originator_id=uuid4(), originator_version=0, topic="topic1", state=b"state1", ) recorder.insert_events([stored_event1])
def _createevent(): thread_id = get_ident() if thread_id not in threads: threads[thread_id] = len(threads) if thread_id not in counts: counts[thread_id] = 0 if thread_id not in durations: durations[thread_id] = 0 # thread_num = threads[thread_id] # count = counts[thread_id] originator_id = uuid4() stored_events = [ StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) for i in range(100) ] started = datetime.now() # print(f"Thread {thread_num} write beginning #{count + 1}") try: recorder.insert_events(stored_events) except Exception: ended = datetime.now() duration = (ended - started).total_seconds() print(f"Error after starting {duration}") errors_happened.set() tb = traceback.format_exc() print(tb) pass else: return "OK" finally: ended = datetime.now() duration = (ended - started).total_seconds() counts[thread_id] += 1 if duration > durations[thread_id]: durations[thread_id] = duration
def test_raises_operational_error_when_inserting_fails(self): # Construct the recorder. recorder = PostgresAggregateRecorder(datastore=self.datastore, events_table_name="stored_events") recorder.create_table() # Mess up the statement. recorder.insert_events_statement = "BLAH" # Write two stored events. originator_id = uuid4() stored_event1 = StoredEvent( originator_id=originator_id, originator_version=0, topic="topic1", state=b"state1", ) with self.assertRaises(OperationalError): recorder.insert_events([stored_event1])
def insert(): originator_id = uuid4() stored_event = StoredEvent( originator_id=originator_id, originator_version=0, topic="topic1", state=b"state1", ) tracking1 = Tracking( application_name="upstream_app", notification_id=next(notification_ids), ) recorder.insert_events( stored_events=[ stored_event, ], tracking=tracking1, )
def select_events( self, originator_id: UUID, gt: Optional[int] = None, lte: Optional[int] = None, desc: bool = False, limit: Optional[int] = None, ) -> List[StoredEvent]: statement = self.select_events_statement params: List[Any] = [originator_id] if gt is not None: statement += "AND originator_version > %s " params.append(gt) if lte is not None: statement += "AND originator_version <= %s " params.append(lte) statement += "ORDER BY originator_version " if desc is False: statement += "ASC " else: statement += "DESC " if limit is not None: statement += "LIMIT %s " params.append(limit) # statement += ";" stored_events = [] try: with self.datastore.transaction() as c: c.execute(statement, params) for row in c.fetchall(): stored_events.append( StoredEvent( originator_id=row["originator_id"], originator_version=row["originator_version"], topic=row["topic"], state=bytes(row["state"]), ) ) except psycopg2.Error as e: raise OperationalError(e) return stored_events
def insert_events() -> None: thread_id = get_ident() if thread_id not in threads: threads[thread_id] = len(threads) if thread_id not in counts: counts[thread_id] = 0 if thread_id not in durations: durations[thread_id] = 0 # thread_num = threads[thread_id] # count = counts[thread_id] originator_id = uuid4() stored_events = [ StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) for i in range(num_events_per_write) ] started = datetime.now() # print(f"Thread {thread_num} write beginning #{count + 1}") try: recorder.insert_events(stored_events) except Exception as e: # pragma: nocover if errors: return ended = datetime.now() duration = (ended - started).total_seconds() print(f"Error after starting {duration}", e) errors.append(e) else: ended = datetime.now() duration = (ended - started).total_seconds() counts[thread_id] += 1 if duration > durations[thread_id]: durations[thread_id] = duration sleep(writer_sleep)
def select_events( self, originator_id: UUID, gt: Optional[int] = None, lte: Optional[int] = None, desc: bool = False, limit: Optional[int] = None, ) -> List[StoredEvent]: statement = self.select_events_statement params: List[Any] = [originator_id.hex] if gt is not None: statement += "AND originator_version>? " params.append(gt) if lte is not None: statement += "AND originator_version<=? " params.append(lte) statement += "ORDER BY originator_version " if desc is False: statement += "ASC " else: statement += "DESC " if limit is not None: statement += "LIMIT ? " params.append(limit) try: c = self.datastore.get_connection().cursor() c.execute(statement, params) stored_events = [] for row in c.fetchall(): stored_events.append( StoredEvent( originator_id=UUID(row["originator_id"]), originator_version=row["originator_version"], topic=row["topic"], state=row["state"], )) except sqlite3.OperationalError as e: raise OperationalError(e) return stored_events
def select_events( self, originator_id: UUID, gt: Optional[int] = None, lte: Optional[int] = None, desc: bool = False, limit: Optional[int] = None, ) -> List[StoredEvent]: statement = self.select_events_statement params: List[Any] = [originator_id.hex] if gt is not None: statement += "AND originator_version>? " params.append(gt) if lte is not None: statement += "AND originator_version<=? " params.append(lte) statement += "ORDER BY originator_version " if desc is False: statement += "ASC " else: statement += "DESC " if limit is not None: statement += "LIMIT ? " params.append(limit) stored_events = [] with self.datastore.transaction(commit=False) as c: c.execute(statement, params) for row in c.fetchall(): stored_events.append( StoredEvent( originator_id=UUID(row["originator_id"]), originator_version=row["originator_version"], topic=row["topic"], state=row["state"], )) pass # for Coverage 5.5 bug with CPython 3.10.0rc1 return stored_events
def test_retry_max_tracking_id_after_closing_connection(self): # Construct the recorder. recorder = self.create_recorder() # Check we have a connection (from create_table). self.assertTrue(self.datastore._connections) # Write a stored event. originator_id = uuid4() stored_event1 = StoredEvent( originator_id=originator_id, originator_version=0, topic="topic1", state=b"state1", ) recorder.insert_events([stored_event1], tracking=Tracking("upstream", 1)) # Close connections. pg_close_all_connections() # Select events. notification_id = recorder.max_tracking_id("upstream") self.assertEqual(notification_id, 1)
def test_select(self): recorder = SQLiteApplicationRecorder(SQLiteDatastore(":memory:")) recorder.create_table() # Construct notification log. notification_log = LocalNotificationLog(recorder, section_size=10) # Select start 1, limit 10 notifications = notification_log.select(1, 10) self.assertEqual(len(notifications), 0) # Write 5 events. originator_id = uuid4() for i in range(5): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events([stored_event]) # Select start 1, limit 10 notifications = notification_log.select(1, 5) self.assertEqual(len(notifications), 5) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[1].id, 2) self.assertEqual(notifications[2].id, 3) self.assertEqual(notifications[3].id, 4) self.assertEqual(notifications[4].id, 5) # Select start 1, limit 10 notifications = notification_log.select(1, 5) self.assertEqual(len(notifications), 5) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[1].id, 2) self.assertEqual(notifications[2].id, 3) self.assertEqual(notifications[3].id, 4) self.assertEqual(notifications[4].id, 5) # Select start 6, limit 5 notifications = notification_log.select(6, 5) self.assertEqual(len(notifications), 0) # Write 4 events. originator_id = uuid4() for i in range(4): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events([stored_event]) # Select start 6, limit 5 notifications = notification_log.select(6, 5) self.assertEqual(len(notifications), 4) # event notifications self.assertEqual(notifications[0].id, 6) self.assertEqual(notifications[1].id, 7) self.assertEqual(notifications[2].id, 8) self.assertEqual(notifications[3].id, 9) # Select start 3, limit 5 notifications = notification_log.select(3, 5) self.assertEqual(len(notifications), 5) # event notifications self.assertEqual(notifications[0].id, 3) self.assertEqual(notifications[1].id, 4) self.assertEqual(notifications[2].id, 5) self.assertEqual(notifications[3].id, 6) self.assertEqual(notifications[4].id, 7) # Notification log limits limit. # Select start 1, limit 20 with self.assertRaises(ValueError) as cm: notification_log.select(1, 20) self.assertEqual( cm.exception.args[0], "Requested limit 20 greater than section size 10" )
def test_insert_select(self): # Construct the recorder. recorder = self.create_recorder() # Get current position. self.assertEqual( recorder.max_tracking_id("upstream_app"), 0, ) # Write two stored events. originator_id1 = uuid4() originator_id2 = uuid4() stored_event1 = StoredEvent( originator_id=originator_id1, originator_version=1, topic="topic1", state=b"state1", ) stored_event2 = StoredEvent( originator_id=originator_id1, originator_version=2, topic="topic2", state=b"state2", ) stored_event3 = StoredEvent( originator_id=originator_id2, originator_version=1, topic="topic3", state=b"state3", ) stored_event4 = StoredEvent( originator_id=originator_id2, originator_version=2, topic="topic4", state=b"state4", ) tracking1 = Tracking( application_name="upstream_app", notification_id=1, ) tracking2 = Tracking( application_name="upstream_app", notification_id=2, ) # Insert two events with tracking info. recorder.insert_events( stored_events=[ stored_event1, stored_event2, ], tracking=tracking1, ) # Get current position. self.assertEqual( recorder.max_tracking_id("upstream_app"), 1, ) # Check can't insert third event with same tracking info. with self.assertRaises(IntegrityError): recorder.insert_events( stored_events=[stored_event3], tracking=tracking1, ) # Get current position. self.assertEqual( recorder.max_tracking_id("upstream_app"), 1, ) # Insert third event with different tracking info. recorder.insert_events( stored_events=[stored_event3], tracking=tracking2, ) # Get current position. self.assertEqual( recorder.max_tracking_id("upstream_app"), 2, ) # Insert fourth event without tracking info. recorder.insert_events(stored_events=[stored_event4], ) # Get current position. self.assertEqual( recorder.max_tracking_id("upstream_app"), 2, )
def test_insert_and_select(self) -> None: # Construct the recorder. recorder = self.create_recorder() # Check we can call insert_events() with an empty list. notification_ids = recorder.insert_events([]) self.assertEqual(notification_ids, None) # Select stored events, expect empty list. originator_id1 = uuid4() self.assertEqual( recorder.select_events(originator_id1, desc=True, limit=1), [], ) # Write a stored event. stored_event1 = StoredEvent( originator_id=originator_id1, originator_version=0, topic="topic1", state=b"state1", ) notification_ids = recorder.insert_events([stored_event1]) self.assertEqual(notification_ids, None) # Select stored events, expect list of one. stored_events = recorder.select_events(originator_id1) self.assertEqual(len(stored_events), 1) assert stored_events[0].originator_id == originator_id1 assert stored_events[0].originator_version == 0 assert stored_events[0].topic == "topic1" # Check get record conflict error if attempt to store it again. stored_events = recorder.select_events(originator_id1) with self.assertRaises(IntegrityError): recorder.insert_events([stored_event1]) # Check writing of events is atomic. stored_event2 = StoredEvent( originator_id=originator_id1, originator_version=1, topic="topic2", state=b"state2", ) with self.assertRaises(IntegrityError): recorder.insert_events([stored_event1, stored_event2]) with self.assertRaises(IntegrityError): recorder.insert_events([stored_event2, stored_event2]) # Check still only have one record. stored_events = recorder.select_events(originator_id1) self.assertEqual(len(stored_events), 1) assert stored_events[0].originator_id == originator_id1 assert stored_events[0].originator_version == 0 assert stored_events[0].topic == "topic1" # Check can write two events together. stored_event3 = StoredEvent( originator_id=originator_id1, originator_version=2, topic="topic3", state=b"state3", ) notification_ids = recorder.insert_events( [stored_event2, stored_event3]) self.assertEqual(notification_ids, None) # Check we got what was written. stored_events = recorder.select_events(originator_id1) self.assertEqual(len(stored_events), 3) assert stored_events[0].originator_id == originator_id1 assert stored_events[0].originator_version == 0 assert stored_events[0].topic == "topic1" self.assertEqual(stored_events[0].state, b"state1") assert stored_events[1].originator_id == originator_id1 assert stored_events[1].originator_version == 1 assert stored_events[1].topic == "topic2" assert stored_events[1].state == b"state2" assert stored_events[2].originator_id == originator_id1 assert stored_events[2].originator_version == 2 assert stored_events[2].topic == "topic3" assert stored_events[2].state == b"state3" # Check we can get the last one recorded (used to get last snapshot). events = recorder.select_events(originator_id1, desc=True, limit=1) self.assertEqual(len(events), 1) self.assertEqual( events[0], stored_event3, ) # Check we can get the last one before a particular version. events = recorder.select_events(originator_id1, lte=1, desc=True, limit=1) self.assertEqual(len(events), 1) self.assertEqual( events[0], stored_event2, ) # Check we can get events between particular versions. events = recorder.select_events(originator_id1, gt=0, lte=2) self.assertEqual(len(events), 2) self.assertEqual( events[0], stored_event2, ) self.assertEqual( events[1], stored_event3, ) # Check aggregate sequences are distinguished. originator_id2 = uuid4() self.assertEqual( recorder.select_events(originator_id2), [], ) # Write a stored event. stored_event4 = StoredEvent( originator_id=originator_id2, originator_version=0, topic="topic4", state=b"state4", ) recorder.insert_events([stored_event4]) self.assertEqual( recorder.select_events(originator_id2), [stored_event4], )
def test_insert_select(self) -> None: # Construct the recorder. recorder = self.create_recorder() # Check notifications methods work when there aren't any. self.assertEqual( recorder.max_notification_id(), 0, ) self.assertEqual( len(recorder.select_notifications(1, 3)), 0, ) self.assertEqual( len(recorder.select_notifications(1, 3, topics=["topic1"])), 0, ) # Write two stored events. originator_id1 = uuid4() originator_id2 = uuid4() stored_event1 = StoredEvent( originator_id=originator_id1, originator_version=0, topic="topic1", state=b"state1", ) stored_event2 = StoredEvent( originator_id=originator_id1, originator_version=1, topic="topic2", state=b"state2", ) stored_event3 = StoredEvent( originator_id=originator_id2, originator_version=1, topic="topic3", state=b"state3", ) notification_ids = recorder.insert_events([]) self.assertEqual(notification_ids, []) notification_ids = recorder.insert_events( [stored_event1, stored_event2]) self.assertEqual(notification_ids, [1, 2]) notification_ids = recorder.insert_events([stored_event3]) self.assertEqual(notification_ids, [3]) stored_events1 = recorder.select_events(originator_id1) stored_events2 = recorder.select_events(originator_id2) # Check we got what was written. self.assertEqual(len(stored_events1), 2) self.assertEqual(len(stored_events2), 1) notifications = recorder.select_notifications(1, 3) self.assertEqual(len(notifications), 3) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic1") self.assertEqual(notifications[0].state, b"state1") self.assertEqual(notifications[1].id, 2) self.assertEqual(notifications[1].originator_id, originator_id1) self.assertEqual(notifications[1].topic, "topic2") self.assertEqual(notifications[1].state, b"state2") self.assertEqual(notifications[2].id, 3) self.assertEqual(notifications[2].originator_id, originator_id2) self.assertEqual(notifications[2].topic, "topic3") self.assertEqual(notifications[2].state, b"state3") notifications = recorder.select_notifications( 1, 3, topics=["topic1", "topic2", "topic3"]) self.assertEqual(len(notifications), 3) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic1") self.assertEqual(notifications[0].state, b"state1") self.assertEqual(notifications[1].id, 2) self.assertEqual(notifications[1].originator_id, originator_id1) self.assertEqual(notifications[1].topic, "topic2") self.assertEqual(notifications[1].state, b"state2") self.assertEqual(notifications[2].id, 3) self.assertEqual(notifications[2].originator_id, originator_id2) self.assertEqual(notifications[2].topic, "topic3") self.assertEqual(notifications[2].state, b"state3") notifications = recorder.select_notifications(1, 3, topics=["topic1"]) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic1") self.assertEqual(notifications[0].state, b"state1") notifications = recorder.select_notifications(1, 3, topics=["topic2"]) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 2) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic2") self.assertEqual(notifications[0].state, b"state2") notifications = recorder.select_notifications(1, 3, topics=["topic3"]) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 3) self.assertEqual(notifications[0].originator_id, originator_id2) self.assertEqual(notifications[0].topic, "topic3") self.assertEqual(notifications[0].state, b"state3") notifications = recorder.select_notifications( 1, 3, topics=["topic1", "topic3"]) self.assertEqual(len(notifications), 2) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic1") self.assertEqual(notifications[0].state, b"state1") self.assertEqual(notifications[1].id, 3) self.assertEqual(notifications[1].topic, "topic3") self.assertEqual(notifications[1].state, b"state3") self.assertEqual( recorder.max_notification_id(), 3, ) notifications = recorder.select_notifications(1, 1) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 1) notifications = recorder.select_notifications(2, 1) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 2) notifications = recorder.select_notifications(2, 2) self.assertEqual(len(notifications), 2) self.assertEqual(notifications[0].id, 2) self.assertEqual(notifications[1].id, 3) notifications = recorder.select_notifications(3, 1) self.assertEqual(len(notifications), 1, len(notifications)) self.assertEqual(notifications[0].id, 3) notifications = recorder.select_notifications(start=2, limit=10, stop=2) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 2) notifications = recorder.select_notifications(start=1, limit=10, stop=2) self.assertEqual(len(notifications), 2, len(notifications)) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[1].id, 2)
def test(self): recorder = SQLiteApplicationRecorder(SQLiteDatastore(":memory:")) recorder.create_table() # Construct notification log. notification_log = LocalNotificationLog(recorder, section_size=5) # Get the "current" section of log. section = notification_log["1,10"] self.assertEqual(len(section.items), 0) # event notifications self.assertEqual(section.id, None) self.assertEqual(section.next_id, None) # Write 5 events. originator_id = uuid4() for i in range(5): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events([stored_event]) # Get the "head" section of log. section = notification_log["1,10"] self.assertEqual(len(section.items), 5) # event notifications self.assertEqual(section.items[0].id, 1) self.assertEqual(section.items[1].id, 2) self.assertEqual(section.items[2].id, 3) self.assertEqual(section.items[3].id, 4) self.assertEqual(section.items[4].id, 5) self.assertEqual(section.id, "1,5") self.assertEqual(section.next_id, "6,10") # Get the "1,5" section of log. section = notification_log["1,5"] self.assertEqual(len(section.items), 5) # event notifications self.assertEqual(section.items[0].id, 1) self.assertEqual(section.items[1].id, 2) self.assertEqual(section.items[2].id, 3) self.assertEqual(section.items[3].id, 4) self.assertEqual(section.items[4].id, 5) self.assertEqual(section.id, "1,5") self.assertEqual(section.next_id, "6,10") # Get the next section of log. section = notification_log["6,10"] self.assertEqual(len(section.items), 0) # event notifications self.assertEqual(section.id, None) self.assertEqual(section.next_id, None) # Write 4 events. originator_id = uuid4() for i in range(4): stored_event = StoredEvent( originator_id=originator_id, originator_version=i, topic="topic", state=b"state", ) recorder.insert_events([stored_event]) # Get the next section of log. section = notification_log["6,10"] self.assertEqual(len(section.items), 4) # event notifications self.assertEqual(section.items[0].id, 6) self.assertEqual(section.items[1].id, 7) self.assertEqual(section.items[2].id, 8) self.assertEqual(section.items[3].id, 9) self.assertEqual(section.id, "6,9") self.assertEqual(section.next_id, None) # Start at non-regular section start. section = notification_log["3,7"] self.assertEqual(len(section.items), 5) # event notifications self.assertEqual(section.items[0].id, 3) self.assertEqual(section.items[1].id, 4) self.assertEqual(section.items[2].id, 5) self.assertEqual(section.items[3].id, 6) self.assertEqual(section.items[4].id, 7) self.assertEqual(section.id, "3,7") self.assertEqual(section.next_id, "8,12") # Notification log limits section size. section = notification_log["3,10"] self.assertEqual(len(section.items), 5) # event notifications self.assertEqual(section.items[0].id, 3) self.assertEqual(section.items[1].id, 4) self.assertEqual(section.items[2].id, 5) self.assertEqual(section.items[3].id, 6) self.assertEqual(section.items[4].id, 7) self.assertEqual(section.id, "3,7") self.assertEqual(section.next_id, "8,12") # Reader limits section size. section = notification_log["3,4"] self.assertEqual(len(section.items), 2) # event notifications self.assertEqual(section.items[0].id, 3) self.assertEqual(section.items[1].id, 4) self.assertEqual(section.id, "3,4") self.assertEqual(section.next_id, "5,6") # Meaningless section ID. section = notification_log["3,2"] self.assertEqual(len(section.items), 0) # event notifications self.assertEqual(section.id, None) self.assertEqual(section.next_id, None)
def test_insert_select(self): # Construct the recorder. recorder = self.create_recorder() self.assertEqual( recorder.max_notification_id(), 0, ) # Write two stored events. originator_id1 = uuid4() originator_id2 = uuid4() stored_event1 = StoredEvent( originator_id=originator_id1, originator_version=0, topic="topic1", state=b"state1", ) stored_event2 = StoredEvent( originator_id=originator_id1, originator_version=1, topic="topic2", state=b"state2", ) stored_event3 = StoredEvent( originator_id=originator_id2, originator_version=1, topic="topic3", state=b"state3", ) recorder.insert_events([stored_event1, stored_event2]) recorder.insert_events([stored_event3]) stored_events1 = recorder.select_events(originator_id1) stored_events2 = recorder.select_events(originator_id2) # Check we got what was written. self.assertEqual(len(stored_events1), 2) self.assertEqual(len(stored_events2), 1) notifications = recorder.select_notifications(1, 3) self.assertEqual(len(notifications), 3) self.assertEqual(notifications[0].id, 1) self.assertEqual(notifications[0].originator_id, originator_id1) self.assertEqual(notifications[0].topic, "topic1") self.assertEqual(notifications[0].state, b"state1") self.assertEqual(notifications[1].id, 2) self.assertEqual(notifications[1].topic, "topic2") self.assertEqual(notifications[1].state, b"state2") self.assertEqual(notifications[2].id, 3) self.assertEqual(notifications[2].topic, "topic3") self.assertEqual(notifications[2].state, b"state3") self.assertEqual( recorder.max_notification_id(), 3, ) notifications = recorder.select_notifications(1, 1) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 1) notifications = recorder.select_notifications(2, 1) self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0].id, 2) notifications = recorder.select_notifications(2, 2) self.assertEqual(len(notifications), 2) self.assertEqual(notifications[0].id, 2) self.assertEqual(notifications[1].id, 3) notifications = recorder.select_notifications(3, 1) self.assertEqual(len(notifications), 1, len(notifications)) self.assertEqual(notifications[0].id, 3)