Projet

Général

Profil

Paste
Télécharger (29,5 ko) Statistiques
| Branche: | Révision:

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

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
  public static function getInfo() {
14
    return array(
15
      'name' => 'Processor: Node',
16
      'description' => 'Tests for the node processor.',
17
      'group' => 'Feeds',
18
    );
19
  }
20

    
21
  /**
22
   * Set up test.
23
   */
24
  public function setUp() {
25
    parent::setUp();
26

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

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

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

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

    
72
    // Assert 10 items aggregated after creation of the node.
73
    $this->assertText('Created 10 nodes');
74
    $article_nid = db_query_range("SELECT nid FROM {node} WHERE type = 'article'", 0, 1)->fetchField();
75
    $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());
76

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

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

    
87
    // Assert DB status.
88
    $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();
89
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
90

    
91
    // Assert default input format on first imported feed node.
92

    
93
    // NEEDS update.
94
    // $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();
95
    // $this->assertEqual($format, filter_fallback_format(), 'Using default Input format.');
96

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

    
101
    // Assert DB status, there still shouldn't be more than 10 items.
102
    $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();
103
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
104

    
105
    // All of the above tests should have produced published nodes, set default
106
    // to unpublished, import again.
107
    $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();
108
    $this->assertEqual($count, 10, 'All items are published.');
109
    $edit = array(
110
      'node_options[status]' => FALSE,
111
    );
112
    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
113
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
114
    $this->drupalPost("node/$nid/import", array(), 'Import');
115
    $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();
116
    $this->assertEqual($count, 10, 'No items are published.');
117
    $edit = array(
118
      'node_options[status]' => TRUE,
119
    );
120
    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
121
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
122

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

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

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

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

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

    
151
    // Change input format.
152
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('input_format' => 'plain_text'));
153

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

    
158
    // Assert author.
159
    $this->drupalGet('node');
160
    $this->assertPattern('/<span class="username">' . check_plain($this->auth_user->name) . '<\/span>/');
161
    $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();
162
    $this->assertEqual($count, 10, 'Accurate number of items in database.');
163

    
164
    // Assert input format.
165

    
166
    // NEEDS update.
167
    // $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();
168
    // $this->assertEqual($format, filter_fallback_format() + 1, 'Set non-default Input format.');
169

    
170
    // Set to update existing, remove authorship of above nodes and import again.
171
    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 2));
172
    $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();
173
    db_update('node')
174
      ->fields(array('uid' => 0))
175
      ->condition('nid', $nids, 'IN')
176
      ->execute();
177
    db_update('feeds_item')
178
      ->fields(array('hash' => ''))
179
      ->condition('entity_type', 'node')
180
      ->condition('entity_id', $nids, 'IN')
181
      ->execute();
182
    $this->drupalPost("node/$nid/import", array(), 'Import');
183
    $this->drupalGet('node');
184
    $this->assertNoPattern('/<span class="username">' . check_plain($this->auth_user->name) . '<\/span>/');
185
    $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();
186
    $this->assertEqual($count, 0, 'Accurate number of items in database.');
187

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

    
205
    // Login with new user with only access content permissions.
206
    $this->drupalLogin($this->auth_user);
207

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

    
213
    // Now create a second feed configuration that is not attached to a content
214
    // type and run tests on importing/purging.
215

    
216
    // Login with sufficient permissions.
217
    $this->drupalLogin($this->admin_user);
218
    // Remove all items again so that next test can check for them.
219
    $this->drupalPost("node/$nid/delete-items", array(), 'Delete');
220

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
346
    // Use File Fetcher.
347
    $this->drupalLogin($this->admin_user);
348

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

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

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

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

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

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

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

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

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

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

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

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

    
468
    $account = user_save(drupal_anonymous_user(), $edit);
469

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

    
480
    $nid = $this->createFeedNode();
481

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

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

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

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

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

    
511
    // Create importer.
512
    $this->importURL('syndication');
513

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

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

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

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

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

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

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

    
551
    // Set our process limit to something simple.
552
    variable_set('feeds_process_limit', 5);
553

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

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

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

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

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

    
584
  /**
585
   * Tests skip new items.
586
   */
587
  public function testSkipNewItems() {
588
    // Include FeedsProcessor.inc so processor related constants are available.
589
    module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
590

    
591
    // Attach to standalone importer.
592
    $this->setSettings('syndication', NULL, array('content_type' => ''));
593
    // Set that new items should not be imported.
594
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
595
      'insert_new' => FEEDS_SKIP_NEW,
596
      'update_existing' => FEEDS_SKIP_EXISTING,
597
    ));
598

    
599
    // Make title unique target.
600
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
601
    $this->addMappings('syndication', array(
602
      0 => array(
603
        'source' => 'title',
604
        'target' => 'title',
605
        'unique' => TRUE,
606
      ),
607
      1 => array(
608
        'source' => 'description',
609
        'target' => 'body',
610
      ),
611
      2 => array(
612
        'source' => 'timestamp',
613
        'target' => 'created',
614
      ),
615
    ));
616

    
617
    // Do a first import, no nodes should be created.
618
    $edit = array(
619
      'feeds[FeedsHTTPFetcher][source]' => $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed.rss2',
620
    );
621
    $this->drupalPost('import/syndication', $edit, 'Import');
622
    $this->assertText('There are no new nodes');
623

    
624
    // Now create two nodes with titles that are present in the source
625
    // "developmentseed.rss2".
626
    $this->drupalCreateNode(array(
627
      'type' => 'article',
628
      'title' => 'Open Atrium Translation Workflow: Two Way Translation Updates',
629
    ));
630
    $this->drupalCreateNode(array(
631
      'type' => 'article',
632
      'title' => 'Week in DC Tech: October 5th Edition',
633
    ));
634

    
635
    // Import again. Since the processor is set to not update as well, nothing
636
    // should be imported.
637
    $this->drupalPost('import/syndication', array(), 'Import');
638
    $this->assertText('There are no new nodes');
639

    
640
    // Now set importer to update existing.
641
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
642
      'update_existing' => FEEDS_UPDATE_EXISTING,
643
    ));
644
    // And import again. Two nodes should be updated.
645
    $this->drupalPost('import/syndication', array(), 'Import');
646
    $this->assertText('Updated 2 nodes.');
647

    
648
    // Change "insert_new" setting to insert new items to verify if changing the
649
    // setting later has the effect that new items will be imported as yet.
650
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
651
      'insert_new' => FEEDS_INSERT_NEW,
652
    ));
653
    // Import. Eight nodes should be created. No nodes should be updated.
654
    $this->drupalPost('import/syndication', array(), 'Import');
655
    $this->assertText('Created 8 nodes.');
656
    $this->assertNoText('Updated 2 nodes.');
657
  }
658

    
659
  /**
660
   * Tests if the target "changed" works as expected.
661
   */
662
  public function testChangedTarget() {
663
    // Create and configure importer.
664
    $this->createImporterConfiguration('Content CSV', 'csv');
665
    $this->setSettings('csv', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
666
    $this->setPlugin('csv', 'FeedsFileFetcher');
667
    $this->setPlugin('csv', 'FeedsCSVParser');
668
    $this->addMappings('csv', array(
669
      0 => array(
670
        'source' => 'title',
671
        'target' => 'title',
672
      ),
673
      // Borrow the timestamp value from the "created" column in the csv.
674
      1 => array(
675
        'source' => 'created',
676
        'target' => 'changed',
677
      ),
678
    ));
679

    
680
    // Import CSV file.
681
    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content.csv');
682
    $this->assertText('Created 2 nodes');
683

    
684
    // Assert changed date of nodes.
685
    $expected_values = array(
686
      1 => array(
687
        'changed' => 1251936720,
688
      ),
689
      2 => array(
690
        'changed' => 1251932360,
691
      ),
692
    );
693
    for ($i = 1; $i <= 2; $i++) {
694
      $node = node_load($i);
695
      $this->assertEqual($expected_values[$i]['changed'], $node->changed);
696
    }
697
  }
698

    
699
  /**
700
   * Tests the FeedsSource::pushImport() method.
701
   */
702
  public function testPushImport() {
703
    // Attach to standalone importer.
704
    $this->setSettings('syndication', NULL, array('content_type' => ''));
705

    
706
    $raw = file_get_contents(dirname(__FILE__) . '/feeds/developmentseed.rss2');
707
    feeds_source('syndication', 0)->pushImport(new FeedsFetcherResult($raw));
708
    $this->assertEqual(10, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
709
  }
710

    
711
  /**
712
   * Tests the FeedsSource::pushImport() method with a CSV file.
713
   */
714
  public function testPushImportWithCSV() {
715
    // Attach to standalone importer and configure.
716
    $this->setSettings('syndication', NULL, array('content_type' => ''));
717
    $this->setPlugin('syndication', 'FeedsCSVParser');
718
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
719
    $this->addMappings('syndication', array(
720
      0 => array(
721
        'source' => 'title',
722
        'target' => 'title',
723
      ),
724
    ));
725

    
726
    $raw = file_get_contents($this->absolutePath() . '/tests/feeds/many_nodes.csv');
727
    feeds_source('syndication', 0)->pushImport(new FeedsFetcherResult($raw));
728
    $this->assertEqual(86, db_query("SELECT COUNT(*) FROM {node}")->fetchField());
729
  }
730

    
731
  /**
732
   * Tests if target item is not updated when only non-mapped data on the source changed.
733
   */
734
  public function testIrrelevantUpdate() {
735
    // Include FeedsProcessor.inc so processor related constants are available.
736
    module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
737

    
738
    // Attach to standalone importer and configure.
739
    $this->setSettings('syndication', NULL, array('content_type' => ''));
740
    $this->setPlugin('syndication', 'FeedsFileFetcher');
741
    $this->setPlugin('syndication', 'FeedsCSVParser');
742
    $this->removeMappings('syndication', $this->getCurrentMappings('syndication'));
743
    $this->addMappings('syndication', array(
744
      0 => array(
745
        'source' => 'name',
746
        'target' => 'title',
747
        'unique' => TRUE,
748
      ),
749
    ));
750

    
751
    // Import file.
752
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users.csv');
753
    $this->assertText('Created 5 nodes');
754

    
755
    // Ensure that no nodes are updated when only non-mapped columns changed.
756
    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
757
      'skip_hash_check' => FALSE,
758
      'update_existing' => FEEDS_UPDATE_EXISTING,
759
    ));
760
    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/users_updated.csv');
761
    $this->assertText('There are no new nodes.');
762
  }
763

    
764
}