dblog.test 13.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
<?php
// $Id$

class DBLogTestCase extends DrupalWebTestCase {
  protected $big_user;
  protected $any_user;

  /**
   * Implementation of getInfo().
   */
  function getInfo() {
    return array(
      'name' => t('DBLog functionality'),
      'description' => t('Generate events and verify dblog entries; verify user access to log reports based on persmissions.'),
      'group' => t('DBLog'),
    );
  }

  /**
   * Enable modules and create users with specific permissions.
   */
  function setUp() {
    parent::setUp('dblog', 'blog', 'poll');
    // Create users.
    $this->big_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'administer users'));
    $this->any_user = $this->drupalCreateUser(array());
  }

  /**
   * Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
   */
  function testDBLog() {
    // Login the admin user.
    $this->drupalLogin($this->big_user);

    $row_limit = 100;
    $this->verifyRowLimit($row_limit);
    $this->verifyCron($row_limit);
    $this->verifyEvents();
    $this->verifyReports();

    // Login the regular user.
    $user = $this->drupalLogin($this->any_user);
    $this->verifyReports(403);
  }

  /**
   * Verify setting of the dblog row limit.
   *
   * @param integer $count Log row limit.
   */
  private function verifyRowLimit($row_limit) {
    // Change the dblog row limit.
    $edit = array();
    $edit['dblog_row_limit'] = $row_limit;
    $this->drupalPost('admin/settings/logging/dblog', $edit, t('Save configuration'));
    $this->assertResponse(200);
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    // Check row limit variable.
    $current_limit = variable_get('dblog_row_limit', 1000);
    $this->assertTrue($current_limit == $row_limit, t('[Cache] Row limit variable of @count equals row limit of @limit', array('@count' => $current_limit, '@limit' => $row_limit)));
    // Verify dblog row limit equals specified row limit.
    $current_limit = unserialize(db_result(db_query("SELECT value FROM {variable} WHERE name = '%s'", 'dblog_row_limit')));
    $this->assertTrue($current_limit == $row_limit, t('[Variable table] Row limit variable of @count equals row limit of @limit', array('@count' => $current_limit, '@limit' => $row_limit)));
  }

  /**
   * Verify cron applies the dblog row limit.
   *
   * @param integer $count Log row limit.
   */
  private function verifyCron($row_limit) {
    // Generate additional log entries.
    $this->generateLogEntries($row_limit + 10);
    // Verify dblog row count exceeds row limit.
    $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog}'));
    $this->assertTrue($count > $row_limit, t('Dblog row count of @count exceeds row limit of @limit', array('@count' => $count, '@limit' => $row_limit)));

    // Run cron job.
    $this->drupalGet('admin/reports/status/run-cron');
    $this->assertResponse(200);
    $this->assertText(t('Cron ran successfully'), t('Cron ran successfully'));
    // Verify dblog row count equals row limit plus one because cron adds a record after it runs.
    $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog}'));
    $this->assertTrue($count == $row_limit + 1, t('Dblog row count of @count equals row limit of @limit plus one', array('@count' => $count, '@limit' => $row_limit)));
  }

  /**
   * Generate dblog entries.
   *
   * @param integer $count Log row limit.
   */
  private function generateLogEntries($count) {
    global $base_root;

    // Prepare the fields to be logged
    $log = array(
      'type'        => 'custom',
      'message'     => 'Log entry added to test the dblog row limit.',
      'variables'   => array(),
      'severity'    => WATCHDOG_NOTICE,
      'link'        => NULL,
      'user'        => $this->big_user,
      'request_uri' => $base_root . request_uri(),
105
      'referer'     => $_SERVER['HTTP_REFERER'],
106
      'ip'          => ip_address(),
107
      'timestamp'   => REQUEST_TIME,
108 109 110
      );
    $message = 'Log entry added to test the dblog row limit.';
    for ($i = 0; $i < $count; $i++) {
111
      $log['message'] = $i . ' => ' . $message;
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
      dblog_watchdog($log);
    }
  }

  /**
   * Verify the logged in user has the desired access to the various dblog nodes.
   *
   * @param integer $response HTTP response code.
   */
  private function verifyReports($response = 200) {
    $quote = '&#039;';

    // View dblog help node.
    $this->drupalGet('admin/help/dblog');
    $this->assertResponse($response);
    if ($response == 200) {
      $this->assertText(t('Database logging'), t('DBLog help was displayed'));
    }

    // View dblog report node.
    $this->drupalGet('admin/reports/dblog');
    $this->assertResponse($response);
    if ($response == 200) {
      $this->assertText(t('Recent log entries'), t('DBLog report was displayed'));
    }

    // View dblog page-not-found report node.
    $this->drupalGet('admin/reports/page-not-found');
    $this->assertResponse($response);
    if ($response == 200) {
142
      $this->assertText(t('Top ' . $quote . 'page not found' . $quote . ' errors'), t('DBLog page-not-found report was displayed'));
143 144 145 146 147 148
    }

    // View dblog access-denied report node.
    $this->drupalGet('admin/reports/access-denied');
    $this->assertResponse($response);
    if ($response == 200) {
149
      $this->assertText(t('Top ' . $quote . 'access denied' . $quote . ' errors'), t('DBLog access-denied report was displayed'));
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    }

    // View dblog event node.
    $this->drupalGet('admin/reports/event/1');
    $this->assertResponse($response);
    if ($response == 200) {
      $this->assertText(t('Details'), t('DBLog event node was displayed'));
    }
  }

  /**
   * Verify events.
   */
  private function verifyEvents() {
    // Invoke events.
    $this->doUser();
    $this->doNode('article');
    $this->doNode('blog');
    $this->doNode('page');
    $this->doNode('poll');

171 172 173
    // When a user is deleted, any content they created remains but the
    // uid = 0. Their blog entry shows as "'s blog" on the home page. Records
    // in the watchdog table related to that user have the uid set to zero.
174 175 176 177 178 179
  }

  /**
   * Generate and verify user events.
   *
   */
180
  private function doUser() {
181 182 183 184 185 186
    // Set user variables.
    $name = $this->randomName();
    $pass = user_password();
    // Add user using form to generate add user event (which is not triggered by drupalCreateUser).
    $edit = array();
    $edit['name'] = $name;
187
    $edit['mail'] = $name . '@example.com';
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    $edit['pass[pass1]'] = $pass;
    $edit['pass[pass2]'] = $pass;
    $edit['status'] = 1;
    $this->drupalPost('admin/user/user/create', $edit, t('Create new account'));
    $this->assertResponse(200);
    // Retrieve user object.
    $user = user_load(array('name' => $name)); //, 'pass' => $pass, 'status' => 1));
    $this->assertTrue($user != null, t('User @name was loaded', array('@name' => $name)));
    $user->pass_raw = $pass; // Needed by drupalLogin.
    // Login user.
    $this->drupalLogin($user);
    // Logout user.
    $this->drupalLogout();
    // Fetch row ids in watchdog that relate to the user.
    $result = db_query('SELECT wid FROM {watchdog} WHERE uid = %d', $user->uid);
    while ($row = db_fetch_array($result)) {
      $ids[] = $row['wid'];
    }
    $count_before = (isset($ids)) ? count($ids) : 0;
    $this->assertTrue($count_before > 0, t('DBLog contains @count records for @name', array('@count' => $count_before, '@name' => $user->name)));
    // Delete user.
    user_delete(array(), $user->uid);
    // Count rows that have uids for the user.
    $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog} WHERE uid = %d', $user->uid));
    $this->assertTrue($count == 0, t('DBLog contains @count records for @name', array('@count' => $count, '@name' => $user->name)));
213

214
    // Count rows in watchdog that previously related to the deleted user.
215
    $select = db_select('watchdog');
216
    $select->addExpression('COUNT(*)');
217 218 219 220
    $select->condition('uid', 0);
    if ($ids) {
      $select->condition('wid', $ids, 'IN');
    }
221
    $count_after = $select->execute()->fetchField();
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    $this->assertTrue($count_after == $count_before, t('DBLog contains @count records for @name that now have uid = 0', array('@count' => $count_before, '@name' => $user->name)));
    unset($ids);
    // Fetch row ids in watchdog that relate to the user.
    $result = db_query('SELECT wid FROM {watchdog} WHERE uid = %d', $user->uid);
    while ($row = db_fetch_array($result)) {
      $ids[] = $row['wid'];
    }
    $this->assertTrue(!isset($ids), t('DBLog contains no records for @name', array('@name' => $user->name)));

    // Login the admin user.
    $this->drupalLogin($this->big_user);
    // View the dblog report.
    $this->drupalGet('admin/reports/dblog');
    $this->assertResponse(200);

    // Verify events were recorded.
    // Add user.
    // Default display includes name and email address; if too long then email is replaced by three periods.
    // $this->assertRaw(t('New user: %name (%mail)', array('%name' => $edit['name'], '%mail' => $edit['mail'])), t('DBLog event was recorded: [add user]'));
    $this->assertRaw(t('New user: %name', array('%name' => $name)), t('DBLog event was recorded: [add user]'));
    // Login user.
    $this->assertRaw(t('Session opened for %name', array('%name' => $name)), t('DBLog event was recorded: [login user]'));
    // Logout user.
    $this->assertRaw(t('Session closed for %name', array('%name' => $name)), t('DBLog event was recorded: [logout user]'));
    // Delete user.
    $this->assertRaw(t('Deleted user: %name', array('%name' => $name)), t('DBLog event was recorded: [delete user]'));
  }

  /**
   * Generate and verify node events.
   *
   * @param string $type Content type.
   */
  private function doNode($type) {
    // Create user.
257
    $perm = array('create ' . $type . ' content', 'edit own ' . $type . ' content', 'delete own ' . $type . ' content');
258 259 260 261 262 263 264
    $user = $this->drupalCreateUser($perm);
    // Login user.
    $this->drupalLogin($user);

    // Create node using form to generate add content event (which is not triggered by drupalCreateNode).
    $edit = $this->getContent($type);
    $title = $edit['title'];
265
    $this->drupalPost('node/add/' . $type, $edit, t('Save'));
266 267 268 269 270 271
    $this->assertResponse(200);
    // Retrieve node object.
    $node = node_load(array('title' => $title));
    $this->assertTrue($node != null, t('Node @title was loaded', array('@title' => $title)));
    // Edit node.
    $edit = $this->getContentUpdate($type);
272
    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
273 274
    $this->assertResponse(200);
    // Delete node.
275
    $this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
276 277
    $this->assertResponse(200);
    // View node (to generate page not found event).
278
    $this->drupalGet('node/' . $node->nid);
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    $this->assertResponse(404);
    // View the dblog report (to generate access denied event).
    $this->drupalGet('admin/reports/dblog');
    $this->assertResponse(403);

    // Login the admin user.
    $this->drupalLogin($this->big_user);
    // View the dblog report.
    $this->drupalGet('admin/reports/dblog');
    $this->assertResponse(200);

    // Verify events were recorded.
    // Content added.
    $this->assertRaw(t('@type: added %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content added]'));
    // Content updated.
    $this->assertRaw(t('@type: updated %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content updated]'));
    // Content deleted.
    $this->assertRaw(t('@type: deleted %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content deleted]'));

    // View dblog access-denied report node.
    $this->drupalGet('admin/reports/access-denied');
    $this->assertResponse(200);
    // Access denied.
    $this->assertText(t('admin/reports/dblog'), t('DBLog event was recorded: [access denied]'));

    // View dblog page-not-found report node.
    $this->drupalGet('admin/reports/page-not-found');
    $this->assertResponse(200);
    // Page not found.
    $this->assertText(t('node/@nid', array('@nid' => $node->nid)), t('DBLog event was recorded: [page not found]'));
  }

  /**
   * Create content based on content type.
   *
   * @param string $type Content type.
   * @return array Content.
   */
  private function getContent($type) {
    switch ($type) {
      case 'poll':
        $content = array(
          'title'     => $this->randomName(8),
322 323
          'choice[new:0][chtext]' => $this->randomName(32),
          'choice[new:1][chtext]' => $this->randomName(32),
324 325 326 327 328
        );
      break;

      default:
        $content = array(
329 330
          'title' => $this->randomName(8),
          'body' => $this->randomName(32),
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
        );
      break;
    }
    return $content;
  }

  /**
   * Create content update based on content type.
   *
   * @param string $type Content type.
   * @return array Content.
   */
  private function getContentUpdate($type) {
    switch ($type) {
      case 'poll':
        $content = array(
347 348
          'choice[chid:1][chtext]' => $this->randomName(32),
          'choice[chid:2][chtext]' => $this->randomName(32),
349 350 351 352 353
        );
      break;

      default:
        $content = array(
354
          'body' => $this->randomName(32),
355 356 357 358 359 360
        );
      break;
    }
    return $content;
  }
}