Skip to content

Commit

Permalink
feat: optionally include all message headers in scenario execution re…
Browse files Browse the repository at this point in the history
…sponse
  • Loading branch information
bbortt committed Oct 15, 2024
1 parent 0fd05fd commit 55349a7
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ public interface ScenarioExecutionRepository extends JpaRepository<ScenarioExecu
Optional<ScenarioExecution> findOneByExecutionId(@Param("executionId") Long executionId);

@Query("FROM ScenarioExecution WHERE executionId IN :scenarioExecutionIds")
@EntityGraph(attributePaths = {"testResult", "scenarioParameters", "scenarioActions", "scenarioMessages"})
@EntityGraph(attributePaths = {"testResult", "scenarioParameters", "scenarioActions", "scenarioMessages", "scenarioMessages.headers"})
Page<ScenarioExecution> findAllWhereExecutionIdIn(@Param("scenarioExecutionIds") List<Long> scenarioExecutionIds, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.util.List;
import java.util.Optional;

import static java.lang.Boolean.FALSE;

/**
* REST controller for managing {@link ScenarioExecution}.
*/
Expand All @@ -56,7 +59,8 @@ public class ScenarioExecutionResource {

public ScenarioExecutionResource(
ScenarioExecutionService scenarioExecutionService,
ScenarioExecutionQueryService scenarioExecutionQueryService, ScenarioExecutionMapper scenarioExecutionMapper
ScenarioExecutionQueryService scenarioExecutionQueryService,
ScenarioExecutionMapper scenarioExecutionMapper
) {
this.scenarioExecutionService = scenarioExecutionService;
this.scenarioExecutionQueryService = scenarioExecutionQueryService;
Expand All @@ -71,10 +75,17 @@ public ScenarioExecutionResource(
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of scenarioExecutions in body.
*/
@GetMapping("/scenario-executions")
public ResponseEntity<List<ScenarioExecutionDTO>> getAllScenarioExecutions(ScenarioExecutionCriteria criteria, @ParameterObject Pageable pageable) {
public ResponseEntity<List<ScenarioExecutionDTO>> getAllScenarioExecutions(
ScenarioExecutionCriteria criteria,
@RequestParam(name = "includeActions", required = false, defaultValue = "false") Boolean includeActions,
@RequestParam(name = "includeMessages", required = false, defaultValue = "false") Boolean includeMessages,
@RequestParam(name = "includeParameters", required = false, defaultValue = "false") Boolean includeParameters,
@ParameterObject Pageable pageable
) {
logger.debug("REST request to get ScenarioExecutions by criteria: {}", criteria);

Page<ScenarioExecution> page = scenarioExecutionQueryService.findByCriteria(criteria, pageable);
stripPageContents(page, includeActions, includeMessages, includeParameters);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
return ResponseEntity.ok().headers(headers).body(page.getContent().stream().map(scenarioExecutionMapper::toDto).toList());
}
Expand Down Expand Up @@ -103,4 +114,16 @@ public ResponseEntity<ScenarioExecutionDTO> getScenarioExecution(@PathVariable("
Optional<ScenarioExecution> scenarioExecution = scenarioExecutionService.findOne(id);
return ResponseUtil.wrapOrNotFound(scenarioExecution.map(scenarioExecutionMapper::toDto));
}

private void stripPageContents(Page<ScenarioExecution> page, Boolean includeActions, Boolean includeMessages, Boolean includeParameters) {
if (FALSE.equals(includeActions)) {
page.getContent().forEach(scenarioExecution -> scenarioExecution.getScenarioActions().clear());
}
if (FALSE.equals(includeMessages)) {
page.getContent().forEach(scenarioExecution -> scenarioExecution.getScenarioMessages().clear());
}
if (FALSE.equals(includeParameters)) {
page.getContent().forEach(scenarioExecution -> scenarioExecution.getScenarioParameters().clear());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ public class TechnicalStructureTest {
.layer("Scenario").definedBy("..scenario..")

.whereLayer("Web").mayOnlyBeAccessedByLayers("Config")
.whereLayer("Domain").mayOnlyBeAccessedByLayers("Config", "DTO", "Service", "Persistence", "Endpoint", "Listener", "Scenario");
.whereLayer("Domain").mayOnlyBeAccessedByLayers("Config", "DTO", "Service", "Persistence", "Endpoint", "Listener", "Scenario", "Web");
}
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ void getNonExistingScenarioExecution() throws Exception {

@Nested
class CorrectTimeOnScenarioExecution {

public static final TemporalUnitLessThanOffset LESS_THAN_5_SECONDS = new TemporalUnitLessThanOffset(5, SECONDS);

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright 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.web.rest;

import org.citrusframework.simulator.model.Message;
import org.citrusframework.simulator.model.ScenarioAction;
import org.citrusframework.simulator.model.ScenarioExecution;
import org.citrusframework.simulator.model.ScenarioParameter;
import org.citrusframework.simulator.service.ScenarioExecutionQueryService;
import org.citrusframework.simulator.service.ScenarioExecutionService;
import org.citrusframework.simulator.service.criteria.ScenarioExecutionCriteria;
import org.citrusframework.simulator.web.rest.dto.ScenarioExecutionDTO;
import org.citrusframework.simulator.web.rest.dto.mapper.ScenarioExecutionMapper;
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 org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.springframework.http.HttpStatus.OK;

@ExtendWith({MockitoExtension.class})
class ScenarioExecutionResourceTest {

@Mock
private ScenarioExecutionService scenarioExecutionServiceMock;

@Mock
private ScenarioExecutionQueryService scenarioExecutionQueryServiceMock;

@Mock
private ScenarioExecutionMapper scenarioExecutionMapperMock;

private ScenarioExecutionResource fixture;

@BeforeEach
void beforeEachSetup() {
fixture = new ScenarioExecutionResource(scenarioExecutionServiceMock, scenarioExecutionQueryServiceMock, scenarioExecutionMapperMock);
}

@Nested
class GetAllScenarioExecutions {

@Mock
private ScenarioExecutionCriteria criteriaMock;

@Mock
private Pageable pageableMock;

@Mock
private ScenarioExecutionDTO scenarioExecutionDTOMock;

private ScenarioExecution scenarioExecution;

@BeforeEach
void beforeEachSetup() {
var request = new MockHttpServletRequest();
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));

scenarioExecution = new ScenarioExecution();
scenarioExecution.getScenarioActions().add(mock(ScenarioAction.class));
scenarioExecution.getScenarioMessages().add(mock(Message.class));
scenarioExecution.getScenarioParameters().add(mock(ScenarioParameter.class));

var scenarioExecutions = new PageImpl<>(singletonList(scenarioExecution));
doReturn(scenarioExecutions).when(scenarioExecutionQueryServiceMock).findByCriteria(criteriaMock, pageableMock);

doReturn(scenarioExecutionDTOMock).when(scenarioExecutionMapperMock).toDto(scenarioExecution);
}

@Test
void stripsIncludedActions() {
var response = fixture.getAllScenarioExecutions(criteriaMock, FALSE, TRUE, TRUE, pageableMock);

assertThat(response)
.satisfies(
r -> assertThat(r.getStatusCode()).isEqualTo(OK),
r -> assertThat(r.getBody())
.singleElement()
.isEqualTo(scenarioExecutionDTOMock)
);

assertThat(scenarioExecution.getScenarioActions()).isEmpty();
assertThat(scenarioExecution.getScenarioMessages()).isNotEmpty();
assertThat(scenarioExecution.getScenarioParameters()).isNotEmpty();
}

@Test
void stripsIncludedMessages() {
var response = fixture.getAllScenarioExecutions(criteriaMock, TRUE, FALSE, TRUE, pageableMock);

assertThat(response)
.satisfies(
r -> assertThat(r.getStatusCode()).isEqualTo(OK),
r -> assertThat(r.getBody())
.singleElement()
.isEqualTo(scenarioExecutionDTOMock)
);

assertThat(scenarioExecution.getScenarioActions()).isNotEmpty();
assertThat(scenarioExecution.getScenarioMessages()).isEmpty();
assertThat(scenarioExecution.getScenarioParameters()).isNotEmpty();
}

@Test
void stripsIncludedParameters() {
var response = fixture.getAllScenarioExecutions(criteriaMock, TRUE, TRUE, FALSE, pageableMock);

assertThat(response)
.satisfies(
r -> assertThat(r.getStatusCode()).isEqualTo(OK),
r -> assertThat(r.getBody())
.singleElement()
.isEqualTo(scenarioExecutionDTOMock)
);

assertThat(scenarioExecution.getScenarioActions()).isNotEmpty();
assertThat(scenarioExecution.getScenarioMessages()).isNotEmpty();
assertThat(scenarioExecution.getScenarioParameters()).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import static org.citrusframework.simulator.web.rest.ScenarioResource.Scenario.ScenarioType.STARTER;
import static org.junit.jupiter.params.provider.Arguments.arguments;
Expand Down Expand Up @@ -122,7 +123,7 @@ void doesFilterCacheWithNameContains(String filterLetter, String expectedScenari

assertThat(result)
.extracting(ResponseEntity::getBody)
.asList()
.asInstanceOf(LIST)
.hasSize(1)
.first()
.asInstanceOf(type(Scenario.class))
Expand All @@ -141,7 +142,7 @@ void doesFilterCacheWithNameStartsOrEndsWith() {

assertThat(result)
.extracting(ResponseEntity::getBody)
.asList()
.asInstanceOf(LIST)
.hasSize(2)
.noneSatisfy(scenario ->
assertThat(scenario)
Expand All @@ -161,7 +162,7 @@ void doesNotFilterCacheWithoutNameContains() {

assertThat(result)
.extracting(ResponseEntity::getBody)
.asList()
.asInstanceOf(LIST)
.isEqualTo(SCENARIO_CACHE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,20 @@ export class ScenarioExecutionService {
.pipe(map(res => this.convertResponseFromServer(res)));
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
query(
req?: any,
responseConfig: { includeActions: boolean; includeMessages: boolean; includeParameters: boolean } = {
includeActions: false,
includeMessages: false,
includeParameters: false,
},
): Observable<EntityArrayResponseType> {
let options = createRequestOption(req);

for (const key of Object.keys(responseConfig)) {
options = options.append(key, responseConfig[key as keyof typeof responseConfig]);
}

return this.http
.get<RestScenarioExecution[]>(this.resourceUrl, { params: options, observe: 'response' })
.pipe(map(res => this.convertResponseArrayFromServer(res)));
Expand Down

0 comments on commit 55349a7

Please sign in to comment.