Merge branch '2015.11' into 2015.11-develop
[tine20] / tests / tine20 / Calendar / Frontend / ActiveSyncTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Calendar
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @copyright   Copyright (c) 2010-2014 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Cornelius Weiss <c.weiss@metaways.de>
9  */
10
11 /**
12  * Test class for Calendar_Frontend_ActiveSync
13  * 
14  * @package     Calendar
15  */
16 class Calendar_Frontend_ActiveSyncTest extends ActiveSync_Controller_ControllerTest
17 {
18     /**
19      * name of the application
20      * 
21      * @var string
22      */
23     protected $_applicationName = 'Calendar';
24     
25     protected $_controllerName = 'Calendar_Frontend_ActiveSync';
26     
27     protected $_class = Syncroton_Data_Factory::CLASS_CALENDAR;
28     
29     /**
30      * @var array test objects
31      */
32     protected $objects = array();
33     
34     protected $_testXMLInput;
35     
36     protected $_testXMLInput_palmPreV12 = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
37     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
38         <Collections>
39             <Collection>
40                 <Class>Calendar</Class>
41                 <SyncKey>345</SyncKey>
42                 <CollectionId>calendar-root</CollectionId>
43                 <DeletesAsMoves/>
44                 <GetChanges/>
45                 <WindowSize>50</WindowSize>
46                 <Options>
47                     <FilterType>4</FilterType><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type></AirSyncBase:BodyPreference>
48                 </Options>
49                 <Commands>
50                     <Change>
51                         <ServerId>3452c1dd3f21d1c12589e517f0c6a928137113a4</ServerId>
52                         <ApplicationData>
53                             <AirSyncBase:Body>
54                                 <AirSyncBase:Type>1</AirSyncBase:Type>
55                                 <AirSyncBase:Data>test beschreibung zeile 1&#13;
56 Zeile 2&#13;
57 Zeile 3</AirSyncBase:Data>
58                             </AirSyncBase:Body>
59                             <Calendar:Timezone>xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Calendar:Timezone>
60                             <Calendar:UID>3452c1dd3f21d1c12589e517f0c6a928137113a4</Calendar:UID>
61                             <Calendar:DtStamp>20101104T070652Z</Calendar:DtStamp>
62                             <Calendar:Subject>GM straussberg2</Calendar:Subject>
63                             <Calendar:MeetingStatus>1</Calendar:MeetingStatus>
64                             <Calendar:OrganizerName>Nadine Blau</Calendar:OrganizerName>
65                             <Calendar:OrganizerEmail>meine@mail.com</Calendar:OrganizerEmail>
66                             <Calendar:Attendees><Calendar:Attendee><Calendar:Name>Nadine Blau</Calendar:Name><Calendar:Email>meine@mail.com</Calendar:Email></Calendar:Attendee></Calendar:Attendees>
67                             <Calendar:BusyStatus>0</Calendar:BusyStatus>
68                             <Calendar:AllDayEvent>1</Calendar:AllDayEvent>
69                             <Calendar:StartTime>20101103T230000Z</Calendar:StartTime>
70                             <Calendar:EndTime>20101106T230000Z</Calendar:EndTime>
71                             <Calendar:Sensitivity>0</Calendar:Sensitivity>
72                         </ApplicationData>
73                     </Change>
74                 </Commands>
75             </Collection>
76         </Collections>
77     </Sync>';
78     
79     protected $_testXMLInput_DailyRepeatingEvent = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
80     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
81         <Collections>
82             <Collection>
83                 <Class>Calendar</Class>
84                 <SyncKey>8</SyncKey>
85                 <CollectionId>calendar-root</CollectionId>
86                 <DeletesAsMoves/><GetChanges/>
87                 <WindowSize>100</WindowSize>
88                 <Options><FilterType>4</FilterType><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><AirSyncBase:BodyPreference><AirSyncBase:Type>3</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize><AirSyncBase:AllOrNone>1</AirSyncBase:AllOrNone></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options>
89                 <Commands>
90                     <Add>
91                         <ClientId>1073741902</ClientId>
92                         <ApplicationData><Calendar:Timezone>xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Calendar:Timezone>
93                             <Calendar:AllDayEvent>0</Calendar:AllDayEvent>
94                             <Calendar:BusyStatus>2</Calendar:BusyStatus>
95                             <Calendar:DtStamp>20101224T082738Z</Calendar:DtStamp>
96                             <Calendar:EndTime>20101220T100000Z</Calendar:EndTime>
97                             <Calendar:MeetingStatus>0</Calendar:MeetingStatus>
98                             <Calendar:Reminder>15</Calendar:Reminder>
99                             <Calendar:Sensitivity>0</Calendar:Sensitivity>
100                             <Calendar:Subject>Tdfffdd</Calendar:Subject>
101                             <Calendar:StartTime>20101220T090000Z</Calendar:StartTime>
102                             <Calendar:UID>040000008200E00074C5B7101A82E00800000000DCA959CF1C69F280D15448CF43450B301000000019B5FB15984956377D4EBEFE125A8EF6</Calendar:UID>
103                             <Calendar:Recurrence>
104                                 <Calendar:Until>20101222T230000Z</Calendar:Until>
105                                 <Calendar:Interval>1</Calendar:Interval>
106                                 <Calendar:Type>0</Calendar:Type>
107                             </Calendar:Recurrence>
108                         </ApplicationData>
109                     </Add>
110                 </Commands>
111             </Collection>
112         </Collections>
113     </Sync>';
114
115     protected $_testXMLInput_SamsungGalaxyStatus = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
116     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
117         <Collections>
118             <Collection>
119                 <Class>Calendar</Class>
120                 <SyncKey>20</SyncKey>
121                 <CollectionId>calendar-root</CollectionId>
122                 <DeletesAsMoves/>
123                 <GetChanges/>
124                 <WindowSize>5</WindowSize>
125                 <Options><FilterType>4</FilterType><BodyPreference xmlns="uri:AirSyncBase"><Type>1</Type><TruncationSize>400000</TruncationSize></BodyPreference></Options>
126                 <Commands>
127                     <Change>
128                         <ServerId>b2b0593bc21c89e5d07edb7b5caa56ff7e243e92</ServerId>
129                         <ApplicationData>
130                             <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Timezone>
131                             <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
132                             <StartTime xmlns="uri:Calendar">20120229T120000Z</StartTime>
133                             <EndTime xmlns="uri:Calendar">20120229T140000Z</EndTime>
134                             <DtStamp xmlns="uri:Calendar">20120228T093153Z</DtStamp>
135                             <Subject xmlns="uri:Calendar">testtermin</Subject>
136                             <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
137                             <OrganizerEmail xmlns="uri:Calendar">user2@example.com</OrganizerEmail>
138                             <Reminder xmlns="uri:Calendar">30</Reminder>
139                             <UID xmlns="uri:Calendar">2b4a047d3f71b4d47d2d3907f4a27d70f650cd30</UID>
140                             <Attendees xmlns="uri:Calendar">
141                                 <Attendee><Name>user1@example.com</Name><Email>user1@example.com</Email><AttendeeType>1</AttendeeType></Attendee>
142                                 <Attendee><Name>user2@example.com</Name><Email>user2@example.com</Email><AttendeeType>1</AttendeeType></Attendee>
143                                 <Attendee><Name>user3@example.com</Name><Email>user3@example.com</Email><AttendeeType>1</AttendeeType></Attendee>
144                             </Attendees>
145                             <BusyStatus xmlns="uri:Calendar">0</BusyStatus>
146                             <MeetingStatus xmlns="uri:Calendar">3</MeetingStatus>
147                         </ApplicationData>
148                     </Change>
149                 </Commands>
150             </Collection>
151         </Collections>
152     </Sync>';
153     
154     protected $_testXMLInputOutlook13 = '<?xml version="1.0" encoding="utf-8"?>
155     <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
156     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
157       <Collections>
158         <Collection>
159           <SyncKey>5</SyncKey>
160           <CollectionId>calendar-root</CollectionId>
161           <DeletesAsMoves>0</DeletesAsMoves>
162           <GetChanges>0</GetChanges>
163           <WindowSize>512</WindowSize>
164           <Options>
165             <FilterType>0</FilterType>
166             <BodyPreference xmlns="uri:AirSyncBase">
167               <Type>2</Type>
168               <AllOrNone>1</AllOrNone>
169             </BodyPreference>
170           </Options>
171           <Commands>
172             <Change>
173               <ServerId>d8a9cecb073736aa78c95a249f383123cc03365b</ServerId>
174               <ApplicationData>
175                 <Timezone xmlns="uri:Calendar">xP///1cALgAgAEUAdQByAG8AcABlACAAUwB0AGEAbgBkAGEAcgBkACAAVABpAG0AZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAFcALgAgAEUAdQByAG8AcABlACAARABhAHkAbABpAGcAaAB0ACAAVABpAG0AZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Timezone>
176                 <DtStamp xmlns="uri:Calendar">20120914T125503Z</DtStamp>
177                 <StartTime xmlns="uri:Calendar">20120914T140000Z</StartTime>
178                 <Subject xmlns="uri:Calendar">TEST9</Subject>
179                 <UID xmlns="uri:Calendar">fd4b68a5871aa0082284e9bc5664a35da207b75b</UID>
180                 <OrganizerName xmlns="uri:Calendar">unittest@tine20.org</OrganizerName>
181                 <OrganizerEmail xmlns="uri:Calendar">unittest@tine20.org</OrganizerEmail>
182                 <Attendees xmlns="uri:Calendar">
183                   <Attendee>
184                     <Email>unittest@tine20.org</Email>
185                     <Name>Admin Account, Tine 2.0</Name>
186                     <AttendeeStatus>3</AttendeeStatus>
187                     <AttendeeType>1</AttendeeType>
188                   </Attendee>
189                   <Attendee>
190                     <Email>pwulf@tine20.org</Email>
191                     <Name>Wulf, Paul</Name>
192                     <AttendeeStatus>0</AttendeeStatus>
193                     <AttendeeType>1</AttendeeType>
194                   </Attendee>
195                 </Attendees>
196                 <EndTime xmlns="uri:Calendar">20120914T143000Z</EndTime>
197                 <Recurrence xmlns="uri:Calendar">
198                   <Type>0</Type>
199                   <Interval>1</Interval>
200                   <Occurrences>3</Occurrences>
201                 </Recurrence>
202                 <Exceptions xmlns="uri:Calendar">
203                   <Exception>
204                     <ExceptionStartTime>20120916T140000Z</ExceptionStartTime>
205                     <StartTime>20120916T140000Z</StartTime>
206                     <DtStamp>20120914T125503Z</DtStamp>
207                     <EndTime>20120916T143000Z</EndTime>
208                     <Sensitivity>0</Sensitivity>
209                     <BusyStatus>2</BusyStatus>
210                     <Attendees>
211                       <Attendee>
212                         <Email>unittest@tine20.org</Email>
213                         <Name>Admin Account, Tine 2.0</Name>
214                         <AttendeeStatus>0</AttendeeStatus>
215                         <AttendeeType>1</AttendeeType>
216                       </Attendee>
217                       <Attendee>
218                         <Email>unittest@tine20.org</Email>
219                         <Name>Admin Account, Tine 2.0</Name>
220                         <AttendeeStatus>3</AttendeeStatus>
221                         <AttendeeType>1</AttendeeType>
222                       </Attendee>
223                       <Attendee>
224                         <Email>pwulf@tine20.org</Email>
225                         <Name>Wulf, Paul</Name>
226                         <AttendeeStatus>4</AttendeeStatus>
227                         <AttendeeType>1</AttendeeType>
228                       </Attendee>
229                     </Attendees>
230                   </Exception>
231                 </Exceptions>
232                 <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
233                 <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
234                 <MeetingStatus xmlns="uri:Calendar">1</MeetingStatus>
235                 <ResponseRequested xmlns="uri:Calendar">1</ResponseRequested>
236               </ApplicationData>
237             </Change>
238           </Commands>
239         </Collection>
240       </Collections>
241     </Sync>';
242     
243     protected $_testXMLMeetingResponse = '<?xml version="1.0" encoding="utf-8"?>
244     <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
245     <MeetingResponse xmlns="uri:MeetingResponse" xmlns:Search="uri:Search">
246         <Request>
247             <UserResponse>2</UserResponse>
248             <CollectionId>17</CollectionId>
249             <RequestId>f0c79775b6b44be446f91187e24566aa1c5d06ab</RequestId>
250             <InstanceId>20121125T130000Z</InstanceId>
251         </Request>
252     </MeetingResponse>';
253
254     protected $_testConcurrentUpdate = '<?xml version="1.0" encoding="utf-8"?>
255     <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
256     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
257       <Collections>
258         <Collection>
259           <SyncKey>26</SyncKey>
260           <CollectionId>calendar-root</CollectionId>
261           <GetChanges/>
262           <WindowSize>25</WindowSize>
263           <Options>
264             <FilterType>4</FilterType>
265             <BodyPreference xmlns="uri:AirSyncBase">
266               <Type>1</Type>
267               <TruncationSize>32768</TruncationSize>
268             </BodyPreference>
269           </Options>
270           <Commands>
271             <Change>
272               <ServerId>b2cb312482f641185b205591f40f78a47ea9f667</ServerId>
273               <ApplicationData>
274                 <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w==</Timezone>
275                 <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
276                 <BusyStatus xmlns="uri:Calendar">2</BusyStatus>
277                 <DtStamp xmlns="uri:Calendar">20131106T072501Z</DtStamp>
278                 <EndTime xmlns="uri:Calendar">20140113T140000Z</EndTime>
279                 <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
280                 <Subject xmlns="uri:Calendar">Mittagspause</Subject>
281                 <StartTime xmlns="uri:Calendar">20140113T120000Z</StartTime>
282                 <UID xmlns="uri:Calendar">1a5010a3d46316a2709cda40683911f95a856665</UID>
283                 <MeetingStatus xmlns="uri:Calendar">1</MeetingStatus>
284                 <Attendees xmlns="uri:Calendar">
285                   <Attendee>
286                     <Name>Unittest, Tine</Name>
287                     <Email>unittest@tine20.org</Email>
288                     <AttendeeType>1</AttendeeType>
289                   </Attendee>
290                 </Attendees>
291                 <Recurrence xmlns="uri:Calendar">
292                   <Type>1</Type>
293                   <Interval>1</Interval>
294                   <DayOfWeek>62</DayOfWeek>
295                   <FirstDayOfWeek>1</FirstDayOfWeek>
296                 </Recurrence>
297                 <Exceptions xmlns="uri:Calendar">
298                   <Exception>
299                     <Body xmlns="uri:AirSyncBase">
300                       <Type>1</Type>
301                       <Data/>
302                     </Body>
303                     <Deleted>0</Deleted>
304                     <ExceptionStartTime>20141203T120000Z</ExceptionStartTime>
305                     <StartTime>20141203T140000Z</StartTime>
306                     <EndTime>20141203T153000Z</EndTime>
307                     <Subject>Mittagspause</Subject>
308                     <BusyStatus>2</BusyStatus>
309                     <AllDayEvent>0</AllDayEvent>
310                     <Attendees>
311                       <Attendee>
312                         <Name>Unittest, Tine</Name>
313                         <Email>unittest@tine20.org</Email>
314                         <AttendeeType>1</AttendeeType>
315                       </Attendee>
316                     </Attendees>
317                   </Exception>
318                   <Exception>
319                     <Body xmlns="uri:AirSyncBase">
320                       <Type>1</Type>
321                       <Data/>
322                     </Body>
323                     <Deleted>0</Deleted>
324                     <ExceptionStartTime>20140625T110000Z</ExceptionStartTime>
325                     <StartTime>20140625T130000Z</StartTime>
326                     <EndTime>20140625T150000Z</EndTime>
327                     <Subject>Mittagspause</Subject>
328                     <BusyStatus>2</BusyStatus>
329                     <AllDayEvent>0</AllDayEvent>
330                     <Attendees>
331                       <Attendee>
332                         <Name>Unittest, Tine</Name>
333                         <Email>unittest@tine20.org</Email>
334                         <AttendeeType>1</AttendeeType>
335                       </Attendee>
336                     </Attendees>
337                   </Exception>
338                 </Exceptions>
339               </ApplicationData>
340             </Change>
341           </Commands>
342         </Collection>
343       </Collections>
344     </Sync>';
345
346     protected $_testConcurrentUpdateUpdate = '<?xml version="1.0" encoding="utf-8"?>
347     <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
348     <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
349       <Collections>
350         <Collection>
351           <SyncKey>26</SyncKey>
352           <CollectionId>calendar-root</CollectionId>
353           <GetChanges/>
354           <WindowSize>25</WindowSize>
355           <Options>
356             <FilterType>4</FilterType>
357             <BodyPreference xmlns="uri:AirSyncBase">
358               <Type>1</Type>
359               <TruncationSize>32768</TruncationSize>
360             </BodyPreference>
361           </Options>
362           <Commands>
363             <Change>
364               <ServerId>b2cb312482f641185b205591f40f78a47ea9f667</ServerId>
365               <ApplicationData>
366                 <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w==</Timezone>
367                 <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
368                 <BusyStatus xmlns="uri:Calendar">2</BusyStatus>
369                 <DtStamp xmlns="uri:Calendar">20131106T072501Z</DtStamp>
370                 <EndTime xmlns="uri:Calendar">20140113T140000Z</EndTime>
371                 <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
372                 <Subject xmlns="uri:Calendar">Mittagspause</Subject>
373                 <StartTime xmlns="uri:Calendar">20140113T120000Z</StartTime>
374                 <UID xmlns="uri:Calendar">1a5010a3d46316a2709cda40683911f95a856665</UID>
375                 <MeetingStatus xmlns="uri:Calendar">1</MeetingStatus>
376                 <Attendees xmlns="uri:Calendar">
377                   <Attendee>
378                     <Name>Unittest, Tine</Name>
379                     <Email>unittest@tine20.org</Email>
380                     <AttendeeType>1</AttendeeType>
381                   </Attendee>
382                 </Attendees>
383                 <Recurrence xmlns="uri:Calendar">
384                   <Type>1</Type>
385                   <Interval>1</Interval>
386                   <DayOfWeek>62</DayOfWeek>
387                   <FirstDayOfWeek>1</FirstDayOfWeek>
388                 </Recurrence>
389                 <Exceptions xmlns="uri:Calendar">
390                   <Exception>
391                     <Body xmlns="uri:AirSyncBase">
392                       <Type>1</Type>
393                       <Data/>
394                     </Body>
395                     <Deleted>0</Deleted>
396                     <ExceptionStartTime>20141203T120000Z</ExceptionStartTime>
397                     <StartTime>20141203T140000Z</StartTime>
398                     <EndTime>20141203T153000Z</EndTime>
399                     <Subject>Mittagspause</Subject>
400                     <BusyStatus>2</BusyStatus>
401                     <AllDayEvent>0</AllDayEvent>
402                     <Attendees>
403                       <Attendee>
404                         <Name>Unittest, Tine</Name>
405                         <Email>unittest@tine20.org</Email>
406                         <AttendeeType>1</AttendeeType>
407                       </Attendee>
408                     </Attendees>
409                   </Exception>
410                   <Exception>
411                     <Body xmlns="uri:AirSyncBase">
412                       <Type>1</Type>
413                       <Data/>
414                     </Body>
415                     <Deleted>0</Deleted>
416                     <ExceptionStartTime>20140625T110000Z</ExceptionStartTime>
417                     <StartTime>20140625T130000Z</StartTime>
418                     <EndTime>20140625T150000Z</EndTime>
419                     <Subject>Abendessen</Subject>
420                     <BusyStatus>2</BusyStatus>
421                     <AllDayEvent>0</AllDayEvent>
422                     <Attendees>
423                       <Attendee>
424                         <Name>Unittest, Tine</Name>
425                         <Email>unittest@tine20.org</Email>
426                         <AttendeeType>1</AttendeeType>
427                       </Attendee>
428                     </Attendees>
429                   </Exception>
430                 </Exceptions>
431               </ApplicationData>
432             </Change>
433           </Commands>
434         </Collection>
435       </Collections>
436     </Sync>';
437
438     /**
439      * (non-PHPdoc)
440      * @see ActiveSync/ActiveSync_TestCase::setUp()
441      */
442     protected function setUp()
443     {
444         parent::setUp();
445         
446         Calendar_Controller_Event::getInstance()->doContainerACLChecks(true);
447
448         $this->_testXMLInput = $this->_loadFile('event_with_attendee.xml');
449     }
450
451     protected function _loadFile($filename)
452     {
453         $xml = file_get_contents(__DIR__ . '/files/' . $filename);
454
455         // replace email to make current user organizer and attendee
456         $email = $this->_getEmailAddress();
457
458         $xml = str_replace(array(
459             'lars@kneschke.de',
460             'unittest@tine20.org',
461         ), $email, $xml);
462
463         return $xml;
464     }
465
466     /**
467      * (non-PHPdoc)
468      * @see ActiveSync_TestCase::testCreateEntry()
469      */
470     public function testCreateEntry($syncrotonFolder = null)
471     {
472         if ($syncrotonFolder === null) {
473             $syncrotonFolder = $this->testCreateFolder();
474         }
475         
476         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_WEBOS), Tinebase_DateTime::now());
477         
478         $now = Tinebase_DateTime::now();
479         $thisYear = $now->format('Y');
480         $xmlString = preg_replace('/2012/', $thisYear, $this->_testXMLInput);
481         $xml = new SimpleXMLElement($xmlString);
482         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
483         
484         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
485
486         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
487         
488         $this->assertEquals(0,         $syncrotonEvent->allDayEvent, 'alldayEvent');
489         $this->assertEquals(2,         $syncrotonEvent->busyStatus);
490         $this->assertEquals('Repeat',  $syncrotonEvent->subject);
491         $this->assertEquals(15,        $syncrotonEvent->reminder);
492         $this->assertEquals(2,         $syncrotonEvent->sensitivity);
493         $this->assertTrue($syncrotonEvent->endTime instanceof DateTime);
494         $this->assertTrue($syncrotonEvent->startTime instanceof DateTime);
495         $this->assertEquals($thisYear . '1123T160000Z', $syncrotonEvent->endTime->format('Ymd\THis\Z'));
496         $this->assertEquals($thisYear . '1123T130000Z', $syncrotonEvent->startTime->format('Ymd\THis\Z'));
497         $this->assertEquals(1, count($syncrotonEvent->attendees), 'event: ' . var_export($syncrotonEvent->attendees, TRUE));
498         $this->assertEquals(Tinebase_Core::getUser()->accountEmailAddress, $syncrotonEvent->attendees[0]->email, 'event: ' . var_export($syncrotonEvent, TRUE));
499         
500         //Body
501         $this->assertTrue($syncrotonEvent->body instanceof Syncroton_Model_EmailBody);
502         $this->assertEquals('Hello', $syncrotonEvent->body->data);
503         
504         // Recurrence
505         $this->assertTrue($syncrotonEvent->recurrence instanceof Syncroton_Model_EventRecurrence);
506         $this->assertEquals(Syncroton_Model_EventRecurrence::TYPE_DAILY, $syncrotonEvent->recurrence->type);
507         $this->assertEquals(1, $syncrotonEvent->recurrence->interval);
508         $this->assertTrue($syncrotonEvent->recurrence->until instanceof DateTime);
509         $this->assertEquals($thisYear . '1128T225959Z', $syncrotonEvent->recurrence->until->format('Ymd\THis\Z'));
510         
511         // Exceptions
512         $this->assertEquals(2, count($syncrotonEvent->exceptions));
513         $this->assertTrue($syncrotonEvent->exceptions[0] instanceof Syncroton_Model_EventException);
514         $this->assertFalse(isset($syncrotonEvent->exceptions[0]->deleted), 'exception deleted with value of 0 should not be set');
515         $this->assertEquals('Repeat mal anders', $syncrotonEvent->exceptions[0]->subject);
516         $this->assertEquals($thisYear . '1125T130000Z', $syncrotonEvent->exceptions[0]->exceptionStartTime->format('Ymd\THis\Z'));
517         $this->assertEquals($thisYear . '1125T170000Z', $syncrotonEvent->exceptions[0]->endTime->format('Ymd\THis\Z'));
518         $this->assertEquals($thisYear . '1125T140000Z', $syncrotonEvent->exceptions[0]->startTime->format('Ymd\THis\Z'));
519         
520         $this->assertEquals(1, $syncrotonEvent->exceptions[1]->deleted);
521         $this->assertEquals($thisYear . '1124T130000Z', $syncrotonEvent->exceptions[1]->exceptionStartTime->format('Ymd\THis\Z'));
522         
523         return array($serverId, $syncrotonEvent);
524     }
525     
526     public function testCreateEntryPalmPreV12($syncrotonFolder = null)
527     {
528         if ($syncrotonFolder === null) {
529             $syncrotonFolder = $this->testCreateFolder();
530         }
531     
532         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
533     
534         $xml = new SimpleXMLElement($this->_testXMLInput_palmPreV12);
535         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
536     
537         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
538     
539         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
540     
541         #echo '----------------' . PHP_EOL; foreach ($syncrotonEvent as $key => $value) {echo "$key => "; var_dump($value);}
542         
543         $this->assertEquals(1,         $syncrotonEvent->allDayEvent);
544         $this->assertTrue($syncrotonEvent->endTime instanceof DateTime);
545         $this->assertTrue($syncrotonEvent->startTime instanceof DateTime);
546         $this->assertEquals('20101106T230000Z', $syncrotonEvent->endTime->format('Ymd\THis\Z'));
547         $this->assertEquals('20101103T230000Z', $syncrotonEvent->startTime->format('Ymd\THis\Z'));
548     
549         return array($serverId, $syncrotonEvent);
550     }
551     
552     public function testCreateEntryDailyRepeating($syncrotonFolder = null)
553     {
554         if ($syncrotonFolder === null) {
555             $syncrotonFolder = $this->testCreateFolder();
556         }
557     
558         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
559     
560         $xml = new SimpleXMLElement($this->_testXMLInput_DailyRepeatingEvent);
561         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Add[0]->ApplicationData);
562     
563         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
564     
565         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
566     
567         #echo '----------------' . PHP_EOL; foreach ($syncrotonEvent as $key => $value) {echo "$key => "; var_dump($value);}
568         
569         $this->assertEquals(0, $syncrotonEvent->allDayEvent);
570         $this->assertEquals(0, $syncrotonEvent->sensitivity);
571         $this->assertTrue($syncrotonEvent->endTime instanceof DateTime);
572         $this->assertTrue($syncrotonEvent->startTime instanceof DateTime);
573         $this->assertEquals('20101220T100000Z', $syncrotonEvent->endTime->format('Ymd\THis\Z'));
574         $this->assertEquals('20101220T090000Z', $syncrotonEvent->startTime->format('Ymd\THis\Z'));
575     
576         // Recurrence
577         $this->assertTrue($syncrotonEvent->recurrence instanceof Syncroton_Model_EventRecurrence);
578         $this->assertEquals(Syncroton_Model_EventRecurrence::TYPE_DAILY, $syncrotonEvent->recurrence->type);
579         $this->assertEquals(1, $syncrotonEvent->recurrence->interval);
580         $this->assertTrue($syncrotonEvent->recurrence->until instanceof DateTime);
581         $this->assertEquals('20101222T225959Z', $syncrotonEvent->recurrence->until->format('Ymd\THis\Z'));
582         
583         return array($serverId, $syncrotonEvent);
584     }
585     
586     public function testCreateEntrySamsungGalaxyStatus($syncrotonFolder = null)
587     {
588         if ($syncrotonFolder === null) {
589             $syncrotonFolder = $this->testCreateFolder();
590         }
591     
592         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_SMASUNGGALAXYS2), Tinebase_DateTime::now());
593     
594         $xml = new SimpleXMLElement($this->_testXMLInput_SamsungGalaxyStatus);
595         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
596     
597         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
598     
599         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
600     
601         #echo '----------------' . PHP_EOL; foreach ($syncrotonEvent as $key => $value) {echo "$key => "; var_dump($value);}
602         
603         $this->assertEquals(Syncroton_Model_Event::BUSY_STATUS_BUSY, $syncrotonEvent->busyStatus);
604         
605         return array($serverId, $syncrotonEvent);
606     }
607     
608     public function testConcurrentUpdate($syncrotonFolder = null)
609     {
610         if ($syncrotonFolder === null) {
611             $syncrotonFolder = $this->testCreateFolder();
612         }
613         
614         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
615         
616         $xml = new SimpleXMLElement($this->_testConcurrentUpdate);
617         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
618         
619         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
620         
621         $event = Calendar_Controller_Event::getInstance()->get($serverId);
622         
623         // change exception #2
624         $exceptions = Calendar_Controller_Event::getInstance()->getRecurExceptions($event);
625         foreach ($exceptions as $exception) {
626             if ($exception->dtstart->toString() == '2014-06-25 13:00:00') {
627                 $exception->summary = 'Fruehstueck';
628                 Calendar_Controller_Event::getInstance()->update($exceptions[1]);
629             }
630         }
631         
632         $xmlUpdate = new SimpleXMLElement($this->_testConcurrentUpdateUpdate);
633         $syncrotonEvent = new Syncroton_Model_Event($xmlUpdate->Collections->Collection->Commands->Change[0]->ApplicationData);
634
635         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->creation_time;
636         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
637         
638         // update exception - should not throw concurrency exception
639         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEvent);
640         
641         $event = Calendar_Controller_Event::getInstance()->get($serverId);
642         $exceptions = Calendar_Controller_Event::getInstance()->getRecurExceptions($event);
643         
644         foreach ($exceptions as $exception) {
645             if ($exception->dtstart->toString() == '2014-06-25 13:00:00') {
646                 $this->assertEquals('Abendessen', $exception->summary, print_r($exceptions[1]->toArray(), true));
647             } else {
648                 $this->assertEquals('Mittagspause', $exception->summary, print_r($exceptions[1]->toArray(), true));
649             }
650         }
651     }
652
653     public function testCreateEntryOutlook13($syncrotonFolder = null)
654     {
655         if ($syncrotonFolder === null) {
656             $syncrotonFolder = $this->testCreateFolder();
657         }
658     
659         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_WEBOS), Tinebase_DateTime::now());
660     
661         $xml = new SimpleXMLElement($this->_testXMLInputOutlook13);
662         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
663     
664         $tine20Event = $controller->toTineModel($syncrotonEvent);
665 //         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
666     
667         $this->assertFalse(!!$tine20Event->exdate[0]->is_deleted);
668     }
669     
670     public function testUpdateEntry($syncrotonFolder = null)
671     {
672         if ($syncrotonFolder === null) {
673             $syncrotonFolder = $this->testCreateFolder();
674         }
675     
676         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
677     
678         list($serverId, $syncrotonEvent) = $this->testCreateEntry($syncrotonFolder);
679     
680         unset($syncrotonEvent->recurrence);
681         unset($syncrotonEvent->exceptions);
682         
683         // need to create new controller to set new sync timestamp for concurrency handling
684         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->last_modified_time;
685         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
686         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEvent);
687         
688         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
689     
690         $this->assertFalse($syncrotonEvent->recurrence instanceof Syncroton_Model_EventRecurrence);
691     
692         return array($serverId, $syncrotonEvent);
693     }
694
695     /**
696      * testUpdateExdate
697      * 
698      * @see 0010417: Exdate update does not update seq of base event
699      */
700     public function testUpdateExdate()
701     {
702         list($serverId, $syncrotonEvent) = $this->testCreateEntry();
703         
704         $event = Calendar_Controller_Event::getInstance()->get($serverId);
705         $container = Tinebase_Container::getInstance()->get($event->container_id);
706         
707         $exception = Calendar_Controller_Event::getInstance()->getRecurExceptions($event)->getFirstRecord();
708         $exception->dtstart->subHour(1);
709         Calendar_Controller_Event::getInstance()->update($exception);
710         
711         $baseEventAfterExdateUpdate = Calendar_Controller_Event::getInstance()->get($serverId);
712         $containerAfterExdateUpdate = Tinebase_Container::getInstance()->get($event->container_id);
713         $this->assertEquals($event->seq + 1, $baseEventAfterExdateUpdate->seq, 'base sequence should be updated');
714         $this->assertEquals($container->content_seq + 2, $containerAfterExdateUpdate->content_seq, 'container sequence should be updated');
715     }
716
717     /**
718      * testDeleteExdate
719      *
720      * @see : Exdate delete does not update seq of base event
721      */
722     public function testDeleteExdate()
723     {
724         list($serverId, $syncrotonEvent) = $this->testCreateEntry();
725
726         $event = Calendar_Controller_Event::getInstance()->get($serverId);
727         $container = Tinebase_Container::getInstance()->get($event->container_id);
728
729         $exception = Calendar_Controller_Event::getInstance()->getRecurExceptions($event)->getFirstRecord();
730         Calendar_Controller_Event::getInstance()->delete($exception);
731
732         $baseEventAfterExdateDelete = Calendar_Controller_Event::getInstance()->get($serverId);
733         $containerAfterExdateDelete = Tinebase_Container::getInstance()->get($event->container_id);
734         $this->assertGreaterThan($event->seq, $baseEventAfterExdateDelete->seq, 'base sequence should be updated');
735         $this->assertGreaterThan($container->content_seq, $containerAfterExdateDelete->content_seq, 'container sequence should be updated');
736     }
737
738     public function testRecurEventExceptionFilters($syncrotonFolder = null)
739     {
740         if ($syncrotonFolder === null) {
741             $syncrotonFolder = $this->testCreateFolder();
742         }
743         
744         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
745         
746         list($serverId, $syncrotonEvent) = $this->testCreateEntry($syncrotonFolder);
747         
748         // remove testuser as attendee
749         $eventBackend = new Calendar_Backend_Sql();
750         $exception = $eventBackend->getByProperty($syncrotonEvent->uID . '-' . $syncrotonEvent->exceptions[0]->exceptionStartTime->format(Tinebase_Record_Abstract::ISO8601LONG), 'recurid');
751         $ownAttendee = Calendar_Model_Attender::getOwnAttender($exception->attendee);
752         $eventBackend->deleteAttendee(array($ownAttendee->getId()));
753         
754         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
755         
756         // assert fallout by filter
757         $this->assertTrue((bool) $syncrotonEvent->exceptions[0]->deleted);
758         $this->assertTrue((bool) $syncrotonEvent->exceptions[1]->deleted);
759     }
760
761     public function testRecurEventFirstInstanceException($syncrotonFolder = null)
762     {
763         if ($syncrotonFolder === null) {
764             $syncrotonFolder = $this->testCreateFolder();
765         }
766
767         $xmlString = $this->_loadFile('repeating_with_first_instance_exception.xml');
768         $xml = new SimpleXMLElement($xmlString);
769         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Add[0]->ApplicationData);
770
771         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
772
773         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
774
775         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
776
777         $this->assertEquals('First Instance Exception', $syncrotonEvent->exceptions[0]->subject);
778         $this->assertCount(1, $syncrotonEvent->exceptions);
779
780         return array($serverId, $syncrotonEvent);
781     }
782
783     public function testStatusUpdate($syncrotonFolder = null)
784     {
785         if (Tinebase_User::getConfiguredBackend() === Tinebase_User::ACTIVEDIRECTORY) {
786             $this->markTestSkipped('only working in non-AD setups');
787         }
788
789         if ($syncrotonFolder === null) {
790             $syncrotonFolder = $this->testCreateFolder();
791         }
792         
793         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
794         
795         list($serverId, $syncrotonEvent) = $this->testCreateEntry($syncrotonFolder);
796         
797         // transfer event to other user
798         $rwright = Tinebase_Helper::array_value('rwright', $this->_personas = Zend_Registry::get('personas'));
799         $eventBackend = new Calendar_Backend_Sql();
800         $eventBackend->updateMultiple($eventBackend->getMultipleByProperty($syncrotonEvent->uID, 'uid')->id, array(
801             'container_id'  => Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::DEFAULTCALENDAR, $rwright->getId()),
802             'organizer'     => $rwright->contact_id
803         ));
804         
805         $syncrotonEvent->exceptions[0]->busyStatus = 1;
806         $syncrotonEvent->exceptions[0]->subject = 'do not update';
807         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEvent);
808         
809         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
810         
811         $event = Calendar_Controller_MSEventFacade::getInstance()->get($serverId);
812         $attendee = $event->exdate->getFirstRecord()->attendee->getFirstRecord();
813
814         $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $attendee->status);
815         $this->assertNotEquals('do not update', $event->summary);
816     }
817     
818     public function testMeetingResponse()
819     {
820         $syncrotonFolder = $this->testCreateFolder();
821         
822         list($serverId, $event) = $this->testCreateEntry($syncrotonFolder);
823         
824         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
825         
826         $XMLMeetingResponse = $this->_testXMLMeetingResponse;
827         
828         $XMLMeetingResponse = str_replace('<CollectionId>17</CollectionId>', '<CollectionId>' . $syncrotonFolder->serverId . '</CollectionId>', $XMLMeetingResponse);
829         $XMLMeetingResponse = str_replace('<RequestId>f0c79775b6b44be446f91187e24566aa1c5d06ab</RequestId>', '<RequestId>' . $serverId . '</RequestId>', $XMLMeetingResponse);
830         $XMLMeetingResponse = str_replace('<InstanceId>20121125T130000Z</InstanceId>', '', $XMLMeetingResponse);
831         
832         $xml = new SimpleXMLElement($XMLMeetingResponse);
833         
834         $meetingResponse = new Syncroton_Model_MeetingResponse($xml->Request[0]);
835         
836         $eventId = $controller->setAttendeeStatus($meetingResponse);
837         
838         $event = Calendar_Controller_Event::getInstance()->get($serverId);
839         $ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee);
840         
841         $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $ownAttendee->status);
842     }
843     
844     public function testMeetingResponseWithExistingInstanceId()
845     {
846         $syncrotonFolder = $this->testCreateFolder();
847         
848         list($serverId, $event) = $this->testCreateEntry($syncrotonFolder);
849         
850         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), new Tinebase_DateTime(null, null, 'de_DE'));
851         
852         $XMLMeetingResponse = $this->_testXMLMeetingResponse;
853         
854         $thisYear = Tinebase_DateTime::now()->format('Y');
855         $XMLMeetingResponse = str_replace('2012', $thisYear, $XMLMeetingResponse);
856         $XMLMeetingResponse = str_replace('<CollectionId>17</CollectionId>', '<CollectionId>' . $syncrotonFolder->serverId . '</CollectionId>', $XMLMeetingResponse);
857         $XMLMeetingResponse = str_replace('<RequestId>f0c79775b6b44be446f91187e24566aa1c5d06ab</RequestId>', '<RequestId>' . $serverId . '</RequestId>', $XMLMeetingResponse);
858         
859         $xml = new SimpleXMLElement($XMLMeetingResponse);
860         
861         $meetingResponse = new Syncroton_Model_MeetingResponse($xml->Request[0]);
862         
863         $eventId = $controller->setAttendeeStatus($meetingResponse);
864         
865         $event = Calendar_Controller_MSEventFacade::getInstance()->get($serverId);
866         $instance = $event->exdate->filter('is_deleted', 0)->getFirstRecord();
867         $ownAttendee = Calendar_Model_Attender::getOwnAttender($instance->attendee);
868         
869         $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $ownAttendee->status);
870     }
871     
872     public function testMeetingResponseWithNewInstanceId()
873     {
874         $syncrotonFolder = $this->testCreateFolder();
875         
876         list($serverId, $event) = $this->testCreateEntry($syncrotonFolder);
877         
878         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), new Tinebase_DateTime(null, null, 'de_DE'));
879         
880         $XMLMeetingResponse = $this->_testXMLMeetingResponse;
881         
882         $thisYear = Tinebase_DateTime::now()->format('Y');
883         $XMLMeetingResponse = str_replace('2012', $thisYear, $XMLMeetingResponse);
884         $XMLMeetingResponse = str_replace('<CollectionId>17</CollectionId>', '<CollectionId>' . $syncrotonFolder->serverId . '</CollectionId>', $XMLMeetingResponse);
885         $XMLMeetingResponse = str_replace('<RequestId>f0c79775b6b44be446f91187e24566aa1c5d06ab</RequestId>', '<RequestId>' . $serverId . '</RequestId>', $XMLMeetingResponse);
886         $XMLMeetingResponse = str_replace('<InstanceId>20121125T130000Z</InstanceId>', '<InstanceId>20121126T130000Z</InstanceId>', $XMLMeetingResponse);
887         
888         $xml = new SimpleXMLElement($XMLMeetingResponse);
889         
890         $meetingResponse = new Syncroton_Model_MeetingResponse($xml->Request[0]);
891         
892         $eventId = $controller->setAttendeeStatus($meetingResponse);
893         
894         $event = Calendar_Controller_MSEventFacade::getInstance()->get($serverId);
895         $event->exdate->sort('dtstart', 'DESC');
896         $instance = $event->exdate->filter('is_deleted', 0)->getFirstRecord();
897         $ownAttendee = Calendar_Model_Attender::getOwnAttender($instance->attendee);
898         
899         $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $ownAttendee->status);
900     }
901     
902     /**
903      * test search events (unsyncable)
904      * 
905      * TODO finish this -> assertion fails atm because the event is found even if it is in an unsyncable folder and has no attendees (but 1 exdate)
906      */
907     public function _testUnsyncableSearch()
908     {
909         $this->markTestSkipped();
910         
911         $controller = $this->_getController($this->_getDevice(Syncroton_Model_Device::TYPE_WEBOS));
912
913         $xml = simplexml_import_dom($this->_getInputDOMDocument());
914         
915         $record = $controller->createEntry($this->_getContainerWithoutSyncGrant()->getId(), $xml->Collections->Collection->Commands->Change[0]->ApplicationData);
916         $record->exdate = new Tinebase_Record_RecordSet('Calendar_Model_Event');
917         $record->attendee = NULL;
918
919         $this->objects['events'][] = Calendar_Controller_MSEventFacade::getInstance()->update($record);
920         
921         $events = $controller->search($this->_specialFolderName, $xml->Collections->Collection->Commands->Change[0]->ApplicationData);
922         
923         $this->assertEquals(0, count($events));
924     }
925     
926     /**
927      * testEventWithTags
928      * 
929      * @see 0007346: events with tags are not synced
930      */
931     public function testEventWithTags()
932     {
933         $event = ActiveSync_TestCase::getTestEvent();
934         $event->tags = array(array(
935             'name' => 'test tag',
936             'type' => Tinebase_Model_Tag::TYPE_PERSONAL
937         ));
938         $event = Calendar_Controller_Event::getInstance()->create($event);
939         
940         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
941         $syncrotonEvent = $controller->toSyncrotonModel($event);
942         
943         $this->assertTrue(is_array($syncrotonEvent->categories));
944         $this->assertTrue(in_array('test tag', $syncrotonEvent->categories), 'tag not found in categories: ' . print_r($syncrotonEvent->categories, TRUE));
945     }
946     
947     /**
948      * testEventWithAlarmToSyncrotonModel
949      */
950     public function testEventWithAlarmToSyncrotonModel()
951     {
952         $event = ActiveSync_TestCase::getTestEvent();
953         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(array(
954             'minutes_before' => 15,
955             'alarm_time'     => $event->dtstart->getClone()->subMinute(15),
956             'model'          => 'Calendar_Model_Event'
957         )));
958         
959         $event = Calendar_Controller_Event::getInstance()->create($event);
960         
961         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
962         $syncrotonEvent = $controller->toSyncrotonModel($event);
963         
964         $this->assertEquals(15, $syncrotonEvent->reminder);
965     }
966     
967     /**
968      * @see 0007346 - organizer perspective for alarms
969      */
970     public function testEventWithAlarmToTine20Model()
971     {
972         $syncrotonFolder = $this->testCreateFolder();
973         list($serverId, $event) = $this->testCreateEntry($syncrotonFolder);
974         
975         $alarm = Calendar_Controller_Event::getInstance()->get($serverId)->alarms->getFirstRecord();
976         $this->assertFalse(!!$alarm->getOption('attendee'));
977     }
978     
979     /**
980      * calendar has different grant handling
981      * @see 0007450: shared calendars of other users (iOS)
982      */
983     public function testGetAllFoldersWithContainerSyncFilter()
984     {
985         $device = $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE);
986         $controller = Syncroton_Data_Factory::factory($this->_class, $device, new Tinebase_DateTime(null, null, 'de_DE'));
987     
988         $folderA = $this->testCreateFolder(); // personal of test user
989         
990         $sclever = Tinebase_Helper::array_value('sclever', Zend_Registry::get('personas'));
991         $folderB = Tinebase_Core::getPreference('Calendar')->getValueForUser(Calendar_Preference::DEFAULTCALENDAR, $sclever->getId());
992
993         // have syncGerant for sclever
994         Tinebase_Container::getInstance()->setGrants($folderB, new Tinebase_Record_RecordSet('Tinebase_Model_Grants', array(
995             array(
996                 'account_id'    => $sclever->getId(),
997                 'account_type'  => 'user',
998                 Tinebase_Model_Grants::GRANT_ADMIN    => true,
999             ),
1000             array(
1001                 'account_id'    => Tinebase_Core::getUser()->getId(),
1002                 'account_type'  => 'user',
1003                 Tinebase_Model_Grants::GRANT_READ     => true,
1004                 Tinebase_Model_Grants::GRANT_SYNC     => true,
1005         ))), TRUE);
1006         
1007         $syncFilter = new Calendar_Model_EventFilter(array(
1008             array('field' => 'container_id', 'operator' => 'in', 'value' => array(
1009                 $folderA->serverId,
1010                 $folderB,
1011             ))
1012         ));
1013         
1014         $syncFavorite = Tinebase_PersistentFilter::getInstance()->create(new Tinebase_Model_PersistentFilter(array(
1015             'application_id'        => Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId(),
1016             'account_id'            => Tinebase_Core::getUser()->getId(),
1017             'model'                 => 'Calendar_Model_EventFilter',
1018             'filters'               => $syncFilter,
1019             'name'                  => 'testSyncFilter',
1020             'description'           => 'test two folders'
1021         )));
1022         
1023         $device->calendarfilterId = $syncFavorite->getId();
1024
1025         $allSyncrotonFolders = $controller->getAllFolders();
1026         
1027         $defaultFolderId = Tinebase_Core::getPreference('Calendar')->{Calendar_Preference::DEFAULTCALENDAR};
1028         
1029         foreach ($allSyncrotonFolders as $syncrotonFolder) {
1030             $this->assertTrue($syncrotonFolder->serverId == $defaultFolderId 
1031                 ? $syncrotonFolder->type === Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR
1032                 : $syncrotonFolder->type === Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED
1033             );
1034         }
1035         
1036         $this->assertEquals(2, count($allSyncrotonFolders));
1037         $this->assertArrayHasKey($folderA->serverId, $allSyncrotonFolders);
1038         $this->assertArrayHasKey($folderB, $allSyncrotonFolders);
1039     }
1040     
1041     /**
1042      * validate that current is not removed from the event after creating and updating event from phone 
1043      * 
1044      * @link https://forge.tine20.org/mantisbt/view.php?id=7606
1045      */
1046     public function testUpdateAfterCreate()
1047     {
1048         $syncrotonFolder = $this->testCreateFolder();
1049     
1050         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_SMASUNGGALAXYS2), Tinebase_DateTime::now());
1051     
1052         $xml = new SimpleXMLElement('
1053             <ApplicationData xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
1054               <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Timezone>
1055               <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
1056               <StartTime xmlns="uri:Calendar">20130124T070000Z</StartTime>
1057               <EndTime xmlns="uri:Calendar">20130124T080000Z</EndTime>
1058               <DtStamp xmlns="uri:Calendar">20121228T001432Z</DtStamp>
1059               <Subject xmlns="uri:Calendar">Neues Ereignis</Subject>
1060               <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
1061               <Body xmlns="uri:AirSyncBase">
1062                 <Type>1</Type>
1063                 <Data></Data>
1064               </Body>
1065               <OrganizerEmail xmlns="uri:Calendar">rep@tine.de</OrganizerEmail>
1066               <UID xmlns="uri:Calendar">24f59962-7243-4938-8b8c-a81fda46977e</UID>
1067               <BusyStatus xmlns="uri:Calendar">2</BusyStatus>
1068               <MeetingStatus xmlns="uri:Calendar">0</MeetingStatus>
1069             </ApplicationData>
1070         ');
1071         $syncrotonEvent = new Syncroton_Model_Event($xml);
1072     
1073         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
1074     
1075         #var_dump(Calendar_Controller_Event::getInstance()->get($serverId)->toArray());
1076         $this->assertEquals(1, count(Calendar_Controller_Event::getInstance()->get($serverId)->attendee), 'count after create');
1077         
1078         $xml = new SimpleXMLElement('
1079             <ApplicationData xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar">
1080                 <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==</Timezone>
1081                 <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
1082                 <StartTime xmlns="uri:Calendar">20130124T070000Z</StartTime>
1083                 <EndTime xmlns="uri:Calendar">20130124T080000Z</EndTime>
1084                 <DtStamp xmlns="uri:Calendar">20121228T001526Z</DtStamp>
1085                 <Subject xmlns="uri:Calendar">Neues Ereignis geƤndert</Subject>
1086                 <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
1087                 <Body xmlns="uri:AirSyncBase">
1088                   <Type>1</Type>
1089                   <Data></Data>
1090                 </Body>
1091                 <OrganizerEmail xmlns="uri:Calendar">rep@tine.de</OrganizerEmail>
1092                 <UID xmlns="uri:Calendar">24f59962-7243-4938-8b8c-a81fda46977e</UID>
1093                 <BusyStatus xmlns="uri:Calendar">2</BusyStatus>
1094                 <MeetingStatus xmlns="uri:Calendar">0</MeetingStatus>
1095             </ApplicationData>
1096         ');
1097         $syncrotonEvent = new Syncroton_Model_Event($xml);
1098         
1099         // need to creaate new controller to set new sync timestamp for concurrency handling
1100         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->creation_time;
1101         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_SMASUNGGALAXYS2), $syncTimestamp);
1102         
1103         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEvent);
1104         
1105         #var_dump(Calendar_Controller_Event::getInstance()->get($serverId)->toArray());
1106         $this->assertEquals(1, count(Calendar_Controller_Event::getInstance()->get($serverId)->attendee), 'count after update');
1107     }
1108
1109     /**
1110      * testAddAlarm
1111      * 
1112      * @see 0008230: added alarm to event on iOS 6.1 -> description removed
1113      */
1114     public function testAddAlarm()
1115     {
1116         $syncrotonFolder = $this->testCreateFolder();
1117         
1118         $event = ActiveSync_TestCase::getTestEvent();
1119         $event->summary = 'testtermin';
1120         $event->description = 'some text';
1121         $event->dtstart = new Tinebase_DateTime('2013-10-22 16:00:00');
1122         $event->dtend = new Tinebase_DateTime('2013-10-22 17:00:00');
1123         $event = Calendar_Controller_Event::getInstance()->create($event);
1124         
1125         $xml = new SimpleXMLElement('
1126           <ApplicationData>
1127             <Timezone xmlns="uri:Calendar">xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1128 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w==</Timezone>
1129             <AllDayEvent xmlns="uri:Calendar">0</AllDayEvent>
1130             <BusyStatus xmlns="uri:Calendar">2</BusyStatus>
1131             <DtStamp xmlns="uri:Calendar">20131021T142015Z</DtStamp>
1132             <EndTime xmlns="uri:Calendar">20131022T170000Z</EndTime>
1133             <Reminder xmlns="uri:Calendar">60</Reminder>
1134             <Sensitivity xmlns="uri:Calendar">0</Sensitivity>
1135             <Subject xmlns="uri:Calendar">testtermin</Subject>
1136             <StartTime xmlns="uri:Calendar">20131022T160000Z</StartTime>
1137             <UID xmlns="uri:Calendar">' . $event->uid . '</UID>
1138             <MeetingStatus xmlns="uri:Calendar">1</MeetingStatus>
1139             <Attendees xmlns="uri:Calendar">
1140               <Attendee>
1141                 <Name>' . Tinebase_Core::getUser()->accountDisplayName . '</Name>
1142                 <Email>' . Tinebase_Core::getUser()->accountEmailAddress . '</Email>
1143                 <AttendeeType>1</AttendeeType>
1144               </Attendee>
1145             </Attendees>
1146           </ApplicationData>
1147         ');
1148         $syncrotonEvent = new Syncroton_Model_Event($xml);
1149         
1150         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $event->creation_time);
1151         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $event->getId(), $syncrotonEvent);
1152         
1153         $updatedEvent = Calendar_Controller_Event::getInstance()->get($serverId);
1154         
1155         $this->assertEquals(1, count($updatedEvent->alarms));
1156         $this->assertEquals($event->description, $updatedEvent->description, 'description mismatch: ' . print_r($updatedEvent->toArray(), true));
1157     }
1158     
1159     public function testGetEntriesIPhone()
1160     {
1161         $syncrotonFolder = $this->testCreateFolder();
1162         
1163         $syncrotonFolder2 = $this->testCreateFolder();
1164         
1165         //make $syncrotonFolder2 the default
1166         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $syncrotonFolder2->serverId);
1167         
1168         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
1169         
1170         $now = Tinebase_DateTime::now();
1171         $thisYear = $now->format('Y');
1172         $xmlString = preg_replace('/2012/', $thisYear, $this->_testXMLInput);
1173         $xml = new SimpleXMLElement($xmlString);
1174         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
1175         
1176         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
1177         
1178         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1179         
1180         $this->assertEmpty($syncrotonEvent->attendees, 'Events attendees found in folder which is not the default calendar');
1181         
1182         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
1183         
1184         $now = Tinebase_DateTime::now();
1185         $thisYear = $now->format('Y');
1186         $xmlString = preg_replace('/2012/', $thisYear, $this->_testXMLInput);
1187         $xml = new SimpleXMLElement($xmlString);
1188         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
1189         
1190         $serverId = $controller->createEntry($syncrotonFolder2->serverId, $syncrotonEvent);
1191         
1192         $syncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder2->serverId)), $serverId);
1193         
1194         $this->assertNotEmpty($syncrotonEvent->attendees, 'Events attendees not found in default calendar');
1195     }
1196
1197     public function testUpdateEntriesIPhone($syncrotonFolder = null)
1198     {
1199         // ensure folder is default
1200         $syncrotonFolder = $syncrotonFolder ? $syncrotonFolder : $this->testCreateFolder();
1201         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $syncrotonFolder->serverId);
1202
1203         // create event with external attendee in default calendar
1204         $xml = new SimpleXMLElement(file_get_contents(__DIR__ . '/files/event_with_attendee.xml'));
1205         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
1206         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
1207         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
1208
1209         // assert external attendee is present
1210         $syncrotonEventtoUpdate = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1211         $this->assertEquals(2, count($syncrotonEventtoUpdate->attendees), 'event: ' . var_export($syncrotonEventtoUpdate->attendees, TRUE));
1212
1213         // update event in non default folder
1214         $syncrotonEventtoUpdate->exceptions[0]->subject = 'update';
1215         $syncrotonEventtoUpdate->exceptions[0]->startTime->addHour(1);
1216         $syncrotonEventtoUpdate->exceptions[0]->endTime->addHour(1);
1217         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->last_modified_time;
1218         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
1219         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEventtoUpdate);
1220
1221         // assert update in default folder
1222         $updatedSyncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1223         $this->assertEquals('update', $updatedSyncrotonEvent->exceptions[0]->subject);
1224         $this->assertEquals('2012-11-25 15:00:00', $updatedSyncrotonEvent->exceptions[0]->startTime->toString());
1225         $this->assertEquals(2, count($updatedSyncrotonEvent->attendees), 'event: ' . var_export($updatedSyncrotonEvent->attendees, TRUE));
1226
1227         return array($serverId, $updatedSyncrotonEvent);
1228     }
1229
1230     /**
1231      * testUpdateEntriesIPhoneNonDefaultFolder
1232      *
1233      * for iOS devices we need to suppress attendee during sync for non default folder (see foldertype in foldersync)
1234      * iOS can only have one default folder
1235      */
1236     public function testUpdateEntriesIPhoneNonDefaultFolder()
1237     {
1238         // create event in default folder
1239         $syncrotonFolder = $this->testCreateFolder();
1240         list($serverId, $syncrotonEvent) = $this->testUpdateEntriesIPhone($syncrotonFolder);
1241
1242         // create new default folder2
1243         $syncrotonFolder2 = $this->testCreateFolder();
1244         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $syncrotonFolder2->serverId);
1245
1246         // load event in non default folder
1247         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
1248         $syncrotonEventtoUpdate = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1249         $this->assertEmpty($syncrotonEventtoUpdate->attendees, 'attendee in non default folders must be removed for ios');
1250
1251         // update event in non default folder
1252         $syncrotonEventtoUpdate->exceptions[0]->subject = 'update2';
1253         $syncrotonEventtoUpdate->exceptions[0]->startTime->addHour(1);
1254         $syncrotonEventtoUpdate->exceptions[0]->endTime->addHour(1);
1255
1256         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->last_modified_time;
1257         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
1258         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEventtoUpdate);
1259
1260         // assert update from default folder
1261         $updatedSyncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder2->serverId)), $serverId);
1262         $this->assertEquals('update2', $updatedSyncrotonEvent->exceptions[0]->subject);
1263         $this->assertNotEquals($syncrotonEvent->exceptions[0]->startTime->toString(), $updatedSyncrotonEvent->exceptions[0]->startTime->toString());
1264         $this->assertEquals($syncrotonEventtoUpdate->exceptions[0]->startTime->toString(), $updatedSyncrotonEvent->exceptions[0]->startTime->toString());
1265         $this->assertEquals(2, count($updatedSyncrotonEvent->attendees), 'event: ' . var_export($updatedSyncrotonEvent->attendees, TRUE));
1266     }
1267
1268     public function testCreateUpdateGroupEvents()
1269     {
1270         $syncrotonFolder = $this->testCreateFolder();
1271         Tinebase_Core::getPreference('Calendar')->setValue(Calendar_Preference::DEFAULTCALENDAR, $syncrotonFolder->serverId);
1272
1273         $defaultUserGroup = Tinebase_Group::getInstance()->getDefaultGroup();
1274         $defaultUserGroupMembers = Tinebase_Group::getInstance()->getGroupMembers($defaultUserGroup->getId());
1275
1276         // create event with default user group (without explicit groupmembers)
1277         $xml = new SimpleXMLElement(str_replace(array(
1278             'usersgroupid',
1279         ), $defaultUserGroup->getId(), file_get_contents(__DIR__ . '/files/event_with_group_attendee.xml')));
1280         $syncrotonEvent = new Syncroton_Model_Event($xml->Collections->Collection->Commands->Change[0]->ApplicationData);
1281         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), Tinebase_DateTime::now());
1282         $serverId = $controller->createEntry($syncrotonFolder->serverId, $syncrotonEvent);
1283
1284         // assert created group & groupmembers
1285         $syncrotonEventtoUpdate = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1286         $this->assertCount(count($defaultUserGroupMembers) + 1, $syncrotonEventtoUpdate->attendees, 'groupmembers not resolved: ' . print_r($syncrotonEventtoUpdate->attendees, true));
1287         $this->assertCount(count($defaultUserGroupMembers) + 1, $syncrotonEventtoUpdate->exceptions[0]->attendees, 'groupmembers not resolved');
1288
1289         // update event
1290         $syncrotonEventtoUpdate->exceptions[0]->subject = 'update';
1291         $syncTimestamp = Calendar_Controller_Event::getInstance()->get($serverId)->last_modified_time;
1292         $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), $syncTimestamp);
1293         $serverId = $controller->updateEntry($syncrotonFolder->serverId, $serverId, $syncrotonEventtoUpdate);
1294
1295         // assert updated group & groupmembers
1296         $updatedSyncrotonEvent = $controller->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $syncrotonFolder->serverId)), $serverId);
1297         $this->assertCount(count($defaultUserGroupMembers) + 1, $updatedSyncrotonEvent->attendees, 'groupmembers not resolved');
1298         $this->assertCount(count($defaultUserGroupMembers) + 1, $updatedSyncrotonEvent->exceptions[0]->attendees, 'groupmembers not resolved');
1299     }
1300 }