/** * {@inheritdoc} */ public static function migrateDumpAlter(TestBase $test) { // Creates a random filename and updates the source database. $random = new Random(); $temp_directory = $test->getTempFilesDirectory(); file_prepare_directory($temp_directory, FILE_CREATE_DIRECTORY); static::$tempFilename = $test->getDatabasePrefix() . $random->name() . '.jpg'; $file_path = $temp_directory . '/' . static::$tempFilename; file_put_contents($file_path, ''); Database::getConnection('default', 'migrate')->update('files')->condition('fid', 6)->fields(array('filename' => static::$tempFilename, 'filepath' => $file_path))->execute(); return static::$tempFilename; }
/** * Test the complete Drupal migration. */ public function testDrupal() { $dumps = $this->getDumps(); $this->loadDumps($dumps); $classes = $this->getTestClassesList(); foreach ($classes as $class) { if (is_subclass_of($class, '\\Drupal\\migrate\\Tests\\MigrateDumpAlterInterface')) { $class::migrateDumpAlter($this); } } // Run every migration in the order specified by the storage controller. foreach (entity_load_multiple('migration', static::$migrations) as $migration) { (new MigrateExecutable($migration, $this))->import(); } foreach ($classes as $class) { $test_object = new $class($this->testId); $test_object->databasePrefix = $this->databasePrefix; $test_object->container = $this->container; // run() does a lot of setup and tear down work which we don't need: // it would setup a new database connection and wouldn't find the // Drupal dump. Also by skipping the setUp() methods there are no id // mappings or entities prepared. The tests run against solely migrated // data. foreach (get_class_methods($test_object) as $method) { if (strtolower(substr($method, 0, 4)) == 'test') { // Insert a fail record. This will be deleted on completion to ensure // that testing completed. $method_info = new \ReflectionMethod($class, $method); $caller = array('file' => $method_info->getFileName(), 'line' => $method_info->getStartLine(), 'function' => $class . '->' . $method . '()'); $completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller); // Run the test method. try { $test_object->{$method}(); } catch (\Exception $e) { $this->exceptionHandler($e); } // Remove the completion check record. TestBase::deleteAssert($completion_check_id); } } // Add the pass/fail/exception/debug results. foreach ($this->results as $key => &$value) { $value += $test_object->results[$key]; } } }
/** * Cleans up after testing. * * Deletes created files and temporary files directory, deletes the tables * created by setUp(), and resets the database prefix. */ protected function tearDown() { // Destroy the testing kernel. if (isset($this->kernel)) { $this->kernel->shutdown(); } parent::tearDown(); // Ensure that the maximum meta refresh count is reset. $this->maximumMetaRefreshCount = NULL; // Ensure that internal logged in variable and cURL options are reset. $this->loggedInUser = FALSE; $this->additionalCurlOptions = array(); // Close the CURL handler and reset the cookies array used for upgrade // testing so test classes containing multiple tests are not polluted. $this->curlClose(); $this->curlCookies = array(); $this->cookies = array(); }
/** * Data provider for ::testCommentLinkBuilder. */ public function getLinkCombinations() { $cases = array(); // No links should be created if the entity doesn't have the field. $cases[] = array($this->getMockNode(FALSE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1), array('view_mode' => 'teaser'), TRUE, TRUE, TRUE, TRUE, array()); foreach (array('search_result', 'search_index', 'print') as $view_mode) { // Nothing should be output in these view modes. $cases[] = array($this->getMockNode(TRUE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1), array('view_mode' => $view_mode), TRUE, TRUE, TRUE, TRUE, array()); } // All other combinations. $combinations = array('is_anonymous' => array(FALSE, TRUE), 'comment_count' => array(0, 1), 'has_access_comments' => array(0, 1), 'history_exists' => array(FALSE, TRUE), 'has_post_comments' => array(0, 1), 'form_location' => array(CommentItemInterface::FORM_BELOW, CommentItemInterface::FORM_SEPARATE_PAGE), 'comments' => array(CommentItemInterface::OPEN, CommentItemInterface::CLOSED, CommentItemInterface::HIDDEN), 'view_mode' => array('teaser', 'rss', 'full')); $permutations = TestBase::generatePermutations($combinations); foreach ($permutations as $combination) { $case = array($this->getMockNode(TRUE, $combination['comments'], $combination['form_location'], $combination['comment_count']), array('view_mode' => $combination['view_mode']), $combination['has_access_comments'], $combination['history_exists'], $combination['has_post_comments'], $combination['is_anonymous']); $expected = array(); // When comments are enabled in teaser mode, and comments exist, and the // user has access - we can output the comment count. if ($combination['comments'] && $combination['view_mode'] == 'teaser' && $combination['comment_count'] && $combination['has_access_comments']) { $expected['comment-comments'] = '1 comment'; // And if history module exists, we can show a 'new comments' link. if ($combination['history_exists']) { $expected['comment-new-comments'] = ''; } } // All view modes other than RSS. if ($combination['view_mode'] != 'rss') { // Where commenting is open. if ($combination['comments'] == CommentItemInterface::OPEN) { // And the user has post-comments permission. if ($combination['has_post_comments']) { // If the view mode is teaser, or the user can access comments and // comments exist or the form is on a separate page. if ($combination['view_mode'] == 'teaser' || $combination['has_access_comments'] && $combination['comment_count'] || $combination['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE) { // There should be a add comment link. $expected['comment-add'] = array('title' => 'Add new comment'); if ($combination['form_location'] == CommentItemInterface::FORM_BELOW) { // On the same page. $expected['comment-add']['url'] = Url::fromRoute('node.view'); } else { // On a separate page. $expected['comment-add']['url'] = Url::fromRoute('comment.reply', ['entity_type' => 'node', 'entity' => 1, 'field_name' => 'comment']); } } } elseif ($combination['is_anonymous']) { // Anonymous users get the forbidden message if the can't post // comments. $expected['comment-forbidden'] = "Can't let you do that Dave."; } } } $case[] = $expected; $cases[] = $case; } return $cases; }
/** * {@inheritdoc} */ protected function tearDown() { if ($this->kernel instanceof DrupalKernel) { $this->kernel->shutdown(); } // Before tearing down the test environment, ensure that no stream wrapper // of this test leaks into the parent environment. Unlike all other global // state variables in Drupal, stream wrappers are a global state construct // of PHP core, which has to be maintained manually. // @todo Move StreamWrapper management into DrupalKernel. // @see https://www.drupal.org/node/2028109 foreach ($this->streamWrappers as $scheme => $type) { $this->unregisterStreamWrapper($scheme, $type); } parent::tearDown(); }
/** * Run all tests in this class. * * Regardless of whether $methods are passed or not, only method names * starting with "test" are executed. * * @param $methods * (optional) A list of method names in the test case class to run; e.g., * array('testFoo', 'testBar'). By default, all methods of the class are * taken into account, but it can be useful to only run a few selected test * methods during debugging. */ public function run(array $methods = array()) { $class = get_class($this); if ($missing_requirements = $this->checkRequirements()) { $object_info = new \ReflectionObject($this); $caller = array('file' => $object_info->getFileName()); foreach ($missing_requirements as $missing_requirement) { TestBase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check', $caller); } return; } TestServiceProvider::$currentTest = $this; $simpletest_config = $this->config('simpletest.settings'); // Unless preset from run-tests.sh, retrieve the current verbose setting. if (!isset($this->verbose)) { $this->verbose = $simpletest_config->get('verbose'); } if ($this->verbose) { // Initialize verbose debugging. $this->verbose = TRUE; $this->verboseDirectory = PublicStream::basePath() . '/simpletest/verbose'; $this->verboseDirectoryUrl = file_create_url($this->verboseDirectory); if (file_prepare_directory($this->verboseDirectory, FILE_CREATE_DIRECTORY) && !file_exists($this->verboseDirectory . '/.htaccess')) { file_put_contents($this->verboseDirectory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n"); } $this->verboseClassName = str_replace("\\", "_", $class); } // HTTP auth settings (<username>:<password>) for the simpletest browser // when sending requests to the test site. $this->httpAuthMethod = (int) $simpletest_config->get('httpauth.method'); $username = $simpletest_config->get('httpauth.username'); $password = $simpletest_config->get('httpauth.password'); if (!empty($username) && !empty($password)) { $this->httpAuthCredentials = $username . ':' . $password; } set_error_handler(array($this, 'errorHandler')); // Iterate through all the methods in this class, unless a specific list of // methods to run was passed. $test_methods = array_filter(get_class_methods($class), function ($method) { return strpos($method, 'test') === 0; }); if (empty($test_methods)) { // Call $this->assert() here because we need to pass along custom caller // information, lest the wrong originating code file/line be identified. $this->assert(FALSE, 'No test methods found.', 'Requirements', array('function' => __METHOD__ . '()', 'file' => __FILE__, 'line' => __LINE__)); } if ($methods) { $test_methods = array_intersect($test_methods, $methods); } foreach ($test_methods as $method) { // Insert a fail record. This will be deleted on completion to ensure // that testing completed. $method_info = new \ReflectionMethod($class, $method); $caller = array('file' => $method_info->getFileName(), 'line' => $method_info->getStartLine(), 'function' => $class . '->' . $method . '()'); $test_completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller); try { $this->prepareEnvironment(); } catch (\Exception $e) { $this->exceptionHandler($e); // The prepareEnvironment() method isolates the test from the parent // Drupal site by creating a random database prefix and test site // directory. If this fails, a test would possibly operate in the // parent site. Therefore, the entire test run for this test class // has to be aborted. // restoreEnvironment() cannot be called, because we do not know // where exactly the environment setup failed. break; } try { $this->setUp(); } catch (\Exception $e) { $this->exceptionHandler($e); // Abort if setUp() fails, since all test methods will fail. // But ensure to clean up and restore the environment, since // prepareEnvironment() succeeded. $this->restoreEnvironment(); break; } try { $this->{$method}(); } catch (\Exception $e) { $this->exceptionHandler($e); } try { $this->tearDown(); } catch (\Exception $e) { $this->exceptionHandler($e); // If a test fails to tear down, abort the entire test class, since // it is likely that all tests will fail in the same way and a // failure here only results in additional test artifacts that have // to be manually deleted. $this->restoreEnvironment(); break; } $this->restoreEnvironment(); // Remove the test method completion check record. TestBase::deleteAssert($test_completion_check_id); } TestServiceProvider::$currentTest = NULL; // Clear out the error messages and restore error handler. drupal_get_messages(); restore_error_handler(); }
/** * Test permissions on comment fields. */ public function testAccessToAdministrativeFields() { // Create a comment type. $comment_type = CommentType::create(['id' => 'comment', 'label' => 'Default comments', 'description' => 'Default comment field', 'target_entity_type_id' => 'entity_test']); $comment_type->save(); // Create a comment against a test entity. $host = EntityTest::create(); $host->save(); // An administrator user. No user exists yet, ensure that the first user // does not have UID 1. $comment_admin_user = $this->createUser(['uid' => 2, 'name' => 'admin'], ['administer comments', 'access comments']); // Two comment enabled users, one with edit access. $comment_enabled_user = $this->createUser(['name' => 'enabled'], ['post comments', 'skip comment approval', 'edit own comments', 'access comments']); $comment_no_edit_user = $this->createUser(['name' => 'no edit'], ['post comments', 'skip comment approval', 'access comments']); // An unprivileged user. $comment_disabled_user = $this->createUser(['name' => 'disabled'], ['access content']); $role = Role::load(RoleInterface::ANONYMOUS_ID); $role->grantPermission('post comments')->save(); $anonymous_user = new AnonymousUserSession(); // Add two fields. $this->addDefaultCommentField('entity_test', 'entity_test', 'comment'); $this->addDefaultCommentField('entity_test', 'entity_test', 'comment_other'); // Change the second field's anonymous contact setting. $instance = FieldConfig::loadByName('entity_test', 'entity_test', 'comment_other'); // Default is 'May not contact', for this field - they may contact. $instance->setSetting('anonymous', COMMENT_ANONYMOUS_MAY_CONTACT); $instance->save(); // Create three "Comments". One is owned by our edit-enabled user. $comment1 = Comment::create(['entity_type' => 'entity_test', 'name' => 'Tony', 'hostname' => 'magic.example.com', 'mail' => '*****@*****.**', 'subject' => 'Bruce the Mesopotamian moose', 'entity_id' => $host->id(), 'comment_type' => 'comment', 'field_name' => 'comment', 'pid' => 0, 'uid' => 0, 'status' => 1]); $comment1->save(); $comment2 = Comment::create(['entity_type' => 'entity_test', 'hostname' => 'magic.example.com', 'subject' => 'Brian the messed up lion', 'entity_id' => $host->id(), 'comment_type' => 'comment', 'field_name' => 'comment', 'status' => 1, 'pid' => 0, 'uid' => $comment_enabled_user->id()]); $comment2->save(); $comment3 = Comment::create(['entity_type' => 'entity_test', 'hostname' => 'magic.example.com', 'status' => 0, 'subject' => 'Gail the minky whale', 'entity_id' => $host->id(), 'comment_type' => 'comment', 'field_name' => 'comment_other', 'pid' => $comment2->id(), 'uid' => $comment_no_edit_user->id()]); $comment3->save(); // Note we intentionally don't save this comment so it remains 'new'. $comment4 = Comment::create(['entity_type' => 'entity_test', 'hostname' => 'magic.example.com', 'status' => 0, 'subject' => 'Daniel the Cocker-Spaniel', 'entity_id' => $host->id(), 'comment_type' => 'comment', 'field_name' => 'comment_other', 'pid' => 0, 'uid' => $anonymous_user->id()]); // Generate permutations. $combinations = ['comment' => [$comment1, $comment2, $comment3, $comment4], 'user' => [$comment_admin_user, $comment_enabled_user, $comment_no_edit_user, $comment_disabled_user, $anonymous_user]]; $permutations = TestBase::generatePermutations($combinations); // Check access to administrative fields. foreach ($this->administrativeFields as $field) { foreach ($permutations as $set) { $may_view = $set['comment']->{$field}->access('view', $set['user']); $may_update = $set['comment']->{$field}->access('edit', $set['user']); $this->assertTrue($may_view, SafeMarkup::format('User @user can view field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@comment' => $set['comment']->getSubject(), '@field' => $field])); $this->assertEqual($may_update, $set['user']->hasPermission('administer comments'), SafeMarkup::format('User @user @state update field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@state' => $may_update ? 'can' : 'cannot', '@comment' => $set['comment']->getSubject(), '@field' => $field])); } } // Check access to normal field. foreach ($permutations as $set) { $may_update = $set['comment']->access('update', $set['user']) && $set['comment']->subject->access('edit', $set['user']); $this->assertEqual($may_update, $set['user']->hasPermission('administer comments') || $set['user']->hasPermission('edit own comments') && $set['user']->id() == $set['comment']->getOwnerId(), SafeMarkup::format('User @user @state update field subject on comment @comment', ['@user' => $set['user']->getUsername(), '@state' => $may_update ? 'can' : 'cannot', '@comment' => $set['comment']->getSubject()])); } // Check read-only fields. foreach ($this->readOnlyFields as $field) { // Check view operation. foreach ($permutations as $set) { $may_view = $set['comment']->{$field}->access('view', $set['user']); $may_update = $set['comment']->{$field}->access('edit', $set['user']); // Nobody has access to view the hostname field. if ($field === 'hostname') { $view_access = FALSE; $state = 'cannot'; } else { $view_access = TRUE; $state = 'can'; } $this->assertEqual($may_view, $view_access, SafeMarkup::format('User @user @state view field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@comment' => $set['comment']->getSubject(), '@field' => $field, '@state' => $state])); $this->assertFalse($may_update, SafeMarkup::format('User @user @state update field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@state' => $may_update ? 'can' : 'cannot', '@comment' => $set['comment']->getSubject(), '@field' => $field])); } } // Check create-only fields. foreach ($this->createOnlyFields as $field) { // Check view operation. foreach ($permutations as $set) { $may_view = $set['comment']->{$field}->access('view', $set['user']); $may_update = $set['comment']->{$field}->access('edit', $set['user']); $this->assertEqual($may_view, TRUE, SafeMarkup::format('User @user can view field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@comment' => $set['comment']->getSubject(), '@field' => $field])); $this->assertEqual($may_update, $set['user']->hasPermission('post comments') && $set['comment']->isNew(), SafeMarkup::format('User @user @state update field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@state' => $may_update ? 'can' : 'cannot', '@comment' => $set['comment']->getSubject(), '@field' => $field])); } } // Check contact fields. foreach ($this->contactFields as $field) { // Check view operation. foreach ($permutations as $set) { $may_update = $set['comment']->{$field}->access('edit', $set['user']); // To edit the 'mail' or 'name' field, either the user has the // "administer comments" permissions or the user is anonymous and // adding a new comment using a field that allows contact details. $this->assertEqual($may_update, $set['user']->hasPermission('administer comments') || $set['user']->isAnonymous() && $set['comment']->isNew() && $set['user']->hasPermission('post comments') && $set['comment']->getFieldName() == 'comment_other', SafeMarkup::format('User @user @state update field @field on comment @comment', ['@user' => $set['user']->getUsername(), '@state' => $may_update ? 'can' : 'cannot', '@comment' => $set['comment']->getSubject(), '@field' => $field])); } } foreach ($permutations as $set) { // Check no view-access to mail field for other than admin. $may_view = $set['comment']->mail->access('view', $set['user']); $this->assertEqual($may_view, $set['user']->hasPermission('administer comments')); } }
/** * Constructor for UnitTestBase. */ function __construct($test_id = NULL) { parent::__construct($test_id); $this->skipClasses[__CLASS__] = TRUE; }
/** * Test the complete Drupal migration. */ public function testDrupal() { $dumps = $this->getDumps(); $this->loadDumps($dumps); $classes = $this->getTestClassesList(); $extension_install_storage = new ExtensionInstallStorage(\Drupal::service('config.storage'), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, TRUE); foreach ($classes as $class) { if (is_subclass_of($class, '\\Drupal\\migrate\\Tests\\MigrateDumpAlterInterface')) { $class::migrateDumpAlter($this); } } // Run every migration in the order specified by the storage controller. foreach (entity_load_multiple('migration', static::$migrations) as $migration) { (new MigrateExecutable($migration, $this))->import(); // Ensure that the default migration has the correct dependencies. list($base_name, ) = explode(':', $migration->id(), 2); $default_configuration = $extension_install_storage->read('migrate.migration.' . $base_name); $default_dependencies = isset($default_configuration['dependencies']) ? $default_configuration['dependencies'] : []; $this->assertEqual($default_dependencies, $migration->getDependencies(), SafeMarkup::format('Dependencies in @id match after installing. Default configuration @first is equal to active configuration @second.', array('@id' => $migration->id(), '@first' => var_export($default_dependencies, TRUE), '@second' => var_export($migration->getDependencies(), TRUE)))); } foreach ($classes as $class) { $test_object = new $class($this->testId); $test_object->databasePrefix = $this->databasePrefix; $test_object->container = $this->container; // run() does a lot of setup and tear down work which we don't need: // it would setup a new database connection and wouldn't find the // Drupal dump. Also by skipping the setUp() methods there are no id // mappings or entities prepared. The tests run against solely migrated // data. foreach (get_class_methods($test_object) as $method) { if (strtolower(substr($method, 0, 4)) == 'test') { // Insert a fail record. This will be deleted on completion to ensure // that testing completed. $method_info = new \ReflectionMethod($class, $method); $caller = array('file' => $method_info->getFileName(), 'line' => $method_info->getStartLine(), 'function' => $class . '->' . $method . '()'); $completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller); // Run the test method. try { $test_object->{$method}(); } catch (\Exception $e) { $this->exceptionHandler($e); } // Remove the completion check record. TestBase::deleteAssert($completion_check_id); } } // Add the pass/fail/exception/debug results. foreach ($this->results as $key => &$value) { $value += $test_object->results[$key]; } } }