services_client.test in Services Client 7.2
Tests for the Administration menu module.
File
tests/services_client.testView source
<?php
/**
* @file
* Tests for the Administration menu module.
*/
abstract class ServicesClientBaseWebTestCase extends DrupalWebTestCase {
function setUp() {
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
$modules = array_merge($modules, array(
'ctools',
'services_client_connection',
'services_client',
));
parent::setUp($modules);
variable_set('services_client_id', 'local_id');
ctools_include('export');
$this->admin = $this
->drupalCreateUser(array(
'administer services client',
'skip sending entity',
));
$this->connection = $this
->createSCConnection();
}
/**
* Creates services client connection object.
*
* @param array $connection
* Overrides that will overwrite default configuration.
*
* @return object
* Connection object.
*/
protected function createSCConnection($connection = array()) {
$name = 'fake_connection';
$defaults = array(
'name' => $name,
'admin_title' => $name,
'version' => 3,
'endpoint' => url('services_client', array(
'absolute' => TRUE,
)),
'config' => array(
'auth' => array(
'plugin' => 'ServicesClientConnectionSessionAuth',
'config' => array(
'username' => 'admin',
'password' => 'admin',
'token' => 1,
),
),
'server' => array(
'plugin' => 'ServicesClientConnectionRestServer',
'config' => array(
'request_formatter' => 'json',
'response_parser' => 'json',
),
),
'request' => array(
'plugin' => 'ServicesClientConnectionCurlRequest',
'config' => array(
'request_timeout' => '30',
'ssl_verifypeer_skip' => 1,
),
),
),
'services_client_id' => 'remote_site',
);
$connection = (object) drupal_array_merge_deep($defaults, $connection);
ctools_export_crud_save('services_client_connection', $connection);
return $connection;
}
/**
* Create new services client event.
*
* @return event object.
*/
protected function createSCEvent($event = array()) {
$name = isset($event['name']) ? $event['name'] : 'event';
$this
->drupalPost('admin/structure/services_client/add', $event + array(
'title' => $name,
'name' => $name,
'connection' => 'fake_connection',
'entity_type' => 'node',
'event' => 'save',
'plugin' => 'EntitySaveHandler',
), "Save");
return $this
->loadEvent($name);
}
/**
* Load existing event from storage.
*
* @param string $name
* Name of event.
*
* @return ServicesClientEvent
* Event instance.
*/
protected function loadEvent($name, $reset = FALSE) {
if ($reset) {
$this
->resetEventCache();
}
return ctools_export_crud_load('services_client_connection_event', $name);
}
/**
* Reset ctools load cache.
*/
protected function resetEventCache() {
ctools_export_load_object_reset('services_client_connection_event');
}
/**
* Retrieve plugin UUID from URL. If no url is provided, current client URL is used.
*
* @param string $url
* URL for UUID search.
*
* @return string|NULL
* UUID if exists otherwise NULL
*/
protected function getPluginUuidFromUrl($url = NULL) {
$url = $url ?: $this
->getUrl();
$match = array();
preg_match('~^.*/(condition|mapping)/(?P<uuid>[\\d\\w-]+)/edit$~i', $url, $match);
return !empty($match['uuid']) ? $match['uuid'] : NULL;
}
/**
* Adds condition to event.
*
* @param ServicesClientEvent $event
* Event where should be condition added.
*
* @param string $name
* Condition plugin name.
*
* @param array $config
* Plugin configuration.
*
* @return string
* New plugin uuid.
*/
protected function addEventCondition($event, $name, $config) {
// Test adding new condition
$this
->drupalPost($event
->getHandler()
->getUrl('add_plugin/condition'), array(
'type' => $name,
), "Save");
$uuid = $this
->getPluginUuidFromUrl();
$this
->drupalPost($event
->getHandler()
->getUrl('plugin/condition/' . $uuid . '/edit'), $config, "Submit");
return $uuid;
}
/**
* Remove existing event plugin.
*
* @param ServicesClientEvent $event
* Event from which should be condition removed.
*
* @param string $type
* Plugin type - condition, mapping
*
* @param string $uuid
* Condition UUID.
*/
protected function removeEventPlugin($event, $type, $uuid) {
$this
->drupalGet($event
->getHandler()
->getUrl('configure'));
$xpath_selector = '//table//a[contains(text(), "Remove")][contains(@href, "' . $uuid . '")]';
$result = $this
->xpath($xpath_selector);
$result = reset($result);
if (!empty($result)) {
$parsed = parse_url((string) $result['href']);
$query = array();
parse_str($parsed['query'], $query);
if (isset($query['token'])) {
// Run remove plugin action.
$this
->drupalGet($event
->getHandler()
->getUrl('plugin/' . $type . '/' . $uuid . '/remove'), array(
'query' => array(
'token' => $query['token'],
),
));
$this
->assertText('Plugin was removed', "Plugin remove action was successful.");
// Confirm that plugin was removed.
$result = $this
->xpath($xpath_selector);
if (empty($result)) {
return TRUE;
}
}
}
return FALSE;
}
/**
* Remove existing event condition.
*
* @param ServicesClientEvent $event
* Event from which should be condition removed.
*
* @param string $uuid
* Condition UUID.
*/
protected function removeEventCondition($event, $uuid) {
$result = $this
->removeEventPlugin($event, 'condition', $uuid);
if ($result) {
$this
->pass("Condition {$uuid} was removed from event {$event->name}.");
}
else {
$this
->fail("Error when removing condition {$uuid} from event {$event->name}.");
}
}
/**
* Add new mapping row to event.
*
* @param ServicesClientEvent $event
* Event where should be mapping added.
*
* @param string $reader
* Reader plugin name.
*
* @param array $reader_config
* Reader configuration.
*
* @param string $formatter
* Formatter plugin name.
*
* @param array $formatter_config
* Formatter configuration.
*/
protected function addEventMapping($event, $reader, $reader_config, $formatter, $formatter_config) {
$this
->drupalGet($event
->getHandler()
->getUrl('add_plugin/mapping'));
$uuid = $this
->getPluginUuidFromUrl();
// Add initial plugin configuration.
$this
->drupalPost($event
->getHandler()
->getUrl('plugin/mapping/' . $uuid . '/edit'), array(
'reader' => $reader,
'formatter' => $formatter,
), "Submit");
// Submit plugin configuration.
$config = array();
foreach ($reader_config as $name => $value) {
$config['reader_config[' . $name . ']'] = $value;
}
foreach ($formatter_config as $name => $value) {
$config['formatter_config[' . $name . ']'] = $value;
}
$this
->drupalPost($event
->getHandler()
->getUrl('plugin/mapping/' . $uuid . '/edit'), $config, "Submit");
return $uuid;
}
/**
* Remove existing event mapping row.
*
* @param ServicesClientEvent $event
* Event from which should be condition removed.
*
* @param string $uuid
* Mapping UUID.
*/
protected function removeEventMapping($event, $uuid) {
$result = $this
->removeEventPlugin($event, 'mapping', $uuid);
if ($result) {
$this
->pass("Mapping {$uuid} was removed from event {$event->name}.");
}
else {
$this
->fail("Error when removing mapping {$uuid} from event {$event->name}.");
}
}
/**
* Save event configuration. Saves any configuration changes to permanent storage.
*
* @param ServicesClientEvent $event
* Event that should be saved.
*
* @param array $config
* Optional event configuration on /configure page
*
* @param bool $refresh
* Weather original event should be refreshed.
*/
protected function saveEventConfiguration(&$event, $config = array(), $refresh = FALSE) {
$this
->drupalPost($event
->getHandler()
->getUrl('configure'), $config, "Save");
if ($refresh) {
$event = $this
->loadEvent($event->name, TRUE);
}
}
/**
* Cancel event configuration. Cancel any configuration from object cache.
*
* @param ServicesClientEvent $event
* Event that should be saved.
*/
protected function cancelEventConfiguration($event) {
$this
->drupalPost($event
->getHandler()
->getUrl('configure'), array(), "Cancel");
}
/**
* Enables event in ctools export api.
*
* @param ServicesClientEvent $event
* Event that should be enabled.
*/
protected function enabledEvent($event) {
ctools_export_crud_set_status($event->table, $event, FALSE);
$this
->resetEventCache();
}
/**
* Clears whole queue.
*
* @param string $name
* Optional name of the queue. If non provided, default services client queue
* will be queued.
*/
protected function clearQueue($name = 'services_client_sync') {
$queue = DrupalQueue::get($name, TRUE);
$queue
->deleteQueue();
}
/**
* Retrieve single item from queue.
*
* @param string $name
* Optional name of the queue. If non provided, default services client queue
* will be queued.
*
* @return stdClass
* Drupal queue item.
*/
protected function getQueueItem($name = 'services_client_sync') {
$queue = DrupalQueue::get($name, TRUE);
return $queue
->claimItem();
}
}
/**
* Base class for all administration menu web test cases.
*/
class ServicesClientWebTestCase extends ServicesClientBaseWebTestCase {
protected $admin;
protected $connection;
public static function getInfo() {
return array(
'name' => 'Basic functionality',
'description' => 'Tests basic configuration and UI.',
'group' => 'Services Client',
);
}
function setUp() {
parent::setUp();
}
/**
* Test basic event configuration actions.
*/
public function testAddingEvent() {
// Login admin user.
$this
->drupalLogin($this->admin);
// Load services client page.
$this
->drupalGet('admin/structure/services_client');
$this
->assertText('There are no events to display.', "No events are created when module installed.");
$event = $this
->createSCEvent();
$this
->assertIdentical($event->disabled, TRUE, "Newly created event is disabled by default.");
// Add new property condition.
$conditions['status'] = $this
->addEventCondition($event, 'ServicesClientPropertyCondition', array(
'property' => 'status',
'condition' => 'equals',
'value' => '1',
));
// Test adding new mapping.
$reader_config = array(
'property' => 'uid',
);
$formatter_config = array(
'property' => 'uid',
);
$mapping['uid'] = $this
->addEventMapping($event, 'ServicesClientPropertyReader', $reader_config, 'ServicesClientPropertyFormatter', $formatter_config);
// Check that non-saved event doesn't have any configuration.
$event = $this
->loadEvent($event->name, TRUE);
$this
->assertIdentical($event->config, array(), "Non saved event configured event isn't changed in permanent storage.");
// Store new configuration to permanent storage.
$this
->saveEventConfiguration($event, array(), TRUE);
$this
->assertTrue(isset($event->config['condition'][$conditions['status']]), "Condition plugin was saved to event.");
$this
->assertTrue(isset($event->config['mapping'][$mapping['uid']]), "Mapping row was saved to event.");
// Test condition evalution.
$fake_entity = (object) array(
'status' => 0,
);
$handler = $event
->getHandler();
$handler
->setEntity($fake_entity);
$this
->assertIdentical($handler
->isMatching(), FALSE, 'Single non matching condition is executed correctly');
$fake_entity->status = 1;
$this
->assertIdentical($handler
->isMatching(), TRUE, 'Single matching condition is executed correctly');
$handler
->setEntity(NULL);
$this
->assertIdentical($handler
->isMatching(), FALSE, "Null entity isn't matching event.");
// Test removing event condition without token.
$this
->drupalGet($event
->getHandler()
->getUrl('plugin/condition/' . $conditions['status'] . '/remove'));
$this
->assertText('Invalid token', "When token isn't provided plugin can't be deleted.");
$this
->assertResponse(403, "No token requested resulted in 403 - access denied.");
$this
->drupalGet($event
->getHandler()
->getUrl('plugin/mapping/' . $mapping['uid'] . '/remove'));
$this
->assertText('Invalid token', "When token isn't provided plugin can't be deleted.");
$this
->assertResponse(403, "No token requested resulted in 403 - access denied.");
// Test removing event condition.
$this
->removeEventCondition($event, $conditions['status']);
// Test removing event row mapping.
$this
->removeEventMapping($event, $mapping['uid']);
// Store new configuration.
$this
->saveEventConfiguration($event, array(), TRUE);
$this
->assertIdentical($event->config['condition'], array(), "Removing condition resulted in empty conditions config array.");
$this
->assertIdentical($event->config['mapping'], array(), "Removing mapping row resulted in empty mapping config array.");
// Test field condition plugin.
$conditions['field_test'] = $this
->addEventCondition($event, 'ServicesClientFieldCondition', array(
'field' => 'field_test',
'language' => LANGUAGE_NONE,
'property' => 'value',
'condition' => 'equals',
'value' => 'myval',
));
$this
->saveEventConfiguration($event, array(), TRUE);
$handler = $event
->getHandler();
$fake_entity->field_test[LANGUAGE_NONE][0]['value'] = 'myval';
$handler
->setEntity($fake_entity);
$this
->assertIdentical($handler
->isMatching(), TRUE, 'Field condition is executed correctly when value is matching');
$fake_entity->field_test[LANGUAGE_NONE][0]['value'] = 'otherval';
$handler
->setEntity($fake_entity);
$this
->assertIdentical($handler
->isMatching(), FALSE, 'Field condition is executed correctly when value is not matching');
// Test handler tags
$this
->assertIdentical($handler
->hasTag('test'), FALSE, 'By default no tag is assigned to handler');
$handler
->addTag('test');
$this
->assertIdentical($handler
->hasTag('test'), TRUE, 'Added tag is repsonding.');
$handler
->removeTag('test');
$this
->assertIdentical($handler
->hasTag('test'), FALSE, "Removed tag isn't responding.");
}
public function testServicesClientProcessing() {
// Login admin user.
$this
->drupalLogin($this->admin);
$content_type = $this
->drupalCreateContentType(array(
'type' => 'post',
'name' => 'Post',
));
$node = $this
->drupalCreateNode(array(
'type' => 'post',
'title' => 'Test post',
));
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "No events are triggered by default.");
$event = $this
->createSCEvent();
// Add new property condition.
$conditions['status'] = $this
->addEventCondition($event, 'ServicesClientPropertyCondition', array(
'property' => 'status',
'condition' => 'equals',
'value' => '1',
));
$conditions['status'] = $this
->addEventCondition($event, 'ServicesClientPropertyCondition', array(
'property' => 'type',
'condition' => 'equals',
'value' => 'post',
));
// Add uid mapping.
$mapping['uid'] = $this
->addEventMapping($event, 'ServicesClientPropertyReader', array(
'property' => 'uid',
), 'ServicesClientPropertyFormatter', array(
'property' => 'uid',
));
$reader = array(
'field' => 'body',
'property' => 'value',
);
$formatter = array(
'field' => 'field_body',
'property' => 'value',
);
$mapping['body'] = $this
->addEventMapping($event, 'ServicesClientFieldReader', $reader, 'ServicesClientFieldFormatter', $formatter);
$formatter = array(
'field' => 'field_body_d6',
'property' => 'value',
);
$mapping['body_d6'] = $this
->addEventMapping($event, 'ServicesClientFieldReader', $reader, 'ServicesClientFieldD6Formatter', $formatter);
$this
->saveEventConfiguration($event, array(), TRUE);
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "Disabled events are not triggered by default.");
// Enable configured event.
$this
->enabledEvent($event);
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical(count($result), 1, "One event was triggered automatically.");
$result = reset($result);
$this
->assertIdentical(get_class($result), 'ServicesClientEventResult', "Syncing operation result is returned in correct format");
$this
->assertIdentical($result
->getEntityId(), $node->nid, "Response object extracts entity id correctly.");
$this
->assertIdentical($result
->success(), FALSE, "Failed event is reporting correct result status.");
$this
->assertTrue(!empty($result->object), "Sync event created non-empty object.");
$this
->assertTrue(!empty($result->object->_services_client), 'Control data was correctly set to mapped object.');
$this
->assertIdentical($result->object->uid, $node->uid, "Node uid was mapped correctly.");
$this
->assertIdentical($result->object->field_body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['value'], "Body field was mapped correclty with field mapper.");
$this
->assertIdentical($result->object->field_body_d6[0]['value'], $node->body[LANGUAGE_NONE][0]['value'], "Body field was mapped correclty with field mapper.");
// Test looping control
$node->_services_client['origin'] = 'remote_site';
$node->_services_client['visted'] = array(
'remote_site',
);
$handler = $event
->getHandler();
$result = $handler
->setEntity($node)
->execute();
$this
->assertIdentical($result
->success(), FALSE, "Looping event is reporting correct result status.");
$this
->assertIdentical($result->error_type, ServicesClientErrorType::LOOP, "Loop error type is reported.");
// Test control data queueing.
$this
->clearQueue();
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "No events were processed when node has control data.");
$item = $this
->getQueueItem();
$this
->assertIdentical($node->nid, $item->data['entity']->nid, "Processed entity was queued when contain controlling data");
$this
->clearQueue();
// Bypass queue processing.
$node->_services_client['bypass_queue'] = TRUE;
$result = services_client_process_events('save', $node, 'node');
$this
->assertTrue(!empty($result), "Event was processed directly if bypas_queue flag was present.");
$result = reset($result);
$this
->assertIdentical($result
->getEntityId(), $node->nid, "Response object extracts entity id correctly.");
$this
->assertIdentical($result
->success(), FALSE, "Failed event is reporting correct result status.");
$item = $this
->getQueueItem();
$this
->assertTrue(empty($item), "No object was queued if bypass_queue is present.");
// Test auto queueing
$this
->saveEventConfiguration($event, array(
'queue' => 1,
), TRUE);
unset($node->_services_client);
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "No events were processed when force queue is enabled.");
$item = $this
->getQueueItem();
$this
->assertIdentical($node->nid, $item->data['entity']->nid, "Processed entity was queued when force queue is enabled.");
$this
->clearQueue();
// Test non-triggered events.
$this
->saveEventConfiguration($event, array(
'queue' => FALSE,
'auto_triggered' => FALSE,
), TRUE);
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "No events were processed when auto trigger is off.");
$item = $this
->getQueueItem();
$this
->assertTrue(empty($item), "No queue item was created when auto trigger is turned off.");
}
}
/**
* Base class for all administration menu web test cases.
*/
class ServicesClientHooksWebTestCase extends ServicesClientBaseWebTestCase {
protected $admin;
protected $connection;
public static function getInfo() {
return array(
'name' => 'Hooks functionality',
'description' => 'Tests services client hooks',
'group' => 'Services Client',
);
}
function setUp() {
parent::setUp('services_client_test');
}
public function testServicesClientHooks() {
// Login admin user.
$this
->drupalLogin($this->admin);
$content_type = $this
->drupalCreateContentType(array(
'type' => 'post',
'name' => 'Post',
));
$node = $this
->drupalCreateNode(array(
'type' => 'post',
'title' => 'Test post',
));
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "No events are triggered by default.");
$event = $this
->createSCEvent();
// Add new property condition.
$conditions['status'] = $this
->addEventCondition($event, 'ServicesClientPropertyCondition', array(
'property' => 'status',
'condition' => 'equals',
'value' => '1',
));
$conditions['status'] = $this
->addEventCondition($event, 'ServicesClientPropertyCondition', array(
'property' => 'type',
'condition' => 'equals',
'value' => 'post',
));
// Add uid mapping.
$mapping['uid'] = $this
->addEventMapping($event, 'ServicesClientPropertyReader', array(
'property' => 'uid',
), 'ServicesClientPropertyFormatter', array(
'property' => 'uid',
));
$reader = array(
'field' => 'body',
'property' => 'value',
);
$formatter = array(
'field' => 'field_body',
'property' => 'value',
);
$mapping['body'] = $this
->addEventMapping($event, 'ServicesClientFieldReader', $reader, 'ServicesClientFieldFormatter', $formatter);
$formatter = array(
'field' => 'field_body_d6',
'property' => 'value',
);
$mapping['body_d6'] = $this
->addEventMapping($event, 'ServicesClientFieldReader', $reader, 'ServicesClientFieldD6Formatter', $formatter);
$this
->saveEventConfiguration($event, array(), TRUE);
$this
->enabledEvent($event);
// Test basic sync hooks
$result = services_client_process_events('save', $node, 'node');
$result = reset($result);
$this
->assertIdentical($result->object->services_client_test, TRUE, "hook_services_client_mapped_object_alter was triggered correctly.");
$this
->assertIdentical($result->object->services_client_test_name, $event->name, "Event handler is availbale in hook_services_client_mapped_object_alter.");
$this
->assertIdentical($result->object->services_client_before_request, TRUE, "hook_services_client_before_request was triggered correctly.");
$this
->assertIdentical($result->object->services_client_after_request, TRUE, "hook_services_client_after_request was triggered correctly.");
$this
->assertIdentical($result->services_client_process_events, TRUE, "hook_services_client_process_events was triggered correctly.");
$node->services_client_skip_autosync = TRUE;
$result = services_client_process_events('save', $node, 'node');
$this
->assertIdentical($result, array(), "Skip autosync hook was correctly triggered and prevented entity syncing.");
}
}
// Test user handler features
// Test node handler
Classes
Name | Description |
---|---|
ServicesClientBaseWebTestCase | @file Tests for the Administration menu module. |
ServicesClientHooksWebTestCase | Base class for all administration menu web test cases. |
ServicesClientWebTestCase | Base class for all administration menu web test cases. |