diff --git a/tests/common_syndication_parser.test b/tests/common_syndication_parser.test
index de947ac0687b9cee824581b49a71d018d704d266..4a92d3b757ce73d914bdce8c65e3c316120d40a9 100644
--- a/tests/common_syndication_parser.test
+++ b/tests/common_syndication_parser.test
@@ -2,7 +2,7 @@
 // $Id$
 
 /**
- * Test cases for common syndication parser.
+ * Test cases for common syndication parser library.
  *
  * @todo Break out into Drupal independent test framework.
  * @todo Could I use DrupalUnitTestCase here?
diff --git a/tests/feeds.test b/tests/feeds.test
deleted file mode 100644
index d0c3c7d1c225d35f647b886cd1e87bb899cf5dc6..0000000000000000000000000000000000000000
--- a/tests/feeds.test
+++ /dev/null
@@ -1,1051 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Feeds tests.
- */
-
-// Require FeedsWebTestCase class definition.
-require_once(dirname(__FILE__) .'/feeds.test.inc');
-
-/**
- * Test aggregating a feed as node items.
- */
-class FeedsRSStoNodesTest extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('RSS import to nodes'),
-      'description' => t('Tests a feed configuration that is attached to a content type, uses HTTP fetcher, common syndication parser and a node processor. Repeats the same test for an importer configuration that is not attached to a content type and for a configuration that is attached to a content type and uses the file fetcher.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools');
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes', 'administer content types',
-        )
-      )
-    );
-  }
-
-  /**
-   * Test node creation, refreshing/deleting feeds and feed items.
-   */
-  public function test() {
-    // Set the teaser length to unlimited otherwise tests looking for text on
-    // nodes will fail.
-    $edit = array(
-      'teaser_length' => 0,
-    );
-    $this->drupalPost('admin/content/node-settings', $edit, 'Save configuration');
-
-    // Create an importer configuration.
-    $this->createImporterConfiguration('Syndication', 'syndication');
-    $this->addMappings('syndication',
-      array(
-        array(
-          'source' => 'title',
-          'target' => 'title',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'description',
-          'target' => 'body',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'timestamp',
-          'target' => 'created',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'url',
-          'target' => 'url',
-          'unique' => TRUE,
-        ),
-        array(
-          'source' => 'guid',
-          'target' => 'guid',
-          'unique' => TRUE,
-        ),
-      )
-    );
-
-    $nid = $this->createFeedNode();
-    // Assert 10 items aggregated after creation of the node.
-    $this->assertText('Created 10 Story nodes.');
-
-    // Navigate to feed node, there should be Feeds tabs visible.
-    $this->drupalGet('node/'. $nid);
-    $this->assertRaw('node/'. $nid .'/import');
-    $this->assertRaw('node/'. $nid .'/delete-items');
-
-    // Navigate to a non-feed node, there should be no Feeds tabs visible.
-    $story_nid = db_result(db_query_range('SELECT nid FROM {node} WHERE type = "story"', 0, 1));
-    $this->drupalGet('node/'. $story_nid);
-    $this->assertNoRaw('node/'. $story_nid .'/import');
-    $this->assertNoRaw('node/'. $story_nid .'/delete-items');
-    $this->assertEqual("Created/updated by FeedsNodeProcessor", db_result(db_query("SELECT nr.log FROM {node} n JOIN {node_revisions} nr ON n.vid = nr.vid WHERE n.nid = %d", $story_nid)));
-
-    // Assert accuracy of aggregated information.
-    $this->drupalGet('node');
-    $this->assertPattern('/<span class="submitted">(.*?)Anonymous<\/span>/');
-    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
-    $this->assertText('Tue, 10/06/2009');
-    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
-    $this->assertText('Week in DC Tech: October 5th Edition');
-    $this->assertText('Mon, 10/05/2009');
-    $this->assertText('There are some great technology events happening this week');
-    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
-    $this->assertText('Fri, 10/02/2009');
-    $this->assertText('Open Atrium is being used as a base platform for collaboration');
-    $this->assertText('September GeoDC Meetup Tonight');
-    $this->assertText('Wed, 09/30/2009');
-    $this->assertText('Today is the last Wednesday of the month');
-    $this->assertText('Week in DC Tech: September 28th Edition');
-    $this->assertText('Mon, 09/28/2009');
-    $this->assertText('Looking to geek out this week? There are a bunch of');
-    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
-    $this->assertText('Thu, 09/24/2009');
-    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
-    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
-    $this->assertText('Tue, 09/22/2009');
-    $this->assertText('In addition to authentication, the Siteminder system');
-    $this->assertText('Week in DC Tech: September 21 Edition');
-    $this->assertText('Mon, 09/21/2009');
-    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
-    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
-    $this->assertText('Mon, 09/21/2009');
-    $this->assertText('Presenting on Features in Drupal and Open Atrium');
-    $this->assertText('Scaling the Open Atrium UI');
-    $this->assertText('Fri, 09/18/2009');
-    $this->assertText('The first major change is switching');
-
-    // Assert DB status.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Assert default input format on first imported feed node.
-    $format = db_result(db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revisions} nr ON n.vid = nr.vid", 0, 1));
-    $this->assertEqual($format, FILTER_FORMAT_DEFAULT, 'Using default Input format.');
-
-    // Import again.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('There is no new content.');
-
-    // Assert DB status, there still shouldn't be more than 10 items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // All of the above tests should have produced published nodes, set default
-    // to unpublished, import again.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid WHERE n.status = 1"));
-    $this->assertEqual($count, 10, 'All items are published.');
-    $edit = array(
-      'node_options[status]' => FALSE,
-    );
-    $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid WHERE n.status = 0"));
-    $this->assertEqual($count, 10, 'No items are published.');
-    $edit = array(
-      'node_options[status]' => TRUE,
-    );
-    $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-
-    // Enable replace existing and import updated feed file.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 1));
-    $feed_url = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/developmentseed_changes.rss2';
-    $this->editFeedNode($nid, $feed_url);
-    $this->drupalPost('node/' . $nid . '/import', array(), 'Import');
-    $this->assertText('Updated 2 Story nodes.');
-
-    // Assert accuracy of aggregated content (check 2 updates, one original).
-    $this->drupalGet('node');
-    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
-    $this->assertText('Presenting on Features in Drupal and Managing News');
-    $this->assertText('Scaling the Open Atrium UI');
-
-    // Import again.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('There is no new content.');
-
-    // Assert DB status, there still shouldn't be more than 10 items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Now delete all items.
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 10 nodes.');
-
-    // Assert DB status, now there should be no items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 0, 'Accurate number of items in database.');
-
-    // Change author.
-    $author = $this->drupalCreateUser();
-    $this->setSettings('syndication', 'FeedsNodeProcessor', array('author' => $author->name));
-
-    // Change input format.
-    $this->setSettings('syndication', 'FeedsNodeProcessor', array('input_format' => FILTER_FORMAT_DEFAULT + 1));
-
-    // Import again.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('Created 10 Story nodes.');
-
-    // Assert author.
-    $this->drupalGet('node');
-    $this->assertPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid WHERE n.uid = %d", $author->uid));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Assert input format.
-    $format = db_result(db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revisions} nr ON n.vid = nr.vid", 0, 1));
-    $this->assertEqual($format, FILTER_FORMAT_DEFAULT + 1, 'Set non-default Input format.');
-
-    // Set to update existing, remove authorship of above nodes and import again.
-    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 2));
-    db_query("UPDATE {node} n JOIN {feeds_node_item} fi ON n.nid = fi.nid SET n.uid = 0, fi.hash=''");
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->drupalGet('node');
-    $this->assertNoPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid WHERE n.uid = %d", $author->uid));
-    $this->assertEqual($count, 0, 'Accurate number of items in database.');
-
-    // Map feed node's author to feed item author, update - feed node's items
-    // should now be assigned to feed node author.
-    $this->addMappings('syndication',
-      array(
-        array(
-          'source' => 'parent:uid',
-          'target' => 'uid',
-        ),
-      )
-    );
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->drupalGet('node');
-    $this->assertNoPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
-    $uid = db_result(db_query("SELECT uid FROM {node} WHERE nid = %d", $nid));
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE uid = %d", $uid));
-    $this->assertEqual($count, 11, 'All feed item nodes are assigned to feed node author.');
-
-    // Login with new user with only access content permissions.
-    $this->drupalLogin(
-      $this->drupalCreateUser()
-    );
-    // Navigate to feed node, there should be no Feeds tabs visible.
-    $this->drupalGet('node/'. $nid);
-    $this->assertNoRaw('node/'. $nid .'/import');
-    $this->assertNoRaw('node/'. $nid .'/delete-items');
-
-    // Now create a second feed configuration that is not attached to a content
-    // type and run tests on importing/purging.
-
-    // Login with sufficient permissions.
-    $this->drupalLogin(
-      $this->drupalCreateUser(array('administer feeds', 'administer nodes'))
-    );
-    // Remove all items again so that next test can check for them.
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-
-    // Create an importer, not attached to content type.
-    $this->createImporterConfiguration('Syndication standalone', 'syndication_standalone');
-    $edit = array(
-      'content_type' => '',
-    );
-    $this->drupalPost('admin/build/feeds/edit/syndication_standalone/settings', $edit, 'Save');
-    $this->addMappings('syndication_standalone',
-      array(
-        array(
-          'source' => 'title',
-          'target' => 'title',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'description',
-          'target' => 'body',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'timestamp',
-          'target' => 'created',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'url',
-          'target' => 'url',
-          'unique' => TRUE,
-        ),
-        array(
-          'source' => 'guid',
-          'target' => 'guid',
-          'unique' => TRUE,
-        ),
-      )
-    );
-
-    // Import, assert 10 items aggregated after creation of the node.
-    $this->importURL('syndication_standalone');
-    $this->assertText('Created 10 Story nodes.');
-
-    // Assert accuracy of aggregated information.
-    $this->drupalGet('node');
-    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
-    $this->assertText('Tue, 10/06/2009');
-    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
-    $this->assertText('Week in DC Tech: October 5th Edition');
-    $this->assertText('Mon, 10/05/2009');
-    $this->assertText('There are some great technology events happening this week');
-    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
-    $this->assertText('Fri, 10/02/2009');
-    $this->assertText('Open Atrium is being used as a base platform for collaboration');
-    $this->assertText('September GeoDC Meetup Tonight');
-    $this->assertText('Wed, 09/30/2009');
-    $this->assertText('Today is the last Wednesday of the month');
-    $this->assertText('Week in DC Tech: September 28th Edition');
-    $this->assertText('Mon, 09/28/2009');
-    $this->assertText('Looking to geek out this week? There are a bunch of');
-    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
-    $this->assertText('Thu, 09/24/2009');
-    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
-    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
-    $this->assertText('Tue, 09/22/2009');
-    $this->assertText('In addition to authentication, the Siteminder system');
-    $this->assertText('Week in DC Tech: September 21 Edition');
-    $this->assertText('Mon, 09/21/2009');
-    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
-    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
-    $this->assertText('Mon, 09/21/2009');
-    $this->assertText('Presenting on Features in Drupal and Open Atrium');
-    $this->assertText('Scaling the Open Atrium UI');
-    $this->assertText('Fri, 09/18/2009');
-    $this->assertText('The first major change is switching');
-
-    // Assert DB status.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Import again.
-    $this->drupalPost('import/syndication_standalone', array(), 'Import');
-    $this->assertText('There is no new content.');
-
-    // Assert DB status, there still shouldn't be more than 10 items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Enable replace existing and import updated feed file.
-    $this->setSettings('syndication_standalone', 'FeedsNodeProcessor', array('update_existing' => 1));
-    $feed_url = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed_changes.rss2';
-    $this->importURL('syndication_standalone', $feed_url);
-    $this->assertText('Updated 2 Story nodes.');
-
-    // Assert accuracy of aggregated information (check 2 updates, one orig).
-    $this->drupalGet('node');
-    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
-    $this->assertText('Presenting on Features in Drupal and Managing News');
-    $this->assertText('Scaling the Open Atrium UI');
-
-    // Import again.
-    $this->drupalPost('import/syndication_standalone', array(), 'Import');
-    $this->assertText('There is no new content.');
-
-    // Assert DB status, there still shouldn't be more than 10 items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Now delete all items.
-    $this->drupalPost('import/syndication_standalone/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 10 nodes.');
-
-    // Assert DB status, now there should be no items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 0, 'Accurate number of items in database.');
-
-    // Import again, we should find new content.
-    $this->drupalPost('import/syndication_standalone', array(), 'Import');
-    $this->assertText('Created 10 Story nodes.');
-
-    // Assert DB status, there should be 10 again.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Login with new user with only access content permissions.
-    $this->drupalLogin(
-      $this->drupalCreateUser()
-    );
-    // Navigate to feed import form, access should be denied.
-    $this->drupalGet('import/syndication_standalone');
-    $this->assertResponse(403);
-
-    // Use File Fetcher.
-    $this->drupalLogin(
-      $this->drupalCreateUser(array('administer feeds', 'administer nodes'))
-    );
-    $this->setPlugin('syndication', 'FeedsFileFetcher');
-    // Create a feed node.
-    $edit = array(
-      'files[feeds]' => $this->absolutePath() .'/tests/feeds/drupalplanet.rss2',
-    );
-    $this->drupalPost('node/add/page', $edit, 'Save');
-    $this->assertText('has been created.');
-    $this->assertText('Created 25 Story nodes.');
-  }
-}
-
-/**
- * Test aggregating a feed as data records.
- */
-class FeedsRSStoDataTest extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('RSS import to data records'),
-      'description' => t('Tests a feed configuration that is attached to a content type, uses common syndication parser and a node processor. <strong>Requires Data module and Views module</strong>.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'data', 'data_ui', 'views');
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'create page content',
-        )
-      )
-    );
-  }
-
-  /**
-   * Test node creation, refreshing/deleting feeds and feed items.
-   */
-  public function test() {
-
-    // Create an importer.
-    $this->createImporterConfiguration('Data feed', 'rss');
-
-    // Go to edit page and select the data processor.
-    $edit = array(
-      'plugin_key' => 'FeedsDataProcessor',
-    );
-    $this->drupalPost('admin/build/feeds/edit/rss/processor', $edit, 'Save');
-    $this->assertPlugins('rss', 'FeedsHTTPFetcher', 'FeedsSyndicationParser', 'FeedsDataProcessor');
-
-    // Go to mapping page and create a couple of mappings.
-    $mappings = array(
-      array(
-        'source' => 'guid',
-        'target' => 'new:text',
-        'unique' => TRUE,
-      ),
-      array(
-        'source' => 'url',
-        'target' => 'new:text',
-        'unique' => TRUE,
-      ),
-      array(
-        'source' => 'timestamp',
-        'target' => 'timestamp', // timestamp is an existing target.
-        'unique' => FALSE,
-      ),
-      array(
-        'source' => 'title',
-        'target' => 'new:varchar',
-        'unique' => FALSE,
-      ),
-      array(
-        'source' => 'description',
-        'target' => 'new:text',
-        'unique' => FALSE,
-      ),
-    );
-    $this->addMappings('rss', $mappings);
-
-    // Verify the mapping configuration.
-    $config = unserialize(db_result(db_query("SELECT config FROM {feeds_importer} WHERE id = 'rss'")));
-    $stored_mappings = $config['processor']['config']['mappings'];
-    foreach ($mappings as $i => $mapping) {
-      $this->assertEqual($mapping['source'], $stored_mappings[$i]['source']);
-      // This is intentional: the target of the stored mapping should have the
-      // same key as the source, this has to do with the fact that feeds data
-      // creates storage as the mapping is created.
-      $this->assertEqual($mapping['source'], $stored_mappings[$i]['target']);
-      $this->assertEqual($mapping['unique'], $stored_mappings[$i]['unique']);
-    }
-
-    // Create standard feed node.
-    $nid = $this->createFeedNode('rss');
-    // Assert 10 items aggregated after creation of the node.
-    $this->assertText('Created 10 items.');
-
-    // Login with a user with administer data permissions and review aggregated
-    // content.
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer data tables',
-          'administer feeds',
-        )
-      )
-    );
-
-    // Assert accuracy of aggregated information.
-    $this->drupalGet('admin/content/data/view/feeds_data_rss');
-    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
-    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
-    $this->assertText('Week in DC Tech: October 5th Edition');
-    $this->assertText('There are some great technology events happening this week');
-    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
-    $this->assertText('is being used as a base platform for collaboration at the World Bank because of its feature flexibility');
-    $this->assertText('September GeoDC Meetup Tonight');
-    $this->assertText('Today is the last Wednesday of the month');
-    $this->assertText('Week in DC Tech: September 28th Edition');
-    $this->assertText('Looking to geek out this week? There are a bunch of');
-    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
-    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
-    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
-    $this->assertText('In addition to authentication, the Siteminder system');
-    $this->assertText('Week in DC Tech: September 21 Edition');
-    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
-    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
-    $this->assertText('Presenting on Features in Drupal and Open Atrium');
-    $this->assertText('Scaling the Open Atrium UI');
-    $this->assertText('The first major change is switching');
-
-    // Assert DB status.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Import again.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('There are no new items.');
-
-    // Assert DB status, there still shouldn't be more than 10 items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // Now delete all items.
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('All items have been deleted.');
-
-    // Assert DB status, now there should be no items.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
-    $this->assertEqual($count, 0, 'Accurate number of items in database.');
-
-    // Import again, we should find new content.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('Created 10 items.');
-
-    // Assert DB status, there should be 10 again.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
-    $this->assertEqual($count, 10, 'Accurate number of items in database.');
-
-    // @todo Standalone import form testing.
-    // @todo Create a second feed and test.
-  }
-}
-
-/**
- * Test aggregating a feed as data records.
- */
-class FeedsCSVtoUsersTest extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('CSV import to users'),
-      'description' => t('Tests a standalone import configuration that uses file fetcher and CSV parser to import users from a CSV file.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer users',
-        )
-      )
-    );
-  }
-
-  /**
-   * Test node creation, refreshing/deleting feeds and feed items.
-   */
-  public function test() {
-
-    // Create an importer.
-    $this->createImporterConfiguration('User import', 'user_import');
-
-    // Set and configure plugins.
-    $this->setPlugin('user_import', 'FeedsFileFetcher');
-    $this->setPlugin('user_import', 'FeedsCSVParser');
-    $this->setPlugin('user_import', 'FeedsUserProcessor');
-
-    // Go to mapping page and create a couple of mappings.
-    $mappings = array(
-      '0' => array(
-        'source' => 'name',
-        'target' => 'name',
-        'unique' => 0,
-      ),
-      '1' => array(
-        'source' => 'mail',
-        'target' => 'mail',
-        'unique' => 1,
-      ),
-      '2' => array(
-        'source' => 'since',
-        'target' => 'created',
-        'unique' => FALSE,
-      ),
-    );
-    $this->addMappings('user_import', $mappings);
-
-    // Use standalone form.
-    $edit = array(
-      'content_type' => '',
-    );
-    $this->drupalPost('admin/build/feeds/edit/user_import/settings', $edit, 'Save');
-
-    // Create roles and assign one of them to the users to be imported.
-    $manager_rid = $this->drupalCreateRole(array('access content'), 'manager');
-    $admin_rid = $this->drupalCreateRole(array('access content'), 'administrator');
-    $edit = array(
-      "roles[$manager_rid]" => TRUE,
-      "roles[$admin_rid]" => FALSE,
-    );
-    $this->setSettings('user_import', 'FeedsUserProcessor', $edit);
-
-    // Import CSV file.
-    $this->importFile('user_import', $this->absolutePath() .'/tests/feeds/users.csv');
-
-    // Assert result.
-    $this->assertText('Created 4 users.');
-    // 1 user has an invalid email address, all users should be assigned
-    // the manager role.
-    $this->assertText('There was 1 user that could not be imported because either their name or their email was empty or not valid. Check import data and mapping settings on User processor.');
-    $this->drupalGet('admin/user/user');
-    $this->assertText('Morticia');
-    $this->assertText('Fester');
-    $this->assertText('Gomez');
-    $this->assertText('Pugsley');
-    $count = db_result(db_query("SELECT count(*) FROM {users_roles} WHERE rid = %d", $manager_rid));
-    $this->assertEqual($count, 4, t('All imported users were assigned the manager role.'));
-    $count = db_result(db_query("SELECT count(*) FROM {users_roles} WHERE rid = %d", $admin_rid));
-    $this->assertEqual($count, 0, t('No imported user was assigned the administrator role.'));
-
-    // @todo Test status setting, update existing and role settings.
-  }
-}
-
-/**
- * Test cron scheduling.
- */
-class FeedsSchedulerTestCase extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Scheduler'),
-      'description' => t('Tests for feeds scheduler.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools');
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-    $this->createImporterConfiguration();
-    $this->addMappings('syndication',
-      array(
-        array(
-          'source' => 'title',
-          'target' => 'title',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'description',
-          'target' => 'body',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'timestamp',
-          'target' => 'created',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'url',
-          'target' => 'url',
-          'unique' => TRUE,
-        ),
-        array(
-          'source' => 'guid',
-          'target' => 'guid',
-          'unique' => TRUE,
-        ),
-      )
-    );
-  }
-
-  /**
-   * Test scheduling on cron.
-   */
-  public function testScheduling() {
-    // Create 10 feed nodes. Turn off import on create before doing that.
-    $edit = array(
-      'import_on_create' => FALSE,
-    );
-    $this->drupalPost('admin/build/feeds/edit/syndication/settings', $edit, 'Save');
-    $this->assertText('Do not import on create');
-
-    $nids = $this->createFeedNodes();
-    // This implicitly tests the import_on_create node setting being 0.
-    $this->assertTrue($nids[0] == 1 && $nids[1] == 2, 'Node ids sequential.');
-
-    // Log out and run cron twice.
-    $this->drupalLogout();
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-
-    // There should be feeds_schedule_num (= 10) feeds updated now.
-    $schedule = array();
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_schedule} WHERE last_executed_time <> 0"));
-    $this->assertEqual($count, 10, '10 feeds refreshed on cron.');
-
-    // There should be 100 story nodes in the database.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'"));
-    $this->assertEqual($count, 100, 'There are 100 story nodes aggregated.');
-
-    // Hit twice cron again.
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-
-    // There should be feeds_schedule_num X 2 (= 20) feeds updated now.
-    $schedule = array();
-    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
-    while ($row = db_fetch_object($result)) {
-      $schedule[$row->feed_nid] = $row;
-    }
-    $this->assertEqual(count($schedule), 20, '20 feeds refreshed on cron.');
-
-    // There should be 200 story nodes in the database.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1"));
-    $this->assertEqual($count, 200, 'There are 200 story nodes aggregated.');
-
-    // There shouldn't be any items with scheduled = 1 now, if so, this would
-    // mean they are stuck.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_schedule} WHERE scheduled = 1"));
-    $this->assertEqual($count, 0, 'All items are unscheduled (schedule flag = 0).');
-
-    // Hit cron again twice.
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-
-    // The import_period setting of the feed configuration is 1800, there
-    // shouldn't be any change to the database now.
-    $equal = TRUE;
-    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
-    while ($row = db_fetch_object($result)) {
-      $equal = $equal && ($row->last_executed_time == $schedule[$row->feed_nid]->last_executed_time);
-    }
-    $this->assertTrue($equal, 'Schedule did not change.');
-
-    // Log back in and set refreshing to as often as possible.
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-    $edit = array(
-      'import_period' => 0,
-    );
-    $this->drupalPost('admin/build/feeds/edit/syndication/settings', $edit, 'Save');
-    $this->assertText('Refresh: as often as possible');
-
-    // Hit cron again, 4 times now.
-    for ($i = 0; $i < 4; $i++) {
-      $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-    }
-
-    // Refresh period is set to 'as often as possible'. All scheduled times
-    // should have changed now.
-    // There should not be more nodes than before.
-    $equal = FALSE;
-    $output = '';
-    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
-    while ($row = db_fetch_object($result)) {
-      $equal = $equal || ($row->last_executed_time == $schedule[$row->feed_nid]->last_executed_time);
-    }
-    $this->assertFalse($equal, 'Every feed schedule time changed.');
-
-    // There should be 200 story nodes in the database.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1"));
-    $this->assertEqual($count, 200, 'The total of 200 story nodes has not changed.');
-
-    // @todo Use debug time feature in FeedsScheduler and test behavior in future.
-    // @todo How do I call an API function on the test system from the test script?
-  }
-
-  /**
-   * Test batching on cron.
-   */
-  function testBatching() {
-    // Verify that there are 150 nodes total.
-    $nid = $this->createFeedNode('syndication', $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/many_items.rss2');
-    $this->assertText('Created 150 Story nodes.');
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 150 nodes.');
-
-    // Hit cron 3 times, assert correct number of story nodes.
-    for ($i = 0; $i < 3; $i++) {
-      $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-      // 50 == FEEDS_NODE_BATCH_SIZE
-      $this->assertEqual(50 * ($i + 1), db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
-    }
-
-    // Delete a couple of nodes, then hit cron again. They should not be replaced
-    // as the minimum update time is 30 minutes.
-    $result = db_query_range("SELECT nid FROM {node} WHERE type = 'story'", 0, 2);
-    while ($node = db_fetch_object($result)) {
-      $this->drupalPost("node/{$node->nid}/delete", array(), 'Delete');
-    }
-    $this->assertEqual(148, db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
-    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
-    $this->assertEqual(148, db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
-  }
-}
-
-/**
- * Test single feeds.
- */
-class FeedsSyndicationParserTestCase extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Syndication parsers'),
-      'description' => t('Regression tests for syndication parsers Common syndication and SimplePie. Tests parsers against a set of feeds in the context of Feeds module. <strong>Requires SimplePie parser to be configured correctly.</strong>'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'libraries');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->createImporterConfiguration('Syndication', 'syndication');
-
-    foreach (array('FeedsSyndicationParser', 'FeedsSimplePieParser') as $parser) {
-      $this->setPlugin('syndication', $parser);
-      foreach ($this->feedUrls() as $url => $assertions) {
-        $this->createFeedNode('syndication', $url);
-        $this->assertText('Created '. $assertions['item_count'] .' Story nodes.');
-      }
-    }
-  }
-
-  /**
-   * Return an array of test feeds.
-   */
-  protected function feedUrls() {
-    $path = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/';
-    return array(
-      "{$path}developmentseed.rss2" => array(
-        'item_count' => 10,
-      ),
-      "{$path}feed_without_guid.rss2" => array(
-        'item_count' => 10,
-      ),
-    );
-  }
-}
-
-/**
- * Test Sitemap parser.
- */
-class FeedsSitemapParserTestCase extends FeedsWebTestCase {
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Sitemap parser'),
-      'description' => t('Regression tests for Sitemap XML format parser.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->createImporterConfiguration('Sitemap', 'sitemap');
-    $this->setPlugin('sitemap', 'FeedsSitemapParser');
-
-    $this->addMappings('sitemap',
-      array(
-        array(
-          'source' => 'changefreq',
-          'target' => 'title',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'priority',
-          'target' => 'body',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'lastmod',
-          'target' => 'created',
-          'unique' => FALSE,
-        ),
-        array(
-          'source' => 'url',
-          'target' => 'url',
-          'unique' => TRUE,
-        ),
-         array(
-          'source' => 'url',
-          'target' => 'guid',
-          'unique' => TRUE,
-        ),
-      )
-    );
-
-
-    $path = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/';
-    $nid = $this->createFeedNode('sitemap', $path .'sitemap-example.xml', 'Testing Sitemap Parser');
-    $this->assertText('Created 5 Story nodes.');
-
-    // Assert DB status.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 5, 'Accurate number of items in database.');
-
-    // Check items against known content of feed.
-    $result = db_query('SELECT * FROM {feeds_node_item} WHERE feed_nid = %d ORDER BY nid', $nid);
-
-    // Check first item.
-    date_default_timezone_set('GMT');
-    $item = db_fetch_object($result);
-    $node = node_load($item->nid);
-    $this->assertEqual($node->title, 'monthly', 'Feed item 1 changefreq is correct.');
-    $this->assertEqual($node->body, '0.8', 'Feed item 1 priority is correct.');
-    $this->assertEqual($node->created, strtotime('2005-01-01'), 'Feed item 1 lastmod is correct.');
-    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/', 'Feed item 1 url is correct.');
-    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 1 guid is correct.');
-
-    // Check second item.
-    $item = db_fetch_object($result);
-    $node = node_load($item->nid);
-    $this->assertEqual($node->title, 'weekly', 'Feed item 2 changefreq is correct.');
-    $this->assertEqual($node->body, '', 'Feed item 2 priority is correct.');
-    // $node->created is... recently
-    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=12&desc=vacation_hawaii', 'Feed item 2 url is correct.');
-    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 2 guid is correct.');
-
-    // Check third item.
-    $item = db_fetch_object($result);
-    $node = node_load($item->nid);
-    $this->assertEqual($node->title, 'weekly', 'Feed item 3 changefreq is correct.');
-    $this->assertEqual($node->body, '', 'Feed item 3 priority is correct.');
-    $this->assertEqual($node->created, strtotime('2004-12-23'), 'Feed item 3 lastmod is correct.');
-    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=73&desc=vacation_new_zealand', 'Feed item 3 url is correct.');
-    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 3 guid is correct.');
-
-    // Check fourth item.
-    $item = db_fetch_object($result);
-    $node = node_load($item->nid);
-    $this->assertEqual($node->title, '', 'Feed item 4 changefreq is correct.');
-    $this->assertEqual($node->body, '0.3', 'Feed item 4 priority is correct.');
-    $this->assertEqual($node->created, strtotime('2004-12-23T18:00:15+00:00'), 'Feed item 4 lastmod is correct.');
-    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=74&desc=vacation_newfoundland', 'Feed item 4 url is correct.');
-    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 1 guid is correct.');
-
-    // Check fifth item.
-    $item = db_fetch_object($result);
-    $node = node_load($item->nid);
-    $this->assertEqual($node->title, '', 'Feed item 5 changefreq is correct.');
-    $this->assertEqual($node->body, '', 'Feed item 5 priority is correct.');
-    $this->assertEqual($node->created, strtotime('2004-11-23'), 'Feed item 5 lastmod is correct.');
-    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=83&desc=vacation_usa', 'Feed item 5 url is correct.');
-    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 5 guid is correct.');
-
-    // Check for more items.
-    $item = db_fetch_object($result);
-    $this->assertFalse($item, 'Correct number of feed items recorded.');
-  }
-}
diff --git a/tests/feeds_parser_sitemap.test b/tests/feeds_parser_sitemap.test
new file mode 100644
index 0000000000000000000000000000000000000000..349656400953a4f298fe140740caf622792870ae
--- /dev/null
+++ b/tests/feeds_parser_sitemap.test
@@ -0,0 +1,142 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for plugins/FeedsSitemapParser.inc
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test Sitemap parser.
+ */
+class FeedsSitemapParserTestCase extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Sitemap parser'),
+      'description' => t('Regression tests for Sitemap XML format parser.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+    $this->createImporterConfiguration('Sitemap', 'sitemap');
+    $this->setPlugin('sitemap', 'FeedsSitemapParser');
+
+    $this->addMappings('sitemap',
+      array(
+        array(
+          'source' => 'changefreq',
+          'target' => 'title',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'priority',
+          'target' => 'body',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'lastmod',
+          'target' => 'created',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'url',
+          'target' => 'url',
+          'unique' => TRUE,
+        ),
+         array(
+          'source' => 'url',
+          'target' => 'guid',
+          'unique' => TRUE,
+        ),
+      )
+    );
+
+
+    $path = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/';
+    $nid = $this->createFeedNode('sitemap', $path .'sitemap-example.xml', 'Testing Sitemap Parser');
+    $this->assertText('Created 5 Story nodes.');
+
+    // Assert DB status.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 5, 'Accurate number of items in database.');
+
+    // Check items against known content of feed.
+    $result = db_query('SELECT * FROM {feeds_node_item} WHERE feed_nid = %d ORDER BY nid', $nid);
+
+    // Check first item.
+    date_default_timezone_set('GMT');
+    $item = db_fetch_object($result);
+    $node = node_load($item->nid);
+    $this->assertEqual($node->title, 'monthly', 'Feed item 1 changefreq is correct.');
+    $this->assertEqual($node->body, '0.8', 'Feed item 1 priority is correct.');
+    $this->assertEqual($node->created, strtotime('2005-01-01'), 'Feed item 1 lastmod is correct.');
+    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/', 'Feed item 1 url is correct.');
+    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 1 guid is correct.');
+
+    // Check second item.
+    $item = db_fetch_object($result);
+    $node = node_load($item->nid);
+    $this->assertEqual($node->title, 'weekly', 'Feed item 2 changefreq is correct.');
+    $this->assertEqual($node->body, '', 'Feed item 2 priority is correct.');
+    // $node->created is... recently
+    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=12&desc=vacation_hawaii', 'Feed item 2 url is correct.');
+    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 2 guid is correct.');
+
+    // Check third item.
+    $item = db_fetch_object($result);
+    $node = node_load($item->nid);
+    $this->assertEqual($node->title, 'weekly', 'Feed item 3 changefreq is correct.');
+    $this->assertEqual($node->body, '', 'Feed item 3 priority is correct.');
+    $this->assertEqual($node->created, strtotime('2004-12-23'), 'Feed item 3 lastmod is correct.');
+    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=73&desc=vacation_new_zealand', 'Feed item 3 url is correct.');
+    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 3 guid is correct.');
+
+    // Check fourth item.
+    $item = db_fetch_object($result);
+    $node = node_load($item->nid);
+    $this->assertEqual($node->title, '', 'Feed item 4 changefreq is correct.');
+    $this->assertEqual($node->body, '0.3', 'Feed item 4 priority is correct.');
+    $this->assertEqual($node->created, strtotime('2004-12-23T18:00:15+00:00'), 'Feed item 4 lastmod is correct.');
+    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=74&desc=vacation_newfoundland', 'Feed item 4 url is correct.');
+    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 1 guid is correct.');
+
+    // Check fifth item.
+    $item = db_fetch_object($result);
+    $node = node_load($item->nid);
+    $this->assertEqual($node->title, '', 'Feed item 5 changefreq is correct.');
+    $this->assertEqual($node->body, '', 'Feed item 5 priority is correct.');
+    $this->assertEqual($node->created, strtotime('2004-11-23'), 'Feed item 5 lastmod is correct.');
+    $this->assertEqual($node->feeds_node_item->url, 'http://www.example.com/catalog?item=83&desc=vacation_usa', 'Feed item 5 url is correct.');
+    $this->assertEqual($node->feeds_node_item->url, $node->feeds_node_item->guid, 'Feed item 5 guid is correct.');
+
+    // Check for more items.
+    $item = db_fetch_object($result);
+    $this->assertFalse($item, 'Correct number of feed items recorded.');
+  }
+}
diff --git a/tests/feeds_parser_syndication.test b/tests/feeds_parser_syndication.test
new file mode 100644
index 0000000000000000000000000000000000000000..209d5e185d2754b1df354d6a080ae9ab2886dc1b
--- /dev/null
+++ b/tests/feeds_parser_syndication.test
@@ -0,0 +1,72 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for plugins/FeedsSyndicationParser.inc.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test single feeds.
+ */
+class FeedsSyndicationParserTestCase extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Syndication parsers'),
+      'description' => t('Regression tests for syndication parsers Common syndication and SimplePie. Tests parsers against a set of feeds in the context of Feeds module. <strong>Requires SimplePie parser to be configured correctly.</strong>'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'libraries');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+    $this->createImporterConfiguration('Syndication', 'syndication');
+
+    foreach (array('FeedsSyndicationParser', 'FeedsSimplePieParser') as $parser) {
+      $this->setPlugin('syndication', $parser);
+      foreach ($this->feedUrls() as $url => $assertions) {
+        $this->createFeedNode('syndication', $url);
+        $this->assertText('Created '. $assertions['item_count'] .' Story nodes.');
+      }
+    }
+  }
+
+  /**
+   * Return an array of test feeds.
+   */
+  protected function feedUrls() {
+    $path = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/';
+    return array(
+      "{$path}developmentseed.rss2" => array(
+        'item_count' => 10,
+      ),
+      "{$path}feed_without_guid.rss2" => array(
+        'item_count' => 10,
+      ),
+    );
+  }
+}
diff --git a/tests/feeds_processor_data.test b/tests/feeds_processor_data.test
new file mode 100644
index 0000000000000000000000000000000000000000..3aa6659e3889a06dbac1362d2844e693f1138dfc
--- /dev/null
+++ b/tests/feeds_processor_data.test
@@ -0,0 +1,169 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for plugins/FeedsDataProcessor.inc.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test aggregating a feed as data records.
+ */
+class FeedsRSStoDataTest extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('RSS import to data records'),
+      'description' => t('Tests a feed configuration that is attached to a content type, uses common syndication parser and a node processor. <strong>Requires Data module and Views module</strong>.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'data', 'data_ui', 'views');
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'create page content',
+        )
+      )
+    );
+  }
+
+  /**
+   * Test node creation, refreshing/deleting feeds and feed items.
+   */
+  public function test() {
+
+    // Create an importer.
+    $this->createImporterConfiguration('Data feed', 'rss');
+
+    // Go to edit page and select the data processor.
+    $edit = array(
+      'plugin_key' => 'FeedsDataProcessor',
+    );
+    $this->drupalPost('admin/build/feeds/edit/rss/processor', $edit, 'Save');
+    $this->assertPlugins('rss', 'FeedsHTTPFetcher', 'FeedsSyndicationParser', 'FeedsDataProcessor');
+
+    // Go to mapping page and create a couple of mappings.
+    $mappings = array(
+      array(
+        'source' => 'guid',
+        'target' => 'new:text',
+        'unique' => TRUE,
+      ),
+      array(
+        'source' => 'url',
+        'target' => 'new:text',
+        'unique' => TRUE,
+      ),
+      array(
+        'source' => 'timestamp',
+        'target' => 'timestamp', // timestamp is an existing target.
+        'unique' => FALSE,
+      ),
+      array(
+        'source' => 'title',
+        'target' => 'new:varchar',
+        'unique' => FALSE,
+      ),
+      array(
+        'source' => 'description',
+        'target' => 'new:text',
+        'unique' => FALSE,
+      ),
+    );
+    $this->addMappings('rss', $mappings);
+
+    // Verify the mapping configuration.
+    $config = unserialize(db_result(db_query("SELECT config FROM {feeds_importer} WHERE id = 'rss'")));
+    $stored_mappings = $config['processor']['config']['mappings'];
+    foreach ($mappings as $i => $mapping) {
+      $this->assertEqual($mapping['source'], $stored_mappings[$i]['source']);
+      // This is intentional: the target of the stored mapping should have the
+      // same key as the source, this has to do with the fact that feeds data
+      // creates storage as the mapping is created.
+      $this->assertEqual($mapping['source'], $stored_mappings[$i]['target']);
+      $this->assertEqual($mapping['unique'], $stored_mappings[$i]['unique']);
+    }
+
+    // Create standard feed node.
+    $nid = $this->createFeedNode('rss');
+    // Assert 10 items aggregated after creation of the node.
+    $this->assertText('Created 10 items.');
+
+    // Login with a user with administer data permissions and review aggregated
+    // content.
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer data tables',
+          'administer feeds',
+        )
+      )
+    );
+
+    // Assert accuracy of aggregated information.
+    $this->drupalGet('admin/content/data/view/feeds_data_rss');
+    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
+    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
+    $this->assertText('Week in DC Tech: October 5th Edition');
+    $this->assertText('There are some great technology events happening this week');
+    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
+    $this->assertText('is being used as a base platform for collaboration at the World Bank because of its feature flexibility');
+    $this->assertText('September GeoDC Meetup Tonight');
+    $this->assertText('Today is the last Wednesday of the month');
+    $this->assertText('Week in DC Tech: September 28th Edition');
+    $this->assertText('Looking to geek out this week? There are a bunch of');
+    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
+    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
+    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
+    $this->assertText('In addition to authentication, the Siteminder system');
+    $this->assertText('Week in DC Tech: September 21 Edition');
+    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
+    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
+    $this->assertText('Presenting on Features in Drupal and Open Atrium');
+    $this->assertText('Scaling the Open Atrium UI');
+    $this->assertText('The first major change is switching');
+
+    // Assert DB status.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Import again.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('There are no new items.');
+
+    // Assert DB status, there still shouldn't be more than 10 items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Now delete all items.
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('All items have been deleted.');
+
+    // Assert DB status, now there should be no items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
+    $this->assertEqual($count, 0, 'Accurate number of items in database.');
+
+    // Import again, we should find new content.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('Created 10 items.');
+
+    // Assert DB status, there should be 10 again.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_rss}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // @todo Standalone import form testing.
+    // @todo Create a second feed and test.
+  }
+}
diff --git a/tests/feeds_processor_node.test b/tests/feeds_processor_node.test
new file mode 100644
index 0000000000000000000000000000000000000000..c350ed77d48aa34626a596a83d70425c821dcafa
--- /dev/null
+++ b/tests/feeds_processor_node.test
@@ -0,0 +1,407 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for plugins/FeedsNodeProcessor.inc.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test aggregating a feed as node items.
+ */
+class FeedsRSStoNodesTest extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('RSS import to nodes'),
+      'description' => t('Tests a feed configuration that is attached to a content type, uses HTTP fetcher, common syndication parser and a node processor. Repeats the same test for an importer configuration that is not attached to a content type and for a configuration that is attached to a content type and uses the file fetcher.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools');
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes', 'administer content types',
+        )
+      )
+    );
+  }
+
+  /**
+   * Test node creation, refreshing/deleting feeds and feed items.
+   */
+  public function test() {
+    // Set the teaser length to unlimited otherwise tests looking for text on
+    // nodes will fail.
+    $edit = array(
+      'teaser_length' => 0,
+    );
+    $this->drupalPost('admin/content/node-settings', $edit, 'Save configuration');
+
+    // Create an importer configuration.
+    $this->createImporterConfiguration('Syndication', 'syndication');
+    $this->addMappings('syndication',
+      array(
+        array(
+          'source' => 'title',
+          'target' => 'title',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'description',
+          'target' => 'body',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'timestamp',
+          'target' => 'created',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'url',
+          'target' => 'url',
+          'unique' => TRUE,
+        ),
+        array(
+          'source' => 'guid',
+          'target' => 'guid',
+          'unique' => TRUE,
+        ),
+      )
+    );
+
+    $nid = $this->createFeedNode();
+    // Assert 10 items aggregated after creation of the node.
+    $this->assertText('Created 10 Story nodes.');
+
+    // Navigate to feed node, there should be Feeds tabs visible.
+    $this->drupalGet('node/'. $nid);
+    $this->assertRaw('node/'. $nid .'/import');
+    $this->assertRaw('node/'. $nid .'/delete-items');
+
+    // Navigate to a non-feed node, there should be no Feeds tabs visible.
+    $story_nid = db_result(db_query_range('SELECT nid FROM {node} WHERE type = "story"', 0, 1));
+    $this->drupalGet('node/'. $story_nid);
+    $this->assertNoRaw('node/'. $story_nid .'/import');
+    $this->assertNoRaw('node/'. $story_nid .'/delete-items');
+    $this->assertEqual("Created/updated by FeedsNodeProcessor", db_result(db_query("SELECT nr.log FROM {node} n JOIN {node_revisions} nr ON n.vid = nr.vid WHERE n.nid = %d", $story_nid)));
+
+    // Assert accuracy of aggregated information.
+    $this->drupalGet('node');
+    $this->assertPattern('/<span class="submitted">(.*?)Anonymous<\/span>/');
+    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
+    $this->assertText('Tue, 10/06/2009');
+    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
+    $this->assertText('Week in DC Tech: October 5th Edition');
+    $this->assertText('Mon, 10/05/2009');
+    $this->assertText('There are some great technology events happening this week');
+    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
+    $this->assertText('Fri, 10/02/2009');
+    $this->assertText('Open Atrium is being used as a base platform for collaboration');
+    $this->assertText('September GeoDC Meetup Tonight');
+    $this->assertText('Wed, 09/30/2009');
+    $this->assertText('Today is the last Wednesday of the month');
+    $this->assertText('Week in DC Tech: September 28th Edition');
+    $this->assertText('Mon, 09/28/2009');
+    $this->assertText('Looking to geek out this week? There are a bunch of');
+    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
+    $this->assertText('Thu, 09/24/2009');
+    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
+    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
+    $this->assertText('Tue, 09/22/2009');
+    $this->assertText('In addition to authentication, the Siteminder system');
+    $this->assertText('Week in DC Tech: September 21 Edition');
+    $this->assertText('Mon, 09/21/2009');
+    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
+    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
+    $this->assertText('Mon, 09/21/2009');
+    $this->assertText('Presenting on Features in Drupal and Open Atrium');
+    $this->assertText('Scaling the Open Atrium UI');
+    $this->assertText('Fri, 09/18/2009');
+    $this->assertText('The first major change is switching');
+
+    // Assert DB status.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Assert default input format on first imported feed node.
+    $format = db_result(db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revisions} nr ON n.vid = nr.vid", 0, 1));
+    $this->assertEqual($format, FILTER_FORMAT_DEFAULT, 'Using default Input format.');
+
+    // Import again.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('There is no new content.');
+
+    // Assert DB status, there still shouldn't be more than 10 items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // All of the above tests should have produced published nodes, set default
+    // to unpublished, import again.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid WHERE n.status = 1"));
+    $this->assertEqual($count, 10, 'All items are published.');
+    $edit = array(
+      'node_options[status]' => FALSE,
+    );
+    $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {feeds_node_item} fn ON n.nid = fn.nid WHERE n.status = 0"));
+    $this->assertEqual($count, 10, 'No items are published.');
+    $edit = array(
+      'node_options[status]' => TRUE,
+    );
+    $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+
+    // Enable replace existing and import updated feed file.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 1));
+    $feed_url = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/developmentseed_changes.rss2';
+    $this->editFeedNode($nid, $feed_url);
+    $this->drupalPost('node/' . $nid . '/import', array(), 'Import');
+    $this->assertText('Updated 2 Story nodes.');
+
+    // Assert accuracy of aggregated content (check 2 updates, one original).
+    $this->drupalGet('node');
+    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
+    $this->assertText('Presenting on Features in Drupal and Managing News');
+    $this->assertText('Scaling the Open Atrium UI');
+
+    // Import again.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('There is no new content.');
+
+    // Assert DB status, there still shouldn't be more than 10 items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Now delete all items.
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 10 nodes.');
+
+    // Assert DB status, now there should be no items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 0, 'Accurate number of items in database.');
+
+    // Change author.
+    $author = $this->drupalCreateUser();
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('author' => $author->name));
+
+    // Change input format.
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('input_format' => FILTER_FORMAT_DEFAULT + 1));
+
+    // Import again.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('Created 10 Story nodes.');
+
+    // Assert author.
+    $this->drupalGet('node');
+    $this->assertPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid WHERE n.uid = %d", $author->uid));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Assert input format.
+    $format = db_result(db_query_range("SELECT nr.format FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid JOIN {node_revisions} nr ON n.vid = nr.vid", 0, 1));
+    $this->assertEqual($format, FILTER_FORMAT_DEFAULT + 1, 'Set non-default Input format.');
+
+    // Set to update existing, remove authorship of above nodes and import again.
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('update_existing' => 2));
+    db_query("UPDATE {node} n JOIN {feeds_node_item} fi ON n.nid = fi.nid SET n.uid = 0, fi.hash=''");
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->drupalGet('node');
+    $this->assertNoPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} fi JOIN {node} n ON fi.nid = n.nid WHERE n.uid = %d", $author->uid));
+    $this->assertEqual($count, 0, 'Accurate number of items in database.');
+
+    // Map feed node's author to feed item author, update - feed node's items
+    // should now be assigned to feed node author.
+    $this->addMappings('syndication',
+      array(
+        array(
+          'source' => 'parent:uid',
+          'target' => 'uid',
+        ),
+      )
+    );
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->drupalGet('node');
+    $this->assertNoPattern('/<span class="submitted">(.*?)'. check_plain($author->name) .'<\/span>/');
+    $uid = db_result(db_query("SELECT uid FROM {node} WHERE nid = %d", $nid));
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE uid = %d", $uid));
+    $this->assertEqual($count, 11, 'All feed item nodes are assigned to feed node author.');
+
+    // Login with new user with only access content permissions.
+    $this->drupalLogin(
+      $this->drupalCreateUser()
+    );
+    // Navigate to feed node, there should be no Feeds tabs visible.
+    $this->drupalGet('node/'. $nid);
+    $this->assertNoRaw('node/'. $nid .'/import');
+    $this->assertNoRaw('node/'. $nid .'/delete-items');
+
+    // Now create a second feed configuration that is not attached to a content
+    // type and run tests on importing/purging.
+
+    // Login with sufficient permissions.
+    $this->drupalLogin(
+      $this->drupalCreateUser(array('administer feeds', 'administer nodes'))
+    );
+    // Remove all items again so that next test can check for them.
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+
+    // Create an importer, not attached to content type.
+    $this->createImporterConfiguration('Syndication standalone', 'syndication_standalone');
+    $edit = array(
+      'content_type' => '',
+    );
+    $this->drupalPost('admin/build/feeds/edit/syndication_standalone/settings', $edit, 'Save');
+    $this->addMappings('syndication_standalone',
+      array(
+        array(
+          'source' => 'title',
+          'target' => 'title',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'description',
+          'target' => 'body',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'timestamp',
+          'target' => 'created',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'url',
+          'target' => 'url',
+          'unique' => TRUE,
+        ),
+        array(
+          'source' => 'guid',
+          'target' => 'guid',
+          'unique' => TRUE,
+        ),
+      )
+    );
+
+    // Import, assert 10 items aggregated after creation of the node.
+    $this->importURL('syndication_standalone');
+    $this->assertText('Created 10 Story nodes.');
+
+    // Assert accuracy of aggregated information.
+    $this->drupalGet('node');
+    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
+    $this->assertText('Tue, 10/06/2009');
+    $this->assertText('A new translation process for Open Atrium &amp; integration with Localize Drupal');
+    $this->assertText('Week in DC Tech: October 5th Edition');
+    $this->assertText('Mon, 10/05/2009');
+    $this->assertText('There are some great technology events happening this week');
+    $this->assertText('Mapping Innovation at the World Bank with Open Atrium');
+    $this->assertText('Fri, 10/02/2009');
+    $this->assertText('Open Atrium is being used as a base platform for collaboration');
+    $this->assertText('September GeoDC Meetup Tonight');
+    $this->assertText('Wed, 09/30/2009');
+    $this->assertText('Today is the last Wednesday of the month');
+    $this->assertText('Week in DC Tech: September 28th Edition');
+    $this->assertText('Mon, 09/28/2009');
+    $this->assertText('Looking to geek out this week? There are a bunch of');
+    $this->assertText('Open Data for Microfinance: The New MIXMarket.org');
+    $this->assertText('Thu, 09/24/2009');
+    $this->assertText('There are profiles for every country that the MIX Market is hosting.');
+    $this->assertText('Integrating the Siteminder Access System in an Open Atrium-based Intranet');
+    $this->assertText('Tue, 09/22/2009');
+    $this->assertText('In addition to authentication, the Siteminder system');
+    $this->assertText('Week in DC Tech: September 21 Edition');
+    $this->assertText('Mon, 09/21/2009');
+    $this->assertText('an interesting variety of technology events happening in Washington, DC ');
+    $this->assertText('s Software Freedom Day: Impressions &amp; Photos');
+    $this->assertText('Mon, 09/21/2009');
+    $this->assertText('Presenting on Features in Drupal and Open Atrium');
+    $this->assertText('Scaling the Open Atrium UI');
+    $this->assertText('Fri, 09/18/2009');
+    $this->assertText('The first major change is switching');
+
+    // Assert DB status.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Import again.
+    $this->drupalPost('import/syndication_standalone', array(), 'Import');
+    $this->assertText('There is no new content.');
+
+    // Assert DB status, there still shouldn't be more than 10 items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Enable replace existing and import updated feed file.
+    $this->setSettings('syndication_standalone', 'FeedsNodeProcessor', array('update_existing' => 1));
+    $feed_url = $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed_changes.rss2';
+    $this->importURL('syndication_standalone', $feed_url);
+    $this->assertText('Updated 2 Story nodes.');
+
+    // Assert accuracy of aggregated information (check 2 updates, one orig).
+    $this->drupalGet('node');
+    $this->assertText('Managing News Translation Workflow: Two Way Translation Updates');
+    $this->assertText('Presenting on Features in Drupal and Managing News');
+    $this->assertText('Scaling the Open Atrium UI');
+
+    // Import again.
+    $this->drupalPost('import/syndication_standalone', array(), 'Import');
+    $this->assertText('There is no new content.');
+
+    // Assert DB status, there still shouldn't be more than 10 items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Now delete all items.
+    $this->drupalPost('import/syndication_standalone/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 10 nodes.');
+
+    // Assert DB status, now there should be no items.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 0, 'Accurate number of items in database.');
+
+    // Import again, we should find new content.
+    $this->drupalPost('import/syndication_standalone', array(), 'Import');
+    $this->assertText('Created 10 Story nodes.');
+
+    // Assert DB status, there should be 10 again.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Accurate number of items in database.');
+
+    // Login with new user with only access content permissions.
+    $this->drupalLogin(
+      $this->drupalCreateUser()
+    );
+    // Navigate to feed import form, access should be denied.
+    $this->drupalGet('import/syndication_standalone');
+    $this->assertResponse(403);
+
+    // Use File Fetcher.
+    $this->drupalLogin(
+      $this->drupalCreateUser(array('administer feeds', 'administer nodes'))
+    );
+    $this->setPlugin('syndication', 'FeedsFileFetcher');
+    // Create a feed node.
+    $edit = array(
+      'files[feeds]' => $this->absolutePath() .'/tests/feeds/drupalplanet.rss2',
+    );
+    $this->drupalPost('node/add/page', $edit, 'Save');
+    $this->assertText('has been created.');
+    $this->assertText('Created 25 Story nodes.');
+  }
+}
diff --git a/tests/feeds_processor_user.test b/tests/feeds_processor_user.test
new file mode 100644
index 0000000000000000000000000000000000000000..ab9d005f3aaa73560466f7bf1f4adec21120098a
--- /dev/null
+++ b/tests/feeds_processor_user.test
@@ -0,0 +1,111 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for plugins/FeedsUserProcessor.inc
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test aggregating a feed as data records.
+ */
+class FeedsCSVtoUsersTest extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('CSV import to users'),
+      'description' => t('Tests a standalone import configuration that uses file fetcher and CSV parser to import users from a CSV file.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer users',
+        )
+      )
+    );
+  }
+
+  /**
+   * Test node creation, refreshing/deleting feeds and feed items.
+   */
+  public function test() {
+
+    // Create an importer.
+    $this->createImporterConfiguration('User import', 'user_import');
+
+    // Set and configure plugins.
+    $this->setPlugin('user_import', 'FeedsFileFetcher');
+    $this->setPlugin('user_import', 'FeedsCSVParser');
+    $this->setPlugin('user_import', 'FeedsUserProcessor');
+
+    // Go to mapping page and create a couple of mappings.
+    $mappings = array(
+      '0' => array(
+        'source' => 'name',
+        'target' => 'name',
+        'unique' => 0,
+      ),
+      '1' => array(
+        'source' => 'mail',
+        'target' => 'mail',
+        'unique' => 1,
+      ),
+      '2' => array(
+        'source' => 'since',
+        'target' => 'created',
+        'unique' => FALSE,
+      ),
+    );
+    $this->addMappings('user_import', $mappings);
+
+    // Use standalone form.
+    $edit = array(
+      'content_type' => '',
+    );
+    $this->drupalPost('admin/build/feeds/edit/user_import/settings', $edit, 'Save');
+
+    // Create roles and assign one of them to the users to be imported.
+    $manager_rid = $this->drupalCreateRole(array('access content'), 'manager');
+    $admin_rid = $this->drupalCreateRole(array('access content'), 'administrator');
+    $edit = array(
+      "roles[$manager_rid]" => TRUE,
+      "roles[$admin_rid]" => FALSE,
+    );
+    $this->setSettings('user_import', 'FeedsUserProcessor', $edit);
+
+    // Import CSV file.
+    $this->importFile('user_import', $this->absolutePath() .'/tests/feeds/users.csv');
+
+    // Assert result.
+    $this->assertText('Created 4 users.');
+    // 1 user has an invalid email address, all users should be assigned
+    // the manager role.
+    $this->assertText('There was 1 user that could not be imported because either their name or their email was empty or not valid. Check import data and mapping settings on User processor.');
+    $this->drupalGet('admin/user/user');
+    $this->assertText('Morticia');
+    $this->assertText('Fester');
+    $this->assertText('Gomez');
+    $this->assertText('Pugsley');
+    $count = db_result(db_query("SELECT count(*) FROM {users_roles} WHERE rid = %d", $manager_rid));
+    $this->assertEqual($count, 4, t('All imported users were assigned the manager role.'));
+    $count = db_result(db_query("SELECT count(*) FROM {users_roles} WHERE rid = %d", $admin_rid));
+    $this->assertEqual($count, 0, t('No imported user was assigned the administrator role.'));
+
+    // @todo Test status setting, update existing and role settings.
+  }
+}
diff --git a/tests/feeds_scheduler.test b/tests/feeds_scheduler.test
new file mode 100644
index 0000000000000000000000000000000000000000..a9426fcee8fd2164adf9f36a2d6e03ce1d7c3e27
--- /dev/null
+++ b/tests/feeds_scheduler.test
@@ -0,0 +1,200 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Feeds tests.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/feeds.test.inc');
+
+/**
+ * Test cron scheduling.
+ */
+class FeedsSchedulerTestCase extends FeedsWebTestCase {
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Scheduler'),
+      'description' => t('Tests for feeds scheduler.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools');
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+    $this->createImporterConfiguration();
+    $this->addMappings('syndication',
+      array(
+        array(
+          'source' => 'title',
+          'target' => 'title',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'description',
+          'target' => 'body',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'timestamp',
+          'target' => 'created',
+          'unique' => FALSE,
+        ),
+        array(
+          'source' => 'url',
+          'target' => 'url',
+          'unique' => TRUE,
+        ),
+        array(
+          'source' => 'guid',
+          'target' => 'guid',
+          'unique' => TRUE,
+        ),
+      )
+    );
+  }
+
+  /**
+   * Test scheduling on cron.
+   */
+  public function testScheduling() {
+    // Create 10 feed nodes. Turn off import on create before doing that.
+    $edit = array(
+      'import_on_create' => FALSE,
+    );
+    $this->drupalPost('admin/build/feeds/edit/syndication/settings', $edit, 'Save');
+    $this->assertText('Do not import on create');
+
+    $nids = $this->createFeedNodes();
+    // This implicitly tests the import_on_create node setting being 0.
+    $this->assertTrue($nids[0] == 1 && $nids[1] == 2, 'Node ids sequential.');
+
+    // Log out and run cron twice.
+    $this->drupalLogout();
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+
+    // There should be feeds_schedule_num (= 10) feeds updated now.
+    $schedule = array();
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_schedule} WHERE last_executed_time <> 0"));
+    $this->assertEqual($count, 10, '10 feeds refreshed on cron.');
+
+    // There should be 100 story nodes in the database.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'"));
+    $this->assertEqual($count, 100, 'There are 100 story nodes aggregated.');
+
+    // Hit twice cron again.
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+
+    // There should be feeds_schedule_num X 2 (= 20) feeds updated now.
+    $schedule = array();
+    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
+    while ($row = db_fetch_object($result)) {
+      $schedule[$row->feed_nid] = $row;
+    }
+    $this->assertEqual(count($schedule), 20, '20 feeds refreshed on cron.');
+
+    // There should be 200 story nodes in the database.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1"));
+    $this->assertEqual($count, 200, 'There are 200 story nodes aggregated.');
+
+    // There shouldn't be any items with scheduled = 1 now, if so, this would
+    // mean they are stuck.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_schedule} WHERE scheduled = 1"));
+    $this->assertEqual($count, 0, 'All items are unscheduled (schedule flag = 0).');
+
+    // Hit cron again twice.
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+
+    // The import_period setting of the feed configuration is 1800, there
+    // shouldn't be any change to the database now.
+    $equal = TRUE;
+    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
+    while ($row = db_fetch_object($result)) {
+      $equal = $equal && ($row->last_executed_time == $schedule[$row->feed_nid]->last_executed_time);
+    }
+    $this->assertTrue($equal, 'Schedule did not change.');
+
+    // Log back in and set refreshing to as often as possible.
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+    $edit = array(
+      'import_period' => 0,
+    );
+    $this->drupalPost('admin/build/feeds/edit/syndication/settings', $edit, 'Save');
+    $this->assertText('Refresh: as often as possible');
+
+    // Hit cron again, 4 times now.
+    for ($i = 0; $i < 4; $i++) {
+      $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+    }
+
+    // Refresh period is set to 'as often as possible'. All scheduled times
+    // should have changed now.
+    // There should not be more nodes than before.
+    $equal = FALSE;
+    $output = '';
+    $result = db_query("SELECT feed_nid, last_executed_time, scheduled FROM {feeds_schedule} WHERE last_executed_time <> 0");
+    while ($row = db_fetch_object($result)) {
+      $equal = $equal || ($row->last_executed_time == $schedule[$row->feed_nid]->last_executed_time);
+    }
+    $this->assertFalse($equal, 'Every feed schedule time changed.');
+
+    // There should be 200 story nodes in the database.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1"));
+    $this->assertEqual($count, 200, 'The total of 200 story nodes has not changed.');
+
+    // @todo Use debug time feature in FeedsScheduler and test behavior in future.
+    // @todo How do I call an API function on the test system from the test script?
+  }
+
+  /**
+   * Test batching on cron.
+   */
+  function testBatching() {
+    // Verify that there are 150 nodes total.
+    $nid = $this->createFeedNode('syndication', $GLOBALS['base_url'] .'/'. drupal_get_path('module', 'feeds') .'/tests/feeds/many_items.rss2');
+    $this->assertText('Created 150 Story nodes.');
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 150 nodes.');
+
+    // Hit cron 3 times, assert correct number of story nodes.
+    for ($i = 0; $i < 3; $i++) {
+      $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+      // 50 == FEEDS_NODE_BATCH_SIZE
+      $this->assertEqual(50 * ($i + 1), db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
+    }
+
+    // Delete a couple of nodes, then hit cron again. They should not be replaced
+    // as the minimum update time is 30 minutes.
+    $result = db_query_range("SELECT nid FROM {node} WHERE type = 'story'", 0, 2);
+    while ($node = db_fetch_object($result)) {
+      $this->drupalPost("node/{$node->nid}/delete", array(), 'Delete');
+    }
+    $this->assertEqual(148, db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
+    $this->drupalGet($GLOBALS['base_url'] .'/cron.php');
+    $this->assertEqual(148, db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story'")));
+  }
+}
diff --git a/tests/feeds_parser_csv.test b/tests/parser_csv.test
similarity index 97%
rename from tests/feeds_parser_csv.test
rename to tests/parser_csv.test
index acbd856c40c6157e0828781110252122b37c8427..2aeff646765602b6abd93b84ca98604d8e1c9740 100644
--- a/tests/feeds_parser_csv.test
+++ b/tests/parser_csv.test
@@ -13,7 +13,7 @@
  * Not inheriting from Feeds base class as ParserCSV should be moved out of
  * Feeds at some time.
  */
-class FeedsParserCSVTest extends DrupalWebTestCase  {
+class ParserCSVTest extends DrupalWebTestCase  {
   /**
    * Describe this test.
    */