Projet

Général

Profil

Paste
Télécharger (36,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / feeds / tests / feeds_processor_node.test @ ed9a13f1

1
<?php
2

    
3
/**
4
 * @file
5
 * Tests for plugins/FeedsNodeProcessor.inc.
6
 */
7

    
8
/**
9
 * Test aggregating a feed as node items.
10
 */
11
class FeedsRSStoNodesTest extends FeedsWebTestCase {
12

    
13
  /**
14
   * {@inheritdoc}
15
   */
16
  public static function getInfo() {
17
    return array(
18
      'name' => 'Processor: Node',
19
      'description' => 'Tests for the node processor.',
20
      'group' => 'Feeds',
21
    );
22
  }
23

    
24
  /**
25
   * Set up test.
26
   */
27
  public function setUp() {
28
    parent::setUp();
29

    
30
    // Set the front page to show 20 nodes so we can easily see what is aggregated.
31
    variable_set('default_nodes_main', 20);
32

    
33
    // Set the teaser length display to unlimited otherwise tests looking for
34
    // text on nodes will fail.
35
    $edit = array('fields[body][type]' => 'text_default');
36
    $this->drupalPost('admin/structure/types/manage/article/display/teaser', $edit, 'Save');
37

    
38
    // Create an importer configuration.
39
    $this->createImporterConfiguration('Syndication', 'syndication');
40
    $this->addMappings('syndication',
41
      array(
42
        0 => array(
43
          'source' => 'title',
44
          'target' => 'title',
45
          'unique' => FALSE,
46
        ),
47
        1 => array(
48
          'source' => 'description',
49
          'target' => 'body',
50
        ),
51
        2 => array(
52
          'source' => 'timestamp',
53
          'target' => 'created',
54
        ),
55
        3 => array(
56
          'source' => 'url',
57
          'target' => 'url',
58
          'unique' => TRUE,
59
        ),
60
        4 => array(
61
          'source' => 'guid',
62
          'target' => 'guid',
63
          'unique' => TRUE,
64
        ),
65
      )
66
    );
67
  }
68

    
69
  /**
70
   * Test node creation, refreshing/deleting feeds and feed items.
71
   */
72
  public function test() {
73
    $nid = $this->createFeedNode();
74

    
75
    // Assert 10 items aggregated after creation of the node.
76
    $this->assertText('Created 10 nodes');
77
    $article_nid = db_query_range("SELECT nid FROM {node} WHERE type = 'article'", 0, 1)->fetchField();
78
    $this->assertEqual("Created by FeedsNodeProcessor", db_query("SELECT nr.log FROM {node} n JOIN {node_revision} nr ON n.vid = nr.vid WHERE n.nid = :nid", array(':nid' => $article_nid))->fetchField());
79

    
80
    // Navigate to feed node, there should be Feeds tabs visible.
81
    $this->drupalGet("node/$nid");
82
    $this->assertRaw("node/$nid/import");
83
    $this->assertRaw("node/$nid/delete-items");
84

    
85
    // Assert accuracy of aggregated information.
86
    $this->drupalGet('node');
87
    $this->assertRaw('<span class="username">Anonymous (not verified)</span>');
88
    $this->assertDevseedFeedContent();
89

    
90
    // Assert DB status.
91
    $count = db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_item} fi ON fi.entity_type = 'node' AND n.nid = fi.entity_id")->fetchField();
92
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
93

    
94
    // Assert default input format on first imported feed node.
95

    
96
    // NEEDS update.
97
    // $format = db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revision} nr ON n.vid = nr.vid", 0, 1)->fetchField();
98
    // $this->assertEqual($format, filter_fallback_format(), 'Using default Input format.');
99

    
100
    // Import again.
101
    $this->drupalPost("node/$nid/import", array(), 'Import');
102
    $this->assertText('There are no new nodes');
103

    
104
    // Assert DB status, there still shouldn't be more than 10 items.
105
    $count = db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_item} fi ON fi.entity_type = 'node' AND n.nid = fi.entity_id")->fetchField();
106
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
107

    
108
    // All of the above tests should have produced published nodes, set default
109
    // to unpublished, import again.
110
    $count = db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_item} fi ON fi.entity_type = 'node' AND n.nid = fi.entity_id WHERE n.status = 1")->fetchField();
111
    $this->assertEqual($count, 10, 'All items are published.');
112
    $edit = array(
113
      'node_options[status]' => FALSE,
114
    );
115
    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
116
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
117
    $this->drupalPost("node/$nid/import", array(), 'Import');
118
    $count = db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_item} fi ON fi.entity_type = 'node' AND n.nid = fi.entity_id WHERE n.status = 0")->fetchField();
119
    $this->assertEqual($count, 10, 'No items are published.');
120
    $edit = array(
121
      'node_options[status]' => TRUE,
122
    );
123
    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
124
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
125

    
126
    // Enable replace existing and import updated feed file.
127
    $this->drupalPost("node/$nid/import", array(), 'Import');
128
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 1));
129
    $feed_url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed_changes.rss2';
130
    $this->editFeedNode($nid, $feed_url);
131
    $this->drupalPost("node/$nid/import", array(), 'Import');
132
    $this->assertText('Updated 2 nodes');
133

    
134
    // Assert accuracy of aggregated content (check 2 updates, one original).
135
    $this->drupalGet('node');
136
    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
137
    $this->assertText('Presenting on Features in Drupal and Managing News');
138
    $this->assertText('Scaling the Open Atrium UI');
139

    
140
    // Import again.
141
    $this->drupalPost("node/$nid/import", array(), 'Import');
142
    $this->assertText('There are no new nodes');
143
    $this->assertFeedItemCount(10);
144

    
145
    // Now delete all items.
146
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
147
    $this->assertText('Deleted 10 nodes');
148
    $this->assertFeedItemCount(0);
149

    
150
    // Change author and turn off authorization.
151
    $this->auth_user = $this->drupalCreateUser(array('access content'));
152
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('author' => $this->auth_user->name, 'authorize' => FALSE));
153

    
154
    // Change input format.
155
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('input_format' => 'plain_text'));
156

    
157
    // Import again.
158
    $this->drupalPost("node/$nid/import", array(), 'Import');
159
    $this->assertText('Created 10 nodes');
160

    
161
    // Assert author.
162
    $this->drupalGet('node');
163
    $this->assertPattern('/<span class="username">' . check_plain($this->auth_user->name) . '<\/span>/');
164
    $count = db_query("SELECT COUNT(*) FROM {feeds_item} fi JOIN {node} n ON fi.entity_type = 'node' AND fi.entity_id = n.nid WHERE n.uid = :uid", array(':uid' => $this->auth_user->uid))->fetchField();
165
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
166

    
167
    // Assert input format.
168

    
169
    // NEEDS update.
170
    // $format = db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revision} nr ON n.vid = nr.vid", 0, 1)->fetchField();
171
    // $this->assertEqual($format, filter_fallback_format() + 1, 'Set non-default Input format.');
172

    
173
    // Set to update existing, remove authorship of above nodes and import again.
174
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 2));
175
    $nids = db_query("SELECT nid FROM {node} n INNER JOIN {feeds_item} fi ON fi.entity_type = 'node' AND n.nid = fi.entity_id")->fetchCol();
176
    db_update('node')
177
      ->fields(array('uid' => 0))
178
      ->condition('nid', $nids, 'IN')
179
      ->execute();
180
    db_update('feeds_item')
181
      ->fields(array('hash' => ''))
182
      ->condition('entity_type', 'node')
183
      ->condition('entity_id', $nids, 'IN')
184
      ->execute();
185
    $this->drupalPost("node/$nid/import", array(), 'Import');
186
    $this->drupalGet('node');
187
    $this->assertNoPattern('/<span class="username">' . check_plain($this->auth_user->name) . '<\/span>/');
188
    $count = db_query("SELECT COUNT(*) FROM {feeds_item} fi JOIN {node} n ON fi.entity_type = 'node' AND fi.entity_id = n.nid WHERE n.uid = :uid", array(':uid' => $this->auth_user->uid))->fetchField();
189
    $this->assertEqual($count, 0, 'Accurate number of items in database.');
190

    
191
    // Map feed node's author to feed item author, update - feed node's items
192
    // should now be assigned to feed node author.
193
    $this->addMappings('syndication',
194
      array(
195
        5 => array(
196
          'source' => 'parent:uid',
197
          'target' => 'uid',
198
        ),
199
      )
200
    );
201
    $this->drupalPost("node/$nid/import", array(), 'Import');
202
    $this->drupalGet('node');
203
    $this->assertNoPattern('/<span class="username">' . check_plain($this->auth_user->name) . '<\/span>/');
204
    $uid = db_query("SELECT uid FROM {node} WHERE nid = :nid", array(':nid' => $nid))->fetchField();
205
    $count = db_query("SELECT COUNT(*) FROM {node} WHERE uid = :uid", array(':uid' => $uid))->fetchField();
206
    $this->assertEqual($count, 11, 'All feed item nodes are assigned to feed node author.');
207

    
208
    // Login with new user with only access content permissions.
209
    $this->drupalLogin($this->auth_user);
210

    
211
    // Navigate to feed node, there should be no Feeds tabs visible.
212
    $this->drupalGet("node/$nid");
213
    $this->assertNoRaw("node/$nid/import");
214
    $this->assertNoRaw("node/$nid/delete-items");
215

    
216
    // Now create a second feed configuration that is not attached to a content
217
    // type and run tests on importing/purging.
218
    // Login with sufficient permissions.
219
    $this->drupalLogin($this->admin_user);
220
    // Remove all items again so that next test can check for them.
221
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
222

    
223
    // Create an importer, not attached to content type.
224
    $this->createImporterConfiguration('Syndication standalone', 'syndication_standalone');
225
    $edit = array(
226
      'content_type' => '',
227
    );
228
    $this->drupalPost('admin/structure/feeds/syndication_standalone/settings', $edit, 'Save');
229
    $this->addMappings('syndication_standalone',
230
      array(
231
        0 => array(
232
          'source' => 'title',
233
          'target' => 'title',
234
          'unique' => FALSE,
235
        ),
236
        1 => array(
237
          'source' => 'description',
238
          'target' => 'body',
239
        ),
240
        2 => array(
241
          'source' => 'timestamp',
242
          'target' => 'created',
243
        ),
244
        3 => array(
245
          'source' => 'url',
246
          'target' => 'url',
247
          'unique' => TRUE,
248
        ),
249
        4 => array(
250
          'source' => 'guid',
251
          'target' => 'guid',
252
          'unique' => TRUE,
253
        ),
254
      )
255
    );
256

    
257
    // Import, assert 10 items aggregated after creation of the node.
258
    $this->importURL('syndication_standalone');
259
    $this->assertText('Created 10 nodes');
260

    
261
    // Assert accuracy of aggregated information.
262
    $this->drupalGet('node');
263
    $this->assertDevseedFeedContent();
264
    $this->assertFeedItemCount(10);
265

    
266
    // Import again.
267
    $this->drupalPost('import/syndication_standalone', array(), 'Import');
268
    $this->assertText('There are no new nodes');
269
    $this->assertFeedItemCount(10);
270

    
271
    // Enable replace existing and import updated feed file.
272
    $this->setSettings('syndication_standalone', 'FeedsNodeProcessor', array('update_existing' => 1));
273
    $feed_url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed_changes.rss2';
274
    $this->importURL('syndication_standalone', $feed_url);
275
    $this->assertText('Updated 2 nodes');
276

    
277
    // Assert accuracy of aggregated information (check 2 updates, one orig).
278
    $this->drupalGet('node');
279
    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
280
    $this->assertText('Presenting on Features in Drupal and Managing News');
281
    $this->assertText('Scaling the Open Atrium UI');
282

    
283
    // Import again.
284
    $this->drupalPost('import/syndication_standalone', array(), 'Import');
285
    $this->assertText('There are no new nodes');
286
    $this->assertFeedItemCount(10);
287

    
288
    // Now delete all items.
289
    $this->drupalPost('import/syndication_standalone/delete-items', array(), 'Delete');
290
    $this->assertText('Deleted 10 nodes');
291
    $this->assertFeedItemCount(0);
292

    
293
    // Import again, we should find new content.
294
    $this->drupalPost('import/syndication_standalone', array(), 'Import');
295
    $this->assertText('Created 10 nodes');
296
    $this->assertFeedItemCount(10);
297

    
298
    // Enable unpublish missing nodes and import updated feed file.
299
    $this->setSettings('syndication_standalone', 'FeedsNodeProcessor', array('update_non_existent' => FEEDS_UNPUBLISH_NON_EXISTENT, 'update_existing' => FEEDS_REPLACE_EXISTING));
300
    $missing_url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed_missing.rss2';
301
    $this->importURL('syndication_standalone', $missing_url);
302
    $this->assertText('Unpublished 1 node');
303
    $this->assertFeedItemCount(10);
304

    
305
    // Import again to ensure the message that one node is unpublished doesn't
306
    // reappear (since the node was already unpublished during the previous
307
    // import).
308
    $this->drupalPost('import/syndication_standalone', array(), 'Import');
309
    $this->assertText('There are no new nodes');
310
    $this->assertFeedItemCount(10);
311

    
312
    // Re-import the original feed to ensure the unpublished node is updated,
313
    // even though the item is the same since the last time it was available in
314
    // the feed. Fact is that the node was not available in the previous import
315
    // and that should be seen as a change.
316
    $this->importURL('syndication_standalone', $feed_url);
317
    $this->assertText('Updated 1 node');
318
    $this->assertFeedItemCount(10);
319

    
320
    // Now delete all items.
321
    $this->drupalPost('import/syndication_standalone/delete-items', array(), 'Delete');
322
    $this->assertText('Deleted 10 nodes');
323
    $this->assertFeedItemCount(0);
324

    
325
    // Import again, to reset node counts.
326
    $this->importURL('syndication_standalone', $feed_url);
327
    $this->assertText('Created 10 nodes');
328
    $this->assertFeedItemCount(10);
329

    
330
    // Change settings to delete non-existent nodes from feed.
331
    $this->setSettings('syndication_standalone', 'FeedsNodeProcessor', array('update_non_existent' => 'delete'));
332
    $this->importURL('syndication_standalone', $missing_url);
333
    $this->assertText('Removed 1 node');
334
    $this->assertFeedItemCount(9);
335

    
336
    // Now delete all items.
337
    $this->drupalPost('import/syndication_standalone/delete-items', array(), 'Delete');
338
    $this->assertText('Deleted 9 nodes');
339
    $this->assertFeedItemCount(0);
340

    
341
    // Login with new user with only access content permissions.
342
    $this->drupalLogin($this->auth_user);
343

    
344
    // Navigate to feed import form, access should be denied.
345
    $this->drupalGet('import/syndication_standalone');
346
    $this->assertResponse(403);
347

    
348
    // Use File Fetcher.
349
    $this->drupalLogin($this->admin_user);
350

    
351
    $edit = array('plugin_key' => 'FeedsFileFetcher');
352
    $this->drupalPost('admin/structure/feeds/syndication_standalone/fetcher', $edit, 'Save');
353

    
354
    $edit = array(
355
      'allowed_extensions' => 'rss2',
356
    );
357
    $this->drupalPost('admin/structure/feeds/syndication_standalone/settings/FeedsFileFetcher', $edit, 'Save');
358

    
359
    // Create a feed node.
360
    $edit = array(
361
      'files[feeds]' => $this->absolutePath() . '/tests/feeds/drupalplanet.rss2',
362
    );
363
    $this->drupalPost('import/syndication_standalone', $edit, 'Import');
364
    $this->assertText('Created 25 nodes');
365
  }
366

    
367
  /**
368
   * Check that the total number of entries in the feeds_item table is correct.
369
   */
370
  public function assertFeedItemCount($num) {
371
    $count = db_query("SELECT COUNT(*) FROM {feeds_item} WHERE entity_type = 'node'")->fetchField();
372
    $this->assertEqual($count, $num, 'Accurate number of items in database.');
373
  }
374

    
375
  /**
376
   * Check thet contents of the current page for the DS feed.
377
   */
378
  public function assertDevseedFeedContent() {
379
    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
380
    $this->assertText('Tue, 10/06/2009');
381
    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
382
    $this->assertText('Week in DC Tech: October 5th Edition');
383
    $this->assertText('Mon, 10/05/2009');
384
    $this->assertText('There are some great technology events happening this week');
385
    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
386
    $this->assertText('Fri, 10/02/2009');
387
    $this->assertText('is being used as a base platform for collaboration at the World Bank');
388
    $this->assertText('September GeoDC Meetup Tonight');
389
    $this->assertText('Wed, 09/30/2009');
390
    $this->assertText('Today is the last Wednesday of the month');
391
    $this->assertText('Week in DC Tech: September 28th Edition');
392
    $this->assertText('Mon, 09/28/2009');
393
    $this->assertText('Looking to geek out this week? There are a bunch of');
394
    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
395
    $this->assertText('Thu, 09/24/2009');
396
    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
397
    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
398
    $this->assertText('Tue, 09/22/2009');
399
    $this->assertText('In addition to authentication, the Siteminder system');
400
    $this->assertText('Week in DC Tech: September 21 Edition');
401
    $this->assertText('Mon, 09/21/2009');
402
    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
403
    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
404
    $this->assertText('Mon, 09/21/2009');
405
    $this->assertText('Presenting on Features in Drupal and Open Atrium');
406
    $this->assertText('Scaling the Open Atrium UI');
407
    $this->assertText('Fri, 09/18/2009');
408
    $this->assertText('The first major change is switching');
409
  }
410

    
411
  /**
412
   * Test validation of feed URLs.
413
   */
414
  public function testFeedURLValidation() {
415
    $edit['feeds[FeedsHTTPFetcher][source]'] = 'invalid://url';
416
    $this->drupalPost('node/add/page', $edit, 'Save');
417
    $this->assertText('The URL invalid://url is invalid.');
418
  }
419

    
420
  /**
421
   * Test using non-normal URLs like feed:// and webcal://.
422
   */
423
  public function testOddFeedSchemes() {
424
    $url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed.rss2';
425

    
426
    $schemes = array('feed', 'webcal');
427
    $item_count = 0;
428
    foreach ($schemes as $scheme) {
429
      $feed_url = strtr($url, array('http://' => $scheme . '://', 'https://' => $scheme . '://'));
430

    
431
      $edit['feeds[FeedsHTTPFetcher][source]'] = $feed_url;
432
      $this->drupalPost('node/add/page', $edit, 'Save');
433
      $this->assertText('Basic page Development Seed - Technological Solutions for Progressive Organizations has been created.');
434
      $this->assertText('Created 10 nodes.');
435
      $this->assertFeedItemCount($item_count + 10);
436
      $item_count += 10;
437
    }
438
  }
439

    
440
  /**
441
   * Test that feed elements and links are not found on non-feed nodes.
442
   */
443
  public function testNonFeedNodeUI() {
444
    // There should not be feed links on an article node.
445
    $non_feed_node = $this->drupalCreateNode(array('type' => 'article'));
446
    $this->drupalGet('node/' . $non_feed_node->nid);
447
    $this->assertNoLinkByHref('node/' . $non_feed_node->nid . '/import');
448
    $this->assertNoLink('Delete items');
449

    
450
    // Navigate to a non-feed node form, there should be no Feed field visible.
451
    $this->drupalGet('node/add/article');
452
    $this->assertNoFieldByName('feeds[FeedsHTTPFetcher][source]');
453
  }
454

    
455
  /**
456
   * Test that nodes will not be created if the user is unauthorized to create
457
   * them.
458
   */
459
  public function testAuthorize() {
460
    // Create a user with limited permissions. We can't use
461
    // $this->drupalCreateUser here because we need to to set a specific user
462
    // name.
463
    $edit = array(
464
      'name' => 'Development Seed',
465
      'mail' => 'devseed@example.com',
466
      'pass' => user_password(),
467
      'status' => 1,
468
    );
469

    
470
    $account = user_save(drupal_anonymous_user(), $edit);
471

    
472
    // Adding a mapping to the user_name will invoke authorization.
473
    $this->addMappings('syndication',
474
      array(
475
        5 => array(
476
          'source' => 'author_name',
477
          'target' => 'user_name',
478
        ),
479
      )
480
    );
481

    
482
    $nid = $this->createFeedNode();
483

    
484
    $this->assertText('Failed importing 10 nodes.');
485
    $this->assertText('The user ' . $account->name . ' is not authorized to create content of type article.');
486
    $node_count = db_query("SELECT COUNT(*) FROM {node}")->fetchField();
487

    
488
    // We should have 1 node, the feed node.
489
    $this->assertEqual($node_count, 1, t('Correct number of nodes in the database.'));
490

    
491
    // Give the user our admin powers.
492
    $edit = array(
493
      'roles' => $this->admin_user->roles,
494
    );
495
    $account = user_save($account, $edit);
496

    
497
    $this->drupalPost("node/$nid/import", array(), 'Import');
498
    $this->assertText('Created 10 nodes.');
499
    $node_count = db_query("SELECT COUNT(*) FROM {node}")->fetchField();
500
    $this->assertEqual($node_count, 11, t('Correct number of nodes in the database.'));
501
  }
502

    
503
  /**
504
   * Tests expiring nodes.
505
   */
506
  public function testExpiry() {
507
    // Create importer configuration.
508
    $this->setSettings('syndication', NULL, array('content_type' => ''));
509
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
510
      'expire' => 2592000,
511
    ));
512

    
513
    // Create importer.
514
    $this->importURL('syndication');
515

    
516
    // Set date of a few nodes to current date so they don't expire.
517
    $edit = array(
518
      'date' => date('Y-m-d'),
519
    );
520
    $this->drupalPost('node/2/edit', $edit, 'Save');
521
    $this->assertText(date('m/d/Y'), 'Found correct date.');
522
    $this->drupalPost('node/5/edit', $edit, 'Save');
523
    $this->assertText(date('m/d/Y'), 'Found correct date.');
524

    
525
    // Run cron to schedule jobs.
526
    $this->cronRun();
527

    
528
    // Set feeds source expire to run immediately.
529
    db_update('job_schedule')
530
      ->fields(array(
531
        'next' => 0,
532
      ))
533
      ->condition('name', 'feeds_source_expire')
534
      ->execute();
535

    
536
    // Run cron to execute scheduled jobs.
537
    $this->cronRun();
538

    
539
    // Query the feeds_items table and count the number of entries.
540
    $row_count = db_query('SELECT COUNT(*) FROM {feeds_item}')->fetchField();
541

    
542
    // Check that number of feeds items is equal to the expected items.
543
    $this->assertEqual($row_count, 2, 'Nodes expired.');
544
  }
545

    
546
  /**
547
   * Tests process in background option.
548
   */
549
  public function testImportInBackground() {
550
    // Just remove the mappings rather than creating a new importer.
551
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
552

    
553
    $this->setPlugin('syndication', 'FeedsFileFetcher');
554
    $this->setPlugin('syndication', 'FeedsCSVParser');
555

    
556
    $this->setSettings('syndication', NULL, array(
557
      'content_type' => '',
558
      'process_in_background' => TRUE,
559
      'import_period' => FEEDS_SCHEDULE_NEVER,
560
    ));
561

    
562
    $this->addMappings('syndication', array(
563
      0 => array(
564
        'source' => 'title',
565
        'target' => 'title',
566
      ),
567
      1 => array(
568
        'source' => 'GUID',
569
        'target' => 'guid',
570
        'unique' => TRUE,
571
      ),
572
    ));
573

    
574
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/many_nodes_ordered.csv', 'Schedule import');
575
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
576

    
577
    // Assert that the import button is disabled.
578
    $this->assertFieldDisabled('op');
579

    
580
    // Assert that there is one import task in the queue.
581
    $this->assertEqual(1, db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_import'")->fetchField());
582

    
583
    // The feed should still be scheduled because it is being processed.
584
    // @see https://drupal.org/node/2275893
585
    $this->cronRun();
586
    $this->assertEqual(86, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
587

    
588
    // Assert that the import button is no longer disabled.
589
    $this->drupalGet('import/syndication');
590
    $this->assertFieldEnabled('op');
591

    
592
    // Assert that there are no more import tasks in the queue.
593
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_import'")->fetchField());
594
  }
595

    
596
  /**
597
   * Tests clearing items in background.
598
   */
599
  public function testClearInBackground() {
600
    // Just remove the mappings rather than creating a new importer.
601
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
602

    
603
    $this->setSettings('syndication', NULL, array(
604
      'content_type' => '',
605
    ));
606

    
607
    $this->setPlugin('syndication', 'FeedsFileFetcher');
608
    $this->setPlugin('syndication', 'FeedsCSVParser');
609

    
610
    $this->addMappings('syndication', array(
611
      0 => array(
612
        'source' => 'title',
613
        'target' => 'title',
614
      ),
615
      1 => array(
616
        'source' => 'GUID',
617
        'target' => 'guid',
618
        'unique' => TRUE,
619
      ),
620
    ));
621

    
622
    // Import 86 nodes.
623
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/many_nodes_ordered.csv');
624
    $this->assertEqual(86, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
625

    
626
    // Turn on "Process in background option" and turn off periodic import.
627
    $this->setSettings('syndication', NULL, array(
628
      'process_in_background' => TRUE,
629
      'import_period' => FEEDS_SCHEDULE_NEVER,
630
    ));
631

    
632
    // Now schedule clearing in background.
633
    $this->drupalPost('import/syndication/delete-items', array(), t('Schedule delete'));
634
    $this->assertEqual(86, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
635

    
636
    // Assert that the delete button is disabled.
637
    $this->drupalGet('import/syndication/delete-items');
638
    $this->assertFieldDisabled('op');
639

    
640
    // Assert that there is one clear task in the queue.
641
    $this->assertEqual(1, db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_clear'")->fetchField());
642

    
643
    // And run cron.
644
    $this->cronRun();
645
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
646

    
647
    // Assert that the delete button is no longer disabled.
648
    $this->drupalGet('import/syndication/delete-items');
649
    $this->assertFieldEnabled('op');
650

    
651
    // Assert that there are no more clear tasks in the queue.
652
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_clear'")->fetchField());
653
  }
654

    
655
  /**
656
   * Tests unlocking a feed.
657
   */
658
  public function testUnlock() {
659
    // Just remove the mappings rather than creating a new importer.
660
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
661

    
662
    $this->setPlugin('syndication', 'FeedsFileFetcher');
663
    $this->setPlugin('syndication', 'FeedsCSVParser');
664

    
665
    $this->setSettings('syndication', NULL, array(
666
      'content_type' => '',
667
      'process_in_background' => TRUE,
668
      'import_period' => FEEDS_SCHEDULE_NEVER,
669
    ));
670

    
671
    $this->addMappings('syndication', array(
672
      0 => array(
673
        'source' => 'title',
674
        'target' => 'title',
675
      ),
676
      1 => array(
677
        'source' => 'GUID',
678
        'target' => 'guid',
679
        'unique' => TRUE,
680
      ),
681
    ));
682

    
683
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/many_nodes_ordered.csv', 'Schedule import');
684
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
685

    
686
    // Assert that the import button is disabled.
687
    $this->assertFieldDisabled('op');
688

    
689
    // Assert that there is one import task in the queue.
690
    $this->assertEqual(1, db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_import'")->fetchField());
691

    
692
    // Now unlock the feed.
693
    $this->drupalPost('import/syndication/unlock', array(), 'Unlock');
694
    $this->assertText('Importer unlocked.');
695

    
696
    // Assert that the unlock button is now disabled.
697
    $this->drupalGet('import/syndication/unlock');
698
    $this->assertFieldDisabled('op');
699
    $this->assertText('This importer is not locked, therefore it cannot be unlocked.');
700

    
701
    // And assert that the import button is no longer disabled.
702
    $this->drupalGet('import/syndication');
703
    $this->assertFieldEnabled('op');
704
  }
705

    
706
  /**
707
   * Tests skip new items.
708
   */
709
  public function testSkipNewItems() {
710
    // Include FeedsProcessor.inc so processor related constants are available.
711
    module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
712

    
713
    // Attach to standalone importer.
714
    $this->setSettings('syndication', NULL, array('content_type' => ''));
715
    // Set that new items should not be imported.
716
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
717
      'insert_new' => FEEDS_SKIP_NEW,
718
      'update_existing' => FEEDS_SKIP_EXISTING,
719
    ));
720

    
721
    // Make title unique target.
722
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
723
    $this->addMappings('syndication', array(
724
      0 => array(
725
        'source' => 'title',
726
        'target' => 'title',
727
        'unique' => TRUE,
728
      ),
729
      1 => array(
730
        'source' => 'description',
731
        'target' => 'body',
732
      ),
733
      2 => array(
734
        'source' => 'timestamp',
735
        'target' => 'created',
736
      ),
737
    ));
738

    
739
    // Do a first import, no nodes should be created.
740
    $edit = array(
741
      'feeds[FeedsHTTPFetcher][source]' => $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed.rss2',
742
    );
743
    $this->drupalPost('import/syndication', $edit, 'Import');
744
    $this->assertText('There are no new nodes');
745

    
746
    // Now create two nodes with titles that are present in the source
747
    // "developmentseed.rss2".
748
    $this->drupalCreateNode(array(
749
      'type' => 'article',
750
      'title' => 'Open Atrium Translation Workflow: Two Way Translation Updates',
751
    ));
752
    $this->drupalCreateNode(array(
753
      'type' => 'article',
754
      'title' => 'Week in DC Tech: October 5th Edition',
755
    ));
756

    
757
    // Import again. Since the processor is set to not update as well, nothing
758
    // should be imported.
759
    $this->drupalPost('import/syndication', array(), 'Import');
760
    $this->assertText('There are no new nodes');
761

    
762
    // Now set importer to update existing.
763
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
764
      'update_existing' => FEEDS_UPDATE_EXISTING,
765
    ));
766
    // And import again. Two nodes should be updated.
767
    $this->drupalPost('import/syndication', array(), 'Import');
768
    $this->assertText('Updated 2 nodes.');
769

    
770
    // Change "insert_new" setting to insert new items to verify if changing the
771
    // setting later has the effect that new items will be imported as yet.
772
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
773
      'insert_new' => FEEDS_INSERT_NEW,
774
    ));
775
    // Import. Eight nodes should be created. No nodes should be updated.
776
    $this->drupalPost('import/syndication', array(), 'Import');
777
    $this->assertText('Created 8 nodes.');
778
    $this->assertNoText('Updated 2 nodes.');
779
  }
780

    
781
  /**
782
   * Tests mapping to the node author using a float value.
783
   *
784
   * @see feeds_tests_feeds_after_parse()
785
   */
786
  public function testUidTargetWithFloat() {
787
    // Set flag to turn uid values to floats.
788
    variable_set('feeds_tests_feeds_after_parse_uid_float_value', TRUE);
789

    
790
    // Rebuild node type information.
791
    drupal_static_reset();
792
    node_types_rebuild();
793

    
794
    // Create a role with permission to create articles.
795
    $rid = $this->drupalCreateRole(array(
796
      'access content',
797
      'create article content',
798
    ));
799

    
800
    // Create account with uid 201.
801
    user_save(drupal_anonymous_user(), array(
802
      'uid' => 201,
803
      'name' => 'Morticia',
804
      'mail' => 'morticia@example.com',
805
      'pass' => 'mort',
806
      'status' => 1,
807
      'roles' => array(
808
        $rid => $rid,
809
      ),
810
    ));
811

    
812
    // Create account with uid 202.
813
    user_save(drupal_anonymous_user(), array(
814
      'uid' => 202,
815
      'name' => 'Joe',
816
      'mail' => 'joe@example.com',
817
      'pass' => 'joe',
818
      'status' => 1,
819
      'roles' => array(
820
        $rid => $rid,
821
      ),
822
    ));
823

    
824
    // Create and configure importer.
825
    $this->createImporterConfiguration('Content CSV', 'csv');
826
    $this->setSettings('csv', NULL, array(
827
      'content_type' => '',
828
      'import_period' => FEEDS_SCHEDULE_NEVER,
829
    ));
830
    $this->setPlugin('csv', 'FeedsFileFetcher');
831
    $this->setPlugin('csv', 'FeedsCSVParser');
832
    // Ensure that the "Authorize" option is enabled.
833
    $this->setSettings('csv', 'FeedsNodeProcessor', array(
834
      'authorize' => TRUE,
835
    ));
836
    $this->addMappings('csv', array(
837
      0 => array(
838
        'source' => 'title',
839
        'target' => 'title',
840
      ),
841
      1 => array(
842
        'source' => 'uid',
843
        'target' => 'uid',
844
      ),
845
    ));
846

    
847
    // Import CSV file.
848
    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_uid.csv');
849
    $this->assertText('Created 2 nodes');
850

    
851
    // And assert that the two created nodes have the expected author assigned.
852
    $expected_values = array(
853
      1 => array(
854
        'uid' => 201,
855
      ),
856
      2 => array(
857
        'uid' => 202,
858
      ),
859
    );
860
    for ($i = 1; $i <= 2; $i++) {
861
      $node = node_load($i);
862
      $this->assertEqual($expected_values[$i]['uid'], $node->uid);
863
    }
864
  }
865

    
866
  /**
867
   * Tests if the target "changed" works as expected.
868
   */
869
  public function testChangedTarget() {
870
    // Create and configure importer.
871
    $this->createImporterConfiguration('Content CSV', 'csv');
872
    $this->setSettings('csv', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
873
    $this->setPlugin('csv', 'FeedsFileFetcher');
874
    $this->setPlugin('csv', 'FeedsCSVParser');
875
    $this->addMappings('csv', array(
876
      0 => array(
877
        'source' => 'title',
878
        'target' => 'title',
879
      ),
880
      // Borrow the timestamp value from the "created" column in the csv.
881
      1 => array(
882
        'source' => 'created',
883
        'target' => 'changed',
884
      ),
885
    ));
886

    
887
    // Import CSV file.
888
    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content.csv');
889
    $this->assertText('Created 2 nodes');
890

    
891
    // Assert changed date of nodes.
892
    $expected_values = array(
893
      1 => array(
894
        'changed' => 1251936720,
895
      ),
896
      2 => array(
897
        'changed' => 1251932360,
898
      ),
899
    );
900
    for ($i = 1; $i <= 2; $i++) {
901
      $node = node_load($i);
902
      $this->assertEqual($expected_values[$i]['changed'], $node->changed);
903
    }
904
  }
905

    
906
  /**
907
   * Tests the FeedsSource::pushImport() method.
908
   */
909
  public function testPushImport() {
910
    // Attach to standalone importer.
911
    $this->setSettings('syndication', NULL, array('content_type' => ''));
912

    
913
    $raw = file_get_contents(dirname(__FILE__) . '/feeds/developmentseed.rss2');
914
    feeds_source('syndication', 0)->pushImport(new FeedsFetcherResult($raw));
915
    $this->assertEqual(10, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
916
  }
917

    
918
  /**
919
   * Tests the FeedsSource::pushImport() method with a CSV file.
920
   */
921
  public function testPushImportWithCSV() {
922
    // Attach to standalone importer and configure.
923
    $this->setSettings('syndication', NULL, array('content_type' => ''));
924
    $this->setPlugin('syndication', 'FeedsCSVParser');
925
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
926
    $this->addMappings('syndication', array(
927
      0 => array(
928
        'source' => 'title',
929
        'target' => 'title',
930
      ),
931
    ));
932

    
933
    $raw = file_get_contents($this->absolutePath() . '/tests/feeds/many_nodes.csv');
934
    feeds_source('syndication', 0)->pushImport(new FeedsFetcherResult($raw));
935
    $this->assertEqual(86, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
936
  }
937

    
938
  /**
939
   * Tests if target item is not updated when only non-mapped data on the source changed.
940
   */
941
  public function testIrrelevantUpdate() {
942
    // Include FeedsProcessor.inc so processor related constants are available.
943
    module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
944

    
945
    // Attach to standalone importer and configure.
946
    $this->setSettings('syndication', NULL, array('content_type' => ''));
947
    $this->setPlugin('syndication', 'FeedsFileFetcher');
948
    $this->setPlugin('syndication', 'FeedsCSVParser');
949
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
950
    $this->addMappings('syndication', array(
951
      0 => array(
952
        'source' => 'name',
953
        'target' => 'title',
954
        'unique' => TRUE,
955
      ),
956
    ));
957

    
958
    // Import file.
959
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users.csv');
960
    $this->assertText('Created 5 nodes');
961

    
962
    // Ensure that no nodes are updated when only non-mapped columns changed.
963
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
964
      'skip_hash_check' => FALSE,
965
      'update_existing' => FEEDS_UPDATE_EXISTING,
966
    ));
967
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users_updated.csv');
968
    $this->assertText('There are no new nodes.');
969
  }
970

    
971
}