upgrade.test

File

modules/simpletest/tests/upgrade/upgrade.test

View source
<?php


/**
 * Perform end-to-end tests of the upgrade path.
 */
abstract class UpgradePathTestCase extends DrupalWebTestCase {
    
    /**
     * The file path(s) to the dumped database(s) to load into the child site.
     *
     * @var array
     */
    var $databaseDumpFiles = array();
    
    /**
     * Flag that indicates whether the child site has been upgraded.
     */
    var $upgradedSite = FALSE;
    
    /**
     * Array of errors triggered during the upgrade process.
     */
    var $upgradeErrors = array();
    
    /**
     * Array of modules loaded when the test starts.
     */
    var $loadedModules = array();
    
    /**
     * Flag to indicate whether zlib is installed or not.
     */
    var $zlibInstalled = TRUE;
    
    /**
     * Flag to indicate whether there are pending updates or not.
     */
    var $pendingUpdates = TRUE;
    
    /**
     * Flag to indicate whether to skip upgrade tests.
     */
    var $skipUpgradeTest = FALSE;
    
    /**
     * Constructs an UpgradePathTestCase object.
     *
     * @param $test_id
     *   (optional) The ID of the test. Tests with the same id are reported
     *   together.
     */
    function __construct($test_id = NULL) {
        parent::__construct($test_id);
        $connection_info = Database::getConnectionInfo();
        $this->skipUpgradeTest = (bool) ($connection_info['default']['driver'] == 'pgsql');
        $this->zlibInstalled = function_exists('gzopen');
    }
    
    /**
     * Prepares the appropriate session for the release of Drupal being upgraded.
     */
    protected function prepareD7Session() {
        // Generate and set a D6-compatible session cookie.
        $this->curlInitialize();
        $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
        $session_name = update_get_d6_session_name();
        curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode($session_name) . '=' . rawurlencode($sid));
        // Force our way into the session of the child site.
        drupal_save_session(TRUE);
        // A session cannot be written without the ssid column which is missing on
        // Drupal 6 sites.
        db_add_field('sessions', 'ssid', array(
            'description' => "Secure session ID. The value is generated by Drupal's session handlers.",
            'type' => 'varchar',
            'length' => 128,
            'not null' => TRUE,
            'default' => '',
        ));
        _drupal_session_write($sid, '');
        // Remove the temporarily added ssid column.
        db_drop_field('sessions', 'ssid');
        drupal_save_session(FALSE);
    }
    
    /**
     * Overrides DrupalWebTestCase::setUp() for upgrade testing.
     *
     * @see DrupalWebTestCase::prepareDatabasePrefix()
     * @see DrupalWebTestCase::changeDatabasePrefix()
     * @see DrupalWebTestCase::prepareEnvironment()
     */
    protected function setUp() {
        // We are going to set a missing zlib requirement property for usage
        // during the performUpgrade() and tearDown() methods. Also set that the
        // tests failed.
        if (!$this->zlibInstalled) {
            parent::setUp();
            return;
        }
        global $user, $language, $conf;
        // Load the Update API.
        require_once DRUPAL_ROOT . '/includes/update.inc';
        // Reset flags.
        $this->upgradedSite = FALSE;
        $this->upgradeErrors = array();
        $this->loadedModules = module_list();
        // Create the database prefix for this test.
        $this->prepareDatabasePrefix();
        // Prepare the environment for running tests.
        $this->prepareEnvironment();
        if (!$this->setupEnvironment) {
            return FALSE;
        }
        // Reset all statics and variables to perform tests in a clean environment.
        $conf = array();
        drupal_static_reset();
        // Change the database prefix.
        // All static variables need to be reset before the database prefix is
        // changed, since DrupalCacheArray implementations attempt to
        // write back to persistent caches when they are destructed.
        $this->changeDatabasePrefix();
        if (!$this->setupDatabasePrefix) {
            return FALSE;
        }
        // Unregister the registry.
        // This is required to make sure that the database layer works properly.
        spl_autoload_unregister('drupal_autoload_class');
        spl_autoload_unregister('drupal_autoload_interface');
        // Load the database from the portable PHP dump.
        // The files may be gzipped.
        foreach ($this->databaseDumpFiles as $file) {
            if (substr($file, -3) == '.gz') {
                $file = "compress.zlib://{$file}";
            }
            require $file;
        }
        // Set path variables.
        $this->variable_set('file_public_path', $this->public_files_directory);
        $this->variable_set('file_private_path', $this->private_files_directory);
        $this->variable_set('file_temporary_path', $this->temp_files_directory);
        $this->pass('Finished loading the dump.');
        // Ensure that the session is not written to the new environment and replace
        // the global $user session with uid 1 from the new test site.
        drupal_save_session(FALSE);
        // Login as uid 1.
        $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(
            ':uid' => 1,
        ))->fetchObject();
        // Generate and set a D6-compatible session cookie.
        $this->prepareD7Session();
        // Restore necessary variables.
        $this->variable_set('clean_url', $this->originalCleanUrl);
        $this->variable_set('site_mail', 'simpletest@example.com');
        drupal_set_time_limit($this->timeLimit);
        $this->setup = TRUE;
    }
    
    /**
     * Specialized variable_set() that works even if the child site is not upgraded.
     *
     * @param $name
     *   The name of the variable to set.
     * @param $value
     *   The value to set. This can be any PHP data type; these functions take care
     *   of serialization as necessary.
     */
    protected function variable_set($name, $value) {
        db_delete('variable')->condition('name', $name)
            ->execute();
        db_insert('variable')->fields(array(
            'name' => $name,
            'value' => serialize($value),
        ))
            ->execute();
        try {
            cache_clear_all('variables', 'cache');
            cache_clear_all('variables', 'cache_bootstrap');
        } catch (Exception $e) {
        }
    }
    
    /**
     * Specialized refreshVariables().
     */
    protected function refreshVariables() {
        // No operation if the child has not been upgraded yet.
        if (!$this->upgradedSite) {
            return parent::refreshVariables();
        }
    }
    
    /**
     * Perform the upgrade.
     *
     * @param $register_errors
     *   Register the errors during the upgrade process as failures.
     * @return
     *   TRUE if the upgrade succeeded, FALSE otherwise.
     */
    protected function performUpgrade($register_errors = TRUE) {
        if (!$this->zlibInstalled) {
            $this->fail(t('Missing zlib requirement for upgrade tests.'));
            return FALSE;
        }
        $update_url = $GLOBALS['base_url'] . '/update.php';
        // Load the first update screen.
        $this->drupalGet($update_url, array(
            'external' => TRUE,
        ));
        if (!$this->assertResponse(200)) {
            return FALSE;
        }
        // Continue.
        $this->drupalPost(NULL, array(), t('Continue'));
        if (!$this->assertResponse(200)) {
            return FALSE;
        }
        // The test should pass if there are no pending updates.
        $content = $this->drupalGetContent();
        if (strpos($content, t('No pending updates.')) !== FALSE) {
            $this->pass(t('No pending updates and therefore no upgrade process to test.'));
            $this->pendingUpdates = FALSE;
            return TRUE;
        }
        // Go!
        $this->drupalPost(NULL, array(), t('Apply pending updates'));
        if (!$this->assertResponse(200)) {
            return FALSE;
        }
        // Check for errors during the update process.
        foreach ($this->xpath('//li[@class=:class]', array(
            ':class' => 'failure',
        )) as $element) {
            $message = strip_tags($element->asXML());
            $this->upgradeErrors[] = $message;
            if ($register_errors) {
                $this->fail($message);
            }
        }
        if (!empty($this->upgradeErrors)) {
            // Upgrade failed, the installation might be in an inconsistent state,
            // don't process.
            return FALSE;
        }
        // Check if there still are pending updates.
        $this->drupalGet($update_url, array(
            'external' => TRUE,
        ));
        $this->drupalPost(NULL, array(), t('Continue'));
        if (!$this->assertText(t('No pending updates.'), 'No pending updates at the end of the update process.')) {
            return FALSE;
        }
        // Upgrade succeed, rebuild the environment so that we can call the API
        // of the child site directly from this request.
        $this->upgradedSite = TRUE;
        // Reload module list. For modules that are enabled in the test database,
        // but not on the test client, we need to load the code here.
        $new_modules = array_diff(module_list(TRUE), $this->loadedModules);
        foreach ($new_modules as $module) {
            drupal_load('module', $module);
        }
        // Reload hook implementations
        module_implements('', FALSE, TRUE);
        // Rebuild caches.
        drupal_static_reset();
        drupal_flush_all_caches();
        // Reload global $conf array and permissions.
        $this->refreshVariables();
        $this->checkPermissions(array(), TRUE);
        return TRUE;
    }
    
    /**
     * Force uninstall all modules from a test database, except those listed.
     *
     * @param $modules
     *   The list of modules to keep installed. Required core modules will
     *   always be kept.
     */
    protected function uninstallModulesExcept(array $modules) {
        $required_modules = array(
            'block',
            'dblog',
            'filter',
            'node',
            'system',
            'update',
            'user',
        );
        $modules = array_merge($required_modules, $modules);
        db_delete('system')->condition('type', 'module')
            ->condition('name', $modules, 'NOT IN')
            ->execute();
    }

}

/**
 * Performs end-to-end point test of the release update path.
 */
abstract class UpdatePathTestCase extends UpgradePathTestCase {
    
    /**
     * Overrides UpgradePathTestCase::prepareD7Session().
     */
    protected function prepareD7Session() {
        // Generate and set a D7-compatible session cookie.
        $this->curlInitialize();
        $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
        curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode(session_name()) . '=' . rawurlencode($sid));
        // Force our way into the session of the child site.
        drupal_save_session(TRUE);
        _drupal_session_write($sid, '');
        drupal_save_session(FALSE);
    }

}

/**
 * Perform basic upgrade tests.
 *
 * Load a bare installation of Drupal 6 and run the upgrade process on it.
 *
 * The install only contains dblog (although it's optional, it's only so that
 * another hook_watchdog module can take its place, the site is not functional
 * without watchdog) and update.
 */
class BasicUpgradePath extends UpgradePathTestCase {
    public static function getInfo() {
        return array(
            'name' => 'Basic upgrade path',
            'description' => 'Basic upgrade path tests.',
            'group' => 'Upgrade path',
        );
    }
    public function setUp() {
        // Path to the database dump files.
        $this->databaseDumpFiles = array(
            drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.bare.database.php',
        );
        parent::setUp();
    }
    
    /**
     * Test a failed upgrade, and verify that the failure is reported.
     */
    public function testFailedUpgrade() {
        if ($this->skipUpgradeTest) {
            return;
        }
        // Destroy a table that the upgrade process needs.
        db_drop_table('access');
        // Assert that the upgrade fails.
        $this->assertFalse($this->performUpgrade(FALSE) && $this->pendingUpdates, 'A failed upgrade should return messages.');
    }
    
    /**
     * Test a successful upgrade.
     */
    public function testBasicUpgrade() {
        if ($this->skipUpgradeTest) {
            return;
        }
        $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
        // Hit the frontpage.
        $this->drupalGet('');
        $this->assertResponse(200);
        // Verify that we are still logged in.
        $this->drupalGet('user');
        $this->clickLink(t('Edit'));
        $this->assertEqual($this->getUrl(), url('user/1/edit', array(
            'absolute' => TRUE,
        )), 'We are still logged in as admin at the end of the upgrade.');
        // Logout and verify that we can login back in with our initial password.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // The previous login should've triggered a password rehash, so login one
        // more time to make sure the new hash is readable.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // Test that the site name is correctly displayed.
        $this->assertText('Drupal 6', 'The site name is correctly displayed.');
        // Verify that the main admin sections are available.
        $this->drupalGet('admin');
        $this->assertText(t('Content'));
        $this->assertText(t('Appearance'));
        $this->assertText(t('People'));
        $this->assertText(t('Configuration'));
        $this->assertText(t('Reports'));
        $this->assertText(t('Structure'));
        $this->assertText(t('Modules'));
        // Confirm that no {menu_links} entry exists for user/autocomplete.
        $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(
            ':user_autocomplete' => 'user/autocomplete',
        ))->fetchField();
        $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
        // Test that the environment after the upgrade is in a consistent status.
        $update_d6 = variable_get('update_d6', FALSE);
        $this->assertFalse($update_d6, 'The D6 upgrade flag variable has been correctly disabled.');
    }

}

/**
 * Performs point release update tests on a bare database.
 *
 * Loads an installation of Drupal 7.0 and runs the update process on it.
 *
 * The install contains the standard profile (plus all optional) modules
 * without any content so that an update from any of the modules under this
 * profile installation can be wholly tested.
 */
class BasicStandardUpdatePath extends UpdatePathTestCase {
    public static function getInfo() {
        return array(
            'name' => 'Basic standard + all profile update path',
            'description' => 'Basic update path tests for a standard profile install with all enabled modules.',
            'group' => 'Upgrade path',
        );
    }
    public function setUp() {
        // Path to the database dump files.
        $this->databaseDumpFiles = array(
            drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz',
        );
        parent::setUp();
    }
    
    /**
     * Tests a successful point release update.
     */
    public function testBasicStandardUpdate() {
        $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
        // Hit the frontpage.
        $this->drupalGet('');
        $this->assertResponse(200);
        // Verify that we are still logged in.
        $this->drupalGet('user');
        $this->clickLink(t('Edit'));
        $this->assertEqual($this->getUrl(), url('user/1/edit', array(
            'absolute' => TRUE,
        )), 'We are still logged in as admin at the end of the upgrade.');
        // Logout and verify that we can login back in with our initial password.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // The previous login should've triggered a password rehash, so login one
        // more time to make sure the new hash is readable.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // Test that the site name is correctly displayed.
        $this->assertText('Drupal', 'The site name is correctly displayed.');
        // Verify that the main admin sections are available.
        $this->drupalGet('admin');
        $this->assertText(t('Content'));
        $this->assertText(t('Appearance'));
        $this->assertText(t('People'));
        $this->assertText(t('Configuration'));
        $this->assertText(t('Reports'));
        $this->assertText(t('Structure'));
        $this->assertText(t('Modules'));
        // Confirm that no {menu_links} entry exists for user/autocomplete.
        $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(
            ':user_autocomplete' => 'user/autocomplete',
        ))->fetchField();
        $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
    }

}

/**
 * Performs point release update tests on a bare database.
 *
 * Loads an installation of Drupal 7.0 and runs the update process on it.
 *
 * The install contains the minimal profile modules (without any generated
 * content) so that an update from of a site under this profile may be tested.
 */
class BasicMinimalUpdatePath extends UpdatePathTestCase {
    public static function getInfo() {
        return array(
            'name' => 'Basic minimal profile update path',
            'description' => 'Basic update path tests for a minimal profile install.',
            'group' => 'Upgrade path',
        );
    }
    public function setUp() {
        // Path to the database dump files.
        $this->databaseDumpFiles = array(
            drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.bare.minimal.database.php.gz',
        );
        parent::setUp();
    }
    
    /**
     * Tests a successful point release update.
     */
    public function testBasicMinimalUpdate() {
        $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
        // Hit the frontpage.
        $this->drupalGet('');
        $this->assertResponse(200);
        // Verify that we are still logged in.
        $this->drupalGet('user');
        $this->clickLink(t('Edit'));
        $this->assertEqual($this->getUrl(), url('user/1/edit', array(
            'absolute' => TRUE,
        )), 'We are still logged in as admin at the end of the upgrade.');
        // Logout and verify that we can login back in with our initial password.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // The previous login should've triggered a password rehash, so login one
        // more time to make sure the new hash is readable.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // Test that the site name is correctly displayed.
        $this->assertText('Drupal', 'The site name is correctly displayed.');
        // Verify that the main admin sections are available.
        $this->drupalGet('admin');
        $this->assertText(t('Content'));
        $this->assertText(t('Appearance'));
        $this->assertText(t('People'));
        $this->assertText(t('Configuration'));
        $this->assertText(t('Reports'));
        $this->assertText(t('Structure'));
        $this->assertText(t('Modules'));
        // Confirm that no {menu_links} entry exists for user/autocomplete.
        $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(
            ':user_autocomplete' => 'user/autocomplete',
        ))->fetchField();
        $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
        // Confirm that a date format that just differs in the case can be added.
        $admin_date_format = 'j M y';
        $edit = array(
            'date_format' => $admin_date_format,
        );
        $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
        // Add a new date format which just differs in the case.
        $admin_date_format_uppercase = 'j M Y';
        $edit = array(
            'date_format' => $admin_date_format_uppercase,
        );
        $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
        $this->assertText(t('Custom date format added.'));
        // Verify that the unique key on {date_formats}.format still exists.
        try {
            // The PostgreSQL driver appends suffixes to keys/indexes according to
            // their types. A unique key is a key (not an index), so it has a _key
            // suffix. It is not possible to call db_index_exists() as this function
            // will check the index name with _idx suffix, so it will never succeed on
            // PostgreSQL. An attempt to create a new unique key when it exists should
            // fail and the thrown exception will confirm that the unique key exists.
            // MySQL and SQLite are not affected by this change, as they do not append
            // suffixes to keys/indexes names.
            db_add_unique_key('date_formats', 'formats', array(
                'formats',
            ));
            // This is executed if no exception has been thrown and the unique key
            // did not already exist.
            $this->fail('Unique key on {date_formats} does not exist');
        } catch (DatabaseSchemaObjectExistsException $e) {
            // Exception confirms that the unique key already existed.
            $this->pass('Unique key on {date_formats} exists');
        }
    }

}

/**
 * Performs point release update tests on a 'filled' database.
 *
 * Loads an installation of Drupal 7.0 and runs the update process on it.
 *
 * The install contains the standard profile (plus all optional) modules
 * with generated content so that an update from any of the modules under this
 * profile installation can be wholly tested.
 */
class FilledStandardUpdatePath extends UpdatePathTestCase {
    public static function getInfo() {
        return array(
            'name' => 'Basic standard + all profile update path, populated database',
            'description' => 'Basic update path tests for a standard profile install with all enabled modules and a populated database.',
            'group' => 'Upgrade path',
        );
    }
    public function setUp() {
        // Path to the database dump files.
        $this->databaseDumpFiles = array(
            drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.filled.standard_all.database.php.gz',
        );
        parent::setUp();
    }
    
    /**
     * Tests a successful point release update.
     */
    public function testFilledStandardUpdate() {
        $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
        // Hit the frontpage.
        $this->drupalGet('');
        $this->assertResponse(200);
        // Verify that we are still logged in.
        $this->drupalGet('user');
        $this->clickLink(t('Edit'));
        $this->assertEqual($this->getUrl(), url('user/1/edit', array(
            'absolute' => TRUE,
        )), 'We are still logged in as admin at the end of the upgrade.');
        // Logout and verify that we can login back in with our initial password.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // The previous login should've triggered a password rehash, so login one
        // more time to make sure the new hash is readable.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // Test that the site name is correctly displayed.
        $this->assertText('Drupal', 'The site name is correctly displayed.');
        // Verify that the main admin sections are available.
        $this->drupalGet('admin');
        $this->assertText(t('Content'));
        $this->assertText(t('Appearance'));
        $this->assertText(t('People'));
        $this->assertText(t('Configuration'));
        $this->assertText(t('Reports'));
        $this->assertText(t('Structure'));
        $this->assertText(t('Modules'));
        // Confirm that no {menu_links} entry exists for user/autocomplete.
        $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(
            ':user_autocomplete' => 'user/autocomplete',
        ))->fetchField();
        $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
    }

}

/**
 * Performs point release update tests on a populated database.
 *
 * Loads an installation of Drupal 7.0 and runs the update process on it.
 *
 * The install contains the minimal profile modules (along with generated
 * content) so that an update from of a site under this profile may be tested.
 */
class FilledMinimalUpdatePath extends UpdatePathTestCase {
    public static function getInfo() {
        return array(
            'name' => 'Basic minimal profile update path, populated database',
            'description' => 'Basic update path tests for a minimal profile install with a populated database.',
            'group' => 'Upgrade path',
        );
    }
    public function setUp() {
        // Path to the database dump files.
        $this->databaseDumpFiles = array(
            drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.filled.minimal.database.php.gz',
        );
        parent::setUp();
    }
    
    /**
     * Tests a successful point release update.
     */
    public function testFilledStandardUpdate() {
        $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
        // Hit the frontpage.
        $this->drupalGet('');
        $this->assertResponse(200);
        // Verify that we are still logged in.
        $this->drupalGet('user');
        $this->clickLink(t('Edit'));
        $this->assertEqual($this->getUrl(), url('user/1/edit', array(
            'absolute' => TRUE,
        )), 'We are still logged in as admin at the end of the upgrade.');
        // Logout and verify that we can login back in with our initial password.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // The previous login should've triggered a password rehash, so login one
        // more time to make sure the new hash is readable.
        $this->drupalLogout();
        $this->drupalLogin((object) array(
            'uid' => 1,
            'name' => 'admin',
            'pass_raw' => 'admin',
        ));
        // Test that the site name is correctly displayed.
        $this->assertText('Drupal', 'The site name is correctly displayed.');
        // Verify that the main admin sections are available.
        $this->drupalGet('admin');
        $this->assertText(t('Content'));
        $this->assertText(t('Appearance'));
        $this->assertText(t('People'));
        $this->assertText(t('Configuration'));
        $this->assertText(t('Reports'));
        $this->assertText(t('Structure'));
        $this->assertText(t('Modules'));
        // Confirm that no {menu_links} entry exists for user/autocomplete.
        $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(
            ':user_autocomplete' => 'user/autocomplete',
        ))->fetchField();
        $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
    }

}

Classes

Title Deprecated Summary
BasicMinimalUpdatePath Performs point release update tests on a bare database.
BasicStandardUpdatePath Performs point release update tests on a bare database.
BasicUpgradePath Perform basic upgrade tests.
FilledMinimalUpdatePath Performs point release update tests on a populated database.
FilledStandardUpdatePath Performs point release update tests on a 'filled' database.
UpdatePathTestCase Performs end-to-end point test of the release update path.
UpgradePathTestCase Perform end-to-end tests of the upgrade path.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.