/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.schedassist.model;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import junit.framework.Assert;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.Recur;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.parameter.Cn;
import net.fortuna.ical4j.model.parameter.CuType;
import net.fortuna.ical4j.model.parameter.PartStat;
import net.fortuna.ical4j.model.parameter.Rsvp;
import net.fortuna.ical4j.model.parameter.XParameter;
import net.fortuna.ical4j.model.property.Attendee;
import net.fortuna.ical4j.model.property.RRule;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.schedassist.NullAffiliationSourceImpl;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
/**
* Test bench for {@link VisibleScheduleBuilder}.
*
* @author Nicholas Blair, nblair@doit.wisc.edu
* @version $Id: VisibleScheduleBuilderTest.java 2934 2010-12-09 16:21:58Z npblair $
*/
public class VisibleScheduleBuilderTest {
private Log LOG = LogFactory.getLog(this.getClass());
private DefaultEventUtilsImpl eventUtils = new DefaultEventUtilsImpl(new NullAffiliationSourceImpl());
private VisibleScheduleBuilder builder = new VisibleScheduleBuilder(eventUtils);
static {
// Many of the values in the assertions expect America/Chicago
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
}
private final net.fortuna.ical4j.model.TimeZone americaChicago;
/**
*
* @throws ParseException
*/
public VisibleScheduleBuilderTest() throws ParseException {
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
americaChicago = registry.getTimeZone("America/Chicago");
}
/**
* Assert empty calendar and empty Advising Schedule throw no errors
* @throws Exception
*/
@Test
public void testEmptyCalendar() throws Exception {
Calendar calendar = new Calendar(new ComponentList());
AvailableSchedule schedule = new AvailableSchedule(new TreeSet<AvailableBlock>());
MockScheduleOwner owner = new MockScheduleOwner(new MockCalendarAccount(), 1);
VisibleScheduleBuilder builder = new VisibleScheduleBuilder();
VisibleSchedule newCalendar = builder.calculateVisibleSchedule(new Date(),
DateUtils.addDays(new Date(), 7),
calendar,
schedule,
owner);
Assert.assertEquals(0, newCalendar.getSize());
}
/**
* Create visible schedule for Aug 4 2008.
* Create a calendar with an appointment on Aug 5 2008.
* Send the two into VisibleScheduleBuilder, and assert no conflicts found.
*
* @throws Exception
*/
@Test
public void testCalendarNoConflict() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
// Aug 4 2008 9:30 AM to 3:30 PM
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20080804-0930"), makeDateTime("20080804-1530"));
Set<AvailableBlock> blocks = AvailableBlockBuilder.expand(block, 30);
AvailableSchedule schedule = new AvailableSchedule(blocks);
// Aug 5 2008 10:30 AM to 11:30 AM
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20080805-1030"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new DateTime(makeDateTime("20080805-1130"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart, eventEnd,
"some event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
// week start is Sun Aug 3
VisibleSchedule visibleSchedule = builder.calculateVisibleSchedule(makeDateTime("20080803-0000"),
makeDateTime("20080810-0000"),
new Calendar(components),
schedule,
owner);
ComponentList componentList = visibleSchedule.getCalendar().getComponents(Component.VEVENT);
// there should be 12 events in the result
Assert.assertEquals(12, componentList.size());
Assert.assertEquals(12, visibleSchedule.getFreeCount());
Assert.assertEquals(0, visibleSchedule.getBusyCount());
Assert.assertEquals(0, visibleSchedule.getAttendingCount());
}
/**
*
* @throws Exception
*/
@Test
public void testSimpleConflict() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20091104-0900"), makeDateTime("20091104-1000"));
Set<AvailableBlock> blocks = AvailableBlockBuilder.expand(block, 30);
Assert.assertEquals(2, blocks.size());
AvailableSchedule schedule = new AvailableSchedule(blocks);
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091104-0900"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091104-0930"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"conflict event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
VisibleSchedule visibleSchedule = builder.calculateVisibleSchedule(makeDateTime("20091104-0830"),
makeDateTime("20091104-1030"),
new Calendar(components),
schedule,
owner);
ComponentList componentList = visibleSchedule.getCalendar().getComponents(Component.VEVENT);
// free from 9:30 to 10:30, busy from 10:30 to 11:30, free from 11:30 to 3:30 PM
Assert.assertEquals(2, componentList.size());
Assert.assertEquals(1, visibleSchedule.getFreeCount());
Assert.assertEquals(1, visibleSchedule.getBusyCount());
Assert.assertEquals(0, visibleSchedule.getAttendingCount());
}
/**
*
* @throws Exception
*/
@Test
public void testRecurringConflict() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
SortedSet<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM","10:00 AM", "W", makeDate("20120201"), makeDate("20120307"));
blocks = AvailableBlockBuilder.expand(blocks, 30);
AvailableSchedule schedule = new AvailableSchedule(blocks);
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20120201-0900"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20120201-0930"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"recurring conflict event");
// recur Wed 2/01 through Wed 2/29, leaving 3/07 out of recurrence
Recur recur = new Recur(Recur.WEEKLY, new net.fortuna.ical4j.model.Date(makeDate("20120301")));
RRule rrule = new RRule(recur);
someEvent.getProperties().add(rrule);
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
VisibleSchedule visibleSchedule = builder.calculateVisibleSchedule(makeDate("20120201"),
makeDate("20120308"),
new Calendar(components),
schedule,
owner);
ComponentList componentList = visibleSchedule.getCalendar().getComponents(Component.VEVENT);
// free from 9:30 to 10:30, busy from 10:30 to 11:30, free from 11:30 to 3:30 PM
Assert.assertEquals(12, componentList.size());
Assert.assertEquals(7, visibleSchedule.getFreeCount());
Assert.assertEquals(5, visibleSchedule.getBusyCount());
Assert.assertEquals(0, visibleSchedule.getAttendingCount());
}
/**
* Create an advising schedule for Aug 4 2008.
* Create a calendar with an appointment on Aug 4 2008.
* Send the two into FreeBusyBuilder, and assert correct conflicts found.
*
* @throws Exception
*/
@Test
public void testOneAppointmentConflictsTwoBlocks() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20091109-0930"), makeDateTime("20091109-1230"));
Set<AvailableBlock> blocks = AvailableBlockBuilder.expand(block, 30);
AvailableSchedule schedule = new AvailableSchedule(blocks);
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091109-1030"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091109-1130"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
VisibleSchedule calendar = builder.calculateVisibleSchedule(makeDateTime("20091109-0000"),
makeDateTime("20091110-0000"),
new Calendar(components),
schedule,
owner);
Assert.assertEquals(6, calendar.getSize());
Assert.assertEquals(4, calendar.getFreeCount());
Assert.assertEquals(2, calendar.getBusyCount());
for(AvailableBlock busy : calendar.getBusyList()) {
if(!busy.getStartTime().equals(makeDateTime("20091109-1030"))
&& !busy.getStartTime().equals(makeDateTime("20091109-1100"))
) {
Assert.fail("busyEvents contains unexpected block " + busy);
}
}
}
/**
* Same test as testCalendarConflict1, however all dates are incremented by 1.
* Week start (argument to {@link VisibleScheduleBuilder} constructor) is set to Mon Aug 4.
*
* @throws Exception
*/
@Test
public void testCalendarConflictShiftWeekStart() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
// Aug 5 2008 9:30 AM to 3:30 PM
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20080805-0930"), makeDateTime("20080805-1530"));
Set<AvailableBlock> blocks = AvailableBlockBuilder.expand(block, 30);
AvailableSchedule schedule = new AvailableSchedule(blocks);
// Aug 5 2008 10:30 AM to 11:30 AM
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20080805-1030"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20080805-1130"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
// week start is Mon Aug 4!
VisibleSchedule calendar = builder.calculateVisibleSchedule(makeDateTime("20080804-0000"),
makeDateTime("20080810-0000"),
new Calendar(components),
schedule,
owner);
ComponentList componentList = calendar.getCalendar().getComponents(Component.VEVENT);
// free from 9:30 to 10:30, busy from 10:30 to 11:30, free from 11:30 to 3:30 PM
Assert.assertEquals(12, componentList.size());
Assert.assertEquals(10, calendar.getFreeCount());
Assert.assertEquals(2, calendar.getBusyCount());
Assert.assertEquals(0, calendar.getAttendingCount());
// 9-9:30 AM, 9:30-10 AM, 10-10:30 AM should be "free"
// 10:30-11 AM and 11-11:30AM should be "busy"
// 11:30 AM on should be free
for(AvailableBlock busy : calendar.getBusyList()) {
if(!busy.getStartTime().equals(makeDateTime("20080805-1030"))
&& !busy.getStartTime().equals(makeDateTime("20080805-1100"))
) {
Assert.fail("busyEvents contains startdate of " + busy.getStartTime());
}
}
}
/**
*
* @throws Exception
*/
@Test
public void testFindAttending() throws Exception {
// construct visitor
MockCalendarAccount person1 = new MockCalendarAccount();
person1.setEmailAddress("somevisitor@wisc.edu");
person1.setDisplayName("Some Visitor");
MockScheduleVisitor visitor = new MockScheduleVisitor(person1);
// construct owner
MockCalendarAccount person2 = new MockCalendarAccount();
person2.setEmailAddress("someowner@wisc.edu");
person2.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person2, 1);
// Aug 4 2008 9:30 AM to 3:30 PM
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20080804-0930"), makeDateTime("20080804-1530"));
Set<AvailableBlock> blocks = AvailableBlockBuilder.expand(block, 30);
AvailableSchedule schedule = new AvailableSchedule(blocks);
// some other non-available appointment Aug 4 2008 10:30 AM to 11:30 AM
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20080804-1030"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20080804-1130"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person2.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person2.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
// make available appointment with visitor from 1:00 PM to 1:30 PM
VEvent availableAppointment = this.eventUtils.constructAvailableAppointment(
AvailableBlockBuilder.createBlock(makeDateTime("20080804-1300"), makeDateTime("20080804-1330")),
owner, visitor, "advising appt");
components.add(availableAppointment);
// week start is Sun Aug 3
VisibleSchedule calendar = this.builder.calculateVisibleSchedule(makeDateTime("20080803-0000"),
makeDateTime("20080810-0000"),
new Calendar(components),
schedule,
owner,
visitor);
ComponentList componentList = calendar.getCalendar().getComponents(Component.VEVENT);
// free from 9:30 to 10:30, busy from 10:30 to 11:30, free from 11:30 to 1:00 PM, student appt from 1-1:30 PM, free to 3:30 PM
Assert.assertEquals(12, componentList.size());
// 9-9:30 AM, 9:30-10 AM, 10-10:30 AM should be "free"
// 10:30-11 AM and 11-11:30AM should be "busy"
// 11:30 AM on should be free
Assert.assertEquals(9, calendar.getFreeCount());
Assert.assertEquals(2, calendar.getBusyCount());
for(AvailableBlock busy : calendar.getBusyList()) {
if(!busy.getStartTime().equals(makeDateTime("20080804-1030"))
&& !busy.getStartTime().equals(makeDateTime("20080804-1100"))
) {
Assert.fail("busyEvents contains startdate of " + busy.getStartTime());
}
}
Assert.assertEquals(1, calendar.getAttendingCount());
AvailableBlock attendingEvent = calendar.getAttendingList().get(0);
Assert.assertEquals(attendingEvent.getStartTime(), makeDateTime("20080804-1300"));
Assert.assertEquals(attendingEvent.getEndTime(), makeDateTime("20080804-1330"));
}
/**
*
* @throws Exception
*/
@Test
public void testAlternateMeetingDurations() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
// 4 week available schedule
Set<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM",
"12:00 PM",
"MRF",
makeDateTime("20091102-0000"),
makeDateTime("20091127-0000"),
1,
null);
TreeSet<AvailableBlock> expanded = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 30));
//Assert.assertEquals(72, expanded.size());
LOG.info("expanded set first: " + expanded.first() + ", last: " + expanded.last());
AvailableSchedule schedule = new AvailableSchedule(expanded);
// event conflict is thursday of 2nd week
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091112-0930"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091112-1030"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some event");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
VisibleSchedule visible = this.builder.calculateVisibleSchedule(
makeDateTime("20091102-0000"),
makeDateTime("20091130-0000"),
new Calendar(components),
schedule,
owner);
Assert.assertEquals(2, visible.getBusyCount());
Assert.assertEquals(70, visible.getFreeCount());
Assert.assertEquals(72, visible.getSize());
owner.setPreference(Preferences.DURATIONS, MeetingDurations.FIFTEEN.getKey());
TreeSet<AvailableBlock> expanded2 = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 15));
VisibleSchedule visible2 = this.builder.calculateVisibleSchedule(
makeDateTime("20091102-0000"),
makeDateTime("20091130-0000"),
new Calendar(components),
new AvailableSchedule(expanded2),
owner);
Assert.assertEquals(4, visible2.getBusyCount());
Assert.assertEquals(140, visible2.getFreeCount());
Assert.assertEquals(144, visible2.getSize());
owner.setPreference(Preferences.DURATIONS, MeetingDurations.FORTYFIVE.getKey());
TreeSet<AvailableBlock> expanded3 = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 45));
VisibleSchedule visible3 = this.builder.calculateVisibleSchedule(
makeDateTime("20091102-0000"),
makeDateTime("20091130-0000"),
new Calendar(components),
new AvailableSchedule(expanded3),
owner);
Assert.assertEquals(2, visible3.getBusyCount());
Assert.assertEquals(46, visible3.getFreeCount());
Assert.assertEquals(48, visible3.getSize());
}
/**
*
* @throws Exception
*/
@Test
public void testConflictEventShorterThanPreferredDuration() throws Exception {
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("someowner@wisc.edu");
person.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person, 1);
Set<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM",
"12:00 PM",
"TW",
makeDateTime("20091103-0000"),
makeDateTime("20091105-0000"),
1,
null);
Assert.assertEquals(2, blocks.size());
AvailableSchedule schedule = new AvailableSchedule(blocks);
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091103-1000"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20091103-1030"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some conflicting appointment");
ParameterList parameterList = new ParameterList();
parameterList.add(PartStat.ACCEPTED);
parameterList.add(CuType.INDIVIDUAL);
parameterList.add(Rsvp.FALSE);
parameterList.add(new Cn(person.getDisplayName()));
Attendee attendee = new Attendee(parameterList, "mailto:" + person.getEmailAddress());
someEvent.getProperties().add(attendee);
ComponentList components = new ComponentList();
components.add(someEvent);
owner.setPreference(Preferences.DURATIONS, MeetingDurations.FORTYFIVE.getKey());
VisibleSchedule visible =this.builder.calculateVisibleSchedule(makeDateTime("20091102-0000"),
makeDateTime("20091106-1600"),
new Calendar(components),
schedule,
owner);
Assert.assertEquals(8, visible.getSize());
Assert.assertEquals(1, visible.getBusyCount());
Assert.assertEquals(7, visible.getFreeCount());
AvailableBlock busyBlock = visible.getBusyList().get(0);
Assert.assertEquals(makeDateTime("20091103-0945"), busyBlock.getStartTime());
Assert.assertEquals(makeDateTime("20091103-1030"), busyBlock.getEndTime());
}
/**
* Verify that start and end times of blocks stay consistent for calculateVisibleSchedule.
*
* @throws Exception
*/
@Test
public void testOffsetStart() throws Exception {
Set<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM",
"1:00 PM",
"MWF",
makeDateTime("20090720-0000"),
makeDateTime("20090725-0000"),
1,
null);
TreeSet<AvailableBlock> expanded = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 30));
Assert.assertEquals(makeDateTime("20090720-0900"), expanded.first().getStartTime());
Assert.assertEquals(makeDateTime("20090720-0930"), expanded.first().getEndTime());
Assert.assertEquals(makeDateTime("20090724-1230"), expanded.last().getStartTime());
Assert.assertEquals(makeDateTime("20090724-1300"), expanded.last().getEndTime());
AvailableSchedule schedule = new AvailableSchedule(expanded);
Calendar emptyCalendar = new Calendar();
MockScheduleOwner owner = new MockScheduleOwner(new MockCalendarAccount(), 1);
owner.setPreference(Preferences.DURATIONS, MeetingDurations.THIRTY.getKey());
VisibleSchedule control = this.builder.calculateVisibleSchedule(
makeDateTime("20090719-0000"),
makeDateTime("20090726-0000"),
emptyCalendar,
schedule,
owner);
Assert.assertEquals(24, control.getFreeCount());
// verify that all the free blocks start on the half hour
SortedMap<AvailableBlock,AvailableStatus> blockMap = control.getBlockMap();
for(Entry<AvailableBlock,AvailableStatus> entry : blockMap.entrySet()) {
if(AvailableStatus.FREE.equals(entry.getValue())) {
AvailableBlock freeBlock = entry.getKey();
java.util.Calendar startTimeCal = java.util.Calendar.getInstance();
startTimeCal.setTime(freeBlock.getStartTime());
Assert.assertTrue(startTimeCal.get(java.util.Calendar.MINUTE) % 30 == 0);
java.util.Calendar endTimeCal = java.util.Calendar.getInstance();
endTimeCal.setTime(freeBlock.getEndTime());
Assert.assertTrue(endTimeCal.get(java.util.Calendar.MINUTE) % 30 == 0);
}
}
// now start the offset in between a block
VisibleSchedule startsInBlock = this.builder.calculateVisibleSchedule(
makeDateTime("20090720-1005"),
makeDateTime("20090727-1005"),
emptyCalendar,
schedule,
owner);
Assert.assertEquals(21, startsInBlock.getFreeCount());
// verify that all the free blocks start on the half hour
SortedMap<AvailableBlock,AvailableStatus> blockMap2 = startsInBlock.getBlockMap();
for(Entry<AvailableBlock,AvailableStatus> entry : blockMap2.entrySet()) {
if(AvailableStatus.FREE.equals(entry.getValue())) {
AvailableBlock freeBlock = entry.getKey();
java.util.Calendar startTimeCal = java.util.Calendar.getInstance();
startTimeCal.setTime(freeBlock.getStartTime());
Assert.assertTrue(startTimeCal.get(java.util.Calendar.MINUTE) % 30 == 0);
java.util.Calendar endTimeCal = java.util.Calendar.getInstance();
endTimeCal.setTime(freeBlock.getEndTime());
Assert.assertTrue(endTimeCal.get(java.util.Calendar.MINUTE) % 30 == 0);
}
}
}
/**
* Same as {@link #testOffsetStart()}, only use 40 minute blocks.
*/
@Test
public void testOffsetStart40() throws Exception {
MeetingDurations fortyMinuteDurations = new MeetingDurations("40", 40, 40);
Set<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM",
"1:00 PM",
"MWF",
makeDateTime("20090720-0000"),
makeDateTime("20090725-0000"),
1,
null);
TreeSet<AvailableBlock> expanded = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 40));
Assert.assertEquals(makeDateTime("20090720-0900"), expanded.first().getStartTime());
Assert.assertEquals(makeDateTime("20090720-0940"), expanded.first().getEndTime());
Assert.assertEquals(makeDateTime("20090724-1220"), expanded.last().getStartTime());
Assert.assertEquals(makeDateTime("20090724-1300"), expanded.last().getEndTime());
AvailableSchedule schedule = new AvailableSchedule(expanded);
Calendar emptyCalendar = new Calendar();
MockScheduleOwner owner = new MockScheduleOwner(new MockCalendarAccount(), 1);
owner.setPreference(Preferences.DURATIONS, fortyMinuteDurations.getKey());
VisibleSchedule control = this.builder.calculateVisibleSchedule(
makeDateTime("20090719-0000"),
makeDateTime("20090726-0000"),
emptyCalendar,
schedule,
owner);
Assert.assertEquals(18, control.getFreeCount());
// verify that all the free blocks start on the twenty minute marks
for(AvailableBlock freeBlock : control.getFreeList()) {
java.util.Calendar startTimeCal = java.util.Calendar.getInstance();
startTimeCal.setTime(freeBlock.getStartTime());
Assert.assertTrue(startTimeCal.get(java.util.Calendar.MINUTE) % 20 == 0);
java.util.Calendar endTimeCal = java.util.Calendar.getInstance();
endTimeCal.setTime(freeBlock.getEndTime());
Assert.assertTrue(endTimeCal.get(java.util.Calendar.MINUTE) % 20 == 0);
}
// now start the offset in between a block
VisibleSchedule startsInBlock = this.builder.calculateVisibleSchedule(
makeDateTime("20090720-1005"),
makeDateTime("20090727-1005"),
emptyCalendar,
schedule,
owner);
Assert.assertEquals(16, startsInBlock.getFreeList().size());
// verify that all the free blocks start on the twenty minute marks
for(AvailableBlock freeBlock : startsInBlock.getFreeList()) {
java.util.Calendar startTimeCal = java.util.Calendar.getInstance();
startTimeCal.setTime(freeBlock.getStartTime());
Assert.assertTrue(startTimeCal.get(java.util.Calendar.MINUTE) % 20 == 0);
java.util.Calendar endTimeCal = java.util.Calendar.getInstance();
endTimeCal.setTime(freeBlock.getEndTime());
Assert.assertTrue(endTimeCal.get(java.util.Calendar.MINUTE) % 20 == 0);
}
}
/**
*
* @throws Exception
*/
@Test
public void testCalculateVisibleScheduleVisitorLimit4WithAttending() throws Exception {
// construct owner
MockCalendarAccount person1 = new MockCalendarAccount();
person1.setEmailAddress("someowner@wisc.edu");
person1.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person1, 1);
MockCalendarAccount person2 = new MockCalendarAccount();
person2.setEmailAddress("somevisitor@wisc.edu");
person2.setDisplayName("Some Visitor");
MockScheduleVisitor visitor = new MockScheduleVisitor(person2);
final Date targetMeetingStart = makeDateTime("20091117-1300");
final Date targetMeetingEnd = makeDateTime("20091117-1330");
VEvent availableAppointment = this.eventUtils.constructAvailableAppointment(
AvailableBlockBuilder.createBlock(targetMeetingStart, targetMeetingEnd, 4),
owner,
visitor,
"test event description");
ComponentList components = new ComponentList();
components.add(availableAppointment);
Calendar calendar = new Calendar(components);
SortedSet<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("1:00 PM", "2:00 PM", "TR",
makeDateTime("20091115-0000"),
makeDateTime("20091121-0000"),
4,
null);
AvailableSchedule schedule = new AvailableSchedule(blocks);
VisibleSchedule visibleSchedule = this.builder.calculateVisibleSchedule(
makeDateTime("20091115-0000"),
makeDateTime("20091121-0000"),
calendar,
schedule,
owner,
visitor);
Assert.assertNotNull(visibleSchedule);
// verify attending shows up
List<AvailableBlock> visitor1AttendingList = visibleSchedule.getAttendingList();
Assert.assertEquals(1, visitor1AttendingList.size());
AvailableBlock visitor1Block = visitor1AttendingList.get(0);
Assert.assertEquals(targetMeetingStart, visitor1Block.getStartTime());
Assert.assertEquals(targetMeetingEnd, visitor1Block.getEndTime());
Assert.assertEquals(AvailableStatus.ATTENDING, visibleSchedule.getBlockMap().get(visitor1Block));
// construct 2nd visitor
MockCalendarAccount person3 = new MockCalendarAccount();
person3.setEmailAddress("othervisitor@wisc.edu");
person3.setDisplayName("Other Visitor");
MockScheduleVisitor visitor2 = new MockScheduleVisitor(person3);
VisibleSchedule visibleSchedule2 = this.builder.calculateVisibleSchedule(
makeDateTime("20091115-0000"),
makeDateTime("20091121-0000"),
calendar,
schedule,
owner,
visitor2);
// visibleSchedule2 should show the Tue Nov 17 1:00 PM slot as FREE, but with 1 spot taken
Assert.assertEquals(0, visibleSchedule2.getAttendingCount());
List<AvailableBlock> visitor2FreeList = visibleSchedule2.getFreeList();
for(AvailableBlock visitor2Block : visitor2FreeList) {
if(visitor2Block.getStartTime().equals(targetMeetingStart) &&
visitor2Block.getEndTime().equals(targetMeetingEnd)) {
Assert.assertEquals(1, visitor2Block.getVisitorsAttending());
} else {
Assert.assertEquals(0, visitor2Block.getVisitorsAttending());
}
Assert.assertEquals(4, visitor2Block.getVisitorLimit());
Assert.assertEquals(AvailableStatus.FREE, visibleSchedule2.getBlockMap().get(visitor2Block));
}
}
/**
*
* @throws Exception
*/
@Test
public void testOddAppointmentMultipleAttendees() throws Exception {
Set<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("9:00 AM",
"12:00 PM",
"MTRF",
makeDateTime("20090202-0830"),
makeDateTime("20090206-1600"),
1,
null);
TreeSet<AvailableBlock> expanded = new TreeSet<AvailableBlock>(AvailableBlockBuilder.expand(blocks, 45));
LOG.info("expanded set first: " + expanded.first() + ", last: " + expanded.last());
AvailableSchedule schedule = new AvailableSchedule(expanded);
DateTime eventStart = new net.fortuna.ical4j.model.DateTime(makeDateTime("20090203-1000"));
eventStart.setTimeZone(americaChicago);
DateTime eventEnd = new net.fortuna.ical4j.model.DateTime(makeDateTime("20090203-1030"));
eventEnd.setTimeZone(americaChicago);
VEvent someEvent = new VEvent(eventStart,
eventEnd,
"some conflicting appointment");
Attendee attendee = new Attendee();
attendee.setValue("mailto:person@domain.edu");
attendee.getParameters().add(new XParameter("X-ORACLE-SHOWASFREE", "FREE"));
attendee.getParameters().add(new Cn("GIVEN SURNAME"));
Attendee attendee2 = new Attendee();
attendee2.setValue("mailto:person2@domain.edu");
attendee2.getParameters().add(new Cn("GIVEN2 SURNAME2"));
someEvent.getProperties().add(attendee);
someEvent.getProperties().add(attendee2);
ComponentList components = new ComponentList();
components.add(someEvent);
MockCalendarAccount person1 = new MockCalendarAccount();
person1.setEmailAddress("someowner@wisc.edu");
person1.setDisplayName("Some Owner");
MockScheduleOwner owner = new MockScheduleOwner(person1, 1);
owner.setPreference(Preferences.DURATIONS, MeetingDurations.FORTYFIVE.getKey());
VisibleSchedule visible = this.builder.calculateVisibleSchedule(makeDateTime("20090202-0830"),
makeDateTime("20090206-1600"),
new Calendar(components),
schedule,
owner);
Assert.assertEquals(16, visible.getSize());
List<AvailableBlock> free = visible.getFreeList();
Assert.assertEquals(16, free.size());
List<AvailableBlock> busy = visible.getBusyList();
Assert.assertEquals(0, busy.size());
}
/**
* Simulates the following scenario:
* <ul>
* <li>IScheduleOwner (owner1) has empty available schedule.</li>
* <li>IScheduleOwner's (owner1) calendar agenda has an available appointment, but the owner is a visitor to someone else's agenda (person1 is visitor to owner2).</li>
* </ul>
* @throws Exception
*/
@Test
public void testVisibleScheduleCalendarHasAvailableAppointmentVisitor() throws Exception {
AvailableSchedule emptyAvailableSchedule = new AvailableSchedule(new TreeSet<AvailableBlock>());
MockCalendarAccount person1 = new MockCalendarAccount();
person1.setEmailAddress("someowner@wisc.edu");
person1.setDisplayName("Some Owner");
MockScheduleOwner owner1 = new MockScheduleOwner(person1, 1);
MockScheduleVisitor visitor1 = new MockScheduleVisitor(person1);
MockCalendarAccount person2 = new MockCalendarAccount();
person2.setEmailAddress("someotherowner@wisc.edu");
person2.setDisplayName("Some Other Owner");
MockScheduleOwner owner2 = new MockScheduleOwner(person2, 2);
AvailableBlock block = AvailableBlockBuilder.createBlock(makeDateTime("20100911-0646"), makeDateTime("20100911-0701"), 3);
VEvent event = this.eventUtils.constructAvailableAppointment(block, owner2, visitor1, "test appointment");
ComponentList components = new ComponentList();
components.add(event);
Calendar owner1Calendar = new Calendar(components);
MockCalendarAccount person3 = new MockCalendarAccount();
person3.setEmailAddress("unsuspecting-visitor@wisc.edu");
person3.setDisplayName("Unsuspecting Visitor");
MockScheduleVisitor visitor3 = new MockScheduleVisitor(person3);
VisibleSchedule visibleSchedule = this.builder.calculateVisibleSchedule(makeDateTime("20100910-1200"),
makeDateTime("20100917-1200"),
owner1Calendar, emptyAvailableSchedule, owner1, visitor3);
Assert.assertEquals(0, visibleSchedule.getAttendingCount());
Assert.assertEquals(0, visibleSchedule.getBusyCount());
Assert.assertEquals(0, visibleSchedule.getFreeCount());
}
/**
*
* @throws ParseException
* @throws IOException
* @throws ParserException
* @throws InputFormatException
*/
@Test
public void testVisitorConflictsMisaligned() throws ParseException, IOException, ParserException, InputFormatException {
InputStream calendarData = new ClassPathResource("org/jasig/schedassist/model/misaligned-conflicts-test.ics").getInputStream();
Assert.assertNotNull(calendarData);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(calendarData);
Date startTime = makeDateTime("20101118-0000");
Date endTime = makeDateTime("20101121-0000");
SortedSet<AvailableBlock> blocks = AvailableBlockBuilder.createBlocks("10:00 AM", "3:00 PM", "F", startTime, endTime,
1,
null);
AvailableSchedule schedule = new AvailableSchedule(blocks);
MockCalendarAccount person = new MockCalendarAccount();
person.setEmailAddress("mesdjian@wisctest.wisc.edu");
person.setDisplayName("ARA MESDJIAN");
MockScheduleVisitor visitor = new MockScheduleVisitor(person);
VisibleSchedule visibleSchedule = this.builder.calculateVisitorConflicts(startTime, endTime, calendar, schedule, MeetingDurations.fromKey("17"), visitor);
Assert.assertEquals(3, visibleSchedule.getBusyCount());
List<AvailableBlock> busyBlocks = visibleSchedule.getBusyList();
Assert.assertTrue(busyBlocks.contains(AvailableBlockBuilder.createBlock(makeDateTime("20101119-1324"), makeDateTime("20101119-1341"))));
Assert.assertTrue(busyBlocks.contains(AvailableBlockBuilder.createBlock(makeDateTime("20101119-1341"), makeDateTime("20101119-1358"))));
Assert.assertTrue(busyBlocks.contains(AvailableBlockBuilder.createBlock(makeDateTime("20101119-1358"), makeDateTime("20101119-1415"))));
}
/**
* helper method to create java.util.Date objects from a String
*
* @param dateTimePhrase format is "yyyyMMdd-HHmm"
* @return
* @throws ParseException
*/
private Date makeDateTime(String dateTimePhrase) throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-HHmm");
dateFormat.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
Date time = dateFormat.parse(dateTimePhrase);
return time;
}
/**
* helper method to create java.util.Date objects from a String
*
* @param datePhrase format is "yyyyMMdd"
* @return
* @throws ParseException
*/
private Date makeDate(String datePhrase) throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
dateFormat.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
Date time = dateFormat.parse(datePhrase);
return time;
}
}