You are here

conflict.test in Conflict 7

Tests for conflict.module.

File

conflict.test
View source
<?php

/**
 * @file
 * Tests for conflict.module.
 */
class ConflictWebTestCase extends DrupalWebTestCase {

  /**
   * First drupal user for Concurrent sessions tricks.
   *
   * @var stdClass
   */
  protected $user1;

  /**
   * Second drupal user for Concurrent sessions tricks.
   *
   * @var stdClass
   */
  protected $user2;

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    $modules = func_get_args();
    $modules = isset($modules[0]) && is_array($modules[0]) ? $modules[0] : $modules;
    parent::setUp($modules);

    // Create two web users.
    $this->user1 = $this
      ->drupalCreateUser(array(
      'create page content',
      'edit own page content',
    ));
    $this->user2 = $this
      ->drupalCreateUser(array(
      'create page content',
      'edit own page content',
    ));
  }

  /**
   * Helper function to switch between user1 and user2.
   *
   * @param stdClass $account
   *   Link to drupal user.
   *
   * @return bool
   *   As we are supporting concurrent session we are expecting valid session in
   *   given account. So try to work with existed.
   */
  protected function drupalSwitchUser(stdClass $account) {
    if (isset($account->session)) {

      // Switch to the user session.
      $this->loggedInUser = $account;
      $this->curlHandle = $account->session->curlHandle;

      // Restore internal browser state of the user.
      // Updates content properties on $this as well as $this->loggedInUser.
      $this
        ->drupalSetContent($account->session->content, $account->session->url);
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Overrides DrupalWebTestCase::drupalLogin().
   *
   * @param stdClass $user
   *   The user account to log in.
   * @param bool $create_concurrent_session
   *   (optional) Whether to create a new, concurrent user session. Pass TRUE
   *   for first login. Defaults to FALSE, which means that the currently logged
   *   in user, if logged in, is logged out and back in (default behavior).
   */
  protected function drupalLogin(stdClass $user, $create_concurrent_session = FALSE) {

    // If we're asked to create a new session, unset the current.
    if ($create_concurrent_session) {
      unset($this->curlHandle);
      $this->loggedInUser = FALSE;
    }
    elseif ($this
      ->drupalSwitchUser($user)) {
      $this
        ->verbose($this
        ->drupalGetcontent());
      $this
        ->pass(t('User %name is still logged in.', array(
        '%name' => $user->name,
      )), t('User login'));
      return;
    }

    // If we are logged in already and are asked to re-login, log out first.
    if ($this->loggedInUser && $this->loggedInUser->uid == $user->uid) {
      $this
        ->drupalLogout();
    }
    $edit = array(
      'name' => $user->name,
      'pass' => $user->pass_raw,
    );
    $this
      ->drupalPost('user', $edit, t('Log in'));

    // If a "log out" link appears on the page, it is almost certainly because
    // the login was successful.
    $pass = $this
      ->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array(
      '%name' => $user->name,
    )), t('User login'));
    if ($pass) {

      // Save the user's session on the account itself.
      if (!isset($user->session)) {
        $user->session = new stdClass();
      }
      $user->session->curlHandle = $this->curlHandle;

      // Switch the currently logged in user.
      $this->loggedInUser = $user;
    }
  }

  /**
   * Overrides DrupalWebTestCase::drupalLogout().
   *
   * @param stdClass $account
   *   (optional) The user account to log out.
   */
  protected function drupalLogout(stdClass $account = NULL) {

    // If a specific account was passed, ensure that we are operating on that
    // user's session first.
    if (isset($account) && (!$this->loggedInUser || $account->uid != $this->loggedInUser)) {
      $this
        ->drupalSwitchUser($account);
    }

    // Make a request to the logout page, and redirect to the user page, the
    // idea being if you were properly logged out you should be seeing a login
    // screen.
    $this
      ->drupalGet('user/logout');
    $this
      ->drupalGet('user');
    $pass = $this
      ->assertField('name', t('Username field found.'), t('Logout'));
    $pass = $pass && $this
      ->assertField('pass', t('Password field found.'), t('Logout'));
    if ($pass) {

      // Remove the user's session on the account itself.
      if (isset($account->session->curlHandle)) {
        curl_close($account->session->curlHandle);
      }
      unset($account->session);

      // Switch to no session.
      $this->loggedInUser = FALSE;
    }
  }

  /**
   * Overrides DrupalWebTestCase::drupalSetContent().
   *
   * {@inheritdoc}
   */
  protected function drupalSetContent($content, $url = 'internal:') {
    parent::drupalSetContent($content, $url);

    // Clone the relevant results onto the currently logged in user
    // account/session.
    if (isset($this->loggedInUser->session)) {
      $this->loggedInUser->session->url = $this->url;
      $this->loggedInUser->session->content = $this->content;
      $this->loggedInUser->session->drupalSettings = $this->drupalSettings;
    }
  }
  protected function createFieldWithInstance($suffix, $field_type = 'text', $entity_type = 'node', $bundle = 'page') {
    $field_name = 'field_' . $suffix;
    $field = field_create_field(array(
      'field_name' => $field_name,
      'type' => $field_type,
      'cardinality' => 1,
    ));
    $instance = array(
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $field_name,
      'description' => $this
        ->randomName() . '_description',
      'weight' => mt_rand(0, 127),
      'widget' => array(
        'type' => 'text_textfield',
      ),
    );
    field_create_instance($instance);
  }

}
class ConflictSwitchExampleTestCase extends ConflictWebTestCase {

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
      'name' => 'drupalSwitchUser() example',
      'description' => 'Demonstrates drupalSwitchUser() usage.',
      'group' => 'Conflict',
    );
  }

  /**
   * Test internal concurrent session functional.
   */
  function testConcurrentLogin() {

    // Login first user.
    $this
      ->drupalLogin($this->user1);
    $this
      ->assertText($this->user1->name);
    $this
      ->clickLink(t('Edit'));

    // Login second user.
    // Without passing TRUE, the first user would be logged out.
    $this
      ->drupalLogin($this->user2, TRUE);
    $this
      ->assertText($this->user2->name);
    $this
      ->clickLink(t('Edit'));

    // Switch to first user.
    $this
      ->drupalLogin($this->user1);

    // Verify that we ARE user1 and SEE what user1 saw before.
    $this
      ->assertText($this->user1->name);
    $this
      ->assertFieldByName('mail', $this->user1->mail);

    // Switch to second user.
    $this
      ->drupalLogin($this->user2);

    // Verify that we ARE user2 and SEE what user2 saw before.
    $this
      ->assertText($this->user2->name);
    $this
      ->assertFieldByName('mail', $this->user2->mail);

    // Log out second user.
    $this
      ->drupalLogout();

    // Switch back to first user and confirm that we're still logged in.
    $this
      ->drupalLogin($this->user1);

    // Verify that we ARE user1 and SEE what user1 saw before.
    $this
      ->assertText($this->user1->name);
    $this
      ->assertFieldByName('mail', $this->user1->mail);

    // Log the second user back in (was logged out above).
    // Without passing TRUE, the first user would be logged out.
    $this
      ->drupalLogin($this->user2, TRUE);
    $this
      ->assertText($this->user2->name);
    $this
      ->clickLink(t('Edit'));

    // Switch back to first user once more.
    $this
      ->drupalLogin($this->user1);

    // Verify that we ARE user1 and SEE what user1 saw before.
    $this
      ->assertText($this->user1->name);
    $this
      ->assertFieldByName('mail', $this->user1->mail);
  }

}
class ConflictTestCase extends ConflictWebTestCase {

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
      'name' => 'Exercise node conflicts',
      'description' => 'Force conflicts while editing nodes.',
      'group' => 'Conflict',
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp(array(
      'conflict',
    ));

    // Enable conflict highlights for Page content type.
    variable_set('conflict_enable_page', TRUE);
    $this
      ->drupalLogin($this->user1);
  }

  /**
   * Test case when user should get conflicts.
   *
   * Emulates conflicts for title and body fields.
   */
  public function testConflictCase() {
    $orig_title = $this
      ->randomName();
    $orig_body = $this
      ->randomString();
    $conflict_title = $this
      ->randomName();
    $conflict_body = $this
      ->randomString();

    // Create the node to work with.
    $node = $this
      ->drupalCreateNode(array(
      'title' => $this
        ->randomName(),
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => $this
              ->randomString(),
            'summary' => '',
          ),
        ),
      ),
    ));

    // Load the edit page up.
    $this
      ->drupalGet("node/{$node->nid}/edit");

    // Before submitting the form, make changes to the node from somewhere else.
    $conflict = clone $node;
    $conflict->title = $orig_title;
    $conflict->body['und'][0]['value'] = $orig_body;
    node_save($conflict);

    // Fudge the timestamps in the database.
    db_query('UPDATE {node} SET changed = changed + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));
    db_query('UPDATE {node_revision} SET timestamp = timestamp + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));

    // Attempt to make changes.
    $edit['title'] = $conflict_title;
    $edit['body[und][0][value]'] = $conflict_body;
    $this
      ->drupalPost(NULL, $edit, t('Save'));
    $this
      ->assertText(t('The Title field was changed by another user while you were editing it. Save again to overwrite it.'));
    $this
      ->assertText(t('The Body field was changed by another user while you were editing it. Save again to overwrite it.'));
    $this
      ->assertFieldByXPath('//*[@id="edit-title" and contains(@class, "error")]', $conflict_title, 'Title field was highlighted with error and contains conflicted data.');
    $this
      ->assertFieldByXPath('//*[@id="edit-body-und-0-value" and contains(@class, "error")]', $conflict_body, 'Body field was highlighted with error and contains conflicted data.');
  }

  /**
   * Test case for outdated values.
   *
   * Emulates that title and body fields are outdated.
   */
  public function testNeedUpdateCase() {
    $orig_title = $this
      ->randomName();
    $orig_body = $this
      ->randomString();
    $their_title = $this
      ->randomName();
    $their_body = $this
      ->randomString();

    // Create the node to work with.
    $node = $this
      ->drupalCreateNode(array(
      'title' => $orig_title,
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => $orig_body,
            'summary' => '',
          ),
        ),
      ),
    ));

    // Load the edit page up.
    $this
      ->drupalGet("node/{$node->nid}/edit");

    // Before submitting the form, make changes to the node from somewhere else.
    $conflict = clone $node;
    $conflict->title = $their_title;
    $conflict->body['und'][0]['value'] = $their_body;
    node_save($conflict);

    // Fudge the timestamps in the database.
    db_query('UPDATE {node} SET changed = changed + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));
    db_query('UPDATE {node_revision} SET timestamp = timestamp + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));

    // Attempt to make changes.
    $edit['title'] = $orig_title;
    $edit['body[und][0][value]'] = $orig_body;
    $this
      ->drupalPost(NULL, $edit, t('Save'));
    $this
      ->assertText(t('The Title field was changed by another user. Please verify the updated value.'));
    $this
      ->assertText(t('The Body field was changed by another user. Please verify the updated value.'));
    $this
      ->assertFieldByXPath('//*[@id="edit-title" and contains(@class, "error")]', $their_title, 'Title field was highlighted with error and contains conflicted data.');
    $this
      ->assertFieldByXPath('//*[@id="edit-body-und-0-value" and contains(@class, "error")]', $their_body, 'Body field was highlighted with error and contains conflicted data.');
  }

  /**
   * Test case for complex errors.
   *
   * Emulates that title field has conflict; body field is outdated and
   * custom field_text is not modified and not outdated.
   */
  public function testComplexTroublesCase() {
    $this
      ->createFieldWithInstance('text');
    $orig_title = $this
      ->randomName();
    $orig_body = $this
      ->randomString();
    $orig_text = $this
      ->randomString();
    $their_title = $this
      ->randomName();
    $their_body = $this
      ->randomString();

    // Create the node to work with.
    $node = $this
      ->drupalCreateNode(array(
      'title' => $this
        ->randomName(),
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => $orig_body,
            'summary' => '',
          ),
        ),
      ),
      'field_text' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => $orig_text,
          ),
        ),
      ),
    ));

    // Load the edit page up.
    $this
      ->drupalGet("node/{$node->nid}/edit");

    // Before submitting the form, make changes to the node from somewhere else.
    $conflict = clone $node;
    $conflict->title = $their_title;
    $conflict->body['und'][0]['value'] = $their_body;
    $conflict->field_text['und'][0]['value'] = $orig_text;
    node_save($conflict);

    // Fudge the timestamps in the database.
    db_query('UPDATE {node} SET changed = changed + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));
    db_query('UPDATE {node_revision} SET timestamp = timestamp + 100 WHERE nid = :nid', array(
      ':nid' => $conflict->nid,
    ));

    // Attempt to make changes.
    $edit['title'] = $orig_title;
    $edit['body[und][0][value]'] = $orig_body;
    $edit['field_text[und][0][value]'] = $orig_text;
    $this
      ->drupalPost(NULL, $edit, t('Save'));
    $this
      ->assertNoText('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.');
    $this
      ->assertText(t('The Title field was changed by another user while you were editing it. Save again to overwrite it.'));
    $this
      ->assertText('The Body field was changed by another user. Please verify the updated value.');
    $this
      ->assertNoText('The field_text field was changed by another user. Please verify the updated value.');
    $this
      ->assertFieldByXPath('//*[@id="edit-title" and contains(@class, "error")]', $orig_title, 'Title field was highlighted with error and contains conflicted data.');
    $this
      ->assertFieldByXPath('//*[@id="edit-body-und-0-value" and contains(@class, "error")]', $their_body, 'Body field was highlighted with error and contains conflicted data.');
    $this
      ->assertNoFieldByXPath('//*[@id="edit-field_text-und-0-value" and contains(@class, "error")]', $orig_text, 'Custom field was not highlighted with error and contains conflicted data.');
  }

}