t('RSS import to nodes'), 'description' => t('Tests a feed configuration that is attached to a content type, uses common syndication parser and a node processor. Repeats the same test for a feed configuration that is not attached to a content type.'), 'group' => t('Feeds'), ); } /** * Set up test. */ public function setUp() { // @todo: once we have default configurations shipping with feeds, we do not // need feeds_ui. parent::setUp('feeds', 'feeds_ui', 'ctools'); $this->drupalLogin( $this->drupalCreateUser( array( 'administer feeds', 'administer nodes', ) ) ); } /** * Test node creation, refreshing/deleting feeds and feed items. */ public function test() { // Create a feed. $this->createFeedConfiguration(); $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'); // 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 and 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 and 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('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.'); // Import again, we should find new content. $this->drupalPost('node/'. $nid .'/import', 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 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 a feed, not attached to content type. $this->createFeedConfiguration('Syndication standalone', 'syndication_standalone'); $edit = array( 'content_type' => '', ); $this->drupalPost('admin/build/feeds/edit/syndication_standalone/settings', $edit, 'Save'); // 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 and 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 and 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.'); // 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); } } /** * 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. Requires Data module and Views module.'), 'group' => t('Feeds'), ); } /** * Set up test. */ public function setUp() { // @todo: once we have default configurations shipping with feeds, we do not // need feeds_ui. 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 a feed. $this->createFeedConfiguration('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 and 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 and 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('Deleted 10 items.'); // Assert DB status, now there should be no items. // @todo: fails, is there something cached? $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 a feed. $this->createFeedConfiguration('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); // Change some of the basic configuration. $edit = array( 'content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER, ); $this->drupalPost('admin/build/feeds/edit/user_import/settings', $edit, 'Save'); // 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. $this->assertText('There were 1 users 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'); // @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', ) ) ); } /** * Test scheduling on cron. */ public function testScheduling() { // Create default configuration, turn off refresh on creation. $this->createFeedConfiguration(); // 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_scheduled_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_scheduled_time, scheduled from {feeds_schedule} WHERE last_scheduled_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_scheduled_time, scheduled from {feeds_schedule} WHERE last_scheduled_time <> 0'); while ($row = db_fetch_object($result)) { $equal = $equal && ($row->last_scheduled_time == $schedule[$row->feed_nid]->last_scheduled_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. $this->drupalGet($GLOBALS['base_url'] .'/cron.php'); $this->drupalGet($GLOBALS['base_url'] .'/cron.php'); $this->drupalGet($GLOBALS['base_url'] .'/cron.php'); $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_scheduled_time, scheduled from {feeds_schedule} WHERE last_scheduled_time <> 0'); while ($row = db_fetch_object($result)) { $equal = $equal || ($row->last_scheduled_time == $schedule[$row->feed_nid]->last_scheduled_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 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. Requires Simplepie parser to be configured correctly.'), '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->createFeedConfiguration('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, ), ); } }