diff --git a/docs/src/reference/asciidoc/sm-error-handling.adoc b/docs/src/reference/asciidoc/sm-error-handling.adoc index 85b6c144..e7f24c7d 100644 --- a/docs/src/reference/asciidoc/sm-error-handling.adoc +++ b/docs/src/reference/asciidoc/sm-error-handling.adoc @@ -50,3 +50,26 @@ include::samples/DocsConfigurationSampleTests.java[tags=snippet4] TIP: Actions defined for transitions also have their own error handling logic. See <>. + +With a reactive api's it is possible to get _Action_ execution error +back from a _StateMachineEventResult_. Having simple machine which +errors within action transitioning into state `S1`. + +==== +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests12.java[tags=snippetA1] +---- +==== + +Below test concept shows how possible error can be consumed +from a _StateMachineEventResult_. + +==== +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests12.java[tags=snippetA2] +---- +==== + +NOTE: Error in entry/exit actions will not prevent transition to happen. diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateMachineEventResult.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateMachineEventResult.java index f5dce4d4..0337b068 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateMachineEventResult.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateMachineEventResult.java @@ -52,7 +52,8 @@ public interface StateMachineEventResult { ResultType getResultType(); /** - * Gets a mono representing completion. + * Gets a mono representing completion. Will have exception in a normal + * reactive chain if there is one. * * @return the mono for completion */ diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests12.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests12.java new file mode 100644 index 00000000..aafefb30 --- /dev/null +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests12.java @@ -0,0 +1,85 @@ +/* + * Copyright 2020 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 + * + * https://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.springframework.statemachine.docs; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.StateMachineException; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@SpringBootTest +public class DocsConfigurationSampleTests12 { + + +// tag::snippetA1[] + @Configuration + @EnableStateMachine + static class Config1 extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .stateEntry("S1", (context) -> { + throw new RuntimeException("example error"); + }); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source("SI") + .target("S1") + .event("E1"); + } + } +// end::snippetA1[] + +// tag::snippetA2[] + @Autowired + private StateMachine machine; + + @Test + public void testActionEntryErrorWithEvent() throws Exception { + StepVerifier.create(machine.startReactively()).verifyComplete(); + assertThat(machine.getState().getIds()).containsExactlyInAnyOrder("SI"); + + StepVerifier.create(machine.sendEvent(Mono.just(MessageBuilder.withPayload("E1").build()))) + .consumeNextWith(result -> { + StepVerifier.create(result.complete()).consumeErrorWith(e -> { + assertThat(e).isInstanceOf(StateMachineException.class).hasMessageContaining("example error"); + }).verify(); + }) + .verifyComplete(); + + assertThat(machine.getState().getIds()).containsExactlyInAnyOrder("S1"); + } +// end::snippetA2[] +}