Skip to content
This repository has been archived by the owner on May 18, 2020. It is now read-only.

feat: Add example unit test for running Activiti 7 process #315

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: use ProcessRuntime wrapper to start process instance
igdianov committed Sep 12, 2019
commit aeb48cb87aaf446d8adc91c21530ca2cfa824d9b
Original file line number Diff line number Diff line change
@@ -3,7 +3,10 @@
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -12,15 +15,22 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.StartProcessPayloadBuilder;
import org.activiti.api.process.model.payloads.StartProcessPayload;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.security.SecurityManager;
import org.activiti.cloud.api.process.model.IntegrationRequest;
import org.activiti.cloud.api.process.model.IntegrationResult;
import org.activiti.cloud.api.process.model.impl.IntegrationResultImpl;
import org.activiti.core.common.spring.identity.ExtendedInMemoryUserDetailsManager;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.awaitility.Awaitility;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
@@ -33,6 +43,14 @@
import org.springframework.messaging.Message;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@@ -45,9 +63,15 @@ public class RuntimeBundleApplicationTest {
private static final String CONNECTOR_PROCESS = "ConnectorProcess";
private static final String BUSINESS_KEY = "businessKey";

@Autowired
private ProcessRuntime processRuntime;

@Autowired
private RuntimeService runtimeService;
igdianov marked this conversation as resolved.
Show resolved Hide resolved

@Autowired
private TestSecurityUtil securityUtil;

private static CountDownLatch exampleConnectorConsumer;

@Before
@@ -58,13 +82,15 @@ public void setUp() {
@Test
public void testExampleConnectorProcess() throws InterruptedException {
// given
securityUtil.logInAs("user");

String businessKey = BUSINESS_KEY;
StartProcessPayload payload = new StartProcessPayloadBuilder().withProcessDefinitionKey(CONNECTOR_PROCESS)
.withBusinessKey(businessKey)
.build();

// when
ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
.processDefinitionKey(CONNECTOR_PROCESS)
.businessKey(businessKey)
.start();
ProcessInstance processInstance = processRuntime.start(payload);
// then
assertThat(processInstance).as("Should start process instance")
.isNotNull();
@@ -130,8 +156,106 @@ public TestIntegrationResultSender testIntegrationResultSender() {
return new TestIntegrationResultSender();
}

@Bean
public UserDetailsService myUserDetailsService() {
ExtendedInMemoryUserDetailsManager extendedInMemoryUserDetailsManager = new ExtendedInMemoryUserDetailsManager();

List<GrantedAuthority> userAuthorities = new ArrayList<>();
userAuthorities.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER"));
userAuthorities.add(new SimpleGrantedAuthority("GROUP_activitiTeam"));

extendedInMemoryUserDetailsManager.createUser(new User("user",
"password",
userAuthorities));


List<GrantedAuthority> adminAuthorities = new ArrayList<>();
adminAuthorities.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_ADMIN"));

extendedInMemoryUserDetailsManager.createUser(new User("admin",
"password",
adminAuthorities));

List<GrantedAuthority> garthAuthorities = new ArrayList<>();
garthAuthorities.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER"));
garthAuthorities.add(new SimpleGrantedAuthority("GROUP_doctor"));

extendedInMemoryUserDetailsManager.createUser(new User("garth",
"password",
garthAuthorities));

//dean has role but no group
List<GrantedAuthority> deanAuthorities = new ArrayList<>();
deanAuthorities.add(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER"));
extendedInMemoryUserDetailsManager.createUser(new User("dean",
"password",
deanAuthorities));

return extendedInMemoryUserDetailsManager;
}
}

@TestConfiguration
public static class TestSecurityUtil {

private Logger logger = LoggerFactory.getLogger(TestSecurityUtil.class);

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private SecurityManager securityManager;

public void logInAs(String username) {

UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
}
logger.info("> Logged in as: " + username);
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}

@Override
public Object getCredentials() {
return user.getPassword();
}

@Override
public Object getDetails() {
return user;
}

@Override
public Object getPrincipal() {
return user;
}

@Override
public boolean isAuthenticated() {
return true;
}

@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

}

@Override
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);

assertThat(securityManager.getAuthenticatedUserId()).isEqualTo(username);
}
}


public static class TestIntegrationResultSender {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be easier to add the dependency to activiti-cloud-starter-connector in test scope so you can use the provided IntegrationResultSender?
activiti-cloud-starter-connector is also bringing IntegrationResultBuilder: https://github.com/Activiti/ttc-connectors-dummytwitter/blob/master/src/main/java/org/activiti/cloud/connectors/twitter/connectors/TweetConnector.java#L60

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erdemedeiros I have tried to add starter connector dependency in test scope. It is causing a problem with overriding bean definitions:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-08-26 00:28:16.265  INFO [-,,,] 15596 --- [           main] o.a.c.r.RuntimeBundleApplicationTest     : No active profile set, falling back to default profiles: default
2019-08-26 00:28:17.037  INFO [-,,,] 15596 --- [           main] o.s.c.a.ConfigurationClassParser         : Properties location [classpath:/activiti-audit-producer.properties] not resolvable: class path resource [activiti-audit-producer.properties] cannot be opened because it does not exist
2019-08-26 00:28:17.235  INFO [-,,,] 15596 --- [           main] o.s.c.a.ConfigurationClassParser         : Properties location [classpath:/activiti-audit-producer.properties] not resolvable: class path resource [activiti-audit-producer.properties] cannot be opened because it does not exist
2019-08-26 00:28:18.653  WARN [-,,,] 15596 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'keycloakPreAuthActionsFilter' defined in class path resource [org/activiti/cloud/services/identity/keycloak/config/RuntimeBundleSecurityAutoConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=runtimeBundleSecurityAutoConfiguration; factoryMethodName=keycloakPreAuthActionsFilter; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/activiti/cloud/services/identity/keycloak/config/RuntimeBundleSecurityAutoConfiguration.class]] for bean 'keycloakPreAuthActionsFilter': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=commonSecurityAutoConfiguration; factoryMethodName=keycloakPreAuthActionsFilter; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/activiti/cloud/services/common/security/keycloak/config/CommonSecurityAutoConfiguration.class]] bound.
2019-08-26 00:28:18.663  INFO [-,,,] 15596 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-08-26 00:28:18.668 ERROR [-,,,] 15596 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'keycloakPreAuthActionsFilter', defined in class path resource [org/activiti/cloud/services/identity/keycloak/config/RuntimeBundleSecurityAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/activiti/cloud/services/common/security/keycloak/config/CommonSecurityAutoConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After enabling bean override, it blows up with the error due to component scan:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-08-26 00:38:47.794 ERROR [-,,,] 37240 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'commonSecurityAutoConfiguration': Unsatisfied dependency expressed through field 'keycloakConfigResolver'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'runtimeBundleSecurityAutoConfiguration': Unsatisfied dependency expressed through field 'keycloakConfigResolver'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'KeycloakConfigResolver': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erdemedeiros The activiti-cloud-starter-connector module component scan problem is fixed now. I have updated unit test example to use IntegrationResultBuilder and removed hacks from previous commits.


@Autowired