| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.exchange.adapter; |
| |
| import com.android.exchange.adapter.AbstractSyncAdapter.Operation; |
| import com.android.exchange.adapter.CalendarSyncAdapter.CalendarOperations; |
| import com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser; |
| import com.android.exchange.provider.MockProvider; |
| |
| import android.content.ContentProviderOperation; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.OperationApplicationException; |
| import android.content.res.Resources; |
| import android.database.Cursor; |
| import android.os.RemoteException; |
| import android.provider.CalendarContract.Attendees; |
| import android.provider.CalendarContract.Events; |
| import android.test.IsolatedContext; |
| import android.test.RenamingDelegatingContext; |
| import android.test.mock.MockContentResolver; |
| import android.test.mock.MockContext; |
| import android.test.suitebuilder.annotation.MediumTest; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.GregorianCalendar; |
| import java.util.List; |
| import java.util.TimeZone; |
| |
| /** |
| * You can run this entire test case with: |
| * runtest -c com.android.exchange.adapter.CalendarSyncAdapterTests exchange |
| */ |
| @MediumTest |
| public class CalendarSyncAdapterTests extends SyncAdapterTestCase<CalendarSyncAdapter> { |
| private static final String[] ATTENDEE_PROJECTION = new String[] {Attendees.ATTENDEE_EMAIL, |
| Attendees.ATTENDEE_NAME, Attendees.ATTENDEE_STATUS}; |
| private static final int ATTENDEE_EMAIL = 0; |
| private static final int ATTENDEE_NAME = 1; |
| private static final int ATTENDEE_STATUS = 2; |
| |
| private static final String SINGLE_ATTENDEE_EMAIL = "attendee@host.com"; |
| private static final String SINGLE_ATTENDEE_NAME = "Bill Attendee"; |
| |
| private Context mMockContext; |
| private MockContentResolver mMockResolver; |
| |
| // This is the US/Pacific time zone as a base64-encoded TIME_ZONE_INFORMATION structure, as |
| // it would appear coming from an Exchange server |
| private static final String TEST_TIME_ZONE = "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByA" + |
| "GQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAY" + |
| "QBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAA" + |
| "AAAAAAAAAMAAAACAAIAAAAAAAAAxP///w=="; |
| |
| private class MockContext2 extends MockContext { |
| |
| @Override |
| public Resources getResources() { |
| return getContext().getResources(); |
| } |
| |
| @Override |
| public File getDir(String name, int mode) { |
| // name the directory so the directory will be separated from |
| // one created through the regular Context |
| return getContext().getDir("mockcontext2_" + name, mode); |
| } |
| |
| @Override |
| public Context getApplicationContext() { |
| return this; |
| } |
| } |
| |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| |
| mMockResolver = new MockContentResolver(); |
| final String filenamePrefix = "test."; |
| RenamingDelegatingContext targetContextWrapper = new |
| RenamingDelegatingContext( |
| new MockContext2(), // The context that most methods are delegated to |
| getContext(), // The context that file methods are delegated to |
| filenamePrefix); |
| mMockContext = new IsolatedContext(mMockResolver, targetContextWrapper); |
| mMockResolver.addProvider(MockProvider.AUTHORITY, new MockProvider(mMockContext)); |
| } |
| |
| public CalendarSyncAdapterTests() { |
| super(); |
| } |
| |
| public void testSetTimeRelatedValues_NonRecurring() throws IOException { |
| CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter); |
| ContentValues cv = new ContentValues(); |
| // Basic, one-time meeting lasting an hour |
| GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30); |
| Long startTime = startCalendar.getTimeInMillis(); |
| GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30); |
| Long endTime = endCalendar.getTimeInMillis(); |
| |
| p.setTimeRelatedValues(cv, startTime, endTime, 0); |
| assertNull(cv.getAsInteger(Events.DURATION)); |
| assertEquals(startTime, cv.getAsLong(Events.DTSTART)); |
| assertEquals(endTime, cv.getAsLong(Events.DTEND)); |
| assertEquals(endTime, cv.getAsLong(Events.LAST_DATE)); |
| assertNull(cv.getAsString(Events.EVENT_TIMEZONE)); |
| } |
| |
| public void testSetTimeRelatedValues_Recurring() throws IOException { |
| CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter); |
| ContentValues cv = new ContentValues(); |
| // Recurring meeting lasting an hour |
| GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30); |
| Long startTime = startCalendar.getTimeInMillis(); |
| GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30); |
| Long endTime = endCalendar.getTimeInMillis(); |
| cv.put(Events.RRULE, "FREQ=DAILY"); |
| p.setTimeRelatedValues(cv, startTime, endTime, 0); |
| assertEquals("P60M", cv.getAsString(Events.DURATION)); |
| assertEquals(startTime, cv.getAsLong(Events.DTSTART)); |
| assertNull(cv.getAsLong(Events.DTEND)); |
| assertNull(cv.getAsLong(Events.LAST_DATE)); |
| assertNull(cv.getAsString(Events.EVENT_TIMEZONE)); |
| } |
| |
| public void testSetTimeRelatedValues_AllDay() throws IOException { |
| CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter); |
| ContentValues cv = new ContentValues(); |
| GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30); |
| Long startTime = startCalendar.getTimeInMillis(); |
| GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 11, 8, 30); |
| Long endTime = endCalendar.getTimeInMillis(); |
| cv.put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO"); |
| p.setTimeRelatedValues(cv, startTime, endTime, 1); |
| |
| // The start time should have hour/min/sec zero'd out |
| startCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); |
| startCalendar.set(2010, 5, 10, 0, 0, 0); |
| startCalendar.set(GregorianCalendar.MILLISECOND, 0); |
| startTime = startCalendar.getTimeInMillis(); |
| assertEquals(startTime, cv.getAsLong(Events.DTSTART)); |
| |
| // The duration should be in days |
| assertEquals("P1D", cv.getAsString(Events.DURATION)); |
| assertNull(cv.getAsLong(Events.DTEND)); |
| assertNull(cv.getAsLong(Events.LAST_DATE)); |
| // There must be a timezone |
| assertNotNull(cv.getAsString(Events.EVENT_TIMEZONE)); |
| } |
| |
| public void testSetTimeRelatedValues_Recurring_AllDay_Exception () throws IOException { |
| CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter); |
| ContentValues cv = new ContentValues(); |
| |
| // Recurrence exception for all-day event; the exception is NOT all-day |
| GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 17, 8, 30); |
| Long startTime = startCalendar.getTimeInMillis(); |
| GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 17, 9, 30); |
| Long endTime = endCalendar.getTimeInMillis(); |
| cv.put(Events.ORIGINAL_ALL_DAY, 1); |
| GregorianCalendar instanceCalendar = new GregorianCalendar(2010, 5, 17, 8, 30); |
| cv.put(Events.ORIGINAL_INSTANCE_TIME, instanceCalendar.getTimeInMillis()); |
| p.setTimeRelatedValues(cv, startTime, endTime, 0); |
| |
| // The original instance time should have hour/min/sec zero'd out |
| GregorianCalendar testCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); |
| testCalendar.set(2010, 5, 17, 0, 0, 0); |
| testCalendar.set(GregorianCalendar.MILLISECOND, 0); |
| Long testTime = testCalendar.getTimeInMillis(); |
| assertEquals(testTime, cv.getAsLong(Events.ORIGINAL_INSTANCE_TIME)); |
| |
| // The exception isn't all-day, so we should have DTEND and LAST_DATE and no EVENT_TIMEZONE |
| assertNull(cv.getAsString(Events.DURATION)); |
| assertEquals(endTime, cv.getAsLong(Events.DTEND)); |
| assertEquals(endTime, cv.getAsLong(Events.LAST_DATE)); |
| assertNull(cv.getAsString(Events.EVENT_TIMEZONE)); |
| } |
| |
| public void testIsValidEventValues() throws IOException { |
| CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter); |
| |
| long validTime = System.currentTimeMillis(); |
| String validData = "foo-bar-bletch"; |
| String validDuration = "P30M"; |
| String validRrule = "FREQ=DAILY"; |
| |
| ContentValues cv = new ContentValues(); |
| |
| cv.put(Events.DTSTART, validTime); |
| // Needs _SYNC_DATA and DTEND/DURATION |
| assertFalse(p.isValidEventValues(cv)); |
| cv.put(Events.SYNC_DATA2, validData); |
| // Needs DTEND/DURATION since not an exception |
| assertFalse(p.isValidEventValues(cv)); |
| cv.put(Events.DURATION, validDuration); |
| // Valid (DTSTART, _SYNC_DATA, DURATION) |
| assertTrue(p.isValidEventValues(cv)); |
| cv.remove(Events.DURATION); |
| cv.put(Events.ORIGINAL_INSTANCE_TIME, validTime); |
| // Needs DTEND since it's an exception |
| assertFalse(p.isValidEventValues(cv)); |
| cv.put(Events.DTEND, validTime); |
| // Valid (DTSTART, DTEND, ORIGINAL_INSTANCE_TIME) |
| cv.remove(Events.ORIGINAL_INSTANCE_TIME); |
| // Valid (DTSTART, _SYNC_DATA, DTEND) |
| assertTrue(p.isValidEventValues(cv)); |
| cv.remove(Events.DTSTART); |
| // Needs DTSTART |
| assertFalse(p.isValidEventValues(cv)); |
| cv.put(Events.DTSTART, validTime); |
| cv.put(Events.RRULE, validRrule); |
| // With RRULE, needs DURATION |
| assertFalse(p.isValidEventValues(cv)); |
| cv.put(Events.DURATION, "P30M"); |
| // Valid (DTSTART, RRULE, DURATION) |
| assertTrue(p.isValidEventValues(cv)); |
| cv.put(Events.ALL_DAY, "1"); |
| // Needs DURATION in the form P<n>D |
| assertFalse(p.isValidEventValues(cv)); |
| // Valid (DTSTART, RRULE, ALL_DAY, DURATION(P<n>D) |
| cv.put(Events.DURATION, "P1D"); |
| assertTrue(p.isValidEventValues(cv)); |
| } |
| |
| private void addAttendeesToSerializer(Serializer s, int num) throws IOException { |
| for (int i = 0; i < num; i++) { |
| s.start(Tags.CALENDAR_ATTENDEE); |
| s.data(Tags.CALENDAR_ATTENDEE_EMAIL, "frederick" + num + |
| ".flintstone@this.that.verylongservername.com"); |
| s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1"); |
| s.data(Tags.CALENDAR_ATTENDEE_NAME, "Frederick" + num + " Flintstone, III"); |
| s.end(); |
| } |
| } |
| |
| private void addAttendeeToSerializer(Serializer s, String email, String name) |
| throws IOException { |
| s.start(Tags.CALENDAR_ATTENDEE); |
| s.data(Tags.CALENDAR_ATTENDEE_EMAIL, email); |
| s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1"); |
| s.data(Tags.CALENDAR_ATTENDEE_NAME, name); |
| s.end(); |
| } |
| |
| private int countInsertOperationsForTable(CalendarOperations ops, String tableName) { |
| int cnt = 0; |
| for (Operation op: ops) { |
| ContentProviderOperation cpo = |
| AbstractSyncAdapter.operationToContentProviderOperation(op, 0); |
| List<String> segments = cpo.getUri().getPathSegments(); |
| if (segments.get(0).equalsIgnoreCase(tableName) && |
| cpo.getType() == ContentProviderOperation.TYPE_INSERT) { |
| cnt++; |
| } |
| } |
| return cnt; |
| } |
| |
| class TestEvent extends Serializer { |
| CalendarSyncAdapter mAdapter; |
| EasCalendarSyncParser mParser; |
| Serializer mSerializer; |
| |
| TestEvent() throws IOException { |
| super(false); |
| mAdapter = getTestSyncAdapter(CalendarSyncAdapter.class); |
| mParser = mAdapter.new EasCalendarSyncParser(getTestInputStream(), mAdapter); |
| } |
| |
| void setUserEmailAddress(String addr) { |
| mAdapter.mAccount.mEmailAddress = addr; |
| mAdapter.mEmailAddress = addr; |
| } |
| |
| EasCalendarSyncParser getParser() throws IOException { |
| // Set up our parser's input and eat the initial tag |
| mParser.resetInput(new ByteArrayInputStream(toByteArray())); |
| mParser.nextTag(0); |
| return mParser; |
| } |
| |
| // setupPreAttendees and setupPostAttendees initialize calendar data in the order in which |
| // they would appear in an actual EAS session. Between these two calls, we initialize |
| // attendee data, which varies between the following tests |
| TestEvent setupPreAttendees() throws IOException { |
| start(Tags.SYNC_APPLICATION_DATA); |
| data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE); |
| data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z"); |
| data(Tags.CALENDAR_START_TIME, "20100518T220000Z"); |
| data(Tags.CALENDAR_SUBJECT, "Documentation"); |
| data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85"); |
| data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas"); |
| data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com"); |
| return this; |
| } |
| |
| TestEvent setupPostAttendees()throws IOException { |
| data(Tags.CALENDAR_LOCATION, "CR SF 601T2/North Shore Presentation Self Service (16)"); |
| data(Tags.CALENDAR_END_TIME, "20100518T223000Z"); |
| start(Tags.BASE_BODY); |
| data(Tags.BASE_BODY_PREFERENCE, "1"); |
| data(Tags.BASE_ESTIMATED_DATA_SIZE, "69105"); // The number is ignored by the parser |
| data(Tags.BASE_DATA, |
| "This is the event description; we should probably make it longer"); |
| end(); // BASE_BODY |
| start(Tags.CALENDAR_RECURRENCE); |
| data(Tags.CALENDAR_RECURRENCE_TYPE, "1"); // weekly |
| data(Tags.CALENDAR_RECURRENCE_INTERVAL, "1"); |
| data(Tags.CALENDAR_RECURRENCE_OCCURRENCES, "10"); |
| data(Tags.CALENDAR_RECURRENCE_DAYOFWEEK, "12"); // tue, wed |
| data(Tags.CALENDAR_RECURRENCE_UNTIL, "2005-04-14T00:00:00.000Z"); |
| end(); // CALENDAR_RECURRENCE |
| data(Tags.CALENDAR_SENSITIVITY, "0"); |
| data(Tags.CALENDAR_BUSY_STATUS, "2"); |
| data(Tags.CALENDAR_ALL_DAY_EVENT, "0"); |
| data(Tags.CALENDAR_MEETING_STATUS, "3"); |
| data(Tags.BASE_NATIVE_BODY_TYPE, "3"); |
| end().done(); // SYNC_APPLICATION_DATA |
| return this; |
| } |
| } |
| |
| public void testAddEvent() throws IOException { |
| TestEvent event = new TestEvent(); |
| event.setupPreAttendees(); |
| event.start(Tags.CALENDAR_ATTENDEES); |
| addAttendeesToSerializer(event, 10); |
| event.end(); // CALENDAR_ATTENDEES |
| event.setupPostAttendees(); |
| |
| EasCalendarSyncParser p = event.getParser(); |
| p.addEvent(p.mOps, "1:1", false); |
| // There should be 1 event |
| assertEquals(1, countInsertOperationsForTable(p.mOps, "events")); |
| // Two attendees (organizer and 10 attendees) |
| assertEquals(11, countInsertOperationsForTable(p.mOps, "attendees")); |
| // dtstamp, meeting status, attendees, attendees redacted, and upsync prohibited |
| assertEquals(5, countInsertOperationsForTable(p.mOps, "extendedproperties")); |
| } |
| |
| public void testAddEventIllegal() throws IOException { |
| // We don't send a start time; the event is illegal and nothing should be added |
| TestEvent event = new TestEvent(); |
| event.start(Tags.SYNC_APPLICATION_DATA); |
| event.data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE); |
| event.data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z"); |
| event.data(Tags.CALENDAR_SUBJECT, "Documentation"); |
| event.data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85"); |
| event.data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas"); |
| event.data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com"); |
| event.start(Tags.CALENDAR_ATTENDEES); |
| addAttendeesToSerializer(event, 10); |
| event.end(); // CALENDAR_ATTENDEES |
| event.setupPostAttendees(); |
| |
| EasCalendarSyncParser p = event.getParser(); |
| p.addEvent(p.mOps, "1:1", false); |
| assertEquals(0, countInsertOperationsForTable(p.mOps, "events")); |
| assertEquals(0, countInsertOperationsForTable(p.mOps, "attendees")); |
| assertEquals(0, countInsertOperationsForTable(p.mOps, "extendedproperties")); |
| } |
| |
| public void testAddEventRedactedAttendees() throws IOException { |
| TestEvent event = new TestEvent(); |
| event.setupPreAttendees(); |
| event.start(Tags.CALENDAR_ATTENDEES); |
| addAttendeesToSerializer(event, 100); |
| event.end(); // CALENDAR_ATTENDEES |
| event.setupPostAttendees(); |
| |
| EasCalendarSyncParser p = event.getParser(); |
| p.addEvent(p.mOps, "1:1", false); |
| // There should be 1 event |
| assertEquals(1, countInsertOperationsForTable(p.mOps, "events")); |
| // One attendees (organizer; all others are redacted) |
| assertEquals(1, countInsertOperationsForTable(p.mOps, "attendees")); |
| // dtstamp, meeting status, and attendees redacted |
| assertEquals(3, countInsertOperationsForTable(p.mOps, "extendedproperties")); |
| } |
| |
| /** |
| * Setup for the following three tests, which check attendee status of an added event |
| * @param userEmail the email address of the user |
| * @param update whether or not the event is an update (rather than new) |
| * @return a Cursor to the Attendee records added to our MockProvider |
| * @throws IOException |
| * @throws RemoteException |
| * @throws OperationApplicationException |
| */ |
| private Cursor setupAddEventOneAttendee(String userEmail, boolean update) |
| throws IOException, RemoteException, OperationApplicationException { |
| TestEvent event = new TestEvent(); |
| event.setupPreAttendees(); |
| event.start(Tags.CALENDAR_ATTENDEES); |
| addAttendeeToSerializer(event, SINGLE_ATTENDEE_EMAIL, SINGLE_ATTENDEE_NAME); |
| event.setUserEmailAddress(userEmail); |
| event.end(); // CALENDAR_ATTENDEES |
| event.setupPostAttendees(); |
| |
| EasCalendarSyncParser p = event.getParser(); |
| p.addEvent(p.mOps, "1:1", update); |
| // Send the CPO's to the mock provider |
| ArrayList<ContentProviderOperation> cpos = new ArrayList<ContentProviderOperation>(); |
| for (Operation op: p.mOps) { |
| cpos.add(AbstractSyncAdapter.operationToContentProviderOperation(op, 0)); |
| } |
| mMockResolver.applyBatch(MockProvider.AUTHORITY, cpos); |
| return mMockResolver.query(MockProvider.uri(Attendees.CONTENT_URI), ATTENDEE_PROJECTION, |
| null, null, null); |
| } |
| |
| public void testAddEventOneAttendee() throws IOException, RemoteException, |
| OperationApplicationException { |
| Cursor c = setupAddEventOneAttendee("foo@bar.com", false); |
| assertEquals(2, c.getCount()); |
| // The organizer should be "accepted", the unknown attendee "none" |
| while (c.moveToNext()) { |
| if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) { |
| assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS)); |
| } else { |
| assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS)); |
| } |
| } |
| } |
| |
| public void testAddEventSelfAttendee() throws IOException, RemoteException, |
| OperationApplicationException { |
| Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, false); |
| // The organizer should be "accepted", and our user/attendee should be "done" even though |
| // the busy status = 2 (because we can't tell from a status of 2 on new events) |
| while (c.moveToNext()) { |
| if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) { |
| assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS)); |
| } else { |
| assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS)); |
| } |
| } |
| } |
| |
| public void testAddEventSelfAttendeeUpdate() throws IOException, RemoteException, |
| OperationApplicationException { |
| Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, true); |
| // The organizer should be "accepted", and our user/attendee should be "accepted" (because |
| // busy status = 2 and this is an update |
| while (c.moveToNext()) { |
| if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) { |
| assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS)); |
| } else { |
| assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS)); |
| } |
| } |
| } |
| } |