package org.bonitasoft.forms.server.provider.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.bonitasoft.console.common.server.utils.BPMEngineAPIUtil;
import org.bonitasoft.console.common.server.utils.BPMEngineException;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.bpm.flownode.ActivityInstanceNotFoundException;
import org.bonitasoft.engine.bpm.process.ArchivedProcessInstanceNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessInstanceNotFoundException;
import org.bonitasoft.engine.identity.UserNotFoundException;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.engine.session.InvalidSessionException;
import org.bonitasoft.forms.client.model.exception.ForbiddenFormAccessException;
import org.bonitasoft.forms.client.model.exception.SessionTimeoutException;
import org.bonitasoft.forms.server.api.IFormWorkflowAPI;
import org.bonitasoft.forms.server.api.impl.FormWorkflowAPIImpl;
import org.bonitasoft.forms.server.exception.FormNotFoundException;
import org.bonitasoft.forms.server.provider.impl.util.FormServiceProviderUtil;
import org.bonitasoft.forms.server.util.FormContextUtil;
import org.bonitasoft.web.rest.model.user.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class FormServiceProviderImplTest {
@Spy
FormServiceProviderImpl formServiceProviderImpl;
@Mock
Map<String, Object> context;
@Mock
IFormWorkflowAPI workflowAPI;
@Mock
Map<String, Object> urlContext;
@Mock
FormContextUtil formContextUtil;
@Mock
APISession apiSession;
@Mock
BPMEngineAPIUtil bpmEngineAPIUtil;
@Mock
ProcessAPI processAPI;
@Mock
FormWorkflowAPIImpl formWorkflowAPIImpl;
@Mock
private User user;
@Mock
private Map<String, Object> mapUrlContext;
private List<Class<? extends Exception>> givenExceptions;
private List<Class<? extends Exception>> expectedExceptions;
@Before
public void before() throws Exception {
givenExceptions = new ArrayList<Class<? extends Exception>>();
expectedExceptions = new ArrayList<Class<? extends Exception>>();
doReturn(urlContext).when(context).get(FormServiceProviderUtil.URL_CONTEXT);
doReturn(processAPI).when(bpmEngineAPIUtil).getProcessAPI(any(APISession.class));
doReturn(workflowAPI).when(formServiceProviderImpl).getFormWorkFlowApi();
doReturn(apiSession).when(formContextUtil).getAPISessionFromContext();
}
@Test
public void getProcessDefinitionId_with_process_UUID() throws Exception {
final long expectedProcessDefinitionId = 123l;
// given
doReturn(expectedProcessDefinitionId).when(urlContext).get(FormServiceProviderUtil.PROCESS_UUID);
// when
final long processDefinitionID = formServiceProviderImpl.getProcessDefinitionID(context);
// then exception
verify(workflowAPI, never()).getProcessDefinitionIDFromActivityInstanceID(any(APISession.class), anyLong());
verify(workflowAPI, never()).getProcessDefinitionIDFromUUID(any(APISession.class), any(String.class));
assertThat(processDefinitionID).isEqualTo(expectedProcessDefinitionId);
}
@Test
public void getProcessDefinitionId_with_form_ID() throws Exception {
// given
doReturn(null).when(urlContext).get(FormServiceProviderUtil.PROCESS_UUID);
doReturn("processName--1.0$entry").when(urlContext).get(FormServiceProviderUtil.FORM_ID);
doThrow(ActivityInstanceNotFoundException.class).when(workflowAPI).getProcessDefinitionIDFromActivityInstanceID(any(APISession.class), anyLong());
final long processDefinitionId = 123l;
doReturn(processDefinitionId).when(workflowAPI).getProcessDefinitionIDFromUUID(any(APISession.class), any(String.class));
// when
final long processDefinitionID = formServiceProviderImpl.getProcessDefinitionID(context);
// then exception
verify(workflowAPI, never()).getProcessDefinitionIDFromActivityInstanceID(any(APISession.class), anyLong());
verify(workflowAPI, times(1)).getProcessDefinitionIDFromUUID(any(APISession.class), any(String.class));
assertThat(processDefinitionID).isEqualTo(processDefinitionId);
}
@Test
public void testextractProcessDefinitionUUID() throws Exception {
//given
final String formId = "processName--1.0$entry";
//when
final String extractProcessDefinitionUUID = formServiceProviderImpl.extractProcessDefinitionUUID(formId);
//then
assertThat(extractProcessDefinitionUUID).isEqualTo("processName--1.0");
}
@Test
public void testextractProcessDefinitionUUID_with_step_name() throws Exception {
//given
final String formId = "processName--1.0--Step1$entry";
//when
final String extractProcessDefinitionUUID = formServiceProviderImpl.extractProcessDefinitionUUID(formId);
//then
assertThat(extractProcessDefinitionUUID).isEqualTo("processName--1.0");
}
@Test(expected = ForbiddenFormAccessException.class)
public void should_canUserViewInstanceForm_throw_exception_if_not_involved() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long processInstanceId = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doReturn(false).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
doReturn(false).when(formWorkflowAPIImpl).canUserSeeProcessInstance(apiSession, processInstanceId);
doReturn("john").when(user).getUsername();
doReturn("form-type").when(formServiceProviderImpl).getFormType(formId, context);
//when
formServiceProviderImpl.canUserViewInstanceForm(apiSession, user, formWorkflowAPIImpl, processInstanceId, formId, userId, context);
//exception
}
@Test
public void should_canUserViewInstanceForm_return_true_for_involved_user() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long processInstanceId = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doReturn(false).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
doReturn(true).when(formWorkflowAPIImpl).canUserSeeProcessInstance(apiSession, processInstanceId);
//when
formServiceProviderImpl.canUserViewInstanceForm(apiSession, user, formWorkflowAPIImpl, processInstanceId, formId, userId, context);
}
@Test
public void should_canUserViewInstanceForm_return_true_for_admin() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long processInstanceId = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doReturn(true).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
//when
formServiceProviderImpl.canUserViewInstanceForm(apiSession, user, formWorkflowAPIImpl, processInstanceId, formId, userId, context);
}
@Test
public void should_canUserViewInstanceForm_throw_exception() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long processInstanceId = 3L;
addGivenAndExpectedException(ForbiddenFormAccessException.class, ForbiddenFormAccessException.class);
addGivenAndExpectedException(InvalidSessionException.class, InvalidSessionException.class);
addGivenAndExpectedException(BPMEngineException.class, BPMEngineException.class);
addGivenAndExpectedException(ProcessInstanceNotFoundException.class, FormNotFoundException.class);
addGivenAndExpectedException(ArchivedProcessInstanceNotFoundException.class, FormNotFoundException.class);
addGivenAndExpectedException(ProcessDefinitionNotFoundException.class, FormNotFoundException.class);
addGivenAndExpectedException(UserNotFoundException.class, SessionTimeoutException.class);
givenExceptions.add(UserNotFoundException.class);
expectedExceptions.add(SessionTimeoutException.class);
doReturn("john").when(user).getUsername();
doReturn("form-type").when(formServiceProviderImpl).getFormType(formId, context);
for (int i = 0; i < givenExceptions.size(); i++) {
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doThrow(givenExceptions.get(i)).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
//when
try {
formServiceProviderImpl.canUserViewInstanceForm(apiSession, user, formWorkflowAPIImpl, processInstanceId, formId, userId, context);
} catch (final Exception e) {
assertThat(e.getClass()).as("bad exception with given exception " + givenExceptions.get(i).getClass()).isEqualTo(
expectedExceptions.get(i));
if (e.getClass() != expectedExceptions.get(i)) {
fail("bad exception");
}
}
}
}
private void addGivenAndExpectedException(final Class<? extends Exception> givenException, final Class<? extends Exception> expectedException) {
givenExceptions.add(givenException);
expectedExceptions.add(expectedException);
}
@Test(expected = ForbiddenFormAccessException.class)
public void should_canUserViewActivityInstanceForm_throw_exception_if_not_involved() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long activityInstanceID = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromActivityInstanceID(apiSession, activityInstanceID);
doReturn(false).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
doReturn(false).when(formWorkflowAPIImpl).canUserSeeHumanTask(apiSession, userId, activityInstanceID);
doReturn("john").when(user).getUsername();
doReturn("form-type").when(formServiceProviderImpl).getFormType(formId, context);
//when
formServiceProviderImpl.canUserViewActivityInstanceForm(apiSession, user, formWorkflowAPIImpl, activityInstanceID, formId, userId, context);
//exception
}
@Test
public void should_canUserViewActivityInstanceForm_return_true_for_involved_user() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long activityInstanceID = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromActivityInstanceID(apiSession, activityInstanceID);
doReturn(false).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
doReturn(true).when(formWorkflowAPIImpl).canUserSeeHumanTask(apiSession, userId, activityInstanceID);
//when
formServiceProviderImpl.canUserViewActivityInstanceForm(apiSession, user, formWorkflowAPIImpl, activityInstanceID, formId, userId, context);
}
@Test
public void should_canUserViewActivityInstanceForm_return_true_for_admin() throws Exception {
final String formId = "formId";
final long userId = 2L;
final long activityInstanceID = 3L;
//given
doReturn(1L).when(formWorkflowAPIImpl).getProcessDefinitionIDFromActivityInstanceID(apiSession, activityInstanceID);
doReturn(true).when(formWorkflowAPIImpl).isUserAdminOrProcessOwner(apiSession, 1L);
//when
formServiceProviderImpl.canUserViewActivityInstanceForm(apiSession, user, formWorkflowAPIImpl, activityInstanceID, formId, userId, context);
}
@Test
public void testIsAllowed() throws Exception {
//given
final String formId = "formId";
final String processDefinitionUUIDStr = "processDefinitionUUIDStr";
final String permissions = FormServiceProviderUtil.PROCESS_UUID + "#" + processDefinitionUUIDStr;
final String productVersion = "";
final String migrationProductVersion = "";
final boolean isFormPermissions = true;
final long processInstanceId = 1L;
final long userId = 2L;
final long processDefinitionId = 3L;
doReturn(processInstanceId).when(mapUrlContext).get(FormServiceProviderUtil.INSTANCE_UUID);
doReturn(formContextUtil).when(formServiceProviderImpl).createFormContextUtil(context);
doReturn(userId).when(formContextUtil).getUserId();
doReturn(apiSession).when(formContextUtil).getAPISessionFromContext();
doReturn(processDefinitionId).when(workflowAPI).getProcessDefinitionIDFromUUID(apiSession, processDefinitionUUIDStr);
doReturn(processDefinitionId).when(workflowAPI).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doReturn(mapUrlContext).when(context).get(FormServiceProviderUtil.URL_CONTEXT);
doReturn(user).when(context).get(FormServiceProviderUtil.USER);
doNothing().when(formServiceProviderImpl).canUserViewInstanceForm(apiSession, user, workflowAPI, processInstanceId, formId,
userId, context);
final boolean allowed = formServiceProviderImpl.isAllowed(formId, permissions, productVersion, migrationProductVersion, context, isFormPermissions);
//then
assertThat(allowed).as("should allow user").isTrue();
}
@Test
public void testIsNotAllowed() throws Exception {
//given
final String formId = "formId";
final String processDefinitionUUIDStr = "processDefinitionUUIDStr";
final String permissions = FormServiceProviderUtil.PROCESS_UUID + "#" + processDefinitionUUIDStr;
final String productVersion = "";
final String migrationProductVersion = "";
final boolean isFormPermissions = true;
final long processInstanceId = 1L;
final long userId = 2L;
final long processDefinitionId = 3L;
doReturn(processInstanceId).when(mapUrlContext).get(FormServiceProviderUtil.INSTANCE_UUID);
doReturn(formContextUtil).when(formServiceProviderImpl).createFormContextUtil(context);
doReturn(userId).when(formContextUtil).getUserId();
doReturn(apiSession).when(formContextUtil).getAPISessionFromContext();
doReturn(processDefinitionId).when(workflowAPI).getProcessDefinitionIDFromUUID(apiSession, processDefinitionUUIDStr);
doReturn(processDefinitionId).when(workflowAPI).getProcessDefinitionIDFromProcessInstanceID(apiSession, processInstanceId);
doReturn(mapUrlContext).when(context).get(FormServiceProviderUtil.URL_CONTEXT);
doReturn(user).when(context).get(FormServiceProviderUtil.USER);
addGivenAndExpectedException(InvalidSessionException.class, SessionTimeoutException.class);
addGivenAndExpectedException(BPMEngineException.class, FormNotFoundException.class);
addGivenAndExpectedException(FormNotFoundException.class, FormNotFoundException.class);
addGivenAndExpectedException(ForbiddenFormAccessException.class, ForbiddenFormAccessException.class);
addGivenAndExpectedException(SessionTimeoutException.class, SessionTimeoutException.class);
for (int i = 0; i < givenExceptions.size(); i++) {
//given
doThrow(givenExceptions.get(i)).when(formServiceProviderImpl).canUserViewInstanceForm(apiSession, user, workflowAPI, processInstanceId,
formId,
userId, context);
//when
try {
formServiceProviderImpl.isAllowed(formId, permissions, productVersion, migrationProductVersion, context, isFormPermissions);
} catch (final Exception e) {
assertThat(e.getClass()).as("bad exception with given exception " + givenExceptions.get(i).getClass()).isEqualTo(
expectedExceptions.get(i));
if (e.getClass() != expectedExceptions.get(i)) {
fail("bad exception");
}
}
}
}
@Test
public void should_assignForm_call_worflowAPI() throws Exception {
final String formId = "formId";
final String expectedTaskId = "42";
doReturn(formContextUtil).when(formServiceProviderImpl).createFormContextUtil(context);
doReturn(apiSession).when(formContextUtil).getAPISessionFromContext();
doReturn(expectedTaskId).when(urlContext).get(FormServiceProviderUtil.TASK_UUID);
formServiceProviderImpl.assignForm(formId, context);
verify(workflowAPI, times(1)).assignTaskIfNotAssigned(apiSession, Long.parseLong(expectedTaskId), apiSession.getUserId());
}
}