owner = $this->drupalCreateUser($perms); $this->drupalLogin($this->owner); $this->maintainer = $this->drupalCreateUser($perms); } /** * Assert that a field in the current page is enabled. * @TODO Remove this when http://drupal.org/node/882564 is committed. * * @param $name * name of field to assert. * @param $message * Message to display. * @return * TRUE on pass, FALSE on fail. */ function assertFieldEnabled($name, $message = '') { $elements = $this->xpath('//input[@name="' . $name . '"]'); return $this->assertTrue(isset($elements[0]) && empty($elements[0]['disabled']), $message ? $message : t('Field @name is enabled.', array('@name' => $name))); } /** * Assert that a field in the current page is disabled. * @TODO Remove this when http://drupal.org/node/882564 is committed. * * @param $name * name of field to assert. * @param $message * Message to display. * @return * TRUE on pass, FALSE on fail. */ function assertFieldDisabled($name, $message = '') { $elements = $this->xpath('//input[@name="' . $name . '"]'); return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['disabled']), $message ? $message : t('Field @name is disabled.', array('@name' => $name))); } /** * Assert that a checkbox field in the current page is not checked. * * @param $name * name of field to assert. * @param $message * Message to display. * @return * TRUE on pass, FALSE on fail. */ protected function assertNoFieldCheckedByName($name, $message = '') { $elements = $this->xpath('//input[@name="' . $name . '"]'); return $this->assertTrue(isset($elements[0]) && empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is not checked.', array('@id' => $name)), t('Browser')); } /** * Assert that a checkbox field in the current page is checked. * * @param $name * name of field to assert. * @param $message * Message to display. * @return * TRUE on pass, FALSE on fail. */ protected function assertFieldCheckedByName($name, $message = '') { $elements = $this->xpath('//input[@name="' . $name . '"]'); return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is checked.', array('@id' => $name)), t('Browser')); } /** * Helper function for creating a new project. * * @param $edit array * An array of form values to be passed to DrupalWebTestCase::drupalPost(). */ function createProject($edit = array()) { $edit += array( 'title' => $this->randomName(), 'project[uri]' => $this->randomName(8), 'body' => $this->randomString(128), 'project[homepage]' => 'http://example.com/' . $this->randomName(), 'project[documentation]' => 'http://example.com/' . $this->randomName(), 'project[license]' => 'http://example.com/' . $this->randomName(), 'project[screenshots]' => 'http://example.com/' . $this->randomName(), 'project[changelog]' => 'http://example.com/' . $this->randomName(), 'project[demo]' => 'http://example.com/' . $this->randomName(), ); $this->drupalPost('node/add/project-project', $edit, t('Save')); $this->assertRaw(t('!post %title has been created.', array('!post' => 'Project', '%title' => $edit["title"])), t('Project created.')); return $this->drupalGetNodeByTitle($edit['title']); } } class ProjectTestCase extends ProjectWebTestCase { public static function getInfo() { return array( 'name' => 'Project functionality', 'description' => 'Test Project module functionality.', 'group' => 'Project' ); } function setUp() { parent::setUp('path'); $maintain_user = $this->drupalCreateUser(array('create full projects')); $this->drupalLogin($maintain_user); } /** * Test the creation of projects and the display of project properties. */ function testProjectCreation() { // Test project node form fields. $this->drupalGet('node/add/project-project'); $this->assertText(t('Create Project')); // Create a project and verify that all fields are shown. $edit = array(); $edit['title'] = $this->randomName(); $edit['project[uri]'] = $this->randomName(8); $edit['body'] = $this->randomName(128); $edit['project[homepage]'] = 'http://example.com/' . $this->randomName(); $edit['project[documentation]'] = 'http://example.com/' . $this->randomName(); $edit['project[license]'] = 'http://example.com/' . $this->randomName(); $edit['project[screenshots]'] = 'http://example.com/' . $this->randomName(); $edit['project[changelog]'] = 'http://example.com/' . $this->randomName(); $edit['project[demo]'] = 'http://example.com/' . $this->randomName(); $this->createProject($edit); // Check that all links show up properly. $this->drupalGet('project/'. $edit['project[uri]']); $this->assertText($edit['title'], t('Project found using project URI.')); $this->assertLink(t('Home page')); $this->assertRaw($edit['project[homepage]'], t('Project homepage displayed properly.')); $this->assertLink(t('Read documentation')); $this->assertRaw($edit['project[documentation]'], t('Project documentation displayed properly.')); $this->assertLink(t('Read license')); $this->assertRaw($edit['project[license]'], t('Project license displayed properly.')); $this->assertLink(t('Look at screenshots')); $this->assertRaw($edit['project[screenshots]'], t('Project screenshots displayed properly.')); $this->assertLink(t('Read complete log of changes')); $this->assertRaw($edit['project[changelog]'], t('Project changelog displayed properly.')); $this->assertLink(t('Try out a demonstration')); $this->assertRaw($edit['project[demo]'], t('Project changelog displayed properly.')); $this->assertText($edit['body'], t('Project description found.')); } function testProjectEdit() { $project = $this->createProject(); // Check the the URI is properly hidden when updates are not allowed $this->drupalGet('node/'. $project->nid .'/edit'); $this->assertFieldByName('project[uri]', '', 'Shortname field displayed correctly'); variable_set('project_allow_uri_update', FALSE); $this->drupalGet('node/'. $project->nid .'/edit'); $this->assertNoFieldByName('project[uri]', '', 'Shortname field locked from editing'); } } class ProjectDrupalOrgWebTestCase extends ProjectWebTestCase { /** * Admin level user that can access all necessary pages. * * @var object */ protected $admin_user; /** * List of project nodes created for testing. * * @var array */ protected $projects = array(); /** * List of release nodes created for testing. * * @var array */ protected $releases = array(); public static function getInfo() { return array( 'name' => 'Project suite setup', 'description' => 'Setup functionality similar to Drupal.org for testing functionaltiy of the Project suite.', 'group' => 'Project' ); } function setUp() { parent::setUp( 'taxonomy', 'project', 'project_issue', 'project_release', 'views', 'comment_upload', 'upload' ); // Create administrator user which can access all necessary pages. $this->admin_user = $this->drupalCreateUser(array( 'access projects', 'administer projects', 'create full projects', 'access project issues', 'create project issues', 'administer content types', 'upload files', 'upload files to comments', 'view uploaded files', 'view files uploaded to comments', 'administer site configuration', 'administer taxonomy', )); // Temporarily set vocabulary to remove notices during login. _project_get_vid(); variable_set('project_release_api_vocabulary', 1); // Login and setup environment. $this->drupalLogin($this->admin_user); $this->setUpTaxonomy(); $this->setUpProject(); } /** * Create project and release taxonomy. */ protected function setUpTaxonomy() { // Project types $vid = _project_get_vid(); $this->setUpTaxonomyTerms($vid, array('Drupal project', 'Modules')); // Release type. $edit = array( 'name' => t('Release type'), 'multiple' => 1, 'hierarchy' => 1, 'relations' => 0, 'module' => 'project', 'nodes' => array('project_release' => 1), ); taxonomy_save_vocabulary($edit); $vid = $edit['vid']; $this->setUpTaxonomyTerms($vid, array('Bug fixes', 'New features', 'Security release')); // Core compatibility. $edit = array( 'name' => t('Core compatibility'), 'multiple' => 1, 'hierarchy' => 1, 'relations' => 0, 'required' => 1, 'module' => 'project_release', 'nodes' => array('project_release' => 1), ); taxonomy_save_vocabulary($edit); $vid = $edit['vid']; // Set the variable to ensure that _project_release_get_api_vid() works. variable_set('project_release_api_vocabulary', $vid); $this->setUpTaxonomyTerms($vid, array('5.x', '6.x', '7.x', '8.x')); } /** * Create taxonomy terms for given vocabulary ID. * * @param integer $vid Vocabulary ID. * @param array $terms List of terms to add to vocabulary. */ protected function setUpTaxonomyTerms($vid, array $terms) { // Visit taxonomy page ahead of time to remove all get requests from loop. $this->drupalGet('admin/content/taxonomy/' . $vid . '/add/term'); foreach ($terms as $term) { $edit = array( 'name' => $term, ); $this->drupalPost(NULL, $edit, t('Save')); } } /** * Setup project related information and create dummy projects/releases. * * Projects: * - Drupal: 7.x-dev * - Foo: 7.x-1.x-dev * - Bar: 7.x-1.x-dev */ protected function setUpProject() { // Set project settings, required for auto-followups to function. $edit = array( 'project_issue_followup_user' => $this->admin_user->name, ); $this->drupalPost('admin/project/project-issue-settings', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); // Set project release to work with 6.x and 7.x compatibility terms and use // the drupal.org style version format. $edit = array( 'project_release_default_version_format' => '!api#major%patch#extra', 'project_release_active_compatibility_tids[7]' => TRUE, // 6.x. 'project_release_active_compatibility_tids[8]' => TRUE, // 7.x. ); $this->drupalPost('admin/project/project-release-settings', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); // Enable attachments on project issues. $edit = array( 'upload' => 1, 'comment_preview' => 0, // Optional. 'comment_form_location' => 1, // Display below post or comments. ); $this->drupalPost('admin/content/node-type/project-issue', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been added.', array('%type' => 'Issue'))); // Allow uploading of .patch and .diff files. $edit = array( 'upload_extensions_default' => 'txt patch diff', ); $this->drupalPost('admin/settings/uploads', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); // Setup Drupal core and contrib projects. foreach (array('drupal', 'foo', 'bar') as $project) { // Drupal core must be treated differently. $core = ($project == 'drupal') ? TRUE : FALSE; // Create project and load project node for later use. $edit = array( 'project_type' => $core ? 1 : 2, 'title' => ucfirst($project), 'project[uri]' => $project, 'body' => $this->randomString(64), ); $this->projects[$project] = $this->createProject($edit); } foreach ($this->projects as $project) { $core = ($project->title == 'Drupal') ? TRUE : FALSE; // Drupal core requires a special version format string. if ($core) { $edit = array( 'version_format' => '!major%minor%patch#extra', ); $this->drupalPost('node/' . $project->nid . '/edit/releases', $edit, t('Save')); } // Create 7.x release for project. $edit = array( 'taxonomy[3][]' => 8, // 7.x. 'project_release[version_major]' => $core ? '7' : '1', 'project_release[version_patch]' => 'x', 'project_release[version_extra]' => 'dev', 'body' => $this->randomString(64), ); $this->drupalPost('node/add/project-release/' . $project->nid, $edit, t('Save')); $this->releases[$project->title] = $this->drupalGetNodeByTitle($project->title . ' 7.x' . ($core ? '' : ' -1.x') . '-dev'); } } } class ProjectMaintainersTestCase extends ProjectWebTestCase { public static function getInfo() { return array( 'name' => 'Project maintainers functionality', 'description' => 'Test Project module maintainers access control system.', 'group' => 'Project' ); } function setUp() { parent::setUp(); } /** * Test maintainer permissions. */ function testProjectMaintainerPermissions() { // Create project, make sure Maintainers link is shown $project = $this->createProject(); // Check that owner can access $this->drupalGet("node/$project->nid/edit"); $this->assertResponse(200, 'Project owner can edit project.'); // Check the maintainers tab is shown and owner is included correctly $this->drupalGet("node/$project->nid"); $this->assertLink(t('Maintainers'), 0, ('Maintainers tab is shown.')); $this->drupalGet("node/$project->nid/maintainers"); $this->assertLink($this->owner->name, 0, ('Project owner is displayed on form.')); $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][edit project]", 'Checkbox is disabled for project owner'); $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Checkbox is disabled for project owner'); $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][edit project]", 'Owners permissions are automatically granted'); $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Owners permissions are automatically granted'); $this->assertNoRaw("node/$project->nid/maintainers/delete/{$this->owner->uid}", 'No delete link is displayed for the project owner.'); // Try to delete the owner anyway and make sure it fails. $this->drupalGet("node/$project->nid/maintainers/delete/{$this->owner->uid}"); $this->assertText("You can not delete the project owner ({$this->owner->name}) as a maintainer.", 'Project owner can not be deleted as a maintainer.'); // Verify that other users do not have access $this->drupalLogin($this->maintainer); $this->drupalGet("node/$project->nid/edit"); $this->assertResponse(403, 'Project edit form is protected.'); $this->drupalGet("node/$project->nid/maintainers"); $this->assertResponse(403, 'Project maintainers form is protected.'); $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}"); $this->assertResponse(403, 'Project delete maintainer form is protected.'); // Add a new user and verify that they are added: // Login as owner $this->drupalLogin($this->owner); // Add new user $edit = array(); $edit['new_maintainer[user]'] = $this->maintainer->name; $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update')); $this->assertLink($this->maintainer->name, 0, 'New user is displayed on form correctly.'); $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions not explicitly granted.'); $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions not explicitly granted.'); // Test validation for adding a duplicate maintainer $edit = array(); $edit['new_maintainer[user]'] = $this->maintainer->name; $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update')); $this->assertText("{$this->maintainer->name} is already a maintainer of this project.", 'Duplicate maintainers are not permitted.'); // Add permissions to user $edit = array(); $edit["maintainers[{$this->maintainer->uid}][permissions][edit project]"] = TRUE; $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update')); $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions are displayed correctly on maintainers form.'); // Login as maintainer and check access $this->drupalLogin($this->maintainer); $this->drupalGet("node/$project->nid/edit"); $this->assertResponse(200, 'User is correctly granted access to project edit form.'); $this->drupalGet("node/$project->nid/maintainers"); $this->assertResponse(403, 'Project maintainers form is protected.'); $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}"); $this->assertResponse(403, 'Project delete maintainer form is protected.'); // Have owner grant administer maintainers permission $this->drupalLogin($this->owner); // Add permissions to user $edit = array(); $edit["maintainers[{$this->maintainer->uid}][permissions][administer maintainers]"] = TRUE; $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update')); $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions are displayed correctly on maintainers form.'); // Login as maintainer and check access $this->drupalLogin($this->maintainer); $this->drupalGet("node/$project->nid/maintainers"); $this->assertResponse(200, 'User is correctly granted access to project edit form.'); // Remove the user from the project $this->drupalLogin($this->owner); $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}"); $this->assertText("Are you sure you want to delete {$this->maintainer->name} as a maintainer of {$project->title}?", 'Deletion page is displayed properly.'); $this->drupalPost(NULL, array(), t('Delete')); $this->assertText("Removed {$this->maintainer->name} as a maintainer.", 'Project maintainer successfully deleted.'); // Verify that access has been removed $this->drupalLogin($this->maintainer); $this->drupalGet("node/$project->nid/edit"); $this->assertResponse(403, 'Project edit form is protected.'); $this->drupalGet("node/$project->nid/maintainers"); $this->assertResponse(403, 'Project maintainers form is protected.'); } }