diff --git a/.github/project.yml b/.github/project.yml index 9d5af79cf5..fdd9a4da6c 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -1,4 +1,4 @@ name: Citrus Framework release: - current-version: 4.0.0 + current-version: 4.0.2 next-version: 4.1.0-SNAPSHOT diff --git a/connectors/citrus-docker/src/main/resources/META-INF/spring.schemas b/connectors/citrus-docker/src/main/resources/META-INF/spring.schemas index 250bfcfd9b..0b52afb8fe 100644 --- a/connectors/citrus-docker/src/main/resources/META-INF/spring.schemas +++ b/connectors/citrus-docker/src/main/resources/META-INF/spring.schemas @@ -30,10 +30,10 @@ http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-3.3.1. http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-3.4.0.xsd=com/consol/citrus/schema/citrus-docker-config-3.4.0.xsd http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-docker-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-docker-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-docker-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-docker-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-docker-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.0.0.xsd=org/citrusframework/schema/citrus-docker-config-4.0.0.xsd +http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.0.1.xsd=org/citrusframework/schema/citrus-docker-config-4.0.1.xsd +http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.0.2.xsd=org/citrusframework/schema/citrus-docker-config-4.0.2.xsd +http\://www.citrusframework.org/schema/docker/config/citrus-docker-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-docker-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/docker/config/citrus-docker-config.xsd=org/citrusframework/schema/citrus-docker-config.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-2.3.xsd=com/consol/citrus/schema/citrus-docker-testcase-2.3.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-2.4.xsd=com/consol/citrus/schema/citrus-docker-testcase-2.4.xsd @@ -67,8 +67,8 @@ http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-3. http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-docker-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-docker-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-docker-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-docker-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-docker-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-docker-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-docker-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-docker-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-docker-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-docker-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase.xsd=org/citrusframework/schema/citrus-docker-testcase.xsd diff --git a/connectors/citrus-kubernetes/src/main/resources/META-INF/spring.schemas b/connectors/citrus-kubernetes/src/main/resources/META-INF/spring.schemas index 985bfd2bc9..8ff010c076 100644 --- a/connectors/citrus-kubernetes/src/main/resources/META-INF/spring.schemas +++ b/connectors/citrus-kubernetes/src/main/resources/META-INF/spring.schemas @@ -22,10 +22,10 @@ http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-confi http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-3.4.0.xsd=com/consol/citrus/schema/citrus-kubernetes-config-3.4.0.xsd http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.0.0.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.0.0.xsd +http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.0.1.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.0.1.xsd +http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.0.2.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.0.2.xsd +http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kubernetes-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config.xsd=org/citrusframework/schema/citrus-kubernetes-config.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-2.7.1.xsd=com/consol/citrus/schema/citrus-kubernetes-testcase-2.7.1.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-2.7.2.xsd=com/consol/citrus/schema/citrus-kubernetes-testcase-2.7.2.xsd @@ -51,8 +51,8 @@ http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-tes http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-kubernetes-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kubernetes-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase.xsd=org/citrusframework/schema/citrus-kubernetes-testcase.xsd diff --git a/connectors/citrus-selenium/src/main/resources/META-INF/spring.schemas b/connectors/citrus-selenium/src/main/resources/META-INF/spring.schemas index e6a552118a..6fdbea98fa 100644 --- a/connectors/citrus-selenium/src/main/resources/META-INF/spring.schemas +++ b/connectors/citrus-selenium/src/main/resources/META-INF/spring.schemas @@ -22,10 +22,10 @@ http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-3. http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-3.4.0.xsd=com/consol/citrus/schema/citrus-selenium-config-3.4.0.xsd http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-selenium-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-selenium-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-selenium-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-selenium-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-selenium-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.0.0.xsd=org/citrusframework/schema/citrus-selenium-config-4.0.0.xsd +http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.0.1.xsd=org/citrusframework/schema/citrus-selenium-config-4.0.1.xsd +http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.0.2.xsd=org/citrusframework/schema/citrus-selenium-config-4.0.2.xsd +http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-selenium-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/selenium/config/citrus-selenium-config.xsd=org/citrusframework/schema/citrus-selenium-config.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-2.7.1.xsd=com/consol/citrus/schema/citrus-selenium-testcase-2.7.1.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-2.7.2.xsd=com/consol/citrus/schema/citrus-selenium-testcase-2.7.2.xsd @@ -51,8 +51,8 @@ http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcas http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-selenium-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-selenium-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase.xsd=org/citrusframework/schema/citrus-selenium-testcase.xsd diff --git a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/groovy/AbstractGroovyActionDslTest.java b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/groovy/AbstractGroovyActionDslTest.java index b255fb60fb..92f73773ed 100644 --- a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/groovy/AbstractGroovyActionDslTest.java +++ b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/xml/AbstractXmlActionTest.java b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/xml/AbstractXmlActionTest.java index f91ecfc7c1..46ddf81d14 100644 --- a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/xml/AbstractXmlActionTest.java +++ b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/yaml/AbstractYamlActionTest.java b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/yaml/AbstractYamlActionTest.java index e1c59a478f..6ff8ba526c 100644 --- a/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/yaml/AbstractYamlActionTest.java +++ b/connectors/citrus-selenium/src/test/java/org/citrusframework/selenium/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecutePLSQLTestActionBuilderTest.java b/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecutePLSQLTestActionBuilderTest.java index 6bd7346815..b6c35b5ca6 100644 --- a/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecutePLSQLTestActionBuilderTest.java +++ b/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecutePLSQLTestActionBuilderTest.java @@ -107,6 +107,7 @@ public void testExecutePLSQLBuilderWithTransaction() { @Test public void testExecutePLSQLBuilderWithSQLResource() throws IOException { reset(jdbcTemplate, sqlResource); + when(sqlResource.exists()).thenReturn(true); when(sqlResource.getInputStream()).thenReturn(new ByteArrayInputStream(("TEST_STMT_1\n" + "/\n" + "TEST_STMT_2\n" + diff --git a/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLTestActionBuilderTest.java b/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLTestActionBuilderTest.java index efa25a9860..b8bdce62dc 100644 --- a/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLTestActionBuilderTest.java +++ b/connectors/citrus-sql/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLTestActionBuilderTest.java @@ -16,14 +16,12 @@ package org.citrusframework.actions.dsl; -import java.io.File; import java.io.IOException; import org.citrusframework.DefaultTestCaseRunner; import org.citrusframework.TestCase; import org.citrusframework.UnitTestSupport; import org.citrusframework.actions.ExecuteSQLAction; -import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; import org.mockito.Mockito; import org.springframework.jdbc.core.JdbcTemplate; @@ -42,8 +40,6 @@ public class ExecuteSQLTestActionBuilderTest extends UnitTestSupport { private final JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class); private final PlatformTransactionManager transactionManager = Mockito.mock(PlatformTransactionManager.class); - private final Resource resource = Mockito.mock(Resource.class); - private final File file = Mockito.mock(File.class); @Test public void testExecuteSQLBuilderWithStatement() { diff --git a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/groovy/AbstractGroovyActionDslTest.java b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/groovy/AbstractGroovyActionDslTest.java index ec92aedfda..11541e49cf 100644 --- a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/groovy/AbstractGroovyActionDslTest.java +++ b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/xml/AbstractXmlActionTest.java b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/xml/AbstractXmlActionTest.java index bb1e7df903..f00c73ddfd 100644 --- a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/xml/AbstractXmlActionTest.java +++ b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/xml/AbstractXmlActionTest.java @@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -64,6 +65,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/yaml/AbstractYamlActionTest.java b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/yaml/AbstractYamlActionTest.java index a57a13f527..e69695d874 100644 --- a/connectors/citrus-sql/src/test/java/org/citrusframework/sql/yaml/AbstractYamlActionTest.java +++ b/connectors/citrus-sql/src/test/java/org/citrusframework/sql/yaml/AbstractYamlActionTest.java @@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -64,6 +65,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/core/citrus-api/src/main/java/org/citrusframework/spi/ClasspathResourceResolver.java b/core/citrus-api/src/main/java/org/citrusframework/spi/ClasspathResourceResolver.java index 2998d63046..289dcc3a92 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/spi/ClasspathResourceResolver.java +++ b/core/citrus-api/src/main/java/org/citrusframework/spi/ClasspathResourceResolver.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -36,9 +37,10 @@ import java.util.Set; import java.util.function.Predicate; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.stream.Collectors; - +import org.citrusframework.exceptions.CitrusRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,7 +49,9 @@ */ public class ClasspathResourceResolver { - /** Logger */ + /** + * Logger + */ private static final Logger logger = LoggerFactory.getLogger(ClasspathResourceResolver.class); public Set getClasses(String path) throws IOException { @@ -83,11 +87,12 @@ public Set getResources(String path) throws IOException { public Set getResources(String path, String fileNamePattern) throws IOException { return getResources(path).stream() - .filter(resource -> resource.getFileName().toString().matches(fileNamePattern)) - .collect(Collectors.toSet()); + .filter(resource -> resource.getFileName().toString().matches(fileNamePattern)) + .collect(Collectors.toSet()); } - private void findResources(String path, ClassLoader classLoader, Set result, Predicate filter) throws IOException { + private void findResources(String path, ClassLoader classLoader, Set result, + Predicate filter) throws IOException { String resourcePath; // If the URL is a jar, the URLClassloader.getResources() seems to require a trailing slash. The // trailing slash is harmless for other URLs @@ -113,7 +118,7 @@ private void findResources(String path, ClassLoader classLoader, Set resul if (file.isDirectory()) { loadResourcesInDirectory(resourcePath, file, result, filter); } else { - loadResourcesInJar(classLoader, resourcePath, new FileInputStream(file), urlPath, result, filter); + loadResourcesInJar(classLoader, resourcePath, urlPath, result, filter); } } catch (IOException e) { logger.debug("Failed to read entries in url: {}", url, e); @@ -121,8 +126,36 @@ private void findResources(String path, ClassLoader classLoader, Set resul } } - private void loadResourcesInJar(ClassLoader classLoader, String path, FileInputStream jarInputStream, - String urlPath, Set resources, Predicate filter) { + private void loadResourcesInJar(ClassLoader classLoader, String path, + String urlPath, Set resources, Predicate filter) + throws IOException { + + String[] split = urlPath.split("!"); + + if (split.length == 1) { + readFromJarStream(classLoader, path, urlPath, resources, filter, new FileInputStream(split[0])); + } else if (split.length == 2) { + loadFromNestedJar(classLoader, path, urlPath, resources, filter, split[0], split[1]); + } else { + throw new CitrusRuntimeException("Unable to load urlPath from : "+urlPath); + } + + } + + /** + * Load resources from a nested jar, also known as fat jar. These are typically used in spring + * boot applications. + */ + private static void loadFromNestedJar(ClassLoader classLoader, String path, String urlPath, + Set resources, Predicate filter, String baseJar, String nestedJar) throws IOException { + try (JarFile jarFile = new JarFile(baseJar)) { + JarEntry jarEntry = jarFile.getJarEntry(nestedJar.substring(1)); + readFromJarStream(classLoader, path, urlPath, resources, filter, jarFile.getInputStream(jarEntry)); + } + } + + private static void readFromJarStream(ClassLoader classLoader, String path, String urlPath, + Set resources, Predicate filter, InputStream jarInputStream) { List entries = new ArrayList<>(); try (JarInputStream jarStream = new JarInputStream(jarInputStream);) { JarEntry entry; @@ -137,19 +170,24 @@ private void loadResourcesInJar(ClassLoader classLoader, String path, FileInputS } for (String name : entries) { - String shortName = name.substring(path.length()); - logger.trace("Found resource: {} in {}", shortName, urlPath); + if (logger.isTraceEnabled()) { + logger.trace("Found resource: {} in {}", name.substring(path.length()), + urlPath); + } URL url = classLoader.getResource(name); if (url != null) { resources.add(Paths.get(name)); } } } catch (IOException e) { - logger.warn("Cannot search jar file '{} due to an IOException: {}", urlPath, e.getMessage(), e); + logger.warn("Cannot search jar file '{} due to an IOException: {}", urlPath, + e.getMessage(), e); } } - private void loadResourcesInDirectory(String path, File location, Set result, Predicate filter) { + + private void loadResourcesInDirectory(String path, File location, Set result, + Predicate filter) { File[] files = location.listFiles(); if (files == null || files.length == 0) { return; @@ -161,7 +199,8 @@ private void loadResourcesInDirectory(String path, File location, Set resu String name = file.getName().trim(); if (file.isDirectory()) { - loadResourcesInDirectory(builder.append(path).append(name).append("/").toString(), file, result, filter); + loadResourcesInDirectory(builder.append(path).append(name).append("/").toString(), + file, result, filter); } else if (file.isFile() && file.exists() && filter.test(name)) { logger.trace("Found resource: {} as {}", name, file.toURI()); result.add(Paths.get(builder.append(path).append(name).toString())); @@ -197,7 +236,7 @@ private String parseUrlPath(URL url) { } // else it may be in a JAR, grab the path to the jar - return urlPath.contains("!") ? urlPath.substring(0, urlPath.indexOf("!")) : urlPath; + return urlPath.contains("!") ? urlPath.substring(0, urlPath.lastIndexOf("!")) : urlPath; } private Set getClassLoaders() { @@ -208,7 +247,9 @@ private Set getClassLoaders() { classLoaders.add(ccl); } } catch (Exception e) { - logger.warn("Cannot add ContextClassLoader from current thread due {}. This exception will be ignored", e.getMessage()); + logger.warn( + "Cannot add ContextClassLoader from current thread due {}. This exception will be ignored", + e.getMessage()); } classLoaders.add(ClasspathResourceResolver.class.getClassLoader()); diff --git a/core/citrus-api/src/main/java/org/citrusframework/spi/PropertiesLoader.java b/core/citrus-api/src/main/java/org/citrusframework/spi/PropertiesLoader.java new file mode 100644 index 0000000000..4d5516979e --- /dev/null +++ b/core/citrus-api/src/main/java/org/citrusframework/spi/PropertiesLoader.java @@ -0,0 +1,52 @@ +package org.citrusframework.spi; + +import org.citrusframework.exceptions.CitrusRuntimeException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public final class PropertiesLoader { + + private PropertiesLoader() { + // Not intended for instantiation + } + + public static Properties loadProperties(Resource resource) { + Properties properties = new Properties(); + try (InputStream inputStream = resource.getInputStream()) { + System.out.println("Resource: " + resource); + loadProperties(resource.getLocation(), properties, inputStream); + } catch (IOException e) { + throwPropertiesLoadingFailedException(resource.getLocation(), e); + } + return properties; + } + + public static Properties loadProperties(String path) { + Properties properties = new Properties(); + try (InputStream in = ResourcePathTypeResolver.class.getClassLoader().getResourceAsStream(path)) { + if (in == null) { + throw new CitrusRuntimeException(String.format("Failed to locate resource path '%s'!", path)); + } + + loadProperties(path, properties, in); + } catch (IOException e) { + throwPropertiesLoadingFailedException(path, e); + } + + return properties; + } + + private static void throwPropertiesLoadingFailedException(String path, IOException e) { + throw new CitrusRuntimeException(String.format("Unable to load properties from resource path configuration at '%s'", path), e); + } + + private static void loadProperties(String path, Properties properties, InputStream in) throws IOException { + if (path.endsWith(".xml")) { + properties.loadFromXML(in); + } else { + properties.load(in); + } + } +} diff --git a/core/citrus-api/src/main/java/org/citrusframework/spi/ResourcePathTypeResolver.java b/core/citrus-api/src/main/java/org/citrusframework/spi/ResourcePathTypeResolver.java index 795084c077..a58517afcb 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/spi/ResourcePathTypeResolver.java +++ b/core/citrus-api/src/main/java/org/citrusframework/spi/ResourcePathTypeResolver.java @@ -1,13 +1,6 @@ package org.citrusframework.spi; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.util.ObjectHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; @@ -28,6 +21,12 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.citrusframework.spi.PropertiesLoader.loadProperties; /** * Type resolver resolves references via resource path lookup. Provided resource paths should point @@ -191,8 +190,11 @@ private String toCacheKey(String path, String property, String keyProperty) { private Stream resolveAllFromJar(String path) { String rootAsString = ResourcePathTypeResolver.class.getProtectionDomain().getCodeSource().getLocation().toString(); + ClassLoader classLoader = ObjectHelper.assertNotNull(ResourcePathTypeResolver.class.getClassLoader()); - if (rootAsString.endsWith(".jar") && !rootAsString.matches(".*" + File.separator + "citrus-api-\\d+\\.\\d+\\.\\d+(-.*)?\\.jar")) { + if (rootAsString.matches(".*jar(!/)?") && + !rootAsString.replace("\\", "/") + .matches(".*/citrus-api-\\d+\\.\\d+\\.\\d+(-.*)?\\.jar")) { return getZipEntries().stream() .filter(entry -> entry.startsWith(path)) .map(classLoader::getResource) @@ -288,23 +290,7 @@ private Constructor getConstructor(Class type, Object[] initargs) { private Properties readAsProperties(String resourcePath) { return resourceProperties.computeIfAbsent(resourcePath, k -> { String path = getFullResourcePath(resourcePath); - - try(InputStream in = ResourcePathTypeResolver.class.getClassLoader().getResourceAsStream(path)) { - if (in == null) { - throw new CitrusRuntimeException(String.format("Failed to locate resource path '%s'!", path)); - } - - Properties config = new Properties(); - if (resourcePath.endsWith(".xml")) { - config.loadFromXML(in); - } else { - config.load(in); - } - - return config; - } catch (IOException e) { - throw new CitrusRuntimeException(String.format("Unable to load properties from resource path configuration at '%s'", path), e); - } + return loadProperties(path); }); } diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/DefaultTextEqualsMessageValidator.java b/core/citrus-api/src/main/java/org/citrusframework/validation/DefaultTextEqualsMessageValidator.java new file mode 100644 index 0000000000..277e0fe5c5 --- /dev/null +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/DefaultTextEqualsMessageValidator.java @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2023 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.validation; + +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.message.Message; +import org.citrusframework.validation.context.ValidationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Default message validator implementation performing text equals on given message payloads. + * Validator auto converts message payloads into a String representation in order to perform text equals validation. + * Both received and control message should have textual message payloads. + * By default, the validator ignores leading and trailing whitespaces and normalizes the line endings before the validation. + * Usually this validator implementation is used as a fallback option when no other matching validator implementation could be found. + * + * @author Christoph Deppisch + */ +public class DefaultTextEqualsMessageValidator extends DefaultMessageValidator { + + private static final Logger logger = LoggerFactory.getLogger(DefaultTextEqualsMessageValidator.class); + + private boolean normalizeLineEndings = true; + private boolean trim = true; + + @Override + public void validateMessage(Message receivedMessage, Message controlMessage, + TestContext context, ValidationContext validationContext) { + if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { + logger.debug("Skip message payload validation as no control message was defined"); + return; + } + + logger.debug("Start to verify message payload ..."); + + String controlPayload = controlMessage.getPayload(String.class); + String receivedPayload = receivedMessage.getPayload(String.class); + + if (trim) { + controlPayload = controlPayload.trim(); + receivedPayload = receivedPayload.trim(); + } + + if (normalizeLineEndings) { + controlPayload = normalizeLineEndings(controlPayload); + receivedPayload = normalizeLineEndings(receivedPayload); + } + + if (!receivedPayload.equals(controlPayload)) { + throw new ValidationException("Validation failed - message payload not equal!"); + } + } + + public DefaultTextEqualsMessageValidator normalizeLineEndings() { + this.normalizeLineEndings = true; + return this; + } + + public DefaultTextEqualsMessageValidator enableTrim() { + this.trim = true; + return this; + } + + /** + * Normalize the text by replacing line endings by a linux representation. + */ + private static String normalizeLineEndings(String text) { + return text.replace("\r\n", "\n").replace(" ", ""); + } +} diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java index a7f4210400..1114ef0c0e 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java @@ -58,8 +58,9 @@ public class MessageValidatorRegistry { /** Default message header validator - gets looked up via resource path */ private MessageValidator defaultMessageHeaderValidator; - /** Default empty message validator */ + /** Default message validators used as a fallback option */ private final DefaultEmptyMessageValidator defaultEmptyMessageValidator = new DefaultEmptyMessageValidator(); + private final DefaultTextEqualsMessageValidator defaultTextEqualsMessageValidator = new DefaultTextEqualsMessageValidator(); /** * Finds matching message validators for this message type. @@ -69,6 +70,18 @@ public class MessageValidatorRegistry { * @return the list of matching message validators. */ public List> findMessageValidators(String messageType, Message message) { + return findMessageValidators(messageType, message, false); + } + + /** + * Finds matching message validators for this message type. + * + * @param messageType the message type + * @param message the message object + * @param mustFindValidator is default fallback validator allowed + * @return the list of matching message validators. + */ + public List> findMessageValidators(String messageType, Message message, boolean mustFindValidator) { List> matchingValidators = new ArrayList<>(); for (MessageValidator validator : messageValidators.values()) { @@ -99,8 +112,13 @@ public List> findMessageValidators } if (isEmptyOrDefault(matchingValidators)) { - logger.warn(String.format("Unable to find proper message validator. Message type is '%s' and message payload is '%s'", messageType, message.getPayload(String.class))); - throw new CitrusRuntimeException("Failed to find proper message validator for message"); + if (mustFindValidator) { + logger.warn(String.format("Unable to find proper message validator. Message type is '%s' and message payload is '%s'", messageType, message.getPayload(String.class))); + throw new CitrusRuntimeException("Failed to find proper message validator for message"); + } + + logger.warn("Unable to find proper message validator - fallback to default text equals validation."); + matchingValidators.add(defaultTextEqualsMessageValidator); } if (logger.isDebugEnabled()) { @@ -184,7 +202,7 @@ public MessageValidator getMessageValidator(String } /** - * Adds given message validator and allows overwrite of existing message validators in registry with same name. + * Adds given message validator and allows to overwrite of existing message validators in registry with same name. * @param name * @param messageValidator */ diff --git a/core/citrus-api/src/test/java/org/citrusframework/spi/ClassPathResourceResolverTest.java b/core/citrus-api/src/test/java/org/citrusframework/spi/ClassPathResourceResolverTest.java new file mode 100644 index 0000000000..8a0676470a --- /dev/null +++ b/core/citrus-api/src/test/java/org/citrusframework/spi/ClassPathResourceResolverTest.java @@ -0,0 +1,114 @@ +package org.citrusframework.spi; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class ClassPathResourceResolverTest { + + @Test + void loadFromFatJar() throws IOException { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread() + .setContextClassLoader(new SimulatedNestedJarClassLoader("fatjar.jar", "!/BOOT-INF/lib/test-nested-jar.jar", contextClassLoader)); + ClasspathResourceResolver resolver = new ClasspathResourceResolver(); + Set resources = resolver.getResources("META-INF/citrus/test/parser/core"); + Assertions.assertTrue( + resources.contains(Path.of("META-INF/citrus/test/parser/core/schema-collection"))); + Assertions.assertTrue(resources.contains( + Path.of("META-INF/citrus/test/parser/core/xml-data-dictionary"))); + Assertions.assertTrue(resources.contains( + Path.of("META-INF/citrus/test/parser/core/xpath-data-dictionary"))); + } finally { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + } + + @Test + void loadFromSimpleJar() throws IOException { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread() + .setContextClassLoader(new SimulatedNestedJarClassLoader("simplejar.jar", "", contextClassLoader)); + ClasspathResourceResolver resolver = new ClasspathResourceResolver(); + Set resources = resolver.getResources("META-INF/citrus/test/parser/core"); + Assertions.assertTrue( + resources.contains(Path.of("META-INF/citrus/test/parser/core/schema-collection"))); + Assertions.assertTrue(resources.contains( + Path.of("META-INF/citrus/test/parser/core/xml-data-dictionary"))); + Assertions.assertTrue(resources.contains( + Path.of("META-INF/citrus/test/parser/core/xpath-data-dictionary"))); + } finally { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + } + + /** + * A classloader that simulates resolving from a nested jar. This kind of jar, also known as fat + * jar or uber jar is used in spring boot applications. + */ + private class SimulatedNestedJarClassLoader extends ClassLoader { + + private final String baseJar; + private final String nestedJar; + private final ClassLoader delegate; + + private SimulatedNestedJarClassLoader(String baseJar, String nestedJar, ClassLoader delegate) { + this.baseJar = baseJar; + this.nestedJar = nestedJar; + this.delegate = delegate; + } + + @Override + public Enumeration getResources(String name) throws IOException { + + if (name.equals("META-INF/citrus/test/parser/core/")) { + URL url = delegate.getResource(baseJar); + URL jarResourceUrl = new URL("jar:" + url.toString().replace("\\", "/") + + nestedJar+ "!/META-INF/citrus/test/parser/core"); + return Collections.enumeration(List.of(jarResourceUrl)); + } + return delegate.getResources(name); + } + + @Override + public URL getResource(String name) { + if ("BOOT-INF/lib/test-nested-jar.jar".equals(name)) { + return getNestedJarUrl(); + } else if (name.startsWith("META-INF/citrus/test/parser/core")) { + URL nestedJarUrl = getNestedJarUrl(); + try { + return new URL(nestedJarUrl + "/" + name); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + return delegate.getResource(name); + } + + private URL getNestedJarUrl() { + URL url = delegate.getResource(baseJar); + try { + return new URL("jar:" + url.toString().replace("\\", "/") + + "!/BOOT-INF/lib/test-nested-jar.jar"); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + @Override + public InputStream getResourceAsStream(String name) { + return delegate.getResourceAsStream(name); + } + + } +} \ No newline at end of file diff --git a/core/citrus-api/src/test/resources/fatjar.jar b/core/citrus-api/src/test/resources/fatjar.jar new file mode 100644 index 0000000000..4ae40f6a0e Binary files /dev/null and b/core/citrus-api/src/test/resources/fatjar.jar differ diff --git a/core/citrus-api/src/test/resources/simplejar.jar b/core/citrus-api/src/test/resources/simplejar.jar new file mode 100644 index 0000000000..91758f6b9c Binary files /dev/null and b/core/citrus-api/src/test/resources/simplejar.jar differ diff --git a/core/citrus-base/pom.xml b/core/citrus-base/pom.xml index 0bf2221079..a7cadf742b 100644 --- a/core/citrus-base/pom.xml +++ b/core/citrus-base/pom.xml @@ -21,8 +21,8 @@ - commons-lang - commons-lang + org.apache.commons + commons-lang3 commons-codec diff --git a/core/citrus-base/src/main/java/org/citrusframework/CitrusContext.java b/core/citrus-base/src/main/java/org/citrusframework/CitrusContext.java index 577209f173..673832901d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/CitrusContext.java +++ b/core/citrus-base/src/main/java/org/citrusframework/CitrusContext.java @@ -7,17 +7,22 @@ import java.util.Set; import org.citrusframework.annotations.CitrusAnnotations; +import org.citrusframework.common.InitializingPhase; import org.citrusframework.container.AfterSuite; +import org.citrusframework.container.AfterTest; import org.citrusframework.container.BeforeSuite; +import org.citrusframework.container.BeforeTest; import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; import org.citrusframework.endpoint.DefaultEndpointFactory; import org.citrusframework.endpoint.EndpointFactory; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.functions.DefaultFunctionRegistry; +import org.citrusframework.functions.FunctionLibrary; import org.citrusframework.functions.FunctionRegistry; import org.citrusframework.log.DefaultLogModifier; import org.citrusframework.log.LogModifier; +import org.citrusframework.message.MessageProcessor; import org.citrusframework.message.MessageProcessors; import org.citrusframework.report.*; import org.citrusframework.spi.ReferenceRegistry; @@ -30,6 +35,7 @@ import org.citrusframework.validation.MessageValidatorRegistry; import org.citrusframework.validation.context.ValidationContext; import org.citrusframework.validation.matcher.DefaultValidationMatcherRegistry; +import org.citrusframework.validation.matcher.ValidationMatcherLibrary; import org.citrusframework.validation.matcher.ValidationMatcherRegistry; import org.citrusframework.variable.GlobalVariables; import org.citrusframework.xml.namespace.NamespaceContextBuilder; @@ -340,6 +346,72 @@ public void handleTestResults(TestResults testResults) { } } + public void addComponent(String name, Object component) { + if (component instanceof InitializingPhase c) { + c.initialize(); + } + referenceResolver.bind(name, component); + + if (component instanceof MessageValidator messageValidator) { + messageValidatorRegistry.addMessageValidator(name, messageValidator); + testContextFactory.getMessageValidatorRegistry().addMessageValidator(name, messageValidator); + } + + if (component instanceof MessageProcessor messageProcessor) { + messageProcessors.addMessageProcessor(messageProcessor); + testContextFactory.getMessageProcessors().addMessageProcessor(messageProcessor); + } + + if (component instanceof TestSuiteListener suiteListener) { + testSuiteListeners.addTestSuiteListener(suiteListener); + } + + if (component instanceof TestListener testListener) { + testListeners.addTestListener(testListener); + testContextFactory.getTestListeners().addTestListener(testListener); + } + + if (component instanceof TestReporter testReporter) { + testReporters.addTestReporter(testReporter); + } + + if (component instanceof TestActionListener testActionListener) { + testActionListeners.addTestActionListener(testActionListener); + testContextFactory.getTestActionListeners().addTestActionListener(testActionListener); + } + + if (component instanceof MessageListener messageListener) { + messageListeners.addMessageListener(messageListener); + testContextFactory.getMessageListeners().addMessageListener(messageListener); + } + + if (component instanceof BeforeTest beforeTest) { + testContextFactory.getBeforeTest().add(beforeTest); + } + + if (component instanceof AfterTest afterTest) { + testContextFactory.getAfterTest().add(afterTest); + } + + if (component instanceof BeforeSuite beforeSuiteComponent) { + beforeSuite.add(beforeSuiteComponent); + } + + if (component instanceof AfterSuite afterSuiteComponent) { + afterSuite.add(afterSuiteComponent); + } + + if (component instanceof FunctionLibrary library) { + functionRegistry.addFunctionLibrary(library); + testContextFactory.getFunctionRegistry().addFunctionLibrary(library); + } + + if (component instanceof ValidationMatcherLibrary library) { + validationMatcherRegistry.addValidationMatcherLibrary(library); + testContextFactory.getValidationMatcherRegistry().addValidationMatcherLibrary(library); + } + } + /** * Citrus context builder. */ diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/AbstractAsyncTestAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/AbstractAsyncTestAction.java index ec734dbfcc..f588c85d4d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/AbstractAsyncTestAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/AbstractAsyncTestAction.java @@ -45,30 +45,32 @@ public abstract class AbstractAsyncTestAction extends AbstractTestAction impleme @Override public final void doExecute(TestContext context) { - CompletableFuture result = new CompletableFuture<>(); + CompletableFuture result = new CompletableFuture<>(); + + result.whenComplete((ctx, throwable) -> { + if (throwable != null) { + onError(ctx, throwable); + } else if (ctx.hasExceptions()) { + onError(ctx, ctx.getExceptions().get(0)); + } else { + onSuccess(ctx); + } + }); + ExecutorService executor = Executors.newSingleThreadExecutor(); finished = executor.submit(() -> { try { doExecuteAsync(context); - result.complete(null); } catch (Exception | Error e) { logger.warn("Async test action execution raised error", e); - if (e instanceof CitrusRuntimeException) { - context.addException((CitrusRuntimeException) e); + if (e instanceof CitrusRuntimeException citrusEx) { + context.addException(citrusEx); } else { context.addException(new CitrusRuntimeException(e)); } - - result.completeExceptionally(e); - } - }); - - result.whenComplete((nothing, throwable) -> { - if (throwable != null) { - onError(context, throwable); - } else { - onSuccess(context); + } finally { + result.complete(context); } }); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java index 5e87685ee4..1ab811dc7b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java @@ -43,6 +43,7 @@ import org.citrusframework.messaging.Consumer; import org.citrusframework.messaging.SelectiveConsumer; import org.citrusframework.spi.ReferenceResolverAware; +import org.citrusframework.util.StringUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; import org.citrusframework.validation.HeaderValidator; import org.citrusframework.validation.MessageValidator; @@ -60,7 +61,6 @@ import org.citrusframework.variable.dictionary.DataDictionary; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.citrusframework.util.StringUtils; /** * This action receives messages from a service destination. Action uses a {@link org.citrusframework.endpoint.Endpoint} @@ -251,21 +251,13 @@ protected void validateMessage(Message message, TestContext context) { } } } else { + boolean mustFindValidator = validationContexts.stream() + .anyMatch(item -> JsonPathMessageValidationContext.class.isAssignableFrom(item.getClass()) || + XpathMessageValidationContext.class.isAssignableFrom(item.getClass()) || + ScriptValidationContext.class.isAssignableFrom(item.getClass())); + List> validators = - context.getMessageValidatorRegistry().findMessageValidators(messageType, message); - - if (validators.isEmpty()) { - if (controlMessage.getPayload() instanceof String && - StringUtils.hasText(controlMessage.getPayload(String.class))) { - throw new CitrusRuntimeException(String.format("Unable to find proper message validator for message type '%s' and validation contexts '%s'", messageType, validationContexts)); - } else if (validationContexts.stream().anyMatch(item -> JsonPathMessageValidationContext.class.isAssignableFrom(item.getClass()) - || XpathMessageValidationContext.class.isAssignableFrom(item.getClass()) - || ScriptValidationContext.class.isAssignableFrom(item.getClass()))) { - throw new CitrusRuntimeException(String.format("Unable to find proper message validator for message type '%s' and validation contexts '%s'", messageType, validationContexts)); - } else { - logger.warn(String.format("Unable to find proper message validator for message type '%s' and validation contexts '%s'", messageType, validationContexts)); - } - } + context.getMessageValidatorRegistry().findMessageValidators(messageType, message, mustFindValidator); for (MessageValidator messageValidator : validators) { messageValidator.validateMessage(message, controlMessage, context, validationContexts); diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java index 384da6f891..f54866a961 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java @@ -96,7 +96,7 @@ public class SendMessageAction extends AbstractTestAction implements Completable private final DataDictionary dataDictionary; /** Finished indicator either called when forked send action is finished or immediately when this action has finished */ - private CompletableFuture finished; + private CompletableFuture finished; /** Logger */ private static final Logger logger = LoggerFactory.getLogger(SendMessageAction.class); @@ -129,6 +129,16 @@ public void doExecute(final TestContext context) { final Message message = createMessage(context, messageType); finished = new CompletableFuture<>(); + finished.whenComplete((ctx, ex) -> { + if (ex != null) { + logger.warn("Failure in forked send action: " + ex.getMessage()); + } else { + for (Exception ctxEx : ctx.getExceptions()) { + logger.warn(ctxEx.getMessage()); + } + } + }); + // extract variables from before sending message so we can save dynamic message ids for (VariableExtractor variableExtractor : variableExtractors) { variableExtractor.extractVariables(message, context); @@ -151,13 +161,13 @@ public void doExecute(final TestContext context) { validateMessage(message, context); messageEndpoint.createProducer().send(message, context); } catch (Exception e) { - if (e instanceof CitrusRuntimeException) { - context.addException((CitrusRuntimeException) e); + if (e instanceof CitrusRuntimeException runtimeEx) { + context.addException(runtimeEx); } else { context.addException(new CitrusRuntimeException(e)); } } finally { - finished.complete(null); + finished.complete(context); } }); } else { @@ -165,7 +175,7 @@ public void doExecute(final TestContext context) { validateMessage(message, context); messageEndpoint.createProducer().send(message, context); } finally { - finished.complete(null); + finished.complete(context); } } } @@ -175,7 +185,6 @@ public void doExecute(final TestContext context) { * @param message */ protected void validateMessage(Message message, TestContext context) { - List> schemaValidators = null; SchemaValidationContext validationContext = null; String payload = message.getPayload(String.class); diff --git a/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java b/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java index 6275ac412c..d42d330519 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java +++ b/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java @@ -25,14 +25,12 @@ import org.citrusframework.GherkinTestActionRunner; import org.citrusframework.TestActionRunner; import org.citrusframework.TestCaseRunner; -import org.citrusframework.common.InitializingPhase; +import org.citrusframework.common.Named; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.spi.ReferenceRegistry; import org.citrusframework.util.ReflectionHelper; -import org.citrusframework.validation.MessageValidator; -import org.citrusframework.validation.context.ValidationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -249,9 +247,12 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus try { String name = ReferenceRegistry.getName(m.getAnnotation(BindToRegistry.class), m.getName()); Object component = m.invoke(configuration); - citrusContext.getReferenceResolver().bind(name, component); - initializeComponent(name, component, citrusContext); + if (component instanceof Named named) { + named.setName(name); + } + + citrusContext.addComponent(name, component); } catch (IllegalAccessException | InvocationTargetException e) { throw new CitrusRuntimeException("Failed to invoke configuration method", e); } @@ -270,22 +271,15 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus try { String name = ReferenceRegistry.getName(f.getAnnotation(BindToRegistry.class), f.getName()); Object component = f.get(configuration); - citrusContext.getReferenceResolver().bind(name, component); - initializeComponent(name, component, citrusContext); + if (component instanceof Named named) { + named.setName(name); + } + + citrusContext.addComponent(name, component); } catch (IllegalAccessException e) { throw new CitrusRuntimeException("Failed to access configuration field", e); } }); } - - private static void initializeComponent(String name, Object component, CitrusContext citrusContext) { - if (component instanceof InitializingPhase c) { - c.initialize(); - } - - if (component instanceof MessageValidator) { - citrusContext.getMessageValidatorRegistry().addMessageValidator(name, (MessageValidator) component); - } - } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncEndpointConfiguration.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncEndpointConfiguration.java index fdffacad0e..a4927bf846 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncEndpointConfiguration.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncEndpointConfiguration.java @@ -33,7 +33,7 @@ public MessageCorrelator getCorrelator() { /** * Gets the pollingInterval. - * @return the pollingInterval the pollingInterval to get. + * @return the pollingInterval to get. */ public long getPollingInterval() { return pollingInterval; diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/ChangeDateFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/ChangeDateFunction.java index 4101d74322..4175a23c23 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/ChangeDateFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/ChangeDateFunction.java @@ -39,6 +39,8 @@ public class ChangeDateFunction extends AbstractDateFunction { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(ChangeDateFunction.class); + private final CalendarProvider calendarProvider = new CalendarProvider(); + /** * @see org.citrusframework.functions.Function#execute(java.util.List, org.citrusframework.context.TestContext) * @throws CitrusRuntimeException @@ -48,7 +50,7 @@ public String execute(List parameterList, TestContext context) { throw new InvalidFunctionUsageException("Function parameters must not be empty"); } - Calendar calendar = Calendar.getInstance(); + Calendar calendar = calendarProvider.getInstance(); SimpleDateFormat dateFormat; String result = ""; @@ -79,4 +81,14 @@ public String execute(List parameterList, TestContext context) { return result; } + static class CalendarProvider { + + private CalendarProvider () { + // This class allows mocking in unit tests + } + + Calendar getInstance() { + return Calendar.getInstance(); + } + } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/report/JUnitReporter.java b/core/citrus-base/src/main/java/org/citrusframework/report/JUnitReporter.java index c69236f2e4..0530b68b33 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/report/JUnitReporter.java +++ b/core/citrus-base/src/main/java/org/citrusframework/report/JUnitReporter.java @@ -16,6 +16,14 @@ package org.citrusframework.report; +import org.citrusframework.TestResult; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.PropertyUtils; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -30,14 +38,7 @@ import java.util.Optional; import java.util.Properties; -import org.citrusframework.TestResult; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.PropertyUtils; -import org.apache.commons.lang.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.citrusframework.util.StringUtils; +import static org.apache.commons.lang3.StringEscapeUtils.escapeXml; /** * @author Christoph Deppisch @@ -112,12 +113,12 @@ private String createReportContent(String suiteName, List results, R for (TestResult result: results) { Properties detailProps = new Properties(); detailProps.put("test.class", result.getClassName()); - detailProps.put("test.name", StringEscapeUtils.escapeXml(result.getTestName())); + detailProps.put("test.name", escapeXml(result.getTestName())); detailProps.put("test.duration", "0.0"); if (result.isFailed()) { detailProps.put("test.error.cause", Optional.ofNullable(result.getCause()).map(Object::getClass).map(Class::getName).orElseGet(() -> Objects.toString(result.getFailureType(), ""))); - detailProps.put("test.error.msg", StringEscapeUtils.escapeXml(result.getErrorMessage())); + detailProps.put("test.error.msg", escapeXml(result.getErrorMessage())); detailProps.put("test.error.stackTrace", Optional.ofNullable(result.getCause()).map(cause -> { StringWriter writer = new StringWriter(); cause.printStackTrace(new PrintWriter(writer)); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java index 30d9df6daf..034dee8b02 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java @@ -118,6 +118,10 @@ public static String readToString(Resource resource, Charset charset) throws IOE resource.getLocation(); } + if (!resource.exists()) { + throw new CitrusRuntimeException("Failed to read resource %s - does not exist".formatted(resource.getLocation())); + } + if (logger.isDebugEnabled()) { logger.debug(String.format("Reading file resource: '%s' (encoding is '%s')", resource.getLocation(), charset.displayName())); } @@ -132,6 +136,10 @@ public static String readToString(Resource resource, Charset charset) throws IOE * @throws IOException */ public static String readToString(InputStream inputStream, Charset charset) throws IOException { + if (inputStream == null) { + throw new CitrusRuntimeException("Failed to read resource %s - input stream is empty"); + } + return new String(inputStream.readAllBytes(), charset); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/variable/dictionary/AbstractDataDictionary.java b/core/citrus-base/src/main/java/org/citrusframework/variable/dictionary/AbstractDataDictionary.java index 3b7d0bad1a..8b969afa4b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/variable/dictionary/AbstractDataDictionary.java +++ b/core/citrus-base/src/main/java/org/citrusframework/variable/dictionary/AbstractDataDictionary.java @@ -16,19 +16,18 @@ package org.citrusframework.variable.dictionary; -import java.io.IOException; -import java.io.InputStream; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Properties; - import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.AbstractMessageProcessor; import org.citrusframework.spi.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import static org.citrusframework.spi.PropertiesLoader.loadProperties; + /** * Abstract data dictionary implementation provides global scope handling. * @author Christoph Deppisch @@ -75,27 +74,17 @@ public void initialize() { if (mappingFile != null) { logger.debug("Reading data dictionary mapping: {}", mappingFile.getLocation()); - Properties props = new Properties(); - try (InputStream inputStream = mappingFile.getInputStream()) { - if (mappingFile.getFile().getName().endsWith(".xml")) { - props.loadFromXML(inputStream); - } else { - props.load(inputStream); - } - } catch (IOException e) { - throw new CitrusRuntimeException(e); - } - - for (Map.Entry entry : props.entrySet()) { + Properties properties = loadProperties(mappingFile); + for (Map.Entry entry : properties.entrySet()) { String key = entry.getKey().toString(); - logger.debug("Loading data dictionary mapping: {}={}", key, props.getProperty(key)); + logger.debug("Loading data dictionary mapping: {}={}", key, properties.getProperty(key)); if (logger.isDebugEnabled() && mappings.containsKey(key)) { - logger.warn("Overwriting data dictionary mapping '{}'; old value: {} new value: {}", key, mappings.get(key), props.getProperty(key)); + logger.warn("Overwriting data dictionary mapping '{}'; old value: {} new value: {}", key, mappings.get(key), properties.getProperty(key)); } - mappings.put(key, props.getProperty(key)); + mappings.put(key, properties.getProperty(key)); } logger.info("Loaded data dictionary mapping: {}", mappingFile.getLocation()); diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java index fbc1e3fca9..39c3f7bf99 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java @@ -210,6 +210,7 @@ void testSetPayloadWithResourceIoExceptionsIsWrapped() throws IOException { //GIVEN final ReceiveMessageAction.Builder builder = new ReceiveMessageAction.Builder(); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenThrow(IOException.class); //WHEN diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java index e2b01c84d9..bbeb224038 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java @@ -43,7 +43,7 @@ import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.spi.Resource; import org.citrusframework.validation.AbstractValidationProcessor; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.builder.StaticMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; @@ -84,7 +84,7 @@ public class ReceiveMessageActionBuilderTest extends UnitTestSupport { @BeforeMethod public void prepareTestContext() { MockitoAnnotations.openMocks(this); - context.getMessageValidatorRegistry().addMessageValidator("default", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("default", new DefaultTextEqualsMessageValidator()); } @Test @@ -233,6 +233,7 @@ public void testReceiveBuilderWithPayloadResource() throws IOException { new DefaultMessage("Hello World!") .setHeader("operation", "foo")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); DefaultTestCaseRunner runner = new DefaultTestCaseRunner(context); runner.run(receive(messageEndpoint) @@ -539,6 +540,7 @@ public void testReceiveBuilderWithHeaderResource() throws IOException { .setHeader("operation", "bar") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())); @@ -595,6 +597,7 @@ public void testReceiveBuilderWithMultipleHeaderResource() throws IOException { .addHeaderData("
operationfoo
") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) @@ -654,7 +657,7 @@ public void testReceiveBuilderWithValidator() { when(configuration.getTimeout()).thenReturn(100L); when(messageEndpoint.getActor()).thenReturn(null); when(messageConsumer.receive(any(TestContext.class), anyLong())).thenReturn(new DefaultMessage("TestMessage").setHeader("operation", "sayHello")); - final TextEqualsMessageValidator validator = new TextEqualsMessageValidator(); + final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); DefaultTestCaseRunner runner = new DefaultTestCaseRunner(context); runner.run(receive(messageEndpoint) @@ -684,7 +687,7 @@ public void testReceiveBuilderWithValidator() { @Test public void testReceiveBuilderWithValidatorName() { - final TextEqualsMessageValidator validator = new TextEqualsMessageValidator(); + final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); reset(referenceResolver, messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java index b9e45e788e..5ec514e9b1 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java @@ -286,6 +286,7 @@ public void testSendBuilderWithPayloadResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); DefaultTestCaseRunner runner = new DefaultTestCaseRunner(context); runner.run(send(messageEndpoint) @@ -520,6 +521,7 @@ public void testSendBuilderWithHeaderDataResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo1
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo2
".getBytes())); DefaultTestCaseRunner runner = new DefaultTestCaseRunner(context); diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/ChangeDateFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/ChangeDateFunctionTest.java index 5f179ac5bb..80e67a28aa 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/ChangeDateFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/ChangeDateFunctionTest.java @@ -16,174 +16,206 @@ package org.citrusframework.functions.core; -import java.util.Calendar; -import java.util.Collections; - import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.FunctionParameterHelper; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.Calendar; +import java.util.Collections; + +import static org.mockito.Mockito.doReturn; + /** * @author Christoph Deppisch */ public class ChangeDateFunctionTest extends UnitTestSupport { - ChangeDateFunction function = new ChangeDateFunction(); + + @Mock + private ChangeDateFunction.CalendarProvider calendarProviderMock; + + private AutoCloseable mockitoContext; + + private ChangeDateFunction fixture; + + @BeforeMethod + void beforeMethodSetup() { + mockitoContext = MockitoAnnotations.openMocks(this); + + fixture = new ChangeDateFunction(); + ReflectionTestUtils.setField(fixture, "calendarProvider", calendarProviderMock, ChangeDateFunction.CalendarProvider.class); + } @Test public void testDefaultDateFormat() { - Calendar c = Calendar.getInstance(); + Calendar c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$td.%1$tm.%1$tY", Calendar.getInstance()) + "', '+1y'"), context), String.format("%1$td.%1$tm.%1$tY", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.MONTH, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$td.%1$tm.%1$tY", Calendar.getInstance()) + "', '+1M'"), context), String.format("%1$td.%1$tm.%1$tY", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.DAY_OF_YEAR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$td.%1$tm.%1$tY", Calendar.getInstance()) + "', '+1d'"), context), String.format("%1$td.%1$tm.%1$tY", c)); } @Test public void testFunction() { - Calendar c = Calendar.getInstance(); + Calendar c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.MONTH, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1M', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.DAY_OF_YEAR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1d', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.HOUR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1h', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.MINUTE, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1m', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.SECOND, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1s', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, 10); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+10y', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, 1); c.add(Calendar.MONTH, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y+1M', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); c.add(Calendar.DAY_OF_YEAR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y+1M+1d', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); c.add(Calendar.HOUR, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y+1M+1d+1h', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); c.add(Calendar.MINUTE, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y+1M+1d+1h+1m', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); c.add(Calendar.SECOND, 1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y+1M+1d+1h+1m+1s', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1y', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.MONTH, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1M', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.DAY_OF_YEAR, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1d', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.HOUR, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1h', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.MINUTE, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1m', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.SECOND, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1s', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, -1); c.add(Calendar.MONTH, 1); c.add(Calendar.DAY_OF_YEAR, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '-1y+1M-1d', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); - c = Calendar.getInstance(); + c = getAndInsertMockCalendar(); c.add(Calendar.YEAR, 1); c.add(Calendar.MONTH, -1); c.add(Calendar.DAY_OF_YEAR, -1); - Assert.assertEquals(function.execute(FunctionParameterHelper.getParameterList("'" + + Assert.assertEquals(fixture.execute(FunctionParameterHelper.getParameterList("'" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()) + "', '+1y-1M-1d', 'yyyy-MM-dd HH:mm:ss'"), context), String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", c)); } @Test(expectedExceptions = {CitrusRuntimeException.class}) public void testWrongDateFormatUsage() { - function.execute(FunctionParameterHelper.getParameterList("'1970-01-01', '+1y'"), context); + fixture.execute(FunctionParameterHelper.getParameterList("'1970-01-01', '+1y'"), context); } @Test(expectedExceptions = {InvalidFunctionUsageException.class}) public void testNoParameters() { - function.execute(Collections.EMPTY_LIST, context); + fixture.execute(Collections.EMPTY_LIST, context); + } + + private Calendar getAndInsertMockCalendar() { + Calendar c = Calendar.getInstance(); + doReturn(c.clone()).when(calendarProviderMock).getInstance(); + return c; + } + + @AfterMethod + public void afterMethodTeardown() throws Exception { + mockitoContext.close(); } } diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java new file mode 100644 index 0000000000..67d705b6e6 --- /dev/null +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2023 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.validation; + +import java.nio.charset.StandardCharsets; + +import org.citrusframework.UnitTestSupport; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.message.DefaultMessage; +import org.citrusframework.message.Message; +import org.citrusframework.validation.context.DefaultValidationContext; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * @author Christoph Deppisch + */ +public class DefaultTextEqualsMessageValidatorTest extends UnitTestSupport { + + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); + private final DefaultValidationContext validationContext = new DefaultValidationContext(); + + @Test(dataProvider = "successTests") + public void testValidate(Object received, Object control) { + Message receivedMessage = new DefaultMessage(received); + Message controlMessage = new DefaultMessage(control); + + validator.validateMessage(receivedMessage, controlMessage, context, validationContext); + } + + @Test(dataProvider = "errorTests", expectedExceptions = ValidationException.class) + public void testValidateError(Object received, Object control) throws Exception { + Message receivedMessage = new DefaultMessage(received); + Message controlMessage = new DefaultMessage(control); + + validator.validateMessage(receivedMessage, controlMessage, context, validationContext); + } + + @DataProvider + private Object[][] successTests() { + return new Object[][] { + new Object[]{ null, null }, + new Object[]{ "", null }, + new Object[]{ null, "" }, + new Object[]{ "Hello World!", "Hello World!" }, + new Object[]{ "Hello World! ", "Hello World!" }, + new Object[]{ "Hello World!", "Hello World! " }, + new Object[]{ "Hello World!\n", "Hello World!" }, + new Object[]{ "Hello World!\n", "Hello World!\n" }, + new Object[]{ "\nHello World!", "\nHello World!" }, + new Object[]{ "Hello\nWorld!\n", "Hello\nWorld!\n" }, + new Object[]{ "Hello\r\nWorld!\r\n", "Hello\nWorld!\n" }, + new Object[]{ "Hello World!", null }, // empty control message + new Object[]{ "Hello World!", "" }, // no control message + new Object[]{ "Hello World!".getBytes(StandardCharsets.UTF_8), "" } // no control message + }; + } + + @DataProvider + private Object[][] errorTests() { + return new Object[][] { + new Object[]{ null, "Hello World!" }, + new Object[]{ "", "Hello World!" }, + new Object[]{ "Hello World!", "Hello World!" }, + new Object[]{ "Hello World!", "Hello World!" }, + new Object[]{ "Hello\nWorld!", "Hello World!" }, + new Object[]{ "Hello World!", "Hello\nWorld!" }, + new Object[]{ "Hello!", "Hi!" }, + }; + } + +} diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java index 037aa2447a..2d71df9b9c 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java @@ -74,7 +74,7 @@ public class MessageValidatorRegistryTest { @Mock private SchemaValidator xmlSchemaValidator; - private MessageValidatorRegistry messageValidatorRegistry = new MessageValidatorRegistry(); + private final MessageValidatorRegistry messageValidatorRegistry = new MessageValidatorRegistry(); @BeforeClass public void setupMocks() { @@ -116,7 +116,6 @@ public void setupMocks() { messageValidatorRegistry.addSchemaValidator("jsonSchemaValidator", jsonSchemaValidator); messageValidatorRegistry.addSchemaValidator("xmlSchemaValidator", xmlSchemaValidator); - } @Test @@ -318,12 +317,18 @@ public void shouldAddDefaultEmptyMessagePayloadValidator() { Assert.assertEquals(matchingValidators.get(1).getClass(), DefaultMessageHeaderValidator.class); try { - messageValidatorRegistry.findMessageValidators(MessageType.JSON.name(), new DefaultMessage("Hello")); + messageValidatorRegistry.findMessageValidators(MessageType.JSON.name(), new DefaultMessage("Hello"), true); Assert.fail("Missing exception due to no proper message validator found"); } catch (CitrusRuntimeException e) { Assert.assertEquals(e.getMessage(), "Failed to find proper message validator for message"); } + matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.JSON.name(), new DefaultMessage("Hello")); + Assert.assertNotNull(matchingValidators); + Assert.assertEquals(matchingValidators.size(), 2L); + Assert.assertEquals(matchingValidators.get(0).getClass(), DefaultMessageHeaderValidator.class); + Assert.assertEquals(matchingValidators.get(1).getClass(), DefaultTextEqualsMessageValidator.class); + messageValidatorRegistry.addMessageValidator("plainTextMessageValidator", plainTextMessageValidator); matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.JSON.name(), new DefaultMessage("Hello")); diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java b/core/citrus-base/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java deleted file mode 100644 index 0032120cae..0000000000 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.citrusframework.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.ValidationException; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.context.ValidationContext; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (!receivedMessage.getPayload(String.class).equals(controlMessage.getPayload(String.class))) { - throw new ValidationException("Validation failed - expected message contents not equal!"); - } - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.XML.toString()) - || messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/core/citrus-base/src/test/java/org/citrusframework/variable/dictionary/AbstractDataDictionaryTest.java b/core/citrus-base/src/test/java/org/citrusframework/variable/dictionary/AbstractDataDictionaryTest.java index 7f31bc2282..703b554854 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/variable/dictionary/AbstractDataDictionaryTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/variable/dictionary/AbstractDataDictionaryTest.java @@ -1,6 +1,6 @@ package org.citrusframework.variable.dictionary; -import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang3.NotImplementedException; import org.apache.tools.ant.filters.StringInputStream; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -11,7 +11,6 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.io.File; import java.io.InputStream; import java.util.InvalidPropertiesFormatException; @@ -48,7 +47,7 @@ public void testInitializeWithNormalPropertiesFile() { // Setup mock resource doReturn(inputStream).when(mappingFile).getInputStream(); - doReturn(new File("test.properties")).when(mappingFile).getFile(); + doReturn("test.properties").when(mappingFile).getLocation(); fixture.initialize(); @@ -69,7 +68,7 @@ public void testInitializeWithXMLPropertiesFile() { // Setup mock resource doReturn(inputStream).when(mappingFile).getInputStream(); - doReturn(new File("test.properties.xml")).when(mappingFile).getFile(); // Note the .xml-suffix + doReturn("test.properties.xml").when(mappingFile).getLocation(); // Note the .xml-suffix fixture.initialize(); @@ -83,7 +82,7 @@ public void testInitializeThrowsExceptionWithInvalidXMLPropertiesFile() { // Setup mock resource doReturn(inputStream).when(mappingFile).getInputStream(); - doReturn(new File("test.properties.xml")).when(mappingFile).getFile(); // Note the .xml-suffix + doReturn("test.properties.xml").when(mappingFile).getLocation(); // Note the .xml-suffix CitrusRuntimeException exception = expectThrows(CitrusRuntimeException.class, () -> fixture.initialize()); assertTrue(exception.getCause() instanceof InvalidPropertiesFormatException); diff --git a/core/citrus-spring/src/main/java/org/citrusframework/spi/CitrusResourceWrapper.java b/core/citrus-spring/src/main/java/org/citrusframework/spi/CitrusResourceWrapper.java index 6ae4e4e6a1..aaa9e72631 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/spi/CitrusResourceWrapper.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/spi/CitrusResourceWrapper.java @@ -19,14 +19,15 @@ package org.citrusframework.spi; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalConverter; import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; public class CitrusResourceWrapper implements Resource { @@ -43,6 +44,10 @@ public static CitrusResourceWrapper from(org.springframework.core.io.Resource re @Override public String getLocation() { try { + if (delegate instanceof ClassPathResource classPathResource) { + return classPathResource.getURI().toString(); + } + return delegate.getFile().getPath(); } catch (IOException e) { return delegate.toString(); diff --git a/core/citrus-spring/src/main/resources/META-INF/spring.schemas b/core/citrus-spring/src/main/resources/META-INF/spring.schemas index 6cc275f23b..edbeafae43 100644 --- a/core/citrus-spring/src/main/resources/META-INF/spring.schemas +++ b/core/citrus-spring/src/main/resources/META-INF/spring.schemas @@ -40,10 +40,10 @@ http\://www.citrusframework.org/schema/config/citrus-config-3.3.1.xsd=com/consol http\://www.citrusframework.org/schema/config/citrus-config-3.4.0.xsd=com/consol/citrus/schema/citrus-config-3.4.0.xsd http\://www.citrusframework.org/schema/config/citrus-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/config/citrus-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/config/citrus-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/config/citrus-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/config/citrus-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/config/citrus-config-4.0.0.xsd=org/citrusframework/schema/citrus-config-4.0.0.xsd +http\://www.citrusframework.org/schema/config/citrus-config-4.0.1.xsd=org/citrusframework/schema/citrus-config-4.0.1.xsd +http\://www.citrusframework.org/schema/config/citrus-config-4.0.2.xsd=org/citrusframework/schema/citrus-config-4.0.2.xsd +http\://www.citrusframework.org/schema/config/citrus-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/config/citrus-config.xsd=org/citrusframework/schema/citrus-config.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase-1.0.xsd=com/consol/citrus/schema/citrus-testcase-1.0.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase-1.1.xsd=com/consol/citrus/schema/citrus-testcase-1.1.xsd @@ -87,8 +87,8 @@ http\://www.citrusframework.org/schema/testcase/citrus-testcase-3.3.1.xsd=com/co http\://www.citrusframework.org/schema/testcase/citrus-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/testcase/citrus-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/testcase/citrus-testcase.xsd=org/citrusframework/schema/citrus-testcase.xsd diff --git a/core/citrus-spring/src/test/java/org/citrusframework/spi/CitrusResourceWrapperTest.java b/core/citrus-spring/src/test/java/org/citrusframework/spi/CitrusResourceWrapperTest.java new file mode 100644 index 0000000000..476df21cc1 --- /dev/null +++ b/core/citrus-spring/src/test/java/org/citrusframework/spi/CitrusResourceWrapperTest.java @@ -0,0 +1,41 @@ +package org.citrusframework.spi; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileUrlResource; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class CitrusResourceWrapperTest { + + @Test + public void readUriFromClasspathResource() throws IOException { + String resource = "citrus-application.properties"; + ClassPathResource classPathResource = mock(ClassPathResource.class); + doReturn(URI.create(resource)).when(classPathResource).getURI(); + + CitrusResourceWrapper fixture = new CitrusResourceWrapper(classPathResource); + + assertTrue(fixture.getLocation().endsWith(resource), "Fixture location should resolve URI from classpath resource!"); + verify(classPathResource).getURI(); + } + + @Test + public void readFileFromOtherResources() throws IOException { + String resource = "citrus-application.properties"; + FileUrlResource classPathResource = mock(FileUrlResource.class); + doReturn(File.createTempFile(getClass().getSimpleName(), resource)).when(classPathResource).getFile(); + + CitrusResourceWrapper fixture = new CitrusResourceWrapper(classPathResource); + + assertTrue(fixture.getLocation().endsWith(resource), "Fixture location should resolve URI from classpath resource!"); + verify(classPathResource).getFile(); + } +} diff --git a/endpoints/citrus-camel/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-camel/src/main/resources/META-INF/spring.schemas index c39fd45d2d..14d0d1b7ae 100644 --- a/endpoints/citrus-camel/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-camel/src/main/resources/META-INF/spring.schemas @@ -35,10 +35,10 @@ http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-3.3.1.xs http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-3.4.0.xsd=com/consol/citrus/schema/citrus-camel-config-3.4.0.xsd http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-camel-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-camel-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-camel-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-camel-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-camel-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.0.0.xsd=org/citrusframework/schema/citrus-camel-config-4.0.0.xsd +http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.0.1.xsd=org/citrusframework/schema/citrus-camel-config-4.0.1.xsd +http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.0.2.xsd=org/citrusframework/schema/citrus-camel-config-4.0.2.xsd +http\://www.citrusframework.org/schema/camel/config/citrus-camel-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-camel-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/camel/config/citrus-camel-config.xsd=org/citrusframework/schema/citrus-camel-config.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-2.3.xsd=com/consol/citrus/schema/citrus-camel-testcase-2.3.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-2.4.xsd=com/consol/citrus/schema/citrus-camel-testcase-2.4.xsd @@ -72,8 +72,8 @@ http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-3.3. http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-camel-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-camel-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-camel-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-camel-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-camel-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-camel-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-camel-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-camel-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-camel-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-camel-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase.xsd=org/citrusframework/schema/citrus-camel-testcase.xsd diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/groovy/AbstractGroovyActionDslTest.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/groovy/AbstractGroovyActionDslTest.java index 6caa2bfcaf..70f0dd3a59 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/groovy/AbstractGroovyActionDslTest.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/AbstractXmlActionTest.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/AbstractXmlActionTest.java index a500ce40f5..3acbe4fc41 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/AbstractXmlActionTest.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/AbstractYamlActionTest.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/AbstractYamlActionTest.java index 1951a7e5ed..41e3a6dbcc 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/AbstractYamlActionTest.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/FtpSettings.java b/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/FtpSettings.java new file mode 100644 index 0000000000..7845ac62a7 --- /dev/null +++ b/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/FtpSettings.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.ftp; + +import org.citrusframework.message.MessageType; + +/** + * @author Christoph Deppisch + */ +public class FtpSettings { + + private static final String FTP_PROPERTY_PREFIX = "citrus.ftp."; + private static final String FTP_ENV_PREFIX = "CITRUS_FTP"; + + private static final String MARSHALLER_TYPE_PROPERTY = FTP_PROPERTY_PREFIX + "marshaller.type"; + private static final String MARSHALLER_TYPE_ENV = FTP_ENV_PREFIX + "MARSHALLER_TYPE"; + private static final String MARSHALLER_TYPE_DEFAULT = MessageType.XML.name(); + + private FtpSettings() { + // prevent instantiation of utility class + } + + /** + * Gets the default marshaller type setting that represents the data format + * that the marshaller will use (usually one of XML or JSON). + * @return + */ + public static String getMarshallerType() { + return System.getProperty(MARSHALLER_TYPE_PROPERTY, + System.getenv(MARSHALLER_TYPE_ENV) != null ? System.getenv(MARSHALLER_TYPE_ENV) : MARSHALLER_TYPE_DEFAULT); + } + +} diff --git a/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/message/FtpMarshaller.java b/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/message/FtpMarshaller.java index fd9a259bcc..63c9ffc709 100644 --- a/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/message/FtpMarshaller.java +++ b/endpoints/citrus-ftp/src/main/java/org/citrusframework/ftp/message/FtpMarshaller.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.xml.bind.JAXBException; import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.ftp.FtpSettings; import org.citrusframework.ftp.model.Command; import org.citrusframework.ftp.model.CommandResult; import org.citrusframework.ftp.model.ConnectCommand; @@ -57,11 +58,8 @@ public class FtpMarshaller implements Marshaller, Unmarshaller { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(FtpMarshaller.class); - /** System property defining message format to marshal to */ - private static final String JDBC_MARSHALLER_TYPE_PROPERTY = "citrus.ftp.marshaller.type"; - /** Message type format: XML or JSON */ - private String type; + private String type = FtpSettings.getMarshallerType(); private final ObjectMapper mapper; private final Jaxb2Marshaller marshaller; @@ -84,9 +82,6 @@ public class FtpMarshaller implements Marshaller, Unmarshaller { public FtpMarshaller() { this.mapper = new ObjectMapper(); this.marshaller = new Jaxb2Marshaller(Resources.fromClasspath("org/citrusframework/schema/citrus-ftp-message.xsd"), classesToBeBound); - - type = System.getProperty(JDBC_MARSHALLER_TYPE_PROPERTY, MessageType.XML.name()); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } diff --git a/endpoints/citrus-ftp/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-ftp/src/main/resources/META-INF/spring.schemas index 0198a0816d..b6b9af06ea 100644 --- a/endpoints/citrus-ftp/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-ftp/src/main/resources/META-INF/spring.schemas @@ -33,10 +33,10 @@ http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-3.4.0.xsd=com/consol/citrus/schema/citrus-ftp-config-3.4.0.xsd http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-ftp-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-ftp-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-ftp-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-ftp-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ftp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.0.0.xsd=org/citrusframework/schema/citrus-ftp-config-4.0.0.xsd +http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.0.1.xsd=org/citrusframework/schema/citrus-ftp-config-4.0.1.xsd +http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.0.2.xsd=org/citrusframework/schema/citrus-ftp-config-4.0.2.xsd +http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ftp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ftp/config/citrus-ftp-config.xsd=org/citrusframework/schema/citrus-ftp-config.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-2.7.6.xsd=com/consol/citrus/schema/citrus-scp-config-2.7.6.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-2.7.7.xsd=com/consol/citrus/schema/citrus-scp-config-2.7.7.xsd @@ -56,10 +56,10 @@ http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-3.4.0.xsd=com/consol/citrus/schema/citrus-scp-config-3.4.0.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-scp-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-scp-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-scp-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-scp-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-scp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.0.0.xsd=org/citrusframework/schema/citrus-scp-config-4.0.0.xsd +http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.0.1.xsd=org/citrusframework/schema/citrus-scp-config-4.0.1.xsd +http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.0.2.xsd=org/citrusframework/schema/citrus-scp-config-4.0.2.xsd +http\://www.citrusframework.org/schema/scp/config/citrus-scp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-scp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/scp/config/citrus-scp-config.xsd=org/citrusframework/schema/citrus-scp-config.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-2.7.5.xsd=com/consol/citrus/schema/citrus-sftp-config-2.7.5.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-2.7.6.xsd=com/consol/citrus/schema/citrus-sftp-config-2.7.6.xsd @@ -77,8 +77,8 @@ http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-3.3.1.xsd= http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-3.4.0.xsd=com/consol/citrus/schema/citrus-sftp-config-3.4.0.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-sftp-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-sftp-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-sftp-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-sftp-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-sftp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.0.0.xsd=org/citrusframework/schema/citrus-sftp-config-4.0.0.xsd +http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.0.1.xsd=org/citrusframework/schema/citrus-sftp-config-4.0.1.xsd +http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.0.2.xsd=org/citrusframework/schema/citrus-sftp-config-4.0.2.xsd +http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-sftp-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/sftp/config/citrus-sftp-config.xsd=org/citrusframework/schema/citrus-sftp-config.xsd diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/BasicAuthClientHttpRequestFactory.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/BasicAuthClientHttpRequestFactory.java index 05a773922d..6127637046 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/BasicAuthClientHttpRequestFactory.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/BasicAuthClientHttpRequestFactory.java @@ -21,10 +21,10 @@ import org.apache.hc.client5.http.auth.AuthCache; import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.Credentials; -import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.impl.auth.BasicAuthCache; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.core5.http.HttpHost; @@ -45,7 +45,7 @@ public class BasicAuthClientHttpRequestFactory implements FactoryBean, InitializingPhase { /** The target request factory */ - private HttpClient httpClient; + private HttpClientBuilder httpClient; /** User credentials for basic authentication */ private Credentials credentials; @@ -59,7 +59,7 @@ public class BasicAuthClientHttpRequestFactory implements FactoryBean { /** Endpoint target */ - private HttpClient endpoint = new HttpClient(); + private final HttpClient endpoint = new HttpClient(); @Override protected HttpClient getEndpoint() { @@ -234,4 +236,25 @@ public HttpClientBuilder timeout(long timeout) { endpoint.getEndpointConfiguration().setTimeout(timeout); return this; } + + /** + * Sets the user authentication. + * @param auth + * @return + */ + public HttpClientBuilder authentication(HttpAuthentication auth) { + endpoint.getEndpointConfiguration().setRequestFactory( + auth.getRequestFactory(endpoint.getEndpointConfiguration().getRequestUrl(), endpoint)); + return this; + } + + /** + * Enable secured connection on the client using provided SSL connection. + * @return + */ + public HttpClientBuilder secured(HttpSecureConnection conn) { + endpoint.getEndpointConfiguration().getHttpClient() + .setConnectionManager(conn.getClientConnectionManager()); + return this; + } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java index 834bd28975..c8f95e6381 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.List; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.citrusframework.endpoint.AbstractPollableEndpointConfiguration; import org.citrusframework.endpoint.resolver.DynamicEndpointUriResolver; import org.citrusframework.endpoint.resolver.EndpointUriResolver; @@ -62,6 +63,9 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura /** The rest template */ private RestTemplate restTemplate; + /** Http client builder */ + private HttpClientBuilder httpClient; + /** Request factory */ private ClientHttpRequestFactory requestFactory; @@ -75,7 +79,7 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura private HttpMessageConverter messageConverter = new HttpMessageConverter(); /** Endpoint clientInterceptors */ - private List clientInterceptors; + private List clientInterceptors = new ArrayList<>(); /** Should http errors be handled within endpoint consumer or simply throw exception */ private ErrorHandlingStrategy errorHandlingStrategy = ErrorHandlingStrategy.PROPAGATE; @@ -110,9 +114,7 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura * Default constructor initializes with default logging interceptor. */ public HttpEndpointConfiguration() { - List interceptors = new ArrayList<>(); - interceptors.add(new LoggingClientInterceptor()); - setClientInterceptors(interceptors); + clientInterceptors.add(new LoggingClientInterceptor()); } /** @@ -228,6 +230,7 @@ public String getContentType() { public RestTemplate getRestTemplate() { if (restTemplate == null) { restTemplate = new RestTemplate(); + restTemplate.setInterceptors(clientInterceptors); } restTemplate.setRequestFactory(getRequestFactory()); @@ -298,7 +301,7 @@ public MessageCorrelator getCorrelator() { */ public ClientHttpRequestFactory getRequestFactory() { if (requestFactory == null) { - requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory = new HttpComponentsClientHttpRequestFactory(getHttpClient().build()); } return requestFactory; @@ -312,6 +315,18 @@ public void setRequestFactory(ClientHttpRequestFactory requestFactory) { this.requestFactory = requestFactory; } + public HttpClientBuilder getHttpClient() { + if (httpClient == null) { + httpClient = HttpClientBuilder.create().useSystemProperties(); + } + + return httpClient; + } + + public void setHttpClient(HttpClientBuilder httpClient) { + this.httpClient = httpClient; + } + /** * Gets the message converter. * @return diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfig.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfig.java index f2be3d60e4..f885612d36 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfig.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfig.java @@ -141,4 +141,16 @@ * @return */ String actor() default ""; + + /** + * User authentication. + * @return + */ + String authentication() default ""; + + /** + * Secured connection. + * @return + */ + String secured() default ""; } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfigParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfigParser.java index e25e3f971e..5826a7857f 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfigParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpClientConfigParser.java @@ -26,6 +26,8 @@ import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.message.HttpMessageConverter; +import org.citrusframework.http.security.HttpAuthentication; +import org.citrusframework.http.security.HttpSecureConnection; import org.citrusframework.message.MessageCorrelator; import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.util.StringUtils; @@ -112,6 +114,14 @@ public HttpClient parse(HttpClientConfig annotation, ReferenceResolver reference builder.actor(referenceResolver.resolve(annotation.actor(), TestActor.class)); } + if (StringUtils.hasText(annotation.authentication())) { + builder.authentication(referenceResolver.resolve(annotation.authentication(), HttpAuthentication.class)); + } + + if (StringUtils.hasText(annotation.secured())) { + builder.secured(referenceResolver.resolve(annotation.secured(), HttpSecureConnection.class)); + } + return builder.initialize().build(); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfig.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfig.java index 679cca2772..ccc21bf742 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfig.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfig.java @@ -182,4 +182,28 @@ * @return */ String actor() default ""; + + /** + * User authentication. + * @return + */ + String authentication() default ""; + + /** + * Resource path that is secured with user authentication. + * @return + */ + String securedPath() default "/*"; + + /** + * Secured connection. + * @return + */ + String secured() default ""; + + /** + * Secured server port. + * @return + */ + int securePort() default 8443; } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfigParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfigParser.java index 57cefe99ac..01c21554a9 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfigParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/annotation/HttpServerConfigParser.java @@ -29,6 +29,8 @@ import org.citrusframework.endpoint.EndpointAdapter; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.message.HttpMessageConverter; +import org.citrusframework.http.security.HttpAuthentication; +import org.citrusframework.http.security.HttpSecureConnection; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.spi.ReferenceResolver; @@ -138,6 +140,14 @@ public HttpServer parse(HttpServerConfig annotation, ReferenceResolver reference builder.defaultStatus(annotation.defaultStatus()); builder.responseCacheSize(annotation.responseCacheSize()); + if (StringUtils.hasText(annotation.authentication())) { + builder.authentication(annotation.securedPath(), referenceResolver.resolve(annotation.authentication(), HttpAuthentication.class)); + } + + if (StringUtils.hasText(annotation.secured())) { + builder.secured(annotation.securePort(), referenceResolver.resolve(annotation.secured(), HttpSecureConnection.class)); + } + return builder.initialize().build(); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java index 6b15778dd4..6538ae9891 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import jakarta.servlet.http.Cookie; @@ -54,6 +55,10 @@ public HttpMessageConverter(CookieConverter cookieConverter) { this.cookieConverter = cookieConverter; } + private static String resolveCookieValue(TestContext context, Cookie cookie) { + return Objects.isNull(context) ? cookie.getValue() : context.replaceDynamicContentInString(cookie.getValue()); + } + @Override public HttpEntity convertOutbound(Message message, HttpEndpointConfiguration endpointConfiguration, @@ -63,15 +68,15 @@ public HttpEntity convertOutbound(Message message, HttpHeaders httpHeaders = createHttpHeaders(httpMessage, endpointConfiguration); + for (Cookie cookie : httpMessage.getCookies()) { + httpHeaders.add( + HttpHeaders.COOKIE, + cookie.getName() + "=" + resolveCookieValue(context, cookie)); + } + Object payload = httpMessage.getPayload(); if (httpMessage.getStatusCode() != null) { return new ResponseEntity<>(payload, httpHeaders, httpMessage.getStatusCode()); - } else { - for (Cookie cookie : httpMessage.getCookies()) { - httpHeaders.add( - HttpHeaders.COOKIE, - cookie.getName() + "=" + context.replaceDynamicContentInString(cookie.getValue())); - } } RequestMethod method = determineRequestMethod(endpointConfiguration, httpMessage); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/BasicAuthentication.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/BasicAuthentication.java new file mode 100644 index 0000000000..18ba38bdf9 --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/BasicAuthentication.java @@ -0,0 +1,111 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import java.net.URL; +import java.util.Collections; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.client.BasicAuthClientHttpRequestFactory; +import org.citrusframework.http.client.HttpClient; +import org.eclipse.jetty.security.SecurityHandler; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.util.StringUtils; + +/** + * Basic authentication implementation able to create a proper request factory with basic auth client credentials. + * Trying to read hostname and port from given request URL on the Http client in order to set a proper auth scope. + */ +public class BasicAuthentication implements HttpAuthentication { + + private final String username; + private final String password; + + private String realm = ""; + + private String[] userRoles = new String[] { "citrus" }; + + public BasicAuthentication(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public SecurityHandler getSecurityHandler(String resourcePath) { + try { + SecurityHandlerFactory securityHandlerFactory = new SecurityHandlerFactory(); + securityHandlerFactory.setUsers(Collections.singletonList(new User(username, password, userRoles))); + securityHandlerFactory.setConstraints(Collections.singletonMap(resourcePath, new BasicAuthConstraint(userRoles))); + + securityHandlerFactory.setAuthenticator(new BasicAuthenticator()); + securityHandlerFactory.setRealm(realm); + + securityHandlerFactory.initialize(); + + return securityHandlerFactory.getObject(); + } catch (Exception e) { + throw new CitrusRuntimeException(e); + } + } + + @Override + public ClientHttpRequestFactory getRequestFactory(String requestUrl, HttpClient httpClient) { + try { + BasicAuthClientHttpRequestFactory requestFactory = new BasicAuthClientHttpRequestFactory(); + + if (httpClient != null) { + requestFactory.setHttpClient(httpClient.getEndpointConfiguration().getHttpClient()); + } + + URL url = null; + if (StringUtils.hasText(requestUrl)) { + url = new URL(requestUrl); + } else if (httpClient != null && StringUtils.hasText(httpClient.getEndpointConfiguration().getRequestUrl())) { + url = new URL(httpClient.getEndpointConfiguration().getRequestUrl()); + } + + if (url != null) { + AuthScope authScope = new AuthScope(url.getProtocol(), url.getHost(), url.getPort(), realm, "basic"); + requestFactory.setAuthScope(authScope); + } + + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password.toCharArray()); + requestFactory.setCredentials(credentials); + + requestFactory.initialize(); + return requestFactory.getObject(); + } catch (Exception e) { + throw new CitrusRuntimeException("Failed to configure basic auth on Http client", e); + } + } + + public BasicAuthentication realm(String realm) { + this.realm = realm; + return this; + } + + public BasicAuthentication userRoles(String... roles) { + this.userRoles = roles; + return this; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpAuthentication.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpAuthentication.java new file mode 100644 index 0000000000..98c6cd56b2 --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpAuthentication.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.citrusframework.http.client.HttpClient; +import org.eclipse.jetty.security.SecurityHandler; +import org.springframework.http.client.ClientHttpRequestFactory; + +public interface HttpAuthentication { + + /** + * Security handler able to set up server user authentication on given resource path. + * @param resourcePath + * @return + */ + SecurityHandler getSecurityHandler(String resourcePath); + + /** + * Creates client request factory that uses the given authentication method. + * @param requestUrl + * @param httpClient + * @return + */ + ClientHttpRequestFactory getRequestFactory(String requestUrl, HttpClient httpClient); + + static BasicAuthentication basic(String username, String password) { + return new BasicAuthentication(username, password); + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientConnectionManagerFactory.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientConnectionManagerFactory.java new file mode 100644 index 0000000000..707d4d71cb --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientConnectionManagerFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.springframework.beans.factory.FactoryBean; + +/** + * Spring bean factory for a secure SSL connection manager. + * Factory may be used in Spring bean configuration to set connection manager on a Http client. + */ +public class HttpClientConnectionManagerFactory implements FactoryBean { + + private final HttpSecureConnection secureConnection; + + public HttpClientConnectionManagerFactory(HttpSecureConnection secureConnection) { + this.secureConnection = secureConnection; + } + + @Override + public HttpClientConnectionManager getObject() throws Exception { + return secureConnection.getClientConnectionManager(); + } + + @Override + public Class getObjectType() { + return HttpClientConnectionManager.class; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientRequestFactoryBean.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientRequestFactoryBean.java new file mode 100644 index 0000000000..d225ec0bdf --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpClientRequestFactoryBean.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +public class HttpClientRequestFactoryBean implements FactoryBean { + + private final HttpAuthentication auth; + private String requestUrl; + + public HttpClientRequestFactoryBean(HttpAuthentication auth) { + this.auth = auth; + } + + @Override + public ClientHttpRequestFactory getObject() throws Exception { + return auth.getRequestFactory(requestUrl, null); + } + + @Override + public Class getObjectType() { + return HttpComponentsClientHttpRequestFactory.class; + } + + public void setRequestUrl(String requestUrl) { + this.requestUrl = requestUrl; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecureConnection.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecureConnection.java new file mode 100644 index 0000000000..fd89b453ba --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecureConnection.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.eclipse.jetty.server.ServerConnector; + +/** + * Secure Http connection able to create proper connection manager for clients. + */ +public interface HttpSecureConnection { + + /** + * Create server connector representing the secure connection. + * @param securePort + * @return + */ + ServerConnector getServerConnector(int securePort); + + /** + * Create proper secure connection manager to be used on custom Http clients. + * @return + */ + HttpClientConnectionManager getClientConnectionManager(); + + static SSLConnection ssl() { + return new SSLConnection(); + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecurityHandlerFactoryBean.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecurityHandlerFactoryBean.java new file mode 100644 index 0000000000..70dca39e78 --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpSecurityHandlerFactoryBean.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.eclipse.jetty.security.SecurityHandler; +import org.springframework.beans.factory.FactoryBean; + +public class HttpSecurityHandlerFactoryBean implements FactoryBean { + + private final HttpAuthentication auth; + private String resourcePath = "/*"; + + public HttpSecurityHandlerFactoryBean(HttpAuthentication auth) { + this.auth = auth; + } + + @Override + public SecurityHandler getObject() throws Exception { + return auth.getSecurityHandler(resourcePath); + } + + @Override + public Class getObjectType() { + return SecurityHandler.class; + } + + public void setResourcePath(String resourcePath) { + this.resourcePath = resourcePath; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpServerConnectorFactory.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpServerConnectorFactory.java new file mode 100644 index 0000000000..8ba3ce4bf2 --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/HttpServerConnectorFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import org.eclipse.jetty.server.ServerConnector; +import org.springframework.beans.factory.FactoryBean; + +/** + * Spring factory bean for server connector. + */ +public class HttpServerConnectorFactory implements FactoryBean { + + private final HttpSecureConnection secureConnection; + private int securePort = 8443; + + public HttpServerConnectorFactory(HttpSecureConnection secureConnection) { + this.secureConnection = secureConnection; + } + + @Override + public ServerConnector getObject() throws Exception { + return secureConnection.getServerConnector(securePort); + } + + @Override + public Class getObjectType() { + return ServerConnector.class; + } + + public void setSecurePort(int securePort) { + this.securePort = securePort; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SSLConnection.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SSLConnection.java new file mode 100644 index 0000000000..e56d0e0542 --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SSLConnection.java @@ -0,0 +1,176 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.http.security; + +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.Collections; +import javax.net.ssl.HostnameVerifier; + +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.TrustAllStrategy; +import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.SSLContexts; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.springframework.beans.factory.BeanCreationException; + +/** + * SSL secure connection to set up a proper SSL context and SSL connection socket factory. + * Optionally uses provided keystore and truststore. If not set uses trust all strategy. + */ +public class SSLConnection implements HttpSecureConnection { + + private Resource keyStore; + private String keyStorePassword; + + private Resource trustStore; + + private String trustStorePassword; + + private HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; + + public SSLConnection() { + } + + public SSLConnection(Resource keyStore, String password) { + this.keyStore = keyStore; + this.keyStorePassword = password; + } + + public SSLConnection(Resource keyStore, String ksPassword, Resource trustStore, String tsPassword) { + this.keyStore = keyStore; + this.keyStorePassword = ksPassword; + this.trustStore = trustStore; + this.trustStorePassword = tsPassword; + } + + @Override + public ServerConnector getServerConnector(int securePort) { + ServerConnector connector = new ServerConnector(new Server(), + new SslConnectionFactory(sslContextFactory(), HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpConfiguration(securePort))); + connector.setPort(securePort); + + return connector; + } + + @Override + public HttpClientConnectionManager getClientConnectionManager() { + try { + SSLContextBuilder sslContext; + + if (trustStore != null) { + sslContext = SSLContexts.custom() + .loadTrustMaterial(trustStore.getFile(), trustStorePassword.toCharArray(), + new TrustSelfSignedStrategy()); + } else { + sslContext = SSLContexts.custom() + .loadTrustMaterial(TrustAllStrategy.INSTANCE); + } + + if (keyStore != null) { + sslContext.loadKeyMaterial(KeyStore.getInstance(keyStore.getFile(), keyStorePassword.toCharArray()), + keyStorePassword.toCharArray()); + } + + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + sslContext.build(), hostnameVerifier); + + return PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslSocketFactory) + .build(); + } catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException | + KeyManagementException | UnrecoverableKeyException e) { + throw new BeanCreationException("Failed to create http client for ssl connection", e); + } + } + + public SSLConnection trustStore(String trustStore, String password) { + return trustStore(Resources.create(trustStore), password); + } + + public SSLConnection trustStore(Resource trustStore, String password) { + this.trustStore = trustStore; + this.trustStorePassword = password; + return this; + } + + public SSLConnection keyStore(String keyStore, String password) { + return keyStore(Resources.create(keyStore), password); + } + + public SSLConnection keyStore(Resource keyStore, String password) { + this.keyStore = keyStore; + this.keyStorePassword = password; + return this; + } + + public SSLConnection hostnameVerifier(HostnameVerifier verifier) { + this.hostnameVerifier = verifier; + return this; + } + + private SslContextFactory.Server sslContextFactory() { + SslContextFactory.Server contextFactory = new SslContextFactory.Server(); + + if (trustStore != null) { + contextFactory.setTrustStorePath(trustStore.getFile().getPath()); + contextFactory.setTrustStorePassword(trustStorePassword); + } else { + contextFactory.setTrustAll(true); + } + + if (keyStore != null) { + contextFactory.setKeyStorePath(keyStore.getFile().getPath()); + contextFactory.setKeyStorePassword(keyStorePassword); + } + + return contextFactory; + } + + private HttpConfiguration httpConfiguration(int securePort) { + HttpConfiguration parent = new HttpConfiguration(); + parent.setSecureScheme("https"); + parent.setSecurePort(securePort); + HttpConfiguration configuration = new HttpConfiguration(parent); + SecureRequestCustomizer secureRequestCustomizer = new SecureRequestCustomizer(); + secureRequestCustomizer.setSniHostCheck(false); + configuration.setCustomizers(Collections.singletonList(secureRequestCustomizer)); + return configuration; + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SecurityHandlerFactory.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SecurityHandlerFactory.java index 17f2ce957d..25deb223a1 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SecurityHandlerFactory.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/security/SecurityHandlerFactory.java @@ -16,9 +16,6 @@ package org.citrusframework.http.security; -import javax.security.auth.Subject; -import java.io.IOException; -import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -26,7 +23,6 @@ import java.util.Map.Entry; import org.citrusframework.common.InitializingPhase; -import org.eclipse.jetty.security.AbstractLoginService; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; @@ -49,14 +45,14 @@ */ public class SecurityHandlerFactory implements FactoryBean, InitializingPhase { - /** User credentials known to login service */ + /** User credentials known to the login service */ private List users = new ArrayList<>(); /** Realm name for this security handler */ private String realm = "realm"; /** List of constraints with mapping path as key */ - private Map constraints = new HashMap(); + private Map constraints = new HashMap<>(); /** User login service consolidated for user authentication */ private LoginService loginService; diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java index 2e84011a66..751536b29e 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java @@ -19,11 +19,13 @@ package org.citrusframework.http.server; -import jakarta.servlet.Filter; import java.util.List; import java.util.Map; +import jakarta.servlet.Filter; import org.citrusframework.http.message.HttpMessageConverter; +import org.citrusframework.http.security.HttpAuthentication; +import org.citrusframework.http.security.HttpSecureConnection; import org.citrusframework.server.AbstractServerBuilder; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.Connector; @@ -40,6 +42,8 @@ public class AbstractHttpServerBuilder { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpClientTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpClientTest.java index 2e1b5bc3f9..59450249c1 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpClientTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpClientTest.java @@ -39,7 +39,6 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.Message; @@ -48,6 +47,7 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -75,7 +75,7 @@ public class HttpClientTest extends AbstractGroovyActionDslTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpServerTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpServerTest.java index 1c8e96937e..60d4fe2600 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpServerTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/groovy/HttpServerTest.java @@ -35,12 +35,12 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -66,7 +66,7 @@ public class HttpServerTest extends AbstractGroovyActionDslTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private HttpServer httpServer; diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpBasicAuthJavaIT.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpBasicAuthJavaIT.java new file mode 100644 index 0000000000..316a906676 --- /dev/null +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpBasicAuthJavaIT.java @@ -0,0 +1,124 @@ +/* + * Copyright 2006-2023 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.http.integration; + +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.security.HttpAuthentication; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.citrusframework.util.SocketUtils; +import org.springframework.http.HttpStatus; +import org.testng.annotations.Test; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; + +/** + * @author Christoph Deppisch + */ +@Test +public class HttpBasicAuthJavaIT extends TestNGCitrusSpringSupport { + + private final int port = SocketUtils.findAvailableTcpPort(8888); + + @BindToRegistry + private final HttpServer basicAuthServer = new HttpServerBuilder() + .port(port) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .authentication("/secured/*", HttpAuthentication.basic("citrus", "secr3t")) + .build(); + + @BindToRegistry + private final HttpClient basicAuthClient = new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .authentication(HttpAuthentication.basic("citrus", "secr3t")) + .build(); + + @CitrusTest + public void basicAuth() { + when(http().client(basicAuthClient) + .send() + .post("/secured") + .fork(true) + .message() + .body("Hello from auth user") + .contentType("text/plain")); + + then(http().server(basicAuthServer) + .receive() + .post("/secured") + .message() + .body("Hello from auth user") + .contentType("text/plain")); + + then(http().server(basicAuthServer) + .send() + .response(HttpStatus.OK) + .message() + .body("Hi from secured Http server") + .contentType("text/plain")); + + then(http().client(basicAuthClient) + .receive() + .response(HttpStatus.OK) + .message() + .body("Hi from secured Http server") + .contentType("text/plain")); + } + + @CitrusTest + public void basicAuthPathUnprotected() { + when(http().client("http://localhost:%d".formatted(port)) + .send() + .get("/other")); + + then(http().client("http://localhost:%d".formatted(port)) + .receive() + .response(HttpStatus.NO_CONTENT) + .message()); + } + + @CitrusTest + public void basicAuthHeader() { + when(http().client("http://localhost:%d".formatted(port)) + .send() + .get("/secured") + .message() + .header("Authorization", "Basic citrus:encodeBase64(citrus:secr3t)")); + + then(http().client("http://localhost:%d".formatted(port)) + .receive() + .response(HttpStatus.NO_CONTENT) + .message()); + } + + @CitrusTest + public void basicAuthError() { + when(http().client("http://localhost:%d".formatted(port)) + .send() + .get("/secured")); + + then(http().client("http://localhost:%d".formatted(port)) + .receive() + .response(HttpStatus.UNAUTHORIZED) + .message()); + } +} diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpSecureConnectionJavaIT.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpSecureConnectionJavaIT.java new file mode 100644 index 0000000000..df15a92adf --- /dev/null +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpSecureConnectionJavaIT.java @@ -0,0 +1,90 @@ +/* + * Copyright 2006-2023 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.http.integration; + +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.security.HttpSecureConnection; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.citrusframework.util.SocketUtils; +import org.springframework.http.HttpStatus; +import org.testng.annotations.Test; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; + +/** + * @author Christoph Deppisch + */ +@Test +public class HttpSecureConnectionJavaIT extends TestNGCitrusSpringSupport { + + private final Resource keyStore = Resources.create("http-server.jks", HttpSecureConnectionJavaIT.class); + + @BindToRegistry + private final HttpServer secureHttpServer = new HttpServerBuilder() + .port(SocketUtils.findAvailableTcpPort(8888)) + .timeout(5000L) + .autoStart(true) + .secured(8443, HttpSecureConnection.ssl() + .keyStore(keyStore, "secret")) + .build(); + + @BindToRegistry + private final HttpClient secureHttpClient = new HttpClientBuilder() + .requestUrl("https://localhost:8443") + .secured(HttpSecureConnection.ssl() + .trustStore(keyStore, "secret")) + .build(); + + @CitrusTest + public void secureHttpConnection() { + when(http().client(secureHttpClient) + .send() + .post("/secured") + .fork(true) + .message() + .body("Hello from secure Http client") + .contentType("text/plain")); + + then(http().server(secureHttpServer) + .receive() + .post("/secured") + .message() + .body("Hello from secure Http client") + .contentType("text/plain")); + + then(http().server(secureHttpServer) + .send() + .response(HttpStatus.OK) + .message() + .body("Hi from secured Http server") + .contentType("text/plain")); + + then(http().client(secureHttpClient) + .receive() + .response(HttpStatus.OK) + .message() + .body("Hi from secured Http server") + .contentType("text/plain")); + } +} diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java index 370df18a2d..242515fc5b 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java @@ -16,17 +16,23 @@ package org.citrusframework.http.message; +import jakarta.servlet.http.Cookie; import org.citrusframework.context.TestContext; import org.citrusframework.http.client.HttpEndpointConfiguration; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; -import org.springframework.http.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.integration.mapping.HeaderMapper; import org.springframework.messaging.MessageHeaders; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import jakarta.servlet.http.Cookie; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -43,7 +49,6 @@ import static org.testng.AssertJUnit.assertTrue; public class HttpMessageConverterTest { - private CookieConverter cookieConverterMock; private HttpMessageConverter messageConverter; @@ -54,7 +59,7 @@ public class HttpMessageConverterTest { private final String payload = "Hello World!"; @BeforeMethod - public void setUp(){ + public void setUp() { cookieConverterMock = mock(CookieConverter.class); messageConverter = new HttpMessageConverter(cookieConverterMock); @@ -64,31 +69,29 @@ public void setUp(){ } @Test - public void testDefaultMessageIsConvertedOnOutbound(){ - - //GIVEN + public void testDefaultMessageIsConvertedOnOutbound() { + // GIVEN Message message = new DefaultMessage(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(payload, httpEntity.getBody()); } @Test - public void testHttpMessageCookiesArePreservedOnOutbound(){ - - //GIVEN - Cookie cookie = new Cookie("foo","bar"); + public void testHttpMessageCookiesArePreservedOnOutbound() { + // GIVEN + Cookie cookie = new Cookie("foo", "bar"); message.cookie(cookie); String expectedCookie = "foo=bar"; - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List cookies = httpEntity.getHeaders().get("Cookie"); assert cookies != null; assertEquals(1, cookies.size()); @@ -96,20 +99,19 @@ public void testHttpMessageCookiesArePreservedOnOutbound(){ } @Test - public void testHttpMessageCookiesValuesAreReplacedOnOutbound(){ - - //GIVEN - Cookie cookie = new Cookie("foo","${foobar}"); + public void testHttpMessageCookiesValuesAreReplacedOnOutbound() { + // GIVEN + Cookie cookie = new Cookie("foo", "${foobar}"); message.cookie(cookie); testContext.setVariable("foobar", "bar"); String expectedCookie = "foo=bar"; - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List cookies = httpEntity.getHeaders().get("Cookie"); assert cookies != null; assertEquals(1, cookies.size()); @@ -117,15 +119,14 @@ public void testHttpMessageCookiesValuesAreReplacedOnOutbound(){ } @Test - public void testHttpMessageHeadersAreReplacedOnOutbound(){ + public void testHttpMessageHeadersAreReplacedOnOutbound() { + // GIVEN + message.header("foo", "bar"); - //GIVEN - message.header("foo","bar"); - - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List fooHeader = httpEntity.getHeaders().get("foo"); assert fooHeader != null; assertEquals(1, fooHeader.size()); @@ -133,15 +134,14 @@ public void testHttpMessageHeadersAreReplacedOnOutbound(){ } @Test - public void testHttpContentTypeIsPresent(){ - - //GIVEN + public void testHttpContentTypeIsPresent() { + // GIVEN endpointConfiguration.setContentType("foobar"); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List contentTypeHeader = httpEntity.getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE); assert contentTypeHeader != null; assertEquals(1, contentTypeHeader.size()); @@ -149,16 +149,15 @@ public void testHttpContentTypeIsPresent(){ } @Test - public void testHttpContentTypeContainsAlteredCharsetIsPresent(){ - - //GIVEN + public void testHttpContentTypeContainsAlteredCharsetIsPresent() { + // GIVEN endpointConfiguration.setContentType("foobar"); endpointConfiguration.setCharset("whatever"); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List contentTypeHeader = httpEntity.getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE); assert contentTypeHeader != null; assertEquals(1, contentTypeHeader.size()); @@ -166,16 +165,15 @@ public void testHttpContentTypeContainsAlteredCharsetIsPresent(){ } @Test - public void testHttpContentTypeCharsetIsMissingWhenEmptyIsPresent(){ - - //GIVEN + public void testHttpContentTypeCharsetIsMissingWhenEmptyIsPresent() { + // GIVEN endpointConfiguration.setContentType("foobar"); endpointConfiguration.setCharset(""); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN final List contentTypeHeader = httpEntity.getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE); assert contentTypeHeader != null; assertEquals(1, contentTypeHeader.size()); @@ -183,169 +181,159 @@ public void testHttpContentTypeCharsetIsMissingWhenEmptyIsPresent(){ } @Test - public void testHttpMethodBodyIsSetForPostOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsSetForPostOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.POST); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(payload, httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsSetForPutOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsSetForPutOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.PUT); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(payload, httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsSetForDeleteOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsSetForDeleteOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.DELETE); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(payload, httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsSetForPatchOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsSetForPatchOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.PATCH); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(payload, httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsNotSetForGetOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsNotSetForGetOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.GET); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertNull(httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsNotSetForHeadOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsNotSetForHeadOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.HEAD); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertNull(httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsNotSetForOptionsOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsNotSetForOptionsOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.OPTIONS); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertNull(httpEntity.getBody()); } @Test - public void testHttpMethodBodyIsNotSetForTraceOnOutbound(){ - - //GIVEN + public void testHttpMethodBodyIsNotSetForTraceOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD, HttpMethod.TRACE); message.setPayload(payload); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertNull(httpEntity.getBody()); } - @Test - public void testHttpMessageWithStatusCodeContainsNoCookiesOnOutbound(){ - /* I've added this test to ensure that the current implementation of the HttpMessageConverter - * is fixed. Nevertheless, I doubt that cookies should not be set, if a http status code is preset in a - * incoming HTTP message. So this test might be subject to change. - */ - //GIVEN + @Test + public void testHttpMessageWithStatusCodeContainsCookiesOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_STATUS_CODE, "200"); - Cookie cookie = new Cookie("foo","bar"); + Cookie cookie = new Cookie("foo", "bar"); message.cookie(cookie); - //WHEN + String expectedCookie = "foo=bar"; + + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN - assertNull(httpEntity.getHeaders().get("Cookie")); + // THEN + final List cookies = httpEntity.getHeaders().get("Cookie"); + assert cookies != null; + assertEquals(1, cookies.size()); + assertEquals(expectedCookie, cookies.get(0)); } @Test - public void testCustomStatusCodeIsSetOnOutbound(){ - - //GIVEN + public void testCustomStatusCodeIsSetOnOutbound() { + // GIVEN message.setHeader(HttpMessageHeaders.HTTP_STATUS_CODE, "555"); - //WHEN + // WHEN final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(HttpStatusCode.valueOf(555), ((ResponseEntity) httpEntity).getStatusCode()); } @Test - public void testSpringIntegrationHeaderMapperIsUsedOnOutbound(){ - - //GIVEN + public void testSpringIntegrationHeaderMapperIsUsedOnOutbound() { + // GIVEN @SuppressWarnings("unchecked") HeaderMapper headersHeaderMapperMock = (HeaderMapper) mock(HeaderMapper.class); endpointConfiguration.setHeaderMapper(headersHeaderMapperMock); - //WHEN + // WHEN messageConverter.convertOutbound(new HttpMessage(), endpointConfiguration, testContext); - //THEN + // THEN verify(headersHeaderMapperMock).fromHeaders(any(MessageHeaders.class), any(HttpHeaders.class)); } @Test - public void testSpringIntegrationHeaderMapperResultIsSetOnInbound(){ - - //GIVEN + public void testSpringIntegrationHeaderMapperResultIsSetOnInbound() { + // GIVEN final Map expectedHeaderMap = new HashMap<>(); expectedHeaderMap.put("foo", "bar"); @@ -355,167 +343,143 @@ public void testSpringIntegrationHeaderMapperResultIsSetOnInbound(){ endpointConfiguration.setHeaderMapper(headersHeaderMapperMock); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("bar", httpMessage.getHeaders().get("foo")); } @Test - public void testCitrusDefaultHeaderAreSetOnInbound(){ - - //GIVEN - - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); + public void testCitrusDefaultHeaderAreSetOnInbound() { + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); - //THEN + // THEN assertTrue(httpMessage.getHeaders().containsKey("citrus_message_id")); assertTrue(httpMessage.getHeaders().containsKey("citrus_message_timestamp")); } @Test - public void testHttpEntityMessageBodyIsPreservedOnInbound(){ - - //GIVEN + public void testHttpEntityMessageBodyIsPreservedOnInbound() { + // GIVEN final HttpEntity httpEntity = new HttpEntity<>(payload); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(httpMessage.getPayload(String.class), payload); } @Test - public void testHttpEntityDefaultMessageBodyIsSetOnInbound(){ - - //GIVEN + public void testHttpEntityDefaultMessageBodyIsSetOnInbound() { + // GIVEN final HttpEntity httpEntity = new HttpEntity<>(null); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(httpMessage.getPayload(String.class), ""); } @Test - public void testCustomHeadersAreSetOnInbound(){ - - //GIVEN + public void testCustomHeadersAreSetOnInbound() { + // GIVEN final HttpHeaders expectedHttpHeader = new HttpHeaders(); expectedHttpHeader.put("foo", Collections.singletonList("bar")); final HttpEntity httpEntity = new HttpEntity<>(null, expectedHttpHeader); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("bar", httpMessage.getHeaders().get("foo")); } @Test - public void testCustomHeadersListsAreConvertedToStringOnInbound(){ - - //GIVEN + public void testCustomHeadersListsAreConvertedToStringOnInbound() { + // GIVEN final HttpHeaders expectedHttpHeader = new HttpHeaders(); expectedHttpHeader.put("foo", Arrays.asList("bar", "foobar", "foo")); final HttpEntity httpEntity = new HttpEntity<>(null, expectedHttpHeader); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(httpEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("bar,foobar,foo", httpMessage.getHeaders().get("foo")); } @Test - public void testStatusCodeIsSetOnInbound(){ - - //GIVEN + public void testStatusCodeIsSetOnInbound() { + // GIVEN final ResponseEntity responseEntity = new ResponseEntity<>(HttpStatus.FORBIDDEN); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(HttpStatus.FORBIDDEN, httpMessage.getStatusCode()); } @Test - public void testCustomStatusCodeIsSetOnInbound(){ - - //GIVEN + public void testCustomStatusCodeIsSetOnInbound() { + // GIVEN final ResponseEntity responseEntity = new ResponseEntity<>(null, null, 555); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(HttpStatusCode.valueOf(555), httpMessage.getStatusCode()); } @Test - public void testHttpVersionIsSetOnInbound(){ - - //GIVEN + public void testHttpVersionIsSetOnInbound() { + // GIVEN final ResponseEntity responseEntity = new ResponseEntity<>(HttpStatus.OK); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("HTTP/1.1", httpMessage.getVersion()); } @Test - public void testNoCookiesPreservedByDefaultOnInbound(){ + public void testNoCookiesPreservedByDefaultOnInbound() { + // GIVEN - //GIVEN - - //WHEN + // WHEN messageConverter.convertInbound(ResponseEntity.EMPTY, endpointConfiguration, testContext); - //THEN + // THEN verify(cookieConverterMock, never()).convertCookies(any()); } @Test - public void testCookiesPreservedOnConfigurationOnInbound(){ - - //GIVEN + public void testCookiesPreservedOnConfigurationOnInbound() { + // GIVEN Cookie cookieMock = mock(Cookie.class); final ResponseEntity responseEntity = ResponseEntity.ok("foobar"); when(cookieConverterMock.convertCookies(responseEntity)).thenReturn(new Cookie[]{cookieMock}); endpointConfiguration.setHandleCookies(true); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); - //THEN + // THEN assertEquals(1, httpMessage.getCookies().size()); assertEquals(cookieMock, httpMessage.getCookies().get(0)); } - @Test - public void testSpringIntegrationHeaderMapperListResultIsConvertedOnInbound(){ - - //GIVEN + public void testSpringIntegrationHeaderMapperListResultIsConvertedOnInbound() { + // GIVEN final Map mockedHeaderMap = new HashMap<>(); mockedHeaderMap.put("foo", Arrays.asList("bar", "foobar")); @@ -525,18 +489,16 @@ public void testSpringIntegrationHeaderMapperListResultIsConvertedOnInbound(){ endpointConfiguration.setHeaderMapper(headersHeaderMapperMock); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("bar,foobar", httpMessage.getHeaders().get("foo")); } @Test - public void testSpringIntegrationHeaderMapperMediaTypeResultIsConvertedOnInbound(){ - - //GIVEN + public void testSpringIntegrationHeaderMapperMediaTypeResultIsConvertedOnInbound() { + // GIVEN final Map mockedHeaderMap = new HashMap<>(); mockedHeaderMap.put("foo", MediaType.APPLICATION_JSON); @@ -546,11 +508,10 @@ public void testSpringIntegrationHeaderMapperMediaTypeResultIsConvertedOnInbound endpointConfiguration.setHeaderMapper(headersHeaderMapperMock); - //WHEN - final HttpMessage httpMessage = - messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); + // WHEN + final HttpMessage httpMessage = messageConverter.convertInbound(HttpEntity.EMPTY, endpointConfiguration, testContext); - //THEN + // THEN assertEquals("application/json", httpMessage.getHeaders().get("foo")); } } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/validation/TextEqualsMessageValidator.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/validation/TextEqualsMessageValidator.java deleted file mode 100644 index fd6afa5165..0000000000 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.http.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - private boolean trim = false; - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { - logger.debug("Skip message payload validation as no control message was defined"); - return; - } - - logger.debug("Start text equals validation ..."); - - String controlPayload = controlMessage.getPayload(String.class); - String receivedPayload = receivedMessage.getPayload(String.class); - - if (trim) { - controlPayload = controlPayload.trim(); - receivedPayload = receivedPayload.trim(); - } - - Assert.assertEquals(receivedPayload, controlPayload, "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - public TextEqualsMessageValidator enableTrim() { - this.trim = true; - return this; - } -} diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/AbstractXmlActionTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/AbstractXmlActionTest.java index 658504fb0c..8feea9269c 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/AbstractXmlActionTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpClientTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpClientTest.java index 03f545cdf3..a52d5037c0 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpClientTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpClientTest.java @@ -38,7 +38,6 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.Message; @@ -47,6 +46,7 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -76,7 +76,7 @@ public class HttpClientTest extends AbstractXmlActionTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpServerTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpServerTest.java index a1ff9a32e0..2c18aeb2d7 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpServerTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/xml/HttpServerTest.java @@ -34,12 +34,12 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -66,7 +66,7 @@ public class HttpServerTest extends AbstractXmlActionTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private HttpServer httpServer; diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/AbstractYamlActionTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/AbstractYamlActionTest.java index 645747f74b..570c380b10 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/AbstractYamlActionTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpClientTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpClientTest.java index a0140892a8..603c2bdfe8 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpClientTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpClientTest.java @@ -38,7 +38,6 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.Message; @@ -47,6 +46,7 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -76,7 +76,7 @@ public class HttpClientTest extends AbstractYamlActionTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpServerTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpServerTest.java index 2cdeb38cad..907014e627 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpServerTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/yaml/HttpServerTest.java @@ -34,12 +34,12 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -66,7 +66,7 @@ public class HttpServerTest extends AbstractYamlActionTest { private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); @BindToRegistry - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim(); private HttpServer httpServer; diff --git a/endpoints/citrus-http/src/test/resources/org/citrusframework/http/integration/http-server.jks b/endpoints/citrus-http/src/test/resources/org/citrusframework/http/integration/http-server.jks new file mode 100644 index 0000000000..939a61189c Binary files /dev/null and b/endpoints/citrus-http/src/test/resources/org/citrusframework/http/integration/http-server.jks differ diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParser.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParser.java index e164d63490..ea3342c169 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParser.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParser.java @@ -45,6 +45,11 @@ public JmsEndpoint parse(JmsEndpointConfig annotation, ReferenceResolver referen String destinationName = annotation.destinationName(); if (StringUtils.hasText(destination) || StringUtils.hasText(destinationName)) { + if (StringUtils.hasText(jmsTemplate)) { + throw new CitrusRuntimeException("When providing a jms-template, none of " + + "connection-factory, destination, or destination-name should be provided"); + } + //connectionFactory String connectionFactory = "connectionFactory"; //default value @@ -52,10 +57,6 @@ public JmsEndpoint parse(JmsEndpointConfig annotation, ReferenceResolver referen connectionFactory = annotation.connectionFactory(); } - if (!StringUtils.hasText(connectionFactory)) { - throw new CitrusRuntimeException("Required connection-factory is missing for jms configuration"); - } - builder.connectionFactory(referenceResolver.resolve(connectionFactory, ConnectionFactory.class)); //destination @@ -65,9 +66,7 @@ public JmsEndpoint parse(JmsEndpointConfig annotation, ReferenceResolver referen builder.destination(annotation.destinationName()); } } else if (StringUtils.hasText(jmsTemplate)) { - if (StringUtils.hasText(annotation.connectionFactory()) || - StringUtils.hasText(destination) || - StringUtils.hasText(destinationName)) { + if (StringUtils.hasText(annotation.connectionFactory())) { throw new CitrusRuntimeException("When providing a jms-template, none of " + "connection-factory, destination, or destination-name should be provided"); } @@ -79,12 +78,12 @@ public JmsEndpoint parse(JmsEndpointConfig annotation, ReferenceResolver referen } if (annotation.autoStart() && !annotation.pubSubDomain()) { - throw new CitrusRuntimeException("When providing auto start enabled, " + + throw new CitrusRuntimeException("When providing auto start enabled, " + "pubSubDomain should also be enabled"); } if (annotation.durableSubscription() && !annotation.pubSubDomain()) { - throw new CitrusRuntimeException("When providing durable subscription enabled, " + + throw new CitrusRuntimeException("When providing durable subscription enabled, " + "pubSubDomain should also be enabled"); } diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParser.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParser.java index 30c6d2833a..17df3c758f 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParser.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParser.java @@ -46,6 +46,11 @@ public JmsSyncEndpoint parse(JmsSyncEndpointConfig annotation, ReferenceResolver String destinationName = annotation.destinationName(); if (StringUtils.hasText(destination) || StringUtils.hasText(destinationName)) { + if (StringUtils.hasText(jmsTemplate)) { + throw new CitrusRuntimeException("When providing a jms-template, none of " + + "connection-factory, destination, or destination-name should be provided"); + } + //connectionFactory String connectionFactory = "connectionFactory"; //default value @@ -53,10 +58,6 @@ public JmsSyncEndpoint parse(JmsSyncEndpointConfig annotation, ReferenceResolver connectionFactory = annotation.connectionFactory(); } - if (!StringUtils.hasText(connectionFactory)) { - throw new CitrusRuntimeException("Required connection-factory is missing for jms configuration"); - } - builder.connectionFactory(referenceResolver.resolve(connectionFactory, ConnectionFactory.class)); //destination @@ -66,9 +67,7 @@ public JmsSyncEndpoint parse(JmsSyncEndpointConfig annotation, ReferenceResolver builder.destination(annotation.destinationName()); } } else if (StringUtils.hasText(jmsTemplate)) { - if (StringUtils.hasText(annotation.connectionFactory()) || - StringUtils.hasText(destination) || - StringUtils.hasText(destinationName)) { + if (StringUtils.hasText(annotation.connectionFactory())) { throw new CitrusRuntimeException("When providing a jms-template, none of " + "connection-factory, destination, or destination-name should be provided"); } diff --git a/endpoints/citrus-jms/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-jms/src/main/resources/META-INF/spring.schemas index 11ee04958b..e459a492c7 100644 --- a/endpoints/citrus-jms/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-jms/src/main/resources/META-INF/spring.schemas @@ -33,10 +33,10 @@ http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-3.4.0.xsd=com/consol/citrus/schema/citrus-jms-config-3.4.0.xsd http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-jms-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-jms-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-jms-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-jms-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jms-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.0.0.xsd=org/citrusframework/schema/citrus-jms-config-4.0.0.xsd +http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.0.1.xsd=org/citrusframework/schema/citrus-jms-config-4.0.1.xsd +http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.0.2.xsd=org/citrusframework/schema/citrus-jms-config-4.0.2.xsd +http\://www.citrusframework.org/schema/jms/config/citrus-jms-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jms-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jms/config/citrus-jms-config.xsd=org/citrusframework/schema/citrus-jms-config.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-2.0.xsd=com/consol/citrus/schema/citrus-jms-testcase-2.0.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-2.1.xsd=com/consol/citrus/schema/citrus-jms-testcase-2.1.xsd @@ -73,8 +73,8 @@ http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-3.3.1.xs http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-jms-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-jms-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-jms-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-jms-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-jms-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jms-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-jms-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-jms-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-jms-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jms-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase.xsd=org/citrusframework/schema/citrus-jms-testcase.xsd diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParserExceptionTest.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParserExceptionTest.java new file mode 100644 index 0000000000..9b43b68aae --- /dev/null +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsEndpointConfigParserExceptionTest.java @@ -0,0 +1,116 @@ +/* + * Copyright 2006-2016 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.jms.config.annotation; + +import static org.testng.Assert.fail; + +import jakarta.jms.JMSException; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.jms.endpoint.JmsEndpoint; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.testng.AbstractTestNGUnitTest; +import org.citrusframework.util.ReflectionHelper; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +public class JmsEndpointConfigParserExceptionTest extends AbstractTestNGUnitTest { + + @Mock + private ReferenceResolver referenceResolver; + + @BeforeClass + public void setup() throws JMSException { + MockitoAnnotations.openMocks(this); + } + + @BeforeMethod + public void setMocks() { + context.setReferenceResolver(referenceResolver); + } + + @DataProvider(name = "config-exceptions") + public Object[][] configExceptionsData() { + return new Object[][]{ + {"missingAttributes", "Either a jms-template reference or one of destination or destination-name must be provided"}, + {"jmsTemplateWithConnectionFactory", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"}, + {"jmsTemplateWithDestination", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"}, + {"jmsTemplateWithDestinationName", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"}, + {"autoStartWithoutPubSubDomain", "When providing auto start enabled, pubSubDomain should also be enabled"}, + {"durableSubscriptionWithoutPubSubDomain", "When providing durable subscription enabled, pubSubDomain should also be enabled"}, + }; + } + + @Test(dataProvider = "config-exceptions") + public void testJmsEndpointParser(String fieldName, String exceptionMessage) { + JmsEndpointConfig annotation = getJmsEndpointConfigAnnotationFromField(fieldName); + + assertException(() -> new JmsEndpointConfigParser().parse(annotation, referenceResolver), exceptionMessage); + } + + private static JmsEndpointConfig getJmsEndpointConfigAnnotationFromField(String fieldName) { + Field jmsEndpointField = ReflectionHelper.findField(JmsEndpointConfigs.class, fieldName); + if (jmsEndpointField == null) { + fail("Incorrect field name [" + fieldName + "] provided for @JmsEndpointConfig test data."); + } + + return jmsEndpointField.getAnnotation(JmsEndpointConfig.class); + } + + private static void assertException(Runnable runnable, String exceptionMessage) { + try { + runnable.run(); + fail("Expected exception not thrown!"); + } catch (CitrusRuntimeException e) { + Assert.assertTrue(e.getMessage().contains(exceptionMessage)); + } + } + + private static final class JmsEndpointConfigs { + //"Either a jms-template reference or one of destination or destination-name must be provided" + + @JmsEndpointConfig + private JmsEndpoint missingAttributes; + + //"When providing a jms-template, none of connection-factory, destination, or destination-name should be provided" + + @JmsEndpointConfig(jmsTemplate = "template", connectionFactory = "factory") + private JmsEndpoint jmsTemplateWithConnectionFactory; + + @JmsEndpointConfig(jmsTemplate = "template", destination = "destination") + private JmsEndpoint jmsTemplateWithDestination; + + @JmsEndpointConfig(jmsTemplate = "template", destinationName = "destination-name") + private JmsEndpoint jmsTemplateWithDestinationName; + + //"When providing auto start enabled, pubSubDomain should also be enabled" + + @JmsEndpointConfig(jmsTemplate = "template", autoStart = true) + private JmsEndpoint autoStartWithoutPubSubDomain; + + //"When providing durable subscription enabled, pubSubDomain should also be enabled" + + @JmsEndpointConfig(destinationName = "destination-name", durableSubscription = true) + private JmsEndpoint durableSubscriptionWithoutPubSubDomain; + } +} diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParserExceptionTest.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParserExceptionTest.java new file mode 100644 index 0000000000..2427fc2d9f --- /dev/null +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/config/annotation/JmsSyncEndpointConfigParserExceptionTest.java @@ -0,0 +1,104 @@ +/* + * Copyright 2006-2016 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.jms.config.annotation; + +import static org.testng.Assert.fail; + +import jakarta.jms.JMSException; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.jms.endpoint.JmsEndpoint; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.testng.AbstractTestNGUnitTest; +import org.citrusframework.util.ReflectionHelper; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +public class JmsSyncEndpointConfigParserExceptionTest extends AbstractTestNGUnitTest { + + @Mock + private ReferenceResolver referenceResolver; + + @BeforeClass + public void setup() throws JMSException { + MockitoAnnotations.openMocks(this); + } + + @BeforeMethod + public void setMocks() { + context.setReferenceResolver(referenceResolver); + } + + @DataProvider(name = "config-exceptions") + public Object[][] configExceptionsData() { + return new Object[][]{ + {"missingAttributes", "Either a jms-template reference or one of destination or destination-name must be provided"}, + {"jmsTemplateWithConnectionFactory", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"}, + {"jmsTemplateWithDestination", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"}, + {"jmsTemplateWithDestinationName", "When providing a jms-template, none of connection-factory, destination, or destination-name should be provided"} + }; + } + + @Test(dataProvider = "config-exceptions") + public void testJmsSyncEndpointParser(String fieldName, String exceptionMessage) { + JmsSyncEndpointConfig annotation = getJmsSyncEndpointConfigAnnotationFromField(fieldName); + + assertException(() -> new JmsSyncEndpointConfigParser().parse(annotation, referenceResolver), exceptionMessage); + } + + private static JmsSyncEndpointConfig getJmsSyncEndpointConfigAnnotationFromField(String fieldName) { + Field jmsEndpointField = ReflectionHelper.findField(JmsSyncEndpointConfigs.class, fieldName); + if (jmsEndpointField == null) { + fail("Incorrect field name [" + fieldName + "] provided for @JmsSyncEndpointConfig test data."); + } + + return jmsEndpointField.getAnnotation(JmsSyncEndpointConfig.class); + } + + private static void assertException(Runnable runnable, String exceptionMessage) { + try { + runnable.run(); + fail("Expected exception not thrown!"); + } catch (CitrusRuntimeException e) { + Assert.assertTrue(e.getMessage().contains(exceptionMessage)); + } + } + + private static final class JmsSyncEndpointConfigs { + //"Either a jms-template reference or one of destination or destination-name must be provided" + + @JmsSyncEndpointConfig + private JmsEndpoint missingAttributes; + + //"When providing a jms-template, none of connection-factory, destination, or destination-name should be provided" + + @JmsSyncEndpointConfig(jmsTemplate = "template", connectionFactory = "factory") + private JmsEndpoint jmsTemplateWithConnectionFactory; + + @JmsSyncEndpointConfig(jmsTemplate = "template", destination = "destination") + private JmsEndpoint jmsTemplateWithDestination; + + @JmsSyncEndpointConfig(jmsTemplate = "template", destinationName = "destination-name") + private JmsEndpoint jmsTemplateWithDestinationName; + } +} diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/groovy/AbstractGroovyActionDslTest.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/groovy/AbstractGroovyActionDslTest.java index 9f7853b4c9..f800868766 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/groovy/AbstractGroovyActionDslTest.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/xml/AbstractXmlActionTest.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/xml/AbstractXmlActionTest.java index 7fe9aa8580..a9197c4cc5 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/xml/AbstractXmlActionTest.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/yaml/AbstractYamlActionTest.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/yaml/AbstractYamlActionTest.java index 5b30582e5b..81620dcbd4 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/yaml/AbstractYamlActionTest.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsCommunicationIT.xml b/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsCommunicationIT.xml index bbfd9dec7d..1e05a5858c 100644 --- a/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsCommunicationIT.xml +++ b/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsCommunicationIT.xml @@ -21,9 +21,9 @@ is guaranteed without any deficit. - - - + + + diff --git a/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.xml b/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.xml index e7fdf70485..bac5d81e70 100644 --- a/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.xml +++ b/endpoints/citrus-jms/src/test/resources/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.xml @@ -9,18 +9,18 @@ 2009-11-03T00:00:00 - + JMS topic support in synchronous JMS communication. - - - + + + - + Send synchronous hello request to jms topic diff --git a/endpoints/citrus-jmx/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-jmx/src/main/resources/META-INF/spring.schemas index c762f97088..3da50032b4 100644 --- a/endpoints/citrus-jmx/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-jmx/src/main/resources/META-INF/spring.schemas @@ -28,10 +28,10 @@ http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-3.4.0.xsd=com/consol/citrus/schema/citrus-jmx-config-3.4.0.xsd http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-jmx-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-jmx-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-jmx-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-jmx-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jmx-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.0.0.xsd=org/citrusframework/schema/citrus-jmx-config-4.0.0.xsd +http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.0.1.xsd=org/citrusframework/schema/citrus-jmx-config-4.0.1.xsd +http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.0.2.xsd=org/citrusframework/schema/citrus-jmx-config-4.0.2.xsd +http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jmx-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jmx/config/citrus-jmx-config.xsd=org/citrusframework/schema/citrus-jmx-config.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-2.5.1.xsd=com/consol/citrus/schema/citrus-jmx-testcase-2.5.1.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-2.5.2.xsd=com/consol/citrus/schema/citrus-jmx-testcase-2.5.2.xsd @@ -63,8 +63,8 @@ http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-3.3.1.xs http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-jmx-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-jmx-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/jmx/testcase/citrus-jmx-testcase.xsd=org/citrusframework/schema/citrus-jmx-testcase.xsd diff --git a/endpoints/citrus-kafka/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-kafka/src/main/resources/META-INF/spring.schemas index b74b56310d..f20276f016 100644 --- a/endpoints/citrus-kafka/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-kafka/src/main/resources/META-INF/spring.schemas @@ -29,10 +29,10 @@ http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-3.3.1.xs http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-3.4.0.xsd=com/consol/citrus/schema/citrus-kafka-config-3.4.0.xsd http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-kafka-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-kafka-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-kafka-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-kafka-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kafka-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.0.0.xsd=org/citrusframework/schema/citrus-kafka-config-4.0.0.xsd +http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.0.1.xsd=org/citrusframework/schema/citrus-kafka-config-4.0.1.xsd +http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.0.2.xsd=org/citrusframework/schema/citrus-kafka-config-4.0.2.xsd +http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kafka-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kafka/config/citrus-kafka-config.xsd=org/citrusframework/schema/citrus-kafka-config.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-2.8.0.xsd=com/consol/citrus/schema/citrus-kafka-testcase-2.8.0.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-3.0.0-M1.xsd=com/consol/citrus/schema/citrus-kafka-testcase-3.0.0-M1.xsd @@ -49,8 +49,8 @@ http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-3.3. http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-kafka-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-kafka-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/kafka/testcase/citrus-kafka-testcase.xsd=org/citrusframework/schema/citrus-kafka-testcase.xsd diff --git a/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/MailSettings.java b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/MailSettings.java new file mode 100644 index 0000000000..7e09826d3f --- /dev/null +++ b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/MailSettings.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.mail; + +import org.citrusframework.message.MessageType; + +/** + * @author Christoph Deppisch + */ +public class MailSettings { + + private static final String MAIL_PROPERTY_PREFIX = "citrus.mail."; + private static final String MAIL_ENV_PREFIX = "CITRUS_MAIL"; + + private static final String MARSHALLER_TYPE_PROPERTY = MAIL_PROPERTY_PREFIX + "marshaller.type"; + private static final String MARSHALLER_TYPE_ENV = MAIL_ENV_PREFIX + "MARSHALLER_TYPE"; + private static final String MARSHALLER_TYPE_DEFAULT = MessageType.XML.name(); + + private MailSettings() { + // prevent instantiation of utility class + } + + /** + * Gets the default marshaller type setting that represents the data format + * that the marshaller will use (usually one of XML or JSON). + * @return + */ + public static String getMarshallerType() { + return System.getProperty(MARSHALLER_TYPE_PROPERTY, + System.getenv(MARSHALLER_TYPE_ENV) != null ? System.getenv(MARSHALLER_TYPE_ENV) : MARSHALLER_TYPE_DEFAULT); + } + +} diff --git a/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/message/MailMessageConverter.java b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/message/MailMessageConverter.java index 379a46bc69..e173d60930 100644 --- a/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/message/MailMessageConverter.java +++ b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/message/MailMessageConverter.java @@ -16,20 +16,6 @@ package org.citrusframework.mail.message; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import javax.xml.transform.Source; - import jakarta.mail.MessagingException; import jakarta.mail.Multipart; import jakarta.mail.Session; @@ -56,6 +42,20 @@ import org.springframework.mail.javamail.MimeMailMessage; import org.springframework.mail.javamail.MimeMessageHelper; +import javax.xml.transform.Source; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + /** * @author Christoph Deppisch * @author Christian Guggenmos @@ -398,9 +398,9 @@ static String parseContentType(String contentType) throws IOException { */ static String parseCharsetFromContentType(String contentType) { final String charsetPrefix = "charset="; - if (org.apache.commons.lang.StringUtils.contains(contentType, charsetPrefix)) { - String charsetName = org.apache.commons.lang.StringUtils.substringAfter(contentType, charsetPrefix); - return org.apache.commons.lang.StringUtils.substringBefore(charsetName, ";"); + if (org.apache.commons.lang3.StringUtils.contains(contentType, charsetPrefix)) { + String charsetName = org.apache.commons.lang3.StringUtils.substringAfter(contentType, charsetPrefix); + return org.apache.commons.lang3.StringUtils.substringBefore(charsetName, ";"); } else { return CitrusSettings.CITRUS_FILE_ENCODING; } diff --git a/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/model/MailMarshaller.java b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/model/MailMarshaller.java index 35546a6958..376d27871e 100644 --- a/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/model/MailMarshaller.java +++ b/endpoints/citrus-mail/src/main/java/org/citrusframework/mail/model/MailMarshaller.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.xml.bind.JAXBException; import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.mail.MailSettings; import org.citrusframework.message.MessageType; import org.citrusframework.spi.Resources; import org.citrusframework.xml.Jaxb2Marshaller; @@ -45,11 +46,8 @@ public class MailMarshaller implements Marshaller, Unmarshaller { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(MailMarshaller.class); - /** System property defining message format to marshal to */ - private static final String MAIL_MARSHALLER_TYPE_PROPERTY = "citrus.mail.marshaller.type"; - /** Message type format: XML or JSON */ - private String type; + private String type = MailSettings.getMarshallerType(); private final ObjectMapper mapper; private final Jaxb2Marshaller marshaller; @@ -62,8 +60,6 @@ public class MailMarshaller implements Marshaller, Unmarshaller { public MailMarshaller() { this.mapper = new ObjectMapper(); this.marshaller = new Jaxb2Marshaller(Resources.fromClasspath("org/citrusframework/schema/citrus-mail-message.xsd"), classesToBeBound); - - type = System.getProperty(MAIL_MARSHALLER_TYPE_PROPERTY, MessageType.XML.name()); } public Object unmarshal(Source source) { diff --git a/endpoints/citrus-mail/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-mail/src/main/resources/META-INF/spring.schemas index 5ecb5d65cb..51466582fb 100644 --- a/endpoints/citrus-mail/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-mail/src/main/resources/META-INF/spring.schemas @@ -35,8 +35,8 @@ http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-3.3.1.xsd= http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-3.4.0.xsd=com/consol/citrus/schema/citrus-mail-config-3.4.0.xsd http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-mail-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-mail-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-mail-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-mail-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-mail-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.0.0.xsd=org/citrusframework/schema/citrus-mail-config-4.0.0.xsd +http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.0.1.xsd=org/citrusframework/schema/citrus-mail-config-4.0.1.xsd +http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.0.2.xsd=org/citrusframework/schema/citrus-mail-config-4.0.2.xsd +http\://www.citrusframework.org/schema/mail/config/citrus-mail-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-mail-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/mail/config/citrus-mail-config.xsd=org/citrusframework/schema/citrus-mail-config.xsd diff --git a/endpoints/citrus-rmi/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-rmi/src/main/resources/META-INF/spring.schemas index 34e489017b..1d19902d39 100644 --- a/endpoints/citrus-rmi/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-rmi/src/main/resources/META-INF/spring.schemas @@ -28,8 +28,8 @@ http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-3.4.0.xsd=com/consol/citrus/schema/citrus-rmi-config-3.4.0.xsd http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-rmi-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-rmi-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-rmi-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-rmi-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-rmi-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.0.0.xsd=org/citrusframework/schema/citrus-rmi-config-4.0.0.xsd +http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.0.1.xsd=org/citrusframework/schema/citrus-rmi-config-4.0.1.xsd +http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.0.2.xsd=org/citrusframework/schema/citrus-rmi-config-4.0.2.xsd +http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-rmi-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/rmi/config/citrus-rmi-config.xsd=org/citrusframework/schema/citrus-rmi-config.xsd diff --git a/endpoints/citrus-spring-integration/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-spring-integration/src/main/resources/META-INF/spring.schemas index 7433ac9694..f53425fb82 100644 --- a/endpoints/citrus-spring-integration/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-spring-integration/src/main/resources/META-INF/spring.schemas @@ -12,10 +12,10 @@ http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-i http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-3.4.0.xsd=com/consol/citrus/schema/citrus-spring-integration-config-3.4.0.xsd http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.0.0.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.0.0.xsd +http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.0.1.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.0.1.xsd +http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.0.2.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.0.2.xsd +http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-spring-integration-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config.xsd=org/citrusframework/schema/citrus-spring-integration-config.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-3.0.0-M1.xsd=com/consol/citrus/schema/citrus-spring-integration-testcase-3.0.0-M1.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-3.0.0-M2.xsd=com/consol/citrus/schema/citrus-spring-integration-testcase-3.0.0-M2.xsd @@ -31,8 +31,8 @@ http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-spring-integration-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-spring-integration-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/spring-integration/testcase/citrus-spring-integration-testcase.xsd=org/citrusframework/schema/citrus-spring-integration-testcase.xsd diff --git a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/groovy/AbstractGroovyActionDslTest.java b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/groovy/AbstractGroovyActionDslTest.java index 2e7912f626..0ff6ee63df 100644 --- a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/groovy/AbstractGroovyActionDslTest.java +++ b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/xml/AbstractXmlActionTest.java b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/xml/AbstractXmlActionTest.java index c94cd44418..a9dba0325e 100644 --- a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/xml/AbstractXmlActionTest.java +++ b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/yaml/AbstractYamlActionTest.java b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/yaml/AbstractYamlActionTest.java index 6123930bd4..eaea012bb8 100644 --- a/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/yaml/AbstractYamlActionTest.java +++ b/endpoints/citrus-spring-integration/src/test/java/org/citrusframework/springintegration/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-ssh/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-ssh/src/main/resources/META-INF/spring.schemas index 8324be26a1..c86d712f78 100644 --- a/endpoints/citrus-ssh/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-ssh/src/main/resources/META-INF/spring.schemas @@ -37,8 +37,8 @@ http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-3.3.1.xsd=co http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-3.4.0.xsd=com/consol/citrus/schema/citrus-ssh-config-3.4.0.xsd http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-ssh-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-ssh-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-ssh-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-ssh-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ssh-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.0.0.xsd=org/citrusframework/schema/citrus-ssh-config-4.0.0.xsd +http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.0.1.xsd=org/citrusframework/schema/citrus-ssh-config-4.0.1.xsd +http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.0.2.xsd=org/citrusframework/schema/citrus-ssh-config-4.0.2.xsd +http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ssh-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ssh/config/citrus-ssh-config.xsd=org/citrusframework/schema/citrus-ssh-config.xsd diff --git a/endpoints/citrus-vertx/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-vertx/src/main/resources/META-INF/spring.schemas index 701340e74d..ff35a7ed1d 100644 --- a/endpoints/citrus-vertx/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-vertx/src/main/resources/META-INF/spring.schemas @@ -35,8 +35,8 @@ http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-3.3.1.xs http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-3.4.0.xsd=com/consol/citrus/schema/citrus-vertx-config-3.4.0.xsd http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-vertx-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-vertx-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-vertx-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-vertx-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-vertx-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.0.0.xsd=org/citrusframework/schema/citrus-vertx-config-4.0.0.xsd +http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.0.1.xsd=org/citrusframework/schema/citrus-vertx-config-4.0.1.xsd +http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.0.2.xsd=org/citrusframework/schema/citrus-vertx-config-4.0.2.xsd +http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-vertx-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/vertx/config/citrus-vertx-config.xsd=org/citrusframework/schema/citrus-vertx-config.xsd diff --git a/endpoints/citrus-websocket/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-websocket/src/main/resources/META-INF/spring.schemas index 753e3e9817..39a3704ec7 100644 --- a/endpoints/citrus-websocket/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-websocket/src/main/resources/META-INF/spring.schemas @@ -30,8 +30,8 @@ http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config- http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-3.4.0.xsd=com/consol/citrus/schema/citrus-websocket-config-3.4.0.xsd http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-websocket-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-websocket-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-websocket-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-websocket-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-websocket-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.0.0.xsd=org/citrusframework/schema/citrus-websocket-config-4.0.0.xsd +http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.0.1.xsd=org/citrusframework/schema/citrus-websocket-config-4.0.1.xsd +http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.0.2.xsd=org/citrusframework/schema/citrus-websocket-config-4.0.2.xsd +http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-websocket-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/websocket/config/citrus-websocket-config.xsd=org/citrusframework/schema/citrus-websocket-config.xsd diff --git a/endpoints/citrus-ws/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-ws/src/main/resources/META-INF/spring.schemas index 474a31bf6e..0dc0b96c8a 100644 --- a/endpoints/citrus-ws/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-ws/src/main/resources/META-INF/spring.schemas @@ -40,10 +40,10 @@ http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-3.3.1.xsd=com/ http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-3.4.0.xsd=com/consol/citrus/schema/citrus-ws-config-3.4.0.xsd http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-ws-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-ws-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-ws-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-ws-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ws-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.0.0.xsd=org/citrusframework/schema/citrus-ws-config-4.0.0.xsd +http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.0.1.xsd=org/citrusframework/schema/citrus-ws-config-4.0.1.xsd +http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.0.2.xsd=org/citrusframework/schema/citrus-ws-config-4.0.2.xsd +http\://www.citrusframework.org/schema/ws/config/citrus-ws-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ws-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ws/config/citrus-ws-config.xsd=org/citrusframework/schema/citrus-ws-config.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-1.1.xsd=com/consol/citrus/schema/citrus-ws-testcase-1.1.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-1.2.xsd=com/consol/citrus/schema/citrus-ws-testcase-1.2.xsd @@ -86,8 +86,8 @@ http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-3.3.1.xsd= http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-ws-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-ws-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-ws-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-ws-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-ws-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ws-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-ws-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-ws-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-ws-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-ws-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase.xsd=org/citrusframework/schema/citrus-ws-testcase.xsd diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/TextEqualsMessageValidator.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/TextEqualsMessageValidator.java deleted file mode 100644 index 532bba34bc..0000000000 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/TextEqualsMessageValidator.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.citrusframework.ws; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage.getPayload(String.class).isBlank()) { - logger.info("Skip text validation as no control message payload specified"); - return; - } - - Assert.assertEquals(receivedMessage.getPayload(String.class), controlMessage.getPayload(String.class), "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/UnitTestSupport.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/UnitTestSupport.java index 0cab167ef2..c6d77a6b89 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/UnitTestSupport.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/UnitTestSupport.java @@ -3,6 +3,7 @@ import org.citrusframework.context.TestContextFactory; import org.citrusframework.functions.DefaultFunctionLibrary; import org.citrusframework.testng.AbstractTestNGUnitTest; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.matcher.DefaultValidationMatcherLibrary; import org.citrusframework.validation.xml.DomXmlMessageValidator; @@ -18,7 +19,7 @@ protected TestContextFactory createTestContextFactory() { factory.getValidationMatcherRegistry().addValidationMatcherLibrary(new DefaultValidationMatcherLibrary()); factory.getMessageValidatorRegistry().addMessageValidator("xml", new DomXmlMessageValidator()); - factory.getMessageValidatorRegistry().addMessageValidator("text", new TextEqualsMessageValidator()); + factory.getMessageValidatorRegistry().addMessageValidator("text", new DefaultTextEqualsMessageValidator()); return factory; } } diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/AssertSoapFaultBuilderTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/AssertSoapFaultBuilderTest.java index 998011da13..bc0b9da0e3 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/AssertSoapFaultBuilderTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/AssertSoapFaultBuilderTest.java @@ -353,6 +353,7 @@ public void testMultipleFaultDetails() { @Test public void testFaultDetailResource() throws IOException { reset(resource, referenceResolver, soapMessage, soapFaultValidator, soapBody, soapFault, soapFaultDetail, soapFaultDetailElement); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Something went wrong".getBytes())); when(soapMessage.getSoapBody()).thenReturn(soapBody); @@ -453,6 +454,7 @@ public void testFaultDetailResourcePath() { @Test public void testMultipleFaultDetailsInlineAndResource() throws IOException { reset(resource, referenceResolver, soapMessage, soapFaultValidator, soapBody, soapFault, soapFaultDetail, soapFaultDetailElement); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Something went wrong".getBytes())); when(soapMessage.getSoapBody()).thenReturn(soapBody); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/ReceiveSoapMessageTestActionBuilderTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/ReceiveSoapMessageTestActionBuilderTest.java index 5c8b204672..924ca7d00e 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/ReceiveSoapMessageTestActionBuilderTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/ReceiveSoapMessageTestActionBuilderTest.java @@ -18,7 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import org.citrusframework.DefaultTestCaseRunner; @@ -217,7 +217,9 @@ public void testSoapAttachmentResource() throws IOException { .setHeader("operation","foo") .addAttachment(testAttachment)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); + when(attachmentResource.exists()).thenReturn(true); when(attachmentResource.getInputStream()).thenReturn(new ByteArrayInputStream("This is an attachment".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); @@ -225,7 +227,7 @@ public void testSoapAttachmentResource() throws IOException { .receive() .message() .body(resource) - .attachment(testAttachment.getContentId(), testAttachment.getContentType(), attachmentResource, Charset.forName("UTF-8"))); + .attachment(testAttachment.getContentId(), testAttachment.getContentType(), attachmentResource, StandardCharsets.UTF_8)); TestCase test = builder.getTestCase(); Assert.assertEquals(test.getActionCount(), 1); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapFaultTestActionBuilderTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapFaultTestActionBuilderTest.java index 4e457f6e74..5fb71619e4 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapFaultTestActionBuilderTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapFaultTestActionBuilderTest.java @@ -156,6 +156,7 @@ public void testSendSoapFaultWithDetailResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream(ERROR_DETAIL.getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapMessageTestActionBuilderTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapMessageTestActionBuilderTest.java index 6e7d960d07..8de9cca564 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapMessageTestActionBuilderTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/actions/dsl/SendSoapMessageTestActionBuilderTest.java @@ -349,6 +349,7 @@ public void testSoapAttachmentResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("someAttachmentData".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); builder.$(soap().client(soapClient) diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AbstractGroovyActionDslTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AbstractGroovyActionDslTest.java index ed18276ed4..a29b948573 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AbstractGroovyActionDslTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AssertSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AssertSoapFaultTest.java index 2a4f3fa5a8..05a0e51194 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AssertSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/AssertSoapFaultTest.java @@ -33,7 +33,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.AssertSoapFault; import org.citrusframework.ws.client.WebServiceClient; import org.citrusframework.ws.message.SoapFault; @@ -102,7 +102,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapFaultValidator", new SimpleSoapFaultValidator()); context.getReferenceResolver().bind("customSoapFaultValidator", new SimpleSoapFaultValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SendSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SendSoapFaultTest.java index 595511737e..cc8dd4f322 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SendSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SendSoapFaultTest.java @@ -31,8 +31,8 @@ import org.citrusframework.message.MessageQueue; import org.citrusframework.message.MessageType; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.StaticMessageBuilder; -import org.citrusframework.ws.TextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapFaultAction; import org.citrusframework.ws.message.SoapMessage; @@ -82,7 +82,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapClientTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapClientTest.java index ddfee6cb5d..eba8b02c3e 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapClientTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapClientTest.java @@ -34,7 +34,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.client.WebServiceClient; @@ -104,7 +104,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapServerTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapServerTest.java index 7b715e73a5..2b83ba3340 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapServerTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/groovy/SoapServerTest.java @@ -33,7 +33,7 @@ import org.citrusframework.message.MessageType; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.message.SoapAttachment; @@ -85,7 +85,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AbstractXmlActionTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AbstractXmlActionTest.java index d2c9c07bde..873760df98 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AbstractXmlActionTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AbstractXmlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AssertSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AssertSoapFaultTest.java index f7003bfb13..fc413a1283 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AssertSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/AssertSoapFaultTest.java @@ -32,7 +32,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.AssertSoapFault; import org.citrusframework.ws.client.WebServiceClient; import org.citrusframework.ws.message.SoapFault; @@ -102,7 +102,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapFaultValidator", new SimpleSoapFaultValidator()); context.getReferenceResolver().bind("customSoapFaultValidator", new SimpleSoapFaultValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SendSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SendSoapFaultTest.java index 2321fccabc..032967fbec 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SendSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SendSoapFaultTest.java @@ -30,8 +30,8 @@ import org.citrusframework.message.MessageQueue; import org.citrusframework.message.MessageType; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.StaticMessageBuilder; -import org.citrusframework.ws.TextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapFaultAction; import org.citrusframework.ws.message.SoapMessage; @@ -82,7 +82,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapClientTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapClientTest.java index e788f9e8e0..c98124ccc3 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapClientTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapClientTest.java @@ -34,7 +34,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.client.WebServiceClient; @@ -107,7 +107,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapServerTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapServerTest.java index e828861a21..256f12d4fc 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapServerTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/xml/SoapServerTest.java @@ -32,7 +32,7 @@ import org.citrusframework.message.MessageType; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.message.SoapAttachment; @@ -85,7 +85,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AbstractYamlActionTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AbstractYamlActionTest.java index 79e82416ed..61c6b63716 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AbstractYamlActionTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AssertSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AssertSoapFaultTest.java index 968d34d9b2..b0b065e031 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AssertSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/AssertSoapFaultTest.java @@ -32,7 +32,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.AssertSoapFault; import org.citrusframework.ws.client.WebServiceClient; import org.citrusframework.ws.message.SoapFault; @@ -102,7 +102,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapFaultValidator", new SimpleSoapFaultValidator()); context.getReferenceResolver().bind("customSoapFaultValidator", new SimpleSoapFaultValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SendSoapFaultTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SendSoapFaultTest.java index 5a3afdd852..d7c3c857a3 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SendSoapFaultTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SendSoapFaultTest.java @@ -30,8 +30,8 @@ import org.citrusframework.message.MessageQueue; import org.citrusframework.message.MessageType; import org.citrusframework.validation.DefaultMessageHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.StaticMessageBuilder; -import org.citrusframework.ws.TextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapFaultAction; import org.citrusframework.ws.message.SoapMessage; @@ -82,7 +82,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); endpointAdapter.handleMessage(new SoapMessage("Hello Citrus").contentType("application/xml")); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapClientTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapClientTest.java index 2e244c9a65..0fc14a8006 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapClientTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapClientTest.java @@ -33,7 +33,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.client.WebServiceClient; @@ -105,7 +105,7 @@ public void shouldLoadSoapClientActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapServerTest.java b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapServerTest.java index 6d0f4eab60..f442d22486 100644 --- a/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapServerTest.java +++ b/endpoints/citrus-ws/src/test/java/org/citrusframework/ws/yaml/SoapServerTest.java @@ -32,7 +32,7 @@ import org.citrusframework.message.MessageType; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.ws.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.ws.message.SoapAttachment; @@ -85,7 +85,7 @@ public void shouldLoadSoapServerActions() throws IOException { context.getReferenceResolver().bind("soapServer", soapServer); context.getReferenceResolver().bind("headerValidator", new DefaultMessageHeaderValidator()); - context.getMessageValidatorRegistry().addMessageValidator("validator", new TextEqualsMessageValidator()); + context.getMessageValidatorRegistry().addMessageValidator("validator", new DefaultTextEqualsMessageValidator()); context.getReferenceResolver().bind("soapAttachmentValidator", new SimpleSoapAttachmentValidator()); context.getReferenceResolver().bind("mySoapAttachmentValidator", new SimpleSoapAttachmentValidator()); diff --git a/endpoints/citrus-zookeeper/src/main/resources/META-INF/spring.schemas b/endpoints/citrus-zookeeper/src/main/resources/META-INF/spring.schemas index e241876727..19e7558d23 100644 --- a/endpoints/citrus-zookeeper/src/main/resources/META-INF/spring.schemas +++ b/endpoints/citrus-zookeeper/src/main/resources/META-INF/spring.schemas @@ -25,10 +25,10 @@ http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config- http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-3.4.0.xsd=com/consol/citrus/schema/citrus-zookeeper-config-3.4.0.xsd http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.0.0.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.0.0.xsd +http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.0.1.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.0.1.xsd +http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.0.2.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.0.2.xsd +http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-zookeeper-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config.xsd=org/citrusframework/schema/citrus-zookeeper-config.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-2.6.1.xsd=com/consol/citrus/schema/citrus-zookeeper-testcase-2.6.1.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-2.6.2.xsd=com/consol/citrus/schema/citrus-zookeeper-testcase-2.6.2.xsd @@ -57,8 +57,8 @@ http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testc http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-zookeeper-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-zookeeper-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase.xsd=org/citrusframework/schema/citrus-zookeeper-testcase.xsd diff --git a/pom.xml b/pom.xml index ed4c94b010..5b02299621 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 1.5.0 1.16.0 2.14.0 - 2.6 + 3.14.0 1.2 3.10.0 7.14.0 @@ -323,8 +323,8 @@ ${commons.codec.version}
- commons-lang - commons-lang + org.apache.commons + commons-lang3 ${commons.lang.version} diff --git a/runtime/citrus-cucumber/src/main/resources/META-INF/spring.schemas b/runtime/citrus-cucumber/src/main/resources/META-INF/spring.schemas index c66185fa30..0f5b1a13d5 100644 --- a/runtime/citrus-cucumber/src/main/resources/META-INF/spring.schemas +++ b/runtime/citrus-cucumber/src/main/resources/META-INF/spring.schemas @@ -25,8 +25,8 @@ http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcas http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-3.4.0.xsd=com/consol/citrus/schema/citrus-cucumber-testcase-3.4.0.xsd http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.0.0-M1.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.0.0-M1.xsd http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.0.0-M2.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.0.0.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.0.0.xsd +http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.0.1.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.0.1.xsd +http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.0.2.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.0.2.xsd +http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-cucumber-testcase-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase.xsd=org/citrusframework/schema/citrus-cucumber-testcase.xsd diff --git a/runtime/citrus-cucumber/src/test/java/org/citrusframework/cucumber/integration/TextEqualsMessageValidator.java b/runtime/citrus-cucumber/src/test/java/org/citrusframework/cucumber/integration/TextEqualsMessageValidator.java deleted file mode 100644 index 6f918ca3f0..0000000000 --- a/runtime/citrus-cucumber/src/test/java/org/citrusframework/cucumber/integration/TextEqualsMessageValidator.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.citrusframework.cucumber.integration; - -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.ValidationException; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (!receivedMessage.getPayload(String.class).equals(controlMessage.getPayload(String.class))) { - throw new ValidationException("Validation failed - expected message contents not equal!"); - } - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.XML.toString()) - || messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/runtime/citrus-cucumber/src/test/resources/citrus-context.xml b/runtime/citrus-cucumber/src/test/resources/citrus-context.xml index d2787e7229..780a427612 100644 --- a/runtime/citrus-cucumber/src/test/resources/citrus-context.xml +++ b/runtime/citrus-cucumber/src/test/resources/citrus-context.xml @@ -18,7 +18,7 @@ - + diff --git a/runtime/citrus-groovy/src/main/java/org/citrusframework/groovy/dsl/configuration/ContextConfiguration.java b/runtime/citrus-groovy/src/main/java/org/citrusframework/groovy/dsl/configuration/ContextConfiguration.java index b20c311e6c..50acab345c 100644 --- a/runtime/citrus-groovy/src/main/java/org/citrusframework/groovy/dsl/configuration/ContextConfiguration.java +++ b/runtime/citrus-groovy/src/main/java/org/citrusframework/groovy/dsl/configuration/ContextConfiguration.java @@ -24,7 +24,6 @@ import groovy.lang.Closure; import groovy.lang.DelegatesTo; import org.citrusframework.Citrus; -import org.citrusframework.common.InitializingPhase; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.groovy.dsl.GroovyShellUtils; @@ -98,10 +97,7 @@ public void endpoints(@DelegatesTo(EndpointsConfiguration.class) Closure call callable.call(); configuration.getEndpoints().forEach(endpoint -> { - if (endpoint instanceof InitializingPhase) { - ((InitializingPhase) endpoint).initialize(); - } - citrus.getCitrusContext().bind(endpoint.getName(), endpoint); + citrus.getCitrusContext().addComponent(endpoint.getName(), endpoint); if (context != null && !context.getReferenceResolver().equals(citrus.getCitrusContext().getReferenceResolver())) { context.getReferenceResolver().bind(endpoint.getName(), endpoint); diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/UnitTestSupport.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/UnitTestSupport.java index a81d69411b..6488c60180 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/UnitTestSupport.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/UnitTestSupport.java @@ -23,7 +23,7 @@ import org.citrusframework.functions.DefaultFunctionLibrary; import org.citrusframework.testng.AbstractTestNGUnitTest; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.matcher.DefaultValidationMatcherLibrary; /** @@ -38,7 +38,7 @@ protected TestContextFactory createTestContextFactory() { factory.getValidationMatcherRegistry().addValidationMatcherLibrary(new DefaultValidationMatcherLibrary()); factory.getMessageValidatorRegistry().addMessageValidator("headerValidator", new DefaultMessageHeaderValidator()); - factory.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new TextEqualsMessageValidator()); + factory.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new DefaultTextEqualsMessageValidator()); return factory; } } diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/actions/dsl/GroovyTestActionBuilderTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/actions/dsl/GroovyTestActionBuilderTest.java index 788c4898a0..2fef10a2aa 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/actions/dsl/GroovyTestActionBuilderTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/actions/dsl/GroovyTestActionBuilderTest.java @@ -39,6 +39,7 @@ public class GroovyTestActionBuilderTest extends UnitTestSupport { @Test public void testGroovyBuilderWithResource() throws IOException { reset(scriptResource); + when(scriptResource.exists()).thenReturn(true); when(scriptResource.getInputStream()).thenReturn(new ByteArrayInputStream("println 'Wow groovy!'".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); builder.$(groovy().script(scriptResource) diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/AbstractGroovyActionDslTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/AbstractGroovyActionDslTest.java index 33e0da5f41..abbec2afc6 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/AbstractGroovyActionDslTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/AbstractGroovyActionDslTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -67,6 +68,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/ReceiveTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/ReceiveTest.java index ec0fd50426..e04eae3dad 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/ReceiveTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/ReceiveTest.java @@ -19,6 +19,8 @@ package org.citrusframework.groovy.dsl; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.ReceiveMessageAction; @@ -33,10 +35,10 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultHeaderValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.HeaderValidator; import org.citrusframework.validation.MessageValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -50,8 +52,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -73,7 +73,7 @@ public void shouldLoadReceive() throws IOException { GroovyTestLoader testLoader = createTestLoader("classpath:org/citrusframework/groovy/dsl/receive.test.groovy"); MessageQueue helloQueue = new DefaultMessageQueue("helloQueue"); - context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new TextEqualsMessageValidator().enableTrim().normalizeLineEndings()); + context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings()); context.getReferenceResolver().bind("defaultHeaderValidator", new DefaultHeaderValidator()); context.getReferenceResolver().bind("myHeaderValidator", new DefaultHeaderValidator()); context.getReferenceResolver().bind("helloQueue", helloQueue); diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/SendTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/SendTest.java index 0c84e330d1..2c3306bce5 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/SendTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/SendTest.java @@ -19,6 +19,8 @@ package org.citrusframework.groovy.dsl; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.SendMessageAction; @@ -33,7 +35,7 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -43,8 +45,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -56,7 +56,7 @@ public class SendTest extends AbstractGroovyActionDslTest { final DataDictionary myDataDictionary = Mockito.mock(DataDictionary.class); private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim().normalizeLineEndings(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings(); @Test public void shouldLoadSend() throws IOException { diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/xml/AbstractXmlActionTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/xml/AbstractXmlActionTest.java index 69889b29f5..9b5082655a 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/xml/AbstractXmlActionTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/xml/AbstractXmlActionTest.java @@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -64,6 +65,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/yaml/AbstractYamlActionTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/yaml/AbstractYamlActionTest.java index da9f42678d..42fb5a70b9 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/yaml/AbstractYamlActionTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/yaml/AbstractYamlActionTest.java @@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -64,6 +65,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java deleted file mode 100644 index 760124479a..0000000000 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.util.TestUtils; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - private boolean normalizeLineEndings = false; - private boolean trim = false; - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { - logger.debug("Skip message payload validation as no control message was defined"); - return; - } - - logger.debug("Start text equals validation ..."); - - String controlPayload = controlMessage.getPayload(String.class); - String receivedPayload = receivedMessage.getPayload(String.class); - - if (trim) { - controlPayload = controlPayload.trim(); - receivedPayload = receivedPayload.trim(); - } - - if (normalizeLineEndings) { - controlPayload = TestUtils.normalizeLineEndings(controlPayload); - receivedPayload = TestUtils.normalizeLineEndings(receivedPayload); - } - - Assert.assertEquals(receivedPayload, controlPayload, "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - public TextEqualsMessageValidator normalizeLineEndings() { - this.normalizeLineEndings = true; - return this; - } - - public TextEqualsMessageValidator enableTrim() { - this.trim = true; - return this; - } -} diff --git a/runtime/citrus-groovy/src/test/resources/org/citrusframework/integration/groovy/sample.it.groovy b/runtime/citrus-groovy/src/test/resources/org/citrusframework/integration/groovy/sample.it.groovy index 6df7772f71..f70db72c21 100644 --- a/runtime/citrus-groovy/src/test/resources/org/citrusframework/integration/groovy/sample.it.groovy +++ b/runtime/citrus-groovy/src/test/resources/org/citrusframework/integration/groovy/sample.it.groovy @@ -19,11 +19,12 @@ package org.citrusframework.integration.groovy -import org.citrusframework.validation.TextEqualsMessageValidator +import org.citrusframework.validation.DefaultTextEqualsMessageValidator + configuration { beans { - bean(TextEqualsMessageValidator.class) + bean(DefaultTextEqualsMessageValidator.class) } queues { diff --git a/runtime/citrus-junit/src/test/java/org/citrusframework/junit/integration/validation/TextEqualsMessageValidator.java b/runtime/citrus-junit/src/test/java/org/citrusframework/junit/integration/validation/TextEqualsMessageValidator.java deleted file mode 100644 index f8e8b3b80e..0000000000 --- a/runtime/citrus-junit/src/test/java/org/citrusframework/junit/integration/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.citrusframework.junit.integration.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - Assert.assertEquals(receivedMessage.getPayload(String.class), controlMessage.getPayload(String.class), "Validation failed - " + - "expected message contents not equal!"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } -} diff --git a/runtime/citrus-junit/src/test/resources/org/citrusframework/junit/integration/sample.it.groovy b/runtime/citrus-junit/src/test/resources/org/citrusframework/junit/integration/sample.it.groovy index ff1338948a..01a6ee73a3 100644 --- a/runtime/citrus-junit/src/test/resources/org/citrusframework/junit/integration/sample.it.groovy +++ b/runtime/citrus-junit/src/test/resources/org/citrusframework/junit/integration/sample.it.groovy @@ -19,11 +19,12 @@ package org.citrusframework.junit.integration -import org.citrusframework.junit.integration.validation.TextEqualsMessageValidator + +import org.citrusframework.validation.DefaultTextEqualsMessageValidator configuration { beans { - bean(TextEqualsMessageValidator.class) + bean(DefaultTextEqualsMessageValidator.class) } queues { diff --git a/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/CitrusConfigurationIT.java b/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/CitrusConfigurationIT.java index e5ddbc4f83..5e06b1adf2 100644 --- a/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/CitrusConfigurationIT.java +++ b/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/CitrusConfigurationIT.java @@ -27,11 +27,11 @@ import org.citrusframework.endpoint.direct.DirectEndpoint; import org.citrusframework.endpoint.direct.DirectEndpointBuilder; import org.citrusframework.junit.jupiter.CitrusSupport; -import org.citrusframework.junit.jupiter.integration.validation.TextEqualsMessageValidator; import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageQueue; import org.citrusframework.message.MessageType; import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -102,8 +102,8 @@ public static class Endpoints { private final MessageQueue messages = new DefaultMessageQueue("messages"); @BindToRegistry - public TextEqualsMessageValidator plaintextValidator() { - return new TextEqualsMessageValidator(); + public DefaultTextEqualsMessageValidator plaintextValidator() { + return new DefaultTextEqualsMessageValidator(); } @BindToRegistry diff --git a/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/validation/TextEqualsMessageValidator.java b/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/validation/TextEqualsMessageValidator.java deleted file mode 100644 index 60aef5d8e0..0000000000 --- a/runtime/citrus-junit5/src/test/java/org/citrusframework/junit/jupiter/integration/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.citrusframework.junit.jupiter.integration.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - Assert.assertEquals(receivedMessage.getPayload(String.class), controlMessage.getPayload(String.class), "Validation failed - " + - "expected message contents not equal!"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } -} diff --git a/runtime/citrus-junit5/src/test/resources/org/citrusframework/junit/jupiter/integration/groovy/sample.it.groovy b/runtime/citrus-junit5/src/test/resources/org/citrusframework/junit/jupiter/integration/groovy/sample.it.groovy index 7f4850e601..735f0e7eda 100644 --- a/runtime/citrus-junit5/src/test/resources/org/citrusframework/junit/jupiter/integration/groovy/sample.it.groovy +++ b/runtime/citrus-junit5/src/test/resources/org/citrusframework/junit/jupiter/integration/groovy/sample.it.groovy @@ -19,11 +19,12 @@ package org.citrusframework.junit.jupiter.integration.groovy -import org.citrusframework.junit.jupiter.integration.validation.TextEqualsMessageValidator + +import org.citrusframework.validation.DefaultTextEqualsMessageValidator configuration { beans { - bean(TextEqualsMessageValidator.class) + bean(DefaultTextEqualsMessageValidator.class) } queues { diff --git a/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/DemoApplicationTest.java b/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/DemoApplicationTest.java index 7ffb5aa76e..e1323a02a6 100644 --- a/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/DemoApplicationTest.java +++ b/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/DemoApplicationTest.java @@ -32,8 +32,8 @@ import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageQueue; import org.citrusframework.quarkus.CitrusSupport; -import org.citrusframework.quarkus.app.validation.TextEqualsMessageValidator; import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.MessageValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -67,7 +67,7 @@ public class DemoApplicationTest { private TestCaseRunner t; @BindToRegistry - private final TextEqualsMessageValidator textEqualsMessageValidator = new TextEqualsMessageValidator(); + private final DefaultTextEqualsMessageValidator textEqualsMessageValidator = new DefaultTextEqualsMessageValidator(); @CitrusResource private TestContext context; diff --git a/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/validation/TextEqualsMessageValidator.java b/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/validation/TextEqualsMessageValidator.java deleted file mode 100644 index a8c1e1b226..0000000000 --- a/runtime/citrus-quarkus/citrus-quarkus-it/src/test/java/org/citrusframework/quarkus/app/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.quarkus.app.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.util.TestUtils; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - private boolean normalizeLineEndings = false; - private boolean trim = false; - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { - logger.debug("Skip message payload validation as no control message was defined"); - return; - } - - logger.debug("Start text equals validation ..."); - - String controlPayload = controlMessage.getPayload(String.class); - String receivedPayload = receivedMessage.getPayload(String.class); - - if (trim) { - controlPayload = controlPayload.trim(); - receivedPayload = receivedPayload.trim(); - } - - if (normalizeLineEndings) { - controlPayload = TestUtils.normalizeLineEndings(controlPayload); - receivedPayload = TestUtils.normalizeLineEndings(receivedPayload); - } - - Assert.assertEquals(receivedPayload, controlPayload, "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - public TextEqualsMessageValidator normalizeLineEndings() { - this.normalizeLineEndings = true; - return this; - } - - public TextEqualsMessageValidator enableTrim() { - this.trim = true; - return this; - } -} diff --git a/runtime/citrus-testng/src/test/java/org/citrusframework/TextEqualsMessageValidator.java b/runtime/citrus-testng/src/test/java/org/citrusframework/TextEqualsMessageValidator.java deleted file mode 100644 index 40d171390c..0000000000 --- a/runtime/citrus-testng/src/test/java/org/citrusframework/TextEqualsMessageValidator.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.citrusframework; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage.getPayload(String.class).isBlank()) { - logger.info("Skip text validation as no control message payload specified"); - return; - } - - Assert.assertEquals(receivedMessage.getPayload(String.class), controlMessage.getPayload(String.class), "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/runtime/citrus-testng/src/test/java/org/citrusframework/UnitTestSupport.java b/runtime/citrus-testng/src/test/java/org/citrusframework/UnitTestSupport.java index 85566b4bbe..3e29c2da5a 100644 --- a/runtime/citrus-testng/src/test/java/org/citrusframework/UnitTestSupport.java +++ b/runtime/citrus-testng/src/test/java/org/citrusframework/UnitTestSupport.java @@ -3,6 +3,7 @@ import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; import org.citrusframework.functions.DefaultFunctionLibrary; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.matcher.DefaultValidationMatcherLibrary; import org.testng.annotations.BeforeMethod; @@ -27,7 +28,7 @@ protected TestContextFactory createTestContextFactory() { TestContextFactory factory = TestContextFactory.newInstance(); factory.getFunctionRegistry().addFunctionLibrary(new DefaultFunctionLibrary()); factory.getValidationMatcherRegistry().addValidationMatcherLibrary(new DefaultValidationMatcherLibrary()); - factory.getMessageValidatorRegistry().addMessageValidator("all", new TextEqualsMessageValidator()); + factory.getMessageValidatorRegistry().addMessageValidator("all", new DefaultTextEqualsMessageValidator()); return factory; } } diff --git a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ParallelTestActionBuilderTest.java b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ParallelTestActionBuilderTest.java index 1b8ab6f95e..bbeec8b3c5 100644 --- a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ParallelTestActionBuilderTest.java +++ b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ParallelTestActionBuilderTest.java @@ -63,7 +63,8 @@ public void testParallelBuilderNestedContainer() { sequential() .actions( echo("1st in sequential"), - echo("2nd in sequential") + echo("2nd in sequential"), + sleep().milliseconds(200L) ), sleep().milliseconds(200), echo("Hello World!") diff --git a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageTestActionBuilderTest.java b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageTestActionBuilderTest.java index 3f6c55aa1b..f02361b590 100644 --- a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageTestActionBuilderTest.java +++ b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageTestActionBuilderTest.java @@ -24,7 +24,6 @@ import org.citrusframework.DefaultTestCaseRunner; import org.citrusframework.TestCase; -import org.citrusframework.TextEqualsMessageValidator; import org.citrusframework.UnitTestSupport; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.container.SequenceAfterTest; @@ -41,6 +40,7 @@ import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.spi.Resource; import org.citrusframework.validation.AbstractValidationProcessor; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.builder.StaticMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; @@ -168,6 +168,7 @@ public void testReceiveBuilderWithPayloadResource() throws IOException { new DefaultMessage("Hello World!") .setHeader("operation", "foo")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); builder.$(receive().endpoint(messageEndpoint) @@ -430,6 +431,7 @@ public void testReceiveBuilderWithHeaderResource() throws IOException { .setHeader("operation", "bar") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())); @@ -486,6 +488,7 @@ public void testReceiveBuilderWithMultipleHeaderResource() throws IOException { .addHeaderData("
operationfoo
") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) @@ -545,7 +548,7 @@ public void testReceiveBuilderWithValidator() { when(configuration.getTimeout()).thenReturn(100L); when(messageEndpoint.getActor()).thenReturn(null); when(messageConsumer.receive(any(TestContext.class), anyLong())).thenReturn(new DefaultMessage("TestMessage").setHeader("operation", "sayHello")); - final TextEqualsMessageValidator validator = new TextEqualsMessageValidator(); + final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); builder.$(receive().endpoint(messageEndpoint) @@ -575,7 +578,7 @@ public void testReceiveBuilderWithValidator() { @Test public void testReceiveBuilderWithValidatorName() { - final TextEqualsMessageValidator validator = new TextEqualsMessageValidator(); + final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); reset(referenceResolver, messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); diff --git a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/SendMessageTestActionBuilderTest.java b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/SendMessageTestActionBuilderTest.java index 75d0c56144..9dba2adf71 100644 --- a/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/SendMessageTestActionBuilderTest.java +++ b/runtime/citrus-testng/src/test/java/org/citrusframework/actions/dsl/SendMessageTestActionBuilderTest.java @@ -223,6 +223,7 @@ public void testSendBuilderWithPayloadResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); builder.$(send().endpoint(messageEndpoint) @@ -451,6 +452,7 @@ public void testSendBuilderWithHeaderDataResource() throws IOException { return null; }).when(messageProducer).send(any(Message.class), any(TestContext.class)); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo1
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo2
".getBytes())); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); diff --git a/runtime/citrus-testng/src/test/resources/citrus-context.xml b/runtime/citrus-testng/src/test/resources/citrus-context.xml index c54c839692..cdf54ae6e2 100644 --- a/runtime/citrus-testng/src/test/resources/citrus-context.xml +++ b/runtime/citrus-testng/src/test/resources/citrus-context.xml @@ -22,7 +22,7 @@ - + diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/integration/XmlTestLoaderIT.java b/runtime/citrus-xml/src/test/java/org/citrusframework/integration/XmlTestLoaderIT.java index f6dc41c4e0..6cfcb5e06e 100644 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/integration/XmlTestLoaderIT.java +++ b/runtime/citrus-xml/src/test/java/org/citrusframework/integration/XmlTestLoaderIT.java @@ -20,7 +20,7 @@ import org.citrusframework.common.TestLoader; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.testng.TestNGCitrusSupport; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.testng.annotations.Test; /** @@ -31,7 +31,7 @@ public class XmlTestLoaderIT extends TestNGCitrusSupport { @BindToRegistry - TextEqualsMessageValidator textEqualsMessageValidator = new TextEqualsMessageValidator(); + DefaultTextEqualsMessageValidator textEqualsMessageValidator = new DefaultTextEqualsMessageValidator(); @CitrusTestSource(type = TestLoader.XML, name = { "sample-test" }) public void XmlTestLoader_1_IT() {} diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java b/runtime/citrus-xml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java deleted file mode 100644 index 760124479a..0000000000 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.util.TestUtils; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - private boolean normalizeLineEndings = false; - private boolean trim = false; - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { - logger.debug("Skip message payload validation as no control message was defined"); - return; - } - - logger.debug("Start text equals validation ..."); - - String controlPayload = controlMessage.getPayload(String.class); - String receivedPayload = receivedMessage.getPayload(String.class); - - if (trim) { - controlPayload = controlPayload.trim(); - receivedPayload = receivedPayload.trim(); - } - - if (normalizeLineEndings) { - controlPayload = TestUtils.normalizeLineEndings(controlPayload); - receivedPayload = TestUtils.normalizeLineEndings(receivedPayload); - } - - Assert.assertEquals(receivedPayload, controlPayload, "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - public TextEqualsMessageValidator normalizeLineEndings() { - this.normalizeLineEndings = true; - return this; - } - - public TextEqualsMessageValidator enableTrim() { - this.trim = true; - return this; - } -} diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/AbstractXmlActionTest.java b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/AbstractXmlActionTest.java index 36548b44c9..118c580f01 100644 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/AbstractXmlActionTest.java +++ b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/AbstractXmlActionTest.java @@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -64,6 +65,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/ReceiveTest.java b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/ReceiveTest.java index 1b5313ad29..c6dc6a5a8c 100644 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/ReceiveTest.java +++ b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/ReceiveTest.java @@ -19,6 +19,8 @@ package org.citrusframework.xml.actions; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.ReceiveMessageAction; @@ -30,9 +32,9 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.FileUtils; import org.citrusframework.util.TestUtils; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.MessageValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -49,8 +51,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -72,7 +72,7 @@ public void shouldLoadReceive() throws IOException { XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/xml/actions/receive-test.xml"); MessageQueue helloQueue = new DefaultMessageQueue("helloQueue"); - context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new TextEqualsMessageValidator().enableTrim().normalizeLineEndings()); + context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings()); context.getReferenceResolver().bind("helloQueue", helloQueue); context.getReferenceResolver().bind("helloEndpoint", direct().asynchronous().queue(helloQueue).build()); diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/SendTest.java b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/SendTest.java index 52d4cb1896..9c378e5d17 100644 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/SendTest.java +++ b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/actions/SendTest.java @@ -19,6 +19,8 @@ package org.citrusframework.xml.actions; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.SendMessageAction; @@ -32,7 +34,7 @@ import org.citrusframework.util.FileUtils; import org.citrusframework.util.TestUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -44,8 +46,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -57,7 +57,7 @@ public class SendTest extends AbstractXmlActionTest { final DataDictionary myDataDictionary = Mockito.mock(DataDictionary.class); private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim().normalizeLineEndings(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings(); @Test public void shouldLoadSend() throws IOException { diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/integration/YamlTestLoaderIT.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/integration/YamlTestLoaderIT.java index 7674d89fa1..ff7a993727 100644 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/integration/YamlTestLoaderIT.java +++ b/runtime/citrus-yaml/src/test/java/org/citrusframework/integration/YamlTestLoaderIT.java @@ -20,7 +20,7 @@ import org.citrusframework.common.TestLoader; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.testng.TestNGCitrusSupport; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.testng.annotations.Test; /** @@ -31,7 +31,7 @@ public class YamlTestLoaderIT extends TestNGCitrusSupport { @BindToRegistry - TextEqualsMessageValidator textEqualsMessageValidator = new TextEqualsMessageValidator(); + DefaultTextEqualsMessageValidator textEqualsMessageValidator = new DefaultTextEqualsMessageValidator(); @CitrusTestSource(type = TestLoader.YAML, name = { "sample-test" }) public void YamlTestLoader_1_IT() {} diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java deleted file mode 100644 index 760124479a..0000000000 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/validation/TextEqualsMessageValidator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.util.TestUtils; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - private boolean normalizeLineEndings = false; - private boolean trim = false; - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage == null || controlMessage.getPayload() == null || controlMessage.getPayload(String.class).isEmpty()) { - logger.debug("Skip message payload validation as no control message was defined"); - return; - } - - logger.debug("Start text equals validation ..."); - - String controlPayload = controlMessage.getPayload(String.class); - String receivedPayload = receivedMessage.getPayload(String.class); - - if (trim) { - controlPayload = controlPayload.trim(); - receivedPayload = receivedPayload.trim(); - } - - if (normalizeLineEndings) { - controlPayload = TestUtils.normalizeLineEndings(controlPayload); - receivedPayload = TestUtils.normalizeLineEndings(receivedPayload); - } - - Assert.assertEquals(receivedPayload, controlPayload, "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - public TextEqualsMessageValidator normalizeLineEndings() { - this.normalizeLineEndings = true; - return this; - } - - public TextEqualsMessageValidator enableTrim() { - this.trim = true; - return this; - } -} diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/AbstractYamlActionTest.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/AbstractYamlActionTest.java index 4e47c58d25..246af99376 100644 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/AbstractYamlActionTest.java +++ b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/AbstractYamlActionTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @@ -62,6 +63,10 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); + doAnswer(invocationOnMock-> { + context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); + return null; + }).when(citrusContext).addComponent(anyString(), any()); CitrusAnnotations.injectAll(this, citrus, context); return context; } diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/ReceiveTest.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/ReceiveTest.java index a58c79bbe3..a008d521b4 100644 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/ReceiveTest.java +++ b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/ReceiveTest.java @@ -19,6 +19,8 @@ package org.citrusframework.yaml.actions; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.ReceiveMessageAction; @@ -29,9 +31,9 @@ import org.citrusframework.message.MessageType; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.FileUtils; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.MessageValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -48,8 +50,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -71,7 +71,7 @@ public void shouldLoadReceive() throws IOException { YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/yaml/actions/receive-test.yaml"); MessageQueue helloQueue = new DefaultMessageQueue("helloQueue"); - context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new TextEqualsMessageValidator().enableTrim().normalizeLineEndings()); + context.getMessageValidatorRegistry().addMessageValidator("textEqualsMessageValidator", new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings()); context.getReferenceResolver().bind("helloQueue", helloQueue); context.getReferenceResolver().bind("helloEndpoint", direct().asynchronous().queue(helloQueue).build()); diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/SendTest.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/SendTest.java index fba9655cd0..b0a58ed534 100644 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/SendTest.java +++ b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/actions/SendTest.java @@ -19,6 +19,8 @@ package org.citrusframework.yaml.actions; +import java.io.IOException; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.SendMessageAction; @@ -31,7 +33,7 @@ import org.citrusframework.spi.BindToRegistry; import org.citrusframework.util.FileUtils; import org.citrusframework.validation.DefaultMessageHeaderValidator; -import org.citrusframework.validation.TextEqualsMessageValidator; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.HeaderValidationContext; @@ -43,8 +45,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import java.io.IOException; - import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; /** @@ -56,7 +56,7 @@ public class SendTest extends AbstractYamlActionTest { final DataDictionary myDataDictionary = Mockito.mock(DataDictionary.class); private final DefaultMessageHeaderValidator headerValidator = new DefaultMessageHeaderValidator(); - private final TextEqualsMessageValidator validator = new TextEqualsMessageValidator().enableTrim().normalizeLineEndings(); + private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator().enableTrim().normalizeLineEndings(); @Test public void shouldLoadSend() throws IOException { diff --git a/src/manual/endpoint-http.adoc b/src/manual/endpoint-http.adoc index f1d49ad3ee..b938f510c3 100644 --- a/src/manual/endpoint-http.adoc +++ b/src/manual/endpoint-http.adoc @@ -1195,12 +1195,12 @@ the preferred way according to your test project requirements. [[http-client-basic-authentication]] == Http client basic authentication -As client you may have to use basic authentication in order to access a resource on the server. In most cases this will be -username/password authentication where the credentials are transmitted in the request header section as base64 encoding. +As a client you may have to authenticate properly in order to access a resource on the server. +In many cases this will be basic authentication with username/password where the credentials are transmitted in the request header section with base64 encoding. -The easiest approach to set the *Authorization* header for a basic authentication Http request would be to set it on your -own in the send action definition. Of course you have to use the correct basic authentication header syntax with base64 -encoding for the username:password phrase. See this simple example. +The easiest approach to set the *Authorization* header for a basic authentication Http request would be to explicitly set the header in the send action definition. +Of course, you have to use the correct basic authentication header syntax with base64 encoding for the username:password phrase. +See how it works in this simple example. .Java [source,java,indent=0,role="primary"] @@ -1224,14 +1224,46 @@ http().client("httpClient") ---- -Citrus will add this header to the Http requests and the server will read the *Authorization* username and password. For -more convenient base64 encoding you can also use a Citrus function, see link:#functions-encode-base64[functions-encode-base64] +Citrus will add this header to the Http requests and the server will read the *Authorization* username and password. +For more convenient base64 encoding you can also use a Citrus function `citrus:encodeBase64(username:password)`. +See link:#functions-encode-base64[functions-encode-base64] for more details. -Now there is a more comfortable way to set the basic authentication header in all the Citrus requests. As Citrus uses -Spring's REST support with the RestTemplate and ClientHttpRequestFactory the basic authentication is already covered there -in a more generic way. You simply have to configure the basic authentication credentials on the RestTemplate's ClientHttpRequestFactory. +Instead of adding the Http *Authorization* header manually you can also enable the basic authentication on the Http client endpoint. +Simply configure the basic authentication credentials on the Citrus Http client component. Just see the following example and learn how to do that. +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public HttpClient httpClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:8080/test") + .authentication(HttpAuthentication.basic("username", "password")) + .build(); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + + + +---- + +In case you need a more powerful configuration of the basic authentication you can also directly use the request factory as a configuration item for basic authentication. + .Java [source,java,indent=0,role="primary"] ---- @@ -1250,7 +1282,7 @@ public BasicAuthClientHttpRequestFactory basicAuthFactory() { AuthScope scope = new AuthScope("localhost", "8080", "", "basic"); factory.setAuthScope(scope); - UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("someUsername", "somePassword"); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("username", "password"); factory.setCredentials(credentials); return factory; @@ -1274,21 +1306,21 @@ public BasicAuthClientHttpRequestFactory basicAuthFactory() { - - + + ---- -The advantages of this method is obvious. Now all sending test actions that reference the client component will automatically -add the basic authentication header. +The advantage of setting the basic authentication on the Http client is obvious. +All test actions that reference the client component will automatically use the basic authentication. The above configuration results in Http client requests with authentication headers properly set for basic authentication. The client request factory takes care of adding the proper basic authentication header to each request that is sent with this Citrus message sender. Citrus uses preemptive authentication. The message sender only sends a single request to the server with all authentication information set in the message header. The request which determines the authentication scheme on the -server is skipped. This is why you have to add some auth scope in the client request factory so Citrus can setup an authentication +server is skipped. This is why you have to add some auth scope in the client request factory so Citrus can set up an authentication cache within the Http context in order to have preemptive authentication. As a result of the basic auth client request factory the following example request that is created by the Citrus Http client @@ -1313,7 +1345,41 @@ Content-Length: 175 [[http-server-basic-authentication]] == Http server basic authentication -Citrus as a server can also set basic authentication so clients need to authenticate properly when accessing server resources. +The Citrus Http server is able to configure basic authentication so clients need to authenticate properly when accessing server resources. + +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public HttpServer httpServer() { + return new HttpServerBuilder() + .port(8080) + .autoStart(true) + .authentication("/foo/*", HttpAuthentication.basic("username", "password")) + .build(); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + + + + +---- + +In case you need a more powerful server configuration you can also set the security handler directly. .Java [source,java,indent=0,role="primary"] @@ -1338,7 +1404,7 @@ public SecurityHandlerFactory securityHandler() { factory.setUsers(Collections.singletonList(user)); factory.setConstraints(Collections.singletonMap("/foo/*", - new BasicAuthConstraint("CitrusRole"))); + new BasicAuthConstraint("CitrusRole"))); return factory; } @@ -1385,6 +1451,121 @@ Just have a look at the code base and inspect the settings and properties offere TIP: This mechanism is not restricted to basic authentication only. With other settings you can also set up digest or form-based authentication constraints very easy. +[[http-client-ssl]] +== Http client SSL + +You can use SSL when establishing a client connection with the server. +The Citrus Http client supports a secure connection with these settings. + +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public HttpClient httpClient() { + return new HttpClientBuilder() + .requestUrl("https://localhost:8080/test") + .secured(HttpSecureConnection.ssl()) + .build(); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + +---- + +The example Http client uses SSL secure connection. +By default, the client will accept any server certificates and hostnames often referred to as trust-all-strategy. + +You may want to also use a proper trust store to explicitly accept server certificates. +The client by default allows self-signed certificates. + +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public HttpClient sslHttpClient() { + return new HttpClientBuilder() + .requestUrl("https://localhost:8080/test") + .secured(HttpSecureConnection.ssl() + .trustStore("path/to/server.jks", "trustStorePassword")) + .build(); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + + + +---- + +You need to provide a key store file (.jks) and a password to access the certificates located in the store. +The client now will do proper SSL handshake with the server in order to use secure connections. + +[[http-server-ssl]] +== Http server SSL + +The Citrus Http server is able to configure a SSL connector so clients need to use secure connections to access the server resources. +The connector + +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public HttpServer sslHttpServer() { + return new HttpServerBuilder() + .port(8080) + .autoStart(true) + .secured(8443, HttpSecureConnection.ssl() + .keyStore("path/to/server.jks", "keyStorePassword")) + .build(); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + + + + +---- + +The server now uses a `securePort` and a server certificate. +In most cases the certificate in a test environment is self-signed so please make sure to allow self-signed certificates in your clients. + [[http-cookies]] == Http cookies diff --git a/src/manual/overview.adoc b/src/manual/overview.adoc index 074db1d542..fb2310e8ad 100644 --- a/src/manual/overview.adoc +++ b/src/manual/overview.adoc @@ -15,6 +15,8 @@ hesitate to contact us. Find below the reference documentation for the latest Ci |Latest |link:/citrus/reference/html/index.html[HTML] |link:/citrus/reference/pdf/citrus-reference.pdf[PDF] |4.1.0-SNAPSHOT |link:/citrus/reference/4.1.0-SNAPSHOT/html/index.html[HTML] |link:/citrus/reference/4.1.0-SNAPSHOT/pdf/citrus-reference-4.1.0-SNAPSHOT.pdf[PDF] +|4.0.2 |link:/citrus/reference/4.0.2/html/index.html[HTML] |link:/citrus/reference/4.0.2/pdf/citrus-reference-4.0.2.pdf[PDF] +|4.0.1 |link:/citrus/reference/4.0.1/html/index.html[HTML] |link:/citrus/reference/4.0.1/pdf/citrus-reference-4.0.1.pdf[PDF] |4.0.0 |link:/citrus/reference/4.0.0/html/index.html[HTML] |link:/citrus/reference/4.0.0/pdf/citrus-reference-4.0.0.pdf[PDF] |3.4.0 |link:/citrus/reference/3.4.0/html/index.html[HTML] |link:/citrus/reference/3.4.0/pdf/citrus-reference-3.4.0.pdf[PDF] |3.3.1 |link:/citrus/reference/3.3.1/html/index.html[HTML] |link:/citrus/reference/3.3.1/pdf/citrus-reference-3.3.1.pdf[PDF] diff --git a/tools/jbang/dist/CitrusJBang.java b/tools/jbang/dist/CitrusJBang.java index 8ab141618f..524efc5d99 100755 --- a/tools/jbang/dist/CitrusJBang.java +++ b/tools/jbang/dist/CitrusJBang.java @@ -19,13 +19,13 @@ //JAVA 17+ //REPOS mavencentral -//DEPS org.citrusframework:citrus:${citrus.jbang.version:4.1.0-SNAPSHOT}@pom -//DEPS org.citrusframework:citrus-base:${citrus.jbang.version:4.1.0-SNAPSHOT} -//DEPS org.citrusframework:citrus-main:${citrus.jbang.version:4.1.0-SNAPSHOT} -//DEPS org.citrusframework:citrus-jbang:${citrus.jbang.version:4.1.0-SNAPSHOT} -//DEPS org.citrusframework:citrus-groovy:${citrus.jbang.version:4.1.0-SNAPSHOT} -//DEPS org.citrusframework:citrus-xml:${citrus.jbang.version:4.1.0-SNAPSHOT} -//DEPS org.citrusframework:citrus-yaml:${citrus.jbang.version:4.1.0-SNAPSHOT} +//DEPS org.citrusframework:citrus:${citrus.jbang.version:4.0.2}@pom +//DEPS org.citrusframework:citrus-base:${citrus.jbang.version:4.0.2} +//DEPS org.citrusframework:citrus-main:${citrus.jbang.version:4.0.2} +//DEPS org.citrusframework:citrus-jbang:${citrus.jbang.version:4.0.2} +//DEPS org.citrusframework:citrus-groovy:${citrus.jbang.version:4.0.2} +//DEPS org.citrusframework:citrus-xml:${citrus.jbang.version:4.0.2} +//DEPS org.citrusframework:citrus-yaml:${citrus.jbang.version:4.0.2} package main; import org.citrusframework.jbang.CitrusJBangMain; diff --git a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/CitrusCommand.java b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/CitrusCommand.java index 28d5683550..e94830e178 100644 --- a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/CitrusCommand.java +++ b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/CitrusCommand.java @@ -33,7 +33,7 @@ public abstract class CitrusCommand implements Callable { CommandSpec spec; private final CitrusJBangMain main; - private File citrusDir; + private File userDir; //CHECKSTYLE:OFF @CommandLine.Option(names = { "-h", "--help" }, usageHelp = true, description = "Display the help and sub-commands") @@ -49,17 +49,19 @@ public CitrusJBangMain getMain() { } public File getStatusFile(String pid) { - if (citrusDir == null) { - citrusDir = new File(System.getProperty("user.home"), ".citrus"); - } - return new File(citrusDir, pid + "-status.json"); + return new File(getUserDir(), pid + "-status.json"); } public File getOutputFile(String pid) { - if (citrusDir == null) { - citrusDir = new File(System.getProperty("user.home"), ".citrus"); + return new File(getUserDir(), pid + "-output.json"); + } + + protected File getUserDir() { + if (userDir == null) { + userDir = new File(System.getProperty("user.home"), ".citrus"); } - return new File(citrusDir, pid + "-output.json"); + + return userDir; } protected abstract static class ParameterConsumer implements IParameterConsumer { diff --git a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/ListTests.java b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/ListTests.java index c27728b4b8..1b13cc2a43 100644 --- a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/ListTests.java +++ b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/ListTests.java @@ -16,22 +16,16 @@ */ package org.citrusframework.jbang.commands; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.citrusframework.util.FileUtils; -import com.fasterxml.jackson.databind.JsonNode; import com.github.freva.asciitable.AsciiTable; import com.github.freva.asciitable.Column; import com.github.freva.asciitable.HorizontalAlign; import com.github.freva.asciitable.OverflowBehaviour; import main.CitrusJBang; -import org.citrusframework.jbang.JsonSupport; import org.citrusframework.jbang.CitrusJBangMain; import picocli.CommandLine; import picocli.CommandLine.Command; @@ -58,16 +52,15 @@ public Integer call() throws Exception { final long cur = ProcessHandle.current().pid(); ProcessHandle.allProcesses() .filter(ph -> ph.pid() != cur) + .filter(ph -> isTestProcess(ph.info())) .forEach(ph -> { - if (ph.info().commandLine().orElse("").contains(CitrusJBang.class.getSimpleName())) { - Row row = new Row(); - row.pid = "" + ph.pid(); - row.uptime = extractSince(ph); - row.ago = printSince(row.uptime); - row.name = extractName(ph); - row.status = ph.isAlive() ? "Running" : "Finished"; - rows.add(row); - } + Row row = new Row(); + row.pid = "" + ph.pid(); + row.uptime = extractSince(ph); + row.ago = printSince(row.uptime); + row.name = extractName(ph); + row.status = ph.isAlive() ? "Running" : "Finished"; + rows.add(row); }); // sort rows @@ -88,9 +81,13 @@ public Integer call() throws Exception { return 0; } + protected boolean isTestProcess(ProcessHandle.Info info) { + return info.commandLine().orElse("").contains(CitrusJBang.class.getSimpleName()); + } + private String extractName(ProcessHandle ph) { String cl = ph.info().commandLine().orElse(""); - String citrusJBangRun = String.format("main.%s run ", CitrusJBang.class.getSimpleName()); + String citrusJBangRun = getJBangRunCommand(); if (cl.contains(citrusJBangRun)) { return cl.substring(cl.indexOf(citrusJBangRun) + citrusJBangRun.length()); } @@ -98,6 +95,10 @@ private String extractName(ProcessHandle ph) { return ""; } + protected String getJBangRunCommand() { + return String.format("main.%s run ", CitrusJBang.class.getSimpleName()); + } + private String printSince(long timestamp) { long age = System.currentTimeMillis() - timestamp; Duration duration = Duration.ofMillis(age); @@ -138,22 +139,7 @@ protected int sortRow(Row o1, Row o2) { } } - private JsonNode loadStatus(long pid) { - try { - File f = getStatusFile("" + pid); - if (f != null && f.exists()) { - try (FileInputStream fis = new FileInputStream(f)) { - String text = FileUtils.readToString(fis); - return JsonSupport.json().reader().readTree(text); - } - } - } catch (IOException e) { - // ignore - } - return null; - } - - static long extractSince(ProcessHandle ph) { + protected static long extractSince(ProcessHandle ph) { long since = 0; if (ph.info().startInstant().isPresent()) { since = ph.info().startInstant().get().toEpochMilli(); @@ -161,7 +147,7 @@ static long extractSince(ProcessHandle ph) { return since; } - private static class Row { + protected static class Row { String pid; String name; String status; diff --git a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/Run.java b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/Run.java index d8a9941d4d..519cbaf358 100644 --- a/tools/jbang/src/main/java/org/citrusframework/jbang/commands/Run.java +++ b/tools/jbang/src/main/java/org/citrusframework/jbang/commands/Run.java @@ -147,7 +147,7 @@ private int run() throws Exception { return exitStatus.exitStatus(); } - private TestRunConfiguration getRunConfiguration(List files) { + protected TestRunConfiguration getRunConfiguration(List files) { TestRunConfiguration configuration = new TestRunConfiguration(); String ext = FileUtils.getFileExtension(files.get(0)); diff --git a/tools/restdocs/src/main/resources/META-INF/spring.schemas b/tools/restdocs/src/main/resources/META-INF/spring.schemas index 02dac19084..452130fce0 100644 --- a/tools/restdocs/src/main/resources/META-INF/spring.schemas +++ b/tools/restdocs/src/main/resources/META-INF/spring.schemas @@ -25,8 +25,8 @@ http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-3. http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-3.4.0.xsd=com/consol/citrus/schema/citrus-restdocs-config-3.4.0.xsd http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.0.0-M1.xsd=org/citrusframework/schema/citrus-restdocs-config-4.0.0-M1.xsd http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.0.0-M2.xsd=org/citrusframework/schema/citrus-restdocs-config-4.0.0-M2.xsd -http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.1.0-SNAPSHOT-M1.xsd=org/citrusframework/schema/citrus-restdocs-config-4.1.0-SNAPSHOT-M1.xsd -http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.1.0-SNAPSHOT-M2.xsd=org/citrusframework/schema/citrus-restdocs-config-4.1.0-SNAPSHOT-M2.xsd -http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-restdocs-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.0.0.xsd=org/citrusframework/schema/citrus-restdocs-config-4.0.0.xsd +http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.0.1.xsd=org/citrusframework/schema/citrus-restdocs-config-4.0.1.xsd +http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.0.2.xsd=org/citrusframework/schema/citrus-restdocs-config-4.0.2.xsd +http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config-4.1.0-SNAPSHOT.xsd=org/citrusframework/schema/citrus-restdocs-config-4.1.0-SNAPSHOT.xsd http\://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config.xsd=org/citrusframework/schema/citrus-restdocs-config.xsd diff --git a/validation/citrus-validation-groovy/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLQueryTestActionBuilderTest.java b/validation/citrus-validation-groovy/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLQueryTestActionBuilderTest.java index ecad39db86..a9671cfd1f 100644 --- a/validation/citrus-validation-groovy/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLQueryTestActionBuilderTest.java +++ b/validation/citrus-validation-groovy/src/test/java/org/citrusframework/actions/dsl/ExecuteSQLQueryTestActionBuilderTest.java @@ -92,6 +92,7 @@ public void testValidationScriptResource() throws IOException { results.add(Collections.singletonMap("NAME", "Radj")); reset(jdbcTemplate, resource); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("assert rows[0].NAME == 'Radj'".getBytes())); when(jdbcTemplate.queryForList("SELECT NAME FROM ACTORS")).thenReturn(results); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); @@ -155,6 +156,7 @@ public void testGroovyValidationScriptResource() throws IOException { results.add(Collections.singletonMap("NAME", "Sheldon")); reset(jdbcTemplate, resource); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("assert rows[1].NAME == 'Howard'".getBytes())); when(jdbcTemplate.queryForList("SELECT NAME FROM ACTORS")).thenReturn(results); DefaultTestCaseRunner builder = new DefaultTestCaseRunner(context); diff --git a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/TextEqualsMessageValidator.java b/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/TextEqualsMessageValidator.java deleted file mode 100644 index 40d171390c..0000000000 --- a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/TextEqualsMessageValidator.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.citrusframework; - -import org.citrusframework.context.TestContext; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - private static final Logger logger = LoggerFactory.getLogger(TextEqualsMessageValidator.class); - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (controlMessage.getPayload(String.class).isBlank()) { - logger.info("Skip text validation as no control message payload specified"); - return; - } - - Assert.assertEquals(receivedMessage.getPayload(String.class), controlMessage.getPayload(String.class), "Validation failed - " + - "expected message contents not equal!"); - - logger.info("Text validation successful: All values OK"); - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/UnitTestSupport.java b/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/UnitTestSupport.java index 85566b4bbe..3e29c2da5a 100644 --- a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/UnitTestSupport.java +++ b/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/UnitTestSupport.java @@ -3,6 +3,7 @@ import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; import org.citrusframework.functions.DefaultFunctionLibrary; +import org.citrusframework.validation.DefaultTextEqualsMessageValidator; import org.citrusframework.validation.matcher.DefaultValidationMatcherLibrary; import org.testng.annotations.BeforeMethod; @@ -27,7 +28,7 @@ protected TestContextFactory createTestContextFactory() { TestContextFactory factory = TestContextFactory.newInstance(); factory.getFunctionRegistry().addFunctionLibrary(new DefaultFunctionLibrary()); factory.getValidationMatcherRegistry().addValidationMatcherLibrary(new DefaultValidationMatcherLibrary()); - factory.getMessageValidatorRegistry().addMessageValidator("all", new TextEqualsMessageValidator()); + factory.getMessageValidatorRegistry().addMessageValidator("all", new DefaultTextEqualsMessageValidator()); return factory; } } diff --git a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/integration/TextEqualsMessageValidator.java b/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/integration/TextEqualsMessageValidator.java deleted file mode 100644 index 063b73bb89..0000000000 --- a/validation/citrus-validation-hamcrest/src/test/java/org/citrusframework/integration/TextEqualsMessageValidator.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.citrusframework.integration; - -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.ValidationException; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; -import org.citrusframework.validation.DefaultMessageValidator; -import org.citrusframework.validation.context.ValidationContext; - -/** - * Basic message validator performs String equals on received message payloads. We add this validator in order to have a - * matching message validation strategy for integration tests in this module. - * @author Christoph Deppisch - */ -public class TextEqualsMessageValidator extends DefaultMessageValidator { - - @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, ValidationContext validationContext) { - if (!receivedMessage.getPayload(String.class).equals(controlMessage.getPayload(String.class))) { - throw new ValidationException("Validation failed - expected message contents not equal!"); - } - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return messageType.equalsIgnoreCase(MessageType.PLAINTEXT.toString()); - } -} diff --git a/validation/citrus-validation-hamcrest/src/test/resources/citrus-context.xml b/validation/citrus-validation-hamcrest/src/test/resources/citrus-context.xml index 7013d4d4d8..64a798f47f 100644 --- a/validation/citrus-validation-hamcrest/src/test/resources/citrus-context.xml +++ b/validation/citrus-validation-hamcrest/src/test/resources/citrus-context.xml @@ -11,6 +11,6 @@ - + diff --git a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java index 3f020e769c..e778e5c5ad 100644 --- a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java +++ b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java @@ -203,7 +203,7 @@ public void validateJson(String elementName, JSONObject receivedJson, JSONObject for (int i = 0; i < jsonArrayControl.size(); i++) { if (jsonArrayControl.get(i).getClass().isAssignableFrom(JSONObject.class)) { if (!jsonArrayReceived.get(i).getClass().isAssignableFrom(JSONObject.class)) { - throw new ValidationException(ValidationUtils.buildValueMismatchErrorMessage("Value types not equal for entry: '" + jsonArrayControl.get(i) + "'", + throw new ValidationException(ValidationUtils.buildValueMismatchErrorMessage("Value types not equal for entry: '" + controlKey + "'", JSONObject.class.getName(), jsonArrayReceived.get(i).getClass().getName())); } @@ -211,7 +211,7 @@ public void validateJson(String elementName, JSONObject receivedJson, JSONObject (JSONObject) jsonArrayControl.get(i), validationContext, context, readContext); } else { if (!jsonArrayControl.get(i).equals(jsonArrayReceived.get(i))) { - throw new ValidationException(ValidationUtils.buildValueMismatchErrorMessage("Values not equal for entry: '" + jsonArrayControl.get(i) + "'", + throw new ValidationException(ValidationUtils.buildValueMismatchErrorMessage("Values not equal for entry: '" + controlKey + "'", jsonArrayControl.get(i), jsonArrayReceived.get(i))); } } diff --git a/validation/citrus-validation-json/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java b/validation/citrus-validation-json/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java index 8605ccea17..dbbfd510d1 100644 --- a/validation/citrus-validation-json/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java +++ b/validation/citrus-validation-json/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java @@ -342,6 +342,7 @@ public void testReceiveBuilderWithHeaderResource() throws IOException { .setHeader("operation", "bar") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())); @@ -398,6 +399,7 @@ public void testReceiveBuilderWithMultipleHeaderResource() throws IOException { .addHeaderData("
operationfoo
") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/functions/core/EscapeXmlFunction.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/functions/core/EscapeXmlFunction.java index e9e9e814e3..0767ee0194 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/functions/core/EscapeXmlFunction.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/functions/core/EscapeXmlFunction.java @@ -16,12 +16,13 @@ package org.citrusframework.functions.core; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; -import org.apache.commons.lang.StringEscapeUtils; + +import java.util.List; + +import static org.apache.commons.lang3.StringEscapeUtils.escapeXml; /** * Escapes XML fragment with escaped characters for '<', '>'. @@ -36,7 +37,7 @@ public String execute(List parameterList, TestContext context) { throw new InvalidFunctionUsageException("Invalid function parameter usage! Expected single parameter but found: " + parameterList.size()); } - return StringEscapeUtils.escapeXml(parameterList.get(0)); + return escapeXml(parameterList.get(0)); } } diff --git a/validation/citrus-validation-xml/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java b/validation/citrus-validation-xml/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java index b9f0644ce2..1f6f40961c 100644 --- a/validation/citrus-validation-xml/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java +++ b/validation/citrus-validation-xml/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java @@ -321,6 +321,7 @@ public void testReceiveBuilderWithPayloadResource() throws IOException { new DefaultMessage("Hello World!") .setHeader("operation", "foo")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World!".getBytes())); DefaultTestCaseRunner runner = new DefaultTestCaseRunner(context); runner.run(receive(messageEndpoint) @@ -710,6 +711,7 @@ public void testReceiveBuilderWithHeaderResource() throws IOException { .setHeader("operation", "bar") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())); @@ -766,6 +768,7 @@ public void testReceiveBuilderWithMultipleHeaderResource() throws IOException { .addHeaderData("
operationfoo
") .addHeaderData("
operationbar
")); + when(resource.exists()).thenReturn(true); when(resource.getInputStream()).thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationbar
".getBytes())) .thenReturn(new ByteArrayInputStream("
operationfoo
".getBytes()))