rules_test_case.test

Rules 7.x tests.

This files is here for keeping track which tests have been ported to Drupal 8 and which not. Any tests covered can be removed, so everything that's left in this file still needs to be ported.

File

d7-tests/rules_test_case.test

View source
<?php


/**
 * @file
 * Rules 7.x tests.
 *
 * This files is here for keeping track which tests have been ported to Drupal
 * 8 and which not. Any tests covered can be removed, so everything that's
 * left in this file still needs to be ported.
 */
// @codingStandardsIgnoreStart
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.');
    }

}

Classes

Title Deprecated Summary
RulesTestCase