diff --git a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesActor.java b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesActor.java index 2081142387..1044b4ca2d 100644 --- a/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesActor.java +++ b/connectors/citrus-kubernetes/src/main/java/org/citrusframework/kubernetes/KubernetesActor.java @@ -38,40 +38,48 @@ public class KubernetesActor extends TestActor { /** Kubernetes' connection state, checks connectivity to Kubernetes cluster */ private static AtomicBoolean connected; - private final KubernetesClient kubernetesClient; - public KubernetesActor(KubernetesClient kubernetesClient) { - setName("k8s"); + super("k8s"); - if (kubernetesClient != null) { - this.kubernetesClient = kubernetesClient; - } else { - this.kubernetesClient = new KubernetesClientBuilder().build(); + synchronized (logger) { + if (connected == null) { + if (kubernetesClient != null) { + connected = new AtomicBoolean(verifyConnected(kubernetesClient)); + } else { + try (KubernetesClient tempClient = new KubernetesClientBuilder().build()) { + connected = new AtomicBoolean(verifyConnected(tempClient)); + } + } + } } } @Override public boolean isDisabled() { - synchronized (logger) { - if (connected == null) { - if (KubernetesSettings.isEnabled()) { - try { - Future future = Executors.newSingleThreadExecutor().submit(() -> { - kubernetesClient.pods().list(); - return true; - }); + if (!KubernetesSettings.isEnabled()) { + return true; + } - connected = new AtomicBoolean((future.get(KubernetesSettings.getConnectTimeout(), TimeUnit.MILLISECONDS))); - } catch (Exception e) { - logger.warn("Skipping Kubernetes action as no proper Kubernetes environment is available on host system!", e); - connected = new AtomicBoolean(false); - } - } else { - return false; - } - } + return !connected.get() || super.isDisabled(); + } - return !connected.get(); + public static boolean verifyConnected(KubernetesClient kubernetesClient) { + try { + Future future = Executors.newSingleThreadExecutor().submit(() -> { + kubernetesClient.pods().list(); + return true; + }); + + return future.get(KubernetesSettings.getConnectTimeout(), TimeUnit.MILLISECONDS); + } catch (Exception e) { + logger.warn("Skipping Kubernetes action as no proper Kubernetes environment is available on host system!", e); + return false; + } + } + + public static void resetConnectionState() { + synchronized (logger) { + connected = null; } } } diff --git a/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/KubernetesActorTest.java b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/KubernetesActorTest.java new file mode 100644 index 0000000000..efa7474318 --- /dev/null +++ b/connectors/citrus-kubernetes/src/test/java/org/citrusframework/kubernetes/KubernetesActorTest.java @@ -0,0 +1,84 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.kubernetes; + +import java.util.HashMap; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesCrudDispatcher; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.mockwebserver.Context; +import okhttp3.mockwebserver.MockWebServer; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class KubernetesActorTest { + + private final KubernetesMockServer k8sServer = new KubernetesMockServer(new Context(), new MockWebServer(), + new HashMap<>(), new KubernetesCrudDispatcher(), false); + + KubernetesClient k8sClient; + + @BeforeClass + public void setupMocks() { + k8sServer.init(); + k8sClient = k8sServer.createClient(); + } + + @AfterClass(alwaysRun = true) + public void stop() { + k8sServer.destroy(); + } + + @Test + public void shouldVerifyConnectedState() { + try { + Assert.assertFalse(new KubernetesActor(k8sClient).isDisabled()); + } finally { + KubernetesActor.resetConnectionState(); + } + + try { + KubernetesClient k8sClientMock = Mockito.mock(KubernetesClient.class); + Assert.assertTrue(new KubernetesActor(k8sClientMock).isDisabled()); + } finally { + KubernetesActor.resetConnectionState(); + } + } + + @Test + public void shouldOverruleConnectedState() { + boolean initial = KubernetesSettings.isEnabled(); + try { + System.setProperty("citrus.kubernetes.enabled", "false"); + Assert.assertTrue(new KubernetesActor(k8sClient).isDisabled()); + } finally { + System.setProperty("citrus.kubernetes.enabled", Boolean.toString(initial)); + } + + initial = Boolean.parseBoolean(System.getProperty("citrus.test.actor.k8s.enabled", "true")); + try { + System.setProperty("citrus.test.actor.k8s.enabled", "false"); + Assert.assertTrue(new KubernetesActor(k8sClient).isDisabled()); + } finally { + System.setProperty("citrus.test.actor.k8s.enabled", Boolean.toString(initial)); + } + } +} diff --git a/connectors/citrus-testcontainers/src/main/java/org/citrusframework/testcontainers/TestcontainersActor.java b/connectors/citrus-testcontainers/src/main/java/org/citrusframework/testcontainers/TestcontainersActor.java index 082eb3034f..8dfa773383 100644 --- a/connectors/citrus-testcontainers/src/main/java/org/citrusframework/testcontainers/TestcontainersActor.java +++ b/connectors/citrus-testcontainers/src/main/java/org/citrusframework/testcontainers/TestcontainersActor.java @@ -41,47 +41,54 @@ public class TestcontainersActor extends TestActor { /** Docker's connection state, checks connectivity to Docker engine */ private static AtomicBoolean connected; - private final DockerClient dockerClient; - public TestcontainersActor() { this(null); } public TestcontainersActor(DockerClient dockerClient) { - setName("testcontainers"); + super("testcontainers"); - if (dockerClient != null) { - this.dockerClient = dockerClient; - } else { - DockerClientConfig clientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); - this.dockerClient = DockerClientImpl.getInstance(clientConfig, - new OkDockerHttpClient.Builder().dockerHost(clientConfig.getDockerHost()).build() - ); + synchronized (logger) { + if (connected == null) { + if (dockerClient != null) { + connected = new AtomicBoolean(verifyConnected(dockerClient)); + } else { + DockerClientConfig clientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); + DockerClient tempClient = DockerClientImpl.getInstance(clientConfig, + new OkDockerHttpClient.Builder().dockerHost(clientConfig.getDockerHost()).build() + ); + connected = new AtomicBoolean(verifyConnected(tempClient)); + } + } } } @Override public boolean isDisabled() { - synchronized (logger) { - if (connected == null) { - if (TestContainersSettings.isEnabled()) { - try { - Future future = Executors.newSingleThreadExecutor().submit(() -> { - dockerClient.pingCmd().exec(); - return true; - }); + if (!TestContainersSettings.isEnabled()) { + return true; + } - connected = new AtomicBoolean((future.get(TestContainersSettings.getConnectTimeout(), TimeUnit.MILLISECONDS))); - } catch (Exception e) { - logger.warn("Skipping Docker test execution as no proper Docker environment is available on host system!", e); - connected = new AtomicBoolean(false); - } - } else { - return false; - } - } + return !connected.get() || super.isDisabled(); + } + + public static boolean verifyConnected(DockerClient dockerClient) { + try { + Future future = Executors.newSingleThreadExecutor().submit(() -> { + dockerClient.pingCmd().exec(); + return true; + }); - return !connected.get(); + return (future.get(TestContainersSettings.getConnectTimeout(), TimeUnit.MILLISECONDS)); + } catch (Exception e) { + logger.warn("Skipping Docker test execution as no proper Docker environment is available on host system!", e); + return false; + } + } + + public static void resetConnectionState() { + synchronized (logger) { + connected = null; } } } diff --git a/connectors/citrus-testcontainers/src/test/java/org/citrusframework/testcontainers/TestcontainersActorTest.java b/connectors/citrus-testcontainers/src/test/java/org/citrusframework/testcontainers/TestcontainersActorTest.java new file mode 100644 index 0000000000..323b45d9ff --- /dev/null +++ b/connectors/citrus-testcontainers/src/test/java/org/citrusframework/testcontainers/TestcontainersActorTest.java @@ -0,0 +1,92 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.testcontainers; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.PingCmd; +import org.citrusframework.kubernetes.KubernetesSettings; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +public class TestcontainersActorTest { + + @Mock + DockerClient dockerClient; + + @Mock + PingCmd connected; + + @Mock + PingCmd disconnected; + + @BeforeClass + public void setupMocks() { + MockitoAnnotations.openMocks(this); + + doNothing().when(connected).exec(); + doThrow(IllegalStateException.class).when(disconnected).exec(); + } + + @Test + public void shouldVerifyConnectedState() { + try { + when(dockerClient.pingCmd()).thenReturn(connected); + Assert.assertFalse(new TestcontainersActor(dockerClient).isDisabled()); + } finally { + TestcontainersActor.resetConnectionState(); + reset(dockerClient); + } + + try { + when(dockerClient.pingCmd()).thenReturn(disconnected); + Assert.assertTrue(new TestcontainersActor(dockerClient).isDisabled()); + } finally { + TestcontainersActor.resetConnectionState(); + reset(dockerClient); + } + } + + @Test + public void shouldOverruleConnectedState() { + boolean initial = KubernetesSettings.isEnabled(); + try { + System.setProperty("citrus.testcontainers.enabled", "false"); + when(dockerClient.pingCmd()).thenReturn(connected); + Assert.assertTrue(new TestcontainersActor(dockerClient).isDisabled()); + } finally { + System.setProperty("citrus.testcontainers.enabled", Boolean.toString(initial)); + reset(dockerClient); + } + + initial = Boolean.parseBoolean(System.getProperty("citrus.test.actor.testcontainers.enabled", "true")); + try { + System.setProperty("citrus.test.actor.testcontainers.enabled", "false"); + when(dockerClient.pingCmd()).thenReturn(connected); + Assert.assertTrue(new TestcontainersActor(dockerClient).isDisabled()); + } finally { + System.setProperty("citrus.test.actor.testcontainers.enabled", Boolean.toString(initial)); + } + } +} diff --git a/core/citrus-api/src/main/java/org/citrusframework/TestActor.java b/core/citrus-api/src/main/java/org/citrusframework/TestActor.java index 56e6429edf..a1c05c6532 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/TestActor.java +++ b/core/citrus-api/src/main/java/org/citrusframework/TestActor.java @@ -16,6 +16,8 @@ package org.citrusframework; +import java.util.Optional; + /** * Actor performs send/receive message actions. With send/receive actors we can enable/disable Citrus message simulation * very easily. This enables a fast switch in end-to-end testing when a simulated application suddenly is real and we have to disable @@ -24,15 +26,31 @@ * @since 1.3 */ public class TestActor { - /** The name of this actor*/ + + private static final String TEST_ACTOR_ENABLED_PROPERTY = "citrus.test.actor.%s.enabled"; + private static final String TEST_ACTOR_ENABLED_ENV = "CITRUS_TEST_ACTOR_%s_ENABLED"; + + /** The name of this actor */ private String name; /** Marks if this test actor should not participate in tests */ private boolean disabled = false; + public TestActor() { + } + + public TestActor(String name) { + this.name = name; + } + + public TestActor(String name, boolean disabled) { + this.name = name; + this.disabled = disabled; + } + /** * Gets the name. - * @return the name the name to get. + * @return the name to get. */ public String getName() { return name; @@ -48,10 +66,17 @@ public void setName(String name) { /** * Gets the disabled. - * @return the disabled the disabled to get. + * @return the disabled to get. */ public boolean isDisabled() { - return disabled; + boolean enabled = true; + if (name != null && !name.isBlank()) { + // Check enabled state in System properties or environment variables for this test actor using its name + enabled = Boolean.parseBoolean(System.getProperty(TEST_ACTOR_ENABLED_PROPERTY.formatted(name.trim().toLowerCase()), + Optional.ofNullable(System.getenv(TEST_ACTOR_ENABLED_ENV.formatted(name.trim().toUpperCase()))).orElse("true"))); + } + + return !enabled || disabled; } /** diff --git a/core/citrus-api/src/test/java/org/citrusframework/TestActorTest.java b/core/citrus-api/src/test/java/org/citrusframework/TestActorTest.java new file mode 100644 index 0000000000..0c4c8dd445 --- /dev/null +++ b/core/citrus-api/src/test/java/org/citrusframework/TestActorTest.java @@ -0,0 +1,40 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class TestActorTest { + + @Test + public void shouldBeEnabledByDefault() { + Assert.assertFalse(new TestActor().isDisabled()); + Assert.assertFalse(new TestActor("foo").isDisabled()); + Assert.assertTrue(new TestActor("foo", true).isDisabled()); + + Assert.assertTrue(new TestActor("foo", true).isDisabled()); + } + + @Test + public void shouldDisableViaSystemProperty() { + System.setProperty("citrus.test.actor.foo.enabled", "false"); + Assert.assertTrue(new TestActor("foo").isDisabled()); + Assert.assertFalse(new TestActor("bar").isDisabled()); + } + +} diff --git a/src/manual/test-actors.adoc b/src/manual/test-actors.adoc index 59a52ad89c..edaf25ed06 100644 --- a/src/manual/test-actors.adoc +++ b/src/manual/test-actors.adoc @@ -1,67 +1,304 @@ [[test-actors]] = Test actors -The concept of test actors came to our mind when reusing Citrus test cases in end-to-end test scenarios. Usually Citrus simulates all interface partners within a test case which is great for continuous integration testing. In end-to-end integration test scenarios some of our interface partners may be real and alive. Some other interface partners still require Citrus simulation logic. +The concept of test actors is a way to enable/disable a group of tests actions and message endpoints based on configuration. +Test actors help you to use the same tests in different environments where some of the participating services may be available or need to be simulated by Citrus. +In particular in end-to-end test scenarios some interface partners may be deployed and ready for participating in the test. +In other environments no interface partners are available and Citrus needs to simulate all interfaces accordingly. +Test actors allows us to use the very same test definition in both environments by just adjusting the Citrus configuration. -It would be great if we could reuse the Citrus integration tests in this test setup as we have the complete test flow of messages available in the Citrus tests. We only have to remove the simulated send/receive actions for those real interface partner applications which are available in our end-to-end test setup. +Usually Citrus simulates all interface partners within a test case which is great for continuous integration testing where just the System Under Test is deployed and all surrounding infrastructure and partners get simulated. +In end-to-end integration test scenarios some of our interface partners may be deployed and online. +Some other interface partners still require Citrus simulation logic. -With test actors we have the opportunity to link test actions, in particular send/receive message actions, to a test actor. The test actor can be disabled in configuration very easy and following from that all linked send/receive actions are disabled, too. One Citrus test case is runnable with different test setup scenarios where different partner applications on the one hand are available as real life applications and on the other hand require simulation. +It would be great if we were able to reuse the Citrus integration tests in all of these described test environments. +The Citrus test describes the complete test flow of messages, we only have to remove the simulated send/receive actions for those interface partner applications that are deployed and available in an end-to-end test setup. -[[define-test-actors]] -== Define test actors +With test actors we have the opportunity to link test actions, in particular send/receive message actions, to a named actor. +The test actor can be enabled/disabled via configuration and following from that all linked test actions are enabled/disabled, too. -First thing to do is to define one or more test actors in Citrus configuration. A test actor represents a participating party (e.g. interface partner, backend application). We write the test actors into the central Spring application context. We can use a special Citrus Spring XML schema so definitions are quite easy: +This means the same Citrus test case is runnable with different test actor configurations where some services are deployed as real applications and others may require simulation by Citrus. -[source,xml] +[[test-actors-create]] +== Create test actors + +First thing to do is to define one or more test actors in the Citrus configuration. +A test actor represents a participating party (e.g. interface partner, backend application, service). + +We define the test actors as beans and add them to the Citrus bean registry. + +.Citrus Bean +[source,java,indent=0,role="primary"] +---- +@BindToRegistry(name = "travel_agency") +public TestActor travelAgencyActor() { + return new TestActor("travel_agency"); +} + +@BindToRegistry(name = "royal_airline") +public TestActor royalAirlineActor() { + return new TestActor("royal_airline"); +} + +@BindToRegistry(name = "smart_ariline") +public TestActor smartAirlineActor() { + return new TestActor("smart_ariline"); +} +---- + +.Spring Bean +[source,java,indent=0,role="secondary"] +---- +@Bean(name = "travel_agency") +public TestActor travelAgencyActor() { + return new TestActor("travel_agency"); +} + +@Bean(name = "royal_airline") +public TestActor royalAirlineActor() { + return new TestActor("royal_airline"); +} + +@Bean(name = "smart_ariline") +public TestActor smartAirlineActor() { + return new TestActor("smart_ariline"); +} +---- + +.Spring XML +[source,xml,indent=0,role="secondary"] ---- - - - + + + + + ---- -The listing above defines three test actors participating in our test scenario. A travel agency application which is simulated by Citrus as a calling client, the smart airline application and a royal airline application. Now we have the test actors defined we can link those to message sender/receiver instances and/or test actions within our test case. +The listing above defines three test actors participating in our test scenario. +A `travel_agency` application which is simulated by Citrus as a calling client, the `smart_airline` application and a `royal_airline` application. +Now we have the test actors defined we can link those to message sender/receiver instances and/or test actions within our test case. -[[link-test-actors]] -== Link test actors +[[test-actors-reference]] +== Reference test actors -We need to link the test actors to message send and receive actions in our test cases. We can do this in two different ways. First we can set a test actor reference on a message sender and message receiver. +We need to reference the test actor and set it on a message send or receive action in our test case. +We can do this in two different ways. +First of all we can set a test actor reference on a message endpoint. -[source,xml] +.Citrus Bean +[source,java,indent=0,role="primary"] +---- +@BindToRegistry +public JmsSyncEndpoint royalAirlineBookingEndpoint() { + return JmsEndpoints.jms() + .synchronous() + .destination("${royal.airline.request.queue}") + .actor(royalAirlineActor()) + .build(); +} +---- + +.Spring Bean +[source,java,indent=0,role="secondary"] +---- +@Bean +public JmsSyncEndpoint royalAirlineBookingEndpoint() { + return JmsEndpoints.jms() + .synchronous() + .destination("${royal.airline.request.queue}") + .actor(royalAirlineActor()) + .build(); +} +---- + +.Spring XML +[source,xml,indent=0,role="secondary"] ---- + actor="royal_airline"/> +---- + +Now all test actions that are using this message endpoint are linked to the test actor. +In addition to that you can also explicitly link test actions to a test actor. + +.Java +[source,java,indent=0,role="primary"] +---- +@CitrusTest +public void airlineTest() { + $(receive("royalAirlineBookingEndpoint") + .message() + .body("...") + .actor("royal_airline") + ); + + $(send("royalAirlineBookingEndpoint") + .message() + .body("...") + .actor("royal_airline") + ); +} +---- + +.XML +[source,xml,indent=0,role="secondary"] ---- + + + + + + + -Now all test actions that are using these message receiver and message sender instances are linked to the test actor. In addition to that you can also explicitly link test actions to test actors in a test. + + + + + + + +---- + +.YAML +[source,yaml,indent=0,role="secondary"] +---- +name: AirlineTest +actions: + - receive: + endpoint: "royalAirlineBookingEndpoint" + actor: "royal_airline" + message: {} + - send: + endpoint: "royalAirlineBookingEndpoint" + actor: "royal_airline" + message: {} +---- -[source,xml] +.Spring XML +[source,xml,indent=0,role="secondary"] ---- - - - [...] - - + + + + + + + + - - - [...] - - + + + + + + + + ---- -This explicitly links test actors to test actions so you can decide which link should be set without having to rely on the message receiver and sender configuration. +This explicitly links the test actor named `royal_ariline` to test actions. +The test actor may be enabled/disabled according to the test environment. +All linked test actions and message endpoints will be skipped when the referenced test actor is disabled. -[[disable-test-actors]] +[[test-actors-disable]] == Disable test actors -Usually both airline applications are simulated in our integration tests. But this time we want to change this by introducing a royal airline application which is online as a real application instance. So we need to skip all simulated message interactions for the royal airline application in our Citrus tests. This is easy as we have linked all send/receive actions to one of our test actors. So we can disable the royal airline test actor in our configuration: +By default, test actors are enabled. +In some environments it may be required to disable the test actor and all its linked test actions and message endpoints though. + +In the airline example usually both airline applications are simulated in the integration tests. +Assume that there is a test environment where one of the simulated applications (e.g. the `royal_airline` application) is available as a real application instance deployed. +In this scenario the Citrus tests should skip all simulated message interactions for the `royal_airline` application and the real application instance in the test environment should consume the messages instead. + +This is easy as we have linked all send/receive actions to one of our test actors. +So we can disable the `royal_airline` test actor in our configuration: + +.Citrus Bean +[source,java,indent=0,role="primary"] +---- +@BindToRegistry(name = "travel_agency") +public TestActor travelAgencyActor() { + return new TestActor("travel_agency"); +} + +@BindToRegistry(name = "royal_airline") +public TestActor royalAirlineActor() { + TestActor royalAirlineActor = new TestActor("royal_airline"); + royalAirlineActor.setDisabled(true); + return royalAirlineActor; +} + +@BindToRegistry(name = "smart_ariline") +public TestActor smartAirlineActor() { + return new TestActor("smart_ariline"); +} +---- + +.Spring Bean +[source,java,indent=0,role="secondary"] +---- +@Bean(name = "travel_agency") +public TestActor travelAgencyActor() { + return new TestActor("travel_agency"); +} + +@Bean(name = "royal_airline") +public TestActor royalAirlineActor() { + TestActor royalAirlineActor = new TestActor("royal_airline"); + royalAirlineActor.setDisabled(true); + return royalAirlineActor; +} + +@Bean(name = "smart_ariline") +public TestActor smartAirlineActor() { + return new TestActor("smart_ariline"); +} +---- -[source,xml] +.Spring XML +[source,xml,indent=0,role="secondary"] ---- - + + + + + ---- -Any test action linked to this test actor is now skipped. As we introduced a real royal airline application in our test scenario the requests get answered and the test should be successful within this end-to-end test scenario. The travel agency and the smart airline still get simulated by Citrus. This is a perfect way of reusing integration tests in different test scenarios where you enable and disable simulated participating parties in Citrus. +Any test action linked to this test actor `royal_airline` is now skipped in the test execution. +The real `royal_airline` application available in our test scenario will handle the requests instead. +The `travel_agency` and the `smart_airline` applications still get simulated by Citrus. + +This is a perfect way of reusing integration tests in different test scenarios where you enable and disable simulated participating parties in Citrus. + +IMPORTANT: Server ports may be of special interest when dealing with different test scenarios. +You may have to also disable a Citrus embedded Jetty server instance in order to avoid port binding conflicts. +You may have to wire endpoint URIs accordingly before executing a test. +The real life application may not use the same port and IP address as the Citrus embedded servers for simulation. + +[[test-actors-environment-setting]] +== Test actor environment settings + +You can enable/disable the test actor also by using System property or environment variable settings. +The property and environment variable names follow a specific formatting that includes the test actor name: + +* `citrus.test.actor..enabled=true/false` +* `CITRUS_TEST_ACTOR__ENABLED=true/false` + +When the environment setting is available on the test host the test actor with the referenced name is enabled/disabled. + +You can set these properties in the `citrus-application.properties` for instance: + +.citrus-application.properties +[source,properties] +---- +citrus.test.actor.royal_airline.enabled=false +---- -IMPORTANT: Server ports may be of special interest when dealing with different test scenarios. You may have to also disable a Citrus embedded Jetty server instance in order to avoid port binding conflicts and you may have to wire endpoint URIs accordingly before executing a test. The real life application may not use the same port and ip as the Citrus embedded servers for simulation. +This disables the test actor named `royal_airline` and skips all its linked test actions and message endpoints.