View Javadoc
1   /*
2    * Copyright (C) 2012 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 2.1 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.calendar.service.test;
20  
21  import javax.jcr.query.Query;
22  
23  import java.text.DateFormat;
24  import java.text.SimpleDateFormat;
25  import java.util.*;
26  
27  import org.exoplatform.calendar.service.*;
28  import org.exoplatform.calendar.service.Calendar;
29  import org.exoplatform.calendar.service.impl.CalendarSearchServiceConnector;
30  import org.exoplatform.calendar.service.impl.CalendarServiceImpl;
31  import org.exoplatform.calendar.service.impl.JCRDataStorage;
32  import org.exoplatform.calendar.service.impl.UnifiedQuery;
33  import org.exoplatform.commons.api.search.data.SearchResult;
34  import org.exoplatform.commons.utils.DateUtils;
35  
36  public class RecurringEventTestCase extends BaseCalendarServiceTestCase {
37  
38    private JCRDataStorage storage_;
39    private CalendarSearchServiceConnector unifiedSearchService_ ;
40  
41    @Override
42    public void setUp() throws Exception {
43      super.setUp();
44      unifiedSearchService_ = getService(CalendarSearchServiceConnector.class);
45      storage_ = ((CalendarServiceImpl)calendarService_).getDataStorage();
46    }
47  
48    public void testRemoveOccurrenceEvent() throws Exception {
49  
50      CalendarEvent recurEvent = createRepetitiveEventForTest();
51  
52      java.util.Calendar from = java.util.Calendar.getInstance(tz);
53      java.util.Calendar to = java.util.Calendar.getInstance(tz);
54      from.set(2013, 2, 1, 0, 0, 0);
55      to.set(2013, 2, 12, 0, 0, 0);
56  
57      List<CalendarEvent> original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
58      assertEquals(1, original.size());
59  
60      Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
61      assertEquals(5, occMap.size());
62  
63      SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
64      sf.setTimeZone(tz);
65  
66      java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
67      fromCal.setTime(recurEvent.getFromDateTime());
68      fromCal.add(java.util.Calendar.DATE, 1);
69      String recurenceId1 = sf.format(fromCal.getTime());
70  
71      fromCal.add(java.util.Calendar.DATE, 2);
72      String recurrenceId2 = sf.format(fromCal.getTime());
73  
74      CalendarEvent occEvent1 = occMap.get(recurenceId1);
75      CalendarEvent occEvent2 = occMap.get(recurrenceId2);
76      occEvent2.setDescription("newException");
77      calendarService_.saveOneOccurrenceEvent(recurEvent, occEvent2, username);
78      calendarService_.saveOneOccurrenceEvent(recurEvent, occEvent2, username);
79      List<CalendarEvent> exceptionEvents = calendarService_.getExceptionEvents(username, recurEvent);
80      assertEquals(1,exceptionEvents.size());
81      occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
82      assertEquals(4,occMap.size());
83  
84      calendarService_.removeOneOccurrenceEvent(recurEvent, occEvent2, username);
85      occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
86      exceptionEvents = calendarService_.getExceptionEvents(username, recurEvent);
87  
88      assertEquals(4,occMap.size());
89      assertEquals(0,exceptionEvents.size());
90  
91      calendarService_.removeFollowingSeriesEvents(recurEvent, occEvent1, username);
92      occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
93      exceptionEvents = calendarService_.getExceptionEvents(username, recurEvent);
94  
95      assertEquals(1, occMap.size());
96      assertEquals(0, exceptionEvents.size());
97  
98      calendarService_.removeAllSeriesEvents(recurEvent, username);
99      assertNull(calendarService_.getEventById(recurEvent.getId()));
100   }
101 
102   public void testSaveAllOccurrenceEvent() throws Exception {
103 
104     CalendarEvent recurEvent = createRepetitiveEventForTest();
105     
106     java.util.Calendar from = java.util.Calendar.getInstance(tz);
107     java.util.Calendar to = java.util.Calendar.getInstance(tz);
108     from.set(2013, 2, 1, 0, 0, 0);
109     to.set(2013, 2, 12, 0, 0, 0);
110 
111     List<CalendarEvent> original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
112     assertEquals(1, original.size());
113 
114     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
115     assertEquals(5, occMap.size());
116 
117     SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
118     sf.setTimeZone(tz);
119     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
120     fromCal.setTime(recurEvent.getFromDateTime());
121     fromCal.add(java.util.Calendar.DATE, 2);
122     String reocurenceId1 = sf.format(fromCal.getTime());
123     CalendarEvent occEvent1 = occMap.get(reocurenceId1);
124 
125     calendarService_.saveOneOccurrenceEvent(recurEvent, occEvent1, username);
126     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
127     assertEquals(4, occMap.size());
128 
129     recurEvent.setSummary("change and update all");
130     calendarService_.saveAllSeriesEvents(recurEvent, username);
131     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
132     assertEquals(4, occMap.size());
133   }
134 
135   public void testSaveFollowingOccurrenceEvent() throws Exception {
136 
137     CalendarEvent recurEvent = createRepetitiveEventForTest();
138 
139     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
140     fromCal.setTime(recurEvent.getFromDateTime());
141 
142     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
143     toCal.setTime(recurEvent.getToDateTime());
144 
145     java.util.Calendar from = java.util.Calendar.getInstance(tz);
146     java.util.Calendar to = java.util.Calendar.getInstance(tz);
147 
148     from.set(2013, 2, 1, 0, 0, 0);
149     to.set(2013, 2, 12, 0, 0, 0);
150 
151     List<CalendarEvent> original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
152     assertEquals(1, original.size());
153 
154     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
155     assertEquals(5, occMap.size());
156 
157     SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
158     sf.setTimeZone(tz);
159 
160     fromCal.add(java.util.Calendar.DATE, 1);
161     String recurrenceId1 = sf.format(fromCal.getTime());
162 
163     fromCal.add(java.util.Calendar.DATE,2);
164     String recurrenceId2 = sf.format(fromCal.getTime());
165 
166     CalendarEvent occEvent1 = occMap.get(recurrenceId1);
167     CalendarEvent occEvent2 = occMap.get(recurrenceId2);
168 
169     calendarService_.saveOneOccurrenceEvent(recurEvent, occEvent2, username); //break occEvent2 from the series
170     Collection<CalendarEvent> exceptions = calendarService_.getExceptionEvents(username, recurEvent);
171     assertEquals(1,exceptions.size());
172 
173     //create new series starting from occEvent1
174     calendarService_.saveFollowingSeriesEvents(recurEvent, occEvent1, username);
175     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
176     assertEquals(1, occMap.size());
177 
178     occMap = calendarService_.getOccurrenceEvents(occEvent1, from, to, timeZone);
179     assertEquals(4, occMap.size());
180 
181     exceptions = calendarService_.getExceptionEvents(username, recurEvent);
182     assertEquals(0,exceptions.size());//the exception occEvent2 should be removed now
183   }
184 
185   public void testSaveFollowingOccurrenceEventWithChangeTime() throws Exception {
186     CalendarSetting setting = calendarService_.getCalendarSetting(username);
187     setting.setDateFormat("MMddyyyy");
188     setting.setTimeFormat("H:m");
189     calendarService_.saveCalendarSetting(username, setting);
190     setting = calendarService_.getCalendarSetting(username);
191     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
192 
193     Calendar calendar = createPrivateCalendar(username, "testSaveFollowingOccurrenceEventWithChangeTime calendar", "description");
194 
195     String startTime = "05252015 10:00";
196     String endTime = "05252015 11:00";
197     Date start = getDate(setting, startTime);
198     Date end = getDate(setting, endTime);
199 
200     java.util.Calendar from = java.util.Calendar.getInstance();
201     from.setTime(start);
202     from.add(java.util.Calendar.DATE, -2);
203     java.util.Calendar to = java.util.Calendar.getInstance();
204     to.setTime(end);
205     to.add(java.util.Calendar.DATE, 10);
206 
207     // Create recuring event
208     CalendarEvent event = new CalendarEvent();
209     event.setSummary("testSaveFollowingOccurrenceEventWithChangeTime event");
210     event.setFromDateTime(start);
211     event.setToDateTime(end);
212     event.setRepeatType(CalendarEvent.RP_DAILY);
213     event.setRepeatInterval(1);
214     event.setRepeatCount(5);
215     event.setRepeatUntilDate(null);
216     Utils.updateOriginDate(event, userTimezone);
217     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
218     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
219 
220     event = calendarService_.getEvent(username, event.getId());
221 
222     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
223     assertEquals(5, events.size());
224 
225     CalendarEvent occurence = events.get("20150527T100000Z");
226     assertNotNull(occurence);
227 
228     java.util.Calendar newFromCal = java.util.Calendar.getInstance(userTimezone);
229     newFromCal.setTime(occurence.getFromDateTime());
230     java.util.Calendar newToCal = java.util.Calendar.getInstance(userTimezone);
231     newFromCal.setTime(occurence.getToDateTime());
232     newFromCal.add(java.util.Calendar.MINUTE, 30);
233     newToCal.add(java.util.Calendar.MINUTE, 30);
234     occurence.setFromDateTime(newFromCal.getTime());
235     occurence.setToDateTime(newToCal.getTime());
236 
237     calendarService_.saveFollowingSeriesEvents(event, occurence, username);
238 
239     event = calendarService_.getEvent(username, event.getId());
240     occurence = calendarService_.getEvent(username, occurence.getId());
241 
242     events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
243     assertEquals(2, events.size());
244 
245     events = calendarService_.getOccurrenceEvents(occurence, from, to, setting.getTimeZone());
246     assertEquals(3, events.size());
247   }
248 
249   public void testSaveOneOccurrenceEvent() throws Exception {
250 
251     CalendarEvent recurEvent = createRepetitiveEventForTest();
252 
253     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
254     fromCal.setTime(recurEvent.getFromDateTime());
255 
256     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
257     toCal.setTime(recurEvent.getToDateTime());
258 
259     java.util.Calendar from = java.util.Calendar.getInstance(tz);
260     java.util.Calendar to = java.util.Calendar.getInstance(tz);
261 
262     from.set(2013, 2, 1, 0, 0, 0);
263     to.set(2013, 2, 12, 0, 0, 0);
264 
265     List<CalendarEvent> original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
266     assertEquals(1, original.size());
267 
268     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
269     assertEquals(5, occMap.size());   //there are 5 occurrences
270 
271     SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
272     sf.setTimeZone(tz);
273     String recurrenceId1 = sf.format(fromCal.getTime());
274     CalendarEvent occEvent1 = occMap.get(recurrenceId1);
275 
276     fromCal.add(java.util.Calendar.DATE, 1);
277     String recurrenceId2 = sf.format(fromCal.getTime());
278     CalendarEvent occEvent2 = occMap.get(recurrenceId2);
279 
280     Collection<CalendarEvent> list = calendarService_.getExceptionEvents(username,recurEvent);
281     assertEquals(0,list.size());
282 
283     occEvent1.setSummary("broken series event");
284     //breaks 1 from the series
285     calendarService_.saveOneOccurrenceEvent(recurEvent, occEvent1, username);
286     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
287     list = calendarService_.getExceptionEvents(username,recurEvent);
288     assertNotNull(list);
289     assertEquals(1,list.size());
290     assertEquals(4, occMap.size());  //5 - 1
291 
292     //remove 1 occurrence from the series
293     calendarService_.removeOneOccurrenceEvent(recurEvent, occEvent2, username);
294     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
295     assertEquals(3, occMap.size());  //5 - 1 - 1
296 
297     //remove the exception event
298     calendarService_.removeOneOccurrenceEvent(recurEvent, occEvent1, username);
299     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
300     list = calendarService_.getExceptionEvents(username,recurEvent);
301     assertEquals(3, occMap.size());
302     assertEquals(0,list.size());
303   }
304 
305   public void testGetRepetitiveEvent() throws Exception {
306 
307     SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
308     sf.setTimeZone(tz);
309 
310     CalendarEvent recurEvent = createRepetitiveEventForTest();
311 
312     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
313     fromCal.setTime(recurEvent.getFromDateTime());
314 
315     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
316     toCal.setTime(recurEvent.getToDateTime());
317 
318     java.util.Calendar from = java.util.Calendar.getInstance(tz);
319     java.util.Calendar to = java.util.Calendar.getInstance(tz);
320 
321     from.set(2013, 2, 1, 0, 0, 0);
322     to.set(2013, 2, 12, 0, 0, 0);
323 
324     Map<String,CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
325 
326     fromCal.add(java.util.Calendar.DATE, 1);
327     String recurrenceId = sf.format(fromCal.getTime());
328     CalendarEvent occurrence = occMap.get(recurrenceId);
329 
330     //test get origin event from one occurrence
331     CalendarEvent expectedOrigin = calendarService_.getRepetitiveEvent(occurrence);
332     assertNotNull(expectedOrigin);
333     assertEquals(recurEvent.getId(), expectedOrigin.getId());
334 
335     occurrence.setSummary("I'm now an exception");
336     calendarService_.saveOneOccurrenceEvent(recurEvent, occurrence, username);
337 
338     List<CalendarEvent> exceptions = calendarService_.getExceptionEvents(username, recurEvent);
339     assertEquals(1, exceptions.size());
340     CalendarEvent exceptionEvent = exceptions.iterator().next();
341     assertFalse(exceptionEvent.getId() == recurEvent.getId());
342 
343     //test get origin event from an exception event
344     expectedOrigin = calendarService_.getRepetitiveEvent(exceptionEvent);
345     assertNotNull(expectedOrigin);
346     assertEquals(recurEvent.getId(), expectedOrigin.getId());
347   }
348 
349   /**
350    * test case event created at the beginning of the day, so that the date stored
351    * in server is 1 less than the date selected because of different timezones
352    * @since CAL-351
353    * @throws Exception
354    */
355   public void testGetOccurrenceEvents1() throws Exception {
356     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
357     fromCal.set(2013, 2, 7, 5, 30);
358 
359     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
360     toCal.set(2013, 2, 7, 6, 30);
361 
362     Calendar calendar = createPrivateCalendar(username, username, "unified search test");
363     CalendarEvent recurEvent = new CalendarEvent();
364     recurEvent.setSummary("repeated past");
365     recurEvent.setFromDateTime(fromCal.getTime());
366     recurEvent.setToDateTime(toCal.getTime());
367     recurEvent.setRepeatType(CalendarEvent.RP_WEEKLY);
368     String[] days = {"TH"};
369     recurEvent.setRepeatByDay(days);
370     recurEvent.setRepeatUntilDate(null);
371     java.util.Calendar from = java.util.Calendar.getInstance(tz);
372     java.util.Calendar to = java.util.Calendar.getInstance(tz);
373     from.set(2013, 2, 1, 0, 0, 0);
374     to.set(2013, 2, 12, 0, 0, 0);
375 
376     Utils.adaptRepeatRule(recurEvent, tz, CalendarService.PERSISTED_TIMEZONE);
377     calendarService_.saveUserEvent(username, calendar.getId(), recurEvent, true);
378     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
379 
380     assertEquals(1, occMap.size());
381 
382     CalendarEvent occEvent = occMap.get(occMap.keySet().iterator().next());
383     java.util.Calendar occCal = java.util.Calendar.getInstance(tz);
384     occCal.setTime(occEvent.getFromDateTime());
385 
386     assertEquals(occCal.get(java.util.Calendar.DATE), 7);
387     assertEquals(occCal.get(java.util.Calendar.MONTH), 2);
388     assertEquals(occCal.get(java.util.Calendar.YEAR), 2013);
389 
390     EventQuery query = new UnifiedQuery() ;
391     query.setQueryType(Query.SQL);
392     query.setText("past") ;
393     query.setOrderType(Utils.ORDER_TYPE_ASCENDING);
394     query.setOrderBy(new String[]{Utils.ORDERBY_TITLE});
395     Collection<String> params = new ArrayList<String>();
396     Collection<SearchResult> result = unifiedSearchService_.search(null, query.getText(), params, 0, 10, query.getOrderBy()[0] , query.getOrderType());
397     assertNotNull(result) ;
398     assertEquals(1, result.size());
399   }
400 
401   /**
402    * test with big diffrence of timezone, event created at the end of the day
403    * so that the day stored is 1 more than the day selected because of different timezones
404    * @since CAL-386
405    * @throws Exception
406    */
407   public void testGetOccurrenceEvents2() throws Exception {
408     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
409     fromCal.set(2013, 2, 7, 22, 30);
410 
411     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
412     toCal.set(2013, 2, 7, 23, 30);
413 
414     CalendarEvent recurEvent = new CalendarEvent();
415     recurEvent.setFromDateTime(fromCal.getTime());
416     recurEvent.setToDateTime(toCal.getTime());
417     recurEvent.setRepeatType(CalendarEvent.RP_WEEKLY);
418     String[] days = {"TH"};
419     recurEvent.setRepeatByDay(days);
420     recurEvent.setRepeatUntilDate(null);
421 
422     java.util.Calendar from = java.util.Calendar.getInstance(tz);
423     java.util.Calendar to = java.util.Calendar.getInstance(tz);
424     from.set(2013, 2, 1, 0, 0, 0);
425     to.set(2013, 2, 24, 0, 0, 0);
426     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
427 
428     assertEquals(3, occMap.size());
429 
430     SimpleDateFormat format = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
431     format.setTimeZone(tz);
432 
433     assertNotNull(occMap.get(format.format(fromCal.getTime())));
434 
435     fromCal.add(java.util.Calendar.DATE, 7);
436 
437     assertNotNull(occMap.get(format.format(fromCal.getTime())));
438 
439     fromCal.add(java.util.Calendar.DATE, 7);
440 
441     assertNotNull(occMap.get(format.format(fromCal.getTime())));
442 
443   }
444 
445   /**
446    * test duplicate event issue in shared calendar when break occurrence series
447    * @since CAL-358
448    * @throws Exception
449    */
450   public void testGetOccurrenceEvents3() throws Exception {
451 
452     CalendarEvent recurEvent = createRepetitiveEventForTest();
453     Calendar calendar = calendarService_.getCalendarById(recurEvent.getCalendarId());
454     
455     java.util.Calendar from = java.util.Calendar.getInstance(tz);
456     java.util.Calendar to = java.util.Calendar.getInstance(tz);
457     from.set(2013, 2, 1, 0, 0, 0);
458     to.set(2013, 2, 12, 0, 0, 0);
459 
460     List<CalendarEvent> original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
461     assertEquals(1, original.size());
462 
463     Map<String, CalendarEvent> occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
464     assertEquals(5, occMap.size());
465 
466     SimpleDateFormat sf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
467     sf.setTimeZone(tz);
468     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
469     fromCal.setTime(recurEvent.getFromDateTime());
470     String reocurenceId1 = sf.format(fromCal.getTime());
471     CalendarEvent occEvent1 = occMap.get(reocurenceId1);
472 
473     java.util.Calendar occCal = java.util.Calendar.getInstance(tz);
474     occCal.setTime(occEvent1.getFromDateTime());
475 
476     assertEquals(occCal.get(java.util.Calendar.DATE), 7);
477     assertEquals(occCal.get(java.util.Calendar.MONTH), 2);
478     assertEquals(occCal.get(java.util.Calendar.YEAR), 2013);
479 
480     fromCal.add(java.util.Calendar.DATE, 1);
481     String reocurenceId2 = sf.format(fromCal.getTime());
482     CalendarEvent occEvent2 = occMap.get(reocurenceId2);
483     occCal = java.util.Calendar.getInstance(tz);
484     occCal.setTime(occEvent2.getFromDateTime());
485 
486     assertEquals(occCal.get(java.util.Calendar.DATE), 8);
487     assertEquals(occCal.get(java.util.Calendar.MONTH), 2);
488     assertEquals(occCal.get(java.util.Calendar.YEAR), 2013);
489 
490     //Break first event in series and save
491     //set break ID
492 
493     List<CalendarEvent> listEvent = new ArrayList<CalendarEvent>();
494     occEvent1.setIsExceptionOccurrence(true);
495     occEvent1.setSummary("broken series event");
496     occEvent1.setRecurrenceId(reocurenceId1);
497     listEvent.add(occEvent1);
498     calendar.setEditPermission(new String[]{"john", username});
499     calendarService_.saveUserCalendar(username, calendar, false);
500     calendarService_.shareCalendar(username, calendar.getId(), Arrays.asList(new String[]{"john"}));
501     login("john");
502     calendarService_.updateOccurrenceEvent(calendar.getId(), calendar.getId(), String.valueOf(Calendar.TYPE_SHARED), String.valueOf(Calendar.TYPE_SHARED), listEvent, "john");
503     recurEvent.setExcludeId(new String[]{reocurenceId1});
504     calendarService_.saveEventToSharedCalendar("john", calendar.getId(), recurEvent, false);
505 
506     //check occurrences
507     original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
508     assertEquals(1, original.size());
509     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
510     assertEquals(4, occMap.size());
511     listEvent = new ArrayList<CalendarEvent>();
512     occEvent2.setSummary("broken series event 2");
513     occEvent2.setIsExceptionOccurrence(true);
514     occEvent2.setRecurrenceId(reocurenceId2);
515     listEvent.add(occEvent2);
516     calendarService_.updateOccurrenceEvent(calendar.getId(), calendar.getId(), String.valueOf(Calendar.TYPE_SHARED), String.valueOf(Calendar.TYPE_SHARED), listEvent, "john");
517     recurEvent.setExcludeId(new String[]{reocurenceId1, reocurenceId2});
518     calendarService_.saveEventToSharedCalendar("john", calendar.getId(), recurEvent, false);
519 
520     original = calendarService_.getOriginalRecurrenceEvents(username, from, to, null);
521     assertEquals(1, original.size());
522     occMap = calendarService_.getOccurrenceEvents(recurEvent, from, to, timeZone);
523     assertEquals(3, occMap.size());
524   }
525 
526   public void testUpdateRecurrenceSeries() throws Exception {
527     Calendar calendar = createPrivateCalendar(username, "myCalendar", "Description");
528     Calendar publicCalendar = createGroupCalendar(userGroups, "publicCalendar", "publicDescription");
529     
530     EventCategory eventCategory = createUserEventCategory(username, "eventCategoryName0");
531     
532     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
533     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
534     toCal.add(java.util.Calendar.HOUR, 1);
535     java.util.Calendar repeatUntilDate = java.util.Calendar.getInstance(tz);
536     repeatUntilDate.add(java.util.Calendar.DATE, 5);
537     
538     CalendarEvent userEvent = new CalendarEvent();
539     userEvent.setSummary("Have a meeting");
540     userEvent.setFromDateTime(fromCal.getTime());
541     userEvent.setToDateTime(toCal.getTime());
542     userEvent.setCalendarId(calendar.getId());
543     userEvent.setEventCategoryId(eventCategory.getId());
544     userEvent.setRepeatType(CalendarEvent.RP_DAILY);
545     userEvent.setRepeatInterval(2);
546     userEvent.setRepeatCount(3);
547     userEvent.setRepeatUntilDate(repeatUntilDate.getTime());
548     userEvent.setRepeatByDay(null);
549     userEvent.setRepeatByMonthDay(new long[] { 2, 3, 4, 5, 7 });
550     storage_.saveOccurrenceEvent(username, calendar.getId(), userEvent, true);
551     
552     storage_.getOccurrenceEvents(userEvent, fromCal, toCal, timeZone);
553     
554     List<CalendarEvent> listEvent = new ArrayList<CalendarEvent>();
555     listEvent.add(userEvent);
556     storage_.updateOccurrenceEvent(calendar.getId(),
557                                    publicCalendar.getId(),
558                                    String.valueOf(Calendar.TYPE_PRIVATE),
559                                    String.valueOf(Calendar.TYPE_PUBLIC),
560                                    listEvent,
561                                    username);    
562   }
563 
564   public void testCalculateRecurrenceFinishDate() throws Exception {
565     TimeZone timeZone = DateUtils.getTimeZone("GMT");
566     
567     java.util.Calendar fromCal = java.util.Calendar.getInstance(timeZone);
568     fromCal.set(2011, 6, 20, 5, 30);
569     
570     java.util.Calendar toCal = java.util.Calendar.getInstance(timeZone);
571     toCal.set(2011, 6, 25, 5, 30);
572     
573     CalendarEvent userEvent = new CalendarEvent();
574     userEvent.setFromDateTime(fromCal.getTime());
575     userEvent.setToDateTime(toCal.getTime());
576     userEvent.setRepeatType(CalendarEvent.RP_DAILY);
577     userEvent.setRepeatInterval(2);
578     userEvent.setRepeatCount(3);
579     userEvent.setRepeatUntilDate(null);
580     userEvent.setRepeatByDay(null);
581     userEvent.setRepeatByMonthDay(new long[] { 2, 3, 4, 5, 7 });
582     
583     Date date = storage_.calculateRecurrenceFinishDate(userEvent);
584     
585     java.util.Calendar calendar = java.util.Calendar.getInstance(timeZone);
586     calendar.setTime(date);
587     
588     assertEquals(2011, calendar.get(java.util.Calendar.YEAR));
589     assertEquals(6, calendar.get(java.util.Calendar.MONTH));
590     assertEquals(25, calendar.get(java.util.Calendar.DATE));
591     assertEquals(0, calendar.get(java.util.Calendar.HOUR));
592     assertEquals(0, calendar.get(java.util.Calendar.MINUTE));
593   }
594 
595   public void testGetPreviousOccurence() throws  Exception {
596     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
597     fromCal.set(2013, java.util.Calendar.MARCH, 7, 22, 30);
598 
599     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
600     toCal.set(2013, java.util.Calendar.MARCH, 7, 23, 30);
601 
602     CalendarEvent recurEvent = new CalendarEvent();
603     recurEvent.setSummary("test previous");
604     recurEvent.setFromDateTime(fromCal.getTime());
605     recurEvent.setToDateTime(toCal.getTime());
606     recurEvent.setRepeatType(CalendarEvent.RP_DAILY);
607     recurEvent.setRepeatInterval(1);
608     recurEvent.setRepeatCount(6);
609     recurEvent.setRepeatUntilDate(null);
610 
611     java.util.Calendar calendar = java.util.Calendar.getInstance(tz);
612     calendar.set(2013, java.util.Calendar.MARCH, 10, 22, 30);
613     //get occurrence right before 09 Feb
614     Date expectedDate = Utils.getPreviousOccurrenceDate(recurEvent, calendar.getTime(), tz);
615     calendar.setTime(expectedDate);
616     assertEquals(9,calendar.get(java.util.Calendar.DATE));
617 
618     fromCal.set(2013, java.util.Calendar.SEPTEMBER, 10, 22, 30);
619     toCal.set(2013,java.util.Calendar.SEPTEMBER, 10, 23, 30);
620     recurEvent.setRepeatType(CalendarEvent.RP_WEEKLY);
621     recurEvent.setFromDateTime(fromCal.getTime());
622     recurEvent.setToDateTime(toCal.getTime());
623     recurEvent.setRepeatCount(-1);
624     recurEvent.setRepeatInterval(1);
625     recurEvent.setRepeatByDay(new String[]{"TU"});
626 
627     calendar.set(2013, java.util.Calendar.SEPTEMBER, 24, 22, 30);
628     expectedDate = Utils.getPreviousOccurrenceDate(recurEvent, calendar.getTime(), tz);
629     calendar.setTime(expectedDate);
630     assertEquals(17, calendar.get(java.util.Calendar.DATE));
631 
632   }
633 
634   public void testGetPreviousOccurrence2() throws Exception {
635 
636     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
637     fromCal.set(2013, java.util.Calendar.SEPTEMBER, 11, 19, 0);
638 
639     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
640     toCal.set(2013, java.util.Calendar.SEPTEMBER, 11, 22, 30);
641 
642     CalendarEvent recurEvent = new CalendarEvent();
643     recurEvent.setSummary("test previous");
644     recurEvent.setFromDateTime(fromCal.getTime());
645     recurEvent.setToDateTime(toCal.getTime());
646     recurEvent.setRepeatType(CalendarEvent.RP_WEEKLY);
647     recurEvent.setRepeatInterval(1);
648     recurEvent.setRepeatCount(-1);
649     recurEvent.setRepeatByDay(new String[]{"WE"});
650     recurEvent.setRepeatUntilDate(null);
651 
652     java.util.Calendar calendar = java.util.Calendar.getInstance(tz);
653     calendar.set(2013, java.util.Calendar.SEPTEMBER, 25, 19, 0);
654     Date expectedDate = Utils.getPreviousOccurrenceDate(recurEvent, calendar.getTime(), tz);
655     calendar.setTime(expectedDate);
656     assertEquals(18, calendar.get(java.util.Calendar.DATE));
657   }
658 
659   /**
660    * * This test now only failure if:
661    * - Default timezone (timezone set up on computer) is GMT +7
662    * - Time in GMT +7 is afternoon (after 3:00 PM)
663    *
664    * TODO: Please fix this test case. It is failure in 10 last days of summer time (DST) of timezone GMT+1 (10 days before 25 Oct 2015)
665    * - This seem current behaviour is not good (Google calendar is different)
666    * I see if I create a event recurring at 8AM every day (at GTM+1), but after 25 0ct 2015, all recurring event will start at 9AM.
667    * I think all event must be started at 8AM (like this test case), the start-time only break if I share this event to other user at different timezone
668    *
669    * I will temporary disable this test-case to release CI, please re-enable and fix it.
670    *
671    * @throws Exception
672    */
673   public void tes1tRecurringEventStartFromToday() throws Exception {
674     CalendarSetting setting = calendarService_.getCalendarSetting(username);
675     String originUserTimezone = setting.getTimeZone();
676     setting.setDateFormat("MMddyyyy");
677     setting.setTimeFormat("H:m");
678     // Set current user timezone is GTM +1
679     setting.setTimeZone("Europe/Brussels");
680     calendarService_.saveCalendarSetting(username, setting);
681     setting = calendarService_.getCalendarSetting(username);
682     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
683     // Build startTime and endTime string
684     // startTime == nextHour from current hour
685     // endTime = next hour from start time
686     java.util.Calendar from = java.util.Calendar.getInstance();
687     from.add(java.util.Calendar.HOUR_OF_DAY, 1);
688     from.set(java.util.Calendar.MINUTE, 0);
689     from.set(java.util.Calendar.SECOND, 0);
690     java.util.Calendar to = java.util.Calendar.getInstance();
691     to.setTime(from.getTime());
692     to.add(java.util.Calendar.HOUR_OF_DAY, 1);
693     String startTime = formatDate(setting, from.getTime());
694     String endTime = formatDate(setting, to.getTime());
695     //. Rebuild fromDate and toDate from user time
696     Date fromDate = getDate(setting, startTime);
697     Date toDate = getDate(setting, endTime);
698 
699     java.util.Calendar fromCalendar = java.util.Calendar.getInstance(userTimezone);
700     fromCalendar.setTime(fromDate);
701 
702     //. Create calendar
703     Calendar cal = createPrivateCalendar(username, "testRecurringEventStartFromToday", "testRecurringEventStartFromToday");
704     //. Create recurring event
705     CalendarEvent event = new CalendarEvent();
706     event.setSummary("test previous");
707     event.setFromDateTime(fromDate);
708     event.setToDateTime(toDate);
709     event.setRepeatType(CalendarEvent.RP_DAILY);
710     event.setRepeatInterval(1);
711     event.setRepeatCount(10);
712     event.setRepeatByDay(null);
713     event.setRepeatUntilDate(null);
714     calendarService_.saveUserEvent(username, cal.getId(), event, true);
715     from.setTimeZone(userTimezone);
716     from.add(java.util.Calendar.DATE, -2);
717     to.setTimeZone(userTimezone);
718     to.add(java.util.Calendar.DATE, 20);
719     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
720     Set<String> keys = events.keySet();
721     assertEquals(10, keys.size());
722     SimpleDateFormat format = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
723     format.setCalendar(fromCalendar);
724     from = (java.util.Calendar)fromCalendar.clone();
725     for(int i = 0; i < 10; i++) {
726       assertContain(format.format(from.getTime()), keys);
727       from.add(java.util.Calendar.HOUR_OF_DAY, 1);
728       assertNotContain(format.format(from.getTime()), keys);
729       from.add(java.util.Calendar.HOUR_OF_DAY, -2);
730       assertNotContain(format.format(from.getTime()), keys);
731       from.add(java.util.Calendar.HOUR_OF_DAY, 1);
732       from.add(java.util.Calendar.DAY_OF_YEAR, 1);
733     }
734 
735     calendarService_.removeAllSeriesEvents(event, username);
736     // Reset user timezone
737     setting.setTimeZone(originUserTimezone);
738     calendarService_.saveCalendarSetting(username, setting);
739   }
740 
741   /**
742    * This test now only failure if:
743    * - Default timezone (timezone set up on computer) is GMT +7
744    * - Time in GMT +7 is afternoon (after 3:00 PM)
745    *
746    * TODO: this test case is temporary failed like testRecurringEventStartFromToday, I temporary disable it
747    * @throws Exception
748    */
749   public void tes1tRecurringEventStartFromYesterday() throws Exception {
750     CalendarSetting setting = calendarService_.getCalendarSetting(username);
751     String originUserTimezone = setting.getTimeZone();
752     setting.setDateFormat("MMddyyyy");
753     setting.setTimeFormat("H:m");
754     // Set current user timezone is GTM +1
755     setting.setTimeZone("Europe/Brussels");
756     calendarService_.saveCalendarSetting(username, setting);
757     setting = calendarService_.getCalendarSetting(username);
758     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
759     // Build startTime and endTime string
760     // startTime == nextHour from current hour
761     // endTime = next hour from start time
762     java.util.Calendar from = java.util.Calendar.getInstance();
763     from.add(java.util.Calendar.DATE, -1);
764     from.add(java.util.Calendar.HOUR_OF_DAY, 1);
765     from.set(java.util.Calendar.MINUTE, 0);
766     from.set(java.util.Calendar.SECOND, 0);
767     java.util.Calendar to = java.util.Calendar.getInstance();
768     to.setTime(from.getTime());
769     to.add(java.util.Calendar.HOUR_OF_DAY, 1);
770     String startTime = formatDate(setting, from.getTime());
771     String endTime = formatDate(setting, to.getTime());
772     //. Rebuild fromDate and toDate from user time
773     Date fromDate = getDate(setting, startTime);
774     Date toDate = getDate(setting, endTime);
775 
776     java.util.Calendar fromCalendar = java.util.Calendar.getInstance(userTimezone);
777     fromCalendar.setTime(fromDate);
778 
779     //. Create calendar
780     Calendar cal = createPrivateCalendar(username, "testRecurringEventStartFromYesterday", "testRecurringEventStartFromYesterday");
781     //. Create recurring event
782     CalendarEvent event = new CalendarEvent();
783     event.setSummary("test previous");
784     event.setFromDateTime(fromDate);
785     event.setToDateTime(toDate);
786     event.setRepeatType(CalendarEvent.RP_DAILY);
787     event.setRepeatInterval(1);
788     event.setRepeatCount(10);
789     event.setRepeatByDay(null);
790     event.setRepeatUntilDate(null);
791     calendarService_.saveUserEvent(username, cal.getId(), event, true);
792     from.setTimeZone(userTimezone);
793     from.add(java.util.Calendar.DATE, -2);
794     to.setTimeZone(userTimezone);
795     to.add(java.util.Calendar.DATE, 20);
796     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
797     Set<String> keys = events.keySet();
798     assertEquals(10, keys.size());
799     SimpleDateFormat format = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
800     format.setCalendar(fromCalendar);
801     from = (java.util.Calendar)fromCalendar.clone();
802     for(int i = 0; i < 10; i++) {
803       assertContain(format.format(from.getTime()), keys);
804       from.add(java.util.Calendar.HOUR_OF_DAY, 1);
805       assertNotContain(format.format(from.getTime()), keys);
806       from.add(java.util.Calendar.HOUR_OF_DAY, -2);
807       assertNotContain(format.format(from.getTime()), keys);
808       from.add(java.util.Calendar.HOUR_OF_DAY, 1);
809       from.add(java.util.Calendar.DAY_OF_YEAR, 1);
810     }
811 
812     calendarService_.removeAllSeriesEvents(event, username);
813     // Reset user timezone
814     setting.setTimeZone(originUserTimezone);
815     calendarService_.saveCalendarSetting(username, setting);
816   }
817 
818   public void testRecurringWithTimezoneChange() throws Exception {
819     CalendarSetting setting = calendarService_.getCalendarSetting(username);
820     setting.setDateFormat("MMddyyyy");
821     setting.setTimeFormat("H:m");
822     // Set current user timezone is GTM+7
823     setting.setTimeZone("Asia/Saigon");
824     calendarService_.saveCalendarSetting(username, setting);
825     setting = calendarService_.getCalendarSetting(username);
826     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
827     Calendar calendar = createPrivateCalendar(username, "test recurring calendar", "description");
828     String startTime = "10202014 10:00";
829     String endTime = "10202014 11:00";
830     Date start = getDate(setting, startTime);
831     Date end = getDate(setting, endTime);
832     java.util.Calendar from = java.util.Calendar.getInstance();
833     from.setTimeZone(userTimezone);
834     from.setTime(start);
835     from.add(java.util.Calendar.DATE, -2);
836     java.util.Calendar to = java.util.Calendar.getInstance();
837     to.setTime(end);
838     to.setTimeZone(userTimezone);
839     to.add(java.util.Calendar.MONTH, 2);
840     // Create recuring event
841     CalendarEvent event = new CalendarEvent();
842     event.setSummary("test recurring");
843     event.setFromDateTime(start);
844     event.setToDateTime(end);
845     event.setRepeatType(CalendarEvent.RP_WEEKLY);
846     event.setRepeatInterval(1);
847     event.setRepeatByDay(new String[]{"MO", "TU", "WE", "TH"});
848     event.setRepeatCount(10);
849     event.setRepeatUntilDate(null);
850 
851     Utils.updateOriginDate(event, userTimezone);
852     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
853 
854     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
855     //. Get occurrenceEvent
856     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
857     assertEquals(10, events.size());
858     Set<String> keys = events.keySet();
859     assertContain("20141020T100000Z", keys);
860     assertContain("20141021T100000Z", keys);
861     assertContain("20141022T100000Z", keys);
862     assertContain("20141023T100000Z", keys);
863     // Set current user timezone to GMT-7
864     setting.setTimeZone("US/Mountain");
865     calendarService_.saveCalendarSetting(username, setting);
866     setting = calendarService_.getCalendarSetting(username);
867     userTimezone = TimeZone.getTimeZone(setting.getTimeZone());
868     //. Re get occurrenceEvent
869     from = java.util.Calendar.getInstance();
870     from.setTimeZone(userTimezone);
871     from.setTime(start);
872     from.add(java.util.Calendar.DATE, -2);
873     to = java.util.Calendar.getInstance();
874     to.setTimeZone(userTimezone);
875     to.setTime(end);
876     to.add(java.util.Calendar.MONTH, 2);
877     //. Get list events after user change his timezone
878     events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
879     assertEquals(10, events.size());
880     keys = events.keySet();
881     assertContain("20141019T210000Z", keys);
882     assertContain("20141020T210000Z", keys);
883     assertContain("20141021T210000Z", keys);
884     assertContain("20141022T210000Z", keys);
885   }
886   /**
887    * On this case, we create event on Wednesday 22 Oct 2014 and repeat all weekday (Mon to Fri)
888    * Expect:
889    * - Origin event must start on Wednesday 22 Oct 2014
890    * - On Monday (20 Oct) and Tuesday (21 Oct) must not have any instance of recurring
891    * @throws Exception
892    */
893   public void testCreateRecurringEvent() throws Exception {
894     CalendarSetting setting = calendarService_.getCalendarSetting(username);
895     setting.setDateFormat("MMddyyyy");
896     setting.setTimeFormat("H:m");
897     // Set current user timezone is GTM+7
898     setting.setTimeZone("Asia/Saigon");
899     calendarService_.saveCalendarSetting(username, setting);
900     setting = calendarService_.getCalendarSetting(username);
901     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
902     Calendar calendar = createPrivateCalendar(username, "test recurring calendar", "description");
903     String startTime = "10222014 10:00";
904     String endTime = "10222014 11:00";
905     Date start = getDate(setting, startTime);
906     Date end = getDate(setting, endTime);
907     java.util.Calendar from = java.util.Calendar.getInstance();
908     from.setTimeZone(userTimezone);
909     from.setTime(start);
910     from.add(java.util.Calendar.DATE, -2);
911     java.util.Calendar to = java.util.Calendar.getInstance();
912     to.setTime(end);
913     to.setTimeZone(userTimezone);
914     to.add(java.util.Calendar.MONTH, 2);
915     // Create recuring event
916     CalendarEvent event = new CalendarEvent();
917     event.setSummary("test recurring");
918     event.setFromDateTime(start);
919     event.setToDateTime(end);
920     event.setRepeatType(CalendarEvent.RP_WEEKLY);
921     event.setRepeatInterval(1);
922     event.setRepeatByDay(new String[]{"MO", "TU", "WE", "TH", "FR"});
923     event.setRepeatCount(10);
924     event.setRepeatUntilDate(null);
925     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
926     //. Get occurrenceEvent
927     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
928     assertEquals(10, events.size());
929     Set<String> keys = events.keySet();
930     assertNotContain("20141020T100000Z", keys);
931     assertNotContain("20141021T100000Z", keys);
932     assertContain("20141022T100000Z", keys);
933     assertContain("20141023T100000Z", keys);
934     assertContain("20141024T100000Z", keys);
935     assertNotContain("20141025T100000Z", keys);
936     assertNotContain("20141026T100000Z", keys);
937   }
938   /**
939    * On this test case, we create event on (Wednesday 22 Oct 2014) but repeat on Thursday and Friday
940    * The result: Origin event must be on Thursday 23 Oct 2014 and repeat on Thursday and Friday
941    * @throws Exception
942    */
943   public void testCreateEventAndRecurringFromNextDay() throws Exception {
944     CalendarSetting setting = calendarService_.getCalendarSetting(username);
945     setting.setDateFormat("MMddyyyy");
946     setting.setTimeFormat("H:m");
947     // Set current user timezone is GTM+7
948     setting.setTimeZone("Asia/Saigon");
949     calendarService_.saveCalendarSetting(username, setting);
950     setting = calendarService_.getCalendarSetting(username);
951     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
952     Calendar calendar = createPrivateCalendar(username, "test recurring calendar", "description");
953     //. 22 Oct 2014 (Wednesday)
954     String startTime = "10222014 10:00";
955     String endTime = "10222014 11:00";
956     Date start = getDate(setting, startTime);
957     Date end = getDate(setting, endTime);
958     java.util.Calendar from = java.util.Calendar.getInstance();
959     from.setTimeZone(userTimezone);
960     from.setTime(start);
961     from.add(java.util.Calendar.DATE, -2);
962     java.util.Calendar to = java.util.Calendar.getInstance();
963     to.setTime(end);
964     to.setTimeZone(userTimezone);
965     to.add(java.util.Calendar.MONTH, 2);
966     // Create recuring event
967     CalendarEvent event = new CalendarEvent();
968     event.setSummary("test recurring");
969     event.setFromDateTime(start);
970     event.setToDateTime(end);
971     //. Create event on Wednesday but repeat weekly on Thursday and Friday
972     event.setRepeatType(CalendarEvent.RP_WEEKLY);
973     event.setRepeatInterval(1);
974     event.setRepeatByDay(new String[]{"TH", "FR"});
975     event.setRepeatCount(10);
976     event.setRepeatUntilDate(null);
977     Utils.updateOriginDate(event, userTimezone);
978     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
979     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
980     // Get occurrenceEvent
981     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
982     assertEquals(10, events.size());
983     Set<String> keys = events.keySet();
984     assertNotContain("20141020T100000Z", keys);
985     assertNotContain("20141021T100000Z", keys);
986     assertNotContain("20141022T100000Z", keys);
987     assertContain("20141023T100000Z", keys);
988     assertContain("20141024T100000Z", keys);
989     assertNotContain("20141025T100000Z", keys);
990     assertNotContain("20141026T100000Z", keys);
991   }
992   public void testCreateRecurringEventStartAtSunday() throws Exception {
993     CalendarSetting setting = calendarService_.getCalendarSetting(username);
994     setting.setDateFormat("MMddyyyy");
995     setting.setTimeFormat("H:m");
996     // Set current user timezone is GTM+7
997     setting.setTimeZone("Asia/Saigon");
998     calendarService_.saveCalendarSetting(username, setting);
999     setting = calendarService_.getCalendarSetting(username);
1000     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
1001     Calendar calendar = createPrivateCalendar(username, "test recurring calendar", "description");
1002     //. 22 Oct 2014 (Wednesday)
1003     String startTime = "10192014 10:00";
1004     String endTime = "10192014 11:00";
1005     Date start = getDate(setting, startTime);
1006     Date end = getDate(setting, endTime);
1007     java.util.Calendar from = java.util.Calendar.getInstance();
1008     from.setTimeZone(userTimezone);
1009     from.setTime(start);
1010     from.add(java.util.Calendar.DATE, -2);
1011     java.util.Calendar to = java.util.Calendar.getInstance();
1012     to.setTime(end);
1013     to.setTimeZone(userTimezone);
1014     to.add(java.util.Calendar.MONTH, 2);
1015     // Create recuring event
1016     CalendarEvent event = new CalendarEvent();
1017     event.setSummary("test recurring");
1018     event.setFromDateTime(start);
1019     event.setToDateTime(end);
1020     //. Create event on Wednesday but repeat weekly on Thursday and Friday
1021     event.setRepeatType(CalendarEvent.RP_WEEKLY);
1022     event.setRepeatInterval(1);
1023     event.setRepeatByDay(new String[]{"MO", "SU"});
1024     event.setRepeatCount(10);
1025     event.setRepeatUntilDate(null);
1026     Utils.updateOriginDate(event, userTimezone);
1027     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
1028     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
1029     //. Get occurrenceEvent
1030     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
1031     assertEquals(10, events.size());
1032     Set<String> keys = events.keySet();
1033     assertNotContain("20141017T100000Z", keys);
1034     assertNotContain("20141018T100000Z", keys);
1035     assertContain("20141019T100000Z", keys);
1036     assertContain("20141020T100000Z", keys);
1037     assertNotContain("20141021T100000Z", keys);
1038     assertContain("20141026T100000Z", keys);
1039     assertContain("20141027T100000Z", keys);
1040   }
1041 
1042   public void testEventRecurringMonthlyByDayOfWeek() throws Exception {
1043     CalendarSetting setting = calendarService_.getCalendarSetting(username);
1044     setting.setDateFormat("MMddyyyy");
1045     setting.setTimeFormat("H:m");
1046     // Set current user timezone is GTM+7
1047     String oldTimeZone = setting.getTimeZone();
1048     setting.setTimeZone("Asia/Saigon");
1049     calendarService_.saveCalendarSetting(username, setting);
1050     setting = calendarService_.getCalendarSetting(username);
1051 
1052     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
1053     Calendar calendar = createPrivateCalendar(username, "calendar for testing monthly recurring", "description");
1054     //. 09 Mar 2015 (Monday)
1055     String startTime = "03092015 03:00";
1056     String endTime = "03092015 04:00";
1057     Date start = getDate(setting, startTime);
1058     Date end = getDate(setting, endTime);
1059 
1060     java.util.Calendar from = java.util.Calendar.getInstance(userTimezone);
1061     from.setTime(start);
1062     from.add(java.util.Calendar.DATE, -2);
1063     java.util.Calendar to = java.util.Calendar.getInstance(userTimezone);
1064     to.setTime(end);
1065     to.add(java.util.Calendar.MONTH, 6);
1066 
1067     // Create recuring event
1068     CalendarEvent event = new CalendarEvent();
1069     event.setSummary("test monthly recurring event");
1070     event.setFromDateTime(start);
1071     event.setToDateTime(end);
1072     //. Create event on Wednesday but repeat weekly on Thursday and Friday
1073     event.setRepeatType(CalendarEvent.RP_MONTHLY);
1074     event.setRepeatInterval(1);
1075     // Repeat monthly on the second Monday
1076     event.setRepeatByDay(new String[]{"2MO"});
1077     event.setRepeatCount(5);
1078     event.setRepeatUntilDate(null);
1079     Utils.updateOriginDate(event, userTimezone);
1080     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
1081     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
1082     //. Get occurrenceEvent
1083     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
1084 
1085     //. Reset old timezone in setting
1086     setting.setTimeZone(oldTimeZone);
1087     calendarService_.saveCalendarSetting(username, setting);
1088 
1089     //. Assert result
1090     assertEquals(5, events.size());
1091     Set<String> keys = events.keySet();
1092     assertContain("20150309T030000Z", keys);
1093     assertNotContain("20150316T030000Z", keys);
1094     assertContain("20150413T030000Z", keys);
1095     assertContain("20150511T030000Z", keys);
1096     assertContain("20150608T030000Z", keys);
1097     assertContain("20150713T030000Z", keys);
1098     assertNotContain("20150810T030000Z", keys);
1099   }
1100 
1101   public void testEventRecurringMonthlyByDayOfMonth() throws Exception {
1102     CalendarSetting setting = calendarService_.getCalendarSetting(username);
1103     setting.setDateFormat("MMddyyyy");
1104     setting.setTimeFormat("H:m");
1105     // Set current user timezone is GTM+7
1106     String oldTimeZone = setting.getTimeZone();
1107     setting.setTimeZone("Asia/Saigon");
1108     calendarService_.saveCalendarSetting(username, setting);
1109     setting = calendarService_.getCalendarSetting(username);
1110 
1111     TimeZone userTimezone = DateUtils.getTimeZone(setting.getTimeZone());
1112     Calendar calendar = createPrivateCalendar(username, "calendar for testing monthly recurring", "description");
1113     //. 09 Mar 2015 (Monday)
1114     String startTime = "03092015 03:00";
1115     String endTime = "03092015 04:00";
1116     Date start = getDate(setting, startTime);
1117     Date end = getDate(setting, endTime);
1118 
1119     java.util.Calendar from = java.util.Calendar.getInstance(userTimezone);
1120     from.setTime(start);
1121     from.add(java.util.Calendar.DATE, -2);
1122     java.util.Calendar to = java.util.Calendar.getInstance(userTimezone);
1123     to.setTime(end);
1124     to.add(java.util.Calendar.MONTH, 6);
1125 
1126     // Create recuring event
1127     CalendarEvent event = new CalendarEvent();
1128     event.setSummary("test monthly recurring event");
1129     event.setFromDateTime(start);
1130     event.setToDateTime(end);
1131     //. Create event on Wednesday but repeat weekly on Thursday and Friday
1132     event.setRepeatType(CalendarEvent.RP_MONTHLY);
1133     event.setRepeatInterval(1);
1134     //Repeat at 09th every month
1135     event.setRepeatByMonthDay(new long[]{9L});
1136     event.setRepeatCount(5);
1137     event.setRepeatUntilDate(null);
1138     Utils.updateOriginDate(event, userTimezone);
1139     Utils.adaptRepeatRule(event, userTimezone, CalendarService.PERSISTED_TIMEZONE);
1140     calendarService_.saveUserEvent(username, calendar.getId(), event, true);
1141     //. Get occurrenceEvent
1142     Map<String, CalendarEvent> events = calendarService_.getOccurrenceEvents(event, from, to, setting.getTimeZone());
1143 
1144     //. Reset old timezone in setting
1145     setting.setTimeZone(oldTimeZone);
1146     calendarService_.saveCalendarSetting(username, setting);
1147 
1148     //. Assert result
1149     assertEquals(5, events.size());
1150     Set<String> keys = events.keySet();
1151     assertContain("20150309T030000Z", keys);
1152     assertNotContain("20150316T030000Z", keys);
1153     assertContain("20150409T030000Z", keys);
1154     assertContain("20150509T030000Z", keys);
1155     assertContain("20150609T030000Z", keys);
1156     assertContain("20150709T030000Z", keys);
1157     assertNotContain("20150809T030000Z", keys);
1158   }
1159 
1160   private Date getDate(CalendarSetting setting, String datetime) throws Exception {
1161     String format = setting.getDateFormat() + " " + setting.getTimeFormat();
1162     DateFormat df = new SimpleDateFormat(format);
1163     df.setCalendar(getCalendarInstanceBySetting(setting));
1164     return df.parse(datetime);
1165   }
1166   private String formatDate(CalendarSetting setting, Date date) {
1167     String format = setting.getDateFormat() + " " + setting.getTimeFormat();
1168     DateFormat df = new SimpleDateFormat(format);
1169     return df.format(date);
1170   }
1171   private java.util.Calendar getCalendarInstanceBySetting(final CalendarSetting calendarSetting) {
1172     java.util.Calendar calendar = java.util.Calendar.getInstance() ;
1173     calendar.setLenient(false);
1174     calendar.setTimeZone(DateUtils.getTimeZone(calendarSetting.getTimeZone()));
1175     calendar.setFirstDayOfWeek(Integer.parseInt(calendarSetting.getWeekStartOn()));
1176     calendar.setMinimalDaysInFirstWeek(4);
1177     return calendar;
1178   }
1179   private void assertContain(String key, Set<String> keys) {
1180     for(String k : keys) {
1181       if(k.equals(key)) {
1182         return;
1183       }
1184     }
1185     fail("Event at " + key + " should be found");
1186   }
1187   private void assertNotContain(String key, Set<String> keys) {
1188     for(String k : keys) {
1189       if(k.equals(key)) {
1190         fail("Event at " + key + " should not be found");
1191       }
1192     }
1193   }
1194 
1195   private CalendarEvent createRepetitiveEventForTest() throws  Exception {
1196     java.util.Calendar fromCal = java.util.Calendar.getInstance(tz);
1197     fromCal.set(2013, 2, 7, 5, 30);
1198 
1199     java.util.Calendar toCal = java.util.Calendar.getInstance(tz);
1200     toCal.set(2013, 2, 7, 6, 30);
1201 
1202     Calendar calendar = createPrivateCalendar(username, username, "TestSaveOneOccurrence");
1203 
1204     CalendarEvent recurEvent = new CalendarEvent();
1205     recurEvent.setSummary("repeated past");
1206     recurEvent.setFromDateTime(fromCal.getTime());
1207     recurEvent.setToDateTime(toCal.getTime());
1208     recurEvent.setRepeatType(CalendarEvent.RP_DAILY);
1209     recurEvent.setRepeatInterval(1);
1210     recurEvent.setRepeatCount(6);
1211     recurEvent.setRepeatUntilDate(null);
1212     recurEvent.setRepeatByDay(null);
1213     recurEvent.setCalendarId(calendar.getId());
1214 
1215     calendarService_.saveUserCalendar(username, calendar, true);
1216     calendarService_.saveUserEvent(username, calendar.getId(), recurEvent, true);
1217 
1218     return recurEvent;
1219   }
1220 }