| Current File : /home/jvzmxxx/wiki1/extensions/Flow/tests/phpunit/PostRevisionTestCase.php |
<?php
namespace Flow\Tests;
use DeferredUpdates;
use Flow\Collection\PostCollection;
use Flow\Container;
use Flow\Data\ManagerGroup;
use Flow\Exception\FlowException;
use Flow\Model\AbstractRevision;
use Flow\Model\PostRevision;
use Flow\Model\TopicListEntry;
use Flow\Model\Workflow;
use Flow\Model\UserTuple;
use Flow\Model\UUID;
use Flow\OccupationController;
use SplQueue;
use User;
/**
* @group Flow
* @group Database
*/
class PostRevisionTestCase extends FlowTestCase {
protected $tablesUsed = array(
'flow_revision',
'flow_topic_list',
'flow_tree_node',
'flow_tree_revision',
'flow_workflow',
'page',
'revision',
'text',
);
/**
* @var PostRevision[]
*/
protected $revisions = array();
/**
* @var Workflow[]
*/
protected $workflows = array();
protected function setUp() {
parent::setUp();
// Revisions must be blanked here otherwise phpunit run with --repeat will remember
// ths revision list between multiple invocations of the test causing issues.
$this->revisions = array();
}
/**
* Reset the container and with it any state
*/
protected function tearDown() {
parent::tearDown();
foreach ( $this->revisions as $revision ) {
try {
$workflow = $revision->getCollection()->getWorkflow();
$this->getStorage()->multiRemove( array( $revision ), array( 'workflow' => $workflow ) );
} catch ( \MWException $e ) {
// ignore - lifecyclehandlers may cause issues with tests, where
// not all related stuff is loaded
}
}
foreach ( $this->workflows as $workflow ) {
try {
$this->getStorage()->multiRemove( array( $workflow ) );
$found = $this->getStorage()->find( 'TopicListEntry', array( 'topic_id' => $workflow->getId() ) );
if ( $found ) {
$this->getStorage()->multiRemove( $found );
}
} catch ( FlowException $e ) {
// nothing, was probably never stored...
}
}
// Needed because not all cases do the reset in setUp yet
Container::reset();
}
/**
* @return ManagerGroup
*/
protected function getStorage() {
return Container::get( 'storage' );
}
/**
* Returns an array, representing flow_revision & flow_tree_revision db
* columns.
*
* You can pass in arguments to override default data.
* With no arguments tossed in, default data (resembling a newly-created
* topic title) will be returned.
*
* @param array[optional] $row DB row data (only specify override columns)
* @return array
*/
protected function generateRow( array $row = array() ) {
$workflow = $this->generateWorkflow( array( 'workflow_type' => 'topic' ) );
$uuidRevision = UUID::create();
$user = User::newFromName( 'UTSysop' );
$tuple = UserTuple::newFromUser( $user );
return $row + array(
// flow_revision
'rev_id' => $uuidRevision->getBinary(),
'rev_type' => 'post',
'rev_type_id' => $workflow->getId()->getBinary(),
'rev_user_wiki' => $tuple->wiki,
'rev_user_id' => $tuple->id,
'rev_user_ip' => $tuple->ip,
'rev_parent_id' => null,
'rev_flags' => 'html',
'rev_content' => 'test content',
'rev_change_type' => 'new-topic',
'rev_mod_state' => AbstractRevision::MODERATED_NONE,
'rev_mod_user_wiki' => null,
'rev_mod_user_id' => null,
'rev_mod_user_ip' => null,
'rev_mod_timestamp' => null,
'rev_mod_reason' => null,
'rev_last_edit_id' => null,
'rev_edit_user_wiki' => null,
'rev_edit_user_id' => null,
'rev_edit_user_ip' => null,
'rev_content_length' => 0,
'rev_previous_content_length' => 0,
// flow_tree_revision
'tree_rev_descendant_id' => $workflow->getId()->getBinary(),
'tree_rev_id' => $uuidRevision->getBinary(),
'tree_orig_user_wiki' => $tuple->wiki,
'tree_orig_user_id' => $tuple->id,
'tree_orig_user_ip' => $tuple->ip,
'tree_parent_id' => null,
);
}
/**
* Populate a fake workflow in the unittest database
*
* @param array $row
* @return Workflow
*/
protected function generateWorkflow( $row = array() ) {
$row = $row + array(
'workflow_id' => UUID::create()->getBinary(),
'workflow_type' => 'topic',
'workflow_wiki' => wfWikiID(),
// The test workflow has no real associated page, this is
// just a random page number
'workflow_page_id' => 1,
'workflow_namespace' => NS_USER_TALK,
'workflow_title_text' => 'Test',
'workflow_lock_state' => 0,
'workflow_last_update_timestamp' => wfTimestampNow(),
);
$workflow = Workflow::fromStorageRow( $row );
// store workflow:
// * so we can retrieve it should we want to store it (see store())
// * so we can remove it on tearDown
$this->workflows[$workflow->getId()->getAlphadecimal()] = $workflow;
return $workflow;
}
/**
* Returns a PostRevision object.
*
* You can pass in arguments to override default data.
* With no arguments tossed in, a default revision (resembling a newly-
* created topic title) will be returned.
*
* @param array[optional] $row DB row data (only specify override columns)
* @param array[optional] $children Array of child PostRevision objects
* @param int[optional] $depth Depth of the PostRevision object
* @return PostRevision
*/
protected function generateObject( array $row = array(), $children = array(), $depth = 0 ) {
$row = $this->generateRow( $row );
$revision = PostRevision::fromStorageRow( $row );
$revision->setChildren( $children );
$revision->setDepth( $depth );
return $revision;
}
/**
* Saves a PostRevision to storage.
* Be sure to add the required tables to $tablesUsed and add @group Database
* to the class' phpDoc.
*
* @param PostRevision $revision
*/
protected function store( PostRevision $revision ) {
if ( $revision->isTopicTitle() ) {
$root = $revision;
} else {
/** @var PostCollection $parentCollection */
$parentCollection = PostCollection::newFromId( $revision->getReplyToId() );
$root = $parentCollection->getRoot()->getLastRevision();
}
$topicWorkflow = $this->workflows[$root->getCollectionId()->getAlphadecimal()];
$boardWorkflow = Container::get( 'factory.loader.workflow' )
->createWorkflowLoader( $topicWorkflow->getOwnerTitle() )
->getWorkflow();
$metadata = array(
'workflow' => $topicWorkflow,
'board-workflow' => $boardWorkflow,
// @todo: Topic.php also adds 'topic-title'
);
// check if this topic (+ workflow + board workflow + board page) have
// already been inserted or do so now
$found = $this->getStorage()->find( 'TopicListEntry', array( 'topic_id' => $topicWorkflow->getId() ) );
if ( !$found ) {
$title = $boardWorkflow->getOwnerTitle();
$user = User::newFromName( '127.0.0.1', false );
/** @var OccupationController $occupationController */
$occupationController = Container::get( 'occupation_controller' );
// make sure user has rights to create board
$user->mRights = array_merge( $user->getRights(), array( 'flow-create-board' ) );
$occupationController->safeAllowCreation( $title, $user );
$occupationController->ensureFlowRevision( new \Article( $title ), $boardWorkflow );
$topicListEntry = TopicListEntry::create( $boardWorkflow, $topicWorkflow );
$this->getStorage()->put( $boardWorkflow, $metadata );
$this->getStorage()->put( $topicWorkflow, $metadata );
$this->getStorage()->put( $topicListEntry, $metadata );
}
$this->getStorage()->put( $revision, $metadata );
/** @var SplQueue $deferredQueue */
$deferredQueue = Container::get( 'deferred_queue' );
while( !$deferredQueue->isEmpty() ) {
try {
DeferredUpdates::addCallableUpdate( $deferredQueue->dequeue() );
// doing updates 1 by 1 so an exception doesn't break others in
// the queue
DeferredUpdates::doUpdates();
} catch ( \MWException $e ) {
// ignoring exceptions for now, not all are phpunit-proof yet
}
}
// save for removal at end of tests
$this->revisions[] = $revision;
}
protected function clearExtraLifecycleHandlers() {
$container = Container::getContainer();
foreach( array_unique( $container['storage.manager_list'] ) as $storage ) {
if ( !isset( $container["$storage.listeners"] ) ) {
continue;
}
$container->extend( "$storage.listeners", function( $listeners ) {
unset(
// putting together the right metadata for a commit is beyond the
// scope of these tests
$listeners['listeners.notification'],
// Recent changes logging is outside the scope of tests, and
// causes interaction issues
$listeners['listener.recentchanges'],
// BoardHistory requires we also wire together TopicListEntry objects for
// each revision, but that's also beyond our scope.
$listeners['storage.post_board_history.indexes.primary']
);
return $listeners;
} );
}
}
}