merge cron-fix

This commit is contained in:
Matteo Pagliazzi 2015-01-06 08:55:48 +01:00
commit d63cc4da8f
3 changed files with 95 additions and 39 deletions

View file

@ -14308,14 +14308,20 @@ api.startOfWeek = api.startOfWeek = function(options) {
};
api.startOfDay = function(options) {
var o;
var dayStart, o;
if (options == null) {
options = {};
}
o = sanitizeOptions(options);
return moment(o.now).startOf('day').add({
dayStart = moment(o.now).startOf('day').add({
hours: o.dayStart
});
if (moment(o.now).hour() < o.dayStart) {
dayStart.subtract({
days: 1
});
}
return dayStart;
};
api.dayMapping = {
@ -14341,7 +14347,9 @@ api.daysSince = function(yesterday, options) {
o = sanitizeOptions(options);
return Math.abs(api.startOfDay(_.defaults({
now: yesterday
}, o)).diff(o.now, 'days'));
}, o)).diff(api.startOfDay(_.defaults({
now: o.now
}, o)), 'days'));
};
@ -14350,7 +14358,7 @@ api.daysSince = function(yesterday, options) {
*/
api.shouldDo = function(day, repeat, options) {
var o, selected, yesterday;
var o, selected;
if (options == null) {
options = {};
}
@ -14361,17 +14369,7 @@ api.shouldDo = function(day, repeat, options) {
selected = repeat[api.dayMapping[api.startOfDay(_.defaults({
now: day
}, o)).day()]];
if (!moment(day).zone(o.timezoneOffset).isSame(o.now, 'd')) {
return selected;
}
if (options.dayStart <= o.now.hour()) {
return selected;
} else {
yesterday = moment(o.now).subtract({
days: 1
}).day();
return repeat[api.dayMapping[yesterday]];
}
return selected;
};
@ -16570,5 +16568,5 @@ api.wrap = function(user, main) {
};
}).call(this,require("/Users/lefnire/Google Drive/Sync/Sites/habitrpg/modules/habitrpg-shared/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
},{"./content.coffee":5,"./i18n.coffee":6,"/Users/lefnire/Google Drive/Sync/Sites/habitrpg/modules/habitrpg-shared/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":2,"lodash":3,"moment":4}]},{},[1])
}).call(this,require("/home/matteo/Dev/habitrpg/habitrpg-shared/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
},{"./content.coffee":5,"./i18n.coffee":6,"/home/matteo/Dev/habitrpg/habitrpg-shared/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":2,"lodash":3,"moment":4}]},{},[1])

View file

@ -57,7 +57,10 @@ api.startOfWeek = api.startOfWeek = (options={}) ->
api.startOfDay = (options={}) ->
o = sanitizeOptions(options)
moment(o.now).startOf('day').add({hours:o.dayStart})
dayStart = moment(o.now).startOf('day').add({hours:o.dayStart})
if moment(o.now).hour() < o.dayStart
dayStart.subtract({days:1})
dayStart
api.dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s'}
@ -66,7 +69,7 @@ api.dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s'}
###
api.daysSince = (yesterday, options = {}) ->
o = sanitizeOptions options
Math.abs api.startOfDay(_.defaults {now:yesterday}, o).diff(o.now, 'days')
Math.abs api.startOfDay(_.defaults {now:yesterday}, o).diff(api.startOfDay(_.defaults {now:o.now}, o), 'days')
###
Should the user do this taks on this date, given the task's repeat options and user.preferences.dayStart?
@ -75,12 +78,7 @@ api.shouldDo = (day, repeat, options={}) ->
return false unless repeat
o = sanitizeOptions options
selected = repeat[api.dayMapping[api.startOfDay(_.defaults {now:day}, o).day()]]
return selected unless moment(day).zone(o.timezoneOffset).isSame(o.now,'d')
if options.dayStart <= o.now.hour() # we're past the dayStart mark, is it due today?
return selected
else # we're not past dayStart mark, check if it was due "yesterday"
yesterday = moment(o.now).subtract({days:1}).day() # have to wrap o.now so as not to modify original
return repeat[api.dayMapping[yesterday]] # FIXME is this correct?? Do I need to do any timezone calcaulation here?
return selected
###
------------------------------------------------------

View file

@ -56,6 +56,9 @@ expectStrings = (obj, paths) ->
_.each paths, (path) -> expect(obj[path]).to.be.ok()
# options.daysAgo: days ago when the last cron was executed
# cronAfterStart: moves the lastCron to be after the dayStart.
# This way the daysAgo works as expected if the test case
# makes the assumption that the lastCron was after dayStart.
beforeAfter = (options={}) ->
user = newUser()
[before, after] = [user, _.cloneDeep(user)]
@ -66,7 +69,9 @@ beforeAfter = (options={}) ->
if options.limitOne
before["#{options.limitOne}s"] = [before["#{options.limitOne}s"][0]]
after["#{options.limitOne}s"] = [after["#{options.limitOne}s"][0]]
lastCron = +(moment(options.now || +new Date).subtract(options.daysAgo, 'days')) if options.daysAgo
lastCron = moment(options.now || +new Date).subtract( {days:options.daysAgo} ) if options.daysAgo
lastCron.add( {hours:options.dayStart, minutes:1} ) if options.daysAgo and options.cronAfterStart
lastCron = +lastCron if options.daysAgo
_.each [before,after], (obj) ->
obj.lastCron = lastCron if options.daysAgo
{before:before, after:after}
@ -517,6 +522,59 @@ describe 'Cron', ->
expect(after.todos[0].value).to.be.lessThan before.todos[0].value
expect(after.history.todos).to.have.length 1
# I used hard-coded dates here instead of 'now' so the tests don't fail
# when you run them between midnight and dayStart. Nothing worse than
# intermittent failures.
describe 'cron day calculations', ->
dayStart = 4
fstr = "YYYY-MM-DD HH:mm:ss"
it 'startOfDay before dayStart', ->
# If the time is before dayStart, then we expect the start of the day to be yesterday at dayStart
start = shared.startOfDay {now: moment('2014-10-09 02:30:00'), dayStart}
expect(start.format(fstr)).to.eql '2014-10-08 04:00:00'
it 'startOfDay after dayStart', ->
# If the time is after dayStart, then we expect the start of the day to be today at dayStart
start = shared.startOfDay {now: moment('2014-10-09 05:30:00'), dayStart}
expect(start.format(fstr)).to.eql '2014-10-09 04:00:00'
it 'daysSince cron before, now after', ->
# If the lastCron was before dayStart, then a time on the same day after dayStart
# should be 1 day later than lastCron
lastCron = moment('2014-10-09 02:30:00')
days = shared.daysSince(lastCron, {now: moment('2014-10-09 11:30:00'), dayStart})
expect(days).to.eql 1
it 'daysSince cron before, now before', ->
# If the lastCron was before dayStart, then a time on the same day also before dayStart
# should be 0 days later than lastCron
lastCron = moment('2014-10-09 02:30:00')
days = shared.daysSince(lastCron, {now: moment('2014-10-09 03:30:00'), dayStart})
expect(days).to.eql 0
it 'daysSince cron after, now after', ->
# If the lastCron was after dayStart, then a time on the same day also after dayStart
# should be 0 days later than lastCron
lastCron = moment('2014-10-09 05:30:00')
days = shared.daysSince(lastCron, {now: moment('2014-10-09 06:30:00'), dayStart})
expect(days).to.eql 0
it 'daysSince cron after, now tomorrow before', ->
# If the lastCron was after dayStart, then a time on the following day but before dayStart
# should be 0 days later than lastCron
lastCron = moment('2014-10-09 12:30:00')
days = shared.daysSince(lastCron, {now: moment('2014-10-10 01:30:00'), dayStart})
expect(days).to.eql 0
it 'daysSince cron after, now tomorrow after', ->
# If the lastCron was after dayStart, then a time on the following day and after dayStart
# should be 1 day later than lastCron
lastCron = moment('2014-10-09 12:30:00')
days = shared.daysSince(lastCron, {now: moment('2014-10-10 10:30:00'), dayStart})
expect(days).to.eql 1
describe 'dailies', ->
describe 'new day', ->
@ -530,7 +588,7 @@ describe 'Cron', ->
runCron = (options) ->
_.each [480, 240, 0, -120], (timezoneOffset) -> # test different timezones
now = shared.startOfWeek({timezoneOffset}).add(options.currentHour||0, 'hours')
{before,after} = beforeAfter({now, timezoneOffset, daysAgo:1, dayStart:options.dayStart||0, limitOne:'daily'})
{before,after} = beforeAfter({now, timezoneOffset, daysAgo:1, cronAfterStart:options.cronAfterStart||true, dayStart:options.dayStart||0, limitOne:'daily'})
before.dailys[0].repeat = after.dailys[0].repeat = options.repeat if options.repeat
before.dailys[0].streak = after.dailys[0].streak = 10
before.dailys[0].completed = after.dailys[0].completed = true if options.checked
@ -544,11 +602,14 @@ describe 'Cron', ->
when 'noDamage' then expectDayResetNoDamage(before,after)
{before,after}
# These test cases were written assuming that lastCron was run after dayStart
# even if currentHour < dayStart and lastCron = yesterday at currentHour.
# cronAfterStart makes sure that lastCron is moved to be after dayStart.
cronMatrix =
steps:
'due yesterday':
defaults: {daysAgo:1, limitOne: 'daily'}
defaults: {daysAgo:1, cronAfterStart:true, limitOne: 'daily'}
steps:
'(simple)': {expect:'losePoints'}
@ -599,15 +660,8 @@ describe 'Cron', ->
it "#{options.text}", -> runCron(_.defaults(obj,options))
recurseCronMatrix(cronMatrix)
it 'calculates day differences with dayStart properly', ->
dayStart = 4
yesterday = shared.startOfDay {now: moment().subtract(1, 'd'), dayStart}
now = shared.startOfDay {dayStart: dayStart-1}
expect(shared.daysSince(yesterday, {now, dayStart})).to.eql 0
now = moment().startOf('day').add(dayStart, 'h').add(1, 'm')
expect(shared.daysSince(yesterday, {now, dayStart})).to.eql 1
describe 'Helper', ->
it 'calculates gold coins', ->
expect(shared.gold(10)).to.eql 10
expect(shared.gold(1.957)).to.eql 1
@ -626,9 +680,15 @@ describe 'Helper', ->
expect(shared.tnl 99).to.eql 3580
it 'calculates the start of the day', ->
expect(shared.startOfDay({now: new Date(2013, 0, 1, 0)}).format('YYYY-MM-DD HH:mm')).to.eql '2013-01-01 00:00'
expect(shared.startOfDay({now: new Date(2013, 0, 1, 5)}).format('YYYY-MM-DD HH:mm')).to.eql '2013-01-01 00:00'
expect(shared.startOfDay({now: new Date(2013, 0, 1, 23, 59, 59)}).format('YYYY-MM-DD HH:mm')).to.eql '2013-01-01 00:00'
fstr = 'YYYY-MM-DD HH:mm:ss'
today = '2013-01-01 00:00:00'
# get the timezone for the day, so the test case doesn't fail
# if you run it during daylight savings time because by default
# it uses moment().zone() which is the current minute offset
zone = moment(today).zone()
expect(shared.startOfDay({now: new Date(2013, 0, 1, 0)}, timezoneOffset:zone).format(fstr)).to.eql today
expect(shared.startOfDay({now: new Date(2013, 0, 1, 5)}, timezoneOffset:zone).format(fstr)).to.eql today
expect(shared.startOfDay({now: new Date(2013, 0, 1, 23, 59, 59), timezoneOffset:zone}).format(fstr)).to.eql today
it 'counts pets', ->
pets = {}