calendar and schedule testing and tweaks
This commit is contained in:
parent
507246b46e
commit
3b6b290528
|
@ -1,11 +1,13 @@
|
|||
import { mapStateToProps } from "../map_state_to_props";
|
||||
import { mapStateToProps, mapResourcesToCalendar } from "../map_state_to_props";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import {
|
||||
fakeSequence,
|
||||
fakeRegimen,
|
||||
fakeFarmEvent
|
||||
} from "../../../__test_support__/fake_state/resources";
|
||||
import { buildResourceIndex } from "../../../__test_support__/resource_index_builder";
|
||||
import {
|
||||
buildResourceIndex
|
||||
} from "../../../__test_support__/resource_index_builder";
|
||||
import * as moment from "moment";
|
||||
|
||||
describe("mapStateToProps()", () => {
|
||||
|
@ -23,6 +25,7 @@ describe("mapStateToProps()", () => {
|
|||
|
||||
const getFutureTime =
|
||||
(t: number, value: number, label: string) =>
|
||||
// tslint:disable-next-line:no-any
|
||||
moment(t).add(value as any, label).toISOString();
|
||||
|
||||
const sequenceFarmEvent = fakeFarmEvent("Sequence", 1);
|
||||
|
@ -53,54 +56,52 @@ describe("mapStateToProps()", () => {
|
|||
const testTime = moment().startOf("hour").valueOf();
|
||||
const { calendarRows, push } = mapStateToProps(testState(testTime));
|
||||
|
||||
// Day 1: Sequence Farm Event
|
||||
const day1 = calendarRows[0];
|
||||
const day1Time = moment(testTime).add(1, "day");
|
||||
expect(day1.year).toEqual(day1Time.year() - 2000);
|
||||
expect(day1.month).toEqual(day1Time.format("MMM"));
|
||||
expect(day1.day).toEqual(day1Time.date());
|
||||
const day1ItemTime = day1Time.add(2, "minutes");
|
||||
expect(day1.sortKey).toEqual(day1ItemTime.unix());
|
||||
expect(day1.items).toEqual([{
|
||||
executableId: 1,
|
||||
heading: "fake",
|
||||
id: 1,
|
||||
mmddyy: day1ItemTime.format("MMDDYY"),
|
||||
sortKey: day1ItemTime.unix(),
|
||||
timeStr: day1ItemTime.format("hh:mma")
|
||||
}]);
|
||||
|
||||
// Day 2: Regimen Farm Event
|
||||
const day2 = calendarRows[1];
|
||||
const day2Time = moment(testTime).add(2, "days");
|
||||
expect(day2.year).toEqual(day2Time.year() - 2000);
|
||||
expect(day2.month).toEqual(day2Time.format("MMM"));
|
||||
expect(day2.day).toEqual(day2Time.date());
|
||||
|
||||
// Regimen
|
||||
const regimenStartTime = day2Time.clone().add(1, "minutes");
|
||||
expect(day2.sortKey).toEqual(regimenStartTime.unix());
|
||||
expect(day2.items[0]).toEqual({
|
||||
executableId: 1,
|
||||
heading: "Foo",
|
||||
id: 2,
|
||||
mmddyy: regimenStartTime.format("MMDDYY"),
|
||||
sortKey: regimenStartTime.unix(),
|
||||
subheading: "",
|
||||
timeStr: regimenStartTime.format("hh:mma")
|
||||
});
|
||||
|
||||
// Regimen Item
|
||||
const regimenItemTime = day2Time.clone().add(10, "minutes");
|
||||
expect(day2.items[1]).toEqual({
|
||||
executableId: 1,
|
||||
heading: "Foo",
|
||||
id: 2,
|
||||
mmddyy: regimenItemTime.format("MMDDYY"),
|
||||
sortKey: regimenItemTime.unix(),
|
||||
subheading: "fake",
|
||||
timeStr: regimenItemTime.format("hh:mma")
|
||||
});
|
||||
expect(calendarRows).toEqual([
|
||||
{
|
||||
day: day1Time.date(),
|
||||
items: [
|
||||
{
|
||||
executableId: 1,
|
||||
heading: "fake",
|
||||
id: 1,
|
||||
mmddyy: day1ItemTime.format("MMDDYY"),
|
||||
sortKey: day1ItemTime.unix(),
|
||||
timeStr: day1ItemTime.format("hh:mma")
|
||||
}],
|
||||
month: day1Time.format("MMM"),
|
||||
sortKey: day1Time.unix(),
|
||||
year: day1Time.year() - 2000
|
||||
},
|
||||
{
|
||||
day: day2Time.date(),
|
||||
items: [
|
||||
{
|
||||
executableId: 1,
|
||||
heading: "Foo",
|
||||
id: 2,
|
||||
mmddyy: regimenStartTime.format("MMDDYY"),
|
||||
sortKey: regimenStartTime.unix(),
|
||||
subheading: "",
|
||||
timeStr: regimenStartTime.format("hh:mma")
|
||||
},
|
||||
{
|
||||
executableId: 1,
|
||||
heading: "Foo",
|
||||
id: 2,
|
||||
mmddyy: regimenItemTime.format("MMDDYY"),
|
||||
sortKey: regimenItemTime.unix(),
|
||||
subheading: "fake",
|
||||
timeStr: regimenItemTime.format("hh:mma")
|
||||
}],
|
||||
month: day2Time.format("MMM"),
|
||||
sortKey: regimenStartTime.unix(),
|
||||
year: day2Time.year() - 2000
|
||||
}]);
|
||||
|
||||
expect(push).toBeTruthy();
|
||||
});
|
||||
|
|
|
@ -49,9 +49,12 @@ describe("scheduler", () => {
|
|||
});
|
||||
|
||||
function testSchedule(
|
||||
description: string, fakeEvent: TimeLine, expected: Moment[]) {
|
||||
description: string,
|
||||
fakeEvent: TimeLine,
|
||||
timeNow: Moment,
|
||||
expected: Moment[]) {
|
||||
it(description, () => {
|
||||
const result = scheduleForFarmEvent(fakeEvent);
|
||||
const result = scheduleForFarmEvent(fakeEvent, timeNow);
|
||||
expect(result.length).toEqual(expected.length);
|
||||
expected.map((expectation, index) => {
|
||||
expect(result[index]).toBeSameTimeAs(expectation);
|
||||
|
@ -59,14 +62,21 @@ describe("scheduler", () => {
|
|||
});
|
||||
}
|
||||
|
||||
const singleFarmEvent: TimeLine = {
|
||||
"start_time": "2017-08-01T17:00:00.000Z",
|
||||
"end_time": "2017-08-01T18:00:00.000Z",
|
||||
"repeat": 1,
|
||||
"time_unit": "never"
|
||||
};
|
||||
|
||||
testSchedule("schedules a FarmEvent",
|
||||
{
|
||||
"start_time": "2017-08-01T17:30:00.000Z",
|
||||
"end_time": "2017-08-07T05:00:00.000Z",
|
||||
"repeat": 2,
|
||||
"time_unit": "daily",
|
||||
current_time: "2017-08-01T16:30:00.000Z"
|
||||
"time_unit": "daily"
|
||||
},
|
||||
moment("2017-08-01T16:30:00.000Z"),
|
||||
[
|
||||
moment("2017-08-01T17:30:00.000Z"),
|
||||
moment("2017-08-03T17:30:00.000Z"),
|
||||
|
@ -78,9 +88,9 @@ describe("scheduler", () => {
|
|||
"start_time": "2017-08-01T17:30:00.000Z",
|
||||
"end_time": "2017-08-07T05:00:00.000Z",
|
||||
"repeat": 0,
|
||||
"time_unit": "daily",
|
||||
current_time: "2017-08-01T16:30:00.000Z"
|
||||
"time_unit": "daily"
|
||||
},
|
||||
moment("2017-08-01T16:30:00.000Z"),
|
||||
[moment("2017-08-01T17:30:00.000Z")]);
|
||||
|
||||
testSchedule("handles start_time in the past",
|
||||
|
@ -88,36 +98,51 @@ describe("scheduler", () => {
|
|||
"start_time": "2017-08-01T17:30:00.000Z",
|
||||
"end_time": "2017-08-09T05:00:00.000Z",
|
||||
"repeat": 2,
|
||||
"time_unit": "daily",
|
||||
current_time: "2017-08-03T18:30:00.000Z"
|
||||
"time_unit": "daily"
|
||||
},
|
||||
moment("2017-08-03T18:30:00.000Z"),
|
||||
[
|
||||
moment("2017-08-05T17:30:00.000Z"),
|
||||
moment("2017-08-07T17:30:00.000Z")
|
||||
]);
|
||||
|
||||
testSchedule("handles start_time in the past: no repeat",
|
||||
singleFarmEvent,
|
||||
moment("2017-08-01T17:30:00.000Z"),
|
||||
[moment("2017-08-01T17:00:00.000Z")]);
|
||||
|
||||
testSchedule("uses grace period",
|
||||
{
|
||||
"start_time": "2017-08-01T17:30:00.000Z",
|
||||
"end_time": "2017-08-02T05:00:00.000Z",
|
||||
"repeat": 4,
|
||||
"time_unit": "hourly",
|
||||
current_time: "2017-08-01T17:30:30.000Z"
|
||||
"time_unit": "hourly"
|
||||
},
|
||||
moment("2017-08-01T17:30:30.000Z"),
|
||||
[
|
||||
moment("2017-08-01T17:30:00.000Z"),
|
||||
moment("2017-08-01T21:30:00.000Z"),
|
||||
moment("2017-08-02T01:30:00.000Z")
|
||||
]);
|
||||
|
||||
testSchedule("uses grace period: no repeat",
|
||||
singleFarmEvent,
|
||||
moment("2017-08-01T17:00:30.000Z"),
|
||||
[moment("2017-08-01T17:00:00.000Z")]);
|
||||
|
||||
testSchedule("farm event over",
|
||||
{
|
||||
"start_time": "2017-08-01T17:30:00.000Z",
|
||||
"end_time": "2017-08-02T05:00:00.000Z",
|
||||
"repeat": 4,
|
||||
"time_unit": "hourly",
|
||||
current_time: "2017-08-03T17:30:30.000Z"
|
||||
"time_unit": "hourly"
|
||||
},
|
||||
moment("2017-08-03T17:30:30.000Z"),
|
||||
[]);
|
||||
|
||||
testSchedule("farm event over: no repeat",
|
||||
singleFarmEvent,
|
||||
moment("2017-08-01T19:00:00.000Z"),
|
||||
[]);
|
||||
|
||||
testSchedule("first 60 items",
|
||||
|
@ -125,9 +150,9 @@ describe("scheduler", () => {
|
|||
"start_time": "2017-08-02T17:00:00.000Z",
|
||||
"end_time": "2017-08-02T19:00:00.000Z",
|
||||
"repeat": 1,
|
||||
"time_unit": "minutely",
|
||||
current_time: "2017-08-01T15:30:00.000Z"
|
||||
"time_unit": "minutely"
|
||||
},
|
||||
moment("2017-08-01T15:30:00.000Z"),
|
||||
range(0, 60)
|
||||
.map((x: number) =>
|
||||
moment(`2017-08-02T17:${padStart("" + x, 2, "0")}:00.000Z`)));
|
||||
|
@ -137,9 +162,9 @@ describe("scheduler", () => {
|
|||
"start_time": "2017-08-02T16:00:00.000Z",
|
||||
"end_time": "2017-08-02T21:00:00.000Z",
|
||||
"repeat": 1,
|
||||
"time_unit": "minutely",
|
||||
current_time: "2017-08-02T17:01:00.000Z"
|
||||
"time_unit": "minutely"
|
||||
},
|
||||
moment("2017-08-02T17:01:00.000Z"),
|
||||
range(0, 60)
|
||||
.map((x: number) =>
|
||||
moment(`2017-08-02T17:${padStart("" + x, 2, "0")}:00.000Z`)));
|
||||
|
|
|
@ -68,18 +68,23 @@ export interface TimeLine {
|
|||
}
|
||||
/** Takes a subset of FarmEvent<Sequence> data and generates a list of dates. */
|
||||
export function scheduleForFarmEvent(
|
||||
{ start_time, end_time, repeat, time_unit, current_time = moment() }: TimeLine
|
||||
{ start_time, end_time, repeat, time_unit }: TimeLine, timeNow = moment()
|
||||
): Moment[] {
|
||||
const interval = repeat && farmEventIntervalSeconds(repeat, time_unit);
|
||||
if (interval && (time_unit !== NEVER)) {
|
||||
const schedule = scheduler({
|
||||
startTime: moment(start_time),
|
||||
currentTime: moment(current_time),
|
||||
currentTime: timeNow,
|
||||
endTime: end_time ? moment(end_time) : nextYear(),
|
||||
intervalSeconds: interval
|
||||
});
|
||||
return schedule;
|
||||
} else {
|
||||
return [moment(start_time)];
|
||||
const gracePeriod = timeNow.clone().subtract(1, "minute");
|
||||
if (moment(end_time).isSameOrAfter(gracePeriod)) {
|
||||
return [moment(start_time)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,31 +12,35 @@ import { scheduleForFarmEvent } from "./calendar/scheduler";
|
|||
/** Prepares a FarmEvent[] for use with <FBSelect /> */
|
||||
export function mapStateToProps(state: Everything): FarmEventProps {
|
||||
const push = (state && state.router && state.router.push) || (() => { });
|
||||
const calendar = mapResourcesToCalendar(state.resources.index, moment.now());
|
||||
const calendar = mapResourcesToCalendar(state.resources.index, moment());
|
||||
const calendarRows = calendar.getAll();
|
||||
return { calendarRows, push };
|
||||
}
|
||||
|
||||
/** TODO: Reduce complexity, but write *good* unit tests *before* refactoring.*/
|
||||
export function mapResourcesToCalendar(ri: ResourceIndex, unixNow = moment.now()): Calendar {
|
||||
export function mapResourcesToCalendar(
|
||||
ri: ResourceIndex, now = moment()): Calendar {
|
||||
const x = joinFarmEventsToExecutable(ri);
|
||||
const calendar = new Calendar();
|
||||
const addRegimenToCalendar = regimenCalendarAdder(ri);
|
||||
|
||||
x.map(function (fe) {
|
||||
switch (fe.executable_type) {
|
||||
case "Regimen": return addRegimenToCalendar(fe, calendar);
|
||||
case "Sequence": return addSequenceToCalendar(fe, calendar);
|
||||
default: throw new Error(`Bad fe: ${JSON.stringify(fe)}`);
|
||||
case "Regimen":
|
||||
return addRegimenToCalendar(
|
||||
fe, calendar, now);
|
||||
case "Sequence":
|
||||
return addSequenceToCalendar(fe, calendar, now);
|
||||
default:
|
||||
throw new Error(`Bad fe: ${JSON.stringify(fe)}`);
|
||||
}
|
||||
});
|
||||
|
||||
return calendar;
|
||||
}
|
||||
export let regimenCalendarAdder = (index: ResourceIndex) =>
|
||||
(f: FarmEventWithRegimen, c: Calendar) => {
|
||||
(f: FarmEventWithRegimen, c: Calendar, now = moment()) => {
|
||||
const { regimen_items } = f.executable;
|
||||
const now = moment();
|
||||
const fromEpoch = (ms: number) => moment(f.start_time)
|
||||
.startOf("day")
|
||||
.add(ms, "ms");
|
||||
|
@ -46,7 +50,9 @@ export let regimenCalendarAdder = (index: ResourceIndex) =>
|
|||
c.insert(o);
|
||||
regimen_items.map(ri => {
|
||||
const time = fromEpoch(ri.time_offset);
|
||||
if (time.isAfter(now) && time.isAfter(moment(f.start_time))) {
|
||||
const gracePeriod = now.clone().subtract(1, "minute");
|
||||
if (time.isSameOrAfter(gracePeriod)
|
||||
&& time.isSameOrAfter(moment(f.start_time))) {
|
||||
const oo = occurrence(time, f);
|
||||
const seq = findSequenceById(index, ri.sequence_id);
|
||||
oo.heading = f.executable.name;
|
||||
|
@ -58,6 +64,6 @@ export let regimenCalendarAdder = (index: ResourceIndex) =>
|
|||
|
||||
export let addSequenceToCalendar =
|
||||
(f: FarmEventWithSequence, c: Calendar, now = moment()) => {
|
||||
scheduleForFarmEvent(f)
|
||||
scheduleForFarmEvent(f, now)
|
||||
.map(m => c.insert(occurrence(m, f)));
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue