def test_check_if_new(*_): data_store = comet_core.data_store.DataStore('sqlite://') timestamp = datetime.utcnow() one_a = EventRecord(source_type='test_type', fingerprint='f1', received_at=timestamp) timestamp = datetime.utcnow() - timedelta(days=1) one_b = EventRecord(source_type='test_type', fingerprint='f1', received_at=timestamp, processed_at=timestamp) timestamp = datetime.utcnow() - timedelta(days=8) one_c = EventRecord(source_type='test_type', fingerprint='f1', received_at=timestamp, processed_at=timestamp) assert data_store.check_if_new('f1', timedelta(days=7)) data_store.add_record(one_a) # processed_at is None for that one, so f1 should still be considered new assert data_store.check_if_new('f1', timedelta(days=7)) data_store.add_record(one_c) # older than 7 days, so f1 should still be considered new (kind of "new again") assert data_store.check_if_new('f1', timedelta(days=7)) data_store.add_record(one_b) # more recent than 7 days ago and processed_at is set, so f1 should not be flagged new assert not data_store.check_if_new('f1', timedelta(days=7))
def test_process_unprocessed_events(): app = Comet() app.register_parser('datastoretest', json) app.register_parser('datastoretest2', json) app.register_parser('datastoretest3', json) app.set_config('datastoretest2', {}) specific_router = mock.Mock() router = mock.Mock() escalator = mock.Mock() app.register_router('datastoretest2', func=specific_router) app.register_router(func=router) app.register_escalator(func=escalator) check_user = '******' already_processed_user = '******' app.data_store.add_record( EventRecord(id=1, received_at=datetime.utcnow() - timedelta(days=5), source_type='datastoretest', owner=already_processed_user, data={}, processed_at=datetime.utcnow() - timedelta(days=5), fingerprint='f1')) app.data_store.add_record( EventRecord(id=2, received_at=datetime.utcnow() - timedelta(days=4), source_type='datastoretest', owner=already_processed_user, data={}, fingerprint='f1')) app.data_store.add_record( EventRecord(id=3, received_at=datetime.utcnow() - timedelta(days=3), source_type='datastoretest2', owner=check_user, data={}, fingerprint='f3')) app.data_store.add_record( EventRecord(id=4, received_at=datetime.utcnow() - timedelta(days=3), source_type='datastoretest3', owner=check_user, data={}, fingerprint='f4')) app.process_unprocessed_events() assert specific_router.call_count == 1 assert router.call_count == 2 assert router.call_args[0][2][0].owner == check_user assert escalator.call_count == 3
def test_handle_non_addressed_events(): app = Comet() app.register_parser('real_time_source', json) app.register_parser('real_time_source2', json) app.register_real_time_source('real_time_source') app.register_real_time_source('real_time_source2') app.set_config('real_time_source', {'alerts': { 'alert search name': { 'escalate_cadence': timedelta(minutes=45), 'template': 'alerts_template' } }}) app.set_config('real_time_source2', {'alerts': { 'alert search name': { 'escalate_cadence': timedelta(minutes=45), 'template': 'alerts_template' } }}) escalator = mock.Mock() escalator2 = mock.Mock() app.register_escalator('real_time_source', func=escalator) app.register_escalator('real_time_source2', func=escalator2) already_processed_user = '******' # already processed real time event - needs escalation app.data_store.add_record( EventRecord(id=2, received_at=datetime.utcnow() - timedelta(hours=1), source_type='real_time_source', owner=already_processed_user, processed_at=datetime.utcnow() - timedelta(hours=1), sent_at=datetime.utcnow() - timedelta(hours=1), data={'search_name': 'alert search name', 'name': 'needs escalation'}, fingerprint='f2')) # already processed real time event - still early for escalation # the event sent 35 min ago. app.data_store.add_record( EventRecord(id=3, received_at=datetime.utcnow() - timedelta(hours=1), source_type='real_time_source2', owner=already_processed_user, processed_at=datetime.utcnow() - timedelta(minutes=35), sent_at=datetime.utcnow() - timedelta(minutes=35), data={'search_name': 'alert search name', 'name': 'doesnt need escalation'}, fingerprint='f3')) app.handle_non_addressed_events() assert escalator.call_count == 1 assert escalator2.call_count == 0
def non_addressed_event(): # event sent but missing in the ignore_event table to # indicate that it wasn't addressed by the user event = EventRecord(received_at=datetime(2018, 7, 7, 9, 0, 0), source_type='datastoretest', owner='a', sent_at=datetime(2018, 7, 7, 9, 0, 0), data={}) event.fingerprint = 'f1' return event
def data_store_with_test_events(): data_store = comet_core.data_store.DataStore('sqlite://') one = EventRecord(received_at=datetime(2018, 7, 7, 9, 0, 0), source_type='datastoretest', owner='a', data={}) one.fingerprint = 'f1' two = EventRecord(received_at=datetime(2018, 7, 7, 9, 30, 0), source_type='datastoretest', owner='a', data={}) two.fingerprint = 'f2' three = EventRecord( received_at=datetime(2018, 7, 7, 9, 0, 0), source_type='datastoretest2', # Note that this is another source type! owner='b', data={}) three.fingerprint = 'f3' data_store.add_record(one) data_store.add_record(two) data_store.add_record(three) yield data_store
def data_store_with_test_events(): data_store = comet_core.data_store.DataStore("sqlite://") one = EventRecord(received_at=datetime(2018, 7, 7, 9, 0, 0), source_type="datastoretest", owner="a", data={}) one.fingerprint = "f1" two = EventRecord(received_at=datetime(2018, 7, 7, 9, 30, 0), source_type="datastoretest", owner="a", data={}) two.fingerprint = "f2" three = EventRecord( received_at=datetime(2018, 7, 7, 9, 0, 0), source_type="datastoretest2", # Note that this is another source type! owner="b", data={}, ) three.fingerprint = "f3" data_store.add_record(one) data_store.add_record(two) data_store.add_record(three) yield data_store
def addressed_event(ds_instance): # event was sent and addressed (ack by the user) ack_event = EventRecord(received_at=datetime(2018, 7, 7, 9, 30, 0), source_type='datastoretest', owner='a', sent_at=datetime(2018, 7, 7, 9, 30, 0), data={}) ack_event.fingerprint = 'f2' ds_instance.ignore_event_fingerprint( ack_event.fingerprint, ignore_type=IgnoreFingerprintRecord.ACKNOWLEDGE) return ack_event
def non_addressed_event(): """Event sent but missing in the ignore_event table to indicate that it wasn't addressed by the user""" event = EventRecord( received_at=datetime(2018, 7, 7, 9, 0, 0), source_type="datastoretest", owner="a", sent_at=datetime(2018, 7, 7, 9, 0, 0), data={}, ) event.fingerprint = "f1" return event
def event_to_escalate(ds_instance): # event was sent and addressed (escalated by the user) escalated_event = EventRecord(received_at=datetime(2018, 7, 7, 9, 30, 0), source_type='datastoretest', owner='a', sent_at=datetime(2018, 7, 7, 9, 30, 0), data={}) escalated_event.fingerprint = 'f3' ds_instance.ignore_event_fingerprint( escalated_event.fingerprint, ignore_type=IgnoreFingerprintRecord.ESCALATE_MANUALLY) return escalated_event
def addressed_event(data_store): """Event was sent and addressed (ack by the user).""" ack_event = EventRecord( received_at=datetime(2018, 7, 7, 9, 30, 0), source_type="datastoretest", owner="a", sent_at=datetime(2018, 7, 7, 9, 30, 0), data={}, ) ack_event.fingerprint = "f2" data_store.ignore_event_fingerprint( ack_event.fingerprint, ignore_type=IgnoreFingerprintRecord.ACKNOWLEDGE) return ack_event
def event_to_escalate(data_store): """Event was sent and addressed (escalated by the user).""" escalated_event = EventRecord( received_at=datetime(2018, 7, 7, 9, 30, 0), source_type="datastoretest", owner="a", sent_at=datetime(2018, 7, 7, 9, 30, 0), data={}, ) escalated_event.fingerprint = "f3" data_store.ignore_event_fingerprint( escalated_event.fingerprint, ignore_type=IgnoreFingerprintRecord.ESCALATE_MANUALLY) return escalated_event
def test_process_unprocessed_whitelisted_real_time_events(): app = Comet() app.register_parser('real_time_source', json) app.register_real_time_source('real_time_source') real_time_router = mock.Mock() router = mock.Mock() escalator = mock.Mock() app.register_router('real_time_source', func=real_time_router) app.register_router(func=router) app.register_escalator(func=escalator) check_user = '******' # user whitelisted real time event app.data_store.add_record( EventRecord(id=4, received_at=datetime.utcnow() - timedelta(days=3), sent_at=datetime.utcnow() - timedelta(days=3), source_type='real_time_source', owner=check_user, data={}, fingerprint='f4')) app.data_store.ignore_event_fingerprint( 'f4', IgnoreFingerprintRecord.ACCEPT_RISK) app.process_unprocessed_events() # test the whitelisted event was not routed/escalated assert real_time_router.call_count == 0 assert escalator.call_count == 0
def test_handle_non_escalatable_events(app): """Test that Comet handles events that has been set to not escalate.""" @app.register_parser("real_time_source") def parse_message(message): data = json.loads(message) return data, {} @app.register_config_provider("real_time_source") def register_conf(event): return {"escalate_cadence": False} app.register_real_time_source("real_time_source") escalator = mock.Mock() app.register_escalator("real_time_source", func=escalator) # This event should not be escalated. app.data_store.add_record( EventRecord( id=2, received_at=datetime.utcnow() - timedelta(hours=1), source_type="real_time_source", owner="event owner", processed_at=datetime.utcnow() - timedelta(hours=1), sent_at=datetime.utcnow() - timedelta(hours=1), data={"search_name": "alert search name", "name": "needs escalation"}, fingerprint="f2", ) ) app.handle_non_addressed_events() assert escalator.call_count == 0
def get_record(self): """Make the event container into a database record. Returns: EventRecord: the database record for this event """ return EventRecord(source_type=self.source_type, fingerprint=self.fingerprint, owner=self.owner, event_metadata=self.event_metadata, data=self.message)
def test_may_send_escalation(data_store): """Test the escalation function from a datastore with both escalated and non-escalated events.""" data_store.add_record(EventRecord(source_type="type1", escalated_at=None)) assert data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record( EventRecord(source_type="type1", escalated_at=datetime.utcnow() - timedelta(days=8))) assert data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record( EventRecord(source_type="type1", escalated_at=datetime.utcnow() - timedelta(days=6))) assert not data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record(EventRecord(source_type="type2", escalated_at=None)) assert data_store.may_send_escalation("type2", timedelta(days=7))
def test_check_if_previously_escalated(): data_store = comet_core.data_store.DataStore('sqlite://') one = EventRecord(source_type='test_type', fingerprint='f1', escalated_at=None) data_store.add_record(one) two = EventRecord(source_type='test_type', fingerprint='f2', escalated_at=datetime.utcnow() - timedelta(days=1)) data_store.add_record(two) assert not data_store.check_if_previously_escalated(one) assert data_store.check_if_previously_escalated(two) data_store.add_record(EventRecord(source_type='test_type', fingerprint='f1', escalated_at=datetime.utcnow() - timedelta(days=1))) assert data_store.check_if_previously_escalated(one)
def test_check_if_previously_escalated(data_store): """Test the 'previously escalated' function by adding events and then escalate them.""" one = EventRecord(source_type="test_type", fingerprint="f1", escalated_at=None) data_store.add_record(one) two = EventRecord(source_type="test_type", fingerprint="f2", escalated_at=datetime.utcnow() - timedelta(days=1)) data_store.add_record(two) assert not data_store.check_if_previously_escalated(one) assert data_store.check_if_previously_escalated(two) data_store.add_record( EventRecord(source_type="test_type", fingerprint="f1", escalated_at=datetime.utcnow() - timedelta(days=1))) assert data_store.check_if_previously_escalated(one)
def test_may_send_escalation(): data_store = comet_core.data_store.DataStore("sqlite://") data_store.add_record(EventRecord(source_type="type1", escalated_at=None)) assert data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record( EventRecord(source_type="type1", escalated_at=datetime.utcnow() - timedelta(days=8))) assert data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record( EventRecord(source_type="type1", escalated_at=datetime.utcnow() - timedelta(days=6))) assert not data_store.may_send_escalation("type1", timedelta(days=7)) data_store.add_record(EventRecord(source_type="type2", escalated_at=None)) assert data_store.may_send_escalation("type2", timedelta(days=7))
def data_store_with_test_events(data_store) -> DataStore: """Creates a populated data store.""" one = EventRecord(received_at=datetime(2018, 7, 7, 9, 0, 0), source_type="datastoretest", owner="a", data={}) one.fingerprint = "f1" two = EventRecord(received_at=datetime(2018, 7, 7, 9, 30, 0), source_type="datastoretest", owner="a", data={}) two.fingerprint = "f2" three = EventRecord( received_at=datetime(2018, 7, 7, 9, 0, 0), source_type="datastoretest2", # Note that this is another source type! owner="b", data={}, ) three.fingerprint = "f3" data_store.add_record(one) data_store.add_record(two) data_store.add_record(three) yield data_store
def test_get_open_issues(*_): data_store = comet_core.data_store.DataStore("sqlite://") one = EventRecord(source_type="test_type", fingerprint="f1", received_at=datetime.utcnow(), owner="test") data_store.add_record(one) two = EventRecord(source_type="test_type", fingerprint="f2", received_at=datetime.utcnow() - timedelta(days=0.9), owner="test") data_store.add_record(two) three = EventRecord(source_type="test_type", fingerprint="f3", received_at=datetime.utcnow() - timedelta(days=2), owner="test") data_store.add_record(three) four = EventRecord(source_type="test_type", fingerprint="f4", received_at=datetime.utcnow(), owner="not_test") data_store.add_record(four) five = EventRecord(source_type="test_type", fingerprint="f5", received_at=datetime.utcnow() - timedelta(days=1.5), owner="not_test") data_store.add_record(five) six = EventRecord(source_type="test_type", fingerprint="f2", received_at=datetime.utcnow() - timedelta(days=0.2), owner="test") data_store.add_record(six) open_issues = data_store.get_open_issues(["test"]) assert len(open_issues) == 2 open_issues = data_store.get_open_issues(["test", "not_test"]) assert len(open_issues) == 3 test_snooze_record = IgnoreFingerprintRecord( fingerprint="f1", ignore_type=IgnoreFingerprintRecord.SNOOZE, reported_at=datetime(2018, 2, 22, 0, 0, 11), expires_at=datetime(3000, 2, 23, 0, 0, 11), ) data_store.add_record(test_snooze_record) open_issues = data_store.get_open_issues(["test"]) assert len(open_issues) == 1
def test_check_if_new(data_store): """Check if there are new issues by adding a variety of different events.""" timestamp = datetime.utcnow() one_a = EventRecord(source_type="test_type", fingerprint="f1", received_at=timestamp) timestamp = datetime.utcnow() - timedelta(days=1) one_b = EventRecord(source_type="test_type", fingerprint="f1", received_at=timestamp, processed_at=timestamp) timestamp = datetime.utcnow() - timedelta(days=8) one_c = EventRecord(source_type="test_type", fingerprint="f1", received_at=timestamp, processed_at=timestamp) assert data_store.check_if_new("f1", timedelta(days=7)) data_store.add_record( one_a ) # processed_at is None for that one, so f1 should still be considered new assert data_store.check_if_new("f1", timedelta(days=7)) data_store.add_record( one_c ) # older than 7 days, so f1 should still be considered new (kind of "new again") assert data_store.check_if_new("f1", timedelta(days=7)) data_store.add_record( one_b ) # more recent than 7 days ago and processed_at is set, so f1 should not be flagged new assert not data_store.check_if_new("f1", timedelta(days=7))
def test_get_open_issues(data_store): """Tests getting open issues by adding events of different types and check how many are still open.""" one = EventRecord(source_type="test_type", fingerprint="f1", received_at=datetime.utcnow(), owner="test") data_store.add_record(one) two = EventRecord(source_type="test_type", fingerprint="f2", received_at=datetime.utcnow() - timedelta(days=0.9), owner="test") data_store.add_record(two) three = EventRecord(source_type="test_type", fingerprint="f3", received_at=datetime.utcnow() - timedelta(days=2), owner="test") data_store.add_record(three) four = EventRecord(source_type="test_type", fingerprint="f4", received_at=datetime.utcnow(), owner="not_test") data_store.add_record(four) five = EventRecord(source_type="test_type", fingerprint="f5", received_at=datetime.utcnow() - timedelta(days=1.5), owner="not_test") data_store.add_record(five) six = EventRecord(source_type="test_type", fingerprint="f2", received_at=datetime.utcnow() - timedelta(days=0.2), owner="test") data_store.add_record(six) open_issues = data_store.get_open_issues(["test"]) assert len(open_issues) == 2 open_issues = data_store.get_open_issues(["test", "not_test"]) assert len(open_issues) == 3 test_snooze_record = IgnoreFingerprintRecord( fingerprint="f1", ignore_type=IgnoreFingerprintRecord.SNOOZE, reported_at=datetime(2018, 2, 22, 0, 0, 11), expires_at=datetime(3000, 2, 23, 0, 0, 11), ) data_store.add_record(test_snooze_record) open_issues = data_store.get_open_issues(["test"]) assert len(open_issues) == 1
def test_get_open_issues(*_): data_store = comet_core.data_store.DataStore('sqlite://') one = EventRecord(source_type='test_type', fingerprint='f1', received_at=datetime.utcnow(), owner='test') data_store.add_record(one) two = EventRecord(source_type='test_type', fingerprint='f2', received_at=datetime.utcnow() - timedelta(days=.9), owner='test') data_store.add_record(two) three = EventRecord(source_type='test_type', fingerprint='f3', received_at=datetime.utcnow() - timedelta(days=2), owner='test') data_store.add_record(three) four = EventRecord(source_type='test_type', fingerprint='f4', received_at=datetime.utcnow(), owner='not_test') data_store.add_record(four) five = EventRecord(source_type='test_type', fingerprint='f5', received_at=datetime.utcnow() - timedelta(days=1.5), owner='not_test') data_store.add_record(five) six = EventRecord(source_type='test_type', fingerprint='f2', received_at=datetime.utcnow() - timedelta(days=.2), owner='test') data_store.add_record(six) open_issues = data_store.get_open_issues(['test']) assert len(open_issues) == 2 open_issues = data_store.get_open_issues(['test', 'not_test']) assert len(open_issues) == 3 test_snooze_record = IgnoreFingerprintRecord( fingerprint='f1', ignore_type=IgnoreFingerprintRecord.SNOOZE, reported_at=datetime(2018, 2, 22, 0, 0, 11), expires_at=datetime(3000, 2, 23, 0, 0, 11)) data_store.add_record(test_snooze_record) open_issues = data_store.get_open_issues(['test']) assert len(open_issues) == 1
def test_remove_duplicate_events(): """Test the remove_duplicate_events function""" one = EventRecord(received_at=datetime(2018, 2, 19, 0, 0, 11), source_type="datastoretest", owner="a", data={}) one.fingerprint = "f1" two = EventRecord(received_at=datetime(2018, 2, 20, 0, 0, 11), source_type="datastoretest", owner="a", data={}) two.fingerprint = "f2" three = EventRecord(received_at=datetime(2018, 2, 21, 0, 0, 11), source_type="datastoretest2", owner="a", data={}) three.fingerprint = "f1" records = [one, two, three] records = remove_duplicate_events(records) assert three in records assert one not in records assert len(records) == 2
def test_handle_default_escalation_strategy(app): """Test that the default 36H escalation is honoured if no escalation is set. This differs from the "do-not-escalate"-test since there the escalation is explicitly set to False and here it is missing. """ @app.register_parser("real_time_source") def parse_message(message): data = json.loads(message) return data, {} @app.register_config_provider("real_time_source") def register_conf(event): return {} app.register_real_time_source("real_time_source") escalator = mock.Mock() app.register_escalator("real_time_source", func=escalator) # This event should be escalated once app.data_store.add_record( EventRecord( id=2, received_at=datetime.utcnow() - timedelta(hours=1), source_type="real_time_source", owner="event owner", processed_at=datetime.utcnow() - timedelta(hours=1), sent_at=datetime.utcnow() - timedelta(hours=36), data={"search_name": "alert search name", "name": "needs escalation"}, fingerprint="f2", ) ) app.handle_non_addressed_events() assert escalator.call_count == 1
def test_date_sorting(data_store): """Test that the date sorting work by adding two events to the database and query for the oldest/latest.""" old = EventRecord(received_at=datetime(2018, 2, 19, 0, 0, 11), source_type="datastoretest", data={"fingerprint": "same"}) new = EventRecord(received_at=datetime(2018, 2, 20, 0, 0, 11), source_type="datastoretest", data={"fingerprint": "same"}) old.fingerprint = "same" new.fingerprint = "same" data_store.add_record(old) data_store.add_record(new) oldest = data_store.get_oldest_event_with_fingerprint("same") latest = data_store.get_latest_event_with_fingerprint("same") assert oldest.received_at == old.received_at assert latest.received_at == new.received_at
def test_date_sorting(): data_store = comet_core.data_store.DataStore("sqlite://") old = EventRecord(received_at=datetime(2018, 2, 19, 0, 0, 11), source_type="datastoretest", data={"fingerprint": "same"}) new = EventRecord(received_at=datetime(2018, 2, 20, 0, 0, 11), source_type="datastoretest", data={"fingerprint": "same"}) old.fingerprint = "same" new.fingerprint = "same" data_store.add_record(old) data_store.add_record(new) oldest = data_store.get_oldest_event_with_fingerprint("same") latest = data_store.get_latest_event_with_fingerprint("same") assert oldest.received_at == old.received_at assert latest.received_at == new.received_at
def test_date_sorting(): data_store = comet_core.data_store.DataStore('sqlite://') old = EventRecord(received_at=datetime(2018, 2, 19, 0, 0, 11), source_type='datastoretest', data={'fingerprint': 'same'}) new = EventRecord(received_at=datetime(2018, 2, 20, 0, 0, 11), source_type='datastoretest', data={'fingerprint': 'same'}) old.fingerprint = 'same' new.fingerprint = 'same' data_store.add_record(old) data_store.add_record(new) oldest = data_store.get_oldest_event_with_fingerprint('same') latest = data_store.get_latest_event_with_fingerprint('same') assert oldest.received_at == old.received_at assert latest.received_at == new.received_at
def test_check_needs_escalation(): data_store = comet_core.data_store.DataStore("sqlite://") test_fingerprint1 = "f1" test_fingerprint2 = "f2" test_fingerprint3 = "f3" one = EventRecord(received_at=datetime(2018, 2, 19, 0, 0, 11), source_type="datastoretest", owner="a", data={}) one.fingerprint = test_fingerprint1 two = EventRecord(received_at=datetime.utcnow(), source_type="datastoretest", owner="a", data={}) two.fingerprint = test_fingerprint1 three = EventRecord(received_at=datetime.utcnow() - timedelta(hours=23), source_type="datastoretest", owner="a", data={}) three.fingerprint = test_fingerprint2 four = EventRecord(received_at=datetime.utcnow(), source_type="datastoretest", owner="a", data={}) four.fingerprint = test_fingerprint2 five = EventRecord(received_at=datetime.utcnow(), source_type="datastoretest", owner="a", data={}) four.fingerprint = test_fingerprint3 data_store.add_record(one) data_store.add_record(two) data_store.add_record(three) data_store.add_record(four) data_store.add_record(five) three.fingerprint = test_fingerprint2 assert data_store.check_needs_escalation(timedelta(days=1), two) assert not data_store.check_needs_escalation(timedelta(days=1), four) assert not data_store.check_needs_escalation(timedelta(days=1), five)
def test_check_any_issue_needs_reminder(): data_store = comet_core.data_store.DataStore("sqlite://") test_fingerprint1 = "f1" test_fingerprint2 = "f2" test_fingerprint3 = "f3" one_a = EventRecord(sent_at=datetime.utcnow() - timedelta(days=9), source_type="datastoretest") one_a.fingerprint = test_fingerprint1 one_b = EventRecord(sent_at=datetime.utcnow() - timedelta(days=3), source_type="datastoretest") one_b.fingerprint = test_fingerprint1 two_a = EventRecord(sent_at=datetime.utcnow() - timedelta(days=10), source_type="datastoretest") two_a.fingerprint = test_fingerprint2 two_b = EventRecord(sent_at=datetime.utcnow() - timedelta(days=8), source_type="datastoretest") two_b.fingerprint = test_fingerprint2 two_c = EventRecord(source_type="datastoretest") # sent_at NULL two_c.fingerprint = test_fingerprint2 three_a = EventRecord(source_type="datastoretest") # sent_at NULL three_a.fingerprint = test_fingerprint3 data_store.add_record(one_a) data_store.add_record(two_a) data_store.add_record(two_b) data_store.add_record(two_c) data_store.add_record(three_a) # issue \ time ---> # 1 --------a------|--------------> # 2 ----a-------b--|--------------> (2c sent_at == NULL) # 3 ---------------|--------------> (3a sent_at == NULL) # ^ # -7days assert data_store.check_any_issue_needs_reminder(timedelta(days=7), [one_a, two_a, three_a]) data_store.add_record(one_b) # issue \ time ---> # 1 --------a------|-----b--------> # 2 ----a-------b--|--------------> (2c sent_at == NULL) # 3 ---------------|--------------> (3a sent_at == NULL) # ^ # -7days assert not data_store.check_any_issue_needs_reminder( timedelta(days=7), [one_a, two_a, three_a])