Perforce Chronicle 2012.2/486814
API Documentation
|
Test the workflow model. More...
Public Member Functions | |
testAccessors () | |
Test accessors. | |
testDetectTransitionOn () | |
Test detectTransitionOn() method. | |
testFetchTypeMap () | |
Verify fetchTypeMap() method outputs correct content-type => workflow mapping. | |
testGetDefaultState () | |
Test getDefaultState() method. | |
testGetSetScheduledData () | |
Test getters/setters for manipulation with scheduled data. | |
testGetSetStateOf () | |
Test (set|get)StateOf() methods. | |
testGetState () | |
Test hasState()/getState()/getStateModel() methods. | |
testInstallRemoveDefaults () | |
Test installation and removal of default workflows. | |
testInvalidTypeIsUnpublished () | |
Verify that content entries with an invalid content type are unpublished. | |
testMakeScheduledContentFilter () | |
Test for makeScheduledContentFilter() method. | |
testMutators () | |
Test mutators. | |
Protected Member Functions | |
_generateWorkflowDefinition (array $stateTransitions) | |
Helper method to generate simplified workflow definition. |
Test the workflow model.
Workflow_Test_WorkflowTest::_generateWorkflowDefinition | ( | array $ | stateTransitions | ) | [protected] |
Helper method to generate simplified workflow definition.
array | $stateTransitions | list with state transitions |
{ $definition = array(); foreach ($stateTransitions as $state => $transitions) { $data = array( 'label' => "$state state", ); foreach ($transitions as $transition) { $data['transitions'][$transition] = array( 'label' => "$state to $transition" ); } $definition['states'][$state] = $data; } return $definition; }
Workflow_Test_WorkflowTest::testAccessors | ( | ) |
Test accessors.
{ // add workflow record $modelData = array( 'id' => "test", 'label' => "test label", 'description' => "test description", 'states' => "[foo]\nlabel=foo state\n[bar]\nlabel=bar state" ); Workflow_Model_Workflow::store($modelData); // fetch saved workflow $workflow = Workflow_Model_Workflow::fetch('test'); $this->assertSame( $modelData['label'], $workflow->getLabel(), "Expected workflow label name." ); $this->assertSame( $modelData['description'], $workflow->getDescription(), "Expected workflow description." ); $this->assertSame( $modelData['states'], $workflow->getStatesAsIni(), "Expected workflow states in INI." ); // getStates() should return array of state definitions $states = $workflow->getStates(); $this->assertTrue( is_array($states), "Expected array returned by getState() method." ); // getStateModels() should return iterator with workflow state objects $states = $workflow->getStateModels(); $this->assertTrue( $states instanceof P4Cms_Model_Iterator, "Expected class type returned by getState() method." ); $this->assertEquals( 2, $states->count(), "Expected number of workflow states." ); foreach ($states as $state) { $this->assertTrue( $state instanceof Workflow_Model_State, "Expected class type of workflow state item." ); } }
Workflow_Test_WorkflowTest::testDetectTransitionOn | ( | ) |
Test detectTransitionOn() method.
{ // create workflow with states a, b, c allowing following transitions: // a->b, a->c, b->c, c->a $workflow = Workflow_Model_Workflow::create( $this->_generateWorkflowDefinition( array( 'a' => array('b', 'c'), 'b' => array('c'), 'c' => array('a') ) ) ); // create content type $type = P4Cms_Content_Type::store( array( 'id' => 'ct', 'elements' => array( 'title' => array('type' => 'text') ) ) ); // define tests suite $tests = array( array( 'savedValues' => array( 'contentType' => $type->getId(), ), 'changedValues' => array( 'workflowState' => 'a' ), 'expected' => null, 'message' => __LINE__ . ": invalid from state, valid to state." ), array( 'savedValues' => array( 'contentType' => $type->getId(), 'workflowState' => 'a' ), 'changedValues' => array( 'workflowState' => 'unknown' ), 'expected' => null, 'message' => __LINE__ . ": valid from state, invalid to state." ), array( 'savedValues' => array( 'contentType' => $type->getId(), 'workflowState' => 'notvalid' ), 'changedValues' => array( 'workflowState' => 'unknown' ), 'expected' => null, 'message' => __LINE__ . ": invalid from state, invalid to state." ), array( 'savedValues' => array( 'contentType' => $type->getId(), 'workflowState' => 'a' ), 'changedValues' => array( 'workflowState' => 'b' ), 'expected' => 'a to b', 'message' => __LINE__ . ": valid transiton a -> b." ), array( 'savedValues' => array( 'contentType' => $type->getId(), 'workflowState' => 'a' ), 'changedValues' => array( 'workflowState' => 'a' ), 'expected' => null, 'message' => __LINE__ . ": same from- and to states." ) ); // run tests foreach ($tests as $test) { // create content $content = P4Cms_Content::store($test['savedValues']); // modify record values and save while in batch $adapter = $content->getAdapter(); $adapter->beginBatch('test'); $content->setValues($test['changedValues']); $content->save(); // detect transition $transition = $workflow->detectTransitionOn($content); // get transition label if transition is object if ($transition instanceof Workflow_Model_Transition) { $transition = $transition->getLabel(); } // verify transition $this->assertSame( $test['expected'], $transition, $test['message'] ); $adapter->revertBatch(); } }
Workflow_Test_WorkflowTest::testFetchTypeMap | ( | ) |
Verify fetchTypeMap() method outputs correct content-type => workflow mapping.
{ // add few workflows $workflowX = Workflow_Model_Workflow::store( array( 'id' => "workflow-x", 'label' => "test x", 'states' => "[foo]\na=b" ) ); $workflowY = Workflow_Model_Workflow::store( array( 'id' => "workflow-y", 'label' => "test y", 'states' => "[foo]\na=b" ) ); // add few content types P4Cms_Content_Type::store( array( 'id' => "type-a", 'elements' => "[id]\ntype=text", 'workflow' => "workflow-x" ) ); P4Cms_Content_Type::store( array( 'id' => "type-b", 'elements' => "[id]\ntype=text" ) ); P4Cms_Content_Type::store( array( 'id' => "type-c", 'elements' => "[id]\ntype=text", 'workflow' => "workflow-y" ) ); P4Cms_Content_Type::store( array( 'id' => "type-d", 'elements' => "[id]\ntype=text", 'workflow' => "workflow-x" ) ); $map = Workflow_Model_Workflow::fetchTypeMap(); $expected = array( 'type-a' => $workflowX->toArray(), 'type-c' => $workflowY->toArray(), 'type-d' => $workflowX->toArray(), ); $this->assertTrue( $map instanceof P4Cms_Model_Iterator, "Expected map instance type." ); $this->assertSame( $expected, $map->toArray(), "Expected map array structure." ); }
Workflow_Test_WorkflowTest::testGetDefaultState | ( | ) |
Test getDefaultState() method.
{ Workflow_Model_Workflow::store( array( 'id' => "test1", 'label' => "test label", 'states' => "[first]\n[second]\n[third]\n" ) ); $defaultState = Workflow_Model_Workflow::fetch('test1')->getDefaultState(); $this->assertTrue( $defaultState instanceof Workflow_Model_State, "Expected class type of default state #1." ); $this->assertSame( 'first', $defaultState->getId(), "Expected id of the default state #1." ); Workflow_Model_Workflow::store( array( 'id' => "test2", 'label' => "test label", 'description' => "test description", 'states' => "[one]\ntwo=2\n[two]one=1\ntwo=2" ) ); $defaultState = Workflow_Model_Workflow::fetch('test2')->getDefaultState(); $this->assertTrue( $defaultState instanceof Workflow_Model_State, "Expected class type of default state #2." ); $this->assertSame( 'one', $defaultState->getId(), "Expected id of the default state #2." ); }
Workflow_Test_WorkflowTest::testGetSetScheduledData | ( | ) |
Test getters/setters for manipulation with scheduled data.
{ $this->utility->impersonate('editor'); // create workflow states a,b,c and with transitions a->b, a->c, b->c $workflow = Workflow_Model_Workflow::create( $this->_generateWorkflowDefinition( array( 'a' => array('b', 'c'), 'b' => array('c'), 'c' => array() ) ) ); $record = P4Cms_Content::store( array( 'id' => 1, 'contentType' => 'test', 'workflowState' => 'a' ) ); // ensure exception is thrown when try to set invalid scheduled state try { $workflow->setScheduledStateOf($record, 'none', 123); } catch (Workflow_Exception $e) { // expected exception $this->assertSame( "Cannot set state on the given record. State is undefined or governed by other workflow.", $e->getMessage(), "Expected invalid state exception" ); } catch (Exception $e) { $this->fail("Unexpected exception thrown."); } // prepare timestamp points to the future $time = time() + 10; // ensure exception is thrown when timestamp has invalid format try { $workflow->setScheduledStateOf($record, 'b', "$time"); } catch (InvalidArgumentException $e) { // expected exception $this->assertSame( "Cannot schedule transition. Time must be an integer timestamp in the future.", $e->getMessage(), "Expected invalid timestamp exception" ); } catch (Exception $e) { $this->fail("Unexpected exception thrown."); } try { $workflow->setScheduledStateOf($record, 'b', -1); } catch (InvalidArgumentException $e) { // expected exception $this->assertSame( "Cannot schedule transition. Time must be an integer timestamp in the future.", $e->getMessage(), "Expected invalid timestamp exception" ); } catch (Exception $e) { $this->fail("Unexpected exception thrown."); } // set valid scheduled transition $workflow->setScheduledStateOf($record, 'b', $time); $record->save(); $record->fetch(1); $this->assertSame('a', $workflow->getStateOf($record)->getId(), 'Expected current state'); $this->assertSame('b', $workflow->getScheduledStateOf($record)->getId(), 'Expected scheduled state'); $this->assertSame($time, $workflow->getScheduledTimeOf($record), 'Expected scheduled time'); }
Workflow_Test_WorkflowTest::testGetSetStateOf | ( | ) |
Test (set|get)StateOf() methods.
{ // create workflow states a,b,c and with transitions a->b, a->c, b->c $workflow = Workflow_Model_Workflow::create( $this->_generateWorkflowDefinition( array( 'a' => array('b', 'c'), 'b' => array('c'), 'c' => array() ) ) ); // create content type $type = P4Cms_Content_Type::store( array( 'id' => 'test', 'elements' => array( 'title' => array('type' => 'text') ) ) ); $record = P4Cms_Content::create( array( 'contentType' => 'test', 'workflowState' => 'b' ) ); // ensure exception is thrown when try to set invalid state try { $workflow->setStateOf($record, 'none'); } catch (Workflow_Exception $e) { // expected exception $this->assertSame( "Cannot set state on the given record. State is undefined or governed by other workflow.", $e->getMessage(), "Expected invalid state exception" ); } catch (Exception $e) { $this->fail("Unexpected exception thrown."); } $this->assertSame( 'b', $workflow->getStateOf($record)->getId(), "Expected current state." ); // ensure exception is thrown when invalid transition try { $workflow->setStateOf($record, 'a'); } catch (Workflow_Exception $e) { // expected exception $this->assertSame( "Cannot set state on the given record. Not a valid transition.", $e->getMessage(), "Expected invalid transition exception" ); } catch (Exception $e) { $this->fail("Unexpected exception thrown."); } $this->assertSame( 'b', $workflow->getStateOf($record)->getId(), "Expected current state." ); // set valid state $workflow->setStateOf($record, 'c'); $this->assertSame( 'c', $workflow->getStateOf($record)->getId(), "Expected current state." ); }
Workflow_Test_WorkflowTest::testGetState | ( | ) |
Test hasState()/getState()/getStateModel() methods.
{ Workflow_Model_Workflow::store( array( 'id' => "test", 'label' => "test label", 'description' => "test description", 'states' => "[foo]\na=b\n[bar]a.1=c\na.2=de\nx=yz" ) ); $workflow = Workflow_Model_Workflow::fetch('test'); $this->assertTrue( $workflow->hasState('foo'), "Expected 'foo' is one of the workflow states." ); $this->assertSame( array('a' => 'b'), $workflow->getState('foo'), "Expected value returned for getState('foo')." ); $this->assertTrue( $workflow->getStateModel('foo') instanceof Workflow_Model_State, "Expected class type of 'foo' state model." ); $this->assertTrue( $workflow->hasState('bar'), "Expected 'bar' is one of the workflow states." ); $this->assertSame( array('a' => array (1 => 'c', 2 => 'de'), 'x' => 'yz'), $workflow->getState('bar'), "Expected value returned for getState('bar')." ); $this->assertTrue( $workflow->getStateModel('bar') instanceof Workflow_Model_State, "Expected class type of 'bar' state model." ); $this->assertFalse( $workflow->hasState('noexist'), "Expected 'noexist' is not one of the workflow states." ); try { $workflow->getState('noexist'); $this->fail('Expected throwing an exception when tried to get non-existent state.'); } catch (Workflow_Exception $e) { // expected exception } try { $workflow->getStateModel('noexist'); $this->fail('Expected throwing an exception when tried to get non-existent state model.'); } catch (Workflow_Exception $e) { // expected exception } }
Workflow_Test_WorkflowTest::testInstallRemoveDefaults | ( | ) |
Test installation and removal of default workflows.
{ $this->assertSame( 0, Workflow_Model_Workflow::count(), "Expected no workflows yet." ); $package = P4Cms_Module::fetch('workflow'); Workflow_Model_Workflow::installPackageDefaults($package); $this->assertSame( 1, Workflow_Model_Workflow::count(), "Expected one workflow." ); // ensure workflow has id 'simple'. $this->assertTrue(Workflow_Model_Workflow::exists('simple')); // verify installed workflow has three states: // Draft, Review, Published $workflow = Workflow_Model_Workflow::fetch('simple'); $this->assertSame( $workflow->getStateModels()->invoke('getLabel'), array('Draft', 'Review', 'Published') ); // remove defaults. Workflow_Model_Workflow::removePackageDefaults($package); $this->assertFalse(Workflow_Model_Workflow::exists('simple')); // ensure workflow is not removed if it was edited. Workflow_Model_Workflow::installPackageDefaults($package); $workflow = Workflow_Model_Workflow::fetch('simple'); $workflow->setLabel('modified')->save(); Workflow_Model_Workflow::removePackageDefaults($package); $this->assertTrue(Workflow_Model_Workflow::exists('simple')); }
Workflow_Test_WorkflowTest::testInvalidTypeIsUnpublished | ( | ) |
Verify that content entries with an invalid content type are unpublished.
{ P4Cms_Content::store( array( 'contentType' => 'made-up', 'title' => 'so fake', 'workflowState' => Workflow_Model_State::PUBLISHED ) ); $this->assertSame( 0, P4Cms_Content::count(), 'expected no hits when type does not exist' ); // now add the type and try it with only the workflow missing $type = new P4Cms_Content_Type; $type->setId('made-up') ->setValue('workflow', 'fake') ->save(); $this->assertSame( 0, P4Cms_Content::count(), 'expected no hits when workflow does not exist' ); // try with all items but no published state $workflow = new Workflow_Model_Workflow; $workflow->setId('fake') ->setValues($this->_generateWorkflowDefinition(array('draft' => array('review')))) ->save(); $this->assertSame( 0, P4Cms_Content::count(), 'expected no hits when workflow does not have a published state' ); // test it works when we have a published state $workflow->setValues($this->_generateWorkflowDefinition(array('published' => array('super-published')))) ->save(); $this->assertSame( 1, P4Cms_Content::count(), 'expected a hit when everything is in place' ); }
Workflow_Test_WorkflowTest::testMakeScheduledContentFilter | ( | ) |
Test for makeScheduledContentFilter() method.
{ // these are unpublished entries, impersonate an editor so we can see them $this->utility->impersonate('editor'); // create testing entries // +---------------+--------------+-----------------+-------------------+ // | CONTENT TITLE | STATE | SCHEDULED STATE | SCHEDULED TIME | // +---------------+--------------+-----------------+-------------------+ // | a | draft | review | 1. 1.2010 12:00 | // | b | draft | published | 1. 2.2010 15:00 | // | c | draft | review | 1. 1.2011 12:00 | // | d | draft | - | 31.12.2009 23:00 | // | e | draft | published | - | // | f | draft | - | - | // | g | draft | review | 2. 1.2011 12:00 | // | h | - | published | 2. 1.2012 12:00 | // +---------------+--------------+-----------------+-------------------+ $entries = array( array('a', 'draft', 'review', strtotime('2010-01-01 12:00')), array('b', 'draft', 'published', strtotime('2010-02-01 15:00')), array('c', 'draft', 'review', strtotime('2011-01-01 12:00')), array('d', 'draft', '', strtotime('2009-12-31 23:00')), array('e', 'draft', 'published', ''), array('f', 'draft', '', ''), array('g', 'draft', 'review', strtotime('2011-01-02 12:00')), array('h', '', 'published', strtotime('2012-01-02 12:00')), ); // make a test workflow and type $workflow = Workflow_Model_Workflow::store( $this->_generateWorkflowDefinition( array('draft' => array('published'), 'published' => array('draft')) ) ); $type = new P4Cms_Content_Type; $type->setId('basic') ->setValue('workflow', $workflow->getId()) ->save(); foreach ($entries as $entry) { P4Cms_Content::store( array( 'contentType' => 'basic', 'title' => $entry[0], 'workflowState' => $entry[1], 'workflowScheduledState' => $entry[2], 'workflowScheduledTime' => $entry[3] ) ); } // get all contents with scheduled transitions before 1999-01-01 00:00 $query = P4Cms_Record_Query::create() ->addFilter( Workflow_Model_Workflow::makeScheduledContentFilter(strtotime('1999-01-01 00:00')) ); $result = P4Cms_Content::fetchAll($query)->sortBy('title')->invoke('getTitle'); $this->assertSame( array(), $result, 'Expected entries filtered by scheduled transitions #1.' ); // get all contents with scheduled transitions before 2010-02-01 14:59 $query = P4Cms_Record_Query::create() ->addFilter( Workflow_Model_Workflow::makeScheduledContentFilter(strtotime('2010-02-01 14:59')) ); $result = P4Cms_Content::fetchAll($query)->sortBy('title')->invoke('getTitle'); $this->assertSame( array('a'), $result, 'Expected entries filtered by scheduled transitions #2.' ); // get all contents with scheduled transitions before 2011-01-01 00:00 $query = P4Cms_Record_Query::create() ->addFilter( Workflow_Model_Workflow::makeScheduledContentFilter(strtotime('2011-01-01 00:00')) ); $result = P4Cms_Content::fetchAll($query)->sortBy('title')->invoke('getTitle'); $this->assertSame( array('a', 'b'), $result, 'Expected entries filtered by scheduled transitions #3.' ); // get all contents with scheduled transitions before 2012-01-01 23:00 $query = P4Cms_Record_Query::create() ->addFilter( Workflow_Model_Workflow::makeScheduledContentFilter(strtotime('2012-01-01 23:00')) ); $result = P4Cms_Content::fetchAll($query)->sortBy('title')->invoke('getTitle'); $this->assertSame( array('a', 'b', 'c', 'g'), $result, 'Expected entries filtered by scheduled transitions #4.' ); // get all contents with scheduled transitions before 2025-01-01 17:45 $query = P4Cms_Record_Query::create() ->addFilter( Workflow_Model_Workflow::makeScheduledContentFilter(strtotime('2025-01-01 17:45')) ); $result = P4Cms_Content::fetchAll($query)->sortBy('title')->invoke('getTitle'); $this->assertSame( array('a', 'b', 'c', 'g', 'h'), $result, 'Expected entries filtered by scheduled transitions #5.' ); }
Workflow_Test_WorkflowTest::testMutators | ( | ) |
Test mutators.
{ $workflow = new Workflow_Model_Workflow(array('id' => 'foo')); $workflow->setLabel('foo label') ->setDescription('foo description') ->save(); // fetch and verify values $values = Workflow_Model_Workflow::fetch('foo')->getValues(); $this->assertSame( 'foo', $values['id'], "Expected workflow id." ); $this->assertSame( 'foo label', $values['label'], "Expected workflow label." ); $this->assertSame( 'foo description', $values['description'], "Expected workflow description." ); $this->assertTrue( is_array($values['states']), "Expected type of states field #1." ); // set states as string in INI format $workflow->setStates("[bar]\nlabel=test") ->save(); // fetch and verify states $values = Workflow_Model_Workflow::fetch('foo')->getValues(); $this->assertTrue( is_array($values['states']), "Expected type of states field #2." ); $this->assertEquals( 1, count($values['states']), "Expected number of workflow states #2." ); // verify that workflow state has reference to workflow $state = $workflow->getStateModels()->current(); $this->assertTrue( $state->getValue('workflow') instanceof Workflow_Model_Workflow, "Expected type of state workflow field #2." ); $this->assertSame( 'foo', $state->getValue('workflow')->getId(), "Expected workflow state references correct workflow instance #2." ); // set states as null $workflow->setStates(null) ->save(); // fetch and verify states $values = Workflow_Model_Workflow::fetch('foo')->getValues(); $this->assertTrue( is_array($values['states']), "Expected type of states field." ); $this->assertSame( array(), $values['states'], "Expected no states." ); // set states as array $statesArray = array( 'bar' => array( 'label' => 'bar state', 'foo' => 'temp' ), 'baz' => array( 'label' => 'bazz' ) ); $workflow->setStates($statesArray) ->save(); // fetch and verify states $values = Workflow_Model_Workflow::fetch('foo')->getValues(); $this->assertTrue( is_array($values['states']), "Expected type of states field #3." ); $this->assertEquals( 2, count($values['states']), "Expected number of workflow states #3." ); // verify that workflow states have reference to workflow foreach ($workflow->getStateModels() as $state) { $this->assertTrue( $state->getValue('workflow') instanceof Workflow_Model_Workflow, "Expected type of state workflow field #3 ({$state->getId()})." ); $this->assertSame( 'foo', $state->getValue('workflow')->getId(), "Expected workflow state references correct workflow instance #3 ({$state->getId()})." ); } }