def test_upsert_on_index_elements_mismatch(self): """ Events with a duplicate index elements cannot be upsert if they don't match. """ with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) task_event = TaskEvent( event_type=TaskEventType.CREATED, parent_id=created_event.id, task_id=self.task.id, ) self.store.create(task_event) assert_that( calling(self.store.upsert_on_index_elements).with_args( TaskEvent( event_type=TaskEventType.REVISED, parent_id=created_event.id, task_id=self.task.id, )), raises(ConcurrentStateConflictError), )
def test_column_alias(self): assert_that(TaskEvent.container_id, is_(equal_to(TaskEvent.task_id))) task_event = TaskEvent() task_event.container_id = self.task.id assert_that(task_event.container_id, is_(equal_to(self.task.id))) assert_that(task_event.task_id, is_(equal_to(self.task.id)))
def test_unique_parent_id(self): """ Events are unique per parent. """ with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) task_event = TaskEvent( event_type=TaskEventType.CREATED, parent_id=created_event.id, task_id=self.task.id, ) self.store.create(task_event) assert_that( calling(self.store.create).with_args( TaskEvent( event_type=TaskEventType.CREATED, parent_id=created_event.id, task_id=self.task.id, ), ), raises(DuplicateModelError), )
def test_upsert_on_index_elements(self): """ Events with a duplicate index elements can be upserted. """ with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) task_event = TaskEvent( event_type=TaskEventType.CREATED, parent_id=created_event.id, task_id=self.task.id, ) self.store.create(task_event) upserted = self.store.upsert_on_index_elements( TaskEvent( event_type=TaskEventType.CREATED, parent_id=created_event.id, task_id=self.task.id, )) assert_that(task_event.id, is_(equal_to(upserted.id)))
def iter_events(self): """ Walk through the event state machine. """ created = TaskEvent( event_type=TaskEventType.CREATED, state=[TaskEventType.CREATED], task_id=self.task.id, ).create() yield created assigned = TaskEvent( assignee="Alice", event_type=TaskEventType.ASSIGNED, parent_id=created.id, state=[TaskEventType.CREATED, TaskEventType.ASSIGNED], task_id=self.task.id, ).create() yield assigned scheduled = TaskEvent( deadline=datetime.utcnow(), event_type=TaskEventType.SCHEDULED, parent_id=assigned.id, state=[ TaskEventType.CREATED, TaskEventType.ASSIGNED, TaskEventType.SCHEDULED ], task_id=self.task.id, ).create() yield scheduled started = TaskEvent( event_type=TaskEventType.STARTED, parent_id=scheduled.id, state=[TaskEventType.STARTED], task_id=self.task.id, ).create() yield started reassigned = TaskEvent( assignee="Bob", event_type=TaskEventType.REASSIGNED, parent_id=started.id, state=[TaskEventType.STARTED], task_id=self.task.id, ).create() yield reassigned
def test_retrieve_with_update_lock_exception(self): with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) with patch.object(Query, 'with_for_update') as mocked_with_for_update: mocked_with_for_update.side_effect = OperationalError( statement="", params="", orig=psycopg2.errors.LockNotAvailable()) assert_that( calling(self.store.retrieve_most_recent_with_update_lock). with_args(task_id=self.task.id, ), raises(ContainerLockNotAvailableRetry), ) with patch.object(Query, 'with_for_update') as mocked_with_for_update: mocked_with_for_update.side_effect = Exception() assert_that( calling(self.store.retrieve_most_recent_with_update_lock). with_args(task_id=self.task.id, ), raises(Exception), )
def setup(self): self.graph = create_object_graph( "microcosm_eventsource", root_path=join(dirname(__file__), pardir), testing=True, ) self.graph.use( "task_store", "task_event_store", "activity_store", "activity_event_store", ) self.store = self.graph.task_event_store self.activity_store = self.graph.activity_event_store self.context = SessionContext(self.graph) self.context.recreate_all() self.context.open() with transaction(): self.task = Task().create() self.created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ).create() self.scheduled_event = TaskEvent( deadline=datetime.utcnow(), event_type=TaskEventType.SCHEDULED, parent_id=self.created_event.id, state=[TaskEventType.CREATED, TaskEventType.SCHEDULED], task_id=self.task.id, ).create() self.assigned_event = TaskEvent( deadline=datetime.utcnow(), event_type=TaskEventType.ASSIGNED, parent_id=self.scheduled_event.id, state=[TaskEventType.ASSIGNED, TaskEventType.CREATED, TaskEventType.SCHEDULED], assignee="assignee", task_id=self.task.id, ).create() self.started_event = TaskEvent( event_type=TaskEventType.STARTED, parent_id=self.assigned_event.id, task_id=self.task.id, ).create() # flush sqlalchemy cache before sql operation self.store.session.expire_all()
def setup(self): self.graph = create_object_graph( "microcosm_eventsource", root_path=dirname(__file__), testing=True, ) self.graph.use( "task_store", "task_event_store", "activity_store", "activity_event_store", ) self.context = SessionContext(self.graph) self.context.recreate_all() self.context.open() with transaction(): self.task = Task().create() self.created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ).create() self.assigned_event = TaskEvent( assignee="Alice", event_type=TaskEventType.ASSIGNED, parent_id=self.created_event.id, task_id=self.task.id, ).create() self.started_event = TaskEvent( event_type=TaskEventType.STARTED, parent_id=self.assigned_event.id, task_id=self.task.id, ).create() self.reassigned_event = TaskEvent( assignee="Bob", event_type=TaskEventType.REASSIGNED, parent_id=self.started_event.id, task_id=self.task.id, ).create() self.reassigned_event = TaskEvent( event_type=TaskEventType.COMPLETED, parent_id=self.reassigned_event.id, task_id=self.task.id, ).create()
def test_retrieve_with_update_lock(self): with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) assert_that( self.store.retrieve_most_recent_with_update_lock( task_id=self.task.id), is_(equal_to(created_event)), )
def test_non_initial_event_requires_parent_id(self): """ A non-initial event must have a previous event. """ task_event = TaskEvent( event_type=TaskEventType.STARTED, task_id=self.task.id, ) assert_that( calling(self.store.create).with_args(task_event), raises(ModelIntegrityError), )
def test_retrieve_most_recent(self): """ The logical clock provides a total ordering on the main foreign key. """ with transaction(): created_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(created_event) assigned_event = TaskEvent( assignee="Alice", event_type=TaskEventType.ASSIGNED, parent_id=created_event.id, task_id=self.task.id, ) self.store.create(assigned_event) assert_that( self.store.retrieve_most_recent(task_id=self.task.id), is_(equal_to(assigned_event)), )
def test_multi_valued_state(self): """ A state can contain multiple values. """ with transaction(): task_event = TaskEvent( event_type=TaskEventType.CREATED, state=(TaskEventType.CREATED, TaskEventType.ASSIGNED), task_id=self.task.id, ) self.store.create(task_event) assert_that( task_event.state, contains_inanyorder(TaskEventType.ASSIGNED, TaskEventType.CREATED), )
def test_create_retrieve(self): """ An event can be retrieved after it is created. """ with transaction(): task_event = TaskEvent( event_type=TaskEventType.CREATED, task_id=self.task.id, ) self.store.create(task_event) assert_that(task_event.clock, is_(equal_to(1))) assert_that(task_event.parent_id, is_(none())) assert_that(task_event.state, contains(TaskEventType.CREATED)) assert_that(task_event.version, is_(equal_to(1))) assert_that( self.store.retrieve(task_event.id), is_(equal_to(task_event)), )