Java tutorial
/******************************************************************************* * Copyright (c) 2014 Whizzo Software, LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package com.whizzosoftware.hobson.scheduler.ical; import com.whizzosoftware.hobson.api.action.MockActionManager; import com.whizzosoftware.hobson.scheduler.executor.MockScheduledTaskExecutor; import com.whizzosoftware.hobson.scheduler.util.DateHelper; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.component.VEvent; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONTokener; import org.junit.Test; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import java.io.*; import java.util.TimeZone; public class ICalTaskProviderTest { @Test public void testloadCalendarWithNoExecutor() { ICalTaskProvider scheduler = new ICalTaskProvider("pluginId", null, null); String s = ""; try { scheduler.loadICSStream(new ByteArrayInputStream(s.getBytes()), System.currentTimeMillis()); fail("Should have thrown an exception"); } catch (Exception e) { } } @Test public void testEmptyCalendarFile() throws Exception { File sfile = File.createTempFile("hobsonschedule", ".ics"); sfile.delete(); try { ICalTaskProvider scheduler = new ICalTaskProvider("pluginId", null, null); scheduler.setScheduleExecutor(new MockScheduledTaskExecutor()); scheduler.setScheduleFile(sfile); } finally { sfile.delete(); } } @Test public void testClearAllTasks() throws Exception { TimeZone tz = TimeZone.getTimeZone("GMT"); MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); // make sure executor has no delays already set assertFalse(executor.hasDelays()); String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20130714T170000Z\n" + "DTEND:20130714T170000Z\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'foo'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; long startOfDay = DateHelper.getTime(tz, 2013, 7, 14, 0, 0, 0); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), startOfDay); // confirm executor has a delay assertTrue(executor.hasDelays()); s.clearAllTasks(); // confirm executor has no delays assertFalse(executor.hasDelays()); } @Test public void testLoadScheduleWithSingleEvent() throws Exception { TimeZone tz = TimeZone.getTimeZone("GMT"); String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20130714T170000Z\n" + "DTEND:20130714T170000Z\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'foo'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // assert what happens the day OF the event long startOfDay = DateHelper.getTime(tz, 2013, 7, 14, 0, 0, 0); MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), startOfDay); // verify task was created assertEquals(1, s.getTasks().size()); ICalTask t = (ICalTask) s.getTasks().iterator().next(); assertEquals("My Task", t.getName()); // verify task was scheduled -- should have been scheduled to execute in 61200 seconds (17 hours) assertEquals(61200000, (long) executor.getDelayForTask(t)); // assert what happens the day AFTER the event startOfDay = DateHelper.getTime(tz, 2013, 7, 15, 0, 0, 0); executor.clearDelays(); s.resetForNewDay(startOfDay); // verify the task was created but not scheduled assertEquals(1, s.getTasks().size()); // verify task was not scheduled assertFalse(executor.isTaskScheduled((ICalTask) s.getTasks().iterator().next())); assertFalse(executor.hasDelays()); assertNull(executor.getDelayForTask(t)); } @Test public void testEditEvent() throws Exception { File file = File.createTempFile("hob", ".ics"); try { String ical = "BEGIN:VCALENDAR\n" + "PRODID:-//Whizzo Software//Hobson 1.0//EN\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20130714T170000Z\n" + "DTEND:20130714T170000Z\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'foo'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; String ical2 = "BEGIN:VCALENDAR\n" + "PRODID:-//Whizzo Software//Hobson 1.0//EN\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20130714T170000Z\n" + "DTEND:20130714T170000Z\n" + "SUMMARY:My Edited Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Edited Action','properties':{'message':'foobar'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // write out ICS to temp file FileWriter fw = new FileWriter(file); fw.append(ical); fw.close(); ICalTaskProvider p = new ICalTaskProvider("pluginId", null, null, TimeZone.getTimeZone("America/Denver")); p.setScheduleExecutor(new MockScheduledTaskExecutor()); p.setScheduleFile(file); p.start(); // make sure the task was created assertEquals(1, p.getTasks().size()); // create task JSON JSONObject json = new JSONObject(); json.put("name", "My Edited Task"); JSONArray conds = new JSONArray(); json.put("conditions", conds); JSONObject cond = new JSONObject(); conds.put(cond); cond.put("start", "20130714T170000Z"); JSONArray actions = new JSONArray(); json.put("actions", actions); JSONObject action = new JSONObject(); actions.put(action); action.put("pluginId", "com.whizzosoftware.hobson.server-api"); action.put("actionId", "log"); action.put("name", "My Edited Action"); JSONObject props = new JSONObject(); action.put("properties", props); props.put("message", "foobar"); // update the task p.updateTask("15dee4fe-a841-4cf6-8d7f-76c3ad5492b1", json); assertTrue(file.exists()); // read back file Calendar cal = new CalendarBuilder().build(new FileInputStream(file)); assertEquals(1, cal.getComponents().size()); VEvent c = (VEvent) cal.getComponents().get(0); assertEquals("My Edited Task", c.getProperty("SUMMARY").getValue()); assertEquals("15dee4fe-a841-4cf6-8d7f-76c3ad5492b1", c.getProperty("UID").getValue()); assertEquals("20130714T170000Z", c.getProperty("DTSTART").getValue()); JSONArray aj = new JSONArray(new JSONTokener(c.getProperty("COMMENT").getValue())); assertEquals(1, aj.length()); JSONObject cj = aj.getJSONObject(0); assertEquals("com.whizzosoftware.hobson.server-api", cj.getString("pluginId")); assertEquals("My Edited Action", cj.getString("name")); assertEquals("log", cj.getString("actionId")); assertTrue(cj.has("properties")); JSONObject pj = cj.getJSONObject("properties"); assertEquals("foobar", pj.getString("message")); } finally { file.delete(); } } @Test public void testLoadScheduleWithSingleEventWithSunsetOffset() throws Exception { TimeZone tz = TimeZone.getTimeZone("America/Denver"); String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20141018T000000\n" + "SUMMARY:My Task\n" + "X-SUN-OFFSET: SS30\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'foo'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; long startOfDay = DateHelper.getTime(tz, 2014, 10, 18, 0, 0, 0); MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setLatitudeLongitude(39.3722, -104.8561); s.setScheduleExecutor(executor); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), startOfDay); // verify task was created assertEquals(1, s.getTasks().size()); ICalTask t = (ICalTask) s.getTasks().iterator().next(); assertEquals("My Task", t.getName()); // verify task was scheduled -- should have been scheduled to execute in 61200 seconds (17 hours) assertEquals(67560000, (long) executor.getDelayForTask(t)); } @Test public void testDayReset() throws Exception { TimeZone tz = TimeZone.getTimeZone("GMT"); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T090000Z\n" + "RRULE:FREQ=DAILY\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; long schedulerStart = DateHelper.getTime(tz, 2014, 7, 1, 8, 0, 0); MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionContext = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.setActionManager(actionContext); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), schedulerStart); // verify task was created but not run assertEquals(1, s.getTasks().size()); assertEquals(0, actionContext.getLogCalls()); // reload the file at midnight s.resetForNewDay(DateHelper.getTime(tz, 2014, 7, 2, 0, 0, 0)); // verify task was created but not executed assertEquals(1, s.getTasks().size()); assertEquals(0, actionContext.getLogCalls()); } @Test public void testDelayedDayReset() throws Exception { TimeZone tz = TimeZone.getDefault(); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T000000\n" + "RRULE:FREQ=DAILY\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // start the scheduler after the task should have run MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionManager = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.setActionManager(actionManager); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 7, 1, 17, 0, 0)); // verify task was not scheduled assertEquals(1, s.getTasks().size()); assertFalse(executor.isTaskScheduled((ICalTask) s.getTasks().iterator().next())); assertEquals(0, actionManager.getLogCalls()); // start a new day 30 seconds after midnight -- this covers the corner case where a delay causes the // resetForNewDay() method to get fired slightly after midnight and there are tasks that should have // already executed by then s.resetForNewDay(DateHelper.getTime(tz, 2014, 7, 2, 0, 0, 30)); // verify task was not scheduled but task executed assertEquals(1, s.getTasks().size()); ICalTask task = (ICalTask) s.getTasks().iterator().next(); assertFalse(executor.isTaskScheduled(task)); assertEquals(1404367200000l, task.getProperties().get(ICalTask.PROP_NEXT_RUN_TIME)); assertFalse((boolean) task.getProperties().get(ICalTask.PROP_SCHEDULED)); assertEquals(1, actionManager.getLogCalls()); } @Test public void testDayResetWithSolarOffsetTask() throws Exception { TimeZone tz = TimeZone.getDefault(); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T000000\n" + "RRULE:FREQ=DAILY\n" + "X-SUN-OFFSET:SS30\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // start the scheduler after the task should have run MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionManager = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setLatitudeLongitude(39.3722, -104.8561); s.setScheduleExecutor(executor); s.setActionManager(actionManager); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 7, 1, 22, 0, 0)); // verify task was not scheduled or executed assertEquals(1, s.getTasks().size()); ICalTask t = (ICalTask) s.getTasks().iterator().next(); assertFalse(executor.isTaskScheduled(t)); assertEquals(0, actionManager.getLogCalls()); assertNull(t.getProperties().getProperty(ICalTask.PROP_NEXT_RUN_TIME)); // start a new day at midnight s.resetForNewDay(DateHelper.getTime(tz, 2014, 7, 2, 0, 0, 0)); // verify task was scheduled at appropriate time and task did not execute assertEquals(1, s.getTasks().size()); t = (ICalTask) s.getTasks().iterator().next(); assertTrue(executor.isTaskScheduled(t)); assertEquals(75600000, (long) executor.getDelayForTask(t)); assertEquals(0, actionManager.getLogCalls()); assertEquals(1404356400000l, t.getProperties().get(ICalTask.PROP_NEXT_RUN_TIME)); assertTrue((boolean) t.getProperties().get(ICalTask.PROP_SCHEDULED)); } @Test public void testMonthlyNextRun() throws Exception { TimeZone tz = TimeZone.getDefault(); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T220000\n" + "RRULE:FREQ=MONTHLY\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // start the scheduler when the task should have run MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionManager = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.setActionManager(actionManager); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 7, 1, 23, 0, 0)); // verify task was created and its next run time assertEquals(1, s.getTasks().size()); ICalTask task = (ICalTask) s.getTasks().iterator().next(); assertEquals(1406952000000l, task.getProperties().get(ICalTask.PROP_NEXT_RUN_TIME)); } @Test public void testYearlyNextRun() throws Exception { TimeZone tz = TimeZone.getDefault(); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T220000\n" + "RRULE:FREQ=YEARLY\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // start the scheduler when the task should have run MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionManager = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.setActionManager(actionManager); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 8, 1, 21, 0, 0)); // verify task was created and its next run time assertEquals(1, s.getTasks().size()); ICalTask task = (ICalTask) s.getTasks().iterator().next(); assertEquals(1435809600000l, task.getProperties().get(ICalTask.PROP_NEXT_RUN_TIME)); } @Test public void testTaskRescheduling() throws Exception { TimeZone tz = TimeZone.getTimeZone("GMT"); // an event that runs every minute String ical = "BEGIN:VCALENDAR\n" + "PRODID:-//Whizzo Software//Hobson 1.0//EN\n" + "VERSION:2.0\n" + "CALSCALE:GREGORIAN\n" + "BEGIN:VJOURNAL\n" + "DTSTAMP:20140701T044038Z\n" + "DTSTART;VALUE=DATE:20140701\n" + "SUMMARY:Created\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "END:VJOURNAL\n" + "BEGIN:VEVENT\n" + "DTSTART:20140701T100000Z\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "RRULE:FREQ=MINUTELY;INTERVAL=1\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Testing!'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR\n"; MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionContext = new MockActionManager(); ICalTaskProvider scheduler = new ICalTaskProvider("pluginId", null, null, tz); scheduler.setScheduleExecutor(executor); scheduler.setActionManager(actionContext); assertFalse(executor.hasDelays()); scheduler.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 7, 1, 11, 0, 1)); // verify task was created and scheduled assertEquals(1, scheduler.getTasks().size()); ICalTask task = (ICalTask) scheduler.getTasks().iterator().next(); assertEquals(0, actionContext.getLogCalls()); assertTrue(executor.hasDelays()); assertEquals(59000, (long) executor.getDelayForTask(task)); // force task to fire executor.clearDelays(); scheduler.onTaskExecuted(task, DateHelper.getTime(tz, 2014, 7, 1, 11, 1, 0), true); // verify that task was scheduled again assertTrue(executor.hasDelays()); assertEquals(60000, (long) executor.getDelayForTask(task)); } @Test public void testSunOffsetWithNoLatLong() throws Exception { TimeZone tz = TimeZone.getDefault(); // an event that runs every day at midnight String ical = "BEGIN:VCALENDAR\n" + "VERSION:2.0\n" + "BEGIN:VEVENT\n" + "UID:15dee4fe-a841-4cf6-8d7f-76c3ad5492b1\n" + "DTSTART:20140701T000000\n" + "RRULE:FREQ=DAILY\n" + "X-SUN-OFFSET:SS30\n" + "SUMMARY:My Task\n" + "COMMENT:[{'pluginId':'com.whizzosoftware.hobson.server-api','actionId':'log','name':'My Action','properties':{'message':'Test'}}]\n" + "END:VEVENT\n" + "END:VCALENDAR"; // start the scheduler after the task should have run MockScheduledTaskExecutor executor = new MockScheduledTaskExecutor(); MockActionManager actionManager = new MockActionManager(); ICalTaskProvider s = new ICalTaskProvider("pluginId", null, null, tz); s.setScheduleExecutor(executor); s.setActionManager(actionManager); s.loadICSStream(new ByteArrayInputStream(ical.getBytes()), DateHelper.getTime(tz, 2014, 7, 1, 22, 0, 0)); assertEquals(1, s.getTasks().size()); ICalTask t = (ICalTask) s.getTasks().iterator().next(); assertTrue(t.getProperties().containsKey(ICalTask.PROP_ERROR)); } }