diff --git a/simulator-docs/src/main/asciidoc/images/database-schema.plantuml b/simulator-docs/src/main/asciidoc/images/database-schema.plantuml new file mode 100644 index 000000000..8c448ae5d --- /dev/null +++ b/simulator-docs/src/main/asciidoc/images/database-schema.plantuml @@ -0,0 +1,75 @@ +@startuml + +!theme vibrant +top to bottom direction +skinparam linetype ortho + +class message { + direction: integer + created_date: timestamp(6) with time zone + last_modified_date: timestamp(6) with time zone + scenario_execution_execution_id: bigint + citrus_message_id: varchar(255) + payload: text + message_id: bigint +} +class message_header { + created_date: timestamp(6) with time zone + last_modified_date: timestamp(6) with time zone + message_id: bigint + header_value: varchar(255) + name: varchar(255) + header_id: bigint +} +class scenario_action { + end_date: timestamp(6) with time zone + scenario_execution_execution_id: bigint + start_date: timestamp(6) with time zone + name: varchar(255) + action_id: bigint +} +class scenario_execution { + end_date: timestamp(6) with time zone + start_date: timestamp(6) with time zone + test_result_id: bigint + scenario_name: varchar(255) + execution_id: bigint +} +class scenario_parameter { + control_type: integer + required: boolean + created_date: timestamp(6) with time zone + last_modified_date: timestamp(6) with time zone + scenario_execution_execution_id: bigint + label: varchar(255) + name: varchar(255) + parameter_value: text + parameter_id: bigint +} +class test_parameter { + created_date: timestamp(6) with time zone + last_modified_date: timestamp(6) with time zone + parameter_value: varchar(255) + test_result_id: bigint + parameter_key: varchar(255) +} +class test_result { + status: integer + created_date: timestamp(6) with time zone + last_modified_date: timestamp(6) with time zone + class_name: varchar(255) + failure_type: varchar(255) + test_name: varchar(255) + error_message: text + stack_trace: text + id: bigint +} + +message -[#595959,plain]-^ scenario_execution : "scenario_execution_execution_id:execution_id" +message_header -[#595959,plain]-^ message : "message_id" +scenario_action -[#595959,plain]-^ scenario_execution : "scenario_execution_execution_id:execution_id" +scenario_execution -[#595959,plain]-^ test_result : "test_result_id:id" +scenario_parameter -[#595959,plain]-^ scenario_execution : "scenario_execution_execution_id:execution_id" +test_parameter -[#595959,plain]-^ test_result : "test_result_id:id" + +@enduml diff --git a/simulator-docs/src/main/asciidoc/images/database-schema.png b/simulator-docs/src/main/asciidoc/images/database-schema.png index 577a450bc..c945f6d82 100644 Binary files a/simulator-docs/src/main/asciidoc/images/database-schema.png and b/simulator-docs/src/main/asciidoc/images/database-schema.png differ diff --git a/simulator-docs/src/main/asciidoc/images/database-schema.puml b/simulator-docs/src/main/asciidoc/images/database-schema.puml deleted file mode 100644 index e69de29bb..000000000 diff --git a/simulator-samples/sample-rest/src/main/java/org/citrusframework/simulator/sample/scenario/FailScenario.java b/simulator-samples/sample-rest/src/main/java/org/citrusframework/simulator/sample/scenario/FailScenario.java new file mode 100644 index 000000000..3e0d04f82 --- /dev/null +++ b/simulator-samples/sample-rest/src/main/java/org/citrusframework/simulator/sample/scenario/FailScenario.java @@ -0,0 +1,51 @@ +/* + * 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.sample.scenario; + +import static org.citrusframework.actions.EchoAction.Builder.echo; +import static org.citrusframework.actions.FailAction.Builder.fail; +import static org.citrusframework.dsl.MessageSupport.MessageBodySupport.fromBody; + +import org.citrusframework.simulator.scenario.AbstractSimulatorScenario; +import org.citrusframework.simulator.scenario.Scenario; +import org.citrusframework.simulator.scenario.ScenarioRunner; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * @author Christoph Deppisch + */ +@Scenario("Fail") +@RequestMapping(value = "/services/rest/simulator/fail", method = RequestMethod.POST) +public class FailScenario extends AbstractSimulatorScenario { + + @Override + public void run(ScenarioRunner scenario) { + scenario.$(scenario.http() + .receive() + .post() + .message() + .body("" + + "Fail!" + + "")); + + scenario.$(echo("Careful - I am gonna fail successfully (:")); + + scenario.$(fail("It is the courage to continue that counts.")); + } +} diff --git a/simulator-samples/sample-rest/src/main/resources/META-INF/citrus-simulator-context.xml b/simulator-samples/sample-rest/src/main/resources/META-INF/citrus-simulator-context.xml index e2917a3d4..a53ace752 100755 --- a/simulator-samples/sample-rest/src/main/resources/META-INF/citrus-simulator-context.xml +++ b/simulator-samples/sample-rest/src/main/resources/META-INF/citrus-simulator-context.xml @@ -1,14 +1,15 @@ - - - + + + + @@ -17,7 +18,7 @@ - + + - diff --git a/simulator-samples/sample-rest/src/main/resources/xsd/FailureService.xsd b/simulator-samples/sample-rest/src/main/resources/xsd/FailureService.xsd new file mode 100644 index 000000000..d3ae06018 --- /dev/null +++ b/simulator-samples/sample-rest/src/main/resources/xsd/FailureService.xsd @@ -0,0 +1,24 @@ + + + + + + + diff --git a/simulator-samples/sample-rest/src/main/resources/xsd/HelloService.xsd b/simulator-samples/sample-rest/src/main/resources/xsd/HelloService.xsd index 5dbb7af84..a2efe7ede 100644 --- a/simulator-samples/sample-rest/src/main/resources/xsd/HelloService.xsd +++ b/simulator-samples/sample-rest/src/main/resources/xsd/HelloService.xsd @@ -16,17 +16,16 @@ --> + xmlns="http://citrusframework.org/schemas/hello" + targetNamespace="http://citrusframework.org/schemas/hello" + elementFormDefault="qualified"> - - + + - - + + - - + + diff --git a/simulator-samples/sample-rest/src/test/java/org/citrusframework/simulator/SimulatorRestIT.java b/simulator-samples/sample-rest/src/test/java/org/citrusframework/simulator/SimulatorRestIT.java index a5a97c8bc..71ff10a94 100644 --- a/simulator-samples/sample-rest/src/test/java/org/citrusframework/simulator/SimulatorRestIT.java +++ b/simulator-samples/sample-rest/src/test/java/org/citrusframework/simulator/SimulatorRestIT.java @@ -35,6 +35,8 @@ import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.Test; +import java.util.List; + import static org.citrusframework.actions.SleepAction.Builder.sleep; import static org.citrusframework.http.actions.HttpActionBuilder.http; @@ -224,6 +226,25 @@ public void testInterveningRequest() { .body(defaultResponse)); } + /** + * Sends a request to the server expecting it to purposefully fail a simulation. + */ + @CitrusTest + public void testFailingSimulation() { + $(http().client(simulatorClient) + .send() + .post("fail") + .message() + .contentType(MediaType.APPLICATION_XML_VALUE) + .body("" + + "Fail!" + + "")); + + $(http().client(simulatorClient) + .receive() + .response(HttpStatus.OK)); // TODO: Pretty sure this should be HttpStatus.INTERNAL_SERVER_ERROR + } + @Configuration @PropertySource("classpath:application.properties") public static class EndpointConfig { @@ -231,7 +252,12 @@ public static class EndpointConfig { @Bean public XsdSchemaRepository schemaRepository() { XsdSchemaRepository schemaRepository = new XsdSchemaRepository(); - schemaRepository.getLocations().add("classpath:xsd/HelloService.xsd"); + schemaRepository.getLocations() + .addAll( + List.of( + "classpath:xsd/HelloService.xsd", + "classpath:xsd/FailureService.xsd" + )); return schemaRepository; } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/listener/SimulatorStatusListener.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/listener/SimulatorStatusListener.java index 252cb5283..e37ebca80 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/listener/SimulatorStatusListener.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/listener/SimulatorStatusListener.java @@ -26,7 +26,6 @@ import org.citrusframework.report.TestActionListener; import org.citrusframework.simulator.service.ScenarioActionService; import org.citrusframework.simulator.service.ScenarioExecutionService; -import org.citrusframework.simulator.service.TestResultService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -38,6 +37,7 @@ import static org.citrusframework.TestResult.failed; import static org.citrusframework.TestResult.success; +import static org.citrusframework.simulator.service.TestCaseUtil.getScenarioExecutionId; import static org.citrusframework.util.StringUtils.hasText; import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; @@ -62,12 +62,9 @@ public class SimulatorStatusListener extends AbstractTestListener implements Tes private final ScenarioActionService scenarioActionService; private final ScenarioExecutionService scenarioExecutionService; - private final TestResultService testResultService; - - public SimulatorStatusListener(ScenarioActionService scenarioActionService, ScenarioExecutionService scenarioExecutionService, TestResultService testResultService) { + public SimulatorStatusListener(ScenarioActionService scenarioActionService, ScenarioExecutionService scenarioExecutionService) { this.scenarioActionService = scenarioActionService; this.scenarioExecutionService = scenarioExecutionService; - this.testResultService = testResultService; } @Override @@ -85,45 +82,42 @@ public void onTestFinish(TestCase test) { } @Override - public void onTestSuccess(TestCase test) { - TestResult result; - if (test instanceof DefaultTestCase defaultTestCase) { - result = success(test.getName(), test.getTestClass().getSimpleName(), defaultTestCase.getParameters()); + public void onTestSuccess(TestCase testCase) { + TestResult testResult; + if (testCase instanceof DefaultTestCase defaultTestCase) { + testResult = success(testCase.getName(), testCase.getTestClass().getSimpleName(), defaultTestCase.getParameters()); } else { - result = success(test.getName(), test.getTestClass().getSimpleName()); + testResult = success(testCase.getName(), testCase.getTestClass().getSimpleName()); } - testResultService.transformAndSave(result); - scenarioExecutionService.completeScenarioExecutionSuccess(test); + scenarioExecutionService.completeScenarioExecution(getScenarioExecutionId(testCase), new org.citrusframework.simulator.model.TestResult(testResult)); - logger.info(result.toString()); + logger.info("Test succeeded: {}", testResult); } @Override - public void onTestFailure(TestCase test, Throwable cause) { - TestResult result; - if (test instanceof DefaultTestCase defaultTestCase) { - result = failed(test.getName(), test.getTestClass().getSimpleName(), cause, defaultTestCase.getParameters()); + public void onTestFailure(TestCase testCase, Throwable cause) { + TestResult testResult; + if (testCase instanceof DefaultTestCase defaultTestCase) { + testResult = failed(testCase.getName(), testCase.getTestClass().getSimpleName(), cause, defaultTestCase.getParameters()); } else { - result = failed(test.getName(), test.getTestClass().getSimpleName(), cause); + testResult = failed(testCase.getName(), testCase.getTestClass().getSimpleName(), cause); } - testResultService.transformAndSave(result); - scenarioExecutionService.completeScenarioExecutionFailure(test, cause); + scenarioExecutionService.completeScenarioExecution(getScenarioExecutionId(testCase), new org.citrusframework.simulator.model.TestResult(testResult)); - logger.info(result.toString()); - logger.info(result.getFailureType()); + logger.info("Test failed: {}", testResult); } @Override public void onTestActionStart(TestCase testCase, TestAction testAction) { if (!ignoreTestAction(testAction)) { - if (logger.isDebugEnabled()) { - logger.debug(testCase.getName() + "(" + - arrayToCommaDelimitedString(getParameters(testCase)) + ") - " + - testAction.getName() + - (testAction instanceof Described described && hasText(described.getDescription()) ? ": " + described.getDescription() : "")); - } + logger.debug("{} ({}) - {}{}", + testCase.getName(), + arrayToCommaDelimitedString(getParameters(testCase)), + testAction.getName(), + (testAction instanceof Described described && hasText(described.getDescription()) ? ": " + described.getDescription() : "") + ); scenarioActionService.createForScenarioExecutionAndSave(testCase, testAction); } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/Message.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/Message.java index 89ec6d83d..dda469f7d 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/Message.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/Message.java @@ -86,7 +86,7 @@ public class Message extends AbstractAuditingEntity implements Se private Integer direction = Direction.UNKNOWN.getId(); @Lob - @Column(columnDefinition = "CLOB", updatable = false) + @Column(columnDefinition = "TEXT", updatable = false) private String payload; @NotEmpty diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java index 6c17e697f..095aecb12 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java @@ -17,20 +17,17 @@ package org.citrusframework.simulator.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -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; import jakarta.persistence.Index; import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; import jakarta.persistence.OrderBy; import jakarta.persistence.Table; import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -38,10 +35,11 @@ import java.io.Serial; import java.io.Serializable; import java.time.Instant; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import static jakarta.persistence.CascadeType.ALL; +import static jakarta.persistence.FetchType.LAZY; import static lombok.AccessLevel.NONE; /** @@ -55,7 +53,6 @@ indexes = { @Index(name = "idx_scenario_execution_scenario_name", columnList = "scenario_name"), @Index(name = "idx_scenario_execution_start_date", columnList = "start_date"), - @Index(name = "idx_scenario_execution_status", columnList = "status"), } ) @ToString @@ -81,31 +78,20 @@ public class ScenarioExecution implements Serializable { @Column(nullable = false, updatable = false) private String scenarioName; - /** - * Actual status as a numerical representation of {@link Status} - */ - @NotNull - @Getter(NONE) - @Setter(NONE) - @Column(nullable = false) - private Integer status = Status.UNKNOWN.getId(); - - @Setter(NONE) - @Size(max = 1000) - @Column(length = 1000) - private String errorMessage; + @OneToOne(cascade = ALL) + private TestResult testResult; @OrderBy("name ASC") - @OneToMany(fetch = FetchType.LAZY, mappedBy = "scenarioExecution", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(fetch = LAZY, mappedBy = "scenarioExecution", cascade = ALL, orphanRemoval = true) @JsonIgnoreProperties(value = {"scenarioExecution"}, allowSetters = true) private final Set scenarioParameters = new HashSet<>(); @OrderBy("actionId ASC") - @OneToMany(fetch = FetchType.LAZY, mappedBy = "scenarioExecution", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(fetch = LAZY, mappedBy = "scenarioExecution", cascade = ALL, orphanRemoval = true) private final Set scenarioActions = new HashSet<>(); @OrderBy("messageId ASC") - @OneToMany(fetch = FetchType.LAZY, mappedBy = "scenarioExecution", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(fetch = LAZY, mappedBy = "scenarioExecution", cascade = ALL, orphanRemoval = true) @JsonIgnoreProperties(value = {"headers", "scenarioExecution"}, allowSetters = true) private final Set scenarioMessages = new HashSet<>(); @@ -117,16 +103,10 @@ void setExecutionId(Long executionId) { this.executionId = executionId; } - public Status getStatus() { - return Status.fromId(status); - } - - public void setStatus(Status status) { - this.status = status.id; - } - - public void setErrorMessage(String errorMessage) { - this.errorMessage = EntityUtils.truncateToColumnSize(getClass(), "errorMessage", errorMessage); + public ScenarioExecution withTestResult(TestResult testResult) { + this.testResult = testResult; + testResult.setScenarioExecution(this); + return this; } public ScenarioExecution addScenarioParameter(ScenarioParameter scenarioParameter) { @@ -163,25 +143,6 @@ public int hashCode() { return getClass().hashCode(); } - @Getter - public enum Status { - - UNKNOWN(0), RUNNING(1), SUCCESS(2), FAILED(3); - - private final int id; - - Status(int id) { - this.id = id; - } - - public static Status fromId(int id) { - return Arrays.stream(values()) - .filter(status -> status.id == id) - .findFirst() - .orElse(Status.UNKNOWN); - } - } - public static class ScenarioExecutionBuilder { private final ScenarioExecution scenarioExecution = new ScenarioExecution(); @@ -213,15 +174,5 @@ 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) { - scenarioExecution.setErrorMessage(errorMessage); - return this; - } } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioParameter.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioParameter.java index ee7d0cb12..c32c6a08f 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioParameter.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/model/ScenarioParameter.java @@ -80,7 +80,7 @@ public class ScenarioParameter extends AbstractAuditingEntity impleme /** * Optional test parameters */ - @OneToMany(fetch = FetchType.LAZY, mappedBy = "testResult", cascade = {CascadeType.REMOVE}) - @JsonIgnoreProperties(value = { "testResult" }, allowSetters = true) + @OneToMany(fetch = EAGER, mappedBy = "testResult", cascade = {REMOVE}) + @JsonIgnoreProperties(value = {"testResult"}, allowSetters = true) private final Set testParameters = new HashSet<>(); /** * Error message */ - @Size(max = 1000) - @Column(length = 1000, updatable = false) + @Lob + @Column(columnDefinition = "TEXT", updatable = false) private String errorMessage; /** * Failure stack trace */ - @Column(updatable = false) - private String failureStack; + @Lob + @Column(columnDefinition = "TEXT", updatable = false) + private String stackTrace; /** * Failure type information @@ -126,6 +135,10 @@ public class TestResult extends AbstractAuditingEntity impleme @Column(updatable = false) private String failureType; + @ToString.Exclude + @OneToOne(mappedBy = "testResult") + private ScenarioExecution scenarioExecution; + /** * This is an empty constructor, not intended for "manual" usage. * The Hibernate framework requires this in order to de- and serialize entities. @@ -144,12 +157,25 @@ public TestResult(org.citrusframework.TestResult testResult) { testName = testResult.getTestName(); className = testResult.getClassName(); testResult.getParameters().forEach((key, value) -> testParameters.add(new TestParameter(key, value.toString(), this))); - // NOte that the cause will be dropped: testResult.getCause() - errorMessage = EntityUtils.truncateToColumnSize(getClass(), "errorMessage", testResult.getErrorMessage()); - failureStack = testResult.getFailureStack(); + + if (nonNull(testResult.getCause())) { + enrichErrorInformation(testResult); + } + failureType = testResult.getFailureType(); } + private void enrichErrorInformation(org.citrusframework.TestResult testResult) { + errorMessage = getRootCause(testResult.getCause()).getMessage(); + + try (var stringWriter = new StringWriter(); var printWriter = new PrintWriter(stringWriter)) { + testResult.getCause().printStackTrace(printWriter); + stackTrace = stringWriter.toString(); + } catch (IOException e) { + getLogger(TestResult.class).warn("Error writing stacktrace to entity!", e); + } + } + public static TestResultBuilder builder() { return new TestResultBuilder(); } @@ -215,7 +241,7 @@ public static class TestResultBuilder extends AuditingEntityBuilder findAllForScenarioExecution(Long scenarioExecutionId, Stri @Query("FROM Message WHERE messageId IN :messageIds") @EntityGraph(attributePaths = {"headers", "scenarioExecution"}) - Page findAllWhereIdIn(@Param("messageIds") List messageIds, Pageable pageable); + Page findAllWhereMessageIdIn(@Param("messageIds") List messageIds, Pageable pageable); } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java index 0cb9f495f..3a3551abb 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/repository/ScenarioExecutionRepository.java @@ -36,13 +36,13 @@ public interface ScenarioExecutionRepository extends JpaRepository, JpaSpecificationExecutor { @Override - @EntityGraph(attributePaths = {"scenarioParameters", "scenarioActions", "scenarioMessages"}) + @EntityGraph(attributePaths = {"testResult", "scenarioParameters", "scenarioActions", "scenarioMessages"}) Page findAll(Pageable pageable); - @EntityGraph(attributePaths = {"scenarioParameters", "scenarioActions", "scenarioMessages"}) + @EntityGraph(attributePaths = {"testResult", "scenarioParameters", "scenarioActions", "scenarioMessages"}) Optional findOneByExecutionId(@Param("executionId") Long executionId); @Query("FROM ScenarioExecution WHERE executionId IN :scenarioExecutionIds") - @EntityGraph(attributePaths = {"scenarioParameters", "scenarioActions", "scenarioMessages", "scenarioMessages.headers"}) - Page findAllWhereIdIn(@Param("scenarioExecutionIds") List scenarioExecutionIds, Pageable pageable); + @EntityGraph(attributePaths = {"testResult", "scenarioParameters", "scenarioActions", "scenarioMessages"}) + Page findAllWhereExecutionIdIn(@Param("scenarioExecutionIds") List scenarioExecutionIds, Pageable pageable); } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java index c4af3b3e9..ec2dd1a2a 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/MessageQueryService.java @@ -76,7 +76,7 @@ public Page findByCriteria(MessageCriteria criteria, Pageable page) { ) .getResultList(); - var messages = messageRepository.findAllWhereIdIn(messageIds, unpaged(page.getSort())); + var messages = messageRepository.findAllWhereMessageIdIn(messageIds, unpaged(page.getSort())); return new PageImpl<>(messages.getContent(), page, messageRepository.count(specification)); } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java index ec410559f..bae4a24a5 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionQueryService.java @@ -30,6 +30,7 @@ import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.model.ScenarioExecution_; import org.citrusframework.simulator.model.ScenarioParameter_; +import org.citrusframework.simulator.model.TestResult_; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.citrusframework.simulator.service.criteria.ScenarioExecutionCriteria; import org.citrusframework.simulator.service.filter.Filter; @@ -58,6 +59,7 @@ import static org.citrusframework.simulator.service.CriteriaQueryUtils.newSelectIdBySpecificationQuery; import static org.citrusframework.simulator.service.ScenarioExecutionQueryService.MessageHeaderFilter.fromFilterPattern; import static org.citrusframework.simulator.service.ScenarioExecutionQueryService.Operator.parseOperator; +import static org.citrusframework.simulator.service.ScenarioExecutionService.restrictToDtoProperties; import static org.citrusframework.util.StringUtils.isEmpty; import static org.springframework.data.domain.Pageable.unpaged; @@ -121,8 +123,13 @@ public Page findByCriteria(ScenarioExecutionCriteria criteria ) .getResultList(); - var scenarioExecutions = scenarioExecutionRepository.findAllWhereIdIn(scenarioExecutionIds, unpaged(page.getSort())); - return new PageImpl<>(scenarioExecutions.getContent(), page, scenarioExecutionRepository.count(specification)); + var scenarioExecutions = scenarioExecutionRepository.findAllWhereExecutionIdIn(scenarioExecutionIds, unpaged(page.getSort())); + return new PageImpl<>( + scenarioExecutions.stream() + .map(scenarioExecution -> restrictToDtoProperties(scenarioExecution, entityManager)) + .toList(), + page, + scenarioExecutionRepository.count(specification)); } /** @@ -163,11 +170,14 @@ protected Specification createSpecification(ScenarioExecution if (nonNull(criteria.getScenarioName())) { specification = specification.and(buildStringSpecification(criteria.getScenarioName(), ScenarioExecution_.scenarioName)); } - if (nonNull(criteria.getStatus())) { - specification = specification.and(buildRangeSpecification(criteria.getStatus(), ScenarioExecution_.status)); - } - if (nonNull(criteria.getErrorMessage())) { - specification = specification.and(buildStringSpecification(criteria.getErrorMessage(), ScenarioExecution_.errorMessage)); + if (criteria.getStatus() != null) { + specification = + specification.and( + buildSpecification( + criteria.status(), + root -> root.join(ScenarioExecution_.testResult, JoinType.LEFT).get(TestResult_.status) + ) + ); } if (nonNull(criteria.getScenarioActionsId())) { specification = diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java index 7b1852de6..e4905f549 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/ScenarioExecutionService.java @@ -17,15 +17,18 @@ package org.citrusframework.simulator.service; import jakarta.annotation.Nullable; -import org.citrusframework.TestCase; +import jakarta.persistence.EntityManager; import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.model.ScenarioParameter; +import org.citrusframework.simulator.model.TestResult; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import java.util.List; import java.util.Optional; +import static java.util.Objects.nonNull; + /** * Service Interface for managing {@link ScenarioExecution}. */ @@ -73,19 +76,35 @@ public interface ScenarioExecutionService { ScenarioExecution createAndSaveExecutionScenario(String scenarioName, @Nullable List scenarioParameters); /** - * Mark a {@link ScenarioExecution} as completed successfully. + * Complete a {@link ScenarioExecution} with the given {@link TestResult}. * - * @param testCase the testcase identifying the entity. + * @param scenarioExecutionId the id of the entity. + * @param testResult the result of the execution. * @return the updated entity. */ - ScenarioExecution completeScenarioExecutionSuccess(TestCase testCase); + ScenarioExecution completeScenarioExecution(long scenarioExecutionId, TestResult testResult); /** - * Mark a {@link ScenarioExecution} as failed. + * Function that converts the {@link ScenarioExecution} to its "DTO-form": It especially cuts + * any constraints from the contained {@link TestResult}. * - * @param testCase the testcase identifying the entity. - * @param cause the reason the test case failed. - * @return the updated entity. + * @param scenarioExecution The entity which should be returned + * @param entityManager Entity manager that is currently managing the entity + * @return the entity with prepared {@link TestResult} */ - ScenarioExecution completeScenarioExecutionFailure(TestCase testCase, Throwable cause); + static ScenarioExecution restrictToDtoProperties(ScenarioExecution scenarioExecution, EntityManager entityManager) { + var testResult = scenarioExecution.getTestResult(); + + if (nonNull(testResult)) { + entityManager.detach(scenarioExecution); + scenarioExecution.setTestResult( + TestResult.builder() + .status(testResult.getStatus()) + .errorMessage(testResult.getErrorMessage()) + .stackTrace(testResult.getStackTrace()) + .build()); + } + + return scenarioExecution; + } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestCaseUtil.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestCaseUtil.java new file mode 100644 index 000000000..7204995d6 --- /dev/null +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestCaseUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright 2024 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 org.citrusframework.TestCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.Long.parseLong; +import static java.lang.String.format; +import static org.citrusframework.simulator.model.ScenarioExecution.EXECUTION_ID; + +public class TestCaseUtil { + + private static final Logger logger = LoggerFactory.getLogger(TestCaseUtil.class); + + private TestCaseUtil() { + // Static access only + } + + public static long getScenarioExecutionId(TestCase testCase) { + logger.trace("Lookup '{}' in TestCaseParameters : {}", EXECUTION_ID, testCase.getVariableDefinitions()); + + if (!testCase.getVariableDefinitions().containsKey(EXECUTION_ID)) { + throw new IllegalArgumentException(format("TestCase does not contain '%s'!", EXECUTION_ID)); + } + + return parseLong(testCase.getVariableDefinitions().get(EXECUTION_ID).toString()); + } +} diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultQueryService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultQueryService.java index 29744f3af..5cf9e3b44 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultQueryService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultQueryService.java @@ -118,8 +118,8 @@ protected Specification createSpecification(TestResultCriteria crite if (criteria.getErrorMessage() != null) { specification = specification.and(buildStringSpecification(criteria.getErrorMessage(), TestResult_.errorMessage)); } - if (criteria.getFailureStack() != null) { - specification = specification.and(buildStringSpecification(criteria.getFailureStack(), TestResult_.failureStack)); + if (criteria.getStackTrace() != null) { + specification = specification.and(buildStringSpecification(criteria.getStackTrace(), TestResult_.stackTrace)); } if (criteria.getFailureType() != null) { specification = specification.and(buildStringSpecification(criteria.getFailureType(), TestResult_.failureType)); diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultService.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultService.java index 9c2669f06..c8b25b7c6 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultService.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/TestResultService.java @@ -28,15 +28,6 @@ */ public interface TestResultService { - /** - * Save a citrus testResult. - * - * @param testResult the entity to save. - * @return the persisted entity. - * @see org.citrusframework.TestResult - */ - TestResult transformAndSave(org.citrusframework.TestResult testResult); - /** * Save a testResult. * diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java index 007ea4ea4..999368cf0 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteria.java @@ -61,8 +61,6 @@ public class ScenarioExecutionCriteria implements Serializable, Criteria { private IntegerFilter status; - private StringFilter errorMessage; - private LongFilter scenarioActionsId; private LongFilter scenarioMessagesId; @@ -82,7 +80,6 @@ public ScenarioExecutionCriteria(ScenarioExecutionCriteria other) { 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.scenarioActionsId = other.scenarioActionsId == null ? null : other.scenarioActionsId.copy(); this.scenarioMessagesId = other.scenarioMessagesId == null ? null : other.scenarioMessagesId.copy(); this.scenarioParametersId = other.scenarioParametersId == null ? null : other.scenarioParametersId.copy(); @@ -130,13 +127,6 @@ public IntegerFilter status() { return status; } - public StringFilter errorMessage() { - if (errorMessage == null) { - errorMessage = new StringFilter(); - } - return errorMessage; - } - public LongFilter scenarioActionsId() { if (scenarioActionsId == null) { scenarioActionsId = new LongFilter(); @@ -170,7 +160,6 @@ public boolean equals(Object o) { .append(endDate, scenarioExecutionCriteria.endDate) .append(scenarioName, scenarioExecutionCriteria.scenarioName) .append(status, scenarioExecutionCriteria.status) - .append(errorMessage, scenarioExecutionCriteria.errorMessage) .append(scenarioActionsId, scenarioExecutionCriteria.scenarioActionsId) .append(scenarioMessagesId, scenarioExecutionCriteria.scenarioMessagesId) .append(scenarioParametersId, scenarioExecutionCriteria.scenarioParametersId) @@ -186,7 +175,6 @@ public int hashCode() { .append(endDate) .append(scenarioName) .append(status) - .append(errorMessage) .append(scenarioActionsId) .append(scenarioMessagesId) .append(scenarioParametersId) diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java index d60da85bf..ea7816515 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java @@ -61,7 +61,7 @@ public class TestResultCriteria implements Serializable, Criteria { private StringFilter errorMessage; - private StringFilter failureStack; + private StringFilter stackTrace; private StringFilter failureType; @@ -82,7 +82,7 @@ public TestResultCriteria(TestResultCriteria other) { this.testName = other.testName == null ? null : other.testName.copy(); this.className = other.className == null ? null : other.className.copy(); this.errorMessage = other.errorMessage == null ? null : other.errorMessage.copy(); - this.failureStack = other.failureStack == null ? null : other.failureStack.copy(); + this.stackTrace = other.stackTrace == null ? null : other.stackTrace.copy(); this.failureType = other.failureType == null ? null : other.failureType.copy(); this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); @@ -130,11 +130,11 @@ public StringFilter errorMessage() { return errorMessage; } - public StringFilter failureStack() { - if (failureStack == null) { - failureStack = new StringFilter(); + public StringFilter stackTrace() { + if (stackTrace == null) { + stackTrace = new StringFilter(); } - return failureStack; + return stackTrace; } public StringFilter failureType() { @@ -177,7 +177,7 @@ public boolean equals(Object o) { .append(testName, testResultCriteria.testName) .append(className, testResultCriteria.className) .append(errorMessage, testResultCriteria.errorMessage) - .append(failureStack, testResultCriteria.failureStack) + .append(stackTrace, testResultCriteria.stackTrace) .append(failureType, testResultCriteria.failureType) .append(createdDate, testResultCriteria.createdDate) .append(lastModifiedDate, testResultCriteria.lastModifiedDate) @@ -194,7 +194,7 @@ public int hashCode() { .append(testName) .append(className) .append(errorMessage) - .append(failureStack) + .append(stackTrace) .append(failureType) .append(createdDate) .append(lastModifiedDate) diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java index 562117c37..99562efa9 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java @@ -32,6 +32,8 @@ import java.util.Map; import java.util.Optional; +import static java.lang.String.format; + /** * Service Implementation for managing {@link MessageĀ§}. */ @@ -94,7 +96,7 @@ public Message attachMessageToScenarioExecutionAndSave(Long scenarioExecutionId, scenarioExecution.addScenarioMessage(message); return scenarioExecution; }) - .orElseThrow(() -> new CitrusRuntimeException(String.format("Error while attaching Message to ScenarioExecution %s: Did not find corresponding ScenarioExecution!", scenarioExecutionId))) + .orElseThrow(() -> new CitrusRuntimeException(format("Error while attaching Message to ScenarioExecution %s: Did not find corresponding ScenarioExecution!", scenarioExecutionId))) ); return message; diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java index 2ed0d0f5c..0c354816b 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java @@ -38,7 +38,8 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; -import static org.citrusframework.simulator.service.impl.TestCaseUtil.getScenarioExecutionId; +import static java.util.Collections.singletonList; +import static org.citrusframework.simulator.service.TestCaseUtil.getScenarioExecutionId; /** * Service Implementation for managing {@link ScenarioAction}. @@ -49,7 +50,7 @@ public class ScenarioActionServiceImpl implements ScenarioActionService { private static final Logger logger = LoggerFactory.getLogger(ScenarioActionServiceImpl.class); - private static final List IGNORE_TEST_ACTION_NAMES = List.of("create-variables"); + private static final List IGNORE_TEST_ACTION_NAMES = singletonList("create-variables"); private final TimeProvider timeProvider = new TimeProvider(); diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java index a85f296e5..c256853b3 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImpl.java @@ -17,10 +17,11 @@ package org.citrusframework.simulator.service.impl; import jakarta.annotation.Nullable; -import org.citrusframework.TestCase; +import jakarta.persistence.EntityManager; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.model.ScenarioParameter; +import org.citrusframework.simulator.model.TestResult; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.citrusframework.simulator.service.ScenarioExecutionService; import org.slf4j.Logger; @@ -30,14 +31,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.List; import java.util.Optional; import static java.lang.String.format; -import static org.citrusframework.simulator.service.impl.TestCaseUtil.getScenarioExecutionId; +import static java.util.Objects.nonNull; import static org.springframework.util.CollectionUtils.isEmpty; /** @@ -51,9 +49,11 @@ public class ScenarioExecutionServiceImpl implements ScenarioExecutionService { private final TimeProvider timeProvider = new TimeProvider(); + private final EntityManager entityManager; private final ScenarioExecutionRepository scenarioExecutionRepository; - public ScenarioExecutionServiceImpl(ScenarioExecutionRepository scenarioExecutionRepository) { + public ScenarioExecutionServiceImpl(EntityManager entityManager, ScenarioExecutionRepository scenarioExecutionRepository) { + this.entityManager = entityManager; this.scenarioExecutionRepository = scenarioExecutionRepository; } @@ -67,14 +67,16 @@ public ScenarioExecution save(ScenarioExecution scenarioExecution) { @Transactional(readOnly = true) public Page findAll(Pageable pageable) { logger.debug("Request to get all ScenarioExecutions with eager relationships"); - return scenarioExecutionRepository.findAll(pageable); + return scenarioExecutionRepository.findAll(pageable) + .map(scenarioExecution -> ScenarioExecutionService.restrictToDtoProperties(scenarioExecution, entityManager)); } @Override @Transactional(readOnly = true) public Optional findOne(Long id) { logger.debug("Request to get ScenarioExecution with eager relationships : {}", id); - return scenarioExecutionRepository.findOneByExecutionId(id); + return scenarioExecutionRepository.findOneByExecutionId(id) + .map(scenarioExecution -> ScenarioExecutionService.restrictToDtoProperties(scenarioExecution, entityManager)); } @Override @@ -88,10 +90,9 @@ public Optional findOneLazy(Long id) { public ScenarioExecution createAndSaveExecutionScenario(String scenarioName, @Nullable List scenarioParameters) { logger.debug("Request to create and save ScenarioExecution : {}", scenarioName); - ScenarioExecution scenarioExecution = new ScenarioExecution(); + var scenarioExecution = new ScenarioExecution(); scenarioExecution.setScenarioName(scenarioName); scenarioExecution.setStartDate(timeProvider.getTimeNow()); - scenarioExecution.setStatus(ScenarioExecution.Status.RUNNING); if (!isEmpty(scenarioParameters)) { scenarioParameters.forEach(scenarioExecution::addScenarioParameter); @@ -101,39 +102,20 @@ public ScenarioExecution createAndSaveExecutionScenario(String scenarioName, @Nu } @Override - public ScenarioExecution completeScenarioExecutionSuccess(TestCase testCase) { - logger.debug("Request to complete ScenarioExecution for successful TestCase : {}", testCase); - return completeScenarioExecution(ScenarioExecution.Status.SUCCESS, testCase, null); - } - - @Override - public ScenarioExecution completeScenarioExecutionFailure(TestCase testCase, Throwable cause) { - logger.warn("Request to complete ScenarioExecution for failed TestCase : {}", testCase); - return completeScenarioExecution(ScenarioExecution.Status.FAILED, testCase, cause); - } + public ScenarioExecution completeScenarioExecution(long scenarioExecutionId, TestResult testResult) { + logger.debug("Request to complete ScenarioExecution with TestResult : {}", testResult); - private ScenarioExecution completeScenarioExecution(ScenarioExecution.Status status, TestCase testCase, @Nullable Throwable cause) { - return scenarioExecutionRepository.findOneByExecutionId(getScenarioExecutionId(testCase)) - .map(scenarioExecution -> { - scenarioExecution.setEndDate(timeProvider.getTimeNow()); - scenarioExecution.setStatus(status); + var scenarioExecution = scenarioExecutionRepository.findOneByExecutionId(scenarioExecutionId) + .orElseThrow(() -> new CitrusRuntimeException(format("Error while completing ScenarioExecution for test %s", testResult.getTestName()))); - if (cause != null) { - writeCauseToErrorMessage(cause, scenarioExecution); - } + if (nonNull(scenarioExecution.getEndDate())) { + logger.warn("ScenarioExecution {} already completed!", scenarioExecutionId); + return scenarioExecution; + } - return scenarioExecution; - }) - .map(scenarioExecutionRepository::save) - .orElseThrow(() -> new CitrusRuntimeException(format("Error while completing ScenarioExecution for test %s", testCase.getName()))); - } + scenarioExecution.setEndDate(timeProvider.getTimeNow()); + scenarioExecution.withTestResult(testResult); - private static void writeCauseToErrorMessage(Throwable cause, ScenarioExecution scenarioExecution) { - try (StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter)) { - cause.printStackTrace(printWriter); - scenarioExecution.setErrorMessage(stringWriter.toString()); - } catch (IOException e) { - logger.warn("Failed to write error message to scenario execution!", e); - } + return scenarioExecutionRepository.save(scenarioExecution); } } diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestCaseUtil.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestCaseUtil.java deleted file mode 100644 index a80479d0e..000000000 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestCaseUtil.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.citrusframework.simulator.service.impl; - -import org.citrusframework.TestCase; -import org.citrusframework.simulator.model.ScenarioExecution; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class TestCaseUtil { - - private static final Logger logger = LoggerFactory.getLogger(TestCaseUtil.class); - - private TestCaseUtil() { - // Static access only - } - - static long getScenarioExecutionId(TestCase testCase) { - logger.trace("Lookup '{}' in TestCaseParameters : {}", ScenarioExecution.EXECUTION_ID, testCase.getVariableDefinitions()); - return Long.parseLong(testCase.getVariableDefinitions().get(ScenarioExecution.EXECUTION_ID).toString()); - } -} diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestResultServiceImpl.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestResultServiceImpl.java index 4c8c426b4..7cd68e46e 100644 --- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestResultServiceImpl.java +++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/service/impl/TestResultServiceImpl.java @@ -44,12 +44,6 @@ public TestResultServiceImpl(TestResultRepository testResultRepository) { this.testResultRepository = testResultRepository; } - @Override - public TestResult transformAndSave(org.citrusframework.TestResult testResult) { - logger.debug("Request to save citrus TestResult : {}", testResult); - return save(new TestResult(testResult)); - } - @Override public TestResult save(TestResult testResult) { logger.debug("Request to save TestResult : {}", testResult); diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/listener/SimulatorStatusListenerTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/listener/SimulatorStatusListenerTest.java new file mode 100644 index 000000000..9f26929f0 --- /dev/null +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/listener/SimulatorStatusListenerTest.java @@ -0,0 +1,271 @@ +package org.citrusframework.simulator.listener; + +import org.assertj.core.api.Condition; +import org.citrusframework.DefaultTestCase; +import org.citrusframework.TestAction; +import org.citrusframework.TestCase; +import org.citrusframework.TestResult; +import org.citrusframework.actions.SleepAction; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.simulator.service.ScenarioActionService; +import org.citrusframework.simulator.service.ScenarioExecutionService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.simulator.model.ScenarioExecution.EXECUTION_ID; +import static org.citrusframework.simulator.model.TestResult.Status.FAILURE; +import static org.citrusframework.simulator.model.TestResult.Status.SUCCESS; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.springframework.test.util.ReflectionTestUtils.getField; +import static org.springframework.test.util.ReflectionTestUtils.setField; + +@ExtendWith({MockitoExtension.class}) +class SimulatorStatusListenerTest { + + @Mock + private ScenarioActionService scenarioActionServiceMock; + + @Mock + private ScenarioExecutionService scenarioExecutionServiceMock; + + private SimulatorStatusListener fixture; + + @BeforeEach + void setup() { + fixture = new SimulatorStatusListener(scenarioActionServiceMock, scenarioExecutionServiceMock); + } + + @Nested + class OnTestStart { + + @Test + void shouldConstructKeyFromDefaultTestCase() { + // Arrange + var testName = "shouldConstructKeyFromDefaultTestCase"; + + var defaultTestCaseMock = mock(DefaultTestCase.class); + doReturn(testName).when(defaultTestCaseMock).getName(); + doReturn(getClass()).when(defaultTestCaseMock).getTestClass(); + doReturn(Map.of("key", "value")).when(defaultTestCaseMock).getParameters(); + + // Act + fixture.onTestStart(defaultTestCaseMock); + + // Assert + assertThatRunningTestHasBeenRegistered(testName, "key=value", r -> assertThat(r.getParameters()).hasSize(1).containsOnlyKeys("key")); + } + + @Test + void cannotConstructKeyFromOtherTestCaseImplementation() { + // Arrange + var testName = "cannotConstructKeyFromOtherTestCaseImplementation"; + + var testCaseMock = mock(TestCase.class); + doReturn(testName).when(testCaseMock).getName(); + doReturn(getClass()).when(testCaseMock).getTestClass(); + + // Act + fixture.onTestStart(testCaseMock); + + // Assert + assertThatRunningTestHasBeenRegistered(testName, "", r -> assertThat(r.getParameters()).isEmpty()); + } + + private void assertThatRunningTestHasBeenRegistered(String testName, String key, Consumer parameterVerifier) { + assertThat(getRunningTests()) + .hasSize(1) + .hasKeySatisfying(new Condition<>("equals constructed key") { + @Override + public boolean matches(String value) { + return value.equals(key); + } + }) + .extracting(runningTests -> runningTests.get(key)) + .satisfies( + r -> assertThat(r.getTestName()).isEqualTo(testName), + r -> assertThat(r.isSuccess()).isTrue(), + parameterVerifier::accept + ); + } + } + + @Nested + class OnTestFinish { + + @Test + void shouldRemoveEntryFromRunningTests() { + // Arrange + var defaultTestCaseMock = mock(DefaultTestCase.class); + doReturn(Map.of("key", "value")).when(defaultTestCaseMock).getParameters(); + + var runningTests = new HashMap(); + var key = "key=value"; + runningTests.put(key, mock(TestResult.class)); + + setField(fixture, "runningTests", runningTests, Map.class); + + // Act + fixture.onTestFinish(defaultTestCaseMock); + + // Assert + assertThat(runningTests) + .isEmpty(); + } + } + + @Nested + class OnTestSuccess { + + private static long createAndGetScenarioExecutionId(TestCase testCaseMock) { + var scenarioExecutionId = 1234L; + doReturn(Map.of(EXECUTION_ID, scenarioExecutionId)).when(testCaseMock).getVariableDefinitions(); + return scenarioExecutionId; + } + + @Test + void shouldCompleteScenarioExecutionWithParameters() { + // Arrange + var defaultTestCaseMock = mock(DefaultTestCase.class); + doReturn("shouldCompleteScenarioExecutionWithParameters").when(defaultTestCaseMock).getName(); + doReturn(getClass()).when(defaultTestCaseMock).getTestClass(); + doReturn(Map.of("key", "value")).when(defaultTestCaseMock).getParameters(); + + var scenarioExecutionId = createAndGetScenarioExecutionId(defaultTestCaseMock); + + // Act + fixture.onTestSuccess(defaultTestCaseMock); + + // Assert + verify(scenarioExecutionServiceMock).completeScenarioExecution(eq(scenarioExecutionId), argThat(r -> r.getStatus() == SUCCESS && r.getTestParameters().size() == 1)); + } + + @Test + void shouldCompleteScenarioExecutionWithoutParameters() { + // Arrange + var testCaseMock = mock(TestCase.class); + doReturn("shouldCompleteScenarioExecutionWithoutParameters").when(testCaseMock).getName(); + doReturn(getClass()).when(testCaseMock).getTestClass(); + + var scenarioExecutionId = createAndGetScenarioExecutionId(testCaseMock); + + // Act + fixture.onTestSuccess(testCaseMock); + + // Assert + verify(scenarioExecutionServiceMock).completeScenarioExecution(eq(scenarioExecutionId), argThat(r -> r.getStatus() == SUCCESS && r.getTestParameters().isEmpty())); + } + } + + @Nested + class OnTestFailure { + + @Test + void shouldCompleteScenarioExecutionWithParameters() { + // Arrange + var defaultTestCaseMock = mock(DefaultTestCase.class); + doReturn("shouldCompleteScenarioExecutionWithParameters").when(defaultTestCaseMock).getName(); + doReturn(getClass()).when(defaultTestCaseMock).getTestClass(); + doReturn(Map.of("key", "value")).when(defaultTestCaseMock).getParameters(); + + var scenarioExecutionId = 1234L; + doReturn(Map.of(EXECUTION_ID, scenarioExecutionId)).when(defaultTestCaseMock).getVariableDefinitions(); + + var errorMessage = "Test failure cause!"; + var cause = new CitrusRuntimeException(errorMessage); + + // Act + fixture.onTestFailure(defaultTestCaseMock, cause); + + // Assert + verify(scenarioExecutionServiceMock).completeScenarioExecution(eq(scenarioExecutionId), argThat(r -> r.getStatus() == FAILURE && r.getErrorMessage().equals(errorMessage) && r.getTestParameters().size() == 1)); + } + + @Test + void shouldCompleteScenarioExecutionWithoutParameters() { + // Arrange + var testCaseMock = mock(TestCase.class); + doReturn("shouldCompleteScenarioExecutionWithoutParameters").when(testCaseMock).getName(); + doReturn(getClass()).when(testCaseMock).getTestClass(); + + var scenarioExecutionId = 1234L; + doReturn(Map.of(EXECUTION_ID, scenarioExecutionId)).when(testCaseMock).getVariableDefinitions(); + + var errorMessage = "Test failure cause!"; + var cause = new CitrusRuntimeException(errorMessage); + + // Act + fixture.onTestFailure(testCaseMock, cause); + + // Assert + verify(scenarioExecutionServiceMock).completeScenarioExecution(eq(scenarioExecutionId), argThat(r -> r.getStatus() == FAILURE && r.getErrorMessage().equals(errorMessage) && r.getTestParameters().isEmpty())); + } + } + + @Nested + class OnTestActionStart { + + @Mock + private TestCase testCaseMock; + + @Test + void shouldCompleteTestAction() { + var testActionMock = mock(TestAction.class); + + fixture.onTestActionStart(testCaseMock, testActionMock); + + verify(scenarioActionServiceMock).createForScenarioExecutionAndSave(testCaseMock, testActionMock); + } + + @Test + void shouldIgnoreSleepAction() { + var testActionMock = mock(SleepAction.class); + + fixture.onTestActionStart(testCaseMock, testActionMock); + + verifyNoInteractions(testCaseMock, scenarioActionServiceMock, scenarioExecutionServiceMock); + } + } + + @Nested + class OnTestActionFinish { + + @Mock + private TestCase testCaseMock; + + @Test + void shouldCompleteTestAction() { + var testActionMock = mock(TestAction.class); + + fixture.onTestActionFinish(testCaseMock, testActionMock); + + verify(scenarioActionServiceMock).completeTestAction(testCaseMock, testActionMock); + } + + @Test + void shouldIgnoreSleepAction() { + var testActionMock = mock(SleepAction.class); + + fixture.onTestActionFinish(testCaseMock, testActionMock); + + verifyNoInteractions(testCaseMock, scenarioActionServiceMock, scenarioExecutionServiceMock); + } + } + + private Map getRunningTests() { + return (Map) getField(fixture, SimulatorStatusListener.class, "runningTests"); + } +} diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/ScenarioExecutionTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/ScenarioExecutionTest.java index 4b0c73204..3ecac6798 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/ScenarioExecutionTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/ScenarioExecutionTest.java @@ -16,12 +16,67 @@ package org.citrusframework.simulator.model; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; class ScenarioExecutionTest { + private ScenarioExecution fixture; + + @BeforeEach + void beforeEachSetup() { + fixture = new ScenarioExecution(); + } + + @Test + void withTestResult() { + var testResult = mock(TestResult.class); + + fixture.withTestResult(testResult); + + assertThat(fixture) + .extracting(ScenarioExecution::getTestResult) + .isEqualTo(testResult); + verify(testResult).setScenarioExecution(fixture); + } + + @Test + void addScenarioParameter() { + var scenarioParameter = mock(ScenarioParameter.class); + + fixture.addScenarioParameter(scenarioParameter); + + assertThat(fixture) + .satisfies(s -> assertThat(s.getScenarioParameters()).containsExactly(scenarioParameter)); + verify(scenarioParameter).setScenarioExecution(fixture); + } + + @Test + void addScenarioAction() { + var scenarioAction = mock(ScenarioAction.class); + + fixture.addScenarioAction(scenarioAction); + + assertThat(fixture) + .satisfies(s -> assertThat(s.getScenarioActions()).containsExactly(scenarioAction)); + verify(scenarioAction).setScenarioExecution(fixture); + } + + @Test + void addScenarioMessage() { + var message = mock(Message.class); + + fixture.addScenarioMessage(message); + + assertThat(fixture) + .satisfies(s -> assertThat(s.getScenarioMessages()).containsExactly(message)); + verify(message).setScenarioExecution(fixture); + } + @Test void equalsVerifier() throws Exception { EntityTestUtils.equalsVerifier(ScenarioExecution.class); diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/TestResultTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/TestResultTest.java index aca0fa0ac..644e820f0 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/TestResultTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/model/TestResultTest.java @@ -16,12 +16,69 @@ package org.citrusframework.simulator.model; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.junit.jupiter.api.Test; +import java.util.Map; + import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.simulator.model.TestResult.Status.FAILURE; +import static org.citrusframework.simulator.model.TestResult.Status.SUCCESS; class TestResultTest { + private final String className = getClass().getSimpleName(); + + @Test + void constructFromSuccessfulResult() { + var testName = "constructFromSuccessfulResult"; + Map parameters = Map.of("a", "b"); + var failureType = "Just a type of error..."; + + var fixture = new TestResult(org.citrusframework.TestResult.success(testName, className, parameters).withFailureType(failureType)); + + assertThat(fixture) + .hasNoNullFieldsOrPropertiesExcept("id", "errorMessage", "stackTrace", "scenarioExecution") + .satisfies( + f -> assertThat(f).extracting(TestResult::getStatus).isEqualTo(SUCCESS), + f -> assertThat(f).extracting(TestResult::getTestName).isEqualTo(testName), + f -> assertThat(f).extracting(TestResult::getClassName).isEqualTo(className), + f -> assertThat(f).extracting(TestResult::getFailureType).isEqualTo(failureType), + f -> assertThat(f.getTestParameters()) + .hasSize(1).first() + .hasFieldOrPropertyWithValue("key", "a") + .hasFieldOrPropertyWithValue("value", "b") + ); + } + + @Test + void constructFromFailedResult() { + var testName = "constructFromSuccessfulResult"; + Map parameters = Map.of("a", "b"); + var failureType = "Another type of error..."; + + var errorMessage = "Something went wrong!"; + var rootErrorMessage = "Just kidding, it's a test."; + var exception = new CitrusRuntimeException(errorMessage, new CitrusRuntimeException(rootErrorMessage)); + + var fixture = new TestResult(org.citrusframework.TestResult.failed(testName, className, exception, parameters).withFailureType(failureType)); + + assertThat(fixture) + .hasNoNullFieldsOrPropertiesExcept("id", "scenarioExecution") + .satisfies( + f -> assertThat(f).extracting(TestResult::getStatus).isEqualTo(FAILURE), + f -> assertThat(f).extracting(TestResult::getTestName).isEqualTo(testName), + f -> assertThat(f).extracting(TestResult::getClassName).isEqualTo(className), + f -> assertThat(f).extracting(TestResult::getErrorMessage).isEqualTo(rootErrorMessage), + f -> assertThat(f).extracting(TestResult::getStackTrace).isNotNull().asString().contains(errorMessage, rootErrorMessage), + f -> assertThat(f).extracting(TestResult::getFailureType).isEqualTo(failureType), + f -> assertThat(f.getTestParameters()) + .hasSize(1).first() + .hasFieldOrPropertyWithValue("key", "a") + .hasFieldOrPropertyWithValue("value", "b") + ); + } + @Test void equalsVerifier() throws Exception { EntityTestUtils.equalsVerifier(TestResult.class); diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionQueryServiceIT.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionQueryServiceIT.java index 2d15e6d10..595a103d7 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionQueryServiceIT.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionQueryServiceIT.java @@ -11,11 +11,13 @@ import org.citrusframework.simulator.model.TestResult_; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.citrusframework.simulator.service.criteria.ScenarioExecutionCriteria; +import org.citrusframework.simulator.service.filter.IntegerFilter; import org.citrusframework.simulator.service.filter.LongFilter; import org.citrusframework.simulator.web.rest.MessageResourceIT; import org.citrusframework.simulator.web.rest.ScenarioActionResourceIT; import org.citrusframework.simulator.web.rest.ScenarioExecutionResourceIT; import org.citrusframework.simulator.web.rest.ScenarioParameterResourceIT; +import org.citrusframework.simulator.web.rest.TestResultResourceIT; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -37,6 +39,7 @@ import static java.time.temporal.ChronoUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.simulator.model.TestResult.Status.FAILURE; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.springframework.data.domain.Sort.Direction.ASC; import static org.springframework.data.domain.Sort.Direction.DESC; @@ -94,6 +97,7 @@ void beforeEachSetup() { .startDate(now.minus(2, MINUTES)) .endDate(now.minus(1, MINUTES)) .build() + .withTestResult(TestResultResourceIT.createEntity(entityManager)) .addScenarioAction(ScenarioActionResourceIT.createEntity(entityManager)) .addScenarioMessage( MessageResourceIT.createEntityBuilder(entityManager) @@ -113,6 +117,7 @@ void beforeEachSetup() { .startDate(now.minus(4, MINUTES)) .endDate(now) .build() + .withTestResult(TestResultResourceIT.createEntity(entityManager)) .addScenarioAction(ScenarioActionResourceIT.createEntity(entityManager)) .addScenarioMessage(message) .addScenarioParameter( @@ -125,6 +130,7 @@ void beforeEachSetup() { .startDate(now) .endDate(now.minus(1, MINUTES)) .build() + .withTestResult(TestResultResourceIT.createUpdatedEntity(entityManager)) .addScenarioAction(scenarioAction) .addScenarioMessage( MessageResourceIT.createEntityBuilder(entityManager) @@ -213,6 +219,14 @@ void selectWithJoinToScenarioParameters() { assertThatScenarioExecutionAtIndexSelectedByCriteria(scenarioExecutionCriteria, 0); } + @Test + void selectWithJoinToTestResult() { + var scenarioExecutionCriteria = new ScenarioExecutionCriteria(); + scenarioExecutionCriteria.setStatus((IntegerFilter) new IntegerFilter().setEquals(FAILURE.getId())); + + assertThatScenarioExecutionAtIndexSelectedByCriteria(scenarioExecutionCriteria, 2); + } + public static Stream selectWithJoinToMessageHeader() { return Stream.of( arguments("83def191b1dda4c79c00ae4c443f0ca2", 0), diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionServiceTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionServiceTest.java new file mode 100644 index 000000000..29b4d74f4 --- /dev/null +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/ScenarioExecutionServiceTest.java @@ -0,0 +1,62 @@ +package org.citrusframework.simulator.service; + +import jakarta.persistence.EntityManager; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.model.TestResult; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.citrusframework.simulator.model.TestResult.Status.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +@ExtendWith({MockitoExtension.class}) +class ScenarioExecutionServiceTest { + + @Mock + private EntityManager entityManagerMock; + + @Nested + class RestrictToDtoProperties { + + @Test + void shouldFilterTestResultDetails() { + var testResult = mock(TestResult.class); + doReturn(SUCCESS).when(testResult).getStatus(); + doReturn("errorMessage").when(testResult).getErrorMessage(); + doReturn("stackTrace").when(testResult).getStackTrace(); + + var scenarioExecution = new ScenarioExecution(); + scenarioExecution.setTestResult(testResult); + + var restrictedScenarioExecution = ScenarioExecutionService.restrictToDtoProperties(scenarioExecution, entityManagerMock); + + var restrictedTestResult = restrictedScenarioExecution.getTestResult(); + assertEquals(testResult.getStatus(), restrictedTestResult.getStatus()); + assertEquals(testResult.getErrorMessage(), restrictedTestResult.getErrorMessage()); + assertEquals(testResult.getStackTrace(), restrictedTestResult.getStackTrace()); + + verify(testResult, never()).getTestParameters(); + verify(entityManagerMock).detach(scenarioExecution); + } + + @Test + void shouldHandleNullTestResult() { + var execution = new ScenarioExecution(); + + var restrictedExecution = ScenarioExecutionService.restrictToDtoProperties(execution, entityManagerMock); + + assertNull(restrictedExecution.getTestResult()); + + verifyNoInteractions(entityManagerMock); + } + } +} diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/TestCaseUtilTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/TestCaseUtilTest.java new file mode 100644 index 000000000..558f196e2 --- /dev/null +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/TestCaseUtilTest.java @@ -0,0 +1,49 @@ +package org.citrusframework.simulator.service; + +import org.citrusframework.TestCase; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.HashMap; +import java.util.Map; + +import static java.lang.Long.parseLong; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.simulator.service.TestCaseUtil.getScenarioExecutionId; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +@ExtendWith({MockitoExtension.class}) +class TestCaseUtilTest { + + @Mock + private TestCase testCase; + + @Nested + class GetScenarioExecutionId { + + @Test + void shouldGetScenarioExecutionIdWhenPresent() { + var executionId = "1234"; + doReturn(Map.of(ScenarioExecution.EXECUTION_ID, executionId)).when(testCase).getVariableDefinitions(); + + long retrievedId = getScenarioExecutionId(testCase); + + assertEquals(parseLong(executionId), retrievedId); + } + + @Test + void shouldThrowExceptionWhenExecutionIdMissing() { + when(testCase.getVariableDefinitions()).thenReturn(new HashMap<>()); + + assertThatThrownBy(() -> getScenarioExecutionId(testCase)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TestCase does not contain 'scenarioExecutionId'!"); + } + } +} diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteriaTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteriaTest.java index 5b21559a6..b2997bb39 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteriaTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/ScenarioExecutionCriteriaTest.java @@ -50,8 +50,6 @@ void testStartDate() { assertSame(mockStartDateFilter, fixture.startDate()); } - // Add more test methods following the same pattern for all the other attributes... - @Test void testScenarioName() { assertNull(fixture.getScenarioName()); @@ -78,19 +76,6 @@ void testStatus() { assertSame(mockStatusFilter, fixture.status()); } - @Test - void testErrorMessage() { - assertNull(fixture.getErrorMessage()); - - StringFilter errorMessageFilter = fixture.errorMessage(); - assertNotNull(errorMessageFilter); - assertSame(errorMessageFilter, fixture.getErrorMessage()); - - StringFilter mockErrorMessageFilter = mock(StringFilter.class); - fixture.setErrorMessage(mockErrorMessageFilter); - assertSame(mockErrorMessageFilter, fixture.errorMessage()); - } - @Test void testScenarioActionsId() { assertNull(fixture.getScenarioActionsId()); diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/TestResultCriteriaTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/TestResultCriteriaTest.java index 0c9d76982..f6928bb17 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/TestResultCriteriaTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/criteria/TestResultCriteriaTest.java @@ -89,16 +89,16 @@ void testErrorMessage() { } @Test - void testFailureStack() { - assertNull(criteria.getFailureStack()); + void testStackTrace() { + assertNull(criteria.getStackTrace()); - StringFilter failureStackFilter = criteria.failureStack(); - assertNotNull(failureStackFilter); - assertSame(failureStackFilter, criteria.getFailureStack()); + StringFilter stackTraceFilter = criteria.stackTrace(); + assertNotNull(stackTraceFilter); + assertSame(stackTraceFilter, criteria.getStackTrace()); StringFilter mockFailureStackFilter = mock(StringFilter.class); - criteria.setFailureStack(mockFailureStackFilter); - assertSame(mockFailureStackFilter, criteria.failureStack()); + criteria.setStackTrace(mockFailureStackFilter); + assertSame(mockFailureStackFilter, criteria.stackTrace()); } @Test diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java index e673736a5..4f94996a2 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImplTest.java @@ -44,7 +44,6 @@ import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.simulator.model.ScenarioExecution.Status.UNKNOWN; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -97,7 +96,6 @@ void beforeEachSetup() { .startDate(Instant.now()) .endDate(Instant.now()) .scenarioName("scenario-name") - .errorMessage("error-message") .build(); scenarioAction.setScenarioExecution(scenarioExecution); scenarioActionWithScenarioExecution = spy(scenarioAction); @@ -159,8 +157,7 @@ private void verifyDtoPreparations() { "scenarioActions", "scenarioMessages") .hasFieldOrPropertyWithValue("executionId", expectedScenarioExecution.getExecutionId()) - .hasFieldOrPropertyWithValue("scenarioName", expectedScenarioExecution.getScenarioName()) - .hasFieldOrPropertyWithValue("status", UNKNOWN); + .hasFieldOrPropertyWithValue("scenarioName", expectedScenarioExecution.getScenarioName()); } @Nested diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImplTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImplTest.java index 3ad3481c3..21265661d 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImplTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/ScenarioExecutionServiceImplTest.java @@ -16,10 +16,11 @@ package org.citrusframework.simulator.service.impl; -import org.citrusframework.TestCase; +import jakarta.persistence.EntityManager; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.model.ScenarioParameter; +import org.citrusframework.simulator.model.TestResult; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -34,28 +35,32 @@ import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.Optional; +import static java.lang.String.format; +import static java.util.Optional.empty; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.springframework.data.domain.Pageable.unpaged; @ExtendWith(MockitoExtension.class) class ScenarioExecutionServiceImplTest { + @Mock + private EntityManager entityManagerMock; + @Mock private ScenarioExecutionRepository scenarioExecutionRepositoryMock; @Mock - TimeProvider timeProviderMock; + private TimeProvider timeProviderMock; private ScenarioExecution sampleScenarioExecution; @@ -65,7 +70,7 @@ class ScenarioExecutionServiceImplTest { void beforeEachSetup() { sampleScenarioExecution = new ScenarioExecution(); - fixture = new ScenarioExecutionServiceImpl(scenarioExecutionRepositoryMock); + fixture = new ScenarioExecutionServiceImpl(entityManagerMock, scenarioExecutionRepositoryMock); ReflectionTestUtils.setField(fixture, "timeProvider", timeProviderMock, TimeProvider.class); } @@ -129,7 +134,6 @@ void testCreateAndSaveExecutionScenario() { assertEquals(scenarioName, result.getScenarioName()); assertEquals(now, result.getStartDate()); - assertEquals(ScenarioExecution.Status.RUNNING, result.getStatus()); assertThat(result.getScenarioParameters()) .hasSize(1) .containsExactly(scenarioParameter); @@ -142,65 +146,41 @@ class CompleteScenarioExecution { private final Instant now = Instant.now(); @Mock - private TestCase testCaseMock; - - @BeforeEach - void beforeEachSetup() { - Map variableDefinitions = Map.of(ScenarioExecution.EXECUTION_ID, String.valueOf(scenarioExecutionId)); - doReturn(variableDefinitions).when(testCaseMock).getVariableDefinitions(); - } + private TestResult testResultMock; @Test - void successful() { - preparePersistenceLayerMocks(); + void withTestResult() { + doReturn(Optional.of(sampleScenarioExecution)).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); + doReturn(sampleScenarioExecution).when(scenarioExecutionRepositoryMock).save(sampleScenarioExecution); + doReturn(now).when(timeProviderMock).getTimeNow(); - ScenarioExecution result = fixture.completeScenarioExecutionSuccess(testCaseMock); + var result = fixture.completeScenarioExecution(scenarioExecutionId, testResultMock); - assertEquals(ScenarioExecution.Status.SUCCESS, result.getStatus()); + assertEquals(testResultMock, result.getTestResult()); assertEquals(now, result.getEndDate()); - assertNull(result.getErrorMessage()); } @Test - void successfulWithNoScenarioExecutionFound() { + void withNoScenarioExecutionFound() { String testName = "testCase"; - doReturn(testName).when(testCaseMock).getName(); + doReturn(testName).when(testResultMock).getTestName(); - doReturn(Optional.empty()).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); + doReturn(empty()).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); - CitrusRuntimeException exception = assertThrows(CitrusRuntimeException.class, () -> fixture.completeScenarioExecutionSuccess(testCaseMock)); - assertEquals(String.format("Error while completing ScenarioExecution for test %s", testName), exception.getMessage()); + assertThatThrownBy(() -> fixture.completeScenarioExecution(scenarioExecutionId, testResultMock)) + .isInstanceOf(CitrusRuntimeException.class) + .hasMessage(format("Error while completing ScenarioExecution for test %s", testName)); } @Test - void failed() { - preparePersistenceLayerMocks(); - - Throwable cause = new RuntimeException("Failure cause"); - ScenarioExecution result = fixture.completeScenarioExecutionFailure(testCaseMock, cause); - - assertEquals(ScenarioExecution.Status.FAILED, result.getStatus()); - assertEquals(now, result.getEndDate()); - assertTrue(result.getErrorMessage().startsWith("java.lang.RuntimeException: Failure cause"), "Error message must contain cause!"); - - verify(scenarioExecutionRepositoryMock).save(result); - } - - @Test - void failedWithNoScenarioExecutionFound() { - String testName = "testCase"; - doReturn(testName).when(testCaseMock).getName(); - - doReturn(Optional.empty()).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); + void withScenarioExecutionThatHasAlreadyBeenEnded() { + sampleScenarioExecution.setEndDate(now); + doReturn(Optional.of(sampleScenarioExecution)).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); - CitrusRuntimeException exception = assertThrows(CitrusRuntimeException.class, () -> fixture.completeScenarioExecutionFailure(testCaseMock, new RuntimeException("Failure cause"))); - assertEquals(String.format("Error while completing ScenarioExecution for test %s", testName), exception.getMessage()); - } + assertDoesNotThrow(() -> fixture.completeScenarioExecution(scenarioExecutionId, testResultMock)); - private void preparePersistenceLayerMocks() { - doReturn(Optional.of(sampleScenarioExecution)).when(scenarioExecutionRepositoryMock).findOneByExecutionId(scenarioExecutionId); - doReturn(sampleScenarioExecution).when(scenarioExecutionRepositoryMock).save(sampleScenarioExecution); - doReturn(now).when(timeProviderMock).getTimeNow(); + verifyNoInteractions(testResultMock); + verifyNoInteractions(timeProviderMock); } } } diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java index 9f6719a6f..04d630d27 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/impl/TestResultServiceImplTest.java @@ -15,7 +15,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -33,18 +32,6 @@ void beforeEachSetup() { fixture = new TestResultServiceImpl(testResultRepositoryMock); } - @Test - void testTransformAndSave() { - org.citrusframework.TestResult citrusTestResult = org.citrusframework.TestResult.success("TestResult", TestResultServiceImpl.class.getSimpleName()); - - TestResult testResult = new TestResult(citrusTestResult); - doReturn(testResult).when(testResultRepositoryMock).save(any(TestResult.class)); - - TestResult result = fixture.transformAndSave(citrusTestResult); - - assertEquals(testResult, result); - } - @Test void testSave() { TestResult testResult = new TestResult(); diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/runner/DefaultScenarioExecutorServiceIT.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/runner/DefaultScenarioExecutorServiceIT.java index 370e4ed52..4b26d3548 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/runner/DefaultScenarioExecutorServiceIT.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/service/runner/DefaultScenarioExecutorServiceIT.java @@ -18,6 +18,7 @@ import org.citrusframework.simulator.IntegrationTest; import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.model.TestResult; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.citrusframework.simulator.scenario.AbstractSimulatorScenario; import org.citrusframework.simulator.scenario.Scenario; @@ -29,7 +30,7 @@ import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.simulator.model.ScenarioExecution.Status.SUCCESS; +import static org.citrusframework.simulator.model.TestResult.Status.SUCCESS; @IntegrationTest class DefaultScenarioExecutorServiceIT { @@ -65,7 +66,8 @@ void resultsBeingPersistedSynchronously() { assertThat(scenarioExecutionRepository.findOneByExecutionId(executionId)) .hasValueSatisfying(scenarioExecution -> assertThat(scenarioExecution) .hasNoNullFieldsOrPropertiesExcept("errorMessage") - .extracting(ScenarioExecution::getStatus) + .extracting(ScenarioExecution::getTestResult) + .extracting(TestResult::getStatus) .isEqualTo(SUCCESS)); } diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java index ae3ab93c9..aff6c4938 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/ScenarioExecutionResourceIT.java @@ -7,6 +7,7 @@ import org.citrusframework.simulator.model.ScenarioExecution; import org.citrusframework.simulator.model.ScenarioExecution.ScenarioExecutionBuilder; import org.citrusframework.simulator.model.ScenarioParameter; +import org.citrusframework.simulator.model.TestResult; import org.citrusframework.simulator.repository.ScenarioExecutionRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -19,6 +20,8 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import static org.citrusframework.simulator.model.TestResult.Status.FAILURE; +import static org.citrusframework.simulator.model.TestResult.Status.SUCCESS; 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; @@ -43,11 +46,8 @@ public class ScenarioExecutionResourceIT { 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 TestResult.Status DEFAULT_STATUS = SUCCESS; // Integer value: 1 + private static final TestResult.Status UPDATED_STATUS = FAILURE; // Integer value: 2 private static final String ENTITY_API_URL = "/api/scenario-executions"; private static final String ENTITY_API_URL_ID = ENTITY_API_URL + "/{id}"; @@ -67,9 +67,7 @@ public static ScenarioExecutionBuilder createEntityBuilder(EntityManager entityM return ScenarioExecution.builder() .startDate(DEFAULT_START_DATE) .endDate(DEFAULT_END_DATE) - .scenarioName(DEFAULT_SCENARIO_NAME) - .status(DEFAULT_STATUS) - .errorMessage(DEFAULT_ERROR_MESSAGE); + .scenarioName(DEFAULT_SCENARIO_NAME); } /** @@ -94,14 +92,15 @@ public static ScenarioExecution createUpdatedEntity(EntityManager entityManager) .startDate(UPDATED_START_DATE) .endDate(UPDATED_END_DATE) .scenarioName(UPDATED_SCENARIO_NAME) - .status(UPDATED_STATUS) - .errorMessage(UPDATED_ERROR_MESSAGE) .build(); } @BeforeEach - void beforeEachSetup() { - scenarioExecution = createEntity(entityManager); + void beforeEachSetup() { + var testResult = TestResultResourceIT.createEntity(entityManager); + + scenarioExecution = createEntity(entityManager) + .withTestResult(testResult); } @Test @@ -119,8 +118,7 @@ void getAllScenarioExecutions() throws Exception { .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))); + .andExpect(jsonPath("$.[*].testResult.status").value(SUCCESS.toString())); } @Test @@ -138,8 +136,7 @@ void getScenarioExecution() throws Exception { .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)); + .andExpect(jsonPath("$.testResult.status").value(DEFAULT_STATUS.toString())); } @Test @@ -394,71 +391,6 @@ void getAllScenarioExecutionsByStatusIsNullOrNotNull() throws Exception { 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 getAllScenarioExecutionsByScenarioActionIsEqualToSomething() throws Exception { @@ -537,8 +469,7 @@ private void defaultScenarioExecutionShouldBeFound(String filter) throws Excepti .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))); + .andExpect(jsonPath("$.[*].testResult.status").value(DEFAULT_STATUS.toString())); // Check, that the count call also returns 1 mockMvc diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java index 1ca9acd91..bda10a747 100644 --- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java +++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/web/rest/TestResultResourceIT.java @@ -33,7 +33,7 @@ */ @IntegrationTest @AutoConfigureMockMvc -class TestResultResourceIT { +public class TestResultResourceIT { private static final TestResult.Status DEFAULT_STATUS = TestResult.Status.SUCCESS; // Integer value: 1 private static final TestResult.Status UPDATED_STATUS = TestResult.Status.FAILURE; // Integer value: 2 @@ -47,8 +47,8 @@ class TestResultResourceIT { private static final String DEFAULT_ERROR_MESSAGE = "AAAAAAAAAA"; private static final String UPDATED_ERROR_MESSAGE = "BBBBBBBBBB"; - private static final String DEFAULT_FAILURE_STACK = "AAAAAAAAAA"; - private static final String UPDATED_FAILURE_STACK = "BBBBBBBBBB"; + private static final String DEFAULT_STACK_TRACE = "AAAAAAAAAA"; + private static final String UPDATED_STACK_TRACE = "BBBBBBBBBB"; private static final String DEFAULT_FAILURE_TYPE = "AAAAAAAAAA"; private static final String UPDATED_FAILURE_TYPE = "BBBBBBBBBB"; @@ -87,7 +87,7 @@ public static TestResult createEntity(EntityManager entityManager) { .testName(DEFAULT_TEST_NAME) .className(DEFAULT_CLASS_NAME) .errorMessage(DEFAULT_ERROR_MESSAGE) - .failureStack(DEFAULT_FAILURE_STACK) + .stackTrace(DEFAULT_STACK_TRACE) .failureType(DEFAULT_FAILURE_TYPE) .createdDate(DEFAULT_CREATED_DATE) .lastModifiedDate(DEFAULT_LAST_MODIFIED_DATE) @@ -106,7 +106,7 @@ public static TestResult createUpdatedEntity(EntityManager entityManager) { .testName(UPDATED_TEST_NAME) .className(UPDATED_CLASS_NAME) .errorMessage(UPDATED_ERROR_MESSAGE) - .failureStack(UPDATED_FAILURE_STACK) + .stackTrace(UPDATED_STACK_TRACE) .failureType(UPDATED_FAILURE_TYPE) .createdDate(UPDATED_CREATED_DATE) .lastModifiedDate(UPDATED_LAST_MODIFIED_DATE) @@ -134,7 +134,7 @@ void getAllTestResults() throws Exception { .andExpect(jsonPath("$.[*].testName").value(hasItem(DEFAULT_TEST_NAME))) .andExpect(jsonPath("$.[*].className").value(hasItem(DEFAULT_CLASS_NAME))) .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(DEFAULT_ERROR_MESSAGE))) - .andExpect(jsonPath("$.[*].failureStack").value(hasItem(DEFAULT_FAILURE_STACK))) + .andExpect(jsonPath("$.[*].stackTrace").value(hasItem(DEFAULT_STACK_TRACE))) .andExpect(jsonPath("$.[*].failureType").value(hasItem(DEFAULT_FAILURE_TYPE))) .andExpect(jsonPath("$.[*].createdDate").value(hasItem(sameInstant(DEFAULT_CREATED_DATE)))) .andExpect(jsonPath("$.[*].lastModifiedDate").value(hasItem(sameInstant(DEFAULT_LAST_MODIFIED_DATE)))); @@ -156,7 +156,7 @@ void getTestResult() throws Exception { .andExpect(jsonPath("$.testName").value(DEFAULT_TEST_NAME)) .andExpect(jsonPath("$.className").value(DEFAULT_CLASS_NAME)) .andExpect(jsonPath("$.errorMessage").value(DEFAULT_ERROR_MESSAGE)) - .andExpect(jsonPath("$.failureStack").value(DEFAULT_FAILURE_STACK)) + .andExpect(jsonPath("$.stackTrace").value(DEFAULT_STACK_TRACE)) .andExpect(jsonPath("$.failureType").value(DEFAULT_FAILURE_TYPE)) .andExpect(jsonPath("$.createdDate").value(sameInstant(DEFAULT_CREATED_DATE))) .andExpect(jsonPath("$.lastModifiedDate").value(sameInstant(DEFAULT_LAST_MODIFIED_DATE))); @@ -416,67 +416,67 @@ void getAllTestResultsByErrorMessageNotContainsSomething() throws Exception { @Test @Transactional - void getAllTestResultsByFailureStackIsEqualToSomething() throws Exception { + void getAllTestResultsByStackTraceIsEqualToSomething() throws Exception { // Initialize the database testResultRepository.saveAndFlush(testResult); - // Get all the testResultList where failureStack equals to DEFAULT_FAILURE_STACK - defaultTestResultShouldBeFound("failureStack.equals=" + DEFAULT_FAILURE_STACK); + // Get all the testResultList where stackTrace equals to DEFAULT_FAILURE_STACK + defaultTestResultShouldBeFound("stackTrace.equals=" + DEFAULT_STACK_TRACE); - // Get all the testResultList where failureStack equals to UPDATED_FAILURE_STACK - defaultTestResultShouldNotBeFound("failureStack.equals=" + UPDATED_FAILURE_STACK); + // Get all the testResultList where stackTrace equals to UPDATED_FAILURE_STACK + defaultTestResultShouldNotBeFound("stackTrace.equals=" + UPDATED_STACK_TRACE); } @Test @Transactional - void getAllTestResultsByFailureStackIsInShouldWork() throws Exception { + void getAllTestResultsByStackTraceIsInShouldWork() throws Exception { // Initialize the database testResultRepository.saveAndFlush(testResult); - // Get all the testResultList where failureStack in DEFAULT_FAILURE_STACK or UPDATED_FAILURE_STACK - defaultTestResultShouldBeFound("failureStack.in=" + DEFAULT_FAILURE_STACK + "," + UPDATED_FAILURE_STACK); + // Get all the testResultList where stackTrace in DEFAULT_FAILURE_STACK or UPDATED_FAILURE_STACK + defaultTestResultShouldBeFound("stackTrace.in=" + DEFAULT_STACK_TRACE + "," + UPDATED_STACK_TRACE); - // Get all the testResultList where failureStack equals to UPDATED_FAILURE_STACK - defaultTestResultShouldNotBeFound("failureStack.in=" + UPDATED_FAILURE_STACK); + // Get all the testResultList where stackTrace equals to UPDATED_FAILURE_STACK + defaultTestResultShouldNotBeFound("stackTrace.in=" + UPDATED_STACK_TRACE); } @Test @Transactional - void getAllTestResultsByFailureStackIsNullOrNotNull() throws Exception { + void getAllTestResultsByStackTraceIsNullOrNotNull() throws Exception { // Initialize the database testResultRepository.saveAndFlush(testResult); - // Get all the testResultList where failureStack is not null - defaultTestResultShouldBeFound("failureStack.specified=true"); + // Get all the testResultList where stackTrace is not null + defaultTestResultShouldBeFound("stackTrace.specified=true"); - // Get all the testResultList where failureStack is null - defaultTestResultShouldNotBeFound("failureStack.specified=false"); + // Get all the testResultList where stackTrace is null + defaultTestResultShouldNotBeFound("stackTrace.specified=false"); } @Test @Transactional - void getAllTestResultsByFailureStackContainsSomething() throws Exception { + void getAllTestResultsByStackTraceContainsSomething() throws Exception { // Initialize the database testResultRepository.saveAndFlush(testResult); - // Get all the testResultList where failureStack contains DEFAULT_FAILURE_STACK - defaultTestResultShouldBeFound("failureStack.contains=" + DEFAULT_FAILURE_STACK); + // Get all the testResultList where stackTrace contains DEFAULT_FAILURE_STACK + defaultTestResultShouldBeFound("stackTrace.contains=" + DEFAULT_STACK_TRACE); - // Get all the testResultList where failureStack contains UPDATED_FAILURE_STACK - defaultTestResultShouldNotBeFound("failureStack.contains=" + UPDATED_FAILURE_STACK); + // Get all the testResultList where stackTrace contains UPDATED_FAILURE_STACK + defaultTestResultShouldNotBeFound("stackTrace.contains=" + UPDATED_STACK_TRACE); } @Test @Transactional - void getAllTestResultsByFailureStackNotContainsSomething() throws Exception { + void getAllTestResultsByStackTraceNotContainsSomething() throws Exception { // Initialize the database testResultRepository.saveAndFlush(testResult); - // Get all the testResultList where failureStack does not contain DEFAULT_FAILURE_STACK - defaultTestResultShouldNotBeFound("failureStack.doesNotContain=" + DEFAULT_FAILURE_STACK); + // Get all the testResultList where stackTrace does not contain DEFAULT_FAILURE_STACK + defaultTestResultShouldNotBeFound("stackTrace.doesNotContain=" + DEFAULT_STACK_TRACE); - // Get all the testResultList where failureStack does not contain UPDATED_FAILURE_STACK - defaultTestResultShouldBeFound("failureStack.doesNotContain=" + UPDATED_FAILURE_STACK); + // Get all the testResultList where stackTrace does not contain UPDATED_FAILURE_STACK + defaultTestResultShouldBeFound("stackTrace.doesNotContain=" + UPDATED_STACK_TRACE); } @Test @@ -782,7 +782,7 @@ private void defaultTestResultShouldBeFound(String filter) throws Exception { .andExpect(jsonPath("$.[*].testName").value(hasItem(DEFAULT_TEST_NAME))) .andExpect(jsonPath("$.[*].className").value(hasItem(DEFAULT_CLASS_NAME))) .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(DEFAULT_ERROR_MESSAGE))) - .andExpect(jsonPath("$.[*].failureStack").value(hasItem(DEFAULT_FAILURE_STACK))) + .andExpect(jsonPath("$.[*].stackTrace").value(hasItem(DEFAULT_STACK_TRACE))) .andExpect(jsonPath("$.[*].failureType").value(hasItem(DEFAULT_FAILURE_TYPE))) .andExpect(jsonPath("$.[*].createdDate").value(hasItem(sameInstant(DEFAULT_CREATED_DATE)))) .andExpect(jsonPath("$.[*].lastModifiedDate").value(hasItem(sameInstant(DEFAULT_LAST_MODIFIED_DATE)))); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.html b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.html index b0f561c01..813c41c88 100644 --- a/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.html +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/detail/scenario-execution-detail.component.html @@ -28,13 +28,13 @@

{{ scenarioExecution.scenarioName }}
-
Status
+
Status
- {{ scenarioExecution.status }} + {{ scenarioExecution.testResult?.status }}
-
Error Message
+
Error Message
- {{ scenarioExecution.errorMessage }} + {{ scenarioExecution.testResult?.errorMessage }}
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 index 2c3b590a1..2ac90defc 100644 --- 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 @@ -50,13 +50,13 @@

- Status + Status
- Error Message + Error Message
@@ -72,11 +72,11 @@

{{ scenarioExecution.startDate | formatMediumDatetime }} {{ scenarioExecution.endDate | formatMediumDatetime }} - {{ - scenarioExecution.status + {{ + scenarioExecution.testResult?.status }} - {{ scenarioExecution.errorMessage }} + {{ scenarioExecution.testResult?.errorMessage }}
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 index 3d8d66900..c080527b0 100644 --- 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 @@ -16,9 +16,10 @@ import { ItemCountComponent } from 'app/shared/pagination'; import { SortByDirective, SortDirective } from 'app/shared/sort'; import { EntityArrayResponseType, ScenarioExecutionService } from '../service/scenario-execution.service'; -import { IScenarioExecution, IScenarioExecutionStatus } from '../scenario-execution.model'; +import { IScenarioExecution } from '../scenario-execution.model'; import { navigateToWithPagingInformation } from '../../navigation-util'; +import { ITestResultStatus } from '../../test-result/test-result.model'; @Component({ standalone: true, @@ -163,9 +164,9 @@ export class ScenarioExecutionComponent implements OnInit { } } - protected getStatusBadgeClass(status: IScenarioExecutionStatus): string { + protected getStatusBadgeClass(status: ITestResultStatus): string { switch (status.name) { - case 'FAILED': + case 'FAILURE': return 'bg-danger'; case 'SUCCESS': return 'bg-success'; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.spec.ts deleted file mode 100644 index cb02ddde2..000000000 --- a/simulator-ui/src/main/webapp/app/entities/scenario-execution/scenario-execution.model.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - scenarioExecutionStatusFromName, - scenarioExecutionStatusFromId, - STATUS_UNKNOWN, - STATUS_RUNNING, - STATUS_SUCCESS, - STATUS_FAILED, -} from './scenario-execution.model'; - -describe('ScenarioExecutionStatus', () => { - describe('scenarioExecutionStatusFromName', () => { - it('should return the correct status for a valid name', () => { - expect(scenarioExecutionStatusFromName('RUNNING')).toEqual(STATUS_RUNNING); - expect(scenarioExecutionStatusFromName('SUCCESS')).toEqual(STATUS_SUCCESS); - expect(scenarioExecutionStatusFromName('FAILED')).toEqual(STATUS_FAILED); - expect(scenarioExecutionStatusFromName('UNKNOWN')).toEqual(STATUS_UNKNOWN); - }); - - it('should return STATUS_UNKNOWN for an invalid name', () => { - expect(scenarioExecutionStatusFromName('invalid')).toEqual(STATUS_UNKNOWN); - }); - }); - - describe('scenarioExecutionStatusFromId', () => { - it('should return the correct status for a valid id', () => { - expect(scenarioExecutionStatusFromId(1)).toEqual(STATUS_RUNNING); - expect(scenarioExecutionStatusFromId(2)).toEqual(STATUS_SUCCESS); - expect(scenarioExecutionStatusFromId(3)).toEqual(STATUS_FAILED); - expect(scenarioExecutionStatusFromId(0)).toEqual(STATUS_UNKNOWN); - }); - - it('should return STATUS_UNKNOWN for an invalid id', () => { - expect(scenarioExecutionStatusFromId(99)).toEqual(STATUS_UNKNOWN); - }); - }); -}); 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 index b1fff0f2a..f5201f97b 100644 --- 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 @@ -1,45 +1,15 @@ import dayjs from 'dayjs/esm'; import { IMessage } from 'app/entities/message/message.model'; +import { ITestResult } from 'app/entities/test-result/test-result.model'; export interface IScenarioExecution { executionId: number; startDate?: dayjs.Dayjs | null; endDate?: dayjs.Dayjs | null; scenarioName?: string | null; - status?: 'UNKNOWN' | 'RUNNING' | 'SUCCESS' | 'FAILED' | null; - errorMessage?: string | null; + testResult?: ITestResult | null; scenarioMessages?: IMessage[] | null; } export type NewScenarioExecution = Omit & { executionId: null }; - -export interface IScenarioExecutionStatus { - id: number; - name: 'UNKNOWN' | 'RUNNING' | 'SUCCESS' | 'FAILED'; -} - -export const STATUS_UNKNOWN: IScenarioExecutionStatus = { id: 0, name: 'UNKNOWN' }; -export const STATUS_RUNNING: IScenarioExecutionStatus = { id: 1, name: 'RUNNING' }; -export const STATUS_SUCCESS: IScenarioExecutionStatus = { id: 2, name: 'SUCCESS' }; -export const STATUS_FAILED: IScenarioExecutionStatus = { id: 3, name: 'FAILED' }; - -export const scenarioExecutionStatusFromName = (name: string): IScenarioExecutionStatus => { - for (const status of [STATUS_UNKNOWN, STATUS_RUNNING, STATUS_SUCCESS, STATUS_FAILED]) { - if (status.name === name) { - return status; - } - } - - return STATUS_UNKNOWN; -}; - -export const scenarioExecutionStatusFromId = (id: number): IScenarioExecutionStatus => { - for (const status of [STATUS_UNKNOWN, STATUS_RUNNING, STATUS_SUCCESS, STATUS_FAILED]) { - if (status.id === id) { - return status; - } - } - - return STATUS_UNKNOWN; -}; 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 index 44ebf3785..ff4e15ac1 100644 --- 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 @@ -6,15 +6,12 @@ export const sampleWithRequiredData: IScenarioExecution = { executionId: 28068, startDate: dayjs('2023-10-18T19:26'), scenarioName: 'geez', - status: 'RUNNING', }; export const sampleWithPartialData: IScenarioExecution = { executionId: 6290, startDate: dayjs('2023-10-18T20:56'), scenarioName: 'baptise gracefully', - status: 'SUCCESS', - errorMessage: 'gee sniffle bunch', }; export const sampleWithFullData: IScenarioExecution = { @@ -22,14 +19,11 @@ export const sampleWithFullData: IScenarioExecution = { startDate: dayjs('2023-10-19T02:53'), endDate: dayjs('2023-10-18T17:11'), scenarioName: 'midst', - status: 'FAILED', - errorMessage: 'jiffy wherever', }; export const sampleWithNewData: NewScenarioExecution = { startDate: dayjs('2023-10-18T16:49'), scenarioName: 'robotics', - status: 'UNKNOWN', executionId: null, }; diff --git a/simulator-ui/src/main/webapp/app/entities/test-result/detail/test-result-detail.component.html b/simulator-ui/src/main/webapp/app/entities/test-result/detail/test-result-detail.component.html index a6932a387..f4594b8f3 100644 --- a/simulator-ui/src/main/webapp/app/entities/test-result/detail/test-result-detail.component.html +++ b/simulator-ui/src/main/webapp/app/entities/test-result/detail/test-result-detail.component.html @@ -30,9 +30,9 @@

Failure Stack +
Failure Stack
- {{ testResult.failureStack }} + {{ testResult.stackTrace }}
Failure Type
diff --git a/simulator-ui/src/main/webapp/app/entities/test-result/list/test-result.component.html b/simulator-ui/src/main/webapp/app/entities/test-result/list/test-result.component.html index 4e49e5642..b24ce5b3f 100644 --- a/simulator-ui/src/main/webapp/app/entities/test-result/list/test-result.component.html +++ b/simulator-ui/src/main/webapp/app/entities/test-result/list/test-result.component.html @@ -56,7 +56,7 @@

- Failure Stack + Failure Stack
@@ -94,7 +94,7 @@

{{ testResult.testName }} {{ testResult.className }} {{ testResult.errorMessage }} - {{ testResult.failureStack }} + {{ testResult.stackTrace }} {{ testResult.failureType }} {{ testResult.createdDate | formatMediumDatetime }} {{ testResult.lastModifiedDate | formatMediumDatetime }} diff --git a/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.spec.ts b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.spec.ts new file mode 100644 index 000000000..63c9d382c --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.spec.ts @@ -0,0 +1,36 @@ +import { + testResultStatusFromId, + testResultStatusFromName, + STATUS_UNKNOWN, + STATUS_SUCCESS, + STATUS_FAILURE, + STATUS_SKIP +} from './test-result.model'; + +describe('TestResult Status', () => { + describe('testResultStatusFromName', () => { + it('should return the correct status for a valid name', () => { + expect(testResultStatusFromName('UNKNOWN')).toEqual(STATUS_UNKNOWN); + expect(testResultStatusFromName('SUCCESS')).toEqual(STATUS_SUCCESS); + expect(testResultStatusFromName('FAILURE')).toEqual(STATUS_FAILURE); + expect(testResultStatusFromName('SKIP')).toEqual(STATUS_SKIP); + }); + + it('should return STATUS_UNKNOWN for an invalid name', () => { + expect(testResultStatusFromName('invalid')).toEqual(STATUS_UNKNOWN); + }); + }); + + describe('testResultStatusFromId', () => { + it('should return the correct status for a valid id', () => { + expect(testResultStatusFromId(0)).toEqual(STATUS_UNKNOWN); + expect(testResultStatusFromId(1)).toEqual(STATUS_SUCCESS); + expect(testResultStatusFromId(2)).toEqual(STATUS_FAILURE); + expect(testResultStatusFromId(3)).toEqual(STATUS_SKIP); + }); + + it('should return STATUS_UNKNOWN for an invalid id', () => { + expect(testResultStatusFromId(99)).toEqual(STATUS_UNKNOWN); + }); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.ts b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.ts index 1dfed6054..55bbe3b98 100644 --- a/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.ts +++ b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.model.ts @@ -6,7 +6,7 @@ export interface ITestResult { testName?: string | null; className?: string | null; errorMessage?: string | null; - failureStack?: string | null; + stackTrace?: string | null; failureType?: string | null; createdDate?: dayjs.Dayjs | null; lastModifiedDate?: dayjs.Dayjs | null; @@ -21,5 +21,25 @@ export interface ITestResultStatus { export const STATUS_UNKNOWN: ITestResultStatus = { id: 0, name: 'UNKNOWN' }; export const STATUS_SUCCESS: ITestResultStatus = { id: 1, name: 'SUCCESS' }; -export const STATUS_FAILED: ITestResultStatus = { id: 2, name: 'FAILURE' }; +export const STATUS_FAILURE: ITestResultStatus = { id: 2, name: 'FAILURE' }; export const STATUS_SKIP: ITestResultStatus = { id: 3, name: 'SKIP' }; + +export const testResultStatusFromName = (name: string): ITestResultStatus => { + for (const status of [STATUS_UNKNOWN, STATUS_SUCCESS, STATUS_FAILURE, STATUS_SKIP]) { + if (status.name === name) { + return status; + } + } + + return STATUS_UNKNOWN; +}; + +export const testResultStatusFromId = (id: number): ITestResultStatus => { + for (const status of [STATUS_UNKNOWN, STATUS_SUCCESS, STATUS_FAILURE, STATUS_SKIP]) { + if (status.id === id) { + return status; + } + } + + return STATUS_UNKNOWN; +}; diff --git a/simulator-ui/src/main/webapp/app/entities/test-result/test-result.test-samples.ts b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.test-samples.ts index 6ea1d32e5..12955b402 100644 --- a/simulator-ui/src/main/webapp/app/entities/test-result/test-result.test-samples.ts +++ b/simulator-ui/src/main/webapp/app/entities/test-result/test-result.test-samples.ts @@ -17,7 +17,7 @@ export const sampleWithPartialData: ITestResult = { testName: 'zowie', className: 'regarding openly', errorMessage: 'toward', - failureStack: 'whose', + stackTrace: 'whose', createdDate: dayjs('2023-09-26T13:39'), lastModifiedDate: dayjs('2023-09-26T15:03'), }; @@ -28,7 +28,7 @@ export const sampleWithFullData: ITestResult = { testName: 'peruse probable display', className: 'dining', errorMessage: 'reproachfully better what', - failureStack: 'flugelhorn over', + stackTrace: 'flugelhorn over', failureType: 'aha', createdDate: dayjs('2023-09-26T07:09'), lastModifiedDate: dayjs('2023-09-26T09:18'), diff --git a/simulator-ui/src/main/webapp/app/home/test-result-summary.component.ts b/simulator-ui/src/main/webapp/app/home/test-result-summary.component.ts index 1555abc9c..09e856414 100644 --- a/simulator-ui/src/main/webapp/app/home/test-result-summary.component.ts +++ b/simulator-ui/src/main/webapp/app/home/test-result-summary.component.ts @@ -5,12 +5,14 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { filter, map } from 'rxjs/operators'; -import { STATUS_FAILED, STATUS_SUCCESS } from 'app/entities/scenario-execution/scenario-execution.model'; +import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; + +import { STATUS_FAILURE, STATUS_SUCCESS } from 'app/entities/test-result/test-result.model'; import { TestResultsByStatus, TestResultService } from 'app/entities/test-result/service/test-result.service'; + import SharedModule from 'app/shared/shared.module'; + import TestResultDeleteDialogComponent from './delete/test-result-delete-dialog.component'; -import { switchMap } from 'rxjs'; -import { ITEM_DELETED_EVENT } from '../config/navigation.constants'; @Component({ standalone: true, @@ -27,7 +29,7 @@ export default class TestResultSummaryComponent implements OnInit { failedPercentage = '0'; statusSuccess = STATUS_SUCCESS; - statusFailed = STATUS_FAILED; + statusFailed = STATUS_FAILURE; constructor( private modalService: NgbModal, diff --git a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.html b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.html index a16ee4b06..90336ee9a 100644 --- a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.html +++ b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.html @@ -20,16 +20,16 @@
diff --git a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.spec.ts b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.spec.ts index 56fa71d8e..5a3a26db2 100644 --- a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.spec.ts +++ b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.spec.ts @@ -10,7 +10,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { DEBOUNCE_TIME_MILLIS } from 'app/config/input.constants'; -import { STATUS_SUCCESS } from 'app/entities/scenario-execution/scenario-execution.model'; +import {STATUS_SUCCESS} from "app/entities/test-result/test-result.model"; import SharedModule from 'app/shared/shared.module'; diff --git a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.ts b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.ts index ec81032d6..8f674e724 100644 --- a/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.ts +++ b/simulator-ui/src/main/webapp/app/scenario-result/filter/scenario-execution-filter.component.ts @@ -16,11 +16,7 @@ import SharedModule from 'app/shared/shared.module'; import { formatDateTimeFilterOptions } from 'app/shared/date/format-date-time-filter-options'; import { FilterOptions, IFilterOptions } from 'app/shared/filter'; -import { - IScenarioExecutionStatus, - scenarioExecutionStatusFromId, - scenarioExecutionStatusFromName, -} from 'app/entities/scenario-execution/scenario-execution.model'; +import { ITestResultStatus, testResultStatusFromId, testResultStatusFromName } from 'app/entities/test-result/test-result.model'; import HeaderFilterDialogComponent, { ComparatorType, HeaderFilter, ValueType } from './header-filter-dialog.component'; import HeaderFilterHelpDialogComponent from './header-filter-help-dialog.component'; @@ -29,7 +25,7 @@ type ScenarioExecutionFilter = { nameContains: string | undefined; fromDate: dayjs.Dayjs | undefined; toDate: dayjs.Dayjs | undefined; - statusIn: IScenarioExecutionStatus | undefined; + statusIn: ITestResultStatus | undefined; headerFilter: string | undefined; }; @@ -165,7 +161,7 @@ export default class ScenarioExecutionFilterComponent implements OnInit, OnDestr nameContains: formValue.nameContains, fromDate: formValue.fromDate ? dayjs(formValue.fromDate) : undefined, toDate: formValue.toDate ? dayjs(formValue.toDate) : undefined, - statusIn: formValue.statusIn ? scenarioExecutionStatusFromName(formValue.statusIn) : undefined, + statusIn: formValue.statusIn ? testResultStatusFromName(formValue.statusIn) : undefined, headerFilter: formValue.headerFilter, }), ), @@ -195,7 +191,7 @@ export default class ScenarioExecutionFilterComponent implements OnInit, OnDestr this.filterForm.controls.toDate.markAsDirty(); break; case 'status': - this.filterForm.controls.statusIn.setValue(scenarioExecutionStatusFromId(Number(filterOption.values[0])).name); + this.filterForm.controls.statusIn.setValue(testResultStatusFromId(Number(filterOption.values[0])).name); this.filterForm.controls.statusIn.markAsDirty(); break; case 'headers': diff --git a/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json b/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json index 254274f71..a42461770 100644 --- a/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json +++ b/simulator-ui/src/main/webapp/i18n/en/scenarioExecution.json @@ -43,13 +43,9 @@ "id": "ID", "startDate": "Start Date", "endDate": "End Date", - "status": "Status", - "statusAll": "All", - "statusRunning": "Running", - "statusSuccess": "Success", - "statusFailed": "Failed", "scenarioName": "Scenario Name", "errorMessage": "Error Message", + "testResult": "Test Result", "scenarioActions": "Scenario Actions", "scenarioMessages": "Scenario Messages", "scenarioParameters": "Scenario Parameters" diff --git a/simulator-ui/src/main/webapp/i18n/en/testResult.json b/simulator-ui/src/main/webapp/i18n/en/testResult.json index 1abeca263..06b66f7b9 100644 --- a/simulator-ui/src/main/webapp/i18n/en/testResult.json +++ b/simulator-ui/src/main/webapp/i18n/en/testResult.json @@ -11,10 +11,14 @@ }, "id": "ID", "status": "Status", + "statusAll": "All", + "statusSuccess": "Success", + "statusFailure": "Failure", + "statusSkip": "Skipped", "testName": "Test Name", "className": "Class Name", "errorMessage": "Error Message", - "failureStack": "Failure Stack", + "stackTrace": "Stack Trace", "failureType": "Failure Type", "testParameter": "Test Parameters", "createdDate": "Created Date",