simplenews_scheduler.test 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. <?php
  2. /**
  3. * @file
  4. * Tests for Simplenews Scheduler.
  5. */
  6. /**
  7. * Class with common setup.
  8. *
  9. * Declares the module dependencies for the test.
  10. *
  11. * We need to use DrupalWebTestCase as our base class even for functional
  12. * testing, as the functions that we test rely on variable_get() which requires
  13. * a bootstrapped database.
  14. */
  15. class SimpleNewsSchedulerWebTestCase extends DrupalWebTestCase {
  16. /**
  17. * Overrides DrupalWebTestCase::setUp().
  18. *
  19. * @param $modules
  20. * Additional modules to enable for the test. simplenews_scheduler and
  21. * the dependencies are always enabled.
  22. */
  23. function setUp($modules = array()) {
  24. // Add our dependencies to the module list.
  25. $modules = array_merge(array('simplenews_scheduler'), $modules);
  26. parent::setUp($modules);
  27. // Set the site timezone to something visibly different from UTC, which
  28. // has daylight saving changes.
  29. variable_set('date_default_timezone', 'Europe/Kiev');
  30. date_default_timezone_set(drupal_get_user_timezone());
  31. }
  32. }
  33. /**
  34. * Test scheduled edition creation.
  35. */
  36. class SimpleNewsSchedulerNodeCreationTest extends SimpleNewsSchedulerWebTestCase {
  37. protected $privileged_user;
  38. /**
  39. * Provides information about this test.
  40. */
  41. public static function getInfo() {
  42. return array(
  43. 'name' => 'Newsletter generation test',
  44. 'description' => 'Testing generation of newsletters',
  45. 'group' => 'Simplenews Scheduler',
  46. );
  47. }
  48. /**
  49. * Declares the module dependencies for the test.
  50. */
  51. function setUp() {
  52. parent::setUp();
  53. $this->privileged_user = $this->drupalCreateUser(array(
  54. 'access content',
  55. 'administer nodes',
  56. 'create simplenews content',
  57. 'edit own simplenews content',
  58. 'send newsletter',
  59. 'send scheduled newsletters',
  60. 'overview scheduled newsletters',
  61. ));
  62. $this->drupalLogin($this->privileged_user);
  63. // Subscribe a user to simplenews.
  64. $categories = simplenews_categories_load_multiple();
  65. $this->mail = 'test@example.org';
  66. simplenews_subscribe_user($this->mail, key($categories), FALSE, 'test');
  67. }
  68. /**
  69. * Basic simplenews newsletter generation test
  70. * create a simplenews node,
  71. */
  72. function testNewsletterGeneration() {
  73. $edit = array();
  74. $title ="newsletter " . $this->randomName(8);
  75. $edit = array();
  76. $edit['title'] = $title;
  77. $edit["body[und][0][value]"] = $this->randomName(16);
  78. $this->drupalPost('node/add/simplenews', $edit, t('Save'));
  79. $this->assertText($title);
  80. preg_match('|node/(\d+)$|', $this->getUrl(), $matches);
  81. $node = node_load($matches[1]);
  82. // Make sure that the editions tab is not visible as long as it's not a
  83. // scheduled newsletter.
  84. $this->drupalGet("node/{$node->nid}/editions");
  85. $this->assertResponse(403, t('Editions tab not accessible'));
  86. // Now create the simplenews schedule configuration.
  87. $this->drupalGet("node/{$node->nid}/simplenews");
  88. $this->assertText(t("Send newsletter according to schedule"));
  89. $edit = array();
  90. $edit["simplenews[send]"] = '4';
  91. $edit["simplenews[scheduler][interval]"] = "hour";
  92. // Specify a start time 30 minutes in the past to be able to have a known
  93. // edition creation time that can be checked.
  94. $date = new DateTime();
  95. $date->sub(new DateInterval('PT30M'));
  96. $edit["simplenews[scheduler][start_date][year]"] = $date->format('Y');
  97. $edit["simplenews[scheduler][start_date][month]"] = $date->format('n');
  98. $edit["simplenews[scheduler][start_date][day]"] = $date->format('j');
  99. $edit["simplenews[scheduler][start_date][hour]"] = $date->format('G');
  100. $edit["simplenews[scheduler][start_date][minute]"] = $date->format('i');
  101. $edit["simplenews[scheduler][title]"] = "Custom title [site:name]";
  102. $this->drupalPost("node/{$node->nid}/simplenews", $edit, t('Submit'));
  103. // Make sure it knows no editions created yet.
  104. $this->drupalGet("node/{$node->nid}/editions");
  105. $this->assertText(t("No scheduled newsletter editions have been sent."));
  106. // Execute cron.
  107. drupal_cron_run();
  108. // See if it was created.
  109. $this->drupalGet("node/{$node->nid}/editions");
  110. $this->assertText("Custom title");
  111. $this->assertNoText(t("No scheduled newsletter editions have been sent."));
  112. $this->assertText($title); // original real node title
  113. // Go to node and verify creation time and token for custom title
  114. // @todo: make this real token integration
  115. $this->clickLink("Custom title ". variable_get('site_name', 'Drupal'));
  116. $this->assertText(t('This is a newsletter edititon. View the the master template of this newsletter here'));
  117. $this->assertText(t('Submitted by @name on @date', array('@name' => format_username($this->privileged_user), '@date' => format_date($date->getTimestamp()))));
  118. // Check sent mails.
  119. $mails = $this->drupalGetMails();
  120. $this->assertEqual(1, count($mails), t('Newsletter mail has been sent.'));
  121. $this->clickLink(t('Newsletter'));
  122. $this->assertText(t('This node is part of a scheduled newsletter configuration.'));
  123. $this->clickLink(t('here'));
  124. $this->assertEqual(url('node/' . $node->nid, array('absolute' => TRUE)), $this->getUrl());
  125. // Test the tab on a sent newsletter, schedule details should not be shown.
  126. $title ="newsletter " . $this->randomName(8);
  127. $edit = array();
  128. $edit['title'] = $title;
  129. $edit["body[und][0][value]"] = $this->randomName(16);
  130. $this->drupalPost('node/add/simplenews', $edit, t('Save'));
  131. $this->assertText($title);
  132. preg_match('|node/(\d+)$|', $this->getUrl(), $matches);
  133. $node = node_load($matches[1]);
  134. $edit = array();
  135. $edit["simplenews[send]"] = SIMPLENEWS_COMMAND_SEND_NOW;
  136. $this->drupalPost("node/{$node->nid}/simplenews", $edit, t('Submit'));
  137. $this->assertNoText(t('Schedule details'));
  138. // Check sent mails.
  139. $mails = $this->drupalGetMails();
  140. $this->assertEqual(1, count($mails), t('Newsletter mail has been sent.'));
  141. }
  142. }
  143. /**
  144. * Unit testing for monthly newsletter next run times.
  145. */
  146. class SimpleNewsSchedulerNextRunTimeTest extends SimpleNewsSchedulerWebTestCase {
  147. /**
  148. * Provides information about this test.
  149. */
  150. public static function getInfo() {
  151. return array(
  152. 'name' => 'Next run time: monthly',
  153. 'description' => 'Testing edition times for newsletters due every month and every 2 months.',
  154. 'group' => 'Simplenews Scheduler',
  155. );
  156. }
  157. /**
  158. * Test a frequency of 1 month.
  159. */
  160. function testNextRunTimeOneMonth() {
  161. // The start date of the edition.
  162. $this->edition_day = '05';
  163. $start_date = new DateTime("2012-01-{$this->edition_day} 12:00:00");
  164. // Fake newsletter parent data: sets the interval, start date, and frequency.
  165. $newsletter_parent_data = (object) array(
  166. 'nid' => 1,
  167. 'last_run' => 0,
  168. 'activated' => '1',
  169. 'send_interval' => 'month',
  170. 'interval_frequency' => '1',
  171. 'start_date' => $start_date->getTimestamp(),
  172. 'next_run' => $start_date->getTimestamp(), // Needs to be set manually when creating new records programmatically.
  173. 'stop_type' => '0',
  174. 'stop_date' => '0',
  175. 'stop_edition' => '0',
  176. 'php_eval' => '',
  177. 'title' => '[node:title] for [current-date:long]',
  178. );
  179. // Number of days to run for.
  180. $days = 370;
  181. // Index of the days we've done so far.
  182. $added_days = 0;
  183. // Iterate over days.
  184. $last_run_time = $start_date->getTimestamp();
  185. while ($added_days <= $days) {
  186. // Create today's date at noon and get the timestamp.
  187. $date = clone($start_date);
  188. $date->add(new DateInterval("P{$added_days}D"));
  189. $timestamp_noon = $date->getTimestamp();
  190. // Get the next run time from the API function we're testing.
  191. $next_run_time = simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $timestamp_noon);
  192. //debug($edition_time);
  193. if ($next_run_time != $last_run_time) {
  194. $offset = _simplenews_scheduler_make_time_offset($newsletter_parent_data->send_interval, $newsletter_parent_data->interval_frequency);
  195. $next_run_date = date_add(date_create(date('Y-m-d H:i:s', $last_run_time)), date_interval_create_from_date_string($offset));
  196. $this->assertEqual($next_run_date->getTimestamp(), $next_run_time, t('New next run timestamp has advanced by the expected offset of !offset.', array(
  197. '!offset' => $offset,
  198. )));
  199. $last_run_time = $next_run_time;
  200. }
  201. $this->assertTrue($timestamp_noon < $next_run_time, t('Next run time of !next-run is in the future relative to current time of !now.', array(
  202. '!next-run' => date("Y-n-d H:i:s", $next_run_time),
  203. '!now' => date("Y-n-d H:i:s", $timestamp_noon),
  204. )));
  205. $interval = $newsletter_parent_data->interval_frequency * 31 * 24 * 60 * 60;
  206. //$this->assertTrue($next_run_time - $timestamp_noon <= $interval, t('Next run timestamp is less than or exactly one month in the future.'));
  207. // Create a date object from the timestamp. The '@' makes the constructor
  208. // consider the string as a timestamp.
  209. $next_run_date = new DateTime(date('Y-m-d H:i:s', $last_run_time));
  210. $d = date_format($next_run_date, 'd');
  211. $this->assertEqual($next_run_date->format('d'), $this->edition_day, t('Next run timestamp is on same day of the month as the start date.'));
  212. $this->assertEqual($next_run_date->format('H:i:s'), '12:00:00', t('Next run timestamp is at the same time.'));
  213. $added_days++;
  214. } // while days
  215. }
  216. /**
  217. * Test a frequency of 2 months.
  218. */
  219. function testNextRunTimeTwoMonths() {
  220. // The start date of the edition.
  221. $this->edition_day = '05';
  222. $start_date = new DateTime("2012-01-{$this->edition_day} 12:00:00");
  223. // Fake newsletter parent data: sets the interval, start date, and frequency.
  224. $newsletter_parent_data = (object) array(
  225. 'nid' => 1,
  226. 'last_run' => 0,
  227. 'activated' => '1',
  228. 'send_interval' => 'month',
  229. 'interval_frequency' => '2',
  230. 'start_date' => $start_date->getTimestamp(),
  231. 'next_run' => $start_date->getTimestamp(), // Needs to be set manually when creating new records programmatically.
  232. 'stop_type' => '0',
  233. 'stop_date' => '0',
  234. 'stop_edition' => '0',
  235. 'php_eval' => '',
  236. 'title' => '[node:title] for [current-date:long]',
  237. );
  238. // Number of days to run for.
  239. $days = 370;
  240. // Index of the days we've done so far.
  241. $added_days = 0;
  242. // Iterate over days.
  243. while ($added_days <= $days) {
  244. // Create today's date at noon and get the timestamp.
  245. $date = clone($start_date);
  246. $date->add(new DateInterval("P{$added_days}D"));
  247. $timestamp_noon = $date->getTimestamp();
  248. // Get the next run time from the API function we're testing.
  249. $next_run_time = simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $timestamp_noon);
  250. //debug($edition_time);
  251. $this->assertTrue($timestamp_noon < $next_run_time, t('Next run time of !next-run is in the future relative to current time of !now.', array(
  252. '!next-run' => date("Y-n-d H:i:s", $next_run_time),
  253. '!now' => date("Y-n-d H:i:s", $timestamp_noon),
  254. )));
  255. $interval = $newsletter_parent_data->interval_frequency * 31 * 24 * 60 * 60;
  256. $this->assertTrue($next_run_time - $timestamp_noon <= $interval, t('Next run timestamp is less than or exactly two months in the future.'));
  257. // Create a date object from the timestamp. The '@' makes the constructor
  258. // consider the string as a timestamp.
  259. $next_run_date = new DateTime("@$next_run_time");
  260. $d = date_format($next_run_date, 'd');
  261. $this->assertEqual($next_run_date->format('d'), $this->edition_day, t('Next run timestamp is on same day of the month as the start date.'));
  262. $added_days++;
  263. } // while days
  264. }
  265. }
  266. /**
  267. * Unit testing for monthly newsletter edition times.
  268. */
  269. class SimpleNewsSchedulerEditionTimeTest extends SimpleNewsSchedulerWebTestCase {
  270. /**
  271. * Provides information about this test.
  272. */
  273. public static function getInfo() {
  274. return array(
  275. 'name' => 'Edition time: monthly',
  276. 'description' => 'Testing edition times for newsletters due every month and every 2 months.',
  277. 'group' => 'Simplenews Scheduler',
  278. );
  279. }
  280. /**
  281. * Test a frequency of 1 month.
  282. */
  283. function testEditionTimeOneMonth() {
  284. // The start date of the edition.
  285. $this->edition_day = '01';
  286. $start_date = new DateTime("2012-01-{$this->edition_day} 12:00:00");
  287. // Fake newsletter parent data: sets the interval, start date, and frequency.
  288. $newsletter_parent_data = (object) array(
  289. 'nid' => 1,
  290. 'last_run' => 0,
  291. 'activated' => '1',
  292. 'send_interval' => 'month',
  293. 'interval_frequency' => '1',
  294. 'start_date' => $start_date->getTimestamp(),
  295. 'stop_type' => '0',
  296. 'stop_date' => '0',
  297. 'stop_edition' => '0',
  298. 'php_eval' => '',
  299. 'title' => '[node:title] for [current-date:long]',
  300. );
  301. // Number of days to run for. Go just over one year.
  302. $days = 370;
  303. // Index of the days we've done so far.
  304. $added_days = 0;
  305. // Iterate over days.
  306. while ($added_days <= $days) {
  307. // Create today's date at noon and get the timestamp.
  308. $date = clone($start_date);
  309. $date->add(new DateInterval("P{$added_days}D"));
  310. $timestamp_noon = $date->getTimestamp();
  311. $edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $timestamp_noon);
  312. //debug($edition_time);
  313. // Expected edition time is always the {$this->edition_day}th of the month
  314. // at noon.
  315. $edition_time_formatted = date("Y-m-d H:i:s", $edition_time);
  316. $this_month = $date->format('Y-m');
  317. $expected_time_formatted = "{$this_month}-{$this->edition_day} 12:00:00";
  318. $this->assertEqual($edition_time_formatted, $expected_time_formatted, t("Edition time of !edition-time matches expected time of !edition-time-expected at time !now.", array(
  319. '!edition-time' => $edition_time_formatted,
  320. '!edition-time-expected' => $expected_time_formatted,
  321. '!now' => $date->format("Y-m-d H:i:s"),
  322. )));
  323. $added_days++;
  324. } // while days
  325. }
  326. /**
  327. * Test a frequency of 2 months.
  328. */
  329. function testEditionTimeTwoMonths() {
  330. // The start date of the edition.
  331. $this->edition_day = '01';
  332. $start_date = new DateTime("2012-01-{$this->edition_day} 12:00:00");
  333. // Fake newsletter parent data: sets the interval, start date, and frequency.
  334. $newsletter_parent_data = (object) array(
  335. 'nid' => 1,
  336. 'last_run' => 0,
  337. 'activated' => '1',
  338. 'send_interval' => 'month',
  339. 'interval_frequency' => '2',
  340. 'start_date' => $start_date->getTimestamp(),
  341. 'stop_type' => '0',
  342. 'stop_date' => '0',
  343. 'stop_edition' => '0',
  344. 'php_eval' => '',
  345. 'title' => '[node:title] for [current-date:long]',
  346. );
  347. // Number of days to run for. Go just over one year.
  348. $days = 370;
  349. // Index of the days we've done so far.
  350. $added_days = 0;
  351. // Iterate over days.
  352. while ($added_days <= $days) {
  353. // Create today's date at noon and get the timestamp.
  354. $date = clone($start_date);
  355. $date->add(new DateInterval("P{$added_days}D"));
  356. $timestamp_noon = $date->getTimestamp();
  357. $edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $timestamp_noon);
  358. //debug($edition_time);
  359. // Expected edition time is always the {$this->edition_day}th of the month
  360. // at noon.
  361. // Note here we use 'n' for the month to avoid having to pad.
  362. $edition_time_formatted = date("Y-n-d H:i:s", $edition_time);
  363. $this_year = $date->format('Y');
  364. $this_month = $date->format('n');
  365. // We start in January and run 2-monthly.
  366. // We want the number of elapsed months, module 2 (the frequency), to know
  367. // the remainder to subtract.
  368. $elapsed_mod = ($this_month - 1) % 2;
  369. $expected_month = $this_month - $elapsed_mod;
  370. $expected_time_formatted = "{$this_year}-{$expected_month}-{$this->edition_day} 12:00:00";
  371. $this->assertEqual($edition_time_formatted, $expected_time_formatted, t("Edition time of !edition-time matches expected time of !edition-time-expected at time !now.", array(
  372. '!edition-time' => $edition_time_formatted,
  373. '!edition-time-expected' => $expected_time_formatted,
  374. '!now' => $date->format("Y-m-d H:i:s"),
  375. )));
  376. $added_days++;
  377. } // while days
  378. }
  379. }
  380. /**
  381. * Unit testing for simplenews_scheduler_get_newsletters_due().
  382. */
  383. class SimpleNewsSchedulerEditionDueTest extends SimpleNewsSchedulerWebTestCase {
  384. protected $privileged_user;
  385. /**
  386. * Provides information about this test.
  387. */
  388. public static function getInfo() {
  389. return array(
  390. 'name' => 'Edition due test',
  391. 'description' => 'Functional tests for simplenews_scheduler_get_newsletters_due().',
  392. 'group' => 'Simplenews Scheduler',
  393. );
  394. }
  395. /**
  396. * Declares the module dependencies and create data for the test.
  397. */
  398. function setUp() {
  399. parent::setUp();
  400. $this->privileged_user = $this->drupalCreateUser(array(
  401. 'access content',
  402. 'administer nodes',
  403. 'create simplenews content',
  404. 'edit own simplenews content',
  405. 'send newsletter',
  406. 'send scheduled newsletters',
  407. 'overview scheduled newsletters',
  408. ));
  409. $this->drupalLogin($this->privileged_user);
  410. // The start date of the edition. This is on 5 January so that we get some
  411. // days in either month, and at at noon to keep things simple.
  412. $this->edition_day = '05';
  413. $start_date = new DateTime("2012-01-{$this->edition_day} 12:00:00");
  414. // Create a parent newsletter node.
  415. $node = (object) NULL;
  416. $node->type = 'simplenews';
  417. $node->title = 'Parent';
  418. $node->uid = 1;
  419. $node->status = 1;
  420. $node->language = 'und';
  421. // Safe to assume there is only one taxonomy term and it's the newsletter.
  422. $node->field_simplenews_term['und'][0]['tid'] = 1;
  423. // Workaround for http://drupal.org/node/1480258
  424. $node->nid = NULL;
  425. node_save($node);
  426. // Grumble grumble there's no node saving API in our module!
  427. // @see http://drupal.org/node/1480328 to clean this up.
  428. $node->simplenews_scheduler = (object) array(
  429. 'nid' => $node->nid,
  430. 'last_run' => 0,
  431. 'activated' => '1',
  432. 'send_interval' => 'month',
  433. 'interval_frequency' => '1',
  434. 'start_date' => $start_date->getTimestamp(),
  435. 'next_run' => $start_date->getTimestamp(), // Needs to be set manually when creating new records programmatically.
  436. 'stop_type' => '0',
  437. 'stop_date' => '0',
  438. 'stop_edition' => '0',
  439. 'php_eval' => '',
  440. 'title' => '[node:title] for [current-date:long]',
  441. );
  442. $record = (array) $node->simplenews_scheduler;
  443. $query = db_merge('simplenews_scheduler');
  444. $query->key(array(
  445. 'nid' => $record['nid'],
  446. ))
  447. ->fields($record)
  448. ->execute();
  449. // Store the node ID for the test to use.
  450. $this->parent_nid = $node->nid;
  451. }
  452. /**
  453. * Test simplenews_scheduler_get_newsletters_due().
  454. */
  455. function testEditionsDue() {
  456. // Get the node id of the parent newsletter node.
  457. $parent_nid = $this->parent_nid ;
  458. // But just check it exists for sanity.
  459. $this->drupalGet("node/$parent_nid");
  460. // Simulate cron running daily at half past 12 so that an edition due at
  461. // 12 noon should be picked up.
  462. $start_date = new DateTime("2012-01-01 12:00:00");
  463. $time_offsets = array(
  464. 'before' => "-1 hour",
  465. 'after' => "+1 hour",
  466. );
  467. // Number of days to run cron for.
  468. $days = 150;
  469. // Index of the days we've done so far.
  470. $added_days = 0;
  471. // Iterate over days.
  472. while ($added_days <= $days) {
  473. // Create today's date at noon and get the timestamp.
  474. $date = clone($start_date);
  475. $date->add(new DateInterval("P{$added_days}D"));
  476. $timestamp_noon = $date->getTimestamp();
  477. // We simulate running cron one hour before and one hour after noon.
  478. foreach ($time_offsets as $offset_key => $offset) {
  479. // Create a timestamp based on noon + the offset.
  480. // This gives us either 11:00 or 13:00 on the current day.
  481. $timestamp = strtotime($offset, $timestamp_noon);
  482. // debug("base: $timestamp_noon, off: $offset, result: $timestamp");
  483. // Get the list of newsletters due.
  484. $due = simplenews_scheduler_get_newsletters_due($timestamp);
  485. // An edition is due if it's 13:00 on the edition day.
  486. $formatted = date(DATE_RFC850, $timestamp);
  487. if ($offset_key == 'after' && date('d', $timestamp) == $this->edition_day) {
  488. $this->assertTrue(isset($due[$parent_nid]), "Edition due at day $added_days, $formatted, $timestamp");
  489. }
  490. else {
  491. $this->assertFalse(isset($due[$parent_nid]), "Edition not due at day $added_days, $formatted, $timestamp");
  492. }
  493. // Get some debug output to figure out what is going on in
  494. // simplenews_scheduler_get_newsletters_due().
  495. $intervals['hour'] = 3600;
  496. $intervals['day'] = 86400;
  497. $intervals['week'] = $intervals['day'] * 7;
  498. $intervals['month'] = $intervals['day'] * date_days_in_month(date('Y', $timestamp), date('m', $timestamp));
  499. if (isset($due[$parent_nid])) {
  500. // Output what we got back from the function.
  501. // debug($due);
  502. $newsletter_parent_data = $due[$parent_nid];
  503. $edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $timestamp);
  504. $eid = _simplenews_scheduler_new_edition($newsletter_parent_data->nid, $timestamp);
  505. // Output the last_run as a sanity check.
  506. $result = db_query("SELECT last_run FROM {simplenews_scheduler} WHERE nid = :nid", array(':nid' => $parent_nid));
  507. $last_run = $result->fetchField();
  508. $formatted = date(DATE_RFC850, $last_run);
  509. // debug("Last run: $formatted, $last_run");
  510. // Output the calculated edition time.
  511. $formatted = date(DATE_RFC850, $edition_time);
  512. // debug("Edition time: $formatted, $edition_time");
  513. // Check the edition time is 12:00.
  514. $this->assertEqual(date('H:i', $edition_time), '12:00', t('Edition time is at 12:00.'));
  515. // Fake sending it: update the 'last_run' for subsequent iterations.
  516. db_update('simplenews_scheduler')
  517. ->fields(array('last_run' => $timestamp))
  518. ->condition('nid', $parent_nid)
  519. ->execute();
  520. // Update the edition record.
  521. simplenews_scheduler_scheduler_update($newsletter_parent_data, $timestamp);
  522. // Check the node exists.
  523. $this->drupalGet("node/$eid");
  524. } // handling the request for a new edition
  525. } // foreach offset timestamp
  526. // Increment our counter.
  527. $added_days++;
  528. } // foreach day
  529. }
  530. }
  531. /**
  532. * Test edition time around DST changes.
  533. *
  534. * Test that simplenews_scheduler_calculate_edition_time() returns an edition
  535. * timestamp whose time in the local timezone remains the same after the
  536. * timezone changes over to Daylight Saving Time.
  537. */
  538. class SimpleNewsSchedulerDaylightSavingSwitchTest extends SimpleNewsSchedulerWebTestCase {
  539. protected $privileged_user;
  540. /**
  541. * Provides information about this test.
  542. */
  543. public static function getInfo() {
  544. return array(
  545. 'name' => 'Daylight Saving Time',
  546. 'description' => 'Functional tests for DST changes.',
  547. 'group' => 'Simplenews Scheduler',
  548. );
  549. }
  550. /**
  551. * Test edition time after DST changes for a monthly newsletter.
  552. *
  553. * @todo: generalize this for other intervals.
  554. */
  555. function testDSTMonthly() {
  556. $timezone_name = date_default_timezone();
  557. //debug($timezone_name);
  558. // Create a last run time before DST begins, and a now time after.
  559. // Use date_create() rather than strtotime so that we create a date at the
  560. // given time *in the current timezone* rather than UTC.
  561. $last_run_date = new DateTime("01-Mar-12 12:00:00");
  562. $now_date = date_create("05-Apr-12 12:00:00");
  563. //debug('last run date TZ: ' . $last_run_date->getTimezone()->getName());
  564. //debug('now date TZ: ' . $now_date->getTimezone()->getName());
  565. // Fake up newsletter data.
  566. $newsletter_parent_data = (object) array(
  567. 'last_run' => $last_run_date->getTimestamp(),
  568. 'send_interval' => 'month',
  569. 'interval_frequency' => 1,
  570. );
  571. // Get the edition time.
  572. $edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $now_date->getTimestamp());
  573. $edition_date = date_create('@' . $edition_time);
  574. //debug($edition_date->format(DATE_ATOM));
  575. // Format the edition time.
  576. $edition_time_formatted = format_date($edition_time, 'custom', DATE_ATOM);
  577. $edition_hour_formatted = format_date($edition_time, 'custom', 'H:i');
  578. $this->assertEqual($edition_hour_formatted, '12:00', t('Edition time is at 12:00 in the local timezone; full edition time is %time.', array(
  579. '%time' => $edition_time_formatted,
  580. )));
  581. }
  582. }