class RulesTestCase in Rules 8.3
Same name and namespace in other branches
- 6 rules_test/rules_test.test \RulesTestCase
- 7.2 tests/rules.test \RulesTestCase
Hierarchy
- class \RulesTestCase extends \DrupalWebTestCase
Expanded class hierarchy of RulesTestCase
File
- d7-tests/
rules_test_case.test, line 14 - Rules 7.x tests.
View source
class RulesTestCase extends DrupalWebTestCase {
static function getInfo() {
return array(
'name' => 'Rules Engine tests',
'description' => 'Test using the rules API to create and evaluate rules.',
'group' => 'Rules',
);
}
function setUp() {
parent::setUp('rules', 'rules_test');
RulesLog::logger()
->clear();
variable_set('rules_debug_log', 1);
}
/**
* Calculates the output of t() given an array of placeholders to replace.
*/
static function t($text, $strings) {
$placeholders = array();
foreach ($strings as $key => $string) {
$key = !is_numeric($key) ? $key : $string;
$placeholders['%' . $key] = drupal_placeholder($string);
}
return strtr($text, $placeholders);
}
protected function createTestRule() {
$rule = rule();
$rule
->condition('rules_test_condition_true')
->condition('rules_test_condition_true')
->condition(rules_or()
->condition(rules_condition('rules_test_condition_true')
->negate())
->condition('rules_test_condition_false')
->condition(rules_and()
->condition('rules_test_condition_false')
->condition('rules_test_condition_true')
->negate()));
$rule
->action('rules_test_action');
return $rule;
}
/**
* Test handling dependencies.
*/
function testdependencies() {
$action = rules_action('rules_node_publish_action');
$this
->assertEqual($action
->dependencies(), array(
'rules_test',
), 'Providing module is returned as dependency.');
$container = new RulesTestContainer();
$this
->assertEqual($container
->dependencies(), array(
'rules_test',
), 'Providing module for container plugin is returned as dependency.');
// Test handling unmet dependencies.
$rule = rules_config_load('rules_export_test');
$this
->assertTrue(in_array('comment', $rule->dependencies) && !$rule->dirty, 'Dependencies have been imported.');
// Remove the required comment module and make sure the rule is dirty then.
module_disable(array(
'comment',
));
rules_clear_cache();
$rule = rules_config_load('rules_export_test');
$this
->assertTrue($rule->dirty, 'Rule has been marked as dirty');
// Now try re-enabling.
module_enable(array(
'comment',
));
rules_clear_cache();
$rule = rules_config_load('rules_export_test');
$this
->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
// Test it with components.
module_enable(array(
'path',
));
$action_set = rules_action_set(array(
'node' => array(
'type' => 'node',
),
));
$action_set
->action('node_path_alias');
$action_set
->save('rules_test_alias');
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->action('component_rules_test_alias');
$rule
->integrityCheck();
$rule
->save('rules_test_rule');
$rule = rules_config_load('rules_test_rule');
$component = rules_config_load('rules_test_alias');
$this
->assertTrue(in_array('path', $component->dependencies) && !$rule->dirty && !$component->dirty, 'Component has path module dependency.');
// Now disable path module and make sure both configs are marked as dirty.
module_disable(array(
'path',
));
rules_clear_cache();
$rule = rules_config_load('rules_test_rule');
$component = rules_config_load('rules_test_alias');
$this
->assertTrue($component->dirty, 'Component has been marked as dirty');
$node = $this
->drupalCreateNode();
$result = rules_invoke_component('rules_test_alias', $node);
$this
->assertTrue($result === FALSE, 'Unable to execute a dirty component.');
// When the rule is evaluated, the broken component is detected and the
// rule should be marked as dirty too.
$rule
->execute($node);
$this
->assertTrue($rule->dirty, 'Rule has been marked as dirty');
module_enable(array(
'path',
));
rules_clear_cache();
// Trigger rebuilding the cache, so configs are checked again.
rules_get_cache();
$rule = rules_config_load('rules_test_rule');
$component = rules_config_load('rules_test_alias');
$this
->assertTrue(!$component->dirty, 'Component has been marked as not dirty again.');
$this
->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
}
/**
* Test setting up an action with some action_info and serializing and
* executing it.
*/
function testActionSetup() {
$action = rules_action('rules_node_publish_action');
$s = serialize($action);
$action2 = unserialize($s);
$node = (object) array(
'status' => 0,
'type' => 'page',
);
$node->title = 'test';
$action2
->execute($node);
$this
->assertEqual($node->status, 1, 'Action executed correctly');
$this
->assertTrue(in_array('node', array_keys($action2
->parameterInfo())), 'Parameter info returned.');
$node->status = 0;
$action2
->integrityCheck();
$action2
->executeByArgs(array(
'node' => $node,
));
$this
->assertEqual($node->status, 1, 'Action executed correctly');
// Test calling an extended + overridden method.
$this
->assertEqual($action2
->help(), 'custom', 'Using custom help callback.');
// Inspect the cache
//$this->pass(serialize(rules_get_cache()));
RulesLog::logger()
->checkLog();
}
/**
* Test executing with wrong arguments.
*/
function testActionExecutionFails() {
$action = rules_action('rules_node_publish_action');
try {
$action
->execute();
$this
->fail("Execution hasn't created an exception.");
} catch (RulesEvaluationException $e) {
$this
->pass("RulesEvaluationException was thrown: " . $e);
}
}
/**
* Test setting up a rule and mapping variables.
*/
function testVariableMapping() {
$rule = rule(array(
'node' => array(
'type' => 'node',
),
'node_unchanged' => array(
'type' => 'node',
),
));
$rule
->condition(rules_condition('rules_condition_content_is_published')
->negate())
->condition('rules_condition_content_is_type', array(
'type' => array(
'page',
'story',
),
))
->action('rules_node_publish_action', array(
'node:select' => 'node_unchanged',
));
$node1 = $this
->drupalCreateNode(array(
'status' => 0,
'type' => 'page',
));
$node2 = $this
->drupalCreateNode(array(
'status' => 0,
'type' => 'page',
));
$rule
->integrityCheck();
$rule
->execute($node1, $node2);
$this
->assertEqual($node2->status, 1, 'Action executed correctly on node2.');
$this
->assertEqual($node1->status, 0, 'Action not executed on node1.');
RulesLog::logger()
->checkLog();
}
/**
* Tests making use of class based actions.
*/
function testClassBasedActions() {
$cache = rules_get_cache();
$this
->assertTrue(!empty($cache['action_info']['rules_test_class_action']), 'Action has been discovered.');
$action = rules_action('rules_test_class_action');
$parameters = $action
->parameterInfo();
$this
->assertTrue($parameters['node'], 'Action parameter needs a value.');
$node = $this
->drupalCreateNode();
$action
->execute($node);
$log = RulesLog::logger()
->get();
$last = array_pop($log);
$last = array_pop($log);
$this
->assertEqual($last[0], 'Action called with node ' . $node->nid, 'Action called');
RulesLog::logger()
->checkLog();
}
/**
* Tests CRUD functionality.
*/
function testRulesCRUD() {
$rule = $this
->createTestRule();
$rule
->integrityCheck()
->save('test');
$this
->assertEqual(TRUE, $rule->active, 'Rule is active.');
$this
->assertEqual(0, $rule->weight, 'Rule weight is zero.');
$results = entity_load('rules_config', array(
'test',
));
$rule2 = array_pop($results);
$this
->assertEqual($rule->id, $rule2->id, 'Rule created and loaded');
$this
->assertEqual(get_class($rule2), get_class($rule), 'Class properly instantiated.');
$rule2
->execute();
// Update.
$rule2
->save();
// Make sure all rule elements are still here.
$it = new RecursiveIteratorIterator($rule2
->conditions(), RecursiveIteratorIterator::SELF_FIRST);
$this
->assertEqual(iterator_count($it), 8, 'Iterated over all conditions and condition containers');
$it = new RecursiveIteratorIterator($rule2
->conditions());
$this
->assertEqual(iterator_count($it), 6, 'Iterated over all conditions');
$this
->assertEqual(iterator_count($rule2
->actions()), 1, 'Iterated over all actions');
// Delete.
$rule2
->delete();
$this
->assertEqual(entity_load('rules_config', FALSE, array(
'id' => $rule->id,
)), array(), 'Deleted.');
// Tests CRUD for tags - making sure the tags are stored properly..
$rule = $this
->createTestRule();
$tag = $this
->randomString();
$rule->tags = array(
$tag,
);
$rule
->save();
$result = db_select('rules_tags')
->fields('rules_tags', array(
'tag',
))
->condition('id', $rule->id)
->execute();
$this
->assertEqual($result
->fetchField(), $tag, 'Associated tag has been saved.');
// Try updating.
$rule->tags = array(
$this
->randomName(),
$this
->randomName(),
);
$rule
->integrityCheck()
->save();
$result = db_select('rules_tags')
->fields('rules_tags', array(
'tag',
))
->condition('id', $rule->id)
->execute()
->fetchCol();
$this
->assertTrue(in_array($rule->tags[0], $result) && in_array($rule->tags[1], $result), 'Updated associated tags.');
// Try loading multiple rules by tags.
$rule2 = $this
->createTestRule();
$rule2->tags = array(
$this
->randomName(),
);
$rule2
->save();
$loaded = entity_load('rules_config', FALSE, array(
'tags' => array(
$rule->tags[0],
$rule2->tags[0],
),
));
$this
->assertTrue($loaded[$rule->id]->id == $rule->id && $loaded[$rule2->id]->id == $rule2->id, 'Loading configs by tags');
// Try deleting.
$rule
->delete();
$result = db_select('rules_tags')
->fields('rules_tags', array(
'tag',
))
->condition('id', $rule->id)
->execute();
$this
->assertEqual($result
->fetchField(), FALSE, 'Deleted associated tags.');
}
/**
* Test automatic saving of variables.
*/
function testActionSaving() {
// Test saving a parameter.
$action = rules_action('rules_node_publish_action_save');
$node = $this
->drupalCreateNode(array(
'status' => 0,
'type' => 'page',
));
$action
->executeByArgs(array(
'node' => $node,
));
$this
->assertEqual($node->status, 1, 'Action executed correctly on node.');
// Sync node_load cache with node_save
entity_get_controller('node')
->resetCache();
$node = node_load($node->nid);
$this
->assertEqual($node->status, 1, 'Node has been saved.');
// Now test saving a provided variable, which is renamed and modified before
// it is saved.
$title = $this
->randomName();
$rule = rule();
$rule
->action('entity_create', array(
'type' => 'node',
'param_type' => 'article',
'param_author:select' => 'site:current-user',
'param_title' => $title,
'entity_created:var' => 'node',
));
$rule
->action('data_set', array(
'data:select' => 'node:body',
'value' => array(
'value' => 'body',
),
));
$rule
->integrityCheck();
$rule
->execute();
$node = $this
->drupalGetNodeByTitle($title);
$this
->assertTrue(!empty($node) && $node->body[LANGUAGE_NONE][0]['value'] == 'body', 'Saved a provided variable');
RulesLog::logger()
->checkLog();
}
/**
* Test adding a variable and optional parameters.
*/
function testVariableAdding() {
$node = $this
->drupalCreateNode();
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule
->condition('rules_test_condition_true')
->action('rules_action_load_node')
->action('rules_action_delete_node', array(
'node:select' => 'node_loaded',
))
->execute($node->nid);
$this
->assertEqual(FALSE, node_load($node->nid), 'Variable added and skipped optional parameter.');
RulesLog::logger()
->checkLog();
$vars = $rule
->conditions()
->offsetGet(0)
->availableVariables();
$this
->assertEqual(!isset($vars['node_loaded']), 'Loaded variable is not available to conditions.');
// Test adding a variable with a custom variable name.
$node = $this
->drupalCreateNode();
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule
->action('rules_action_load_node', array(
'node_loaded:var' => 'node',
))
->action('rules_action_delete_node')
->execute($node->nid);
$this
->assertEqual(FALSE, node_load($node->nid), 'Variable with custom name added.');
RulesLog::logger()
->checkLog();
}
/**
* Test custom access for using component actions/conditions.
*/
function testRuleComponentAccess() {
// Create a normal user.
$normal_user = $this
->drupalCreateUser();
// Create a role for granting access to the rule component.
$this->normal_role = $this
->drupalCreateRole(array(), 'test_role');
$normal_user->roles[$this->normal_role] = 'test_role';
user_save($normal_user, array(
'roles' => $normal_user->roles,
));
// Create an 'action set' rule component making use of a permission.
$action_set = rules_action_set(array(
'node' => array(
'type' => 'node',
),
));
$action_set->access_exposed = TRUE;
$action_set
->save('rules_test_roles');
// Set the global user to be the current one as access is checked for the
// global user.
global $user;
$user = user_load($normal_user->uid);
$this
->assertFalse(rules_action('component_rules_test_roles')
->access(), 'Authenticated user without the correct role can\'t use the rule component.');
// Assign the role that will have permissions for the rule component.
user_role_change_permissions($this->normal_role, array(
'use Rules component rules_test_roles' => TRUE,
));
$this
->assertTrue(rules_action('component_rules_test_roles')
->access(), 'Authenticated user with the correct role can use the rule component.');
// Reset global user to anonyous.
$user = user_load(0);
$this
->assertFalse(rules_action('component_rules_test_roles')
->access(), 'Anonymous user can\'t use the rule component.');
}
/**
* Test passing arguments by reference to an action.
*/
function testPassingByReference() {
// Keeping references of variables is unsupported, though the
// EntityMetadataArrayObject may be used to achieve that.
$array = array(
'foo' => 'bar',
);
$data = new EntityMetadataArrayObject($array);
rules_action('rules_action_test_reference')
->execute($data);
$this
->assertTrue($data['changed'], 'Parameter has been passed by reference');
}
/**
* Test sorting rule elements.
*/
function testSorting() {
$rule = $this
->createTestRule();
$conditions = $rule
->conditions();
$conditions[0]->weight = 10;
$conditions[2]->weight = 10;
$id[0] = $conditions[0]
->elementId();
$id[1] = $conditions[1]
->elementId();
$id[2] = $conditions[2]
->elementId();
// For testing use a deep sort, even if not necessary here.
$rule
->sortChildren(TRUE);
$conditions = $rule
->conditions();
$this
->assertEqual($conditions[0]
->elementId(), $id[1], 'Condition sorted correctly.');
$this
->assertEqual($conditions[1]
->elementId(), $id[0], 'Condition sorted correctly.');
$this
->assertEqual($conditions[2]
->elementId(), $id[2], 'Condition sorted correctly.');
}
/**
* Tests using data selectors.
*/
function testDataSelectors() {
$body[LANGUAGE_NONE][0] = array(
'value' => '<b>The body & nothing.</b>',
);
$node = $this
->drupalCreateNode(array(
'body' => $body,
'type' => 'page',
'summary' => '',
));
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule
->action('rules_action_load_node')
->action('drupal_message', array(
'message:select' => 'node_loaded:body:value',
))
->execute($node->nid);
RulesLog::logger()
->checkLog();
$msg = drupal_get_messages('status');
$last_msg = array_pop($msg['status']);
$wrapper = entity_metadata_wrapper('node', $node);
$this
->assertEqual($last_msg, $wrapper->body->value
->value(array(
'sanitize' => TRUE,
)), 'Data selector for getting parameter applied.');
// Get a "reference" on the same object as returned by node_load().
$node = node_load($node->nid);
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule
->action('rules_action_load_node')
->action('data_set', array(
'data:select' => 'node_loaded:title',
'value' => 'Test title',
))
->action('data_set', array(
'data:select' => 'node_loaded:title',
'value' => 'Test title2',
))
->execute($node->nid);
$wrapper = entity_metadata_wrapper('node', $node);
$this
->assertEqual('Test title2', $wrapper->title
->value(), 'Data has been modified and saved.');
RulesLog::logger()
->checkLog();
$text = RulesLog::logger()
->render();
$msg = RulesTestCase::t('Saved %node_loaded of type %node.', array(
'node_loaded',
'node',
));
if ($pos1 = strpos($text, $msg)) {
$pos2 = strpos($text, $msg, $pos1 + 1);
}
$this
->assertTrue($pos1 && $pos2 === FALSE, 'Data has been saved only once.');
// Test validation.
try {
rules_action('data_set', array(
'data' => 'no-selector',
'value' => '',
))
->integrityCheck();
$this
->fail("Validation hasn't created an exception.");
} catch (RulesIntegrityException $e) {
$this
->pass("Validation error correctly detected: " . $e);
}
// Test auto creation of nested data structures, like the node body field.
// I.e. if $node->body is not set, it is automatically initialized to an
// empty array, so that the nested value can be set and the wrappers do not
// complain about missing parent data structures.
$rule = rule();
$rule
->action('entity_create', array(
'type' => 'node',
'param_type' => 'page',
'param_title' => 'foo',
'param_author' => $GLOBALS['user'],
));
$rule
->action('data_set', array(
'data:select' => 'entity_created:body:value',
'value' => 'test content',
))
->execute();
try {
RulesLog::logger()
->checkLog();
$this
->pass('Auto creation of nested data structures.');
} catch (Exception $e) {
$this
->fail('Auto creation of nested data structures.');
}
// Make sure variables that are passed wrapped work.
$result = rules_condition('rules_test_condition_node_wrapped')
->execute($node->nid);
$this
->assertTrue($result, 'Condition receiving wrapped parameter.');
// Make sure wrapped parameters are checked for containing NULL values.
$rule = rule(array(
'node' => array(
'type' => 'node',
'optional' => TRUE,
),
));
$rule
->condition('rules_test_condition_node_wrapped', array(
'node:select' => 'node',
));
$rule
->execute(entity_metadata_wrapper('node'));
$text = RulesLog::logger()
->render();
$msg = RulesTestCase::t('The variable or parameter %node is empty.', array(
'node',
));
$this
->assertTrue(strpos($text, $msg) !== FALSE, 'Evaluation aborted due to an empty argument value.');
}
/**
* Tests making use of rule sets.
*/
function testRuleSets() {
$set = rules_rule_set(array(
'node' => array(
'type' => 'node',
'label' => 'node',
),
));
$set
->rule(rule()
->action('drupal_message', array(
'message:select' => 'node:title',
)))
->rule(rule()
->condition('rules_condition_content_is_published')
->action('drupal_message', array(
'message' => 'Node is published.',
)));
$set
->integrityCheck()
->save('rules_test_set_1');
$node = $this
->drupalCreateNode(array(
'title' => 'The title.',
'status' => 1,
));
// Execute.
rules_invoke_component('rules_test_set_1', $node);
$msg = drupal_get_messages();
$this
->assertEqual($msg['status'][0], 'The title.', 'First rule evaluated.');
$this
->assertEqual($msg['status'][1], 'Node is published.', 'Second rule evaluated.');
// Test a condition set.
$set = rules_or(array(
'node' => array(
'type' => 'node',
'label' => 'node',
),
));
$set
->condition('data_is', array(
'data:select' => 'node:author:name',
'value' => 'notthename',
))
->condition('data_is', array(
'data:select' => 'node:nid',
'value' => $node->nid,
))
->integrityCheck()
->save('test', 'rules_test');
// Load and execute condition set.
$set = rules_config_load('test');
$this
->assertTrue($set
->execute($node), 'Set has been correctly evaluated.');
RulesLog::logger()
->checkLog();
}
/**
* Tests invoking components from the action.
*/
function testComponentInvocations() {
$set = rules_rule_set(array(
'node1' => array(
'type' => 'node',
'label' => 'node',
),
));
$set
->rule(rule()
->condition('node_is_published', array(
'node:select' => 'node1',
))
->action('node_unpublish', array(
'node:select' => 'node1',
)));
$set
->integrityCheck()
->save('rules_test_set_2');
// Use different names for the variables to ensure they are properly mapped
// when taking over the variables to be saved.
$rule = rule(array(
'node2' => array(
'type' => 'node',
'label' => 'node',
),
));
$rule
->action('component_rules_test_set_2', array(
'node1:select' => 'node2',
));
$rule
->action('node_make_sticky', array(
'node:select' => 'node2',
));
$node = $this
->drupalCreateNode(array(
'title' => 'The title.',
'status' => 1,
'sticky' => 0,
));
$rule
->execute($node);
$node = node_load($node->nid, NULL, TRUE);
$this
->assertFalse($node->status, 'The component changes have been saved correctly.');
$this
->assertTrue($node->sticky, 'The action changes have been saved correctly.');
// Check that we have saved the changes only once.
$text = RulesLog::logger()
->render();
// Make sure both saves are handled in one save operation.
$this
->assertEqual(substr_count($text, 'Saved'), 1, 'Changes have been saved in one save operation.');
RulesLog::logger()
->checkLog();
// Test recursion prevention on components by invoking the component from
// itself, what should be prevented.
$set
->action('component_rules_test_set_2', array(
'node1:select' => 'node1',
))
->save();
$rule
->execute($node);
$text1 = RulesLog::logger()
->render();
$text2 = RulesTestCase::t('Not evaluating rule set %rules_test_set_2 to prevent recursion.', array(
'rules_test_set_2',
));
$this
->assertTrue(strpos($text1, $text2) !== FALSE, "Recursion of component invocation prevented.");
// Test executing the component provided in code via the action. This makes
// sure the component in code has been properly picked up.
$node->status = 0;
node_save($node);
rules_action('component_rules_test_action_set')
->execute($node);
$this
->assertTrue($node->status == 1, 'Component provided in code has been executed.');
}
/**
* Test asserting metadata, customizing action info and make sure integrity
* is checked.
*/
function testMetadataAssertion() {
$action = rules_action('rules_node_make_sticky_action');
// Test failing integrity check.
try {
$rule = rule(array(
'node' => array(
'type' => 'entity',
),
));
$rule
->action($action);
// Fails due to the 'node' variable not matching the node type.
$rule
->integrityCheck();
$this
->fail('Integrity check has not thrown an exception.');
} catch (RulesIntegrityException $e) {
$this
->pass('Integrity check has thrown exception: ' . $e
->getMessage());
}
// Test asserting additional metadata.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
// Customize action info using the settings.
$rule
->condition('data_is', array(
'data:select' => 'node:type',
'value' => 'page',
))
->condition(rules_condition('data_is', array(
'data:select' => 'node:body:value',
'value' => 'foo',
))
->negate())
->action($action);
// Make sure the integrity check doesn't throw an exception.
$rule
->integrityCheck();
// Test the rule.
$node = $this
->drupalCreateNode(array(
'type' => 'page',
'sticky' => 0,
));
$rule
->execute($node);
$this
->assertTrue($node->sticky, 'Rule with asserted metadata executed.');
// Test asserting metadata on a derived property, i.e. not a variable.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->condition('entity_is_of_type', array(
'entity:select' => 'node:reference',
'type' => 'node',
))
->condition('data_is', array(
'data:select' => 'node:reference:type',
'value' => 'page',
))
->action('rules_node_page_make_sticky_action', array(
'node:select' => 'node:reference',
));
$rule
->integrityCheck();
$rule
->execute($node);
// Test asserting an entity field.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->condition('entity_has_field', array(
'entity:select' => 'node:reference',
'field' => 'field_tags',
))
->action('data_set', array(
'data:select' => 'node:reference:field-tags',
'value' => array(),
));
$rule
->integrityCheck();
$rule
->execute($node);
// Make sure an asserted bundle can be used as argument.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->condition('entity_is_of_type', array(
'entity:select' => 'node:reference',
'type' => 'node',
))
->condition('node_is_of_type', array(
'node:select' => 'node:reference',
'type' => array(
'page',
),
))
->action('rules_node_page_make_sticky_action', array(
'node:select' => 'node:reference',
));
$rule
->integrityCheck();
$rule
->execute($node);
// Test asserting metadata on a derived property being a list item.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->condition('node_is_of_type', array(
'node:select' => 'node:ref-nodes:0',
'type' => array(
'article',
),
))
->action('data_set', array(
'data:select' => 'node:ref-nodes:0:field-tags',
'value' => array(),
));
$rule
->integrityCheck();
$rule
->execute($node);
// Give green lights if there were no exceptions and check rules-log errors.
$this
->pass('Rules asserting metadata on a derived property pass integrity checks.');
RulesLog::logger()
->checkLog();
// Make sure assertions of a one list item are not valid for another item.
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->condition('node_is_of_type', array(
'node:select' => 'node:ref-nodes:0',
'type' => array(
'article',
),
))
->action('data_set', array(
'data:select' => 'node:ref-nodes:1:field-tags',
'value' => array(),
));
try {
$rule
->integrityCheck();
$this
->fail('Assertion of a list item is not valid for another item.');
} catch (RulesException $e) {
$this
->pass('Assertion of a list item is not valid for another item.');
}
}
/**
* Test using loops.
*/
function testLoops() {
// Test passing the list parameter as argument to ensure that is working
// generally for plugin container too.
drupal_get_messages(NULL, TRUE);
$loop = rules_loop();
$loop
->action('drupal_message', array(
'message' => 'test',
));
$arg_info = $loop
->parameterInfo();
$this
->assert($arg_info['list']['type'] == 'list', 'Argument info contains list.');
$loop
->execute(array(
1,
2,
));
// Ensure the action has been executed twice, once for each list item.
$msg = drupal_get_messages();
$this
->assert($msg['status'][0] == 'test' && $msg['status'][1], 'Loop has been properly executed');
// Now test looping over nodes.
$node1 = $this
->drupalCreateNode(array(
'type' => 'page',
'sticky' => 0,
));
$node2 = $this
->drupalCreateNode(array(
'type' => 'page',
'sticky' => 0,
));
$node3 = $this
->drupalCreateNode(array(
'type' => 'page',
'sticky' => 0,
));
$rule = rule(array(
'list' => array(
'type' => 'list<node>',
'label' => 'A list of nodes',
),
));
$loop = rules_loop(array(
'list:select' => 'list',
'item:var' => 'node',
));
$loop
->action('data_set', array(
'data:select' => 'node:sticky',
'value' => TRUE,
));
$rule
->action($loop);
// Test using a list with data selectors, just output the last nodes type.
$rule
->action('drupal_message', array(
'message:select' => 'list:2:type',
));
$rule
->execute(array(
$node1->nid,
$node2->nid,
$node3->nid,
));
$text = RulesLog::logger()
->render();
$save_msg = RulesTestCase::t('Saved %node of type %node.', array(
'node',
'node',
));
$this
->assertTrue(substr_count($text, $save_msg) == 3, 'List item variables have been saved.');
RulesLog::logger()
->checkLog();
}
/**
* Test access checks.
*/
function testAccessCheck() {
$rule = rule();
// Try to set a property which is provided by the test module and is not
// accessible, so the access check has to return FALSE.
$rule
->action('data_set', array(
'data:select' => 'site:no-access-user',
'value' => 'foo',
));
$this
->assertTrue($rule
->access() === FALSE, 'Access check is working.');
}
/**
* Test returning provided variables.
*/
function testReturningVariables() {
$node = $this
->drupalCreateNode();
$action = rules_action('entity_fetch', array(
'type' => 'node',
'id' => $node->nid,
));
list($node2) = $action
->execute();
$this
->assertTrue($node2->nid == $node->nid, 'Action returned a variable.');
// Create a simple set that just passed through the given node.
$set = rules_rule_set(array(
'node' => array(
'type' => 'node',
),
), array(
'node',
));
$set
->integrityCheck()
->save('rules_test_set_1');
$provides = $set
->providesVariables();
$this
->assertTrue($provides['node']['type'] == 'node', 'Rule set correctly passed through the node.');
list($node2) = $set
->execute($node);
$this
->assertTrue($node2->nid == $node->nid, 'Rule set returned a variable.');
// Create an action set returning a variable that is no parameter.
$set = rules_action_set(array(
'node' => array(
'type' => 'node',
'parameter' => FALSE,
),
), array(
'node',
));
$set
->action('entity_fetch', array(
'type' => 'node',
'id' => $node->nid,
))
->action('data_set', array(
'data:select' => 'node',
'value:select' => 'entity_fetched',
));
$set
->integrityCheck();
list($node3) = $set
->execute();
$this
->assertTrue($node3->nid == $node->nid, 'Action set returned a variable that has not been passed as parameter.');
// Test the same again with a variable holding a not wrapped data type.
$set = rules_action_set(array(
'number' => array(
'type' => 'integer',
'parameter' => FALSE,
),
), array(
'number',
));
$set
->action('data_set', array(
'data:select' => 'number',
'value' => 3,
));
$set
->integrityCheck();
list($number) = $set
->execute();
$this
->assertTrue($number == 3, 'Actions set returned a number.');
}
/**
* Tests using input evaluators.
*/
function testInputEvaluators() {
$node = $this
->drupalCreateNode(array(
'title' => '<b>The body & nothing.</b>',
'type' => 'page',
));
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule
->action('rules_action_load_node')
->action('drupal_message', array(
'message' => 'Title: [node_loaded:title]',
))
->execute($node->nid);
RulesLog::logger()
->checkLog();
$msg = drupal_get_messages();
$this
->assertEqual(array_pop($msg['status']), 'Title: ' . check_plain('<b>The body & nothing.</b>'), 'Token input evaluator applied.');
// Test token replacements on a list of text values.
$component = rules_action_set(array(
'var' => array(
'type' => 'list<text>',
'label' => 'var',
),
), array(
'var',
));
$component
->save('rules_test_input');
$action = rules_action('component_rules_test_input', array(
'var' => array(
'uid: [site:current-user:uid]',
),
));
list($var) = $action
->execute();
$uid = $GLOBALS['user']->uid;
$this
->assertEqual(array(
"uid: {$uid}",
), $var, 'Token replacements on a list of values applied.');
}
/**
* Test importing and exporting a rule.
*/
function testRuleImportExport() {
$rule = rule(array(
'nid' => array(
'type' => 'integer',
),
));
$rule->name = "rules_export_test";
$rule
->action('rules_action_load_node')
->action('drupal_message', array(
'message' => 'Title: [node_loaded:title]',
));
$export = '{ "rules_export_test" : {
"PLUGIN" : "rule",
"REQUIRES" : [ "rules_test", "rules" ],
"USES VARIABLES" : { "nid" : { "type" : "integer" } },
"DO" : [
{ "rules_action_load_node" : { "PROVIDE" : { "node_loaded" : { "node_loaded" : "Loaded content" } } } },
{ "drupal_message" : { "message" : "Title: [node_loaded:title]" } }
]
}
}';
$this
->assertEqual($export, $rule
->export(), 'Rule has been exported correctly.');
// Test importing a rule which makes use of almost all features.
$export = _rules_export_get_test_export();
$rule = rules_import($export);
$this
->assertTrue(!empty($rule) && $rule
->integrityCheck(), 'Rule has been imported.');
// Test loading the same export provided as default rule.
$rule = rules_config_load('rules_export_test');
$this
->assertTrue(!empty($rule) && $rule
->integrityCheck(), 'Export has been provided in code.');
// Export it and make sure the same export is generated again.
$this
->assertEqual($export, $rule
->export(), 'Export of imported rule equals original export.');
// Now try importing a rule set.
$export = '{ "rules_test_set" : {
"LABEL" : "Test set",
"PLUGIN" : "rule set",
"REQUIRES" : [ "rules" ],
"USES VARIABLES" : { "node" : { "label" : "Test node", "type" : "node" } },
"RULES" : [
{ "RULE" : {
"IF" : [ { "NOT data_is" : { "data" : [ "node:title" ], "value" : "test" } } ],
"DO" : [ { "data_set" : { "data" : [ "node:title" ], "value" : "test" } } ],
"LABEL" : "Test Rule"
}
},
{ "RULE" : {
"DO" : [ { "drupal_message" : { "message" : "hi" } } ],
"LABEL" : "Test Rule 2"
}
}
]
}
}';
$set = rules_import($export);
$this
->assertTrue(!empty($set) && $set
->integrityCheck(), 'Rule set has been imported.');
// Export it and make sure the same export is generated again.
$this
->assertEqual($export, $set
->export(), 'Export of imported rule set equals original export.');
// Try executing the imported rule set.
$node = $this
->drupalCreateNode();
$set
->execute($node);
$this
->assertEqual($node->title, 'test', 'Imported rule set has been executed.');
RulesLog::logger()
->checkLog();
// Try import / export for a rule component providing a variable.
$rule = rule(array(
'number' => array(
'type' => 'integer',
'label' => 'Number',
'parameter' => FALSE,
),
), array(
'number',
));
$rule
->action('data_set', array(
'data:select' => 'number',
'value' => 3,
));
$rule->name = 'rules_test_provides';
$export = '{ "rules_test_provides" : {
"PLUGIN" : "rule",
"REQUIRES" : [ "rules" ],
"USES VARIABLES" : { "number" : { "type" : "integer", "label" : "Number", "parameter" : false } },
"DO" : [ { "data_set" : { "data" : [ "number" ], "value" : 3 } } ],
"PROVIDES VARIABLES" : [ "number" ]
}
}';
$this
->assertEqual($export, $rule
->export(), 'Rule 2 has been exported correctly.');
$imported_rule = rules_import($rule
->export());
$this
->assertTrue(!empty($imported_rule) && $imported_rule
->integrityCheck(), 'Rule 2 has been imported.');
$this
->assertEqual($export, $imported_rule
->export(), 'Export of imported rule 2 equals original export.');
// Test importing a negated condition component.
$export = '{ "rules_negated_component" : {
"LABEL" : "negated_component",
"PLUGIN" : "or",
"REQUIRES" : [ "rules" ],
"NOT OR" : [ { "data_is_empty" : { "data" : [ "site:slogan" ] } } ]
}
}';
$or = rules_import($export);
$this
->assertTrue($or
->integrityCheck() && $or
->isNegated(), 'Negated condition component imported.');
}
/**
* Test the named parameter mode.
*/
function testNamedParameters() {
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->action('rules_action_node_set_title', array(
'title' => 'foo',
));
$rule
->integrityCheck();
// Test the rule.
$node = $this
->drupalCreateNode(array(
'type' => 'page',
'sticky' => 0,
));
$rule
->execute($node);
$this
->assertTrue($node->title == 'foo', 'Action with named parameters has been correctly executed.');
RulesLog::logger()
->checkLog();
}
/**
* Make sure Rules aborts when NULL values are used.
*/
function testAbortOnNULLValues() {
$rule = rule(array(
'node' => array(
'type' => 'node',
),
));
$rule
->action('drupal_message', array(
'message:select' => 'node:log',
));
$rule
->integrityCheck();
// Test the rule.
$node = $this
->drupalCreateNode();
$node->log = NULL;
$rule
->execute($node);
$text = RulesLog::logger()
->render();
$msg = RulesTestCase::t('The variable or parameter %message is empty.', array(
'message',
));
$this
->assertTrue(strpos($text, $msg) !== FALSE, 'Evaluation aborted due to an empty argument value.');
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
RulesTestCase:: |
protected | function | ||
RulesTestCase:: |
static | function | ||
RulesTestCase:: |
function | |||
RulesTestCase:: |
static | function | Calculates the output of t() given an array of placeholders to replace. | |
RulesTestCase:: |
function | Make sure Rules aborts when NULL values are used. | ||
RulesTestCase:: |
function | Test access checks. | ||
RulesTestCase:: |
function | Test executing with wrong arguments. | ||
RulesTestCase:: |
function | Test automatic saving of variables. | ||
RulesTestCase:: |
function | Test setting up an action with some action_info and serializing and executing it. | ||
RulesTestCase:: |
function | Tests making use of class based actions. | ||
RulesTestCase:: |
function | Tests invoking components from the action. | ||
RulesTestCase:: |
function | Tests using data selectors. | ||
RulesTestCase:: |
function | Test handling dependencies. | ||
RulesTestCase:: |
function | Tests using input evaluators. | ||
RulesTestCase:: |
function | Test using loops. | ||
RulesTestCase:: |
function | Test asserting metadata, customizing action info and make sure integrity is checked. | ||
RulesTestCase:: |
function | Test the named parameter mode. | ||
RulesTestCase:: |
function | Test passing arguments by reference to an action. | ||
RulesTestCase:: |
function | Test returning provided variables. | ||
RulesTestCase:: |
function | Test custom access for using component actions/conditions. | ||
RulesTestCase:: |
function | Test importing and exporting a rule. | ||
RulesTestCase:: |
function | Tests CRUD functionality. | ||
RulesTestCase:: |
function | Tests making use of rule sets. | ||
RulesTestCase:: |
function | Test sorting rule elements. | ||
RulesTestCase:: |
function | Test adding a variable and optional parameters. | ||
RulesTestCase:: |
function | Test setting up a rule and mapping variables. |