• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.exchange.adapter;
18 
19 import com.android.exchange.adapter.AbstractSyncAdapter.Operation;
20 import com.android.exchange.adapter.CalendarSyncAdapter.CalendarOperations;
21 import com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser;
22 import com.android.exchange.provider.MockProvider;
23 
24 import android.content.ContentProviderOperation;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.OperationApplicationException;
28 import android.content.res.Resources;
29 import android.database.Cursor;
30 import android.os.RemoteException;
31 import android.provider.CalendarContract.Attendees;
32 import android.provider.CalendarContract.Events;
33 import android.test.IsolatedContext;
34 import android.test.RenamingDelegatingContext;
35 import android.test.mock.MockContentResolver;
36 import android.test.mock.MockContext;
37 import android.test.suitebuilder.annotation.MediumTest;
38 
39 import java.io.ByteArrayInputStream;
40 import java.io.File;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.GregorianCalendar;
44 import java.util.List;
45 import java.util.TimeZone;
46 
47 /**
48  * You can run this entire test case with:
49  *   runtest -c com.android.exchange.adapter.CalendarSyncAdapterTests exchange
50  */
51 @MediumTest
52 public class CalendarSyncAdapterTests extends SyncAdapterTestCase<CalendarSyncAdapter> {
53     private static final String[] ATTENDEE_PROJECTION = new String[] {Attendees.ATTENDEE_EMAIL,
54             Attendees.ATTENDEE_NAME, Attendees.ATTENDEE_STATUS};
55     private static final int ATTENDEE_EMAIL = 0;
56     private static final int ATTENDEE_NAME = 1;
57     private static final int ATTENDEE_STATUS = 2;
58 
59     private static final String SINGLE_ATTENDEE_EMAIL = "attendee@host.com";
60     private static final String SINGLE_ATTENDEE_NAME = "Bill Attendee";
61 
62     private Context mMockContext;
63     private MockContentResolver mMockResolver;
64 
65     // This is the US/Pacific time zone as a base64-encoded TIME_ZONE_INFORMATION structure, as
66     // it would appear coming from an Exchange server
67     private static final String TEST_TIME_ZONE = "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByA" +
68         "GQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAY" +
69         "QBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAA" +
70         "AAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==";
71 
72     private class MockContext2 extends MockContext {
73 
74         @Override
getResources()75         public Resources getResources() {
76             return getContext().getResources();
77         }
78 
79         @Override
getDir(String name, int mode)80         public File getDir(String name, int mode) {
81             // name the directory so the directory will be separated from
82             // one created through the regular Context
83             return getContext().getDir("mockcontext2_" + name, mode);
84         }
85 
86         @Override
getApplicationContext()87         public Context getApplicationContext() {
88             return this;
89         }
90     }
91 
92     @Override
setUp()93     public void setUp() throws Exception {
94         super.setUp();
95 
96         mMockResolver = new MockContentResolver();
97         final String filenamePrefix = "test.";
98         RenamingDelegatingContext targetContextWrapper = new
99         RenamingDelegatingContext(
100                 new MockContext2(), // The context that most methods are delegated to
101                 getContext(), // The context that file methods are delegated to
102                 filenamePrefix);
103         mMockContext = new IsolatedContext(mMockResolver, targetContextWrapper);
104         mMockResolver.addProvider(MockProvider.AUTHORITY, new MockProvider(mMockContext));
105     }
106 
CalendarSyncAdapterTests()107     public CalendarSyncAdapterTests() {
108         super();
109     }
110 
testSetTimeRelatedValues_NonRecurring()111     public void testSetTimeRelatedValues_NonRecurring() throws IOException {
112         CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
113         EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
114         ContentValues cv = new ContentValues();
115         // Basic, one-time meeting lasting an hour
116         GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
117         Long startTime = startCalendar.getTimeInMillis();
118         GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
119         Long endTime = endCalendar.getTimeInMillis();
120 
121         p.setTimeRelatedValues(cv, startTime, endTime, 0);
122         assertNull(cv.getAsInteger(Events.DURATION));
123         assertEquals(startTime, cv.getAsLong(Events.DTSTART));
124         assertEquals(endTime, cv.getAsLong(Events.DTEND));
125         assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
126         assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
127     }
128 
testSetTimeRelatedValues_Recurring()129     public void testSetTimeRelatedValues_Recurring() throws IOException {
130         CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
131         EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
132         ContentValues cv = new ContentValues();
133         // Recurring meeting lasting an hour
134         GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
135         Long startTime = startCalendar.getTimeInMillis();
136         GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
137         Long endTime = endCalendar.getTimeInMillis();
138         cv.put(Events.RRULE, "FREQ=DAILY");
139         p.setTimeRelatedValues(cv, startTime, endTime, 0);
140         assertEquals("P60M", cv.getAsString(Events.DURATION));
141         assertEquals(startTime, cv.getAsLong(Events.DTSTART));
142         assertNull(cv.getAsLong(Events.DTEND));
143         assertNull(cv.getAsLong(Events.LAST_DATE));
144         assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
145     }
146 
testSetTimeRelatedValues_AllDay()147     public void testSetTimeRelatedValues_AllDay() throws IOException {
148         CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
149         EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
150         ContentValues cv = new ContentValues();
151         GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
152         Long startTime = startCalendar.getTimeInMillis();
153         GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 11, 8, 30);
154         Long endTime = endCalendar.getTimeInMillis();
155         cv.put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO");
156         p.setTimeRelatedValues(cv, startTime, endTime, 1);
157 
158         // The start time should have hour/min/sec zero'd out
159         startCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
160         startCalendar.set(2010, 5, 10, 0, 0, 0);
161         startCalendar.set(GregorianCalendar.MILLISECOND, 0);
162         startTime = startCalendar.getTimeInMillis();
163         assertEquals(startTime, cv.getAsLong(Events.DTSTART));
164 
165         // The duration should be in days
166         assertEquals("P1D", cv.getAsString(Events.DURATION));
167         assertNull(cv.getAsLong(Events.DTEND));
168         assertNull(cv.getAsLong(Events.LAST_DATE));
169         // There must be a timezone
170         assertNotNull(cv.getAsString(Events.EVENT_TIMEZONE));
171     }
172 
testSetTimeRelatedValues_Recurring_AllDay_Exception()173     public void testSetTimeRelatedValues_Recurring_AllDay_Exception () throws IOException {
174         CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
175         EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
176         ContentValues cv = new ContentValues();
177 
178         // Recurrence exception for all-day event; the exception is NOT all-day
179         GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
180         Long startTime = startCalendar.getTimeInMillis();
181         GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 17, 9, 30);
182         Long endTime = endCalendar.getTimeInMillis();
183         cv.put(Events.ORIGINAL_ALL_DAY, 1);
184         GregorianCalendar instanceCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
185         cv.put(Events.ORIGINAL_INSTANCE_TIME, instanceCalendar.getTimeInMillis());
186         p.setTimeRelatedValues(cv, startTime, endTime, 0);
187 
188         // The original instance time should have hour/min/sec zero'd out
189         GregorianCalendar testCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
190         testCalendar.set(2010, 5, 17, 0, 0, 0);
191         testCalendar.set(GregorianCalendar.MILLISECOND, 0);
192         Long testTime = testCalendar.getTimeInMillis();
193         assertEquals(testTime, cv.getAsLong(Events.ORIGINAL_INSTANCE_TIME));
194 
195         // The exception isn't all-day, so we should have DTEND and LAST_DATE and no EVENT_TIMEZONE
196         assertNull(cv.getAsString(Events.DURATION));
197         assertEquals(endTime, cv.getAsLong(Events.DTEND));
198         assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
199         assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
200     }
201 
testIsValidEventValues()202     public void testIsValidEventValues() throws IOException {
203         CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
204         EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
205 
206         long validTime = System.currentTimeMillis();
207         String validData = "foo-bar-bletch";
208         String validDuration = "P30M";
209         String validRrule = "FREQ=DAILY";
210 
211         ContentValues cv = new ContentValues();
212 
213         cv.put(Events.DTSTART, validTime);
214         // Needs _SYNC_DATA and DTEND/DURATION
215         assertFalse(p.isValidEventValues(cv));
216         cv.put(Events.SYNC_DATA2, validData);
217         // Needs DTEND/DURATION since not an exception
218         assertFalse(p.isValidEventValues(cv));
219         cv.put(Events.DURATION, validDuration);
220         // Valid (DTSTART, _SYNC_DATA, DURATION)
221         assertTrue(p.isValidEventValues(cv));
222         cv.remove(Events.DURATION);
223         cv.put(Events.ORIGINAL_INSTANCE_TIME, validTime);
224         // Needs DTEND since it's an exception
225         assertFalse(p.isValidEventValues(cv));
226         cv.put(Events.DTEND, validTime);
227         // Valid (DTSTART, DTEND, ORIGINAL_INSTANCE_TIME)
228         cv.remove(Events.ORIGINAL_INSTANCE_TIME);
229         // Valid (DTSTART, _SYNC_DATA, DTEND)
230         assertTrue(p.isValidEventValues(cv));
231         cv.remove(Events.DTSTART);
232         // Needs DTSTART
233         assertFalse(p.isValidEventValues(cv));
234         cv.put(Events.DTSTART, validTime);
235         cv.put(Events.RRULE, validRrule);
236         // With RRULE, needs DURATION
237         assertFalse(p.isValidEventValues(cv));
238         cv.put(Events.DURATION, "P30M");
239         // Valid (DTSTART, RRULE, DURATION)
240         assertTrue(p.isValidEventValues(cv));
241         cv.put(Events.ALL_DAY, "1");
242         // Needs DURATION in the form P<n>D
243         assertFalse(p.isValidEventValues(cv));
244         // Valid (DTSTART, RRULE, ALL_DAY, DURATION(P<n>D)
245         cv.put(Events.DURATION, "P1D");
246         assertTrue(p.isValidEventValues(cv));
247     }
248 
addAttendeesToSerializer(Serializer s, int num)249     private void addAttendeesToSerializer(Serializer s, int num) throws IOException {
250         for (int i = 0; i < num; i++) {
251             s.start(Tags.CALENDAR_ATTENDEE);
252             s.data(Tags.CALENDAR_ATTENDEE_EMAIL, "frederick" + num +
253                     ".flintstone@this.that.verylongservername.com");
254             s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
255             s.data(Tags.CALENDAR_ATTENDEE_NAME, "Frederick" + num + " Flintstone, III");
256             s.end();
257         }
258     }
259 
addAttendeeToSerializer(Serializer s, String email, String name)260     private void addAttendeeToSerializer(Serializer s, String email, String name)
261             throws IOException {
262         s.start(Tags.CALENDAR_ATTENDEE);
263         s.data(Tags.CALENDAR_ATTENDEE_EMAIL, email);
264         s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
265         s.data(Tags.CALENDAR_ATTENDEE_NAME, name);
266         s.end();
267     }
268 
countInsertOperationsForTable(CalendarOperations ops, String tableName)269     private int countInsertOperationsForTable(CalendarOperations ops, String tableName) {
270         int cnt = 0;
271         for (Operation op: ops) {
272             ContentProviderOperation cpo =
273                     AbstractSyncAdapter.operationToContentProviderOperation(op, 0);
274             List<String> segments = cpo.getUri().getPathSegments();
275             if (segments.get(0).equalsIgnoreCase(tableName) &&
276                     cpo.getType() == ContentProviderOperation.TYPE_INSERT) {
277                 cnt++;
278             }
279         }
280         return cnt;
281     }
282 
283     class TestEvent extends Serializer {
284         CalendarSyncAdapter mAdapter;
285         EasCalendarSyncParser mParser;
286         Serializer mSerializer;
287 
TestEvent()288         TestEvent() throws IOException {
289             super(false);
290             mAdapter = getTestSyncAdapter(CalendarSyncAdapter.class);
291             mParser = mAdapter.new EasCalendarSyncParser(getTestInputStream(), mAdapter);
292         }
293 
setUserEmailAddress(String addr)294         void setUserEmailAddress(String addr) {
295             mAdapter.mAccount.mEmailAddress = addr;
296             mAdapter.mEmailAddress = addr;
297         }
298 
getParser()299         EasCalendarSyncParser getParser() throws IOException {
300             // Set up our parser's input and eat the initial tag
301             mParser.resetInput(new ByteArrayInputStream(toByteArray()));
302             mParser.nextTag(0);
303             return mParser;
304         }
305 
306         // setupPreAttendees and setupPostAttendees initialize calendar data in the order in which
307         // they would appear in an actual EAS session.  Between these two calls, we initialize
308         // attendee data, which varies between the following tests
setupPreAttendees()309         TestEvent setupPreAttendees() throws IOException {
310             start(Tags.SYNC_APPLICATION_DATA);
311             data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE);
312             data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z");
313             data(Tags.CALENDAR_START_TIME, "20100518T220000Z");
314             data(Tags.CALENDAR_SUBJECT, "Documentation");
315             data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85");
316             data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas");
317             data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com");
318             return this;
319         }
320 
setupPostAttendees()321         TestEvent setupPostAttendees()throws IOException {
322             data(Tags.CALENDAR_LOCATION, "CR SF 601T2/North Shore Presentation Self Service (16)");
323             data(Tags.CALENDAR_END_TIME, "20100518T223000Z");
324             start(Tags.BASE_BODY);
325             data(Tags.BASE_BODY_PREFERENCE, "1");
326             data(Tags.BASE_ESTIMATED_DATA_SIZE, "69105"); // The number is ignored by the parser
327             data(Tags.BASE_DATA,
328                     "This is the event description; we should probably make it longer");
329             end(); // BASE_BODY
330             start(Tags.CALENDAR_RECURRENCE);
331             data(Tags.CALENDAR_RECURRENCE_TYPE, "1"); // weekly
332             data(Tags.CALENDAR_RECURRENCE_INTERVAL, "1");
333             data(Tags.CALENDAR_RECURRENCE_OCCURRENCES, "10");
334             data(Tags.CALENDAR_RECURRENCE_DAYOFWEEK, "12"); // tue, wed
335             data(Tags.CALENDAR_RECURRENCE_UNTIL, "2005-04-14T00:00:00.000Z");
336             end();  // CALENDAR_RECURRENCE
337             data(Tags.CALENDAR_SENSITIVITY, "0");
338             data(Tags.CALENDAR_BUSY_STATUS, "2");
339             data(Tags.CALENDAR_ALL_DAY_EVENT, "0");
340             data(Tags.CALENDAR_MEETING_STATUS, "3");
341             data(Tags.BASE_NATIVE_BODY_TYPE, "3");
342             end().done(); // SYNC_APPLICATION_DATA
343             return this;
344         }
345     }
346 
testAddEvent()347     public void testAddEvent() throws IOException {
348         TestEvent event = new TestEvent();
349         event.setupPreAttendees();
350         event.start(Tags.CALENDAR_ATTENDEES);
351         addAttendeesToSerializer(event, 10);
352         event.end(); // CALENDAR_ATTENDEES
353         event.setupPostAttendees();
354 
355         EasCalendarSyncParser p = event.getParser();
356         p.addEvent(p.mOps, "1:1", false);
357         // There should be 1 event
358         assertEquals(1, countInsertOperationsForTable(p.mOps, "events"));
359         // Two attendees (organizer and 10 attendees)
360         assertEquals(11, countInsertOperationsForTable(p.mOps, "attendees"));
361         // dtstamp, meeting status, attendees, attendees redacted, and upsync prohibited
362         assertEquals(5, countInsertOperationsForTable(p.mOps, "extendedproperties"));
363     }
364 
testAddEventIllegal()365     public void testAddEventIllegal() throws IOException {
366         // We don't send a start time; the event is illegal and nothing should be added
367         TestEvent event = new TestEvent();
368         event.start(Tags.SYNC_APPLICATION_DATA);
369         event.data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE);
370         event.data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z");
371         event.data(Tags.CALENDAR_SUBJECT, "Documentation");
372         event.data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85");
373         event.data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas");
374         event.data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com");
375         event.start(Tags.CALENDAR_ATTENDEES);
376         addAttendeesToSerializer(event, 10);
377         event.end(); // CALENDAR_ATTENDEES
378         event.setupPostAttendees();
379 
380         EasCalendarSyncParser p = event.getParser();
381         p.addEvent(p.mOps, "1:1", false);
382         assertEquals(0, countInsertOperationsForTable(p.mOps, "events"));
383         assertEquals(0, countInsertOperationsForTable(p.mOps, "attendees"));
384         assertEquals(0, countInsertOperationsForTable(p.mOps, "extendedproperties"));
385     }
386 
testAddEventRedactedAttendees()387     public void testAddEventRedactedAttendees() throws IOException {
388         TestEvent event = new TestEvent();
389         event.setupPreAttendees();
390         event.start(Tags.CALENDAR_ATTENDEES);
391         addAttendeesToSerializer(event, 100);
392         event.end(); // CALENDAR_ATTENDEES
393         event.setupPostAttendees();
394 
395         EasCalendarSyncParser p = event.getParser();
396         p.addEvent(p.mOps, "1:1", false);
397         // There should be 1 event
398         assertEquals(1, countInsertOperationsForTable(p.mOps, "events"));
399         // One attendees (organizer; all others are redacted)
400         assertEquals(1, countInsertOperationsForTable(p.mOps, "attendees"));
401         // dtstamp, meeting status, and attendees redacted
402         assertEquals(3, countInsertOperationsForTable(p.mOps, "extendedproperties"));
403     }
404 
405     /**
406      * Setup for the following three tests, which check attendee status of an added event
407      * @param userEmail the email address of the user
408      * @param update whether or not the event is an update (rather than new)
409      * @return a Cursor to the Attendee records added to our MockProvider
410      * @throws IOException
411      * @throws RemoteException
412      * @throws OperationApplicationException
413      */
setupAddEventOneAttendee(String userEmail, boolean update)414     private Cursor setupAddEventOneAttendee(String userEmail, boolean update)
415             throws IOException, RemoteException, OperationApplicationException {
416         TestEvent event = new TestEvent();
417         event.setupPreAttendees();
418         event.start(Tags.CALENDAR_ATTENDEES);
419         addAttendeeToSerializer(event, SINGLE_ATTENDEE_EMAIL, SINGLE_ATTENDEE_NAME);
420         event.setUserEmailAddress(userEmail);
421         event.end(); // CALENDAR_ATTENDEES
422         event.setupPostAttendees();
423 
424         EasCalendarSyncParser p = event.getParser();
425         p.addEvent(p.mOps, "1:1", update);
426         // Send the CPO's to the mock provider
427         ArrayList<ContentProviderOperation> cpos = new ArrayList<ContentProviderOperation>();
428         for (Operation op: p.mOps) {
429             cpos.add(AbstractSyncAdapter.operationToContentProviderOperation(op, 0));
430         }
431         mMockResolver.applyBatch(MockProvider.AUTHORITY, cpos);
432         return mMockResolver.query(MockProvider.uri(Attendees.CONTENT_URI), ATTENDEE_PROJECTION,
433                 null, null, null);
434     }
435 
testAddEventOneAttendee()436     public void testAddEventOneAttendee() throws IOException, RemoteException,
437             OperationApplicationException {
438         Cursor c = setupAddEventOneAttendee("foo@bar.com", false);
439         assertEquals(2, c.getCount());
440         // The organizer should be "accepted", the unknown attendee "none"
441         while (c.moveToNext()) {
442             if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
443                 assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS));
444             } else {
445                 assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
446             }
447         }
448     }
449 
testAddEventSelfAttendee()450     public void testAddEventSelfAttendee() throws IOException, RemoteException,
451             OperationApplicationException {
452         Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, false);
453         // The organizer should be "accepted", and our user/attendee should be "done" even though
454         // the busy status = 2 (because we can't tell from a status of 2 on new events)
455         while (c.moveToNext()) {
456             if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
457                 assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS));
458             } else {
459                 assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
460             }
461         }
462     }
463 
testAddEventSelfAttendeeUpdate()464     public void testAddEventSelfAttendeeUpdate() throws IOException, RemoteException,
465             OperationApplicationException {
466         Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, true);
467         // The organizer should be "accepted", and our user/attendee should be "accepted" (because
468         // busy status = 2 and this is an update
469         while (c.moveToNext()) {
470             if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
471                 assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
472             } else {
473                 assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
474             }
475         }
476     }
477 }
478