diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderQueryService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderQueryService.java index c769983c2..c40d95b0d 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderQueryService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderQueryService.java @@ -16,6 +16,7 @@ package org.citrusframework.simulator.service; +import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.JoinType; import org.citrusframework.simulator.model.MessageHeader; import org.citrusframework.simulator.model.MessageHeader_; @@ -44,9 +45,11 @@ public class MessageHeaderQueryService extends QueryService { private static final Logger logger = LoggerFactory.getLogger(MessageHeaderQueryService.class); + private final EntityManager entityManager; private final MessageHeaderRepository messageHeaderRepository; - public MessageHeaderQueryService(MessageHeaderRepository messageHeaderRepository) { + public MessageHeaderQueryService(EntityManager entityManager, MessageHeaderRepository messageHeaderRepository) { + this.entityManager = entityManager; this.messageHeaderRepository = messageHeaderRepository; } @@ -75,7 +78,7 @@ public Page findByCriteria(MessageHeaderCriteria criteria, Pageab logger.debug("find by criteria : {}, page: {}", criteria, page); final Specification specification = createSpecification(criteria); return messageHeaderRepository.findAll(specification, page) - .map(MessageHeaderService::restrictToDtoProperties); + .map(messageHeader -> MessageHeaderService.restrictToDtoProperties(messageHeader, entityManager)); } /** diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java index 4a1f8df8a..fed409f67 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java @@ -16,6 +16,7 @@ package org.citrusframework.simulator.service; +import jakarta.persistence.EntityManager; import org.citrusframework.simulator.model.Message; import org.citrusframework.simulator.model.MessageHeader; import org.springframework.data.domain.Page; @@ -23,6 +24,8 @@ import java.util.Optional; +import static java.util.Objects.nonNull; + /** * Service Interface for managing {@link MessageHeader}. */ @@ -58,11 +61,21 @@ public interface MessageHeaderService { * relationships, because of a possible {@link org.hibernate.LazyInitializationException}). * * @param messageHeader The entity, which should be returned + * @param entityManager Entity manager that is currently managing the entity * @return the entity with prepared {@link Message} */ - static MessageHeader restrictToDtoProperties(MessageHeader messageHeader) { - Message message = messageHeader.getMessage(); - messageHeader.setMessage(Message.builder().messageId(message.getMessageId()).citrusMessageId(message.getCitrusMessageId()).build()); + static MessageHeader restrictToDtoProperties(MessageHeader messageHeader, EntityManager entityManager) { + var message = messageHeader.getMessage(); + + if (nonNull(message)) { + entityManager.detach(messageHeader); + messageHeader.setMessage( + Message.builder() + .messageId(message.getMessageId()) + .citrusMessageId(message.getCitrusMessageId()) + .build()); + } + return messageHeader; } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java index 4df4a1da8..5fdde78bb 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java @@ -17,6 +17,7 @@ package org.citrusframework.simulator.service; import jakarta.annotation.Nullable; +import jakarta.persistence.EntityManager; import org.citrusframework.TestAction; import org.citrusframework.TestCase; import org.citrusframework.simulator.model.ScenarioAction; @@ -86,13 +87,21 @@ public interface ScenarioActionService { * because of a possible {@link org.hibernate.LazyInitializationException}). * * @param scenarioAction The entity, which should be returned + * @param entityManager Entity manager that is currently managing the entity * @return the entity with prepared {@link ScenarioExecution} */ - static ScenarioAction restrictToDtoProperties(ScenarioAction scenarioAction) { + static ScenarioAction restrictToDtoProperties(ScenarioAction scenarioAction, EntityManager entityManager) { ScenarioExecution scenarioExecution = scenarioAction.getScenarioExecution(); + if (nonNull(scenarioExecution)) { - scenarioAction.setScenarioExecution(ScenarioExecution.builder().executionId(scenarioExecution.getExecutionId()).scenarioName(scenarioExecution.getScenarioName()).build()); + entityManager.detach(scenarioAction); + scenarioAction.setScenarioExecution( + ScenarioExecution.builder() + .executionId(scenarioExecution.getExecutionId()) + .scenarioName(scenarioExecution.getScenarioName()) + .build()); } + return scenarioAction; } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java index 5cebbff54..6127b461e 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java @@ -16,6 +16,7 @@ package org.citrusframework.simulator.service.impl; +import jakarta.persistence.EntityManager; import org.citrusframework.simulator.model.MessageHeader; import org.citrusframework.simulator.repository.MessageHeaderRepository; import org.citrusframework.simulator.service.MessageHeaderService; @@ -37,9 +38,11 @@ public class MessageHeaderServiceImpl implements MessageHeaderService { private static final Logger logger = LoggerFactory.getLogger(MessageHeaderServiceImpl.class); + private final EntityManager entityManager; private final MessageHeaderRepository messageHeaderRepository; - public MessageHeaderServiceImpl(MessageHeaderRepository messageHeaderRepository) { + public MessageHeaderServiceImpl(EntityManager entityManager, MessageHeaderRepository messageHeaderRepository) { + this.entityManager = entityManager; this.messageHeaderRepository = messageHeaderRepository; } @@ -54,7 +57,7 @@ public MessageHeader save(MessageHeader messageHeader) { public Page findAll(Pageable pageable) { logger.debug("Request to get all MessageHeaders with eager relationships"); return messageHeaderRepository.findAllWithEagerRelationships(pageable) - .map(MessageHeaderService::restrictToDtoProperties); + .map(messageHeader -> MessageHeaderService.restrictToDtoProperties(messageHeader, entityManager)); } @Override @@ -62,6 +65,6 @@ public Page findAll(Pageable pageable) { public Optional findOne(Long headerId) { logger.debug("Request to get MessageHeader : {}", headerId); return messageHeaderRepository.findOneWithEagerRelationships(headerId) - .map(MessageHeaderService::restrictToDtoProperties); + .map(messageHeader -> MessageHeaderService.restrictToDtoProperties(messageHeader, entityManager)); } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java index e9fb2b63b..2ed0d0f5c 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java @@ -17,6 +17,7 @@ package org.citrusframework.simulator.service.impl; import jakarta.annotation.Nullable; +import jakarta.persistence.EntityManager; import org.apache.commons.lang3.StringUtils; import org.citrusframework.TestAction; import org.citrusframework.TestCase; @@ -52,10 +53,12 @@ public class ScenarioActionServiceImpl implements ScenarioActionService { private final TimeProvider timeProvider = new TimeProvider(); + private final EntityManager entityManager; private final ScenarioActionRepository scenarioActionRepository; private final ScenarioExecutionService scenarioExecutionService; - public ScenarioActionServiceImpl(ScenarioActionRepository scenarioActionRepository, ScenarioExecutionService scenarioExecutionService) { + public ScenarioActionServiceImpl(EntityManager entityManager, ScenarioActionRepository scenarioActionRepository, ScenarioExecutionService scenarioExecutionService) { + this.entityManager = entityManager; this.scenarioActionRepository = scenarioActionRepository; this.scenarioExecutionService = scenarioExecutionService; } @@ -75,7 +78,7 @@ public ScenarioAction save(ScenarioAction scenarioAction) { public Page findAll(Pageable pageable) { logger.debug("Request to get all ScenarioActions with eager relationships"); return scenarioActionRepository.findAllWithToOneRelationships(pageable) - .map(ScenarioActionService::restrictToDtoProperties); + .map(scenarioAction -> ScenarioActionService.restrictToDtoProperties(scenarioAction, entityManager)); } @Override @@ -83,7 +86,7 @@ public Page findAll(Pageable pageable) { public Optional findOne(Long id) { logger.debug("Request to get ScenarioAction with eager relationships: {}", id); return scenarioActionRepository.findOneWithEagerRelationships(id) - .map(ScenarioActionService::restrictToDtoProperties); + .map(scenarioAction -> ScenarioActionService.restrictToDtoProperties(scenarioAction, entityManager)); } @Override diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/MessageHeaderServiceTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/MessageHeaderServiceTest.java new file mode 100644 index 000000000..699532b56 --- /dev/null +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/MessageHeaderServiceTest.java @@ -0,0 +1,61 @@ +package org.citrusframework.simulator.service; + +import jakarta.persistence.EntityManager; +import org.citrusframework.simulator.model.Message; +import org.citrusframework.simulator.model.MessageHeader; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +@ExtendWith({MockitoExtension.class}) +class MessageHeaderServiceTest { + + @Mock + private EntityManager entityManagerMock; + + @Nested + class RestrictToDtoProperties { + + @Test + void shouldFilterMessageDetails() { + var message = mock(Message.class); + doReturn(1234L).when(message).getMessageId(); + doReturn("citrus-message-id").when(message).getCitrusMessageId(); + + var messageHeader = new MessageHeader(); + messageHeader.setMessage(message); + + var restrictedMessageHeader = MessageHeaderService.restrictToDtoProperties(messageHeader, entityManagerMock); + + var restrictedMessage = restrictedMessageHeader.getMessage(); + assertEquals(message.getMessageId(), restrictedMessage.getMessageId()); + assertEquals(message.getCitrusMessageId(), restrictedMessage.getCitrusMessageId()); + + verify(message, never()).getHeaders(); + verify(message, never()).getScenarioExecution(); + + verify(entityManagerMock).detach(messageHeader); + } + + @Test + void shouldHandleNullMessage() { + var messageHeader = new MessageHeader(); + + var restrictedMessageHeader = MessageHeaderService.restrictToDtoProperties(messageHeader, entityManagerMock); + + assertNull(restrictedMessageHeader.getMessage()); + + verifyNoInteractions(entityManagerMock); + } + } +} diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioActionServiceTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioActionServiceTest.java new file mode 100644 index 000000000..e11cf5c05 --- /dev/null +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioActionServiceTest.java @@ -0,0 +1,62 @@ +package org.citrusframework.simulator.service; + +import jakarta.persistence.EntityManager; +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +@ExtendWith({MockitoExtension.class}) +class ScenarioActionServiceTest { + + @Mock + private EntityManager entityManagerMock; + + @Nested + class RestrictToDtoProperties { + + @Test + void shouldFilterMessageDetails() { + var scenarioExecution = mock(ScenarioExecution.class); + doReturn(1234L).when(scenarioExecution).getExecutionId(); + doReturn("scenario-name").when(scenarioExecution).getScenarioName(); + + var scenarioAction = new ScenarioAction(); + scenarioAction.setScenarioExecution(scenarioExecution); + + var restrictedScenarioAction = ScenarioActionService.restrictToDtoProperties(scenarioAction, entityManagerMock); + + var restrictedScenarioExecution = restrictedScenarioAction.getScenarioExecution(); + assertEquals(scenarioExecution.getExecutionId(), restrictedScenarioExecution.getExecutionId()); + assertEquals(scenarioExecution.getScenarioName(), restrictedScenarioExecution.getScenarioName()); + + verify(scenarioExecution, never()).getScenarioParameters(); + verify(scenarioExecution, never()).getScenarioActions(); + verify(scenarioExecution, never()).getScenarioMessages(); + + verify(entityManagerMock).detach(scenarioAction); + } + + @Test + void shouldHandleNullMessage() { + var scenarioAction = new ScenarioAction(); + + var restrictedScenarioAction = ScenarioActionService.restrictToDtoProperties(scenarioAction, entityManagerMock); + + assertNull(restrictedScenarioAction.getScenarioExecution()); + + verifyNoInteractions(entityManagerMock); + } + } +} diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java index 0ffbfdb6c..e20f60f74 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java @@ -16,6 +16,7 @@ package org.citrusframework.simulator.service.impl; +import jakarta.persistence.EntityManager; import org.citrusframework.simulator.model.Message; import org.citrusframework.simulator.model.MessageHeader; import org.citrusframework.simulator.repository.MessageHeaderRepository; @@ -42,6 +43,9 @@ @ExtendWith(MockitoExtension.class) class MessageHeaderServiceImplTest { + @Mock + private EntityManager entityManagerMock; + @Mock private MessageHeaderRepository messageHeaderRepositoryMock; @@ -59,7 +63,7 @@ void beforeEachSetup() { messageHeader.setMessage(message); messageHeaderWithMessage = spy(messageHeader); - fixture = new MessageHeaderServiceImpl(messageHeaderRepositoryMock); + fixture = new MessageHeaderServiceImpl(entityManagerMock, messageHeaderRepositoryMock); } @Test diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java index ad782be78..e673736a5 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java @@ -16,6 +16,7 @@ package org.citrusframework.simulator.service.impl; +import jakarta.persistence.EntityManager; import org.citrusframework.TestAction; import org.citrusframework.TestCase; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -47,7 +48,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentCaptor.captor; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doReturn; @@ -60,6 +60,9 @@ @ExtendWith(MockitoExtension.class) class ScenarioActionServiceImplTest { + @Mock + private EntityManager entityManagerMock; + @Mock private ScenarioActionRepository scenarioActionRepositoryMock; @@ -87,7 +90,7 @@ private static TestAction getTestActionWithName(String toBeReturned) { } @BeforeEach - void beforeEachSetup() { + void beforeEachSetup() { ScenarioAction scenarioAction = new ScenarioAction(); ScenarioExecution scenarioExecution = ScenarioExecution.builder() .executionId(1234L) @@ -99,7 +102,7 @@ void beforeEachSetup() { scenarioAction.setScenarioExecution(scenarioExecution); scenarioActionWithScenarioExecution = spy(scenarioAction); - fixture = new ScenarioActionServiceImpl(scenarioActionRepositoryMock, scenarioExecutionServiceMock); + fixture = new ScenarioActionServiceImpl(entityManagerMock, scenarioActionRepositoryMock, scenarioExecutionServiceMock); ReflectionTestUtils.setField(fixture, "timeProvider", timeProviderMock, TimeProvider.class); }