mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Add a "daily routine" trigger clock for backups, etc.
Summary: Ref T6881. Before implementing subscriptions, I'm going to vet triggers by using them to do backups. Each instance will get a daily trigger for backups, and that should give us a smaller-scale test to catch issues and limitations, with more opportunities for something to go wrong since it fires more often. Test Plan: Added unit tests. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T6881 Differential Revision: https://secure.phabricator.com/D11427
This commit is contained in:
parent
53b06408f4
commit
a988a1a043
4 changed files with 219 additions and 66 deletions
|
@ -8,10 +8,10 @@
|
|||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => '8d1c0f87',
|
||||
'core.pkg.js' => 'd60876a7',
|
||||
'core.pkg.js' => '7923c2e6',
|
||||
'darkconsole.pkg.js' => '8ab24e01',
|
||||
'differential.pkg.css' => '8af45893',
|
||||
'differential.pkg.js' => 'f437e70e',
|
||||
'differential.pkg.js' => 'dad3622f',
|
||||
'diffusion.pkg.css' => '591664fa',
|
||||
'diffusion.pkg.js' => 'bfc0737b',
|
||||
'maniphest.pkg.css' => 'e34dfbec',
|
||||
|
@ -166,10 +166,10 @@ return array(
|
|||
'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85',
|
||||
'rsrc/externals/javelin/core/__tests__/stratcom.js' => '88bf7313',
|
||||
'rsrc/externals/javelin/core/__tests__/util.js' => 'e251703d',
|
||||
'rsrc/externals/javelin/core/init.js' => '8c4e8f8b',
|
||||
'rsrc/externals/javelin/core/init_node.js' => 'c234aded',
|
||||
'rsrc/externals/javelin/core/init.js' => '76e1fd61',
|
||||
'rsrc/externals/javelin/core/init_node.js' => '77350e4d',
|
||||
'rsrc/externals/javelin/core/install.js' => '05270951',
|
||||
'rsrc/externals/javelin/core/util.js' => '93cc50d6',
|
||||
'rsrc/externals/javelin/core/util.js' => 'bdcfee9e',
|
||||
'rsrc/externals/javelin/docs/Base.js' => '74676256',
|
||||
'rsrc/externals/javelin/docs/onload.js' => 'e819c479',
|
||||
'rsrc/externals/javelin/ext/fx/Color.js' => '7e41274a',
|
||||
|
@ -186,11 +186,11 @@ return array(
|
|||
'rsrc/externals/javelin/ext/view/ViewRenderer.js' => '6c2b09a2',
|
||||
'rsrc/externals/javelin/ext/view/ViewVisitor.js' => 'efe49472',
|
||||
'rsrc/externals/javelin/ext/view/__tests__/HTMLView.js' => 'f92d7bcb',
|
||||
'rsrc/externals/javelin/ext/view/__tests__/View.js' => '6450b38b',
|
||||
'rsrc/externals/javelin/ext/view/__tests__/View.js' => 'bda69c40',
|
||||
'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5',
|
||||
'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9',
|
||||
'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03',
|
||||
'rsrc/externals/javelin/lib/DOM.js' => 'c8fd8db2',
|
||||
'rsrc/externals/javelin/lib/Cookie.js' => '6b3dcf44',
|
||||
'rsrc/externals/javelin/lib/DOM.js' => 'c4569c05',
|
||||
'rsrc/externals/javelin/lib/History.js' => 'c60f4327',
|
||||
'rsrc/externals/javelin/lib/JSON.js' => '69adf288',
|
||||
'rsrc/externals/javelin/lib/Leader.js' => '9330f91b',
|
||||
|
@ -215,7 +215,7 @@ return array(
|
|||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '8b3fd187',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '2818f5ce',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => 'e3b841c8',
|
||||
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '316b8fa1',
|
||||
'rsrc/externals/raphael/g.raphael.js' => '40dde778',
|
||||
'rsrc/externals/raphael/g.raphael.line.js' => '40da039e',
|
||||
|
@ -362,7 +362,7 @@ return array(
|
|||
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
|
||||
'rsrc/js/application/differential/behavior-comment-preview.js' => '6932def3',
|
||||
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
|
||||
'rsrc/js/application/differential/behavior-dropdown-menus.js' => 'e33d4bc5',
|
||||
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '3bc14668',
|
||||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '00861799',
|
||||
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
|
||||
'rsrc/js/application/differential/behavior-populate.js' => 'bdb3e4d0',
|
||||
|
@ -410,7 +410,7 @@ return array(
|
|||
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
|
||||
'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb',
|
||||
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => '3a1a4060',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'ab836011',
|
||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => 'f9539603',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||
|
@ -444,7 +444,7 @@ return array(
|
|||
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
|
||||
'rsrc/js/core/TextAreaUtils.js' => '5c93c52c',
|
||||
'rsrc/js/core/Title.js' => '5c1c758c',
|
||||
'rsrc/js/core/ToolTip.js' => '1d298e3a',
|
||||
'rsrc/js/core/ToolTip.js' => '031d4411',
|
||||
'rsrc/js/core/behavior-active-nav.js' => 'e379b58e',
|
||||
'rsrc/js/core/behavior-audio-source.js' => '59b251eb',
|
||||
'rsrc/js/core/behavior-autofocus.js' => '7319e029',
|
||||
|
@ -564,7 +564,7 @@ return array(
|
|||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
|
||||
'javelin-behavior-differential-comment-jump' => '4fdb476d',
|
||||
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
|
||||
'javelin-behavior-differential-dropdown-menus' => 'e33d4bc5',
|
||||
'javelin-behavior-differential-dropdown-menus' => '3bc14668',
|
||||
'javelin-behavior-differential-edit-inline-comments' => '00861799',
|
||||
'javelin-behavior-differential-feedback-preview' => '6932def3',
|
||||
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
|
||||
|
@ -635,7 +635,7 @@ return array(
|
|||
'javelin-behavior-project-create' => '065227cc',
|
||||
'javelin-behavior-refresh-csrf' => '7814b593',
|
||||
'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf',
|
||||
'javelin-behavior-releeph-request-state-change' => '3a1a4060',
|
||||
'javelin-behavior-releeph-request-state-change' => 'ab836011',
|
||||
'javelin-behavior-releeph-request-typeahead' => 'de2e896f',
|
||||
'javelin-behavior-remarkup-preview' => 'f7379f45',
|
||||
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
||||
|
@ -650,9 +650,9 @@ return array(
|
|||
'javelin-behavior-view-placeholder' => '47830651',
|
||||
'javelin-behavior-workflow' => '0a3f3021',
|
||||
'javelin-color' => '7e41274a',
|
||||
'javelin-cookie' => '62dfea03',
|
||||
'javelin-cookie' => '6b3dcf44',
|
||||
'javelin-diffusion-locate-file-source' => 'b42eddc7',
|
||||
'javelin-dom' => 'c8fd8db2',
|
||||
'javelin-dom' => 'c4569c05',
|
||||
'javelin-dynval' => 'f6555212',
|
||||
'javelin-event' => '85ea0626',
|
||||
'javelin-fx' => '54b612ba',
|
||||
|
@ -660,7 +660,7 @@ return array(
|
|||
'javelin-install' => '05270951',
|
||||
'javelin-json' => '69adf288',
|
||||
'javelin-leader' => '9330f91b',
|
||||
'javelin-magical-init' => '8c4e8f8b',
|
||||
'javelin-magical-init' => '76e1fd61',
|
||||
'javelin-mask' => '8a41885b',
|
||||
'javelin-reactor' => '2b8de964',
|
||||
'javelin-reactor-dom' => 'c90a04fc',
|
||||
|
@ -677,10 +677,10 @@ return array(
|
|||
'javelin-typeahead-normalizer' => '6f7a9da8',
|
||||
'javelin-typeahead-ondemand-source' => '8b3fd187',
|
||||
'javelin-typeahead-preloaded-source' => '54f314a0',
|
||||
'javelin-typeahead-source' => '2818f5ce',
|
||||
'javelin-typeahead-source' => 'e3b841c8',
|
||||
'javelin-typeahead-static-source' => '316b8fa1',
|
||||
'javelin-uri' => '6eff08aa',
|
||||
'javelin-util' => '93cc50d6',
|
||||
'javelin-util' => 'bdcfee9e',
|
||||
'javelin-vector' => 'cc1bd0b0',
|
||||
'javelin-view' => '0f764c35',
|
||||
'javelin-view-html' => 'fe287620',
|
||||
|
@ -738,7 +738,7 @@ return array(
|
|||
'phabricator-standard-page-view' => '2c96cfb5',
|
||||
'phabricator-textareautils' => '5c93c52c',
|
||||
'phabricator-title' => '5c1c758c',
|
||||
'phabricator-tooltip' => '1d298e3a',
|
||||
'phabricator-tooltip' => '031d4411',
|
||||
'phabricator-transaction-view-css' => '5d0cae25',
|
||||
'phabricator-ui-example-css' => '528b19de',
|
||||
'phabricator-uiexample-javelin-view' => 'd4a14807',
|
||||
|
@ -834,6 +834,12 @@ return array(
|
|||
'029a133d' => array(
|
||||
'aphront-dialog-view-css',
|
||||
),
|
||||
'031d4411' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'03d6ed07' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -938,12 +944,6 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-keyboard-shortcut-manager',
|
||||
),
|
||||
'1d298e3a' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'1def2711' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -956,12 +956,6 @@ return array(
|
|||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
),
|
||||
'2818f5ce' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-typeahead-normalizer',
|
||||
),
|
||||
'2926fff2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1029,14 +1023,6 @@ return array(
|
|||
'javelin-json',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'3a1a4060' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'3ab51e2c' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
|
@ -1045,6 +1031,18 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-magical-init',
|
||||
),
|
||||
'3bc14668' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'phabricator-phtize',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'3d51a746' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1228,10 +1226,6 @@ return array(
|
|||
'javelin-magical-init',
|
||||
'javelin-util',
|
||||
),
|
||||
'62dfea03' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
),
|
||||
'6453c869' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1251,6 +1245,10 @@ return array(
|
|||
'69adf288' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'6b3dcf44' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
),
|
||||
'6c2b09a2' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1562,6 +1560,14 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'ab836011' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-util',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'ad7a69ca' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1650,6 +1656,13 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-shaped-request',
|
||||
),
|
||||
'c4569c05' => array(
|
||||
'javelin-magical-init',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-vector',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'c51ae228' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-util',
|
||||
|
@ -1663,13 +1676,6 @@ return array(
|
|||
'javelin-uri',
|
||||
'javelin-util',
|
||||
),
|
||||
'c8fd8db2' => array(
|
||||
'javelin-magical-init',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-vector',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'c90a04fc' => array(
|
||||
'javelin-dom',
|
||||
'javelin-dynval',
|
||||
|
@ -1788,18 +1794,6 @@ return array(
|
|||
'javelin-workflow',
|
||||
'javelin-vector',
|
||||
),
|
||||
'e33d4bc5' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'phuix-dropdown-menu',
|
||||
'phuix-action-list-view',
|
||||
'phuix-action-view',
|
||||
'phabricator-phtize',
|
||||
'changeset-view-manager',
|
||||
),
|
||||
'e379b58e' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1807,6 +1801,12 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'e3b841c8' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-typeahead-normalizer',
|
||||
),
|
||||
'e4cc26b3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
|
@ -1596,6 +1596,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonTasksTableView' => 'applications/daemon/view/PhabricatorDaemonTasksTableView.php',
|
||||
'PhabricatorDaemonsApplication' => 'applications/daemon/application/PhabricatorDaemonsApplication.php',
|
||||
'PhabricatorDaemonsSetupCheck' => 'applications/config/check/PhabricatorDaemonsSetupCheck.php',
|
||||
'PhabricatorDailyRoutineTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorDailyRoutineTriggerClock.php',
|
||||
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
|
||||
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
|
||||
'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php',
|
||||
|
@ -4801,6 +4802,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonTasksTableView' => 'AphrontView',
|
||||
'PhabricatorDaemonsApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorDaemonsSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorDailyRoutineTriggerClock' => 'PhabricatorTriggerClock',
|
||||
'PhabricatorDashboard' => array(
|
||||
'PhabricatorDashboardDAO',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Triggers a daily routine, like server backups.
|
||||
*
|
||||
* This clock triggers events every 24 hours, using UTC. It does not use a
|
||||
* locale, and is intended for technical processes like backing up a server
|
||||
* every night.
|
||||
*
|
||||
* Because UTC does not have daylight savings, the local hour when this event
|
||||
* occurs will change over the course of the year. For example, from the
|
||||
* perspective of a user in California, it might run backups at 3AM in the
|
||||
* winter and 2AM in the summer. This is desirable for maintenance processes,
|
||||
* but problematic for some human processes. Use a different clock if you're
|
||||
* triggering a human-oriented event.
|
||||
*
|
||||
* The clock uses the time of day of the `start` epoch to calculate the time
|
||||
* of day of the next event, so you can change the time of day when the event
|
||||
* occurs by adjusting the `start` time of day.
|
||||
*/
|
||||
final class PhabricatorDailyRoutineTriggerClock
|
||||
extends PhabricatorTriggerClock {
|
||||
|
||||
public function validateProperties(array $properties) {
|
||||
PhutilTypeSpec::checkMap(
|
||||
$properties,
|
||||
array(
|
||||
'start' => 'int',
|
||||
));
|
||||
}
|
||||
|
||||
public function getNextEventEpoch($last_epoch, $is_reschedule) {
|
||||
$start_epoch = $this->getProperty('start');
|
||||
if (!$last_epoch) {
|
||||
$last_epoch = $start_epoch;
|
||||
}
|
||||
|
||||
$start = new DateTime('@'.$start_epoch);
|
||||
$last = new DateTime('@'.$last_epoch);
|
||||
|
||||
// NOTE: We're choosing the date from the last event, but the time of day
|
||||
// from the start event. This allows callers to change when the event
|
||||
// occurs by updating the trigger's start parameter.
|
||||
$ymd = $last->format('Y-m-d');
|
||||
$hms = $start->format('G:i:s');
|
||||
|
||||
$next = new DateTime("{$ymd} {$hms} UTC");
|
||||
|
||||
// Add a day.
|
||||
// NOTE: DateInterval doesn't exist until PHP 5.3.0, and we currently
|
||||
// target PHP 5.2.3.
|
||||
$next->modify('+1 day');
|
||||
|
||||
return (int)$next->format('U');
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,90 @@ final class PhabricatorTriggerClockTestCase extends PhabricatorTestCase {
|
|||
pht('Should never trigger.'));
|
||||
}
|
||||
|
||||
public function testDailyRoutineTriggerClockDaylightSavings() {
|
||||
// These dates are selected to cross daylight savings in PST; they should
|
||||
// be unaffected.
|
||||
$start = strtotime('2015-03-05 16:17:18 UTC');
|
||||
|
||||
$clock = new PhabricatorDailyRoutineTriggerClock(
|
||||
array(
|
||||
'start' => $start,
|
||||
));
|
||||
|
||||
$expect_list = array(
|
||||
'2015-03-06 16:17:18',
|
||||
'2015-03-07 16:17:18',
|
||||
'2015-03-08 16:17:18',
|
||||
'2015-03-09 16:17:18',
|
||||
'2015-03-10 16:17:18',
|
||||
);
|
||||
|
||||
$this->expectClock($clock, $expect_list, pht('Daily Routine (PST)'));
|
||||
}
|
||||
|
||||
public function testDailyRoutineTriggerClockLeapSecond() {
|
||||
// These dates cross the leap second on June 30, 2012. There has never
|
||||
// been a negative leap second, so we can't test that yet.
|
||||
$start = strtotime('2012-06-28 23:59:59 UTC');
|
||||
|
||||
$clock = new PhabricatorDailyRoutineTriggerClock(
|
||||
array(
|
||||
'start' => $start,
|
||||
));
|
||||
|
||||
$expect_list = array(
|
||||
'2012-06-29 23:59:59',
|
||||
'2012-06-30 23:59:59',
|
||||
'2012-07-01 23:59:59',
|
||||
'2012-07-02 23:59:59',
|
||||
);
|
||||
|
||||
$this->expectClock($clock, $expect_list, pht('Daily Routine (Leap)'));
|
||||
}
|
||||
|
||||
|
||||
public function testCDailyRoutineTriggerClockAdjustTimeOfDay() {
|
||||
// In this case, we're going to update the time of day on the clock and
|
||||
// make sure it keeps track of the date but adjusts the time.
|
||||
$start = strtotime('2015-01-15 6:07:08 UTC');
|
||||
|
||||
$clock = new PhabricatorDailyRoutineTriggerClock(
|
||||
array(
|
||||
'start' => $start,
|
||||
));
|
||||
|
||||
$expect_list = array(
|
||||
'2015-01-16 6:07:08',
|
||||
'2015-01-17 6:07:08',
|
||||
'2015-01-18 6:07:08',
|
||||
);
|
||||
|
||||
$last_epoch = $this->expectClock(
|
||||
$clock,
|
||||
$expect_list,
|
||||
pht('Daily Routine (Pre-Adjust)'));
|
||||
|
||||
// Now, change the time of day.
|
||||
$new_start = strtotime('2015-01-08 1:23:45 UTC');
|
||||
|
||||
$clock = new PhabricatorDailyRoutineTriggerClock(
|
||||
array(
|
||||
'start' => $new_start,
|
||||
));
|
||||
|
||||
$expect_list = array(
|
||||
'2015-01-19 1:23:45',
|
||||
'2015-01-20 1:23:45',
|
||||
'2015-01-21 1:23:45',
|
||||
);
|
||||
|
||||
$this->expectClock(
|
||||
$clock,
|
||||
$expect_list,
|
||||
pht('Daily Routine (Post-Adjust)'),
|
||||
$last_epoch);
|
||||
}
|
||||
|
||||
public function testSubscriptionTriggerClock() {
|
||||
$start = strtotime('2014-01-31 2:34:56 UTC');
|
||||
|
||||
|
@ -76,7 +160,15 @@ final class PhabricatorTriggerClockTestCase extends PhabricatorTestCase {
|
|||
'2016-03-31 2:34:56',
|
||||
);
|
||||
|
||||
$last_epoch = null;
|
||||
$this->expectClock($clock, $expect_list, pht('Billing Cycle'));
|
||||
}
|
||||
|
||||
private function expectClock(
|
||||
PhabricatorTriggerClock $clock,
|
||||
array $expect_list,
|
||||
$clock_name,
|
||||
$last_epoch = null) {
|
||||
|
||||
foreach ($expect_list as $cycle => $expect) {
|
||||
$next_epoch = $clock->getNextEventEpoch(
|
||||
$last_epoch,
|
||||
|
@ -84,11 +176,13 @@ final class PhabricatorTriggerClockTestCase extends PhabricatorTestCase {
|
|||
|
||||
$this->assertEqual(
|
||||
$expect,
|
||||
id(new DateTime('@'.$next_epoch))->format('Y-m-d g:i:s'),
|
||||
pht('Billing cycle %s.', $cycle));
|
||||
id(new DateTime('@'.$next_epoch))->format('Y-m-d G:i:s'),
|
||||
pht('%s (%s)', $clock_name, $cycle));
|
||||
|
||||
$last_epoch = $next_epoch;
|
||||
}
|
||||
|
||||
return $last_epoch;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue