make content releases use a given offset to the time.

This commit is contained in:
Phillip Thelen
2024-05-29 19:05:17 +02:00
parent b501e06f27
commit 54b1afd5b4
8 changed files with 107 additions and 18 deletions

View File

@@ -89,5 +89,6 @@
"REDIS_PASSWORD": "12345678",
"TRUSTED_DOMAINS": "localhost,https://habitica.com",
"TIME_TRAVEL_ENABLED": "false",
"DEBUG_ENABLED": "false"
"DEBUG_ENABLED": "false",
"CONTENT_SWITCHOVER_TIME_OFFSET": 8
}

View File

@@ -116,8 +116,8 @@
"chalk": "^5.3.0",
"cross-spawn": "^7.0.3",
"mocha": "^5.1.1",
"nyc": "^15.1.0",
"monk": "^7.3.4",
"nyc": "^15.1.0",
"require-again": "^2.0.0",
"run-rs": "^0.7.7",
"sinon-chai": "^3.7.0",

View File

@@ -0,0 +1,67 @@
/* eslint-disable global-require */
import { expect } from 'chai';
import nconf from 'nconf';
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
describe('datedMemoize', () => {
it('should return a function that returns a function', () => {
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(() => {});
expect(memoized).to.be.a('function');
});
it('should not call multiple times', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized(1, 2);
memoized(1, 3);
expect(stub).to.have.been.calledOnce;
});
it('call multiple times for different identifiers', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
memoized({ identifier: 'b', memoizeConfig: true }), 1, 2;
expect(stub).to.have.been.calledTwice;
});
it('call once for the same identifier', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
expect(stub).to.have.been.calledOnce;
});
it('call once on the same day', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
expect(stub).to.have.been.calledOnce;
});
it('call multiple times on different days', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
memoized({ date: new Date('2024-01-02'), memoizeConfig: true }, 1, 2);
expect(stub).to.have.been.calledTwice;
});
it('respects switchover time', () => {
const stub = sandbox.stub().returns({});
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
const memoized = datedMemoize(stub);
memoized({ date: new Date('2024-01-01T00:00:00.000Z'), memoizeConfig: true }, 1, 2);
memoized({ date: new Date(`2024-01-01T${String(SWITCHOVER_TIME).padStart(2, '0')}`), memoizeConfig: true }, 1, 2);
expect(stub).to.have.been.calledTwice;
});
});

View File

@@ -26,7 +26,7 @@ describe('armoire', () => {
clock.restore();
});
it('does not return unreleased gear', async () => {
clock = sinon.useFakeTimers(new Date('2024-01-01'));
clock = sinon.useFakeTimers(new Date('2024-01-02'));
const items = makeArmoireIitemList();
expect(items.length).to.equal(377);
expect(items.filter(item => item.set === 'pottersSet' || item.set === 'optimistSet' || item.set === 'schoolUniform')).to.be.an('array').that.is.empty;
@@ -47,7 +47,7 @@ describe('armoire', () => {
});
it('releases gear when appropriate', async () => {
clock = sinon.useFakeTimers(new Date('2024-01-01'));
clock = sinon.useFakeTimers(new Date('2024-01-01T00:00:00.000Z'));
const items = makeArmoireIitemList();
expect(items.length).to.equal(377);
clock.restore();
@@ -57,8 +57,13 @@ describe('armoire', () => {
expect(januaryItems.length).to.equal(381);
clock.restore();
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
clock = sinon.useFakeTimers(new Date('2024-02-20'));
clock = sinon.useFakeTimers(new Date('2024-02-07'));
const januaryItems2 = makeArmoireIitemList();
expect(januaryItems2.length).to.equal(381);
clock.restore();
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
clock = sinon.useFakeTimers(new Date('2024-02-07T09:00:00.000Z'));
const febuaryItems = makeArmoireIitemList();
expect(febuaryItems.length).to.equal(384);
expect(febuaryItems.length).to.equal(381);
});
});

View File

@@ -1,5 +1,6 @@
// eslint-disable-next-line max-len
import moment from 'moment';
import nconf from 'nconf';
import {
getAllScheduleMatchingGroups, clearCachedMatchers, MONTHLY_SCHEDULE, GALA_SCHEDULE,
} from '../../website/common/script/content/constants/schedule';
@@ -16,7 +17,10 @@ function validateMatcher (matcher, checkedDate) {
}
describe('Content Schedule', () => {
let switchoverTime;
beforeEach(() => {
switchoverTime = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
clearCachedMatchers();
});
@@ -50,8 +54,8 @@ describe('Content Schedule', () => {
}
});
it('assembles scheduled items on march 21st', () => {
const date = new Date('2024-03-21');
it('assembles scheduled items on march 22st', () => {
const date = new Date('2024-03-22');
const matchers = getAllScheduleMatchingGroups(date);
for (const key in matchers) {
if (matchers[key]) {
@@ -92,31 +96,31 @@ describe('Content Schedule', () => {
it('sets the end date if its in the same month', () => {
const date = new Date('2024-04-03');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-04-07').toDate());
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-04-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('sets the end date if its in the next day', () => {
const date = new Date('2024-05-06T14:00:00.000Z');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-05-07').toDate());
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('sets the end date if its on the release day', () => {
const date = new Date('2024-05-07');
const date = new Date('2024-05-07T07:00:00.000Z');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-06-07').toDate());
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('sets the end date if its next month', () => {
const date = new Date('2024-05-20T01:00:00.000Z');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-06-07').toDate());
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('sets the end date for a gala', () => {
const date = new Date('2024-05-20');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.seasonalGear.end).to.eql(moment.utc('2024-06-21').toDate());
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('contains content for repeating events', () => {

View File

@@ -1,4 +1,5 @@
import moment from 'moment';
import nconf from 'nconf';
import SEASONAL_SETS from './seasonalSets';
import { getRepeatingEvents } from './events';
@@ -773,6 +774,8 @@ export const GALA_SCHEDULE = {
},
};
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
export const TYPE_SCHEDULE = {
timeTravelers: FIRST_RELEASE_DAY,
backgrounds: SECOND_RELEASE_DAY,
@@ -790,7 +793,9 @@ function getDay (date) {
if (date === undefined) {
return 0;
}
return date instanceof moment ? date.date() : date.getDate();
const checkDate = new Date(date.getTime());
checkDate.setHours(checkDate.getHours() - SWITCHOVER_TIME);
return checkDate.getDate();
}
function getMonth (date) {
@@ -871,7 +876,7 @@ function makeMatcherClass (date) {
function makeEndDate (checkedDate, matcher) {
let end = moment.utc(checkedDate);
end.date(TYPE_SCHEDULE[matcher.type]);
end.hour(0);
end.hour(SWITCHOVER_TIME);
end.minute(0);
end.second(0);
if (matcher.endMonth !== undefined) {

View File

@@ -2,6 +2,7 @@ import defaults from 'lodash/defaults';
import find from 'lodash/find';
import forEach from 'lodash/forEach';
import moment from 'moment';
import nconf from 'nconf';
import upperFirst from 'lodash/upperFirst';
import { ownsItem } from '../gear-helper';
import { ATTRIBUTES } from '../../../constants';
@@ -1832,6 +1833,7 @@ const weapon = {
},
};
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
const releaseDay = 7;
const releaseDates = {
somethingSpooky: { year: 2023, month: 10 },
@@ -1888,7 +1890,7 @@ forEach({
function updateReleased (type) {
const today = moment();
const releaseDateEndPart = `${String(releaseDay).padStart(2, '0')}T08:00-0500`;
const releaseDateEndPart = `${String(releaseDay).padStart(2, '0')}T${String(SWITCHOVER_TIME).padStart(2, '0')}:00-0500`;
const returnType = {};
forEach(type, (gearItem, gearKey) => {
let released;

View File

@@ -1,10 +1,15 @@
import moment from 'moment';
import nconf from 'nconf';
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
function getDay (date) {
if (date === undefined) {
return 0;
}
return date instanceof moment ? date.date() : date.getDate();
const checkDate = new Date(date.getTime());
checkDate.setHours(checkDate.getHours() - SWITCHOVER_TIME);
return checkDate.getDate();
}
function getMonth (date) {