XmlSitemapTestBase.php 14 KB
Newer Older
1
2
3
4
<?php

namespace Drupal\xmlsitemap\Tests;

5
use Drupal\Core\Logger\RfcLogLevel;
6
use Drupal\Core\Url;
7
use Drupal\simpletest\WebTestBase;
8
use Drupal\xmlsitemap\Entity\XmlSitemap;
9

10
11
12
/**
 * Helper test class with some added functions for testing.
 */
13
abstract class XmlSitemapTestBase extends WebTestBase {
14

15
16
17
18
19
  /**
   * Modules to enable.
   *
   * @var array
   */
amateescu's avatar
amateescu committed
20
  public static $modules = ['node', 'system', 'user', 'xmlsitemap'];
21
22
23
24
25
26

  /**
   * The admin user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
27
  protected $admin_user;
28

29
30
31
32
33
34
35
  /**
   * The normal user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $normal_user;

36
37
38
39
40
  /**
   * The state store.
   *
   * @var \Drupal\Core\State\StateInterface
   */
41
  protected $state;
42
43
44
45
46
47

  /**
   * The xmlsitemap.settings configuration object.
   *
   * @var \Drupal\Core\Config\Config
   */
48
  protected $config;
49
50
51
52
53
54

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
55
  protected $moduleHandler;
56

57
58
59
60
61
62
63
  /**
   * The language manager object.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

64
65
66
67
68
69
70
  /**
   * The xmlsitemap link storage handler.
   *
   * @var \Drupal\xmlsitemap\XmlSitemapLinkStorageInterface
   */
  protected $linkStorage;

71
72
73
  /**
   * {@inheritdoc}
   */
74
  protected function setUp() {
75
    parent::setUp();
amateescu's avatar
amateescu committed
76

77
    $this->state = \Drupal::state();
amateescu's avatar
amateescu committed
78
    $this->config = \Drupal::configFactory()->getEditable('xmlsitemap.settings');
79
    $this->moduleHandler = \Drupal::moduleHandler();
80
    $this->languageManager = \Drupal::languageManager();
81
    $this->linkStorage = \Drupal::service('xmlsitemap.link_storage');
82
83
84

    // Create the Article and Page content types.
    if ($this->profile != 'standard') {
amateescu's avatar
amateescu committed
85
86
87
88
89
      $this->drupalCreateContentType([
        'type' => 'article',
        'name' => 'Article',
      ]);
      $this->drupalCreateContentType([
90
91
92
        'type' => 'page',
        'name' => 'Basic page',
        'settings' => [
amateescu's avatar
amateescu committed
93
        // Set proper default options for the page content type.
94
95
96
97
          'node' => [
            'options' => ['promote' => FALSE],
            'submitted' => FALSE,
          ],
amateescu's avatar
amateescu committed
98
        ],
99
      ]);
100
    }
101
102
  }

103
104
105
  /**
   * {@inheritdoc}
   */
106
  public function tearDown() {
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    // Capture any (remaining) watchdog errors.
    $this->assertNoWatchdogErrors();

    parent::tearDown();
  }

  /**
   * Assert the page does not respond with the specified response code.
   *
   * @param $code
   *   Response code. For example 200 is a successful page request. For a list
   *   of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
   * @param $message
   *   Message to display.
121
   *
122
123
124
   * @return
   *   Assertion result.
   */
125
  protected function assertNoResponse($code, $message = '', $group = 'Browser') {
126
127
    $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
    $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
128
    return $this->assertFalse($match, $message ? $message : t('HTTP response not expected @code, actual @curl_code', ['@code' => $code, '@curl_code' => $curl_code]), t('Browser'));
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  }

  /**
   * Check the files directory is created (massive fails if not done).
   *
   * @todo This can be removed when http://drupal.org/node/654752 is fixed.
   */
  protected function checkFilesDirectory() {
    if (!xmlsitemap_check_directory()) {
      $this->fail(t('Sitemap directory was found and writable for testing.'));
    }
  }

  /**
   * Retrieves an XML sitemap.
   *
   * @param $context
   *   An optional array of the XML sitemap's context.
   * @param $options
148
   *   Options to be forwarded to Url::fromUri(). These values will be merged with, but
149
150
151
152
   *   always override $sitemap->uri['options'].
   * @param $headers
   *   An array containing additional HTTP request headers, each formatted as
   *   "name: value".
153
   *
154
155
156
   * @return
   *   The retrieved HTML string, also available as $this->drupalGetContent()
   */
157
  protected function drupalGetSitemap(array $context = [], array $options = [], array $headers = []) {
158
    $sitemap = XmlSitemap::loadByContext($context);
159
160
161
    if (!$sitemap) {
      return $this->fail('Could not load sitemap by context.');
    }
162
163
    $uri = xmlsitemap_sitemap_uri($sitemap);
    return $this->drupalGet($uri['path'], $options + $uri['options'], $headers);
164
165
166
167
168
169
  }

  /**
   * Regenerate the sitemap by setting the regenerate flag and running cron.
   */
  protected function regenerateSitemap() {
170
171
    $this->state->set('xmlsitemap_regenerate_needed', TRUE);
    $this->state->set('xmlsitemap_generated_last', 0);
172
    $this->cronRun();
173
    $this->assertTrue($this->state->get('xmlsitemap_generated_last') && !$this->state->get('xmlsitemap_regenerate_needed'), t('XML sitemaps regenerated and flag cleared.'));
174
175
  }

176
177
178
  /**
   *
   */
179
180
  protected function assertSitemapLink($entity_type, $entity_id = NULL) {
    if (is_array($entity_type)) {
181
      $links = $this->linkStorage->loadMultiple($entity_type);
182
183
184
      $link = $links ? reset($links) : FALSE;
    }
    else {
185
      $link = $this->linkStorage->load($entity_type, $entity_id);
186
187
188
189
190
    }
    $this->assertTrue(is_array($link), 'Link loaded.');
    return $link;
  }

191
192
193
  /**
   *
   */
194
195
  protected function assertNoSitemapLink($entity_type, $entity_id = NULL) {
    if (is_array($entity_type)) {
196
      $links = $this->linkStorage->loadMultiple($entity_type);
197
198
199
      $link = $links ? reset($links) : FALSE;
    }
    else {
200
      $link = $this->linkStorage->load($entity_type, $entity_id);
201
202
203
204
205
    }
    $this->assertFalse($link, 'Link not loaded.');
    return $link;
  }

206
207
208
  /**
   *
   */
209
  protected function assertSitemapLinkVisible($entity_type, $entity_id) {
210
    $link = $this->linkStorage->load($entity_type, $entity_id);
211
    $this->assertTrue($link && $link['access'] && $link['status'], t('Sitemap link @type @id is visible.', ['@type' => $entity_type, '@id' => $entity_id]));
212
213
  }

214
215
216
  /**
   *
   */
217
  protected function assertSitemapLinkNotVisible($entity_type, $entity_id) {
218
    $link = $this->linkStorage->load($entity_type, $entity_id);
219
    $this->assertTrue($link && !($link['access'] && $link['status']), t('Sitemap link @type @id is not visible.', ['@type' => $entity_type, '@id' => $entity_id]));
220
221
  }

222
223
224
  /**
   *
   */
225
  protected function assertSitemapLinkValues($entity_type, $entity_id, array $conditions) {
226
    $link = $this->linkStorage->load($entity_type, $entity_id);
227
228

    if (!$link) {
229
      return $this->fail(t('Could not load sitemap link for @type @id.', ['@type' => $entity_type, '@id' => $entity_id]));
230
231
232
233
234
    }

    foreach ($conditions as $key => $value) {
      if ($value === NULL || $link[$key] === NULL) {
        // For nullable fields, always check for identical values (===).
235
        $this->assertIdentical($link[$key], $value, t('Identical values for @type @id link field @key.', ['@type' => $entity_type, '@id' => $entity_id, '@key' => $key]));
236
237
238
      }
      else {
        // Otherwise check simple equality (==).
239
        $this->assertEqual($link[$key], $value, t('Equal values for @type @id link field @key - @a - @b.', ['@type' => $entity_type, '@id' => $entity_id, '@key' => $key, '@a' => $link[$key], '@b' => $value]));
240
241
242
243
      }
    }
  }

244
245
246
  /**
   *
   */
247
  protected function assertNotSitemapLinkValues($entity_type, $entity_id, array $conditions) {
248
    $link = $this->linkStorage->load($entity_type, $entity_id);
249
250

    if (!$link) {
251
      return $this->fail(t('Could not load sitemap link for @type @id.', ['@type' => $entity_type, '@id' => $entity_id]));
252
253
254
255
256
    }

    foreach ($conditions as $key => $value) {
      if ($value === NULL || $link[$key] === NULL) {
        // For nullable fields, always check for identical values (===).
257
        $this->assertNotIdentical($link[$key], $value, t('Not identical values for @type @id link field @key.', ['@type' => $entity_type, '@id' => $entity_id, '@key' => $key]));
258
259
260
      }
      else {
        // Otherwise check simple equality (==).
261
        $this->assertNotEqual($link[$key], $value, t('Not equal values for link @type @id field @key.', ['@type' => $entity_type, '@id' => $entity_id, '@key' => $key]));
262
263
264
265
      }
    }
  }

266
267
268
  /**
   *
   */
269
270
271
  protected function assertRawSitemapLinks() {
    $links = func_get_args();
    foreach ($links as $link) {
272
273
      $path = Url::fromUri('internal:' . $link['loc'], ['language' => xmlsitemap_language_load($link['language']), 'absolute' => TRUE])->toString();
      $this->assertRaw($link['loc'], t('Link %path found in the sitemap.', ['%path' => $path]));
274
275
276
    }
  }

277
278
279
  /**
   *
   */
280
281
282
  protected function assertNoRawSitemapLinks() {
    $links = func_get_args();
    foreach ($links as $link) {
283
284
      $path = Url::fromUri('internal:' . $link['loc'], ['language' => xmlsitemap_language_load($link['language']), 'absolute' => TRUE])->toString();
      $this->assertNoRaw($link['loc'], t('Link %path not found in the sitemap.', ['%path' => $path]));
285
286
287
    }
  }

288
289
290
291
  /**
   *
   */
  protected function addSitemapLink(array $link = []) {
292
293
    $last_id = &drupal_static(__FUNCTION__, 1);

294
    $link += [
295
      'type' => 'testing',
amateescu's avatar
amateescu committed
296
      'subtype' => '',
297
298
299
      'id' => $last_id,
      'access' => 1,
      'status' => 1,
300
    ];
301
302

    // Make the default path easier to read than a random string.
303
    $link += ['loc' => '/' . $link['type'] . '-' . $link['id']];
304
305

    $last_id = max($last_id, $link['id']) + 1;
306
    $this->linkStorage->save($link);
307
308
309
    return $link;
  }

310
311
312
  /**
   *
   */
313
314
315
316
  protected function assertFlag($variable, $assert_value = TRUE, $reset_if_true = TRUE) {
    $value = xmlsitemap_var($variable);

    if ($reset_if_true && $value) {
317
318
      $state_variables = xmlsitemap_state_variables();
      if (isset($state_variables[$variable])) {
319
        $this->state->set($variable, FALSE);
320
321
      }
      else {
322
        $this->config->set($variable, FALSE)->save();
323
      }
324
325
326
327
328
    }

    return $this->assertEqual($value, $assert_value, "xmlsitemap_$variable is " . ($assert_value ? 'TRUE' : 'FALSE'));
  }

329
330
331
  /**
   *
   */
332
333
334
335
  protected function assertXMLSitemapProblems($problem_text = FALSE) {
    $this->drupalGet('admin/config/search/xmlsitemap');
    $this->assertText(t('One or more problems were detected with your XML sitemap configuration'));
    if ($problem_text) {
336
      $this->clickLink(t('status report'));
337
338
339
340
      $this->assertText($problem_text);
    }
  }

341
342
343
  /**
   *
   */
344
345
346
347
348
349
350
351
352
353
  protected function assertNoXMLSitemapProblems() {
    $this->drupalGet('admin/config/search/xmlsitemap');
    $this->assertNoText(t('One or more problems were detected with your XML sitemap configuration'));
  }

  /**
   * Fetch all seen watchdog messages.
   *
   * @todo Add unit tests for this function.
   */
354
355
  protected function getWatchdogMessages(array $conditions = [], $reset = FALSE) {
    static $seen_ids = [];
356

357
    if (!$this->moduleHandler->moduleExists('dblog') || $reset) {
358
359
      $seen_ids = [];
      return [];
360
361
362
    }

    $query = db_select('watchdog');
363
    $query->fields('watchdog', ['wid', 'type', 'severity', 'message', 'variables', 'timestamp']);
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
    foreach ($conditions as $field => $value) {
      if ($field == 'variables' && !is_string($value)) {
        $value = serialize($value);
      }
      $query->condition($field, $value);
    }
    if ($seen_ids) {
      $query->condition('wid', $seen_ids, 'NOT IN');
    }
    $query->orderBy('timestamp');
    $messages = $query->execute()->fetchAllAssoc('wid');

    $seen_ids = array_merge($seen_ids, array_keys($messages));
    return $messages;
  }

380
381
382
  /**
   *
   */
383
384
385
386
  protected function assertWatchdogMessage(array $conditions, $message = 'Watchdog message found.') {
    $this->assertTrue($this->getWatchdogMessages($conditions), $message);
  }

387
388
389
  /**
   *
   */
390
391
392
393
394
395
396
397
398
  protected function assertNoWatchdogMessage(array $conditions, $message = 'Watchdog message not found.') {
    $this->assertFalse($this->getWatchdogMessages($conditions), $message);
  }

  /**
   * Check that there were no watchdog errors or worse.
   */
  protected function assertNoWatchdogErrors() {
    $messages = $this->getWatchdogMessages();
399
    $verbose = [];
400
401
402

    foreach ($messages as $message) {
      $message->text = $this->formatWatchdogMessage($message);
403
      if (in_array($message->severity, [RfcLogLevel::EMERGENCY, RfcLogLevel::ALERT, RfcLogLevel::CRITICAL, RfcLogLevel::ERROR, RfcLogLevel::WARNING])) {
404
405
406
407
408
409
410
        $this->fail($message->text);
      }
      $verbose[] = $message->text;
    }

    if ($verbose) {
      array_unshift($verbose, '<h2>Watchdog messages</h2>');
411
      $this->verbose(implode('<br />', $verbose), 'Watchdog messages from test run');
412
413
414
    }

    // Clear the seen watchdog messages since we've failed on any errors.
415
    $this->getWatchdogMessages([], TRUE);
416
417
418
419
420
421
422
  }

  /**
   * Format a watchdog message in a one-line summary.
   *
   * @param $message
   *   A watchdog messsage object.
423
   *
424
425
426
427
   * @return
   *   A string containing the watchdog message's timestamp, severity, type,
   *   and actual message.
   */
428
  private function formatWatchdogMessage($message) {
429
430
431
432
    static $levels;

    if (!isset($levels)) {
      module_load_include('admin.inc', 'dblog');
433
      $levels = RfcLogLevel::getLevels();
434
435
    }

436
    return t('@timestamp - @severity - @type - @message', [
437
438
439
      '@timestamp' => $message->timestamp,
      '@severity' => $levels[$message->severity],
      '@type' => $message->type,
440
441
        // '@message' => theme_dblog_message(array('event' => $message, 'link' => FALSE)),.
    ]);
442
443
444
445
446
447
448
449
450
451
452
453
  }

  /**
   * Log verbose message in a text file.
   *
   * This is a copy of DrupalWebTestCase->verbose() but allows a customizable
   * summary message rather than hard-coding 'Verbose message'.
   *
   * @param $verbose_message
   *   The verbose message to be stored.
   * @param $message
   *   Message to display.
454
   *
455
456
457
458
459
   * @see simpletest_verbose()
   *
   * @todo Remove when http://drupal.org/node/800426 is fixed.
   */
  protected function verbose($verbose_message, $message = 'Verbose message') {
460
    if ($id = parent::verbose($verbose_message)) {
461
      $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html');
462
      $message_url = Url::fromUri($url, ['attributes' => ['target' => '_blank']]);
463
      $this->error($this->l($message, $message_url), 'User notice');
464
465
466
467
    }
  }

}