Skip to content

Commit

Permalink
#11265 : Adding more tests to the four-eye sub-action integration test.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcastro-dotcms committed Jan 29, 2018
1 parent f9e34a3 commit 6b81895
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
import com.dotcms.contenttype.transform.contenttype.StructureTransformer;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.beans.Host;
import com.dotmarketing.beans.Permission;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.business.Role;
import com.dotmarketing.business.RoleAPI;
import com.dotmarketing.business.UserAPI;
Expand All @@ -27,205 +25,263 @@
import com.dotmarketing.portlets.workflows.business.BaseWorkflowIntegrationTest;
import com.dotmarketing.portlets.workflows.business.WorkflowAPI;
import com.dotmarketing.portlets.workflows.model.WorkflowActionClass;
import com.dotmarketing.portlets.workflows.model.WorkflowActionClassParameter;
import com.dotmarketing.portlets.workflows.model.WorkflowActionletParameter;
import com.dotmarketing.portlets.workflows.model.WorkflowProcessor;
import com.liferay.portal.model.User;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* This class verifies the correct behavior of the {@link FourEyeApproverActionlet}, which requires
* a specific number of users to approve a content BEFORE it can be published. The workflow action
* that triggers this action should have the following actionlets in it:
* <ol>
* <li>Unlock Content.</li>
* <li>'4 Eye' Approval.</li>
* <li>Publish Content.</li>
* </ol>
* This ensures that a contentlet will be correctly published after the required approvers have
* accepted the new content. This is how the Multiple Approver action works too.
*
* @author Jose Castro
* @version 4.3.0
* @since Jan 10, 2018
*/
public class FourEyeApproverActionletTest extends BaseWorkflowIntegrationTest {

private static RoleAPI roleAPI;
private static WorkflowAPI workflowAPI;
private static ContentletAPI contentletAPI;
private static LanguageAPI languageAPI;
private static ContentTypeAPI contentTypeAPI;
private static UserAPI userAPI;

private static Role publisherRole;
private static User systemUser;

private static CreateSchemeStepActionResult schemeStepActionResult = null;
private static ContentType type = null;
private static Contentlet contentlet = null;
private static User publisher1;
private static User publisher2;

@BeforeClass
public static void prepare() throws Exception {
// Setting up the web app environment
IntegrationTestInitService.getInstance().init();

systemUser = APILocator.systemUser();
roleAPI = APILocator.getRoleAPI();
publisherRole = roleAPI.findRoleByName("Publisher / Legal", null);

workflowAPI = APILocator.getWorkflowAPI();
contentTypeAPI = APILocator.getContentTypeAPI(systemUser);
contentletAPI = APILocator.getContentletAPI();
languageAPI = APILocator.getLanguageAPI();
userAPI = APILocator.getUserAPI();
final RoleAPI roleAPI = APILocator.getRoleAPI();

final long sysTime = System.currentTimeMillis();
// Get the test role and two users from such a role
final Role publisherRole = roleAPI.findRoleByName("Publisher / Legal", null);
publisher1 = userAPI.getUsersByNameOrEmailOrUserID("[email protected]", 0, 1).get(0);
publisher2 = userAPI.getUsersByNameOrEmailOrUserID("[email protected]", 0, 1).get(0);

// creates the scheme and actions
// Create the scheme and actions. This method allows you to add just one sub-action
// in the beginning
final long sysTime = System.currentTimeMillis();
schemeStepActionResult = createSchemeStepActionActionlet
("itFourEyeApprovalScheme_" + sysTime, "step1", "action1",
CheckinContentActionlet.class);

final List<Permission> permissions = new ArrayList<>();
Permission permission = new Permission(schemeStepActionResult.getAction().getId(), publisherRole.getId(), PermissionAPI.PERMISSION_USE);
permissions.add(permission);
workflowAPI.saveAction(schemeStepActionResult.getAction(), permissions);

WorkflowActionClass wac = new WorkflowActionClass();
wac.setActionId(schemeStepActionResult.getAction().getId());
wac.setClazz(FourEyeApproverActionlet.class.getName());
wac.setName(WorkFlowActionlet.class.cast(FourEyeApproverActionlet.class.newInstance()).getName());
wac.setOrder(1);
workflowAPI.saveActionClass(wac);

wac = new WorkflowActionClass();
wac.setActionId(schemeStepActionResult.getAction().getId());
wac.setClazz(PublishContentActionlet.class.getName());
wac.setName(WorkFlowActionlet.class.cast(PublishContentActionlet.class.newInstance()).getName());
wac.setOrder(2);
workflowAPI.saveActionClass(wac);

List<WorkflowActionClass> actionClasses = workflowAPI
.findActionClasses(schemeStepActionResult.getAction());

wac = actionClasses.get(1);
WorkFlowActionlet actionlet = workflowAPI.findActionlet(wac.getClazz());
List<WorkflowActionletParameter> actionletParams = actionlet.getParameters();

List<WorkflowActionClassParameter> newParams = new ArrayList<>();
WorkflowActionClassParameter testParam = new WorkflowActionClassParameter();
testParam.setActionClassId(wac.getId());
testParam.setKey(actionletParams.get(0).getKey());
testParam.setValue("[email protected],[email protected]");
newParams.add(testParam);

testParam = new WorkflowActionClassParameter();
testParam.setActionClassId(wac.getId());
testParam.setKey(actionletParams.get(1).getKey());
testParam.setValue("2");
newParams.add(testParam);

testParam = new WorkflowActionClassParameter();
testParam.setActionClassId(wac.getId());
testParam.setKey(actionletParams.get(2).getKey());
testParam.setValue("'4 Eye' Approval Required");
newParams.add(testParam);

testParam = new WorkflowActionClassParameter();
testParam.setActionClassId(wac.getId());
testParam.setKey(actionletParams.get(3).getKey());
testParam.setValue("Please review this content.");
newParams.add(testParam);

workflowAPI.saveWorkflowActionClassParameters(newParams);

//Map<String, WorkflowActionClassParameter> enteredParams = workflowAPI.findParamsForActionClass(wac);

// creates the type to trigger the scheme
createTestType();

// associated the scheme to the type
// Set the role ID of the people who can use the action
addWhoCanUseToAction(schemeStepActionResult.getAction(),
Collections.singletonList(publisherRole.getId()));
// Add the remaining two sub-actions for this test
addActionletToAction(schemeStepActionResult.getAction().getId(),
FourEyeApproverActionlet.class, 1);
addActionletToAction(schemeStepActionResult.getAction().getId(),
PublishContentActionlet.class, 2);
// Add the required parameters to the '4-eyes' sub-action
final List<WorkflowActionClass> actionletClasses = getActionletsFromAction(
schemeStepActionResult.getAction());
WorkflowActionClass workflowActionClass = actionletClasses.get(1);
addParameterValuesToActionlet(workflowActionClass,
Arrays.asList("[email protected],[email protected]", "2",
"'4 Eye' Approval Required", "Please review this content."));

// Create the content type to trigger the scheme
createTestContentType();

// Associate the scheme to the content type
workflowAPI.saveSchemesForStruct(new StructureTransformer(type).asStructure(),
Arrays.asList(schemeStepActionResult.getScheme()));
Collections.singletonList(schemeStepActionResult.getScheme()));
}

/**
* Creates the test Content Type
*
* @throws DotDataException
* @throws DotSecurityException
*/
private static void createTestType()
private static void createTestContentType()
throws DotDataException, DotSecurityException {

type = contentTypeAPI.save(
ContentTypeBuilder.builder(BaseContentType.CONTENT.immutableClass())
.expireDateVar(null).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST)
.description("SaveContentActionletTest...")
.name("SaveContentActionletTest").owner(APILocator.systemUser().toString())
.variable("SaveContentActionletTest").build());

.description("Content Type for testing the 4-Eye Approval actionlet.")
.name("FourEyeActionletTest").owner(APILocator.systemUser().toString())
.variable("FourEyeActionletTest").build());
final List<Field> fields = new ArrayList<>(type.fields());

fields.add(FieldBuilder.builder(TextField.class).name("title").variable("title")
.contentTypeId(type.id()).dataType(DataTypes.TEXT).indexed(true).build());
fields.add(FieldBuilder.builder(TextField.class).name("txt").variable("txt")
.contentTypeId(type.id()).dataType(DataTypes.TEXT).indexed(true).build());

type = contentTypeAPI.save(type, fields);
}

@Test
public void runActionlet() throws DotSecurityException, DotDataException, InterruptedException {
User publisher1 = userAPI.getUsersByNameOrEmailOrUserID("[email protected]", 0, 2).get(0);
User publisher2 = userAPI.getUsersByNameOrEmailOrUserID("[email protected]", 0, 2).get(0);
public void contentApprovalWithTwoApprovers()
throws DotSecurityException, DotDataException {
// Create a contentlet first and save it
final long languageId = languageAPI.getDefaultLanguage().getId();
Contentlet cont = new Contentlet();
final Contentlet cont = new Contentlet();
cont.setContentTypeId(type.id());
cont.setOwner(APILocator.systemUser().toString());
cont.setModDate(new Date());
cont.setLanguageId(languageId);
cont.setStringProperty("title", "Test Save");
cont.setStringProperty("txt", "Test Save Text");
cont.setStringProperty("title", "4-Eye Approval Test Title");
cont.setStringProperty("txt", "4-Eye Approval Test Text");
cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797");
cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d");

// first save
final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false);
boolean isLive = false;
Assert.assertFalse("The contentlet cannot be live, it has just been created.",
contentlet1.isLive());

// triggering the save content action
// Set the appropriate workflow action to the contentlet
contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY,
schemeStepActionResult.getAction().getId());
contentlet1.setStringProperty("title", "Test Save");
contentlet1.setStringProperty("txt", "Test Save Text");

// Triggering the save content action
WorkflowProcessor processor =
workflowAPI.fireWorkflowPreCheckin(contentlet1, publisher1);
workflowAPI.fireWorkflowPostCheckin(processor);

Thread.sleep(2000);
// The contentlet MUST NOT be live yet, it needs one more approval
final Contentlet contentlet2 = contentletAPI
.findContentletByIdentifier(contentlet1.getIdentifier(),
false, languageId, systemUser, false);
isLive = contentlet2.isLive();
Assert.assertFalse("The contentlet cannot be live, it needs 1 more approver.",
contentlet2.isLive());

processor = workflowAPI.fireWorkflowPreCheckin(contentlet2, publisher2);
workflowAPI.fireWorkflowPostCheckin(processor);

Thread.sleep(2000);
Contentlet contentlet3 = contentletAPI
// The contentlet MUST be live now as it has been approved by another user
final Contentlet contentlet3 = contentletAPI
.findContentletByIdentifier(contentlet2.getIdentifier(),
false, languageId, systemUser, false);
isLive = contentlet3.isLive();
Assert.assertTrue("The contentlet MUST be live, it has all the approvers.",
contentlet2.isLive());

int counter = 0;
// Cleanup
contentlet = contentlet3;
contentletAPI.delete(contentlet3, systemUser, false);
}

@Test
public void contentApprovalWithOneApprover()
throws DotSecurityException, DotDataException, InterruptedException {
// Create a contentlet first and save it
final long languageId = languageAPI.getDefaultLanguage().getId();
final Contentlet cont = new Contentlet();
cont.setContentTypeId(type.id());
cont.setOwner(APILocator.systemUser().toString());
cont.setModDate(new Date());
cont.setLanguageId(languageId);
cont.setStringProperty("title", "4-Eye Approval Test Title");
cont.setStringProperty("txt", "4-Eye Approval Test Text");
cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797");
cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d");
final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false);
Assert.assertFalse("The contentlet cannot be live, it has just been created.",
contentlet1.isLive());

// Set the appropriate workflow action to the contentlet
contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY,
schemeStepActionResult.getAction().getId());
contentlet1.setStringProperty("title", "Test Save");
contentlet1.setStringProperty("txt", "Test Save Text");

// Triggering the save content action
WorkflowProcessor processor =
workflowAPI.fireWorkflowPreCheckin(contentlet1, publisher1);
workflowAPI.fireWorkflowPostCheckin(processor);

// The contentlet MUST NOT be live yet, it needs one more approval
final Contentlet contentlet2 = contentletAPI
.findContentletByIdentifier(contentlet1.getIdentifier(),
false, languageId, systemUser, false);
Assert.assertFalse("The contentlet cannot be live, it needs 1 more approver.",
contentlet2.isLive());

// Cleanup
contentletAPI.delete(contentlet2, systemUser, false);
}

@Test
public void unauthorizedUserTriggeringWorkflowAction()
throws DotSecurityException, DotDataException {
// Create a contentlet first and save it
final long languageId = languageAPI.getDefaultLanguage().getId();
final Contentlet cont = new Contentlet();
cont.setContentTypeId(type.id());
cont.setOwner(APILocator.systemUser().toString());
cont.setModDate(new Date());
cont.setLanguageId(languageId);
cont.setStringProperty("title", "4-Eye Approval Test Title");
cont.setStringProperty("txt", "4-Eye Approval Test Text");
cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797");
cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d");
final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false);
Assert.assertFalse("The contentlet cannot be live, it has just been created.",
contentlet1.isLive());

contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY,
schemeStepActionResult.getAction().getId());
contentlet1.setStringProperty("title", "Test Save");
contentlet1.setStringProperty("txt", "Test Save Text");

// Expect the correct 'user cannot read' exception
boolean isErrorExpected = false;
final String expectedErrorMsg = "User Joe Contributor : dotcms.org.2789 cannot read action action1";
try {
// Triggering the save content action with a non-authorized user
User incorrectUser = userAPI.getUsersByNameOrEmailOrUserID("[email protected]", 0, 1).get(0);
workflowAPI.fireWorkflowPreCheckin(contentlet1, incorrectUser);
} catch (Exception e) {
// Get the expected error message that validates if user can use the workflow action
final String errorMsg = e.getCause().getCause().getMessage();
isErrorExpected = expectedErrorMsg.equalsIgnoreCase(errorMsg);
}

// Cleanup
contentletAPI.delete(contentlet1, systemUser, false);

Assert.assertTrue(
"The root cause of the exception IS NOT the expected error. Please check this test.",
isErrorExpected);
}

/**
* Remove the content type and workflows created
* Removes the test contentlet, workflow, and content type.
*/
@AfterClass
public static void cleanup()
throws DotDataException, DotSecurityException, AlreadyExistException {
try {
if (null != contentlet) {
contentletAPI.delete(contentlet, APILocator.systemUser(), false);
contentletAPI.delete(contentlet, systemUser, false);
}
} finally {
try {
Expand Down
Loading

0 comments on commit 6b81895

Please sign in to comment.