diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/CustomersService.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/CustomersService.java index 3697a3c..02a0ef8 100644 --- a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/CustomersService.java +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/CustomersService.java @@ -1,10 +1,14 @@ package de.sample.schulung.accounts.domain; import de.sample.schulung.accounts.domain.Customer.CustomerState; +import de.sample.schulung.accounts.domain.events.CustomerCreatedEvent; +import de.sample.schulung.accounts.domain.events.CustomerDeletedEvent; +import de.sample.schulung.accounts.domain.events.CustomerReplacedEvent; import de.sample.schulung.accounts.domain.sink.CustomersSink; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -18,6 +22,7 @@ public class CustomersService { private final CustomersSink sink; + private final ApplicationEventPublisher eventPublisher; public Stream getCustomers() { return sink.getCustomers(); @@ -29,6 +34,7 @@ public Stream getCustomersByState(@NotNull CustomerState state) { public void createCustomer(@Valid Customer customer) { sink.createCustomer(customer); + eventPublisher.publishEvent(new CustomerCreatedEvent(customer)); } public Optional findCustomerById(@NotNull UUID uuid) { @@ -37,10 +43,12 @@ public Optional findCustomerById(@NotNull UUID uuid) { public void replaceCustomer(@Valid Customer customer) { sink.replaceCustomer(customer); + eventPublisher.publishEvent(new CustomerReplacedEvent(customer)); } public void deleteCustomer(@NotNull UUID uuid) { sink.deleteCustomer(uuid); + eventPublisher.publishEvent(new CustomerDeletedEvent(uuid)); } public boolean exists(UUID uuid) { diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerCreatedEvent.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerCreatedEvent.java new file mode 100644 index 0000000..bfeb140 --- /dev/null +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerCreatedEvent.java @@ -0,0 +1,8 @@ +package de.sample.schulung.accounts.domain.events; + +import de.sample.schulung.accounts.domain.Customer; + +public record CustomerCreatedEvent( + Customer customer +) { +} diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerDeletedEvent.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerDeletedEvent.java new file mode 100644 index 0000000..ecbf7ef --- /dev/null +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerDeletedEvent.java @@ -0,0 +1,8 @@ +package de.sample.schulung.accounts.domain.events; + +import java.util.UUID; + +public record CustomerDeletedEvent( + UUID uuid +) { +} diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerReplacedEvent.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerReplacedEvent.java new file mode 100644 index 0000000..41eb658 --- /dev/null +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/events/CustomerReplacedEvent.java @@ -0,0 +1,8 @@ +package de.sample.schulung.accounts.domain.events; + +import de.sample.schulung.accounts.domain.Customer; + +public record CustomerReplacedEvent( + Customer customer +) { +} diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventLogger.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventLogger.java new file mode 100644 index 0000000..96d271b --- /dev/null +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventLogger.java @@ -0,0 +1,15 @@ +package de.sample.schulung.accounts.domain.logging; + +import de.sample.schulung.accounts.domain.Customer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CustomerEventLogger { + + public void logCustomerCreated(Customer customer) { + log.info("Customer created with UUID {}", customer.getUuid()); + } + +} diff --git a/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventObserver.java b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventObserver.java new file mode 100644 index 0000000..d515bd7 --- /dev/null +++ b/account-service-provider/src/main/java/de/sample/schulung/accounts/domain/logging/CustomerEventObserver.java @@ -0,0 +1,19 @@ +package de.sample.schulung.accounts.domain.logging; + +import de.sample.schulung.accounts.domain.events.CustomerCreatedEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CustomerEventObserver { + + private final CustomerEventLogger customerEventLogger; + + @EventListener + public void handle(CustomerCreatedEvent event) { + customerEventLogger.logCustomerCreated(event.customer()); + } + +} diff --git a/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/CustomersServiceTest.java b/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/CustomersServiceTest.java index 86b5678..064683c 100644 --- a/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/CustomersServiceTest.java +++ b/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/CustomersServiceTest.java @@ -1,18 +1,27 @@ package de.sample.schulung.accounts.domain; +import de.sample.schulung.accounts.domain.events.CustomerCreatedEvent; +import de.sample.schulung.accounts.domain.logging.CustomerEventLogger; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.event.ApplicationEvents; import java.time.LocalDate; import java.time.Month; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.verify; @DomainLayerTest public class CustomersServiceTest { @Autowired CustomersService service; + @Autowired + CustomerEventLogger customerEventLogger; + @Autowired + ApplicationEvents events; @Test void shouldNotCreateInvalidCustomer() { @@ -38,5 +47,36 @@ void shouldNotCreateCustomerThatIsNoAdult() { } + @Test + void shouldLogEventWhenCustomerIsCreated() { + + var customer = new Customer(); + customer.setName("Tom Mayer"); + customer.setState(Customer.CustomerState.ACTIVE); + customer.setDateOfBirth(LocalDate.of(2000, Month.DECEMBER, 20)); + + service.createCustomer(customer); + + verify(customerEventLogger).logCustomerCreated(customer); + + } + + @Test + void shouldPublishEventWhenCustomerIsCreated() { + + var customer = new Customer(); + customer.setName("Tom Mayer"); + customer.setState(Customer.CustomerState.ACTIVE); + customer.setDateOfBirth(LocalDate.of(2000, Month.DECEMBER, 20)); + + service.createCustomer(customer); + + assertThat(events.stream(CustomerCreatedEvent.class)) + .hasSize(1) + .first() + .extracting(CustomerCreatedEvent::customer) + .isSameAs(customer); + + } } diff --git a/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/DomainLayerTest.java b/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/DomainLayerTest.java index c54f7a7..ea362bb 100644 --- a/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/DomainLayerTest.java +++ b/account-service-provider/src/test/java/de/sample/schulung/accounts/domain/DomainLayerTest.java @@ -1,20 +1,24 @@ package de.sample.schulung.accounts.domain; import de.sample.schulung.accounts.config.InitializationProperty; +import de.sample.schulung.accounts.domain.logging.CustomerEventLogger; import de.sample.schulung.accounts.domain.sink.CustomersSink; import de.sample.schulung.accounts.domain.sink.CustomersSinkInMemoryImpl; import org.junit.jupiter.api.Tag; +import org.mockito.Mockito; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockReset; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.event.RecordApplicationEvents; import java.lang.annotation.*; @@ -31,6 +35,7 @@ HibernateJpaAutoConfiguration.class }) @InitializationProperty +@RecordApplicationEvents // optional @ActiveProfiles({"test", "domain-test"}) @Tag("integration-test") @@ -50,6 +55,16 @@ CustomersSink testCustomerSink() { return new CustomersSinkInMemoryImpl(); } + @Primary + @Bean + CustomerEventLogger testCustomerEventLogger() { + // Mock or DefaultImpl? + return Mockito.mock( + CustomerEventLogger.class, + MockReset.withSettings(MockReset.AFTER) + ); + } + }