You are here

function WorkbenchAccessMenuTestCase::testWorkbenchAccessMenu in Workbench Access 7

File

tests/workbench_access.test, line 433
Test file for Workbench Access.

Class

WorkbenchAccessMenuTestCase

Code

function testWorkbenchAccessMenu() {

  // Load all includes.
  workbench_access_load_include();

  // Create some node and users.
  $this
    ->createWorkbenchAccessUsers();
  $this
    ->createWorkbenchAccessNodes(30);

  // Set node titles for easier debugging.
  for ($i = 1; $i <= 30; $i++) {
    $node = node_load($i);
    $node->title = $this->node_titles[$i];
    node_save($node);
  }

  // Create a menu.
  $menu = array(
    'menu_name' => 'menu-workbench_access',
    'description' => '',
    'title' => $this
      ->randomName(16),
  );
  menu_save($menu);
  $menu_name = $menu['menu_name'];

  // Attach menu to content type.
  variable_set('menu_options_page', array(
    'menu_options[' . $menu_name . ']' => $menu_name,
  ));

  // Make all menu items access sections.
  variable_set('workbench_access_auto_assign', 1);

  // Set this menu as our active section.
  variable_set('workbench_access', 'menu');
  variable_set('workbench_access_menu', array(
    $menu_name,
  ));

  // Use a custom form element.
  variable_set('workbench_access_custom_form', 1);

  // Set up the top-level menu.
  $section = array(
    'access_id' => $menu_name,
    'access_scheme' => 'menu',
    'access_type' => 'menu',
    'access_type_id' => $menu_name,
  );
  workbench_access_section_save($section);

  /**
   * Assign menu links for nodes.
   * The hierarchy should four levels deep with two options per level
   * A helpful diagram
   *
   * A
   *   A1
   *     A1a
   *        A1a1
   *        A1a2
   *     A1b
   *        A1b1
   *        A1b2
   *   A2
   *     A2a
   *        A2a1
   *        A2a2
   *     A2b
   *        A2b1
   *        A2b2
   * B
   *   B1
   *     B1a
   *        B1a1
   *        B1a2
   *     B1b
   *        B1b1
   *        B1b2
   *   B2
   *     B2a
   *        B2a1
   *        B2a2
   *     B2b
   *        B2b1
   *        B2b2
   */
  $mlids = array();
  $nodes = db_query("SELECT nid, title FROM {node} ORDER BY nid")
    ->fetchAll();
  foreach ($nodes as $nid => $node) {

    // Create a menu item
    $settings = array(
      'link_path' => 'node/' . $node->nid,
      'link_title' => $node->title,
      'menu_name' => $menu_name,
      'weight' => $node->nid,
      'plid' => 0,
    );
    if ($nid > 1) {
      $settings['plid'] = $mlids[floor(($nid - 2) / 2)];
    }
    $mlids[] = menu_link_save($settings);
  }

  // Check that the menu scheme is setup correctly.
  $this
    ->assertWorkbenchScheme('menu', $menu_name);

  // Check for node creation.
  $count = db_query("SELECT COUNT(n.nid) FROM {node} n")
    ->fetchField();
  $this
    ->assertTrue($count == 30, t('Thirty initial nodes created.'));

  // Check for node assignment.
  $count = db_query("SELECT COUNT(n.nid) FROM {node} n INNER JOIN {workbench_access_node} wan ON n.nid = wan.nid")
    ->fetchField();
  $this
    ->assertTrue($count == 0, t('Initial nodes have no access data.'));

  // Save data for nodes.
  foreach ($nodes as $node) {
    $mlid = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :link_path", array(
      ':link_path' => 'node/' . $node->nid,
    ))
      ->fetchField();
    if (!isset($first_mlid)) {
      $first_mlid = $mlid;
    }
    $edit = array(
      'nid' => $node->nid,
      'access_id' => $mlid,
      'access_scheme' => 'menu',
    );
    db_insert('workbench_access_node')
      ->fields($edit)
      ->execute();
  }

  // Assign user 1 to the top-level.
  workbench_access_user_section_save(1, $menu_name, 'menu');

  // Check node data.
  $count = db_query("SELECT COUNT(n.nid) FROM {node} n INNER JOIN {workbench_access_node} wan ON n.nid = wan.nid")
    ->fetchField();
  $this
    ->assertTrue($count == 30, t('Initial nodes assigned access data.'));
  $active = workbench_access_get_active_tree();

  // Check that a node has been assigned to a first-level menu item.
  $count = db_query("SELECT COUNT(n.nid) FROM {node} n INNER JOIN {workbench_access_node} wan ON n.nid = wan.nid WHERE wan.access_id = :access_id AND wan.access_scheme = 'menu'", array(
    ':access_id' => $first_mlid,
  ))
    ->fetchField();
  $this
    ->assertTrue($count == 1, t('One node assigned to first-level menu item.'));

  // Test access settings of user 1.
  $account = user_load(1, TRUE);
  $this
    ->assertTrue(!empty($account->workbench_access[$menu_name]), t('User 1 assigned to top-level hierarchy.'));

  // End setup tests.
  // Assign a user to a section and check permissions.
  // This is a multi-step check.
  // First, the user should not be able to do anything (Create, Update or Delete).
  $account = $this
    ->getWorkbenchAccessUser();
  $id = $account->testId;
  $this
    ->assertTrue(empty($account->workbench_access[$menu_name]), t('Test user not assigned to a section.'));
  $nids = db_query("SELECT nid FROM {node}")
    ->fetchCol('nid');
  $nodes = node_load_multiple($nids);
  $assigned = TRUE;
  foreach ($nodes as $node) {

    // Just check if its set or not
    if (!isset($node->workbench_access) && !empty($node->workbench_access)) {
      $assigned = FALSE;
    }
  }
  $this
    ->assertTrue(!empty($assigned), t('All nodes properly assigned.'));
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('No sections'), FALSE);

  // Test that the role lookup function works correctly.
  $roles = workbench_access_get_roles('access workbench access by role');

  // The 'administrator' role always has permission.
  $this
    ->assertTrue(count($roles) == 2, t('One user role assigned.'));

  // Now, we assign the user to a section and check again.
  workbench_access_user_section_save($account->uid, $menu_name, 'menu');
  $account = user_load($account->uid, TRUE);
  $this
    ->assertTrue(!empty($account->workbench_access[$menu_name]), t('Test user assigned to top-level hierarchy.'));
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('Assigned sections'), TRUE);

  // Remove the permission to 'access workbench access by role' and check again.
  user_role_revoke_permissions($this->editor_role, array(
    'access workbench access by role',
  ));
  $account = user_load($account->uid, TRUE);
  $this
    ->assertTrue(empty($account->workbench_access[$menu_name]), t('Permission revoked and test user not assigned to a section.'));
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('Role disallowed'), FALSE);

  // Test that the role lookup function works correctly.
  drupal_static_reset('workbench_access_get_roles');
  $roles = workbench_access_get_roles('access workbench access by role');

  // The 'administrator' role always has permission. Ignore that.
  $this
    ->assertTrue(count($roles) == 1, t('One user roles assigned.'));

  // Now give them permissions again.
  user_role_grant_permissions($this->editor_role, array(
    'access workbench access by role',
  ));
  $account = user_load($account->uid, TRUE);
  $this
    ->assertTrue(!empty($account->workbench_access[$menu_name]), t('Permission reinstated and test user assigned to a section.'));
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('Role allowed'), TRUE);

  // Test the autocomplete query for adding new editors.
  drupal_static_reset('workbench_access_get_roles');
  module_load_include('inc', 'workbench_access', 'workbench_access.pages');

  // Search for the existing user via autocomplete. Should return empty.
  $test = workbench_access_autocomplete('menu', $menu_name, substr($account->name, 0), TRUE);
  $this
    ->assertTrue(empty($test), t('Autocomplete did not match assigned user.'));

  // Test another user who is currently not assigned.
  $test_account = $this
    ->getWorkbenchAccessUser($id);
  $test = workbench_access_autocomplete('menu', $menu_name, substr($test_account->name, 0, 1), TRUE);
  $this
    ->assertTrue(!empty($test), t('Autocomplete matched unassigned user.'));

  // Now take away the core permissions to page content and test.
  $perms = array(
    'create page content',
    'edit any page content',
    'delete any page content',
  );
  user_role_revoke_permissions($this->editor_role, $perms);
  $account = user_load($account->uid, TRUE);
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('Page access disallowed'), FALSE);

  // Now give back the core permissions.
  user_role_grant_permissions($this->editor_role, $perms);
  $account = user_load($account->uid, TRUE);
  $this
    ->assertWorkbenchAccessCheck($nodes, $account, t('Page access allowed'), TRUE);

  // Form testing in Drupal is horribly broken.
  // We can confirm that a form page is loaded, but cannot perform
  // any introspection on the $form array.
  $account->pass_raw = 'fubar';
  $this
    ->drupalLogin($account);

  // Set the form label.
  // Attempt to access edit page.
  $this
    ->drupalGet("node/{$node->nid}/edit");
  $this
    ->assertResponse(200);
  $this
    ->assertRaw('Section', t('Workbench Access field was found.'));

  // Note that the field is nested as
  // $form['workbench_access']['workbench_access'], which forces FormAPI to
  // add the --2 suffix to the id.
  $this
    ->assertRaw('<select id="edit-workbench-access--2" name="workbench_access" class="form-select required">', t('Form presents a select list with no multiple select.'));

  // Change some values and try again.
  variable_set('workbench_access_allow_multiple', 1);
  variable_set('workbench_access_label', 'TestWA');
  $this
    ->drupalGet("node/{$node->nid}/edit");
  $this
    ->assertRaw('TestWA', t('Workbench Access field was renamed.'));
  $this
    ->assertRaw('<select multiple="multiple" name="workbench_access[]" id="edit-workbench-access--2" class="form-select required">', t('Form presents a select list with multiple select.'));

  // Test module hooks.
  // Ensure that our node type uses the form element.
  $GLOBALS['conf']['workbench_access_node_type_' . $node->type] = TRUE;
  module_load_include('inc', 'node', 'node.pages');
  $form = drupal_get_form($node->type . '_node_form', $node);
  $this
    ->assertTrue(!empty($form['workbench_access']['workbench_access']['#workbench_access_test']), t('hook_workbench_access_node_element_alter() fired correctly.'));

  // Try some form introspection.
  $form = $this
    ->workbenchAccessNodeForm($account->uid, $node->type);
  $this
    ->assertTrue(isset($form['workbench_access']['workbench_access']['#options']), t('Form element returns properly.'));
  $this
    ->assertTrue(count($form['workbench_access']['workbench_access']['#options']) == 31, t('Form element returned thirty-one options (top menu and thirty nodes) to user with all sections.'));

  // Delete global permission.
  workbench_access_user_section_delete($account->uid, $menu_name, 'menu');

  // Add sub permission.
  $array = array_slice($active['tree'][$menu_name]['children'], 0, 1);
  $mlid = array_shift($array);
  workbench_access_user_section_save($account->uid, $mlid, 'menu');
  $form = $this
    ->workbenchAccessNodeForm($account->uid, $node->type);
  $this
    ->assertTrue(count($form['workbench_access']['workbench_access']['#options']) == 15, t('Form element returned fifteen options to user with limited options.'));

  // Test the form again using native support.
  // Do not set a custom form element.
  variable_set('workbench_access_custom_form', 0);
  $custom = variable_get('workbench_access_custom_form', 1);
  $this
    ->assertTrue(empty($custom), t('Switched to using native menu form.'));

  // Try some form introspection.
  $form = $this
    ->workbenchAccessNodeForm($account->uid, $node->type);
  $this
    ->assertTrue(count($form['menu']['link']['parent']['#options']) == 15, t('Native menu form element returned fifteen options to user with limited options.'));

  // Check that access control by node type settings work.
  $this
    ->assertTrue(variable_get('workbench_access_node_type_' . $node->type, 1), t('Workbench Access enforced for %type content.', array(
    '%type' => $node->type,
  )));

  // Force a fail by removing this user's access rules. Else it will just
  // return NODE_ACCESS_IGNORE, which cannot be tested.
  $account->workbench_access = array(
    'foo',
  );
  $response = workbench_access_node_access($node, 'update', $account);
  $this
    ->assertTrue($response == NODE_ACCESS_DENY, t('Workbench Access rules enforced on test node.'));

  // Since the user is not in a section, this should DENY, unless the node
  // type is ignored.
  // Test for ignore.
  variable_set('workbench_access_node_type_' . $node->type, 0);
  $this
    ->assertFalse(variable_get('workbench_access_node_type_' . $node->type, 1), t('Workbench Access not enforced for %type content.', array(
    '%type' => $node->type,
  )));
  $response = workbench_access_node_access($node, 'update', $account);
  $this
    ->assertTrue($response == NODE_ACCESS_IGNORE, t('Workbench Access rules ignored on test node.'));

  // Test for deny.
  variable_set('workbench_access_node_type_' . $node->type, 1);
  $this
    ->assertTrue(variable_get('workbench_access_node_type_' . $node->type, 1), t('Workbench Access enforced for %type content.', array(
    '%type' => $node->type,
  )));
  $response = workbench_access_node_access($node, 'update', $account);
  $this
    ->assertTrue($response == NODE_ACCESS_DENY, t('Workbench Access rules enforced on test node.'));

  // If the node is not assigned, we should ignore.
  $temp = $node->workbench_access;
  $node->workbench_access = array();
  $response = workbench_access_node_access($node, 'update', $account);
  $this
    ->assertTrue($response == NODE_ACCESS_IGNORE, t('Workbench Access rules ignored for unassigned node.'));

  // Make sure the above was not a false positive.
  $node->workbench_access = $temp;
  $response = workbench_access_node_access($node, 'update', $account);
  $this
    ->assertTrue($response == NODE_ACCESS_DENY, t('Workbench Access rules enforced on test node.'));

  // Delete the user account.
  user_delete($account->uid);
  $records = db_query("SELECT 1 FROM {workbench_access_user} WHERE uid = :uid", array(
    ':uid' => $account->uid,
  ))
    ->fetchField();
  $this
    ->assertFalse($records, 'User section assignments removed.');

  // Tests access per menu levels.  We have structured our menu so that we
  // know what these results should return.
  // Test another user who is currently not assigned.
  $account = $this
    ->getWorkbenchAccessUser($id);

  // @todo: This is pretty obtuse. Can we improve it?
  // @params are $account, $nid, $depth, $expected_count.
  // See the map in the large docblock at the top of this test.
  $this
    ->assertMenuUpdateNodes($account, 1, 1, 15);
  $this
    ->assertMenuUpdateNodes($account, 3, 2, 7);
  $this
    ->assertMenuUpdateNodes($account, 7, 3, 3);
  $this
    ->assertMenuUpdateNodes($account, 15, 4, 1);

  // Test for issue #1203260. Some menu links cause fatal error.
  // Make all menu items access sections.
  variable_set('workbench_access_auto_assign', 1);

  // Create a menu item that triggers the failure, which is based on access
  // checks for menu links while we are fetching our raw tree.
  $link = array(
    'link_path' => 'node/add',
    'link_title' => 'Add content',
    'menu_name' => $menu_name,
    'weight' => 0,
    'plid' => 0,
  );
  menu_link_save($link);

  // Bug is triggered by anonymous users building the cache.
  $this
    ->drupalLogout();
  workbench_access_reset_tree();

  // Check that the menu scheme is setup correctly.
  drupal_flush_all_caches();
  $this
    ->drupalGet('node');

  // If we hit an infinite loop, the page does not return listings.
  // Note the HTML fragent here, which assures success on various installs.
  $this
    ->assertRaw('node/30">B2b2</a>', t('Node listing page returns properly.'));
  $this
    ->assertWorkbenchScheme('menu', $menu_name);
}