ContentControllerTest.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • application/
  • workflow/
  • tests/
  • ContentControllerTest.php
  • View
  • Commits
  • Open Download .zip Download (16 KB)
<?php
/**
 * Test the workflow content controller.
 *
 * @copyright   2012 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 */
class Workflow_Test_ContentControllerTest extends ModuleControllerTest
{
    /**
     * Test successful changing workflow state on multiple entries.
     */
    public function testChangeStateSuccess()
    {
        $this->utility->impersonate('administrator');

        // create workflows, content types and entries
        $this->_createWorkflowsAndTypes(3);

        // change workflow state to review on some entries
        $ids = array('simple1', 'simple3');

        // dispatch
        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'workflows' => array('simple'),
                'ids'       => $ids,
                'state'     => 'review',
                'scheduled' => 'false'
            )
        );
        $this->dispatch('/workflow/content/change-state/format/json');

        $this->assertModule('workflow', __LINE__ .': Last module run should be workflow module.');
        $this->assertController('content', __LINE__ .': Expected controller');
        $this->assertAction('change-state', __LINE__ .': Expected action');

        // verify json response
        $this->_verifyChangeStateJsonResponse($ids);

        // verify all entries have given workflow state and they have been changes in one chagelist
        $this->_verifyEntriesWorkflow($ids, 'review');

        // change workflow state to published for contents of simple and basic type
        $this->resetRequest()->resetResponse();
        $ids = $this->_getContentsByType(array('simple', 'basic'))->invoke('getId');

        // dispatch
        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'workflows' => array('simple', 'basic'),
                'ids'       => $ids,
                'state'     => 'published',
                'scheduled' => 'false'
            )
        );
        $this->dispatch('/workflow/content/change-state/format/json');

        $this->assertModule('workflow', __LINE__ .': Last module run should be workflow module.');
        $this->assertController('content', __LINE__ .': Expected controller');
        $this->assertAction('change-state', __LINE__ .': Expected action');

        // verify json response
        $this->_verifyChangeStateJsonResponse($ids);

        // verify all entries have given workflow state and they have been changes in one chagelist
        $this->_verifyEntriesWorkflow($ids, 'published');
    }

    /**
     * Test changing workflow state on multiple entries with some entries not under workflow.
     */
    public function testChangeStateNoWorkflow()
    {
        $this->utility->impersonate('administrator');

        // create workflows, content types and entries
        $this->_createWorkflowsAndTypes(1);

        // change workflow state to review for contents of simple and basic type
        $ids = array('simple1', 'no-workflow1');

        // dispatch
        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'workflows' => array('simple'),
                'ids'       => $ids,
                'state'     => 'review',
                'scheduled' => 'false'
            )
        );
        $this->dispatch('/workflow/content/change-state/format/json');

        $this->assertModule('workflow', __LINE__ .': Last module run should be workflow module.');
        $this->assertController('content', __LINE__ .': Expected controller');
        $this->assertAction('change-state', __LINE__ .': Expected action');

        $response = Zend_Json::decode($this->response->getBody());

        // verify json response
        $this->_verifyChangeStateJsonResponse(array(), array('no-workflow1'));

        // ensure simple1 has not been changed
        $entry          = P4Cms_Content::fetch('simple1');
        $simpleWorkflow = Workflow_Model_Workflow::fetchByContent($entry);
        $this->assertSame(
            'draft',
            $simpleWorkflow->getStateOf($entry)->getId(),
            "Expected state of the simple1 entry."
        );
    }

    /**
     * Test changing workflow state on multiple entries where not all entries can be changed.
     */
    public function testChangeStateFail()
    {
        $this->utility->impersonate('administrator');

        // create workflows, content types and entries
        $this->_createWorkflowsAndTypes(3);

        // change workflow state to published on entries of simple and private type
        // this should not work as draft->published transition in private workflow is
        // not allowed due to a 'False' condition
        $ids = $this->_getContentsByType(array('simple', 'private'))->invoke('getId');

        // dispatch
        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'workflows' => array('simple', 'private'),
                'ids'       => $ids,
                'state'     => 'published',
                'scheduled' => 'false'
            )
        );
        $this->dispatch('/workflow/content/change-state/format/json');

        $this->assertModule('workflow', __LINE__ .': Last module run should be workflow module.');
        $this->assertController('content', __LINE__ .': Expected controller');
        $this->assertAction('change-state', __LINE__ .': Expected action');

        $response = Zend_Json::decode($this->response->getBody());

        // verify json response
        $this->_verifyChangeStateJsonResponse(
            array(),
            $this->_getContentsByType('private')->invoke('getId')
        );

        // ensure simple entries were not changed
        $simpleWorkflow = Workflow_Model_Workflow::fetch('simple');
        foreach ($this->_getContentsByType('simple') as $entry) {
            $this->assertSame(
                'draft',
                $simpleWorkflow->getStateOf($entry)->getId(),
                "Expected simple entries were not changed."
            );
        }
    }

    /**
     * Test changing workflow state on multiple entries with using 'forced' parameter.
     */
    public function testChangeStateForce()
    {
        $this->utility->impersonate('administrator');

        // create workflows, content types and entries
        $this->_createWorkflowsAndTypes(3);

        // change workflow state to published on entries of simple and private type by force
        // it should change only entries of simple type and leave untouched entries of private
        // type
        $ids = $this->_getContentsByType(array('simple', 'private'))->invoke('getId');

        // dispatch
        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'workflows' => array('simple', 'private'),
                'ids'       => $ids,
                'state'     => 'published',
                'scheduled' => 'false'
            )
        );
        $this->dispatch('/workflow/content/change-state/format/json/forced/true');

        $this->assertModule('workflow', __LINE__ .': Last module run should be workflow module.');
        $this->assertController('content', __LINE__ .': Expected controller');
        $this->assertAction('change-state', __LINE__ .': Expected action');

        $response       = Zend_Json::decode($this->response->getBody());
        $simpleEntries  = $this->_getContentsByType('simple');
        $privateEntries = $this->_getContentsByType('private');

        // verify json response
        $this->_verifyChangeStateJsonResponse(
            $simpleEntries->invoke('getId'),
            array()
        );

        // ensure simple entries were changed (in a single change)
        $this->_verifyEntriesWorkflow($simpleEntries->invoke('getId'), 'published');

        // ensure private entries were not changed
        $privateWorkflow = Workflow_Model_Workflow::fetch('private');
        foreach ($privateEntries as $entry) {
            $this->assertSame(
                'draft',
                $privateWorkflow->getStateOf($entry)->getId(),
                "Expected private entries were not changed."
            );
        }
    }

    /**
     * Helper function to return list of entries having given content type(s).
     *
     * @param   string|array    $types  list of content types
     * @return  P4Cms_Model_Iterator    list of entries having given content type(s)
     */
    public function _getContentsByType($types)
    {
        $types  = array ($types);

        // create record filter to keep only entries with given types
        $filter = new P4Cms_Record_Filter;
        foreach ($types as $type) {
            $filter->add(
                'contentType',
                $type,
                P4Cms_Record_Filter::COMPARE_EQUAL,
                P4Cms_Record_Filter::CONNECTIVE_OR
            );
        }

        $query = P4Cms_Record_Query::create()->addFilter($filter);
        return P4Cms_Content::fetchAll($query);
    }

    /**
     * Helper function to verify json response of changed-state action.
     *
     * @param   array       $changedEntries     list of expected entry ids that have been changed
     * @param   array       $failedEntries      list of expected entry ids that have failed
     * @param   string|null $errors             expected errors
     */
    public function _verifyChangeStateJsonResponse(
        array $changedEntries, array $failedEntries = array(), $errors = null
    )
    {
        $response = Zend_Json::decode($this->response->getBody());
        $this->assertSame(
            $changedEntries,
            $response['changedEntries'],
            "Expected list of changed entries."
        );
        $this->assertSame(
            $failedEntries,
            $response['failedEntries'],
            "Expected list of failed entries."
        );
        $this->assertSame(
            $errors,
            $response['errors'],
            "Expected errors message."
        );
    }

    /**
     * Helper function, verify that all given entries (specified by their ids)
     * have given workflow state. Also verifies, that they have been submitted
     * in one change list.
     *
     * @param   array       $entryIds           list with entry ids to verify
     * @param   string      $state              workflow state assumed to be the current
     *                                          entries state of workflow
     * @param   string|null $scheduledState     optional, workflow state assumed to be
     *                                          scheduled for the entries, if null then
     *                                          it won't be checked
     * @param   string|null $scheduledTime      optional, timestamp of scheduled transition
     *                                          for given entries
     */
    public function _verifyEntriesWorkflow(
        array $entryIds, $state, $scheduledState = null, $scheduledTime = null
    )
    {
        $workflowsByType = Workflow_Model_Workflow::fetchTypeMap();

        // ensure all entries have given state and they have been submitted in the same changelist
        $entryChanges = array();
        $entries      = P4Cms_Content::fetchAll(array('ids' => $entryIds));
        foreach ($entries as $entry) {
            $type = $entry->getContentTypeId();
            if (!isset($workflowsByType[$type])) {
                $this->fail("Unexpected entry with no workflow.");
            }

            $workflow = $workflowsByType[$type];
            $this->assertSame(
                $state,
                $workflow->getStateOf($entry)->getId(),
                "Expected entry has '$state' workflow state."
            );

            if ($scheduledState) {
                $this->assertSame(
                    $scheduledState,
                    $workflow->getScheduledStateOf($entry)->getId(),
                    "Expected entry has '$scheduledState' as scheduled workflow state."
                );
            }

            if ($scheduledTime) {
                $this->assertSame(
                    $scheduledTime,
                    $workflow->getScheduledTimeOf($entry),
                    "Expected scheduled time of the scheduled workflow transition."
                );
            }

            $entryChanges[] = $entry->toP4File()->getChange()->getId();
        }

        // ensure that entryChangelist contains just one unique value
        $this->assertSame(
            1,
            count(array_unique($entryChanges)),
            "Expected all entries have been submitted in the same changelist."
        );
    }

    /**
     * Helper function, creates workflows, content types (one for each workflow +
     * one with no workflow) and optionally specified number of entries for each
     * content type, ids are derived from content type ids with appended number 1
     * to <number of entries>.
     *
     * @param   int $entriesPerType     optional, number entries to create for each
     *                                  content type
     */
    protected function _createWorkflowsAndTypes($entriesPerType = 0)
    {
        // create workflows with following states (and labels):
        //  simple  : draft (Draft), review (Review), published (Published)
        //  basic   : draft (Preliminary), published (Live)
        //  private : draft (Private), published (Public), unable to transit from draft to published
        Workflow_Model_Workflow::store(
            array(
                'id'        => 'simple',
                'states'    => "
[draft]
label = 'Draft'
transitions.review.label = 'Promote to reviw'
transitions.published.label = 'Publish'

[review]
label = 'Review'
transitions.draft.label = 'Demote to Draft'
transitions.published.label = 'Publish'

[published]
label = 'Published'
transitions.review.label = 'Demote to Review'
transitions.draft.label = 'Demote to Draft'"
            )
        );

        Workflow_Model_Workflow::store(
            array(
                'id'        => 'basic',
                'states'    => "
[draft]
label = 'Preliminary'
transitions.published.label = 'Go Live'

[published]
label = 'Live'
transitions.draft.label = 'Demote to Preliminary'"
            )
        );

        Workflow_Model_Workflow::store(
            array(
                'id'        => 'private',
                'states'    => "
[draft]
label = 'Private'
transitions.published.label = 'Publish'
transitions.published.conditions[] = 'False'

[published]
label = 'Public'
transitions.draft.label = 'Demote to Private'"
            )
        );

        // create content types, one for each workflow + one with no workflow
        foreach (Workflow_Model_Workflow::fetchAll() as $workflow) {
            P4Cms_Content_Type::store(
                array(
                    'id'        => $workflow->getId(),
                    'elements'  => array(
                        'title' => array(
                            'type'  => 'text'
                        )
                    ),
                    'workflow'  => $workflow->getId()
                )
            );
        }
        P4Cms_Content_Type::store(
            array(
                'id'        => 'no-workflow',
                'elements'  => array(
                    'title' => array(
                        'type'  => 'text'
                    )
                )
            )
        );

        // create content
        if ($entriesPerType) {
            $entry = P4Cms_Content::create(
                array('title' => 'test')
            );

            foreach (P4Cms_Content_Type::fetchAll() as $type) {
                $typeId = $type->getId();
                $entry->setContentType($typeId);
                for ($i = 1; $i <= $entriesPerType; $i++) {
                    $entry->setId($typeId . $i);
                    $entry->save();
                }
            }
        }
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/application/workflow/tests/ContentControllerTest.php
#1 8972 Matt Attaway Initial add of the Chronicle source code