Skip to content

Commit 0abcfa4

Browse files
authored
TestKit - Model Unmrashalling (#359)
* Use model defined in unmarshal definition instead of annotation when unmarshalling objects in TestKit * Add camel-jackson dependency * Add changelog * Refactor and add tests * Add tests
1 parent 7ad0615 commit 0abcfa4

6 files changed

Lines changed: 398 additions & 5 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"author": "Nemikor",
3+
"pullrequestId": 359,
4+
"message": "Use model defined in the the unmarshal definition of a connector instead of response model from annotation to read objects while executing a test case."
5+
}

sip-test-kit/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,9 @@
127127
<artifactId>camel-kafka-starter</artifactId>
128128
<optional>true</optional>
129129
</dependency>
130+
<dependency>
131+
<groupId>org.apache.camel</groupId>
132+
<artifactId>camel-jackson</artifactId>
133+
</dependency>
130134
</dependencies>
131135
</project>

sip-test-kit/src/main/java/one/x1f/sip/foundation/testkit/util/TestKitHelper.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88

99
import com.fasterxml.jackson.core.JsonProcessingException;
1010
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import java.util.List;
1112
import lombok.extern.slf4j.Slf4j;
1213
import one.x1f.sip.foundation.core.util.SIPExchangeHelper;
1314
import one.x1f.sip.foundation.core.util.exception.SIPFrameworkException;
1415
import one.x1f.sip.foundation.testkit.configurationproperties.models.EndpointProperties;
1516
import one.x1f.sip.foundation.testkit.workflow.givenphase.Mock;
1617
import org.apache.camel.*;
1718
import org.apache.camel.builder.ExchangeBuilder;
19+
import org.apache.camel.component.jackson.JacksonDataFormat;
20+
import org.apache.camel.model.*;
21+
import org.apache.camel.model.dataformat.JsonDataFormat;
1822

1923
/** Utility class that changes the {@link Exchange} */
2024
@Slf4j
@@ -114,4 +118,32 @@ public static void unmarshallExchangeBodyFromJson(
114118
throw new SIPFrameworkException(e);
115119
}
116120
}
121+
122+
public static Class<?> extractUnmarshalClass(RouteDefinition routeDef) {
123+
for (ProcessorDefinition<?> output : routeDef.getOutputs()) {
124+
if (output instanceof ChoiceDefinition choiceDef) {
125+
return findUnmarshalType(choiceDef.getOutputs());
126+
}
127+
}
128+
return null;
129+
}
130+
131+
private static Class<?> findUnmarshalType(List<ProcessorDefinition<?>> outputs) {
132+
for (ProcessorDefinition<?> output : outputs) {
133+
if (output instanceof UnmarshalDefinition unmarshalDef) {
134+
return extractUnmarshalType(unmarshalDef.getDataFormatType());
135+
}
136+
}
137+
return null;
138+
}
139+
140+
private static Class<?> extractUnmarshalType(DataFormatDefinition dfDef) {
141+
if (dfDef instanceof JsonDataFormat jsonDf) {
142+
return jsonDf.getUnmarshalType();
143+
}
144+
if (dfDef != null && dfDef.getDataFormat() instanceof JacksonDataFormat jacksonDf) {
145+
return jacksonDf.getUnmarshalType();
146+
}
147+
return null;
148+
}
117149
}

sip-test-kit/src/main/java/one/x1f/sip/foundation/testkit/workflow/givenphase/ProcessorProxyMock.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package one.x1f.sip.foundation.testkit.workflow.givenphase;
22

3+
import static one.x1f.sip.foundation.testkit.util.TestKitHelper.extractUnmarshalClass;
34
import static one.x1f.sip.foundation.testkit.util.TestKitHelper.unmarshallExchangeBodyFromJson;
45
import static one.x1f.sip.foundation.testkit.workflow.whenphase.routeinvoker.impl.DirectRouteInvoker.CONNECTOR_ID_EXCHANGE_PROPERTY;
56
import static one.x1f.sip.foundation.testkit.workflow.whenphase.routeinvoker.impl.DirectRouteInvoker.STRING_CLASS;
@@ -10,6 +11,8 @@
1011
import lombok.RequiredArgsConstructor;
1112
import lombok.extern.slf4j.Slf4j;
1213
import one.x1f.sip.foundation.core.declarative.DeclarationsRegistryApi;
14+
import one.x1f.sip.foundation.core.declarative.RouteRole;
15+
import one.x1f.sip.foundation.core.declarative.RoutesRegistry;
1316
import one.x1f.sip.foundation.core.declarative.connector.ConnectorDefinition;
1417
import one.x1f.sip.foundation.core.proxies.ProcessorProxy;
1518
import one.x1f.sip.foundation.core.proxies.ProcessorProxyRegistry;
@@ -18,6 +21,7 @@
1821
import one.x1f.sip.foundation.testkit.exception.TestCaseInitializationException;
1922
import one.x1f.sip.foundation.testkit.workflow.TestExecutionStatus;
2023
import org.apache.camel.Exchange;
24+
import org.apache.camel.model.*;
2125
import org.springframework.context.annotation.Scope;
2226
import org.springframework.stereotype.Component;
2327

@@ -31,6 +35,7 @@ public class ProcessorProxyMock extends Mock {
3135
private final ProcessorProxyRegistry proxyRegistry;
3236
private final ObjectMapper mapper;
3337
private final Optional<DeclarationsRegistryApi> declarationsRegistry;
38+
private final Optional<RoutesRegistry> routesRegistry;
3439

3540
/**
3641
* Sets a mock operation on a proxy
@@ -81,7 +86,7 @@ private void unmarshallFromJson(Exchange exchange, String connectorId) {
8186
Optional<ConnectorDefinition> connector =
8287
declarationsRegistry.flatMap(registry -> registry.getConnectorById(connectorId));
8388
if (connector.isPresent()) {
84-
Optional<Class<?>> responseModelClass = connector.get().getResponseModelClass();
89+
Optional<Class<?>> responseModelClass = getUnmarshalType(exchange, connector);
8590
if (responseModelClass.isPresent()) {
8691
if (!responseModelClass.get().equals(STRING_CLASS)) {
8792
unmarshallExchangeBodyFromJson(exchange, mapper, responseModelClass.get());
@@ -92,4 +97,27 @@ private void unmarshallFromJson(Exchange exchange, String connectorId) {
9297
}
9398
}
9499
}
100+
101+
private Optional<Class<?>> getUnmarshalType(
102+
Exchange exchange, Optional<ConnectorDefinition> connector) {
103+
Model modelContext =
104+
exchange.getContext().getCamelContextExtension().getContextPlugin(Model.class);
105+
if (routesRegistry.isPresent() && connector.isPresent()) {
106+
var routes = routesRegistry.get().getRoutesInfo(connector.get());
107+
var external =
108+
routes.stream()
109+
.filter(
110+
route ->
111+
route.getRouteRole().equals(RouteRole.EXTERNAL_ENDPOINT.getExternalName()))
112+
.findFirst();
113+
if (external.isPresent()) {
114+
var routeDef = modelContext.getRouteDefinition(external.get().getRouteId());
115+
Class<?> unmarshalType = extractUnmarshalClass(routeDef);
116+
if (unmarshalType != null) {
117+
return Optional.of(unmarshalType);
118+
}
119+
}
120+
}
121+
return connector.isPresent() ? connector.get().getResponseModelClass() : Optional.empty();
122+
}
95123
}

sip-test-kit/src/test/java/one/x1f/sip/foundation/testkit/util/TestKitHelperTest.java

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@
1111
import static org.mockito.Mockito.when;
1212

1313
import com.fasterxml.jackson.databind.ObjectMapper;
14+
import java.lang.reflect.Method;
1415
import java.util.HashMap;
16+
import java.util.List;
1517
import java.util.Map;
1618
import one.x1f.sip.foundation.core.util.exception.SIPFrameworkException;
1719
import one.x1f.sip.foundation.testkit.configurationproperties.models.EndpointProperties;
1820
import one.x1f.sip.foundation.testkit.configurationproperties.models.MessageProperties;
1921
import one.x1f.sip.foundation.testkit.workflow.givenphase.Mock;
2022
import one.x1f.sip.foundation.testkit.workflow.whenphase.routeinvoker.impl.DirectRouteInvokerTest;
2123
import org.apache.camel.*;
24+
import org.apache.camel.component.jackson.JacksonDataFormat;
25+
import org.apache.camel.model.*;
26+
import org.apache.camel.model.dataformat.JsonDataFormat;
2227
import org.junit.jupiter.api.BeforeEach;
2328
import org.junit.jupiter.api.Test;
2429
import org.junit.jupiter.params.ParameterizedTest;
@@ -170,4 +175,195 @@ void GIVEN_PersonJsonRequestModel_WHEN_unmarshallExchangeBodyFromJson_THEN_expec
170175
})
171176
.isInstanceOf(SIPFrameworkException.class);
172177
}
178+
179+
@Test
180+
void
181+
GIVEN_choiceContainingJsonDslUnmarshal_WHEN_extractUnmarshalClass_THEN_returnsUnmarshalType() {
182+
JsonDataFormat jsonDf = mock(JsonDataFormat.class);
183+
when(jsonDf.getUnmarshalType()).thenReturn((Class) MyModel.class);
184+
185+
UnmarshalDefinition unmarshalDef = mock(UnmarshalDefinition.class);
186+
when(unmarshalDef.getDataFormatType()).thenReturn(jsonDf);
187+
188+
ChoiceDefinition choiceDef = mock(ChoiceDefinition.class);
189+
when(choiceDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(unmarshalDef));
190+
191+
RouteDefinition routeDef = mock(RouteDefinition.class);
192+
when(routeDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(choiceDef));
193+
194+
Class<?> result = TestKitHelper.extractUnmarshalClass(routeDef);
195+
196+
assertThat(result).isEqualTo(MyModel.class);
197+
}
198+
199+
@Test
200+
void
201+
GIVEN_choiceContainingRawJacksonDataFormatUnmarshal_WHEN_extractUnmarshalClass_THEN_returnsUnmarshalType() {
202+
JacksonDataFormat jacksonDf = mock(JacksonDataFormat.class);
203+
when(jacksonDf.getUnmarshalType()).thenReturn((Class) MyModel.class);
204+
205+
DataFormatDefinition dfDef = mock(DataFormatDefinition.class);
206+
when(dfDef.getDataFormat()).thenReturn(jacksonDf);
207+
208+
UnmarshalDefinition unmarshalDef = mock(UnmarshalDefinition.class);
209+
when(unmarshalDef.getDataFormatType()).thenReturn(dfDef);
210+
211+
ChoiceDefinition choiceDef = mock(ChoiceDefinition.class);
212+
when(choiceDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(unmarshalDef));
213+
214+
RouteDefinition routeDef = mock(RouteDefinition.class);
215+
when(routeDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(choiceDef));
216+
217+
Class<?> result = TestKitHelper.extractUnmarshalClass(routeDef);
218+
219+
assertThat(result).isEqualTo(MyModel.class);
220+
}
221+
222+
@Test
223+
void GIVEN_routeWithoutChoice_WHEN_extractUnmarshalClass_THEN_returnsNull() {
224+
LogDefinition logDef = mock(LogDefinition.class);
225+
226+
RouteDefinition routeDef = mock(RouteDefinition.class);
227+
when(routeDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(logDef));
228+
229+
Class<?> result = TestKitHelper.extractUnmarshalClass(routeDef);
230+
231+
assertThat(result).isNull();
232+
}
233+
234+
@Test
235+
void GIVEN_choiceWithoutUnmarshal_WHEN_extractUnmarshalClass_THEN_returnsNull() {
236+
LogDefinition logDef = mock(LogDefinition.class);
237+
238+
ChoiceDefinition choiceDef = mock(ChoiceDefinition.class);
239+
when(choiceDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(logDef));
240+
241+
RouteDefinition routeDef = mock(RouteDefinition.class);
242+
when(routeDef.getOutputs()).thenReturn(List.<ProcessorDefinition<?>>of(choiceDef));
243+
244+
Class<?> result = TestKitHelper.extractUnmarshalClass(routeDef);
245+
246+
assertThat(result).isNull();
247+
}
248+
249+
@Test
250+
void GIVEN_outputsContainingUnmarshalDefinition_WHEN_findUnmarshalType_THEN_returnsUnmarshalType()
251+
throws Exception {
252+
JsonDataFormat jsonDf = mock(JsonDataFormat.class);
253+
when(jsonDf.getUnmarshalType()).thenReturn((Class) MyModel.class);
254+
255+
UnmarshalDefinition unmarshalDef = mock(UnmarshalDefinition.class);
256+
when(unmarshalDef.getDataFormatType()).thenReturn(jsonDf);
257+
258+
List<ProcessorDefinition<?>> outputs = List.of(unmarshalDef);
259+
260+
Class<?> result = invokeFindUnmarshalType(outputs);
261+
262+
assertThat(result).isEqualTo(MyModel.class);
263+
}
264+
265+
@Test
266+
void GIVEN_emptyOutputs_WHEN_findUnmarshalType_THEN_returnsNull() throws Exception {
267+
Class<?> result = invokeFindUnmarshalType(List.of());
268+
269+
assertThat(result).isNull();
270+
}
271+
272+
@Test
273+
void GIVEN_outputsWithoutUnmarshalDefinition_WHEN_findUnmarshalType_THEN_returnsNull()
274+
throws Exception {
275+
LogDefinition logDef = mock(LogDefinition.class);
276+
277+
List<ProcessorDefinition<?>> outputs = List.of(logDef);
278+
279+
Class<?> result = invokeFindUnmarshalType(outputs);
280+
281+
assertThat(result).isNull();
282+
}
283+
284+
@Test
285+
void GIVEN_jsonDataFormatModel_WHEN_extractUnmarshalType_THEN_returnsUnmarshalType()
286+
throws Exception {
287+
JsonDataFormat jsonDf = mock(JsonDataFormat.class);
288+
when(jsonDf.getUnmarshalType()).thenReturn((Class) MyModel.class);
289+
290+
Class<?> result = invokeExtractUnmarshalType(jsonDf);
291+
292+
assertThat(result).isEqualTo(MyModel.class);
293+
}
294+
295+
@Test
296+
void
297+
GIVEN_dataFormatDefinitionWrappingJacksonDataFormat_WHEN_extractUnmarshalType_THEN_returnsUnmarshalType()
298+
throws Exception {
299+
JacksonDataFormat jacksonDf = mock(JacksonDataFormat.class);
300+
when(jacksonDf.getUnmarshalType()).thenReturn((Class) MyModel.class);
301+
302+
DataFormatDefinition dfDef = mock(DataFormatDefinition.class);
303+
when(dfDef.getDataFormat()).thenReturn(jacksonDf);
304+
305+
Class<?> result = invokeExtractUnmarshalType(dfDef);
306+
307+
assertThat(result).isEqualTo(MyModel.class);
308+
}
309+
310+
@Test
311+
void
312+
GIVEN_arrayUnmarshalType_WHEN_extractUnmarshalType_THEN_returnsArrayClassWithMatchingComponentType()
313+
throws Exception {
314+
JacksonDataFormat jacksonDf = mock(JacksonDataFormat.class);
315+
when(jacksonDf.getUnmarshalType()).thenReturn((Class) MyModel[].class);
316+
317+
DataFormatDefinition dfDef = mock(DataFormatDefinition.class);
318+
when(dfDef.getDataFormat()).thenReturn(jacksonDf);
319+
320+
Class<?> result = invokeExtractUnmarshalType(dfDef);
321+
322+
assertThat(result).isEqualTo(MyModel[].class);
323+
assertThat(result.getComponentType()).isEqualTo(MyModel.class);
324+
}
325+
326+
@Test
327+
void GIVEN_nullDataFormatDefinition_WHEN_extractUnmarshalType_THEN_returnsNull()
328+
throws Exception {
329+
Class<?> result = invokeExtractUnmarshalType(null);
330+
331+
assertThat(result).isNull();
332+
}
333+
334+
@Test
335+
void GIVEN_unrelatedDataFormatDefinition_WHEN_extractUnmarshalType_THEN_returnsNull()
336+
throws Exception {
337+
DataFormatDefinition dfDef = mock(DataFormatDefinition.class);
338+
when(dfDef.getDataFormat()).thenReturn(null);
339+
340+
Class<?> result = invokeExtractUnmarshalType(dfDef);
341+
342+
assertThat(result).isNull();
343+
}
344+
345+
private Class<?> invokeFindUnmarshalType(List<ProcessorDefinition<?>> outputs) throws Exception {
346+
Method m = TestKitHelper.class.getDeclaredMethod("findUnmarshalType", List.class);
347+
m.setAccessible(true);
348+
return (Class<?>) m.invoke(null, outputs);
349+
}
350+
351+
private Class<?> invokeExtractUnmarshalType(DataFormatDefinition dfDef) throws Exception {
352+
Method m =
353+
TestKitHelper.class.getDeclaredMethod("extractUnmarshalType", DataFormatDefinition.class);
354+
m.setAccessible(true);
355+
return (Class<?>) m.invoke(null, dfDef);
356+
}
357+
358+
static class MyModel {
359+
private String field;
360+
361+
public String getField() {
362+
return field;
363+
}
364+
365+
public void setField(String field) {
366+
this.field = field;
367+
}
368+
}
173369
}

0 commit comments

Comments
 (0)