From df41cdd9db8d56985b675d3684182784582f7988 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 19 Oct 2023 18:15:35 +0200 Subject: [PATCH] feat: scenario execution read-only rest api --- .../controller/ScenarioController.java | 10 +- .../endpoint/SimulatorEndpointAdapter.java | 6 +- .../simulator/model/Message.java | 11 +- .../simulator/model/MessageHeader.java | 5 + .../simulator/model/ScenarioExecution.java | 45 +- .../simulator/model/TestParameter.java | 4 + .../simulator/model/TestResult.java | 8 +- .../repository/MessageRepository.java | 34 +- .../ScenarioExecutionRepository.java | 2 +- .../service/MessageHeaderService.java | 19 +- .../service/MessageQueryService.java | 21 + .../simulator/service/MessageService.java | 23 +- .../ScenarioExecutionQueryService.java | 120 +++++ .../service/ScenarioExecutionService.java | 163 +----- .../service/ScenarioExecutorService.java | 163 ++++++ .../service/TestParameterService.java | 2 +- .../service/criteria/MessageCriteria.java | 44 +- .../criteria/MessageHeaderCriteria.java | 6 +- .../criteria/ScenarioExecutionCriteria.java | 217 ++++++++ .../impl/MessageHeaderServiceImpl.java | 20 +- .../service/impl/MessageServiceImpl.java | 19 +- .../impl/ScenarioExecutionServiceImpl.java | 49 ++ .../web/rest/ScenarioExecutionResource.java | 88 ++++ .../service/criteria/MessageCriteriaTest.java | 145 ++++++ .../criteria/MessageHeaderCriteriaTest.java | 91 ++++ .../impl/MessageHeaderServiceImplTest.java | 79 +++ .../service/impl/MessageServiceImplTest.java | 79 +++ .../impl/TestResultServiceImplTest.java | 6 +- .../web/rest/MessageHeaderResourceIT.java | 2 +- .../simulator/web/rest/MessageResourceIT.java | 48 +- .../web/rest/ScenarioExecutionResourceIT.java | 473 ++++++++++++++++++ .../web/rest/TestParameterResourceIT.java | 2 +- .../web/rest/TestResultResourceIT.java | 2 +- simulator-ui/.jhipster/Message.json | 18 +- simulator-ui/.jhipster/ScenarioExecution.json | 47 ++ simulator-ui/.yo-rc.json | 2 +- .../app/entities/entity-routing.module.ts | 5 + .../detail/message-detail.component.html | 6 + .../message/list/message.component.html | 28 ++ .../message/list/message.component.ts | 1 + .../app/entities/message/message.model.ts | 4 + .../scenario-execution-detail.component.html | 46 ++ ...cenario-execution-detail.component.spec.ts | 38 ++ .../scenario-execution-detail.component.ts | 22 + .../list/scenario-execution.component.html | 126 +++++ .../list/scenario-execution.component.spec.ts | 125 +++++ .../list/scenario-execution.component.ts | 151 ++++++ ...-execution-routing-resolve.service.spec.ts | 99 ++++ ...nario-execution-routing-resolve.service.ts | 29 ++ .../scenario-execution.model.ts | 12 + .../scenario-execution.routes.ts | 25 + .../scenario-execution.test-samples.ts | 39 ++ .../scenario-execution.service.spec.ts | 160 ++++++ .../service/scenario-execution.service.ts | 95 ++++ .../list/test-parameter.component.html | 12 +- .../app/layouts/navbar/navbar.component.html | 16 +- .../src/main/webapp/i18n/en/global.json | 1 + .../src/main/webapp/i18n/en/message.json | 2 + .../main/webapp/i18n/en/messageHeader.json | 18 + .../webapp/i18n/en/scenarioExecution.json | 21 + .../main/webapp/i18n/en/testParameter.json | 4 +- .../src/main/webapp/i18n/en/testResult.json | 4 +- 62 files changed, 2916 insertions(+), 246 deletions(-) create mode 100644 simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java create mode 100644 simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutorService.java create mode 100644 simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java create mode 100644 simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java create mode 100644 simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResource.java create mode 100644 simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageCriteriaTest.java create mode 100644 simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteriaTest.java create mode 100644 simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java create mode 100644 simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageServiceImplTest.java create mode 100644 simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java create mode 100644 simulator-ui/.jhipster/ScenarioExecution.json create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.html create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.spec.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.html create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.spec.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.routes.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.test-samples.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.spec.ts create mode 100644 simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.ts create mode 100644 simulator-ui/src/main/webapp/i18n/en/messageHeader.json create mode 100644 simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/controller/ScenarioController.java b/simulator-starter/src/main/java/org/citrusframework/simulator/controller/ScenarioController.java index 978fb45e9..e3fe128f3 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/controller/ScenarioController.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/controller/ScenarioController.java @@ -19,7 +19,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.citrusframework.simulator.model.ScenarioParameter; -import org.citrusframework.simulator.service.ScenarioExecutionService; +import org.citrusframework.simulator.service.ScenarioExecutorService; import org.citrusframework.simulator.service.ScenarioLookupService; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; @@ -37,12 +37,12 @@ @RequestMapping("api/scenario") public class ScenarioController { - private final ScenarioExecutionService scenarioExecutionService; + private final ScenarioExecutorService scenarioExecutorService; private final ScenarioLookupService scenarioLookupService; private final List scenarios; - public ScenarioController(ScenarioExecutionService scenarioExecutionService, ScenarioLookupService scenarioLookupService) { - this.scenarioExecutionService = scenarioExecutionService; + public ScenarioController(ScenarioExecutorService scenarioExecutorService, ScenarioLookupService scenarioLookupService) { + this.scenarioExecutorService = scenarioExecutorService; this.scenarioLookupService = scenarioLookupService; this.scenarios = getScenarioList(scenarioLookupService); } @@ -93,7 +93,7 @@ public Collection getScenarioParameters(@PathVariable("name") public Long launchScenario( @PathVariable("name") String name, @RequestBody(required = false) List scenarioParameters) { - return scenarioExecutionService.run(name, scenarioParameters); + return scenarioExecutorService.run(name, scenarioParameters); } public record Scenario(String name, ScenarioController.Scenario.ScenarioType type) { diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/endpoint/SimulatorEndpointAdapter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/endpoint/SimulatorEndpointAdapter.java index 681bf4a3e..1fafd1a47 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/endpoint/SimulatorEndpointAdapter.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/endpoint/SimulatorEndpointAdapter.java @@ -22,8 +22,8 @@ import org.citrusframework.simulator.correlation.CorrelationHandler; import org.citrusframework.simulator.correlation.CorrelationHandlerRegistry; import org.citrusframework.simulator.exception.SimulatorException; +import org.citrusframework.simulator.service.ScenarioExecutorService; import org.citrusframework.simulator.scenario.SimulatorScenario; -import org.citrusframework.simulator.service.ScenarioExecutionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -51,7 +51,7 @@ public class SimulatorEndpointAdapter extends RequestDispatchingEndpointAdapter private SimulatorConfigurationProperties configuration; @Autowired - private ScenarioExecutionService scenarioExecutionService; + private ScenarioExecutorService scenarioExecutorService; /** * Spring application context @@ -106,7 +106,7 @@ public Message dispatchMessage(Message request, String mappingName) { scenario.getScenarioEndpoint().setName(scenarioName); scenario.getScenarioEndpoint().add(request, responseFuture); - scenarioExecutionService.run(scenario, scenarioName, Collections.emptyList()); + scenarioExecutorService.run(scenario, scenarioName, Collections.emptyList()); try { if (handleResponse) { diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/model/Message.java b/simulator-starter/src/main/java/org/citrusframework/simulator/model/Message.java index 637265789..22fb22884 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/model/Message.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/model/Message.java @@ -20,6 +20,7 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -28,6 +29,7 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.OrderBy; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import org.apache.commons.lang3.StringUtils; import java.io.Serial; @@ -67,10 +69,11 @@ public class Message extends AbstractAuditingEntity implements Se private String citrusMessageId; @OrderBy("name ASC") - @OneToMany(mappedBy = "message", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnoreProperties(value = { "message" }, allowSetters = true) + @OneToMany(mappedBy = "message", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) private Collection headers = new ArrayList<>(); - @ManyToOne + @ManyToOne(fetch = FetchType.EAGER) @JsonIgnoreProperties(value = {"scenarioParameters", "scenarioActions", "scenarioMessages"}, allowSetters = true) private ScenarioExecution scenarioExecution; @@ -196,6 +199,10 @@ public static class MessageBuilder extends AuditingEntityBuilder scenarioActions = new ArrayList<>(); @OrderBy("messageId ASC") - @OneToMany(mappedBy = "scenarioExecution", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "scenarioExecution", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @JsonIgnoreProperties(value = { "headers", "scenarioExecution" }, allowSetters = true) private List scenarioMessages = new ArrayList<>(); + public static ScenarioExecutionBuilder builder() { + return new ScenarioExecutionBuilder(); + } + public Long getExecutionId() { return executionId; } @@ -222,4 +228,41 @@ public ErrorMessageTruncationException(String errorMessage, Exception exception) super(errorMessage, exception); } } + + public static class ScenarioExecutionBuilder { + + private final ScenarioExecution scenarioExecution = new ScenarioExecution(); + + private ScenarioExecutionBuilder(){ + // Static access through entity + } + + public ScenarioExecution build(){ + return scenarioExecution; + } + + public ScenarioExecutionBuilder startDate(Instant startDate) { + scenarioExecution.setStartDate(startDate); + return this; + } + public ScenarioExecutionBuilder endDate(Instant endDate) { + scenarioExecution.setEndDate(endDate); + return this; + } + + public ScenarioExecutionBuilder scenarioName(String scenarioName) { + scenarioExecution.setScenarioName(scenarioName); + return this; + } + + public ScenarioExecutionBuilder status(Status status) { + scenarioExecution.setStatus(status); + return this; + } + + public ScenarioExecutionBuilder errorMessage(String errorMessage) throws ErrorMessageTruncationException { +scenarioExecution.setErrorMessage(errorMessage); + return this; + } + } } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/model/TestParameter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/model/TestParameter.java index df845955f..b5267f84f 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/model/TestParameter.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/model/TestParameter.java @@ -196,6 +196,10 @@ public static class TestParameterBuilder extends AuditingEntityBuilder impleme /** * Error message */ - @Column(updatable = false) + @Size(max = 1000) + @Column(length = 1000, updatable = false) private String errorMessage; /** @@ -233,6 +235,10 @@ public static class TestResultBuilder extends AuditingEntityBuilder, JpaSpecificationExecutor {} +public interface MessageRepository extends JpaRepository, JpaSpecificationExecutor { + + default Optional findOneWithEagerRelationships(Long id) { + return this.findOneWithToOneRelationships(id); + } + + default List findAllWithEagerRelationships() { + return this.findAllWithToOneRelationships(); + } + + default Page findAllWithEagerRelationships(Pageable pageable) { + return this.findAllWithToOneRelationships(pageable); + } + + @Query( + value = "select message from Message message left join fetch message.scenarioExecution", + countQuery = "select count(message) from Message message" + ) + Page findAllWithToOneRelationships(Pageable pageable); + + @Query("select message from Message message left join fetch message.scenarioExecution") + List findAllWithToOneRelationships(); + + @Query("select message from Message message left join fetch message.scenarioExecution where message.id =:id") + Optional findOneWithToOneRelationships(@Param("id") Long id); +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java b/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java index e072da415..701e9ac66 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Repository; /** - * Spring Data JPA repository for the {@link ScenarioExecution} entity. + * Spring Data JPA repository for the ScenarioExecution entity. */ @Repository public interface ScenarioExecutionRepository extends JpaRepository, JpaSpecificationExecutor {} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java index 8c9770639..1da54ff1d 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageHeaderService.java @@ -18,14 +18,6 @@ public interface MessageHeaderService { */ MessageHeader save(MessageHeader messageHeader); - /** - * Updates a messageHeader. - * - * @param messageHeader the entity to update. - * @return the persisted entity. - */ - MessageHeader update(MessageHeader messageHeader); - /** * Get all the messageHeaders. * @@ -45,15 +37,8 @@ public interface MessageHeaderService { /** * Get the "id" messageHeader. * - * @param id the id of the entity. + * @param headerId the id of the entity. * @return the entity. */ - Optional findOne(Long id); - - /** - * Delete the "id" messageHeader. - * - * @param id the id of the entity. - */ - void delete(Long id); + Optional findOne(Long headerId); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java index 01f3b891f..f40c18518 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java @@ -1,7 +1,10 @@ package org.citrusframework.simulator.service; +import jakarta.persistence.criteria.JoinType; import org.citrusframework.simulator.model.Message; +import org.citrusframework.simulator.model.MessageHeader_; import org.citrusframework.simulator.model.Message_; +import org.citrusframework.simulator.model.ScenarioExecution_; import org.citrusframework.simulator.repository.MessageRepository; import org.citrusframework.simulator.service.criteria.MessageCriteria; import org.slf4j.Logger; @@ -87,6 +90,24 @@ protected Specification createSpecification(MessageCriteria criteria) { if (criteria.getLastModifiedDate() != null) { specification = specification.and(buildRangeSpecification(criteria.getLastModifiedDate(), Message_.lastModifiedDate)); } + if (criteria.getHeadersId() != null) { + specification = + specification.and( + buildSpecification( + criteria.getHeadersId(), + root -> root.join(Message_.headers, JoinType.LEFT).get(MessageHeader_.headerId) + ) + ); + } + if (criteria.getScenarioExecutionId() != null) { + specification = + specification.and( + buildSpecification( + criteria.getScenarioExecutionId(), + root -> root.join(Message_.scenarioExecution, JoinType.LEFT).get(ScenarioExecution_.executionId) + ) + ); + } } return specification; } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageService.java index 6f903fb00..f89abe623 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageService.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/MessageService.java @@ -18,14 +18,6 @@ public interface MessageService { */ Message save(Message message); - /** - * Updates a message. - * - * @param message the entity to update. - * @return the persisted entity. - */ - Message update(Message message); - /** * Get all the messages. * @@ -35,17 +27,18 @@ public interface MessageService { Page findAll(Pageable pageable); /** - * Get the "id" message. + * Get all the messages with eager load of many-to-many relationships. * - * @param id the id of the entity. - * @return the entity. + * @param pageable the pagination information. + * @return the list of entities. */ - Optional findOne(Long id); + Page findAllWithEagerRelationships(Pageable pageable); /** - * Delete the "id" message. + * Get the "id" message. * - * @param id the id of the entity. + * @param messageId the id of the entity. + * @return the entity. */ - void delete(Long id); + Optional findOne(Long messageId); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java new file mode 100644 index 000000000..02f921335 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java @@ -0,0 +1,120 @@ +package org.citrusframework.simulator.service; + +import jakarta.persistence.criteria.JoinType; +import org.citrusframework.simulator.model.Message_; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.model.ScenarioExecution_; +import org.citrusframework.simulator.repository.ScenarioExecutionRepository; +import org.citrusframework.simulator.service.criteria.ScenarioExecutionCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * Service for executing complex queries for {@link ScenarioExecution} entities in the database. + * The main input is a {@link ScenarioExecutionCriteria} which gets converted to {@link Specification}, + * in a way that all the filters must apply. + * It returns a {@link List} of {@link ScenarioExecution} or a {@link Page} of {@link ScenarioExecution} which fulfills the criteria. + */ +@Service +@Transactional(readOnly = true) +public class ScenarioExecutionQueryService extends QueryService { + + private final Logger log = LoggerFactory.getLogger(ScenarioExecutionQueryService.class); + + private final ScenarioExecutionRepository scenarioExecutionRepository; + + public ScenarioExecutionQueryService(ScenarioExecutionRepository scenarioExecutionRepository) { + this.scenarioExecutionRepository = scenarioExecutionRepository; + } + + /** + * Return a {@link List} of {@link ScenarioExecution} which matches the criteria from the database. + * + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public List findByCriteria(ScenarioExecutionCriteria criteria) { + log.debug("find by criteria : {}", criteria); + final Specification specification = createSpecification(criteria); + return scenarioExecutionRepository.findAll(specification); + } + + /** + * Return a {@link Page} of {@link ScenarioExecution} which matches the criteria from the database. + * + * @param criteria The object which holds all the filters, which the entities should match. + * @param page The page, which should be returned. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public Page findByCriteria(ScenarioExecutionCriteria criteria, Pageable page) { + log.debug("find by criteria : {}, page: {}", criteria, page); + final Specification specification = createSpecification(criteria); + return scenarioExecutionRepository.findAll(specification, page); + } + + /** + * Return the number of matching entities in the database. + * + * @param criteria The object which holds all the filters, which the entities should match. + * @return the number of matching entities. + */ + @Transactional(readOnly = true) + public long countByCriteria(ScenarioExecutionCriteria criteria) { + log.debug("count by criteria : {}", criteria); + final Specification specification = createSpecification(criteria); + return scenarioExecutionRepository.count(specification); + } + + /** + * Function to convert {@link ScenarioExecutionCriteria} to a {@link Specification} + * + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching {@link Specification} of the entity. + */ + protected Specification createSpecification(ScenarioExecutionCriteria criteria) { + Specification specification = Specification.where(null); + if (criteria != null) { + // This has to be called first, because the distinct method returns null + if (criteria.getDistinct() != null) { + specification = specification.and(distinct(criteria.getDistinct())); + } + if (criteria.getExecutionId() != null) { + specification = specification.and(buildRangeSpecification(criteria.getExecutionId(), ScenarioExecution_.executionId)); + } + if (criteria.getStartDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getStartDate(), ScenarioExecution_.startDate)); + } + if (criteria.getEndDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getEndDate(), ScenarioExecution_.endDate)); + } + if (criteria.getScenarioName() != null) { + specification = specification.and(buildStringSpecification(criteria.getScenarioName(), ScenarioExecution_.scenarioName)); + } + if (criteria.getStatus() != null) { + specification = specification.and(buildRangeSpecification(criteria.getStatus(), ScenarioExecution_.status)); + } + if (criteria.getErrorMessage() != null) { + specification = specification.and(buildStringSpecification(criteria.getErrorMessage(), ScenarioExecution_.errorMessage)); + } + if (criteria.getScenarioMessagesId() != null) { + specification = + specification.and( + buildSpecification( + criteria.getScenarioMessagesId(), + root -> root.join(ScenarioExecution_.scenarioMessages, JoinType.LEFT).get(Message_.messageId) + ) + ); + } + } + return specification; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java index 8a4f0e5be..27b884568 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java @@ -1,166 +1,37 @@ -/* - * Copyright 2006-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package org.citrusframework.simulator.service; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import org.citrusframework.Citrus; -import org.citrusframework.annotations.CitrusAnnotations; -import org.citrusframework.context.TestContext; -import org.citrusframework.simulator.config.SimulatorConfigurationProperties; -import org.citrusframework.simulator.exception.SimulatorException; import org.citrusframework.simulator.model.ScenarioExecution; -import org.citrusframework.simulator.model.ScenarioParameter; -import org.citrusframework.simulator.scenario.ScenarioRunner; -import org.citrusframework.simulator.scenario.SimulatorScenario; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextClosedEvent; -import org.springframework.stereotype.Service; -import org.springframework.util.ReflectionUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; +import java.util.Optional; /** - * Service capable of executing test executables. The service takes care on setting up the executable before execution. Service - * gets a list of normalized parameters which has to be translated to setters on the test executable instance before execution. - * - * @author Christoph Deppisch + * Service Interface for managing {@link ScenarioExecution}. */ -@Service -public class ScenarioExecutionService implements DisposableBean, ApplicationListener { - private static final Logger LOG = LoggerFactory.getLogger(ScenarioExecutionService.class); - - private final ActivityService activityService; - private final ApplicationContext applicationContext; - private final Citrus citrus; - - private final ExecutorService executorService; - - @Autowired - public ScenarioExecutionService(ActivityService activityService, ApplicationContext applicationContext, - Citrus citrus, SimulatorConfigurationProperties properties) { - this.activityService = activityService; - this.applicationContext = applicationContext; - this.citrus = citrus; - - this.executorService = Executors.newFixedThreadPool( - properties.getExecutorThreads(), - new ThreadFactoryBuilder() - .setDaemon(true) - .setNameFormat("execution-svc-thread-%d") - .build() - ); - } +public interface ScenarioExecutionService { /** - * Starts a new scenario instance using the collection of supplied parameters. + * Save a scenarioExecution. * - * @param name the name of the scenario to start - * @param scenarioParameters the list of parameters to pass to the scenario when starting + * @param scenarioExecution the entity to save. + * @return the persisted entity. */ - public final Long run(String name, List scenarioParameters) { - return run(applicationContext.getBean(name, SimulatorScenario.class), name, scenarioParameters); - } + ScenarioExecution save(ScenarioExecution scenarioExecution); /** - * Starts a new scenario instance using the collection of supplied parameters. + * Get all the scenarioExecutions. * - * @param scenario the scenario to start - * @param name the name of the scenario to start - * @param scenarioParameters the list of parameters to pass to the scenario when starting + * @param pageable the pagination information. + * @return the list of entities. */ - public final Long run(SimulatorScenario scenario, String name, List scenarioParameters) { - LOG.info(String.format("Starting scenario : %s", name)); - - ScenarioExecution es = activityService.createExecutionScenario(name, scenarioParameters); - - prepare(scenario); - - startScenarioAsync(es.getExecutionId(), name, scenario, scenarioParameters); - - return es.getExecutionId(); - } - - private Future startScenarioAsync(Long executionId, String name, SimulatorScenario scenario, List scenarioParameters) { - return executorService.submit(() -> { - try { - TestContext context = citrus.getCitrusContext().createTestContext(); - ReflectionUtils.doWithMethods(scenario.getClass(), m -> { - if (m.getDeclaringClass().equals(SimulatorScenario.class)) { - // no need to execute the default run implementations - return; - } - - if (m.getParameterCount() != 1) { - throw new SimulatorException("Invalid scenario method signature - expect single method parameter but got: " + m.getParameterCount()); - } - - Class parameterType = m.getParameterTypes()[0]; - if (parameterType.equals(ScenarioRunner.class)) { - ScenarioRunner runner = new ScenarioRunner(scenario.getScenarioEndpoint(), applicationContext, context); - if (scenarioParameters != null) { - scenarioParameters.forEach(p -> runner.variable(p.getName(), p.getValue())); - } - - runner.variable(ScenarioExecution.EXECUTION_ID, executionId); - runner.name(String.format("Scenario(%s)", name)); - - CitrusAnnotations.injectAll(scenario, citrus, context); - - try { - runner.start(); - ReflectionUtils.invokeMethod(m, scenario, runner); - } finally { - runner.stop(); - } - } else { - throw new SimulatorException("Invalid scenario method parameter type: " + parameterType); - } - }, method -> method.getName().equals("run")); - LOG.debug(String.format("Scenario completed: '%s'", name)); - } catch (Exception e) { - LOG.error(String.format("Scenario completed with error: '%s'", name), e); - } - }); - } + Page findAll(Pageable pageable); /** - * Prepare scenario instance before execution. Subclasses can add custom preparation steps in here. + * Get the "id" scenarioExecution. * - * @param scenario + * @param id the id of the entity. + * @return the entity. */ - protected void prepare(SimulatorScenario scenario) { - } - - @Override - public void destroy() { - executorService.shutdownNow(); - } - - @Override - public void onApplicationEvent(ContextClosedEvent event) { - executorService.shutdownNow(); - } + Optional findOne(Long id); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutorService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutorService.java new file mode 100644 index 000000000..72171bccf --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioExecutorService.java @@ -0,0 +1,163 @@ +/* + * Copyright 2006-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.simulator.service; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.citrusframework.Citrus; +import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.context.TestContext; +import org.citrusframework.simulator.config.SimulatorConfigurationProperties; +import org.citrusframework.simulator.exception.SimulatorException; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.model.ScenarioParameter; +import org.citrusframework.simulator.scenario.ScenarioRunner; +import org.citrusframework.simulator.scenario.SimulatorScenario; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * Service capable of executing test executables. The service takes care on setting up the executable before execution. Service + * gets a list of normalized parameters which has to be translated to setters on the test executable instance before execution. + * + * @author Christoph Deppisch + */ +@Service +public class ScenarioExecutorService implements DisposableBean, ApplicationListener { + + private static final Logger logger = LoggerFactory.getLogger(ScenarioExecutorService.class); + + private final ActivityService activityService; + private final ApplicationContext applicationContext; + private final Citrus citrus; + + private final ExecutorService executorService; + + public ScenarioExecutorService(ActivityService activityService, ApplicationContext applicationContext, Citrus citrus, SimulatorConfigurationProperties properties) { + this.activityService = activityService; + this.applicationContext = applicationContext; + this.citrus = citrus; + + this.executorService = Executors.newFixedThreadPool( + properties.getExecutorThreads(), + new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("execution-svc-thread-%d") + .build() + ); + } + + /** + * Starts a new scenario instance using the collection of supplied parameters. + * + * @param name the name of the scenario to start + * @param scenarioParameters the list of parameters to pass to the scenario when starting + */ + public final Long run(String name, List scenarioParameters) { + return run(applicationContext.getBean(name, SimulatorScenario.class), name, scenarioParameters); + } + + /** + * Starts a new scenario instance using the collection of supplied parameters. + * + * @param scenario the scenario to start + * @param name the name of the scenario to start + * @param scenarioParameters the list of parameters to pass to the scenario when starting + */ + public final Long run(SimulatorScenario scenario, String name, List scenarioParameters) { + logger.info(String.format("Starting scenario : %s", name)); + + ScenarioExecution scenarioExecution = activityService.createExecutionScenario(name, scenarioParameters); + + prepareBeforeExecution(scenario); + + startScenarioAsync(scenarioExecution.getExecutionId(), name, scenario, scenarioParameters); + + return scenarioExecution.getExecutionId(); + } + + private Future startScenarioAsync(Long executionId, String name, SimulatorScenario scenario, List scenarioParameters) { + return executorService.submit(() -> { + try { + TestContext context = citrus.getCitrusContext().createTestContext(); + ReflectionUtils.doWithMethods(scenario.getClass(), method -> { + if (method.getDeclaringClass().equals(SimulatorScenario.class)) { + // no need to execute the default run implementations + return; + } + + if (method.getParameterCount() != 1) { + throw new SimulatorException("Invalid scenario method signature - expect single method parameter but got: " + method.getParameterCount()); + } + + Class parameterType = method.getParameterTypes()[0]; + if (parameterType.equals(ScenarioRunner.class)) { + ScenarioRunner runner = new ScenarioRunner(scenario.getScenarioEndpoint(), applicationContext, context); + if (scenarioParameters != null) { + scenarioParameters.forEach(p -> runner.variable(p.getName(), p.getValue())); + } + + runner.variable(ScenarioExecution.EXECUTION_ID, executionId); + runner.name(String.format("Scenario(%s)", name)); + + CitrusAnnotations.injectAll(scenario, citrus, context); + + try { + runner.start(); + ReflectionUtils.invokeMethod(method, scenario, runner); + } finally { + runner.stop(); + } + } else { + throw new SimulatorException("Invalid scenario method parameter type: " + parameterType); + } + }, method -> method.getName().equals("run")); + logger.debug(String.format("Scenario completed: '%s'", name)); + } catch (Exception e) { + logger.error(String.format("Scenario completed with error: '%s'", name), e); + } + }); + } + + /** + * Prepare scenario instance before execution. Subclasses can add custom preparation steps in here. + * + * @param scenario + */ + protected void prepareBeforeExecution(SimulatorScenario scenario) { + } + + @Override + public void destroy() throws Exception { + executorService.shutdownNow(); + } + + @Override + public void onApplicationEvent(ContextClosedEvent event) { + executorService.shutdownNow(); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/TestParameterService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/TestParameterService.java index 71ed7efe1..c01f3de90 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/TestParameterService.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/TestParameterService.java @@ -29,7 +29,7 @@ public interface TestParameterService { /** * Get the "id" testParameter. * - * @param id the id of the entity. + * @param testResultId the id of the entity. * @return the entity. */ Optional findOne(Long testResultId, String key); diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageCriteria.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageCriteria.java index b2a0371a3..4713fa1e9 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageCriteria.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageCriteria.java @@ -35,6 +35,10 @@ public class MessageCriteria implements Serializable, Criteria { private StringFilter citrusMessageId; + private LongFilter headersId; + + private LongFilter scenarioExecutionId; + private InstantFilter createdDate; private InstantFilter lastModifiedDate; @@ -49,6 +53,8 @@ public MessageCriteria(MessageCriteria other) { this.direction = other.direction == null ? null : other.direction.copy(); this.payload = other.payload == null ? null : other.payload.copy(); this.citrusMessageId = other.citrusMessageId == null ? null : other.citrusMessageId.copy(); + this.headersId = other.headersId == null ? null : other.headersId.copy(); + this.scenarioExecutionId = other.scenarioExecutionId == null ? null : other.scenarioExecutionId.copy(); this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); this.distinct = other.distinct; @@ -63,7 +69,7 @@ public LongFilter getMessageId() { return messageId; } - public LongFilter id() { + public LongFilter messageId() { if (messageId == null) { messageId = new LongFilter(); } @@ -119,6 +125,36 @@ public void setCitrusMessageId(StringFilter citrusMessageId) { this.citrusMessageId = citrusMessageId; } + public LongFilter getHeadersId() { + return headersId; + } + + public LongFilter headersId() { + if (headersId == null) { + headersId = new LongFilter(); + } + return headersId; + } + + public void setHeadersId(LongFilter headersId) { + this.headersId = headersId; + } + + public LongFilter getScenarioExecutionId() { + return scenarioExecutionId; + } + + public LongFilter scenarioExecutionId() { + if (scenarioExecutionId == null) { + scenarioExecutionId = new LongFilter(); + } + return scenarioExecutionId; + } + + public void setScenarioExecutionId(LongFilter scenarioExecutionId) { + this.scenarioExecutionId = scenarioExecutionId; + } + public InstantFilter getCreatedDate() { return createdDate; } @@ -171,6 +207,8 @@ public boolean equals(Object o) { Objects.equals(direction, that.direction) && Objects.equals(payload, that.payload) && Objects.equals(citrusMessageId, that.citrusMessageId) && + Objects.equals(headersId, that.headersId) && + Objects.equals(scenarioExecutionId, that.scenarioExecutionId) && Objects.equals(createdDate, that.createdDate) && Objects.equals(lastModifiedDate, that.lastModifiedDate) && Objects.equals(distinct, that.distinct) @@ -179,7 +217,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(messageId, direction, payload, citrusMessageId, createdDate, lastModifiedDate, distinct); + return Objects.hash(messageId, direction, payload, citrusMessageId, headersId, scenarioExecutionId, createdDate, lastModifiedDate, distinct); } // prettier-ignore @@ -190,6 +228,8 @@ public String toString() { (direction != null ? "direction=" + direction + ", " : "") + (payload != null ? "payload=" + payload + ", " : "") + (citrusMessageId != null ? "citrusMessageId=" + citrusMessageId + ", " : "") + + (headersId != null ? "headersId=" + headersId + ", " : "") + + (scenarioExecutionId != null ? "scenarioExecutionId=" + scenarioExecutionId + ", " : "") + (createdDate != null ? "createdDate=" + createdDate + ", " : "") + (lastModifiedDate != null ? "lastModifiedDate=" + lastModifiedDate + ", " : "") + (distinct != null ? "distinct=" + distinct + ", " : "") + diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteria.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteria.java index 63ee9df72..cb98aa3ac 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteria.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteria.java @@ -9,8 +9,8 @@ /** * Criteria class for the {@link org.citrusframework.simulator.model.MessageHeader} entity. This class is used - * in {@link org.citrusframework.simulator.web.rest.MessageHeaderResource} to receive all the possible filtering options from - * the Http GET request parameters. + * in {@link org.citrusframework.simulator.web.rest.MessageHeaderResource} to receive all the possible filtering options + * from the Http GET request parameters. *

* For example the following could be a valid request: * {@code /message-headers?id.greaterThan=5&attr1.contains=something&attr2.specified=false} @@ -54,7 +54,7 @@ public LongFilter getHeaderId() { return headerId; } - public LongFilter id() { + public LongFilter headerId() { if (headerId == null) { headerId = new LongFilter(); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java new file mode 100644 index 000000000..a234fee96 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java @@ -0,0 +1,217 @@ +package org.citrusframework.simulator.service.criteria; + +import org.citrusframework.simulator.service.filter.InstantFilter; +import org.citrusframework.simulator.service.filter.IntegerFilter; +import org.citrusframework.simulator.service.filter.LongFilter; +import org.citrusframework.simulator.service.filter.StringFilter; +import org.springdoc.core.annotations.ParameterObject; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Criteria class for the {@link org.citrusframework.simulator.model.ScenarioExecution} entity. This class is used + * in {@link org.citrusframework.simulator.web.rest.ScenarioExecutionResource} to receive all the possible filtering + * options from the Http GET request parameters. + *

+ * For example the following could be a valid request: + * {@code /scenario-executions?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + *

+ * As Spring is unable to properly convert the types, unless + * specific {@link org.citrusframework.simulator.service.filter.Filter} class are used, we need to use fix type + * specific filters. + */ +@ParameterObject +@SuppressWarnings("common-java:DuplicatedBlocks") +public class ScenarioExecutionCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private LongFilter executionId; + + private InstantFilter startDate; + + private InstantFilter endDate; + + private StringFilter scenarioName; + + private IntegerFilter status; + + private StringFilter errorMessage; + + private LongFilter scenarioMessagesId; + + private Boolean distinct; + + public ScenarioExecutionCriteria() {} + + public ScenarioExecutionCriteria(ScenarioExecutionCriteria other) { + this.executionId = other.executionId == null ? null : other.executionId.copy(); + this.startDate = other.startDate == null ? null : other.startDate.copy(); + this.endDate = other.endDate == null ? null : other.endDate.copy(); + this.scenarioName = other.scenarioName == null ? null : other.scenarioName.copy(); + this.status = other.status == null ? null : other.status.copy(); + this.errorMessage = other.errorMessage == null ? null : other.errorMessage.copy(); + this.scenarioMessagesId = other.scenarioMessagesId == null ? null : other.scenarioMessagesId.copy(); + this.distinct = other.distinct; + } + + @Override + public ScenarioExecutionCriteria copy() { + return new ScenarioExecutionCriteria(this); + } + + public LongFilter getExecutionId() { + return executionId; + } + + public LongFilter id() { + if (executionId == null) { + executionId = new LongFilter(); + } + return executionId; + } + + public void setExecutionId(LongFilter executionId) { + this.executionId = executionId; + } + + public InstantFilter getStartDate() { + return startDate; + } + + public InstantFilter startDate() { + if (startDate == null) { + startDate = new InstantFilter(); + } + return startDate; + } + + public void setStartDate(InstantFilter startDate) { + this.startDate = startDate; + } + + public InstantFilter getEndDate() { + return endDate; + } + + public InstantFilter endDate() { + if (endDate == null) { + endDate = new InstantFilter(); + } + return endDate; + } + + public void setEndDate(InstantFilter endDate) { + this.endDate = endDate; + } + + public StringFilter getScenarioName() { + return scenarioName; + } + + public StringFilter scenarioName() { + if (scenarioName == null) { + scenarioName = new StringFilter(); + } + return scenarioName; + } + + public void setScenarioName(StringFilter scenarioName) { + this.scenarioName = scenarioName; + } + + public IntegerFilter getStatus() { + return status; + } + + public IntegerFilter status() { + if (status == null) { + status = new IntegerFilter(); + } + return status; + } + + public void setStatus(IntegerFilter status) { + this.status = status; + } + + public StringFilter getErrorMessage() { + return errorMessage; + } + + public StringFilter errorMessage() { + if (errorMessage == null) { + errorMessage = new StringFilter(); + } + return errorMessage; + } + + public void setErrorMessage(StringFilter errorMessage) { + this.errorMessage = errorMessage; + } + + public LongFilter getScenarioMessagesId() { + return scenarioMessagesId; + } + + public LongFilter scenarioMessagesId() { + if (scenarioMessagesId == null) { + scenarioMessagesId = new LongFilter(); + } + return scenarioMessagesId; + } + + public void setScenarioMessagesId(LongFilter scenarioMessagesId) { + this.scenarioMessagesId = scenarioMessagesId; + } + + public Boolean getDistinct() { + return distinct; + } + + public void setDistinct(Boolean distinct) { + this.distinct = distinct; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ScenarioExecutionCriteria that = (ScenarioExecutionCriteria) o; + return ( + Objects.equals(executionId, that.executionId) && + Objects.equals(startDate, that.startDate) && + Objects.equals(endDate, that.endDate) && + Objects.equals(scenarioName, that.scenarioName) && + Objects.equals(status, that.status) && + Objects.equals(errorMessage, that.errorMessage) && + Objects.equals(scenarioMessagesId, that.scenarioMessagesId) && + Objects.equals(distinct, that.distinct) + ); + } + + @Override + public int hashCode() { + return Objects.hash(executionId, startDate, endDate, scenarioName, status, errorMessage, scenarioMessagesId, distinct); + } + + // prettier-ignore + @Override + public String toString() { + return "ScenarioExecutionCriteria{" + + (executionId != null ? "id=" + executionId + ", " : "") + + (startDate != null ? "startDate=" + startDate + ", " : "") + + (endDate != null ? "endDate=" + endDate + ", " : "") + + (scenarioName != null ? "scenarioName=" + scenarioName + ", " : "") + + (status != null ? "status=" + status + ", " : "") + + (errorMessage != null ? "errorMessage=" + errorMessage + ", " : "") + + (scenarioMessagesId != null ? "scenarioMessagesId=" + scenarioMessagesId + ", " : "") + + (distinct != null ? "distinct=" + distinct + ", " : "") + + "}"; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java index 015803d42..020be13ed 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java @@ -33,12 +33,6 @@ public MessageHeader save(MessageHeader messageHeader) { return messageHeaderRepository.save(messageHeader); } - @Override - public MessageHeader update(MessageHeader messageHeader) { - log.debug("Request to update MessageHeader : {}", messageHeader); - return messageHeaderRepository.save(messageHeader); - } - @Override @Transactional(readOnly = true) public Page findAll(Pageable pageable) { @@ -46,20 +40,16 @@ public Page findAll(Pageable pageable) { return messageHeaderRepository.findAll(pageable); } + @Override + @Transactional(readOnly = true) public Page findAllWithEagerRelationships(Pageable pageable) { return messageHeaderRepository.findAllWithEagerRelationships(pageable); } @Override @Transactional(readOnly = true) - public Optional findOne(Long id) { - log.debug("Request to get MessageHeader : {}", id); - return messageHeaderRepository.findOneWithEagerRelationships(id); - } - - @Override - public void delete(Long id) { - log.debug("Request to delete MessageHeader : {}", id); - messageHeaderRepository.deleteById(id); + public Optional findOne(Long headerId) { + log.debug("Request to get MessageHeader : {}", headerId); + return messageHeaderRepository.findOneWithEagerRelationships(headerId); } } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java index 728e172e0..ee5b288c4 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java @@ -33,12 +33,6 @@ public Message save(Message message) { return messageRepository.save(message); } - @Override - public Message update(Message message) { - log.debug("Request to update Message : {}", message); - return messageRepository.save(message); - } - @Override @Transactional(readOnly = true) public Page findAll(Pageable pageable) { @@ -48,14 +42,15 @@ public Page findAll(Pageable pageable) { @Override @Transactional(readOnly = true) - public Optional findOne(Long id) { - log.debug("Request to get Message : {}", id); - return messageRepository.findById(id); + public Page findAllWithEagerRelationships(Pageable pageable) { + log.debug("Request to get all Messages with eager relationships"); + return messageRepository.findAllWithEagerRelationships(pageable); } @Override - public void delete(Long id) { - log.debug("Request to delete Message : {}", id); - messageRepository.deleteById(id); + @Transactional(readOnly = true) + public Optional findOne(Long messageId) { + log.debug("Request to get Message : {}", messageId); + return messageRepository.findOneWithEagerRelationships(messageId); } } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java new file mode 100644 index 000000000..7a2e32f0b --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java @@ -0,0 +1,49 @@ +package org.citrusframework.simulator.service.impl; + +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.repository.ScenarioExecutionRepository; +import org.citrusframework.simulator.service.ScenarioExecutionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +/** + * Service Implementation for managing {@link ScenarioExecution}. + */ +@Service +@Transactional +public class ScenarioExecutionServiceImpl implements ScenarioExecutionService { + + private final Logger log = LoggerFactory.getLogger(ScenarioExecutionServiceImpl.class); + + private final ScenarioExecutionRepository scenarioExecutionRepository; + + public ScenarioExecutionServiceImpl(ScenarioExecutionRepository scenarioExecutionRepository) { + this.scenarioExecutionRepository = scenarioExecutionRepository; + } + + @Override + public ScenarioExecution save(ScenarioExecution scenarioExecution) { + log.debug("Request to save ScenarioExecution : {}", scenarioExecution); + return scenarioExecutionRepository.save(scenarioExecution); + } + + @Override + @Transactional(readOnly = true) + public Page findAll(Pageable pageable) { + log.debug("Request to get all ScenarioExecutions"); + return scenarioExecutionRepository.findAll(pageable); + } + + @Override + @Transactional(readOnly = true) + public Optional findOne(Long id) { + log.debug("Request to get ScenarioExecution : {}", id); + return scenarioExecutionRepository.findById(id); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResource.java b/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResource.java new file mode 100644 index 000000000..3f7f4b525 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResource.java @@ -0,0 +1,88 @@ +package org.citrusframework.simulator.web.rest; + +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.service.ScenarioExecutionQueryService; +import org.citrusframework.simulator.service.ScenarioExecutionService; +import org.citrusframework.simulator.service.criteria.ScenarioExecutionCriteria; +import org.citrusframework.simulator.web.util.PaginationUtil; +import org.citrusframework.simulator.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing {@link ScenarioExecution}. + */ +@RestController +@RequestMapping("/api") +public class ScenarioExecutionResource { + + private final Logger log = LoggerFactory.getLogger(ScenarioExecutionResource.class); + + private final ScenarioExecutionService scenarioExecutionService; + + private final ScenarioExecutionQueryService scenarioExecutionQueryService; + + public ScenarioExecutionResource( + ScenarioExecutionService scenarioExecutionService, + ScenarioExecutionQueryService scenarioExecutionQueryService + ) { + this.scenarioExecutionService = scenarioExecutionService; + this.scenarioExecutionQueryService = scenarioExecutionQueryService; + } + + /** + * {@code GET /scenario-executions} : get all the scenarioExecutions. + * + * @param pageable the pagination information. + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of scenarioExecutions in body. + */ + @GetMapping("/scenario-executions") + public ResponseEntity> getAllScenarioExecutions( + ScenarioExecutionCriteria criteria, + @org.springdoc.core.annotations.ParameterObject Pageable pageable + ) { + log.debug("REST request to get ScenarioExecutions by criteria: {}", criteria); + + Page page = scenarioExecutionQueryService.findByCriteria(criteria, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); + return ResponseEntity.ok().headers(headers).body(page.getContent()); + } + + /** + * {@code GET /scenario-executions/count} : count all the scenarioExecutions. + * + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the count in body. + */ + @GetMapping("/scenario-executions/count") + public ResponseEntity countScenarioExecutions(ScenarioExecutionCriteria criteria) { + log.debug("REST request to count ScenarioExecutions by criteria: {}", criteria); + return ResponseEntity.ok().body(scenarioExecutionQueryService.countByCriteria(criteria)); + } + + /** + * {@code GET /scenario-executions/:id} : get the "id" scenarioExecution. + * + * @param id the id of the scenarioExecution to retrieve. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the scenarioExecution, or with status {@code 404 (Not Found)}. + */ + @GetMapping("/scenario-executions/{id}") + public ResponseEntity getScenarioExecution(@PathVariable Long id) { + log.debug("REST request to get ScenarioExecution : {}", id); + Optional scenarioExecution = scenarioExecutionService.findOne(id); + return ResponseUtil.wrapOrNotFound(scenarioExecution); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageCriteriaTest.java b/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageCriteriaTest.java new file mode 100644 index 000000000..afb05d9a2 --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageCriteriaTest.java @@ -0,0 +1,145 @@ +package org.citrusframework.simulator.service.criteria; + +import org.citrusframework.simulator.service.filter.InstantFilter; +import org.citrusframework.simulator.service.filter.IntegerFilter; +import org.citrusframework.simulator.service.filter.LongFilter; +import org.citrusframework.simulator.service.filter.StringFilter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class MessageCriteriaTest { + + private MessageCriteria fixture; + + @BeforeEach + void beforeEachSetup() { + fixture = new MessageCriteria(); + } + + @Test + void testMessageId() { + assertNull(fixture.getMessageId()); + + LongFilter messageIdFilter = fixture.messageId(); + assertNotNull(messageIdFilter); + assertSame(messageIdFilter, fixture.getMessageId()); + + LongFilter mockMessageIdFilter = mock(LongFilter.class); + fixture.setMessageId(mockMessageIdFilter); + assertSame(mockMessageIdFilter, fixture.messageId()); + } + + @Test + void testDirection() { + assertNull(fixture.getDirection()); + + IntegerFilter directionFilter = fixture.direction(); + assertNotNull(directionFilter); + assertSame(directionFilter, fixture.getDirection()); + + IntegerFilter mockDirectionFilter = mock(IntegerFilter.class); + fixture.setDirection(mockDirectionFilter); + assertSame(mockDirectionFilter, fixture.direction()); + } + + @Test + void testPayload() { + assertNull(fixture.getPayload()); + + StringFilter payloadFilter = fixture.payload(); + assertNotNull(payloadFilter); + assertSame(payloadFilter, fixture.getPayload()); + + StringFilter mockPayloadFilter = mock(StringFilter.class); + fixture.setPayload(mockPayloadFilter); + assertSame(mockPayloadFilter, fixture.payload()); + } + + @Test + void testCitrusMessageId() { + assertNull(fixture.getCitrusMessageId()); + + StringFilter citrusMessageIdFilter = fixture.citrusMessageId(); + assertNotNull(citrusMessageIdFilter); + assertSame(citrusMessageIdFilter, fixture.getCitrusMessageId()); + + StringFilter mockCitrusMessageIdFilter = mock(StringFilter.class); + fixture.setCitrusMessageId(mockCitrusMessageIdFilter); + assertSame(mockCitrusMessageIdFilter, fixture.citrusMessageId()); + } + + @Test + void testHeadersId() { + assertNull(fixture.getHeadersId()); + + LongFilter headersIdFilter = fixture.headersId(); + assertNotNull(headersIdFilter); + assertSame(headersIdFilter, fixture.getHeadersId()); + + LongFilter mockHeadersIdFilter = mock(LongFilter.class); + fixture.setHeadersId(mockHeadersIdFilter); + assertSame(mockHeadersIdFilter, fixture.headersId()); + } + + @Test + void testScenarioExecutionId() { + assertNull(fixture.getScenarioExecutionId()); + + LongFilter scenarioExecutionIdFilter = fixture.scenarioExecutionId(); + assertNotNull(scenarioExecutionIdFilter); + assertSame(scenarioExecutionIdFilter, fixture.getScenarioExecutionId()); + + LongFilter mockScenarioExecutionIdFilter = mock(LongFilter.class); + fixture.setScenarioExecutionId(mockScenarioExecutionIdFilter); + assertSame(mockScenarioExecutionIdFilter, fixture.scenarioExecutionId()); + } + + @Test + void testCreatedDate() { + assertNull(fixture.getCreatedDate()); + + InstantFilter createdDateFilter = fixture.createdDate(); + assertNotNull(createdDateFilter); + assertSame(createdDateFilter, fixture.getCreatedDate()); + + InstantFilter mockCreatedDateFilter = mock(InstantFilter.class); + fixture.setCreatedDate(mockCreatedDateFilter); + assertSame(mockCreatedDateFilter, fixture.createdDate()); + } + + @Test + void testLastModifiedDate() { + assertNull(fixture.getLastModifiedDate()); + + InstantFilter lastModifiedDateFilter = fixture.lastModifiedDate(); + assertNotNull(lastModifiedDateFilter); + assertSame(lastModifiedDateFilter, fixture.getLastModifiedDate()); + + InstantFilter mockLastModifiedDateFilter = mock(InstantFilter.class); + fixture.setLastModifiedDate(mockLastModifiedDateFilter); + assertSame(mockLastModifiedDateFilter, fixture.lastModifiedDate()); + } + + @Test + void testDistinct() { + assertNull(fixture.getDistinct()); + + fixture.setDistinct(true); + assertTrue(fixture.getDistinct()); + } + + @Test + void testCopy() { + MessageCriteria copiedCriteria = fixture.copy(); + assertNotSame(copiedCriteria, fixture); + assertEquals(copiedCriteria, fixture); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteriaTest.java b/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteriaTest.java new file mode 100644 index 000000000..9ea963afb --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/service/criteria/MessageHeaderCriteriaTest.java @@ -0,0 +1,91 @@ +package org.citrusframework.simulator.service.criteria; + +import org.citrusframework.simulator.service.filter.LongFilter; +import org.citrusframework.simulator.service.filter.StringFilter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class MessageHeaderCriteriaTest { + + private MessageHeaderCriteria fixture; + + @BeforeEach + void beforeEachSetup() { + fixture = new MessageHeaderCriteria(); + } + + @Test + void testHeaderId() { + assertNull(fixture.getHeaderId()); + + LongFilter headerIdFilter = fixture.headerId(); + assertNotNull(headerIdFilter); + assertSame(headerIdFilter, fixture.getHeaderId()); + + LongFilter mockHeaderIdFilter = mock(LongFilter.class); + fixture.setHeaderId(mockHeaderIdFilter); + assertSame(mockHeaderIdFilter, fixture.headerId()); + } + + @Test + void testName() { + assertNull(fixture.getName()); + + StringFilter nameFilter = fixture.name(); + assertNotNull(nameFilter); + assertSame(nameFilter, fixture.getName()); + + StringFilter mockNameFilter = mock(StringFilter.class); + fixture.setName(mockNameFilter); + assertSame(mockNameFilter, fixture.name()); + } + + @Test + void testValue() { + assertNull(fixture.getValue()); + + StringFilter valueFilter = fixture.value(); + assertNotNull(valueFilter); + assertSame(valueFilter, fixture.getValue()); + + StringFilter mockValueFilter = mock(StringFilter.class); + fixture.setValue(mockValueFilter); + assertSame(mockValueFilter, fixture.value()); + } + + @Test + void testMessageId() { + assertNull(fixture.getMessageId()); + + LongFilter messageIdFilter = fixture.messageId(); + assertNotNull(messageIdFilter); + assertSame(messageIdFilter, fixture.getMessageId()); + + LongFilter mockMessageIdFilter = mock(LongFilter.class); + fixture.setMessageId(mockMessageIdFilter); + assertSame(mockMessageIdFilter, fixture.messageId()); + } + + @Test + void testDistinct() { + assertNull(fixture.getDistinct()); + + fixture.setDistinct(true); + assertTrue(fixture.getDistinct()); + } + + @Test + void testCopy() { + MessageHeaderCriteria copiedCriteria = fixture.copy(); + assertNotSame(copiedCriteria, fixture); + assertEquals(copiedCriteria, fixture); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java new file mode 100644 index 000000000..ee1d404d5 --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImplTest.java @@ -0,0 +1,79 @@ +package org.citrusframework.simulator.service.impl; + +import org.citrusframework.simulator.model.MessageHeader; +import org.citrusframework.simulator.repository.MessageHeaderRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class MessageHeaderServiceImplTest { + + @Mock + private MessageHeaderRepository messageHeaderRepositoryMock; + + private MessageHeaderServiceImpl fixture; + + @BeforeEach + void beforeEachSetup() { + fixture = new MessageHeaderServiceImpl(messageHeaderRepositoryMock); + } + + @Test + void testSave() { + MessageHeader messageHeader = new MessageHeader(); + + when(messageHeaderRepositoryMock.save(messageHeader)).thenReturn(messageHeader); + + MessageHeader savedMessageHeader = fixture.save(messageHeader); + assertEquals(messageHeader, savedMessageHeader); + } + + @Test + void testFindAll() { + Pageable pageable = Pageable.unpaged(); + Page mockPage = mock(Page.class); + + when(messageHeaderRepositoryMock.findAll(pageable)).thenReturn(mockPage); + + Page result = fixture.findAll(pageable); + + assertEquals(mockPage, result); + } + + @Test + void testFindAllWithEagerRelationships() { + Pageable pageable = Pageable.unpaged(); + Page mockPage = mock(Page.class); + + when(messageHeaderRepositoryMock.findAllWithEagerRelationships(pageable)).thenReturn(mockPage); + + Page result = fixture.findAllWithEagerRelationships(pageable); + + assertEquals(mockPage, result); + } + + @Test + void testFindOne() { + Long messageId = 1L; + MessageHeader messageHeader = new MessageHeader(); + + when(messageHeaderRepositoryMock.findOneWithEagerRelationships(messageId)).thenReturn(Optional.of(messageHeader)); + + Optional maybeMessageHeader = fixture.findOne(messageId); + + assertTrue(maybeMessageHeader.isPresent()); + assertEquals(messageHeader, maybeMessageHeader.get()); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageServiceImplTest.java b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageServiceImplTest.java new file mode 100644 index 000000000..27357c03e --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/MessageServiceImplTest.java @@ -0,0 +1,79 @@ +package org.citrusframework.simulator.service.impl; + +import org.citrusframework.simulator.model.Message; +import org.citrusframework.simulator.repository.MessageRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class MessageServiceImplTest { + + @Mock + private MessageRepository messageRepositoryMock; + + private MessageServiceImpl fixture; + + @BeforeEach + void beforeEachSetup() { + fixture = new MessageServiceImpl(messageRepositoryMock); + } + + @Test + void testSave() { + Message message = new Message(); + + when(messageRepositoryMock.save(message)).thenReturn(message); + + Message savedMessage = fixture.save(message); + assertEquals(message, savedMessage); + } + + @Test + void testFindAll() { + Pageable pageable = Pageable.unpaged(); + Page mockPage = mock(Page.class); + + when(messageRepositoryMock.findAll(pageable)).thenReturn(mockPage); + + Page result = fixture.findAll(pageable); + + assertEquals(mockPage, result); + } + + @Test + void testFindAllWithEagerRelationships() { + Pageable pageable = Pageable.unpaged(); + Page mockPage = mock(Page.class); + + when(messageRepositoryMock.findAllWithEagerRelationships(pageable)).thenReturn(mockPage); + + Page result = fixture.findAllWithEagerRelationships(pageable); + + assertEquals(mockPage, result); + } + + @Test + void testFindOne() { + Long messageId = 1L; + Message message = new Message(); + + when(messageRepositoryMock.findOneWithEagerRelationships(messageId)).thenReturn(Optional.of(message)); + + Optional maybeMessage = fixture.findOne(messageId); + + assertTrue(maybeMessage.isPresent()); + assertEquals(message, maybeMessage.get()); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java index 3fe38c220..704283a85 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java @@ -57,12 +57,12 @@ void testSave() { @Test void testFindAll() { Pageable pageable = mock(Pageable.class); - Page page = mock(Page.class); - doReturn(page).when(testResultRepository).findAll(pageable); + Page mockPage = mock(Page.class); + doReturn(mockPage).when(testResultRepository).findAll(pageable); Page result = fixture.findAll(pageable); - assertEquals(page, result); + assertEquals(mockPage, result); } @Test diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java index 4b39c9b42..8ab471d5e 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java @@ -114,7 +114,7 @@ public static MessageHeader createUpdatedEntity(EntityManager entityManager) { } @BeforeEach - public void initTest() { + void beforeEachSetup() { messageHeader = createEntity(entityManager); } diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageResourceIT.java index e0cb69dce..694fce426 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageResourceIT.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageResourceIT.java @@ -3,6 +3,8 @@ import jakarta.persistence.EntityManager; import org.citrusframework.simulator.IntegrationTest; import org.citrusframework.simulator.model.Message; +import org.citrusframework.simulator.model.MessageHeader; +import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.repository.MessageRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -95,7 +97,7 @@ public static Message createUpdatedEntity(EntityManager entityManager) { } @BeforeEach - public void initTest() { + void beforeEachSetup() { message = createEntity(entityManager); } @@ -324,6 +326,50 @@ void getAllMessagesByCitrusMessageIdNotContainsSomething() throws Exception { defaultMessageShouldBeFound("citrusMessageId.doesNotContain=" + UPDATED_CITRUS_MESSAGE_ID); } + @Test + @Transactional + void getAllMessagesByHeadersIsEqualToSomething() throws Exception { + MessageHeader messageHeader; + if (TestUtil.findAll(entityManager, MessageHeader.class).isEmpty()) { + messageRepository.saveAndFlush(message); + messageHeader = MessageHeaderResourceIT.createEntity(entityManager); + } else { + messageHeader = TestUtil.findAll(entityManager, MessageHeader.class).get(0); + } + entityManager.persist(messageHeader); + entityManager.flush(); + message.addHeader(messageHeader); + messageRepository.saveAndFlush(message); + Long headersId = messageHeader.getHeaderId(); + // Get all the messageList where headers equals to headersId + defaultMessageShouldBeFound("headersId.equals=" + headersId); + + // Get all the messageList where headers equals to (headersId + 1) + defaultMessageShouldNotBeFound("headersId.equals=" + (headersId + 1)); + } + + @Test + @Transactional + void getAllMessagesByScenarioExecutionIsEqualToSomething() throws Exception { + ScenarioExecution scenarioExecution; + if (TestUtil.findAll(entityManager, ScenarioExecution.class).isEmpty()) { + messageRepository.saveAndFlush(message); + scenarioExecution = ScenarioExecutionResourceIT.createEntity(entityManager); + } else { + scenarioExecution = TestUtil.findAll(entityManager, ScenarioExecution.class).get(0); + } + entityManager.persist(scenarioExecution); + entityManager.flush(); + message.setScenarioExecution(scenarioExecution); + messageRepository.saveAndFlush(message); + Long scenarioExecutionId = scenarioExecution.getExecutionId(); + // Get all the messageList where scenarioExecution equals to scenarioExecutionId + defaultMessageShouldBeFound("scenarioExecutionId.equals=" + scenarioExecutionId); + + // Get all the messageList where scenarioExecution equals to (scenarioExecutionId + 1) + defaultMessageShouldNotBeFound("scenarioExecutionId.equals=" + (scenarioExecutionId + 1)); + } + @Test @Transactional void getAllMessagesByCreatedDateIsEqualToSomething() throws Exception { diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java new file mode 100644 index 000000000..dc6e236c1 --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java @@ -0,0 +1,473 @@ +package org.citrusframework.simulator.web.rest; + +import jakarta.persistence.EntityManager; +import org.citrusframework.simulator.IntegrationTest; +import org.citrusframework.simulator.model.Message; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.repository.ScenarioExecutionRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Integration tests for the {@link ScenarioExecutionResource} REST controller. + */ +@IntegrationTest +@AutoConfigureMockMvc +class ScenarioExecutionResourceIT { + + private static final Instant DEFAULT_START_DATE = Instant.ofEpochMilli(0L); + private static final Instant UPDATED_START_DATE = Instant.now().truncatedTo(ChronoUnit.MILLIS); + + private static final Instant DEFAULT_END_DATE = Instant.ofEpochMilli(0L); + private static final Instant UPDATED_END_DATE = Instant.now().truncatedTo(ChronoUnit.MILLIS); + + private static final String DEFAULT_SCENARIO_NAME = "AAAAAAAAAA"; + private static final String UPDATED_SCENARIO_NAME = "BBBBBBBBBB"; + + private static final ScenarioExecution.Status DEFAULT_STATUS = ScenarioExecution.Status.RUNNING; // Integer value: 1 + private static final ScenarioExecution.Status UPDATED_STATUS = ScenarioExecution.Status.SUCCESS; // Integer value: 2 + + private static final String DEFAULT_ERROR_MESSAGE = "AAAAAAAAAA"; + private static final String UPDATED_ERROR_MESSAGE = "BBBBBBBBBB"; + + private static final String ENTITY_API_URL = "/api/scenario-executions"; + private static final String ENTITY_API_URL_ID = ENTITY_API_URL + "/{id}"; + + @Autowired + private ScenarioExecutionRepository scenarioExecutionRepository; + + @Autowired + private EntityManager entityManager; + + @Autowired + private MockMvc restScenarioExecutionMockMvc; + + private ScenarioExecution scenarioExecution; + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static ScenarioExecution createEntity(EntityManager entityManager) throws ScenarioExecution.ErrorMessageTruncationException { + ScenarioExecution scenarioExecution = ScenarioExecution.builder() + .startDate(DEFAULT_START_DATE) + .endDate(DEFAULT_END_DATE) + .scenarioName(DEFAULT_SCENARIO_NAME) + .status(DEFAULT_STATUS) + .errorMessage(DEFAULT_ERROR_MESSAGE) + .build(); + return scenarioExecution; + } + + /** + * Create an updated entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static ScenarioExecution createUpdatedEntity(EntityManager entityManager) throws ScenarioExecution.ErrorMessageTruncationException { + ScenarioExecution scenarioExecution = ScenarioExecution.builder() + .startDate(UPDATED_START_DATE) + .endDate(UPDATED_END_DATE) + .scenarioName(UPDATED_SCENARIO_NAME) + .status(UPDATED_STATUS) + .errorMessage(UPDATED_ERROR_MESSAGE) + .build(); + return scenarioExecution; + } + + @BeforeEach + void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException { + scenarioExecution = createEntity(entityManager); + } + + @Test + @Transactional + void getAllScenarioExecutions() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL + "?sort=executionId,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.[*].executionId").value(hasItem(scenarioExecution.getExecutionId().intValue()))) + .andExpect(jsonPath("$.[*].startDate").value(hasItem(DEFAULT_START_DATE.toString()))) + .andExpect(jsonPath("$.[*].endDate").value(hasItem(DEFAULT_END_DATE.toString()))) + .andExpect(jsonPath("$.[*].scenarioName").value(hasItem(DEFAULT_SCENARIO_NAME))) + .andExpect(jsonPath("$.[*].status").value(hasItem(DEFAULT_STATUS.toString()))) + .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(DEFAULT_ERROR_MESSAGE))); + } + + @Test + @Transactional + void getScenarioExecution() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get the scenarioExecution + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL_ID, scenarioExecution.getExecutionId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.executionId").value(scenarioExecution.getExecutionId().intValue())) + .andExpect(jsonPath("$.startDate").value(DEFAULT_START_DATE.toString())) + .andExpect(jsonPath("$.endDate").value(DEFAULT_END_DATE.toString())) + .andExpect(jsonPath("$.scenarioName").value(DEFAULT_SCENARIO_NAME)) + .andExpect(jsonPath("$.status").value(DEFAULT_STATUS.toString())) + .andExpect(jsonPath("$.errorMessage").value(DEFAULT_ERROR_MESSAGE)); + } + + @Test + @Transactional + void getScenarioExecutionsByIdFiltering() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + Long executionId = scenarioExecution.getExecutionId(); + + defaultScenarioExecutionShouldBeFound("executionId.equals=" + executionId); + defaultScenarioExecutionShouldNotBeFound("executionId.notEquals=" + executionId); + + defaultScenarioExecutionShouldBeFound("executionId.greaterThanOrEqual=" + executionId); + defaultScenarioExecutionShouldNotBeFound("executionId.greaterThan=" + executionId); + + defaultScenarioExecutionShouldBeFound("executionId.lessThanOrEqual=" + executionId); + defaultScenarioExecutionShouldNotBeFound("executionId.lessThan=" + executionId); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStartDateIsEqualToSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where startDate equals to DEFAULT_START_DATE + defaultScenarioExecutionShouldBeFound("startDate.equals=" + DEFAULT_START_DATE); + + // Get all the scenarioExecutionList where startDate equals to UPDATED_START_DATE + defaultScenarioExecutionShouldNotBeFound("startDate.equals=" + UPDATED_START_DATE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStartDateIsInShouldWork() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where startDate in DEFAULT_START_DATE or UPDATED_START_DATE + defaultScenarioExecutionShouldBeFound("startDate.in=" + DEFAULT_START_DATE + "," + UPDATED_START_DATE); + + // Get all the scenarioExecutionList where startDate equals to UPDATED_START_DATE + defaultScenarioExecutionShouldNotBeFound("startDate.in=" + UPDATED_START_DATE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStartDateIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where startDate is not null + defaultScenarioExecutionShouldBeFound("startDate.specified=true"); + + // Get all the scenarioExecutionList where startDate is null + defaultScenarioExecutionShouldNotBeFound("startDate.specified=false"); + } + + @Test + @Transactional + void getAllScenarioExecutionsByEndDateIsEqualToSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where endDate equals to DEFAULT_END_DATE + defaultScenarioExecutionShouldBeFound("endDate.equals=" + DEFAULT_END_DATE); + + // Get all the scenarioExecutionList where endDate equals to UPDATED_END_DATE + defaultScenarioExecutionShouldNotBeFound("endDate.equals=" + UPDATED_END_DATE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByEndDateIsInShouldWork() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where endDate in DEFAULT_END_DATE or UPDATED_END_DATE + defaultScenarioExecutionShouldBeFound("endDate.in=" + DEFAULT_END_DATE + "," + UPDATED_END_DATE); + + // Get all the scenarioExecutionList where endDate equals to UPDATED_END_DATE + defaultScenarioExecutionShouldNotBeFound("endDate.in=" + UPDATED_END_DATE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByEndDateIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where endDate is not null + defaultScenarioExecutionShouldBeFound("endDate.specified=true"); + + // Get all the scenarioExecutionList where endDate is null + defaultScenarioExecutionShouldNotBeFound("endDate.specified=false"); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioNameIsEqualToSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where scenarioName equals to DEFAULT_SCENARIO_NAME + defaultScenarioExecutionShouldBeFound("scenarioName.equals=" + DEFAULT_SCENARIO_NAME); + + // Get all the scenarioExecutionList where scenarioName equals to UPDATED_SCENARIO_NAME + defaultScenarioExecutionShouldNotBeFound("scenarioName.equals=" + UPDATED_SCENARIO_NAME); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioNameIsInShouldWork() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where scenarioName in DEFAULT_SCENARIO_NAME or UPDATED_SCENARIO_NAME + defaultScenarioExecutionShouldBeFound("scenarioName.in=" + DEFAULT_SCENARIO_NAME + "," + UPDATED_SCENARIO_NAME); + + // Get all the scenarioExecutionList where scenarioName equals to UPDATED_SCENARIO_NAME + defaultScenarioExecutionShouldNotBeFound("scenarioName.in=" + UPDATED_SCENARIO_NAME); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioNameIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where scenarioName is not null + defaultScenarioExecutionShouldBeFound("scenarioName.specified=true"); + + // Get all the scenarioExecutionList where scenarioName is null + defaultScenarioExecutionShouldNotBeFound("scenarioName.specified=false"); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioNameContainsSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where scenarioName contains DEFAULT_SCENARIO_NAME + defaultScenarioExecutionShouldBeFound("scenarioName.contains=" + DEFAULT_SCENARIO_NAME); + + // Get all the scenarioExecutionList where scenarioName contains UPDATED_SCENARIO_NAME + defaultScenarioExecutionShouldNotBeFound("scenarioName.contains=" + UPDATED_SCENARIO_NAME); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioNameNotContainsSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where scenarioName does not contain DEFAULT_SCENARIO_NAME + defaultScenarioExecutionShouldNotBeFound("scenarioName.doesNotContain=" + DEFAULT_SCENARIO_NAME); + + // Get all the scenarioExecutionList where scenarioName does not contain UPDATED_SCENARIO_NAME + defaultScenarioExecutionShouldBeFound("scenarioName.doesNotContain=" + UPDATED_SCENARIO_NAME); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStatusIsEqualToSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where status equals to DEFAULT_STATUS + defaultScenarioExecutionShouldBeFound("status.equals=" + DEFAULT_STATUS.getId()); + + // Get all the scenarioExecutionList where status equals to UPDATED_STATUS + defaultScenarioExecutionShouldNotBeFound("status.equals=" + UPDATED_STATUS.getId()); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStatusIsInShouldWork() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where status in DEFAULT_STATUS or UPDATED_STATUS + defaultScenarioExecutionShouldBeFound("status.in=" + DEFAULT_STATUS.getId() + "," + UPDATED_STATUS.getId()); + + // Get all the scenarioExecutionList where status equals to UPDATED_STATUS + defaultScenarioExecutionShouldNotBeFound("status.in=" + UPDATED_STATUS.getId()); + } + + @Test + @Transactional + void getAllScenarioExecutionsByStatusIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where status is not null + defaultScenarioExecutionShouldBeFound("status.specified=true"); + + // Get all the scenarioExecutionList where status is null + defaultScenarioExecutionShouldNotBeFound("status.specified=false"); + } + + @Test + @Transactional + void getAllScenarioExecutionsByErrorMessageIsEqualToSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where errorMessage equals to DEFAULT_ERROR_MESSAGE + defaultScenarioExecutionShouldBeFound("errorMessage.equals=" + DEFAULT_ERROR_MESSAGE); + + // Get all the scenarioExecutionList where errorMessage equals to UPDATED_ERROR_MESSAGE + defaultScenarioExecutionShouldNotBeFound("errorMessage.equals=" + UPDATED_ERROR_MESSAGE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByErrorMessageIsInShouldWork() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where errorMessage in DEFAULT_ERROR_MESSAGE or UPDATED_ERROR_MESSAGE + defaultScenarioExecutionShouldBeFound("errorMessage.in=" + DEFAULT_ERROR_MESSAGE + "," + UPDATED_ERROR_MESSAGE); + + // Get all the scenarioExecutionList where errorMessage equals to UPDATED_ERROR_MESSAGE + defaultScenarioExecutionShouldNotBeFound("errorMessage.in=" + UPDATED_ERROR_MESSAGE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByErrorMessageIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where errorMessage is not null + defaultScenarioExecutionShouldBeFound("errorMessage.specified=true"); + + // Get all the scenarioExecutionList where errorMessage is null + defaultScenarioExecutionShouldNotBeFound("errorMessage.specified=false"); + } + + @Test + @Transactional + void getAllScenarioExecutionsByErrorMessageContainsSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where errorMessage contains DEFAULT_ERROR_MESSAGE + defaultScenarioExecutionShouldBeFound("errorMessage.contains=" + DEFAULT_ERROR_MESSAGE); + + // Get all the scenarioExecutionList where errorMessage contains UPDATED_ERROR_MESSAGE + defaultScenarioExecutionShouldNotBeFound("errorMessage.contains=" + UPDATED_ERROR_MESSAGE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByErrorMessageNotContainsSomething() throws Exception { + // Initialize the database + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + + // Get all the scenarioExecutionList where errorMessage does not contain DEFAULT_ERROR_MESSAGE + defaultScenarioExecutionShouldNotBeFound("errorMessage.doesNotContain=" + DEFAULT_ERROR_MESSAGE); + + // Get all the scenarioExecutionList where errorMessage does not contain UPDATED_ERROR_MESSAGE + defaultScenarioExecutionShouldBeFound("errorMessage.doesNotContain=" + UPDATED_ERROR_MESSAGE); + } + + @Test + @Transactional + void getAllScenarioExecutionsByScenarioMessagesIsEqualToSomething() throws Exception { + Message scenarioMessages; + if (TestUtil.findAll(entityManager, Message.class).isEmpty()) { + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + scenarioMessages = MessageResourceIT.createEntity(entityManager); + } else { + scenarioMessages = TestUtil.findAll(entityManager, Message.class).get(0); + } + entityManager.persist(scenarioMessages); + entityManager.flush(); + scenarioExecution.addScenarioMessage(scenarioMessages); + scenarioExecutionRepository.saveAndFlush(scenarioExecution); + Long scenarioMessagesId = scenarioMessages.getMessageId(); + // Get all the scenarioExecutionList where scenarioMessages equals to scenarioMessagesId + defaultScenarioExecutionShouldBeFound("scenarioMessagesId.equals=" + scenarioMessagesId); + + // Get all the scenarioExecutionList where scenarioMessages equals to (scenarioMessagesId + 1) + defaultScenarioExecutionShouldNotBeFound("scenarioMessagesId.equals=" + (scenarioMessagesId + 1)); + } + + /** + * Executes the search, and checks that the default entity is returned. + */ + private void defaultScenarioExecutionShouldBeFound(String filter) throws Exception { + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL + "?sort=executionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.[*].executionId").value(hasItem(scenarioExecution.getExecutionId().intValue()))) + .andExpect(jsonPath("$.[*].startDate").value(hasItem(DEFAULT_START_DATE.toString()))) + .andExpect(jsonPath("$.[*].endDate").value(hasItem(DEFAULT_END_DATE.toString()))) + .andExpect(jsonPath("$.[*].scenarioName").value(hasItem(DEFAULT_SCENARIO_NAME))) + .andExpect(jsonPath("$.[*].status").value(hasItem(DEFAULT_STATUS.toString()))) + .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(DEFAULT_ERROR_MESSAGE))); + + // Check, that the count call also returns 1 + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL + "/count?sort=executionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(content().string("1")); + } + + /** + * Executes the search, and checks that the default entity is not returned. + */ + private void defaultScenarioExecutionShouldNotBeFound(String filter) throws Exception { + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL + "?sort=executionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$").isEmpty()); + + // Check, that the count call also returns 0 + restScenarioExecutionMockMvc + .perform(get(ENTITY_API_URL + "/count?sort=executionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(content().string("0")); + } + + @Test + @Transactional + void getNonExistingScenarioExecution() throws Exception { + // Get the scenarioExecution + restScenarioExecutionMockMvc.perform(get(ENTITY_API_URL_ID, Long.MAX_VALUE)).andExpect(status().isNotFound()); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestParameterResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestParameterResourceIT.java index 757fbb22b..d1fe991e1 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestParameterResourceIT.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestParameterResourceIT.java @@ -89,7 +89,7 @@ public static TestParameter createEntity(EntityManager entityManager) { } @BeforeEach - public void initTest() { + void beforeEachSetup() { testParameter = createEntity(entityManager); } diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java index cde75bb60..1bbf380a4 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java @@ -92,7 +92,7 @@ public static TestResult createEntity(EntityManager entityManager) { } @BeforeEach - public void initTest() { + void beforeEachSetup() { testResult = createEntity(entityManager); } diff --git a/simulator-ui/.jhipster/Message.json b/simulator-ui/.jhipster/Message.json index f1178273e..ad158ef01 100644 --- a/simulator-ui/.jhipster/Message.json +++ b/simulator-ui/.jhipster/Message.json @@ -32,7 +32,23 @@ "name": "Message", "pagination": "pagination", "readOnly": true, - "relationships": [], + "relationships": [ + { + "otherEntityName": "messageHeader", + "otherEntityRelationshipName": "message", + "relationshipName": "headers", + "relationshipSide": "left", + "relationshipType": "one-to-many" + }, + { + "otherEntityField": "scenarioName", + "otherEntityName": "scenarioExecution", + "relationshipName": "scenarioExecution", + "relationshipSide": "left", + "relationshipType": "many-to-one", + "relationshipValidateRules": ["required"] + } + ], "searchEngine": "no", "service": "serviceImpl" } diff --git a/simulator-ui/.jhipster/ScenarioExecution.json b/simulator-ui/.jhipster/ScenarioExecution.json new file mode 100644 index 000000000..c6d35ac9f --- /dev/null +++ b/simulator-ui/.jhipster/ScenarioExecution.json @@ -0,0 +1,47 @@ +{ + "changelogDate": "20231019152955", + "dto": "no", + "entityTableName": "scenario_execution", + "fields": [ + { + "fieldName": "startDate", + "fieldType": "Instant", + "fieldValidateRules": ["required"] + }, + { + "fieldName": "endDate", + "fieldType": "Instant" + }, + { + "fieldName": "scenarioName", + "fieldType": "String", + "fieldValidateRules": ["required"] + }, + { + "fieldName": "status", + "fieldType": "Integer", + "fieldValidateRules": ["required"] + }, + { + "fieldName": "errorMessage", + "fieldType": "String", + "fieldValidateRules": [] + } + ], + "jpaMetamodelFiltering": true, + "name": "ScenarioExecution", + "pagination": "pagination", + "readOnly": true, + "relationships": [ + { + "otherEntityName": "message", + "otherEntityRelationshipName": "scenarioExecution", + "relationshipName": "scenarioMessages", + "relationshipSide": "left", + "relationshipType": "one-to-many", + "relationshipValidateRules": ["required"] + } + ], + "searchEngine": "no", + "service": "serviceImpl" +} diff --git a/simulator-ui/.yo-rc.json b/simulator-ui/.yo-rc.json index cc688dbb5..101abee13 100644 --- a/simulator-ui/.yo-rc.json +++ b/simulator-ui/.yo-rc.json @@ -8,7 +8,7 @@ "creationTimestamp": 1694794967405, "devServerPort": 4200, "enableTranslation": true, - "entities": ["TestParameter", "TestResult", "Message"], + "entities": ["Message", "MessageHeader", "ScenarioExecution", "TestParameter", "TestResult"], "jhipsterVersion": "8.0.0-beta.3", "languages": ["en"], "microfrontend": false, diff --git a/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts b/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts index 6581c76d0..626121297 100644 --- a/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts +++ b/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts @@ -14,6 +14,11 @@ import { RouterModule } from '@angular/router'; data: { pageTitle: 'citrusSimulatorApp.messageHeader.home.title' }, loadChildren: () => import('./message-header/message-header.routes'), }, + { + path: 'scenario-execution', + data: { pageTitle: 'citrusSimulatorApp.scenarioExecution.home.title' }, + loadChildren: () => import('./scenario-execution/scenario-execution.routes'), + }, { path: 'test-parameter', data: { pageTitle: 'citrusSimulatorApp.testParameter.home.title' }, diff --git a/simulator-ui/src/main/webapp/app/entities/message/detail/message-detail.component.html b/simulator-ui/src/main/webapp/app/entities/message/detail/message-detail.component.html index 609b86b27..3de3fc491 100644 --- a/simulator-ui/src/main/webapp/app/entities/message/detail/message-detail.component.html +++ b/simulator-ui/src/main/webapp/app/entities/message/detail/message-detail.component.html @@ -26,6 +26,12 @@

Scenario Execution +
+ +
Created Date
{{ message.createdDate | formatMediumDatetime }} diff --git a/simulator-ui/src/main/webapp/app/entities/message/list/message.component.html b/simulator-ui/src/main/webapp/app/entities/message/list/message.component.html index 602603772..109593fac 100644 --- a/simulator-ui/src/main/webapp/app/entities/message/list/message.component.html +++ b/simulator-ui/src/main/webapp/app/entities/message/list/message.component.html @@ -48,6 +48,12 @@

+ +
+ Scenario Execution + +
+
Created Date @@ -71,10 +77,32 @@

{{ message.direction }} {{ message.payload }} {{ message.citrusMessageId }} + + + {{ message.createdDate | formatMediumDatetime }} {{ message.lastModifiedDate | formatMediumDatetime }}
+ +
+

+ diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.spec.ts new file mode 100644 index 000000000..4a49415db --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.spec.ts @@ -0,0 +1,38 @@ +import { TestBed } from '@angular/core/testing'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; +import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { ScenarioExecutionDetailComponent } from './scenario-execution-detail.component'; + +describe('ScenarioExecution Management Detail Component', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ScenarioExecutionDetailComponent, RouterTestingModule.withRoutes([], { bindToComponentInputs: true })], + providers: [ + provideRouter( + [ + { + path: '**', + component: ScenarioExecutionDetailComponent, + resolve: { scenarioExecution: () => of({ executionId: 123 }) }, + }, + ], + withComponentInputBinding(), + ), + ], + }) + .overrideTemplate(ScenarioExecutionDetailComponent, '') + .compileComponents(); + }); + + describe('OnInit', () => { + it('Should load scenarioExecution on init', async () => { + const harness = await RouterTestingHarness.create(); + const instance = await harness.navigateByUrl('/', ScenarioExecutionDetailComponent); + + // THEN + expect(instance.scenarioExecution).toEqual(expect.objectContaining({ executionId: 123 })); + }); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.ts new file mode 100644 index 000000000..c21b382de --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.ts @@ -0,0 +1,22 @@ +import { Component, Input } from '@angular/core'; +import { ActivatedRoute, RouterModule } from '@angular/router'; + +import SharedModule from 'app/shared/shared.module'; +import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; +import { IScenarioExecution } from '../scenario-execution.model'; + +@Component({ + standalone: true, + selector: 'jhi-scenario-execution-detail', + templateUrl: './scenario-execution-detail.component.html', + imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], +}) +export class ScenarioExecutionDetailComponent { + @Input() scenarioExecution: IScenarioExecution | null = null; + + constructor(protected activatedRoute: ActivatedRoute) {} + + previousState(): void { + window.history.back(); + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.html b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.html new file mode 100644 index 000000000..4491dff9b --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.html @@ -0,0 +1,126 @@ +
+

+ Scenario Executions + +
+ +
+

+ + + + + + + +
+ No Scenario Executions found +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ ID + +
+
+
+ Start Date + +
+
+
+ End Date + +
+
+
+ Status + +
+
+
+ Scenario Name + +
+
+
+ Error Message + +
+
+ {{ scenarioExecution.executionId }} + {{ scenarioExecution.startDate | formatMediumDatetime }}{{ scenarioExecution.endDate | formatMediumDatetime }}{{ scenarioExecution.scenarioName }}{{ scenarioExecution.status }}{{ scenarioExecution.errorMessage }} +
+ + +
+
+
+ +
+
+ +
+ +
+ +
+
+
diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts new file mode 100644 index 000000000..944017929 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts @@ -0,0 +1,125 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRoute } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { ScenarioExecutionService } from '../service/scenario-execution.service'; + +import { ScenarioExecutionComponent } from './scenario-execution.component'; +import SpyInstance = jest.SpyInstance; + +describe('ScenarioExecution Management Component', () => { + let comp: ScenarioExecutionComponent; + let fixture: ComponentFixture; + let service: ScenarioExecutionService; + let routerNavigateSpy: SpyInstance>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([{ path: 'scenario-execution', component: ScenarioExecutionComponent }]), + HttpClientTestingModule, + ScenarioExecutionComponent, + ], + providers: [ + { + provide: ActivatedRoute, + useValue: { + data: of({ + defaultSort: 'executionId,asc', + }), + queryParamMap: of( + jest.requireActual('@angular/router').convertToParamMap({ + page: '1', + size: '1', + sort: 'executionId,desc', + 'filter[someId.in]': 'dc4279ea-cfb9-11ec-9d64-0242ac120002', + }), + ), + snapshot: { queryParams: {} }, + }, + }, + ], + }) + .overrideTemplate(ScenarioExecutionComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(ScenarioExecutionComponent); + comp = fixture.componentInstance; + service = TestBed.inject(ScenarioExecutionService); + routerNavigateSpy = jest.spyOn(comp.router, 'navigate'); + + const headers = new HttpHeaders(); + jest.spyOn(service, 'query').mockReturnValue( + of( + new HttpResponse({ + body: [{ executionId: 123 }], + headers, + }), + ), + ); + }); + + it('Should call load all on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.scenarioExecutions?.[0]).toEqual(expect.objectContaining({ executionId: 123 })); + }); + + describe('trackId', () => { + it('Should forward to scenarioExecutionService', () => { + const entity = { executionId: 123 }; + jest.spyOn(service, 'getScenarioExecutionIdentifier'); + const executionId = comp.trackId(0, entity); + expect(service.getScenarioExecutionIdentifier).toHaveBeenCalledWith(entity); + expect(executionId).toBe(entity.executionId); + }); + }); + + it('should load a page', () => { + // WHEN + comp.navigateToPage(1); + + // THEN + expect(routerNavigateSpy).toHaveBeenCalled(); + }); + + it('should calculate the sort attribute for an executionId', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['executionId,desc'] })); + }); + + it('should calculate the sort attribute for a non-id attribute', () => { + // GIVEN + comp.predicate = 'name'; + + // WHEN + comp.navigateToWithComponentValues(); + + // THEN + expect(routerNavigateSpy).toHaveBeenLastCalledWith( + expect.anything(), + expect.objectContaining({ + queryParams: expect.objectContaining({ + sort: ['name,asc'], + }), + }), + ); + }); + + it('should calculate the filter attribute', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ 'someId.in': ['dc4279ea-cfb9-11ec-9d64-0242ac120002'] })); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.ts new file mode 100644 index 000000000..d02f05d52 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.ts @@ -0,0 +1,151 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpHeaders } from '@angular/common/http'; +import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router'; +import { combineLatest, Observable, switchMap, tap } from 'rxjs'; + +import SharedModule from 'app/shared/shared.module'; +import { SortDirective, SortByDirective } from 'app/shared/sort'; +import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; +import { ItemCountComponent } from 'app/shared/pagination'; +import { FormsModule } from '@angular/forms'; + +import { ITEMS_PER_PAGE, PAGE_HEADER, TOTAL_COUNT_RESPONSE_HEADER } from 'app/config/pagination.constants'; +import { ASC, DESC, SORT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants'; +import { FilterComponent, FilterOptions, IFilterOptions, IFilterOption } from 'app/shared/filter'; +import { EntityArrayResponseType, ScenarioExecutionService } from '../service/scenario-execution.service'; +import { IScenarioExecution } from '../scenario-execution.model'; + +@Component({ + standalone: true, + selector: 'jhi-scenario-execution', + templateUrl: './scenario-execution.component.html', + imports: [ + RouterModule, + FormsModule, + SharedModule, + SortDirective, + SortByDirective, + DurationPipe, + FormatMediumDatetimePipe, + FormatMediumDatePipe, + FilterComponent, + ItemCountComponent, + ], +}) +export class ScenarioExecutionComponent implements OnInit { + scenarioExecutions?: IScenarioExecution[]; + isLoading = false; + + predicate = 'executionId'; + ascending = true; + filters: IFilterOptions = new FilterOptions(); + + itemsPerPage = ITEMS_PER_PAGE; + totalItems = 0; + page = 1; + + constructor( + protected scenarioExecutionService: ScenarioExecutionService, + protected activatedRoute: ActivatedRoute, + public router: Router, + ) {} + + trackId = (_index: number, item: IScenarioExecution): number => this.scenarioExecutionService.getScenarioExecutionIdentifier(item); + + ngOnInit(): void { + this.load(); + + this.filters.filterChanges.subscribe(filterOptions => this.handleNavigation(1, this.predicate, this.ascending, filterOptions)); + } + + load(): void { + this.loadFromBackendWithRouteInformations().subscribe({ + next: (res: EntityArrayResponseType) => { + this.onResponseSuccess(res); + }, + }); + } + + navigateToWithComponentValues(): void { + this.handleNavigation(this.page, this.predicate, this.ascending, this.filters.filterOptions); + } + + navigateToPage(page = this.page): void { + this.handleNavigation(page, this.predicate, this.ascending, this.filters.filterOptions); + } + + protected loadFromBackendWithRouteInformations(): Observable { + return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe( + tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)), + switchMap(() => this.queryBackend(this.page, this.predicate, this.ascending, this.filters.filterOptions)), + ); + } + + protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void { + const page = params.get(PAGE_HEADER); + this.page = +(page ?? 1); + const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(','); + this.predicate = sort[0]; + this.ascending = sort[1] === ASC; + this.filters.initializeFromParams(params); + } + + protected onResponseSuccess(response: EntityArrayResponseType): void { + this.fillComponentAttributesFromResponseHeader(response.headers); + const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); + this.scenarioExecutions = dataFromBody; + } + + protected fillComponentAttributesFromResponseBody(data: IScenarioExecution[] | null): IScenarioExecution[] { + return data ?? []; + } + + protected fillComponentAttributesFromResponseHeader(headers: HttpHeaders): void { + this.totalItems = Number(headers.get(TOTAL_COUNT_RESPONSE_HEADER)); + } + + protected queryBackend( + page?: number, + predicate?: string, + ascending?: boolean, + filterOptions?: IFilterOption[], + ): Observable { + this.isLoading = true; + const pageToLoad: number = page ?? 1; + const queryObject: any = { + page: pageToLoad - 1, + size: this.itemsPerPage, + sort: this.getSortQueryParam(predicate, ascending), + }; + filterOptions?.forEach(filterOption => { + queryObject[filterOption.name] = filterOption.values; + }); + return this.scenarioExecutionService.query(queryObject).pipe(tap(() => (this.isLoading = false))); + } + + protected handleNavigation(page = this.page, predicate?: string, ascending?: boolean, filterOptions?: IFilterOption[]): void { + const queryParamsObj: any = { + page, + size: this.itemsPerPage, + sort: this.getSortQueryParam(predicate, ascending), + }; + + filterOptions?.forEach(filterOption => { + queryParamsObj[filterOption.nameAsQueryParam()] = filterOption.values; + }); + + this.router.navigate(['./'], { + relativeTo: this.activatedRoute, + queryParams: queryParamsObj, + }); + } + + protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] { + const ascendingQueryParam = ascending ? ASC : DESC; + if (predicate === '') { + return []; + } else { + return [predicate + ',' + ascendingQueryParam]; + } + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.spec.ts new file mode 100644 index 000000000..5c67493b8 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.spec.ts @@ -0,0 +1,99 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { IScenarioExecution } from '../scenario-execution.model'; +import { ScenarioExecutionService } from '../service/scenario-execution.service'; + +import scenarioExecutionResolve from './scenario-execution-routing-resolve.service'; + +describe('ScenarioExecution routing resolve service', () => { + let mockRouter: Router; + let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; + let service: ScenarioExecutionService; + let resultScenarioExecution: IScenarioExecution | null | undefined; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])], + providers: [ + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: convertToParamMap({}), + }, + }, + }, + ], + }); + mockRouter = TestBed.inject(Router); + jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); + mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot; + service = TestBed.inject(ScenarioExecutionService); + resultScenarioExecution = undefined; + }); + + describe('resolve', () => { + it('should return IScenarioExecution returned by find', () => { + // GIVEN + service.find = jest.fn(executionId => of(new HttpResponse({ body: { executionId } }))); + mockActivatedRouteSnapshot.params = { executionId: 123 }; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioExecutionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioExecution = result; + }, + }); + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultScenarioExecution).toEqual({ executionId: 123 }); + }); + + it('should return null if executionId is not provided', () => { + // GIVEN + service.find = jest.fn(); + mockActivatedRouteSnapshot.params = {}; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioExecutionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioExecution = result; + }, + }); + }); + + // THEN + expect(service.find).not.toBeCalled(); + expect(resultScenarioExecution).toEqual(null); + }); + + it('should route to 404 page if data not found in server', () => { + // GIVEN + jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null }))); + mockActivatedRouteSnapshot.params = { executionId: 123 }; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioExecutionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioExecution = result; + }, + }); + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultScenarioExecution).toEqual(undefined); + expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); + }); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.ts new file mode 100644 index 000000000..142da1ded --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/route/scenario-execution-routing-resolve.service.ts @@ -0,0 +1,29 @@ +import { inject } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { of, EMPTY, Observable } from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; + +import { IScenarioExecution } from '../scenario-execution.model'; +import { ScenarioExecutionService } from '../service/scenario-execution.service'; + +export const scenarioExecutionResolve = (route: ActivatedRouteSnapshot): Observable => { + const executionId = route.params['executionId']; + if (executionId) { + return inject(ScenarioExecutionService) + .find(executionId) + .pipe( + mergeMap((scenarioExecution: HttpResponse) => { + if (scenarioExecution.body) { + return of(scenarioExecution.body); + } else { + inject(Router).navigate(['404']); + return EMPTY; + } + }), + ); + } + return of(null); +}; + +export default scenarioExecutionResolve; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.ts new file mode 100644 index 000000000..aa2aa809e --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.ts @@ -0,0 +1,12 @@ +import dayjs from 'dayjs/esm'; + +export interface IScenarioExecution { + executionId: number; + startDate?: dayjs.Dayjs | null; + endDate?: dayjs.Dayjs | null; + scenarioName?: string | null; + status?: number | null; + errorMessage?: string | null; +} + +export type NewScenarioExecution = Omit & { executionId: null }; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.routes.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.routes.ts new file mode 100644 index 000000000..22b7c5958 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.routes.ts @@ -0,0 +1,25 @@ +import { Routes } from '@angular/router'; + +import { ASC } from 'app/config/navigation.constants'; +import { ScenarioExecutionComponent } from './list/scenario-execution.component'; +import { ScenarioExecutionDetailComponent } from './detail/scenario-execution-detail.component'; +import ScenarioExecutionResolve from './route/scenario-execution-routing-resolve.service'; + +const scenarioExecutionRoute: Routes = [ + { + path: '', + component: ScenarioExecutionComponent, + data: { + defaultSort: 'executionId,' + ASC, + }, + }, + { + path: ':executionId/view', + component: ScenarioExecutionDetailComponent, + resolve: { + scenarioExecution: ScenarioExecutionResolve, + }, + }, +]; + +export default scenarioExecutionRoute; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.test-samples.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.test-samples.ts new file mode 100644 index 000000000..3495311bc --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.test-samples.ts @@ -0,0 +1,39 @@ +import dayjs from 'dayjs/esm'; + +import { IScenarioExecution, NewScenarioExecution } from './scenario-execution.model'; + +export const sampleWithRequiredData: IScenarioExecution = { + executionId: 28068, + startDate: dayjs('2023-10-18T19:26'), + scenarioName: 'geez', + status: 31399, +}; + +export const sampleWithPartialData: IScenarioExecution = { + executionId: 6290, + startDate: dayjs('2023-10-18T20:56'), + scenarioName: 'baptise gracefully', + status: 4003, + errorMessage: 'gee sniffle bunch', +}; + +export const sampleWithFullData: IScenarioExecution = { + executionId: 29940, + startDate: dayjs('2023-10-19T02:53'), + endDate: dayjs('2023-10-18T17:11'), + scenarioName: 'midst', + status: 18914, + errorMessage: 'jiffy wherever', +}; + +export const sampleWithNewData: NewScenarioExecution = { + startDate: dayjs('2023-10-18T16:49'), + scenarioName: 'robotics', + status: 1073, + executionId: null, +}; + +Object.freeze(sampleWithNewData); +Object.freeze(sampleWithRequiredData); +Object.freeze(sampleWithPartialData); +Object.freeze(sampleWithFullData); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.spec.ts new file mode 100644 index 000000000..8b4e4c437 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.spec.ts @@ -0,0 +1,160 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +import { IScenarioExecution } from '../scenario-execution.model'; +import { sampleWithRequiredData, sampleWithPartialData, sampleWithFullData } from '../scenario-execution.test-samples'; + +import { ScenarioExecutionService, RestScenarioExecution } from './scenario-execution.service'; + +const requireRestSample: RestScenarioExecution = { + ...sampleWithRequiredData, + startDate: sampleWithRequiredData.startDate?.toJSON(), + endDate: sampleWithRequiredData.endDate?.toJSON(), +}; + +describe('ScenarioExecution Service', () => { + let service: ScenarioExecutionService; + let httpMock: HttpTestingController; + let expectedResult: IScenarioExecution | IScenarioExecution[] | boolean | null; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + }); + expectedResult = null; + service = TestBed.inject(ScenarioExecutionService); + httpMock = TestBed.inject(HttpTestingController); + }); + + describe('Service methods', () => { + it('should find an element', () => { + const returnedFromService = { ...requireRestSample }; + const expected = { ...sampleWithRequiredData }; + + service.find(123).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should return a list of ScenarioExecution', () => { + const returnedFromService = { ...requireRestSample }; + + const expected = { ...sampleWithRequiredData }; + + service.query().subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([returnedFromService]); + httpMock.verify(); + expect(expectedResult).toMatchObject([expected]); + }); + + describe('addScenarioExecutionToCollectionIfMissing', () => { + it('should add a ScenarioExecution to an empty array', () => { + const scenarioExecution: IScenarioExecution = sampleWithRequiredData; + expectedResult = service.addScenarioExecutionToCollectionIfMissing([], scenarioExecution); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(scenarioExecution); + }); + + it('should not add a ScenarioExecution to an array that contains it', () => { + const scenarioExecution: IScenarioExecution = sampleWithRequiredData; + const scenarioExecutionCollection: IScenarioExecution[] = [ + { + ...scenarioExecution, + }, + sampleWithPartialData, + ]; + expectedResult = service.addScenarioExecutionToCollectionIfMissing(scenarioExecutionCollection, scenarioExecution); + expect(expectedResult).toHaveLength(2); + }); + + it("should add a ScenarioExecution to an array that doesn't contain it", () => { + const scenarioExecution: IScenarioExecution = sampleWithRequiredData; + const scenarioExecutionCollection: IScenarioExecution[] = [sampleWithPartialData]; + expectedResult = service.addScenarioExecutionToCollectionIfMissing(scenarioExecutionCollection, scenarioExecution); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(scenarioExecution); + }); + + it('should add only unique ScenarioExecution to an array', () => { + const scenarioExecutionArray: IScenarioExecution[] = [sampleWithRequiredData, sampleWithPartialData, sampleWithFullData]; + const scenarioExecutionCollection: IScenarioExecution[] = [sampleWithRequiredData]; + expectedResult = service.addScenarioExecutionToCollectionIfMissing(scenarioExecutionCollection, ...scenarioExecutionArray); + expect(expectedResult).toHaveLength(3); + }); + + it('should accept varargs', () => { + const scenarioExecution: IScenarioExecution = sampleWithRequiredData; + const scenarioExecution2: IScenarioExecution = sampleWithPartialData; + expectedResult = service.addScenarioExecutionToCollectionIfMissing([], scenarioExecution, scenarioExecution2); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(scenarioExecution); + expect(expectedResult).toContain(scenarioExecution2); + }); + + it('should accept null and undefined values', () => { + const scenarioExecution: IScenarioExecution = sampleWithRequiredData; + expectedResult = service.addScenarioExecutionToCollectionIfMissing([], null, scenarioExecution, undefined); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(scenarioExecution); + }); + + it('should return initial array if no ScenarioExecution is added', () => { + const scenarioExecutionCollection: IScenarioExecution[] = [sampleWithRequiredData]; + expectedResult = service.addScenarioExecutionToCollectionIfMissing(scenarioExecutionCollection, undefined, null); + expect(expectedResult).toEqual(scenarioExecutionCollection); + }); + }); + + describe('compareScenarioExecution', () => { + it('Should return true if both entities are null', () => { + const entity1 = null; + const entity2 = null; + + const compareResult = service.compareScenarioExecution(entity1, entity2); + + expect(compareResult).toEqual(true); + }); + + it('Should return false if one entity is null', () => { + const entity1 = { executionId: 123 }; + const entity2 = null; + + const compareResult1 = service.compareScenarioExecution(entity1, entity2); + const compareResult2 = service.compareScenarioExecution(entity2, entity1); + + expect(compareResult1).toEqual(false); + expect(compareResult2).toEqual(false); + }); + + it('Should return false if primaryKey differs', () => { + const entity1 = { executionId: 123 }; + const entity2 = { executionId: 456 }; + + const compareResult1 = service.compareScenarioExecution(entity1, entity2); + const compareResult2 = service.compareScenarioExecution(entity2, entity1); + + expect(compareResult1).toEqual(false); + expect(compareResult2).toEqual(false); + }); + + it('Should return false if primaryKey matches', () => { + const entity1 = { executionId: 123 }; + const entity2 = { executionId: 123 }; + + const compareResult1 = service.compareScenarioExecution(entity1, entity2); + const compareResult2 = service.compareScenarioExecution(entity2, entity1); + + expect(compareResult1).toEqual(true); + expect(compareResult2).toEqual(true); + }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.ts new file mode 100644 index 000000000..f65aeae50 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/service/scenario-execution.service.ts @@ -0,0 +1,95 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { map } from 'rxjs/operators'; + +import dayjs from 'dayjs/esm'; + +import { isPresent } from 'app/core/util/operators'; +import { ApplicationConfigService } from 'app/core/config/application-config.service'; +import { createRequestOption } from 'app/core/request/request-util'; +import { IScenarioExecution, NewScenarioExecution } from '../scenario-execution.model'; + +type RestOf = Omit & { + startDate?: string | null; + endDate?: string | null; +}; + +export type RestScenarioExecution = RestOf; + +export type EntityResponseType = HttpResponse; +export type EntityArrayResponseType = HttpResponse; + +@Injectable({ providedIn: 'root' }) +export class ScenarioExecutionService { + protected resourceUrl = this.applicationConfigService.getEndpointFor('api/scenario-executions'); + + constructor( + protected http: HttpClient, + protected applicationConfigService: ApplicationConfigService, + ) {} + + find(executionId: number): Observable { + return this.http + .get(`${this.resourceUrl}/${executionId}`, { observe: 'response' }) + .pipe(map(res => this.convertResponseFromServer(res))); + } + + query(req?: any): Observable { + const options = createRequestOption(req); + return this.http + .get(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map(res => this.convertResponseArrayFromServer(res))); + } + + getScenarioExecutionIdentifier(scenarioExecution: Pick): number { + return scenarioExecution.executionId; + } + + compareScenarioExecution(o1: Pick | null, o2: Pick | null): boolean { + return o1 && o2 ? this.getScenarioExecutionIdentifier(o1) === this.getScenarioExecutionIdentifier(o2) : o1 === o2; + } + + addScenarioExecutionToCollectionIfMissing>( + scenarioExecutionCollection: Type[], + ...scenarioExecutionsToCheck: (Type | null | undefined)[] + ): Type[] { + const scenarioExecutions: Type[] = scenarioExecutionsToCheck.filter(isPresent); + if (scenarioExecutions.length > 0) { + const scenarioExecutionCollectionIdentifiers = scenarioExecutionCollection.map( + scenarioExecutionItem => this.getScenarioExecutionIdentifier(scenarioExecutionItem)!, + ); + const scenarioExecutionsToAdd = scenarioExecutions.filter(scenarioExecutionItem => { + const scenarioExecutionIdentifier = this.getScenarioExecutionIdentifier(scenarioExecutionItem); + if (scenarioExecutionCollectionIdentifiers.includes(scenarioExecutionIdentifier)) { + return false; + } + scenarioExecutionCollectionIdentifiers.push(scenarioExecutionIdentifier); + return true; + }); + return [...scenarioExecutionsToAdd, ...scenarioExecutionCollection]; + } + return scenarioExecutionCollection; + } + + protected convertDateFromServer(restScenarioExecution: RestScenarioExecution): IScenarioExecution { + return { + ...restScenarioExecution, + startDate: restScenarioExecution.startDate ? dayjs(restScenarioExecution.startDate) : undefined, + endDate: restScenarioExecution.endDate ? dayjs(restScenarioExecution.endDate) : undefined, + }; + } + + protected convertResponseFromServer(res: HttpResponse): HttpResponse { + return res.clone({ + body: res.body ? this.convertDateFromServer(res.body) : null, + }); + } + + protected convertResponseArrayFromServer(res: HttpResponse): HttpResponse { + return res.clone({ + body: res.body ? res.body.map(item => this.convertDateFromServer(item)) : null, + }); + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/test-parameter/list/test-parameter.component.html b/simulator-ui/src/main/webapp/app/entities/test-parameter/list/test-parameter.component.html index 96648b2e1..53c0aea97 100644 --- a/simulator-ui/src/main/webapp/app/entities/test-parameter/list/test-parameter.component.html +++ b/simulator-ui/src/main/webapp/app/entities/test-parameter/list/test-parameter.component.html @@ -36,21 +36,21 @@

- +
- Created Date + Test Result
- +
- Last Modified Date + Created Date
- +
- Test Result + Last Modified Date
diff --git a/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html b/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html index eed4195ca..b7e8e8394 100644 --- a/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html +++ b/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -69,13 +69,13 @@
  • - Test Parameter + Scenario Execution
  • @@ -90,6 +90,18 @@ Test Result
  • +
  • + + + Test Parameter + +
  • diff --git a/simulator-ui/src/main/webapp/i18n/en/global.json b/simulator-ui/src/main/webapp/i18n/en/global.json index 199f93b46..e88ae2124 100644 --- a/simulator-ui/src/main/webapp/i18n/en/global.json +++ b/simulator-ui/src/main/webapp/i18n/en/global.json @@ -9,6 +9,7 @@ "main": "Entities", "message": "Message", "messageHeader": "Message Header", + "scenarioExecution": "Scenario Execution", "testParameter": "Test Parameter", "testResult": "Test Result", "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" diff --git a/simulator-ui/src/main/webapp/i18n/en/message.json b/simulator-ui/src/main/webapp/i18n/en/message.json index 7d5e97339..b6fef70be 100644 --- a/simulator-ui/src/main/webapp/i18n/en/message.json +++ b/simulator-ui/src/main/webapp/i18n/en/message.json @@ -13,6 +13,8 @@ "direction": "Direction", "payload": "Payload", "citrusMessageId": "Citrus Message Id", + "scenarioExecution": "Scenario Execution", + "headers": "Headers", "createdDate": "Created Date", "lastModifiedDate": "Last Modified Date" } diff --git a/simulator-ui/src/main/webapp/i18n/en/messageHeader.json b/simulator-ui/src/main/webapp/i18n/en/messageHeader.json new file mode 100644 index 000000000..8308fbc8b --- /dev/null +++ b/simulator-ui/src/main/webapp/i18n/en/messageHeader.json @@ -0,0 +1,18 @@ +{ + "citrusSimulatorApp": { + "messageHeader": { + "home": { + "title": "Message Headers", + "refreshListLabel": "Refresh list", + "notFound": "No Message Headers found" + }, + "detail": { + "title": "Message Header" + }, + "id": "ID", + "name": "Name", + "value": "Value", + "message": "Message" + } + } +} diff --git a/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json b/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json new file mode 100644 index 000000000..690a5de3d --- /dev/null +++ b/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json @@ -0,0 +1,21 @@ +{ + "citrusSimulatorApp": { + "scenarioExecution": { + "home": { + "title": "Scenario Executions", + "refreshListLabel": "Refresh list", + "notFound": "No Scenario Executions found" + }, + "detail": { + "title": "Scenario Execution" + }, + "id": "ID", + "startDate": "Start Date", + "endDate": "End Date", + "status": "Status", + "scenarioName": "Scenario Name", + "errorMessage": "Error Message", + "scenarioMessages": "Scenario Messages" + } + } +} diff --git a/simulator-ui/src/main/webapp/i18n/en/testParameter.json b/simulator-ui/src/main/webapp/i18n/en/testParameter.json index 0558ca11c..b6daacfbc 100644 --- a/simulator-ui/src/main/webapp/i18n/en/testParameter.json +++ b/simulator-ui/src/main/webapp/i18n/en/testParameter.json @@ -12,9 +12,9 @@ "id": "ID", "key": "Key", "value": "Value", + "testResult": "Test Result", "createdDate": "Created Date", - "lastModifiedDate": "Last Modified Date", - "testResult": "Test Result" + "lastModifiedDate": "Last Modified Date" } } } diff --git a/simulator-ui/src/main/webapp/i18n/en/testResult.json b/simulator-ui/src/main/webapp/i18n/en/testResult.json index 3949c3e28..e41034045 100644 --- a/simulator-ui/src/main/webapp/i18n/en/testResult.json +++ b/simulator-ui/src/main/webapp/i18n/en/testResult.json @@ -16,9 +16,9 @@ "errorMessage": "Error Message", "failureStack": "Failure Stack", "failureType": "Failure Type", + "testParameter": "Test Parameter", "createdDate": "Created Date", - "lastModifiedDate": "Last Modified Date", - "testParameter": "Test Parameter" + "lastModifiedDate": "Last Modified Date" } } }