def test_integration_events_has_integration_fails(environment: ContextEnvironment, event_store, integration, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_integration(IntegrationEvent)

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_integration_n(IntegrationEvent, times=1)

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_integration_with(IntegrationEvent, some_property='x')

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_n_integrations(count=1)

    publisher_bus.publish(integration)
    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_not_integration(IntegrationEvent)

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_not_integration_with(IntegrationEvent, some_property='x')

    with pytest.raises(AssertionError):
        adap.then.integration_events.assert_has_integration_with_error(IntegrationEvent, error='some')
def test_domain_events_has_not_event(environment, event_store, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )
    adap.then.domain_events.assert_has_not_event(DomainEvent)
def test_domain_events_has_event_fails(environment, event_store, event, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_event(DomainEvent)

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_event_once(DomainEvent)

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_event_n_times(DomainEvent, times=1)

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_event_with(DomainEvent, some_property='x')

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_n_events(count=1)

    publisher_bus.publish(event)
    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_not_event(DomainEvent)

    with pytest.raises(AssertionError):
        adap.then.domain_events.assert_has_not_event_with(DomainEvent, some_property='x')
def test_integration_events_has_not_integration(environment: ContextEnvironment, event_store, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    adap.then.integration_events.assert_has_not_integration(IntegrationEvent)
    adap.then.integration_events.assert_has_not_integration_with(IntegrationEvent, some_property='x')
def test_get_integrations(environment: ContextEnvironment, event_store, integration, trace_id, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )
    
    publisher_bus.publish(integration)
    integrations = adap.then.integration_events.get_integrations(IntegrationEvent, trace_id=trace_id)
    assert len(list(integrations)) == 1
def test_get_events(environment, event_store, event, trace_id, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    publisher_bus.publish(event)
    events = adap.then.domain_events.get_events(event.__class__, trace_id=trace_id)
    assert len(list(events)) == 1
def test_when(environment, event_store, command, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    environment.handle = mock.Mock()
    adap.when(command)

    environment.handle.assert_called_once_with(command)
def test_get_events_raises(environment, event_store, event, aggregate_id, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    with pytest.raises(AttributeError):
        adap.then.domain_events.get_events(event.__class__, aggregate_id=aggregate_id)
    with pytest.raises(AttributeError):
        adap.then.domain_events.get_events(event.__class__, aggregate_type=Aggregate)
def test_integration_events_has_integration(environment: ContextEnvironment, event_store, integration, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )
    
    publisher_bus.publish(integration)
    adap.then.integration_events.assert_has_integration(IntegrationEvent)
    adap.then.integration_events.assert_has_integration_n(IntegrationEvent, times=1)
    adap.then.integration_events.assert_has_integration_with(IntegrationEvent, some_property='x')
    adap.then.integration_events.assert_has_integration_with_error(IntegrationEvent, error=None)
def test_domain_events_given_has_event(environment, event_store, event, aggregate_id, publisher_bus):
    adap = TestContextEnvironment(
        environment, 
        EventSourcedProcessor(event_store),
        publisher_bus
    )

    publisher_bus.publish(event)
    adap.then.domain_events.assert_has_event(event.__class__, aggregate_type=Aggregate, aggregate_id=aggregate_id)
    adap.then.domain_events.assert_has_event_once(event.__class__)
    adap.then.domain_events.assert_has_event_n_times(event.__class__, times=1)
    adap.then.domain_events.assert_has_event_with(event.__class__, some_property='x')
def test_all_system():
    ################################## Infrastructure Utils ##################################

    mapper = Mapper(transcoder=Transcoder())

    ################################## Domain Layer ##################################

    ## Domain Model

    ### Value Objects
    class PetStoreId(Identity):
        identity: str

    class PetStoreName(ValueObject):
        name: str

        @classmethod
        def from_text(cls, name: str):
            return PetStoreName(name)

    ### Aggregates

    #### Events
    @mapper.register
    class PetStoreRegistered(DomainEvent):
        __version__: int = 1

        pet_store_id: PetStoreId
        pet_store_name: PetStoreName

    #### Aggregate root
    class PetStore(AggregateRoot):
        @classmethod
        def create(cls, pet_store_id: PetStoreId,
                   pet_store_name: PetStoreName) -> 'PetStore':
            pet_store = PetStore(pet_store_id)
            pet_store.__apply__(
                pet_store.__stamp__(PetStoreRegistered)(
                    pet_store_id=pet_store_id, pet_store_name=pet_store_name))
            return pet_store

        @mutator
        def mutate(self, message: DomainEvent) -> None:
            pass

        @mutate.event(PetStoreRegistered)
        def _(self, e: PetStoreRegistered):
            self.pet_store_id = e.pet_store_id
            self.pet_store_name = e.pet_store_name

    class PetStoreRepository(IRepository[PetStore, PetStoreId]):
        pass

    ################################## Application Layer ##################################

    ## Commands
    @mapper.register
    class RegisterPetStore(ApplicationCommand):
        __version__: int = 1
        pet_store_id: str
        pet_store_name: str

    ## Hanlder
    class PetStoreSerivce(ApplicationService):
        def __init__(self, registry: Registry):
            self.pet_store_repository = registry.get(PetStoreRepository)

        @handler
        def handle(self, message: ApplicationMessage) -> None:
            pass

        @handle.command(RegisterPetStore)
        def _(self, c: RegisterPetStore) -> None:
            pet_store = PetStore.create(
                pet_store_id=PetStoreId.from_text(c.pet_store_id),
                pet_store_name=PetStoreName.from_text(c.pet_store_name))
            self.pet_store_repository.save(pet_store)

    ## Integrations
    @mapper.register
    class CreatePetStoreSucceeded(IntegrationEvent):
        __resolve__: str = 'success'
        __error__: typing.Optional[str] = None
        __version__: int = 1

    ## Resolver
    class PetStoreResolver(ApplicationService):
        def __init__(self, integration_bus: Bus[IntegrationEvent]):
            self.integration_bus = integration_bus

        @handler
        def handle(self, message: ApplicationMessage):
            pass

        @handle.trace(RegisterPetStore, PetStoreRegistered)
        def _(self, c: RegisterPetStore, e: PetStoreRegistered):
            self.integration_bus.publish(
                CreatePetStoreSucceeded(__timestamp__=0.0))

    ## Projection
    class PetStoreProjection(Projection):
        @projector
        def project(self, event: DomainEvent):
            pass

        @project.event(PetStoreRegistered)
        def _(self, e: PetStoreRegistered):
            self.project_pet_store_registered(e)

        @abc.abstractmethod
        def project_pet_store_registered(self, e: PetStoreRegistered):
            pass

    ############################## Infrastructure Layer ##################################

    ## Repositories
    Adapter = make_repo_adapter(PetStore, PetStoreId)

    class EventSourcedPetStoreRepository(PetStoreRepository, Adapter):
        pass

    ## Projections
    class PetStoreMemoryProjection(PetStoreProjection):
        def project_pet_store_registered(self, e: PetStoreRegistered):
            # Should project in some way
            pass

    ################################## Bootstrap ######################################

    class IntegrationTestFactory(IContextFactory):
        def __init__(self, event_store: EventStore, mapper: Mapper):
            self.event_store = event_store
            self.mapper = mapper

        def create_trace_segment_store(self) -> TraceSegmentStore:
            return MemoryTraceSegmentStore(self.mapper)

        def create_projection(self,
                              key: typing.Type[Projection]) -> Projection:
            if key is PetStoreProjection:
                return PetStoreMemoryProjection()

        def create_repository(self,
                              key: typing.Type[IRepository]) -> IRepository:
            if key is PetStoreRepository:
                return EventSourcedPetStoreRepository(self.event_store)

        def create_domain_service(
                self, key: typing.Type[IDomainService]) -> IDomainService:
            pass

    event_store = EventStore(event_mapper=mapper,
                             record_manager=MemoryEventRecordManager())

    factory = IntegrationTestFactory(event_store, mapper)
    publisher_bus = Bus()
    env = ContextEnvironment('ctx', factory, publisher_bus)

    env.add_projection(PetStoreProjection)

    env.add_repository(PetStoreRepository)

    env.add_handler(PetStoreSerivce(env.registry))

    env.add_resolver(PetStoreResolver(publisher_bus))

    env.attach_to_domain_event_bus(BusSubscriber(publisher_bus))

    ################################## Some tests ######################################

    adap = TestContextEnvironment(env, EventSourcedProcessor(event_store),
                                  publisher_bus)
    adap.given(
        adap.stamp_event(PetStoreRegistered, PetStore,
                         PetStoreId.create().identity)(
                             pet_store_id=PetStoreId.create(),
                             pet_store_name=PetStoreName.from_text('noe')))
    adap.when(RegisterPetStore.stamp()(pet_store_id='ark',
                                       pet_store_name='ark'))
    adap.then.domain_events.assert_has_event_n_times(PetStoreRegistered,
                                                     times=1)
    adap.then.integration_events.assert_has_integration(
        CreatePetStoreSucceeded)