/*
* Copyright 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.springframework.statemachine.data;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.Iterator;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineModelConfigurer;
import org.springframework.statemachine.config.model.StateMachineModelFactory;
import org.springframework.statemachine.data.support.StateMachineJackson2RepositoryPopulatorFactoryBean;
import org.springframework.statemachine.guard.Guard;
import org.springframework.statemachine.state.PseudoStateKind;
import org.springframework.statemachine.state.State;
import org.springframework.statemachine.test.StateMachineTestPlan;
import org.springframework.statemachine.test.StateMachineTestPlanBuilder;
import org.springframework.util.ObjectUtils;
/**
* Base repository config tests.
*
* @author Janne Valkealahti
*/
public abstract class AbstractRepositoryTests {
protected AnnotationConfigApplicationContext context;
@Before
public void setup() {
cleanInternal();
context = buildContext();
}
@After
public void clean() {
if (context != null) {
context.close();
}
context = null;
}
protected void cleanInternal() {
}
protected Class<?>[] getRegisteredClasses() {
return new Class<?>[0];
}
@SuppressWarnings("unchecked")
@Test
public void testMachine2() throws Exception {
context.register(getRegisteredClasses());
context.register(Config2.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").and()
.step().sendEvent("E1").expectStates("S2").and()
.step().sendEvent("E2").expectStates("S3").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine3() throws Exception {
context.register(getRegisteredClasses());
context.register(Config3.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").and()
.step().sendEvent("E1").expectStates("S2", "S20").and()
.step().sendEvent("E2").expectStates("S2", "S21").and()
.step().sendEvent("E3").expectStates("S1").and()
.step().sendEvent("E4").expectStates("S2", "S21").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine4() throws Exception {
context.register(getRegisteredClasses());
context.register(Config4.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").and()
.step().sendEvent("E1").expectStates("S2", "S20").and()
.step().sendEvent("E2").expectStates("S2", "S21").and()
.step().sendEvent("E3").expectStates("S1").and()
.step().sendEvent("E4").expectStates("S2", "S21").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine5() throws Exception {
context.register(getRegisteredClasses());
context.register(Config5.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S10", "S20").and()
.step().sendEvent("E1").expectStates("S11", "S21").and()
.step().sendEvent("E2").expectStates("S10", "S21").and()
.step().sendEvent("E3").expectStates("S10", "S20").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine6First() throws Exception {
context.register(getRegisteredClasses());
context.register(Config6.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("choice", "s30").build()).expectStates("S30").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine6Then1() throws Exception {
context.register(getRegisteredClasses());
context.register(Config6.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("choice", "s31").build()).expectStates("S31").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine6Then2() throws Exception {
context.register(getRegisteredClasses());
context.register(Config6.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("choice", "s32").build()).expectStates("S32").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine6Last() throws Exception {
context.register(getRegisteredClasses());
context.register(Config6.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").build()).expectStates("S33").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine8First() throws Exception {
context.register(getRegisteredClasses());
context.register(Config8.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("junction", "s30").build()).expectStates("S30").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine8Then1() throws Exception {
context.register(getRegisteredClasses());
context.register(Config8.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("junction", "s31").build()).expectStates("S31").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine8Then2() throws Exception {
context.register(getRegisteredClasses());
context.register(Config8.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").setHeader("junction", "s32").build()).expectStates("S32").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine8Last() throws Exception {
context.register(getRegisteredClasses());
context.register(Config8.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent(MessageBuilder.withPayload("E1").build()).expectStates("S33").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine9() throws Exception {
context.register(getRegisteredClasses());
context.register(Config9.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").and()
.step().sendEvent("ENTRY1").expectStates("S2", "S22").and()
.step().sendEvent("EXIT1").expectStates("S4").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine10() throws Exception {
context.register(getRegisteredClasses());
context.register(Config10.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent("E1").expectStates("S2", "S21", "S31").and()
.build();
plan.test();
State<String, String> endState = null;
Iterator<State<String, String>> iterator = stateMachine.getStates().iterator();
while (iterator.hasNext()) {
State<String, String> next = iterator.next();
if (next.getId().equals("SF")) {
endState = next;
break;
}
}
assertThat(endState, notNullValue());
assertThat(endState.getPseudoState(), notNullValue());
assertThat(endState.getPseudoState().getKind(), is(PseudoStateKind.END));
}
@SuppressWarnings("unchecked")
@Test
public void testMachine11() throws Exception {
context.register(getRegisteredClasses());
context.register(Config11.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("SI").and()
.step().sendEvent("E1").expectStates("S2", "S20", "S30").and()
.step().sendEvent("E2").expectStates("S2", "S21", "S30").and()
.step().sendEvent("E3").expectStates("S4").and()
.step().sendEvent("E4").expectStates("SI").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine12() throws Exception {
context.register(getRegisteredClasses());
context.register(Config12.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("READY").and()
.step().sendEvent("E3").expectStates("S3").and()
.step().sendEvent("E1").expectStates("S3").and()
.step().sendEvent("E6").expectStates("S1").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine13() throws Exception {
context.register(getRegisteredClasses());
context.register(Config13.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").and()
.step().sendEvent("E1").expectStates("S2", "S21").and()
.step().sendEvent("E3").expectStates("S2", "S22").and()
.step().sendEvent("E2").expectStates("S3").and()
.build();
plan.test();
}
@SuppressWarnings("unchecked")
@Test
public void testMachine14() throws Exception {
context.register(getRegisteredClasses());
context.register(Config14.class, FactoryConfig.class);
context.refresh();
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.stateMachine(stateMachine)
.step().expectStates("S1").expectVariable("foo", 0).and()
.step().sendEvent("E1").expectStates("S2").and()
.build();
plan.test();
}
@Configuration
public static class Config2 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data2.json")});
return factoryBean;
}
}
@Configuration
public static class Config3 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data3.json")});
return factoryBean;
}
}
@Configuration
public static class Config4 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data4.json")});
return factoryBean;
}
}
@Configuration
public static class Config5 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data5.json")});
return factoryBean;
}
}
@Configuration
public static class Config6 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data6.json")});
return factoryBean;
}
@Bean
public Guard<String, String> s30Guard() {
return new ChoiceGuard("s30");
}
@Bean
public Guard<String, String> s31Guard() {
return new ChoiceGuard("s31");
}
@Bean
public Guard<String, String> s32Guard() {
return new ChoiceGuard("s32");
}
}
@Configuration
public static class Config7 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data7.json")});
return factoryBean;
}
}
@Configuration
public static class Config8 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data8.json")});
return factoryBean;
}
@Bean
public Guard<String, String> s30Guard() {
return new JunctionGuard("s30");
}
@Bean
public Guard<String, String> s31Guard() {
return new JunctionGuard("s31");
}
@Bean
public Guard<String, String> s32Guard() {
return new JunctionGuard("s32");
}
}
@Configuration
public static class Config9 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data9.json")});
return factoryBean;
}
}
@Configuration
public static class Config10 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data10.json")});
return factoryBean;
}
}
@Configuration
public static class Config11 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data11.json")});
return factoryBean;
}
}
@Configuration
public static class Config12 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data12.json")});
return factoryBean;
}
}
@Configuration
public static class Config13 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data13.json")});
return factoryBean;
}
}
@Configuration
public static class Config14 {
@Bean
public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() {
StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean();
factoryBean.setResources(new Resource[]{new ClassPathResource("data14.json")});
return factoryBean;
}
}
@Configuration
@EnableStateMachineFactory
public static class FactoryConfig extends StateMachineConfigurerAdapter<String, String> {
@Autowired
private StateRepository<? extends RepositoryState> stateRepository;
@Autowired
private TransitionRepository<? extends RepositoryTransition> transitionRepository;
@Override
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
model
.withModel()
.factory(modelFactory());
}
@Bean
public StateMachineModelFactory<String, String> modelFactory() {
return new RepositoryStateMachineModelFactory(stateRepository, transitionRepository);
}
}
private static class ChoiceGuard implements Guard<String, String> {
private final String match;
public ChoiceGuard(String match) {
this.match = match;
}
@Override
public boolean evaluate(StateContext<String, String> context) {
return ObjectUtils.nullSafeEquals(match, context.getMessageHeaders().get("choice", String.class));
}
}
private static class JunctionGuard implements Guard<String, String> {
private final String match;
public JunctionGuard(String match) {
this.match = match;
}
@Override
public boolean evaluate(StateContext<String, String> context) {
return ObjectUtils.nullSafeEquals(match, context.getMessageHeaders().get("junction", String.class));
}
}
/**
* Builds the context.
*
* @return the annotation config application context
*/
protected AnnotationConfigApplicationContext buildContext() {
return null;
}
}