blob: e378b03dd8ae3ec4212c55a6c38d43cd6f3dffc8 [file] [log] [blame]
/*
* Copyright (C) 2009 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.email.provider.EmailContent;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Body;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailContent.SyncColumns;
import com.android.exchange.EasSyncService;
import com.android.exchange.adapter.EmailSyncAdapter.EasEmailSyncParser;
import com.android.exchange.adapter.EmailSyncAdapter.EasEmailSyncParser.ServerChange;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.test.ProviderTestCase2;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class EmailSyncAdapterTests extends ProviderTestCase2<EmailProvider> {
EmailProvider mProvider;
Context mMockContext;
ContentResolver mMockResolver;
Mailbox mMailbox;
Account mAccount;
EmailSyncAdapter mSyncAdapter;
EasEmailSyncParser mSyncParser;
public EmailSyncAdapterTests() {
super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
}
@Override
public void setUp() throws Exception {
super.setUp();
mMockContext = getMockContext();
mMockResolver = mMockContext.getContentResolver();
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
/**
* Create and return a short, simple InputStream that has at least four bytes, which is all
* that's required to initialize an EasParser (the parent class of EasEmailSyncParser)
* @return the InputStream
*/
public InputStream getTestInputStream() {
return new ByteArrayInputStream(new byte[] {0, 0, 0, 0, 0});
}
EasSyncService getTestService() {
Account account = new Account();
account.mId = -1;
Mailbox mailbox = new Mailbox();
mailbox.mId = -1;
EasSyncService service = new EasSyncService();
service.mContext = mMockContext;
service.mMailbox = mailbox;
service.mAccount = account;
return service;
}
EasSyncService getTestService(Account account, Mailbox mailbox) {
EasSyncService service = new EasSyncService();
service.mContext = mMockContext;
service.mMailbox = mailbox;
service.mAccount = account;
return service;
}
EmailSyncAdapter getTestSyncAdapter() {
EasSyncService service = getTestService();
EmailSyncAdapter adapter = new EmailSyncAdapter(service.mMailbox, service);
return adapter;
}
/**
* Check functionality for getting mime type from a file name (using its extension)
* The default for all unknown files is application/octet-stream
*/
public void testGetMimeTypeFromFileName() throws IOException {
EasSyncService service = getTestService();
EmailSyncAdapter adapter = new EmailSyncAdapter(service.mMailbox, service);
EasEmailSyncParser p = adapter.new EasEmailSyncParser(getTestInputStream(), adapter);
// Test a few known types
String mimeType = p.getMimeTypeFromFileName("foo.jpg");
assertEquals("image/jpeg", mimeType);
// Make sure this is case insensitive
mimeType = p.getMimeTypeFromFileName("foo.JPG");
assertEquals("image/jpeg", mimeType);
mimeType = p.getMimeTypeFromFileName("this_is_a_weird_filename.gif");
assertEquals("image/gif", mimeType);
// Test an illegal file name ending with the extension prefix
mimeType = p.getMimeTypeFromFileName("foo.");
assertEquals("application/octet-stream", mimeType);
// Test a really awful name
mimeType = p.getMimeTypeFromFileName(".....");
assertEquals("application/octet-stream", mimeType);
// Test a bare file name (no extension)
mimeType = p.getMimeTypeFromFileName("foo");
assertEquals("application/octet-stream", mimeType);
// And no name at all (null isn't a valid input)
mimeType = p.getMimeTypeFromFileName("");
assertEquals("application/octet-stream", mimeType);
}
public void testFormatDateTime() throws IOException {
EmailSyncAdapter adapter = getTestSyncAdapter();
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
// Calendar is odd, months are zero based, so the first 11 below is December...
calendar.set(2008, 11, 11, 18, 19, 20);
String date = adapter.formatDateTime(calendar);
assertEquals("2008-12-11T18:19:20.000Z", date);
calendar.clear();
calendar.set(2012, 0, 2, 23, 0, 1);
date = adapter.formatDateTime(calendar);
assertEquals("2012-01-02T23:00:01.000Z", date);
}
public void testSendDeletedItems() throws IOException {
EasSyncService service = getTestService();
EmailSyncAdapter adapter = new EmailSyncAdapter(service.mMailbox, service);
Serializer s = new Serializer();
ArrayList<Long> ids = new ArrayList<Long>();
ArrayList<Long> deletedIds = new ArrayList<Long>();
adapter.mContext = mMockContext;
// Create account and two mailboxes
Account acct = ProviderTestUtils.setupAccount("account", true, mMockContext);
adapter.mAccount = acct;
Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, mMockContext);
adapter.mMailbox = box1;
// Create 3 messages
Message msg1 = ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId,
true, true, mMockContext);
ids.add(msg1.mId);
Message msg2 = ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId,
true, true, mMockContext);
ids.add(msg2.mId);
Message msg3 = ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId,
true, true, mMockContext);
ids.add(msg3.mId);
assertEquals(3, EmailContent.count(mMockContext, Message.CONTENT_URI, null, null));
// Delete them
for (long id: ids) {
mMockResolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, id),
null, null);
}
// Confirm that the messages are in the proper table
assertEquals(0, EmailContent.count(mMockContext, Message.CONTENT_URI, null, null));
assertEquals(3, EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, null, null));
// Call code to send deletions; the id's of the ones actually deleted will be in the
// deletedIds list
adapter.sendDeletedItems(s, deletedIds, true);
assertEquals(3, deletedIds.size());
// Clear this out for the next test
deletedIds.clear();
// Create a new message
Message msg4 = ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId,
true, true, mMockContext);
assertEquals(1, EmailContent.count(mMockContext, Message.CONTENT_URI, null, null));
// Find the body for this message
Body body = Body.restoreBodyWithMessageId(mMockContext, msg4.mId);
// Set its source message to msg2's id
ContentValues values = new ContentValues();
values.put(Body.SOURCE_MESSAGE_KEY, msg2.mId);
body.update(mMockContext, values);
// Now send deletions again; this time only two should get deleted; msg2 should NOT be
// deleted as it's referenced by msg4
adapter.sendDeletedItems(s, deletedIds, true);
assertEquals(2, deletedIds.size());
assertFalse(deletedIds.contains(msg2.mId));
}
void setupSyncParserAndAdapter(Account account, Mailbox mailbox) throws IOException {
EasSyncService service = getTestService(account, mailbox);
mSyncAdapter = new EmailSyncAdapter(mailbox, service);
mSyncParser = mSyncAdapter.new EasEmailSyncParser(getTestInputStream(), mSyncAdapter);
}
ArrayList<Long> setupAccountMailboxAndMessages(int numMessages) {
ArrayList<Long> ids = new ArrayList<Long>();
// Create account and two mailboxes
mAccount = ProviderTestUtils.setupAccount("account", true, mMockContext);
mMailbox = ProviderTestUtils.setupMailbox("box1", mAccount.mId, true, mMockContext);
for (int i = 0; i < numMessages; i++) {
Message msg = ProviderTestUtils.setupMessage("message" + i, mAccount.mId, mMailbox.mId,
true, true, mMockContext);
ids.add(msg.mId);
}
assertEquals(numMessages, EmailContent.count(mMockContext, Message.CONTENT_URI,
null, null));
return ids;
}
public void testDeleteParser() throws IOException {
// Setup some messages
ArrayList<Long> messageIds = setupAccountMailboxAndMessages(3);
ContentValues cv = new ContentValues();
cv.put(SyncColumns.SERVER_ID, "1:22");
long deleteMessageId = messageIds.get(1);
mMockResolver.update(ContentUris.withAppendedId(Message.CONTENT_URI, deleteMessageId), cv,
null, null);
// Setup our adapter and parser
setupSyncParserAndAdapter(mAccount, mMailbox);
// Set up an input stream with a delete command
Serializer s = new Serializer(false);
s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, "1:22").end().done();
byte[] bytes = s.toByteArray();
mSyncParser.resetInput(new ByteArrayInputStream(bytes));
mSyncParser.nextTag(0);
// Run the delete parser
ArrayList<Long> deleteList = new ArrayList<Long>();
mSyncParser.deleteParser(deleteList, Tags.SYNC_DELETE);
// It should have found the message
assertEquals(1, deleteList.size());
long id = deleteList.get(0);
// And the id's should match
assertEquals(deleteMessageId, id);
}
public void testChangeParser() throws IOException {
// Setup some messages
ArrayList<Long> messageIds = setupAccountMailboxAndMessages(3);
ContentValues cv = new ContentValues();
cv.put(SyncColumns.SERVER_ID, "1:22");
long changeMessageId = messageIds.get(1);
mMockResolver.update(ContentUris.withAppendedId(Message.CONTENT_URI, changeMessageId), cv,
null, null);
// Setup our adapter and parser
setupSyncParserAndAdapter(mAccount, mMailbox);
// Set up an input stream with a change command (marking 1:22 unread)
// Note that the test message creation code sets read to "true"
Serializer s = new Serializer(false);
s.start(Tags.SYNC_CHANGE).data(Tags.SYNC_SERVER_ID, "1:22");
s.start(Tags.SYNC_APPLICATION_DATA).data(Tags.EMAIL_READ, "0").end();
s.end().done();
byte[] bytes = s.toByteArray();
mSyncParser.resetInput(new ByteArrayInputStream(bytes));
mSyncParser.nextTag(0);
// Run the delete parser
ArrayList<ServerChange> changeList = new ArrayList<ServerChange>();
mSyncParser.changeParser(changeList);
// It should have found the message
assertEquals(1, changeList.size());
// And the id's should match
ServerChange change = changeList.get(0);
assertEquals(changeMessageId, change.id);
assertNotNull(change.read);
assertFalse(change.read);
}
public void testCleanup() throws IOException {
// Setup some messages
ArrayList<Long> messageIds = setupAccountMailboxAndMessages(3);
// Setup our adapter and parser
setupSyncParserAndAdapter(mAccount, mMailbox);
// Delete two of the messages, change one
long id = messageIds.get(0);
mMockResolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, id),
null, null);
mSyncAdapter.mDeletedIdList.add(id);
id = messageIds.get(1);
mMockResolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI,
id), null, null);
mSyncAdapter.mDeletedIdList.add(id);
id = messageIds.get(2);
ContentValues cv = new ContentValues();
cv.put(Message.FLAG_READ, 0);
mMockResolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI,
id), cv, null, null);
mSyncAdapter.mUpdatedIdList.add(id);
// The changed message should still exist
assertEquals(1, EmailContent.count(mMockContext, Message.CONTENT_URI, null, null));
// As well, the two deletions and one update
assertEquals(2, EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, null, null));
assertEquals(1, EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, null, null));
// Cleanup (i.e. after sync); should remove items from delete/update tables
mSyncAdapter.cleanup();
// The three should be gone
assertEquals(0, EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, null, null));
assertEquals(0, EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, null, null));
}
}