rest call test (untested)
This commit is contained in:
@@ -13,6 +13,7 @@ import java.util.List;
|
||||
/**
|
||||
* Reads an .xlsx workbook (created with Excel or LibreOffice) from the classpath
|
||||
* and returns all cells as Strings: book > sheets > rows > cells.
|
||||
*
|
||||
* Restrictions per sheet:
|
||||
* - The column count is defined by the first row: it starts with the 1st cell
|
||||
* and ends at the 1st empty cell
|
||||
|
||||
@@ -40,6 +40,7 @@ import java.lang.annotation.*;
|
||||
@ExtendWith(TemplateExtension.class)
|
||||
@ExtendWith(TenantSetupExtension.class)
|
||||
@ExtendWith(TestMailServerExtension.class)
|
||||
@ExtendWith(TestRestServerExtension.class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@Transactional
|
||||
@SpringBootTest
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.flowable.audit.api.runtime.AuditInstance;
|
||||
import com.flowable.core.spring.security.SecurityUtils;
|
||||
import com.flowable.platform.service.task.CompleteFormRepresentation;
|
||||
import com.flowable.platform.service.task.PlatformTaskService;
|
||||
import com.flowable.serviceregistry.api.runtime.ServiceInvocationResultResponse;
|
||||
import com.flowable.serviceregistry.api.runtime.ServiceRegistryRuntimeService;
|
||||
import com.github.wnameless.json.flattener.JsonFlattener;
|
||||
import com.github.wnameless.json.unflattener.JsonUnflattener;
|
||||
import jakarta.mail.Address;
|
||||
@@ -35,6 +37,8 @@ import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.platform.commons.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -59,6 +63,9 @@ public class FlowableModelTestUtils {
|
||||
protected final FlowableExcelMapper flowableExcelMapper;
|
||||
protected static final Logger logger = LoggerFactory.getLogger(FlowableModelTestUtils.class);
|
||||
protected final TestMailServer testMailServer;
|
||||
protected final TestRestServer testRestServer;
|
||||
protected final TestRestClient testRestClient;
|
||||
protected final ServiceRegistryRuntimeService serviceRegistryRuntimeService;
|
||||
protected final AuditService auditService;
|
||||
protected final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@@ -79,6 +86,9 @@ public class FlowableModelTestUtils {
|
||||
ManagementService managementService,
|
||||
FlowableExcelMapper flowableExcelMapper,
|
||||
TestMailServer testMailServer,
|
||||
TestRestServer testRestServer,
|
||||
TestRestClient testRestClient,
|
||||
ServiceRegistryRuntimeService serviceRegistryRuntimeService,
|
||||
AuditService auditService) {
|
||||
this.processEngine = processEngine;
|
||||
this.cmmnEngine = cmmnEngine;
|
||||
@@ -87,6 +97,9 @@ public class FlowableModelTestUtils {
|
||||
this.managementService = managementService;
|
||||
this.flowableExcelMapper = flowableExcelMapper;
|
||||
this.testMailServer = testMailServer;
|
||||
this.testRestServer = testRestServer;
|
||||
this.testRestClient = testRestClient;
|
||||
this.serviceRegistryRuntimeService = serviceRegistryRuntimeService;
|
||||
this.auditService = auditService;
|
||||
// Enable ObjectMapper for handling Instant as string
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
@@ -157,6 +170,25 @@ public class FlowableModelTestUtils {
|
||||
.containsExactlyInAnyOrder(receivers.split("[,\\s]+"));
|
||||
}
|
||||
|
||||
public void checkAndAssertRestRequest(Map<String, Object> map, int restNumber, String hint, String method, String path) {
|
||||
if (map != null) {
|
||||
Object check = map.get("rest");
|
||||
if (check instanceof Integer && (Integer) check > 0) {
|
||||
assertRestRequest(restNumber, hint, method, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertRestRequest(int restNumber, String hint, String method, String path) {
|
||||
if (restNumber <= 0) return;
|
||||
List<RestRequestDto> restRequests = getRestRequestList();
|
||||
Assertions.assertThat(restRequests.size()).as("%s: invalid rest request number %s", hint, restNumber).isGreaterThanOrEqualTo(restNumber);
|
||||
|
||||
RestRequestDto restRequest = restRequests.get(restNumber - 1);
|
||||
Assertions.assertThat(restRequest.method()).as("%s: invalid method %s", hint, restRequest.method()).isEqualTo(method);
|
||||
Assertions.assertThat(restRequest.path()).as("%s: invalid path %s", hint, restRequest.path()).isEqualTo(path);
|
||||
}
|
||||
|
||||
public Map<String, Object> getHistoryCasePayload(String caseInstanceId) {
|
||||
List<HistoricVariableInstance> historicVariableInstanceList = cmmnEngine.getCmmnHistoryService()
|
||||
.createHistoricVariableInstanceQuery()
|
||||
@@ -187,6 +219,15 @@ public class FlowableModelTestUtils {
|
||||
.start();
|
||||
}
|
||||
|
||||
public CaseInstance getCaseInstance(String caseDefinitionKey) {
|
||||
CaseInstance caseInstance = cmmnEngine.getCmmnRuntimeService()
|
||||
.createCaseInstanceQuery()
|
||||
.caseDefinitionKey(caseDefinitionKey)
|
||||
.singleResult();
|
||||
Assertions.assertThat(caseInstance).as("No case instance with definition key %s found", caseDefinitionKey).isNotNull();
|
||||
return caseInstance;
|
||||
}
|
||||
|
||||
public Task getOpenTask(String taskKey) {
|
||||
Task task = taskService.createTaskQuery().taskDefinitionKey(taskKey).singleResult();
|
||||
Assertions.assertThat(task).as("No open task with key %s found", taskKey).isNotNull();
|
||||
@@ -221,6 +262,31 @@ public class FlowableModelTestUtils {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<RestRequestDto> getRestRequestList() {
|
||||
return testRestServer.getRequests();
|
||||
}
|
||||
|
||||
public void stubRestResponse(String method, String path, int status, String body) {
|
||||
testRestServer.stubResponse(method, path, status, body);
|
||||
}
|
||||
|
||||
public ResponseEntity<String> sendRestEvent(String channelKey, ObjectNode payload) {
|
||||
return testRestClient.sendChannelEvent(channelKey, payload);
|
||||
}
|
||||
|
||||
public ResponseEntity<String> sendRestCall(HttpMethod method, String path, Object body) {
|
||||
return testRestClient.exchange(method, path, body);
|
||||
}
|
||||
|
||||
public ServiceInvocationResultResponse invokeRestService(String serviceKey, String operationKey, Map<String, Object> serviceData) {
|
||||
return serviceRegistryRuntimeService.createServiceInvocationBuilder()
|
||||
.serviceKey(serviceKey)
|
||||
.operationKey(operationKey)
|
||||
.serviceData(serviceData)
|
||||
.tenantId(TENANT_ID) // Must not be "default"
|
||||
.invoke();
|
||||
}
|
||||
|
||||
public boolean isSubset(JsonNode root, JsonNode test) {
|
||||
// If test is null, it is always a subset of root
|
||||
if (test == null || test.isNull()) {
|
||||
@@ -326,9 +392,12 @@ public class FlowableModelTestUtils {
|
||||
Integer emailCount = null;
|
||||
JsonNode emailNode = row.get("email");
|
||||
if (emailNode != null) emailCount = emailNode.asInt();
|
||||
Integer restCount = null;
|
||||
JsonNode restNode = row.get("rest");
|
||||
if (restNode != null) restCount = restNode.asInt();
|
||||
|
||||
logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} ",
|
||||
path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount);
|
||||
logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} rest={} ",
|
||||
path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount, restCount);
|
||||
Assertions.assertThat(idParam).as("Column 'id' missing in row of %s", path).isNotNull();
|
||||
ObjectNode processIds = createRootTestProcessInstance(idParam.asText(), convertJsonNodeToMap(vars));
|
||||
for (int i = 0; i < timerCount; i++) {
|
||||
@@ -353,6 +422,11 @@ public class FlowableModelTestUtils {
|
||||
Assertions.assertThat(emailList.size()).as("Invalid number of emails: %s", emailList.size()).isEqualTo(emailCount);
|
||||
result.set("emails", objectMapper.valueToTree(Collections.singletonList(emailList)));
|
||||
}
|
||||
if (restCount != null) {
|
||||
List<RestRequestDto> restRequests = getRestRequestList();
|
||||
Assertions.assertThat(restRequests.size()).as("Invalid number of rest requests: %s", restRequests.size()).isEqualTo(restCount);
|
||||
result.set("restRequests", objectMapper.valueToTree(Collections.singletonList(restRequests)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -381,9 +455,12 @@ public class FlowableModelTestUtils {
|
||||
Integer emailCount = null;
|
||||
Object emailNode = row.get("email");
|
||||
if (emailNode != null) emailCount = (Integer) emailNode;
|
||||
Integer restCount = null;
|
||||
Object restNode = row.get("rest");
|
||||
if (restNode != null) restCount = (Integer) restNode;
|
||||
|
||||
logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} ",
|
||||
path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount);
|
||||
logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} rest={} ",
|
||||
path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount, restCount);
|
||||
Assertions.assertThat(idParam).as("Column 'id' missing in row of %s", path).isNotNull();
|
||||
ObjectNode processIds = createRootTestProcessInstance(idParam, vars);
|
||||
for (int i = 0; i < timerCount; i++) {
|
||||
@@ -408,6 +485,11 @@ public class FlowableModelTestUtils {
|
||||
Assertions.assertThat(emailList.size()).as("Invalid number of emails: %s", emailList.size()).isEqualTo(emailCount);
|
||||
result.put("email", emailCount);
|
||||
}
|
||||
if (restCount != null) {
|
||||
List<RestRequestDto> restRequests = getRestRequestList();
|
||||
Assertions.assertThat(restRequests.size()).as("Invalid number of rest requests: %s", restRequests.size()).isEqualTo(restCount);
|
||||
result.put("rest", restCount);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.customer.work.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public record RestRequestDto(String method, String path, String query, Map<String, List<String>> headers, String body) {
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.customer.work.model;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.Filter;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Test client simulating incoming REST calls which are processed in Flowable models. The
|
||||
* requests are executed against the real Flowable REST API (including the security filter
|
||||
* chain) but in-process via MockMvc, so they participate in the test transaction. Base URL
|
||||
* and basic auth are taken from the application configuration (see 'test.rest.in.*').
|
||||
*
|
||||
* The Flowable REST APIs are served by their own dispatcher servlets (/platform-api/*,
|
||||
* /process-api/*, ...) which are never initialized in the mock web environment. Requests
|
||||
* are therefore routed by path prefix to the matching servlet registration, whose child
|
||||
* application context is refreshed on first use.
|
||||
*/
|
||||
@Component
|
||||
public class TestRestClient {
|
||||
private final WebApplicationContext webApplicationContext;
|
||||
private final Filter springSecurityFilterChain;
|
||||
private final String baseUrl;
|
||||
private final String basicAuthHeader;
|
||||
private final Map<String, MockMvc> mockMvcByServletPath = new ConcurrentHashMap<>();
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public TestRestClient(WebApplicationContext webApplicationContext,
|
||||
@Qualifier("springSecurityFilterChain") Filter springSecurityFilterChain,
|
||||
@Value("${test.rest.in.base-url}") String baseUrl,
|
||||
@Value("${test.rest.in.username}") String username,
|
||||
@Value("${test.rest.in.password}") String password) {
|
||||
this.webApplicationContext = webApplicationContext;
|
||||
this.springSecurityFilterChain = springSecurityFilterChain;
|
||||
this.baseUrl = baseUrl;
|
||||
this.basicAuthHeader = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public ResponseEntity<String> get(String path) {
|
||||
return exchange(HttpMethod.GET, path, null);
|
||||
}
|
||||
|
||||
public ResponseEntity<String> post(String path, Object body) {
|
||||
return exchange(HttpMethod.POST, path, body);
|
||||
}
|
||||
|
||||
public ResponseEntity<String> exchange(HttpMethod method, String path, Object body) {
|
||||
try {
|
||||
String servletPath = findServletPath(path);
|
||||
MockMvc mockMvc = mockMvcByServletPath.computeIfAbsent(servletPath, this::createMockMvc);
|
||||
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.request(method, URI.create(baseUrl + path))
|
||||
.servletPath(servletPath)
|
||||
.header(HttpHeaders.AUTHORIZATION, basicAuthHeader);
|
||||
if (body != null) {
|
||||
builder.contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsBytes(body));
|
||||
}
|
||||
MvcResult result = mockMvc.perform(builder).andReturn();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
for (String name : result.getResponse().getHeaderNames()) {
|
||||
headers.addAll(name, result.getResponse().getHeaders(name));
|
||||
}
|
||||
return ResponseEntity.status(result.getResponse().getStatus())
|
||||
.headers(headers)
|
||||
.body(new String(result.getResponse().getContentAsByteArray(), StandardCharsets.UTF_8));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot execute " + method + " " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResponseEntity<String> sendChannelEvent(String channelKey, Object payload) {
|
||||
return post("/platform-api/channel-definitions/key/" + channelKey + "/events", payload);
|
||||
}
|
||||
|
||||
protected String findServletPath(String path) {
|
||||
for (ServletRegistrationBean<?> registration : webApplicationContext.getBeansOfType(ServletRegistrationBean.class).values()) {
|
||||
for (String urlMapping : registration.getUrlMappings()) {
|
||||
if (urlMapping.endsWith("/*") && path.startsWith(urlMapping.substring(0, urlMapping.length() - 1))) {
|
||||
return urlMapping.substring(0, urlMapping.length() - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected MockMvc createMockMvc(String servletPath) {
|
||||
WebApplicationContext context = webApplicationContext;
|
||||
if (!servletPath.isEmpty()) {
|
||||
context = findServletContext(servletPath);
|
||||
}
|
||||
return MockMvcBuilders.webAppContextSetup(context)
|
||||
.addFilters(springSecurityFilterChain)
|
||||
.build();
|
||||
}
|
||||
|
||||
protected WebApplicationContext findServletContext(String servletPath) {
|
||||
for (ServletRegistrationBean<?> registration : webApplicationContext.getBeansOfType(ServletRegistrationBean.class).values()) {
|
||||
if (registration.getUrlMappings().contains(servletPath + "/*")
|
||||
&& registration.getServlet() instanceof DispatcherServlet dispatcherServlet) {
|
||||
WebApplicationContext servletContext = dispatcherServlet.getWebApplicationContext();
|
||||
if (servletContext instanceof ConfigurableWebApplicationContext configurableContext && !configurableContext.isActive()) {
|
||||
configurableContext.setServletContext(webApplicationContext.getServletContext());
|
||||
configurableContext.refresh();
|
||||
}
|
||||
return servletContext;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("No dispatcher servlet registered for " + servletPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.customer.work.model;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Test server receiving outgoing REST calls sent from Flowable models. The models resolve
|
||||
* their base URL from the application configuration (see 'test.rest.out.base-url'), so all
|
||||
* outgoing calls end up here, get recorded and are answered with stubbed responses.
|
||||
* Requests must carry basic auth matching the configured credentials, otherwise 401 is returned.
|
||||
*/
|
||||
@Component
|
||||
public class TestRestServer {
|
||||
private HttpServer server;
|
||||
private final List<RestRequestDto> requests = new CopyOnWriteArrayList<>();
|
||||
private final List<StubbedResponse> stubs = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final String baseUrl;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public TestRestServer(@Value("${test.rest.out.base-url}") String baseUrl,
|
||||
@Value("${test.rest.out.username}") String username,
|
||||
@Value("${test.rest.out.password}") String password) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setup() {
|
||||
try {
|
||||
URI uri = URI.create(baseUrl);
|
||||
server = HttpServer.create(new InetSocketAddress(uri.getHost(), uri.getPort()), 0);
|
||||
server.createContext("/", this::handle);
|
||||
server.start();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Cannot start TestRestServer on " + baseUrl, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (server != null) {
|
||||
server.stop(0);
|
||||
server = null;
|
||||
}
|
||||
requests.clear();
|
||||
stubs.clear();
|
||||
}
|
||||
|
||||
public void stubResponse(String method, String path, int status, String body) {
|
||||
stubs.add(new StubbedResponse(method, path, status, body));
|
||||
}
|
||||
|
||||
public List<RestRequestDto> getRequests() {
|
||||
if (server == null) {
|
||||
throw new IllegalStateException("TestRestServer is not started, is the TestRestServerExtension registered?");
|
||||
}
|
||||
return new ArrayList<>(requests);
|
||||
}
|
||||
|
||||
protected void handle(HttpExchange exchange) throws IOException {
|
||||
try {
|
||||
String method = exchange.getRequestMethod();
|
||||
URI uri = exchange.getRequestURI();
|
||||
String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
|
||||
requests.add(new RestRequestDto(method, uri.getPath(), uri.getQuery(), new LinkedHashMap<>(exchange.getRequestHeaders()), body));
|
||||
|
||||
if (!isAuthorized(exchange)) {
|
||||
send(exchange, 401, "{\"error\":\"unauthorized\"}");
|
||||
return;
|
||||
}
|
||||
StubbedResponse stub = findStub(method, uri.getPath());
|
||||
if (stub != null) {
|
||||
send(exchange, stub.status(), stub.body());
|
||||
} else {
|
||||
send(exchange, 200, "{}");
|
||||
}
|
||||
} finally {
|
||||
exchange.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAuthorized(HttpExchange exchange) {
|
||||
if (username == null || username.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
String expected = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
|
||||
return expected.equals(exchange.getRequestHeaders().getFirst("Authorization"));
|
||||
}
|
||||
|
||||
protected StubbedResponse findStub(String method, String path) {
|
||||
return stubs.stream()
|
||||
.filter(stub -> stub.method().equalsIgnoreCase(method) && path.startsWith(stub.path()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private void send(HttpExchange exchange, int status, String body) throws IOException {
|
||||
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.getResponseHeaders().set("Content-Type", "application/json");
|
||||
exchange.sendResponseHeaders(status, bytes.length);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
}
|
||||
|
||||
public record StubbedResponse(String method, String path, int status, String body) {}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.customer.work.model;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
public class TestRestServerExtension implements BeforeEachCallback, AfterEachCallback {
|
||||
@Override
|
||||
public void beforeEach(@NonNull ExtensionContext context) {
|
||||
getTestRestServer(context).setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(@NonNull ExtensionContext context) {
|
||||
getTestRestServer(context).stop();
|
||||
}
|
||||
|
||||
protected TestRestServer getTestRestServer(ExtensionContext context) {
|
||||
return SpringExtension.getApplicationContext(context).getBean(TestRestServer.class);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,10 @@ package com.customer.work.model.test;
|
||||
import com.customer.work.model.EmailDto;
|
||||
import com.customer.work.model.FlowableModelTest;
|
||||
import com.customer.work.model.FlowableModelTestUtils;
|
||||
import com.customer.work.model.RestRequestDto;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.flowable.serviceregistry.api.runtime.ServiceInvocationResultResponse;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.flowable.cmmn.api.runtime.CaseInstance;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
@@ -13,6 +15,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -76,6 +79,35 @@ public class ModelTest {
|
||||
.hasMessageContaining("Implicit parameter 'param'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void c002RestInboundTest() {
|
||||
// Simulate an incoming REST call to the inbound channel TST_CH001, processed by case TST_C002
|
||||
ObjectNode payload = flowableModelTest.emptyNode();
|
||||
payload.put("param", "my event payload");
|
||||
ResponseEntity<String> response = flowableModelTest.sendRestEvent("TST_CH001", payload);
|
||||
Assertions.assertThat(response.getStatusCode().is2xxSuccessful()).as("response: %s", response.getBody()).isTrue();
|
||||
|
||||
CaseInstance caseInstance = flowableModelTest.getCaseInstance("TST_C002");
|
||||
Map<String, Object> casePayload = flowableModelTest.getRuntimeCasePayload(caseInstance.getId());
|
||||
// param is mapped as full payload, so it contains the complete event body
|
||||
Assertions.assertThat(String.valueOf(casePayload.get("param"))).contains("my event payload");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sv001RestOutgoingTest() {
|
||||
// The outgoing REST call from service model TST_SV001 is answered by the test REST server
|
||||
flowableModelTest.stubRestResponse("GET", "/idm-api/current-user", 200,
|
||||
"{\"id\":\"admin\",\"firstName\":\"Test\",\"lastName\":\"Administrator\"}");
|
||||
ServiceInvocationResultResponse result = flowableModelTest.invokeRestService("TST_SV001", "getCurrentUser", Map.of());
|
||||
Assertions.assertThat(result.getValue("id")).isEqualTo("admin");
|
||||
Assertions.assertThat(result.getValue("lastName")).isEqualTo("Administrator");
|
||||
|
||||
List<RestRequestDto> restRequests = flowableModelTest.getRestRequestList();
|
||||
Assertions.assertThat(restRequests).hasSize(1);
|
||||
Assertions.assertThat(restRequests.get(0).method()).isEqualTo("GET");
|
||||
Assertions.assertThat(restRequests.get(0).path()).isEqualTo("/idm-api/current-user");
|
||||
}
|
||||
|
||||
private Stream<Arguments> p002TestData() {
|
||||
return Stream.of(
|
||||
Arguments.of("model/test/P002/boolean1.json", true, false),
|
||||
|
||||
Reference in New Issue
Block a user