2009-03-04 03:32:22 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 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.email.mail.store;
|
|
|
|
|
2010-11-05 06:34:26 +00:00
|
|
|
import com.android.email.mail.Transport;
|
2009-03-04 03:32:22 +00:00
|
|
|
import com.android.email.mail.transport.MockTransport;
|
2011-02-11 23:05:17 +00:00
|
|
|
import com.android.emailcommon.TempDirectory;
|
2011-02-10 02:47:43 +00:00
|
|
|
import com.android.emailcommon.internet.MimeMessage;
|
|
|
|
import com.android.emailcommon.mail.Address;
|
|
|
|
import com.android.emailcommon.mail.FetchProfile;
|
|
|
|
import com.android.emailcommon.mail.Flag;
|
|
|
|
import com.android.emailcommon.mail.Folder;
|
|
|
|
import com.android.emailcommon.mail.Folder.FolderType;
|
|
|
|
import com.android.emailcommon.mail.Folder.OpenMode;
|
2011-02-11 23:05:17 +00:00
|
|
|
import com.android.emailcommon.mail.Message;
|
2011-02-10 02:47:43 +00:00
|
|
|
import com.android.emailcommon.mail.Message.RecipientType;
|
2011-02-11 23:05:17 +00:00
|
|
|
import com.android.emailcommon.mail.MessagingException;
|
2011-04-19 18:32:06 +00:00
|
|
|
import com.android.emailcommon.provider.EmailContent.Account;
|
|
|
|
import com.android.emailcommon.provider.EmailContent.HostAuth;
|
2009-03-04 03:32:22 +00:00
|
|
|
|
2011-04-19 18:32:06 +00:00
|
|
|
import android.test.InstrumentationTestCase;
|
2009-03-04 03:32:22 +00:00
|
|
|
import android.test.suitebuilder.annotation.SmallTest;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is a series of unit tests for the POP3 Store class. These tests must be locally
|
|
|
|
* complete - no server(s) required.
|
|
|
|
*/
|
|
|
|
@SmallTest
|
2011-04-19 18:32:06 +00:00
|
|
|
public class Pop3StoreUnitTests extends InstrumentationTestCase {
|
2009-03-04 03:32:22 +00:00
|
|
|
final String UNIQUE_ID_1 = "20080909002219r1800rrjo9e00";
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
final static int PER_MESSAGE_SIZE = 100;
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/* These values are provided by setUp() */
|
|
|
|
private Pop3Store mStore = null;
|
|
|
|
private Pop3Store.Pop3Folder mFolder = null;
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Setup code. We generate a lightweight Pop3Store and Pop3Store.Pop3Folder.
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
protected void setUp() throws Exception {
|
|
|
|
super.setUp();
|
2011-04-19 18:32:06 +00:00
|
|
|
// Use the target's (i.e. the Email application) context
|
|
|
|
TempDirectory.setTempDirectory(getInstrumentation().getTargetContext());
|
2010-05-17 20:13:56 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// These are needed so we can get at the inner classes
|
2011-04-19 18:32:06 +00:00
|
|
|
HostAuth testAuth = new HostAuth();
|
|
|
|
Account testAccount = new Account();
|
|
|
|
|
|
|
|
testAuth.setLogin("user", "password");
|
|
|
|
testAuth.setConnection("pop3", "server", 999);
|
|
|
|
testAccount.mHostAuthRecv = testAuth;
|
|
|
|
mStore = (Pop3Store) Pop3Store.newInstance(
|
|
|
|
testAccount, getInstrumentation().getContext(), null);
|
2009-03-04 03:32:22 +00:00
|
|
|
mFolder = (Pop3Store.Pop3Folder) mStore.getFolder("INBOX");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test various sunny-day operations of UIDL parser for multi-line responses
|
|
|
|
*/
|
|
|
|
public void testUIDLParserMulti() {
|
|
|
|
|
|
|
|
// multi-line mode
|
|
|
|
Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// Test basic in-list UIDL
|
|
|
|
parser.parseMultiLine("101 " + UNIQUE_ID_1);
|
|
|
|
assertEquals(101, parser.mMessageNumber);
|
|
|
|
assertEquals(UNIQUE_ID_1, parser.mUniqueId);
|
|
|
|
assertFalse(parser.mEndOfMessage);
|
|
|
|
assertFalse(parser.mErr);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// Test end-of-list
|
|
|
|
parser.parseMultiLine(".");
|
|
|
|
assertTrue(parser.mEndOfMessage);
|
|
|
|
assertFalse(parser.mErr);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test various sunny-day operations of UIDL parser for single-line responses
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
public void testUIDLParserSingle() {
|
2009-03-04 03:32:22 +00:00
|
|
|
|
|
|
|
// single-line mode
|
|
|
|
Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
|
|
|
|
|
|
|
|
// Test single-message OK response
|
|
|
|
parser.parseSingleLine("+OK 101 " + UNIQUE_ID_1);
|
|
|
|
assertEquals(101, parser.mMessageNumber);
|
|
|
|
assertEquals(UNIQUE_ID_1, parser.mUniqueId);
|
|
|
|
assertTrue(parser.mEndOfMessage);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// Test single-message ERR response
|
|
|
|
parser.parseSingleLine("-ERR what???");
|
|
|
|
assertTrue(parser.mErr);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
/**
|
|
|
|
* Test various rainy-day operations of the UIDL parser for multi-line responses
|
|
|
|
* TODO other malformed responses
|
|
|
|
*/
|
|
|
|
public void testUIDLParserMultiFail() {
|
|
|
|
// multi-line mode
|
|
|
|
Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
// Test with null input
|
|
|
|
boolean result;
|
|
|
|
result = parser.parseMultiLine(null);
|
|
|
|
assertFalse(result);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
// Test with empty input
|
|
|
|
result = parser.parseMultiLine("");
|
|
|
|
assertFalse(result);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
/**
|
|
|
|
* Test various rainy-day operations of the UIDL parser for single-line responses
|
|
|
|
* TODO other malformed responses
|
|
|
|
*/
|
|
|
|
public void testUIDLParserSingleFail() {
|
|
|
|
// single-line mode
|
|
|
|
Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
// Test with null input
|
|
|
|
boolean result;
|
|
|
|
result = parser.parseSingleLine(null);
|
|
|
|
assertFalse(result);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-22 18:48:14 +00:00
|
|
|
// Test with empty input
|
|
|
|
result = parser.parseSingleLine("");
|
|
|
|
assertFalse(result);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Tests that variants on the RFC-specified formatting of UIDL work properly.
|
|
|
|
*/
|
|
|
|
public void testUIDLComcastVariant() {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// multi-line mode
|
|
|
|
Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// Comcast servers send multiple spaces in their darn UIDL strings.
|
|
|
|
parser.parseMultiLine("101 " + UNIQUE_ID_1);
|
|
|
|
assertEquals(101, parser.mMessageNumber);
|
|
|
|
assertEquals(UNIQUE_ID_1, parser.mUniqueId);
|
|
|
|
assertFalse(parser.mEndOfMessage);
|
|
|
|
assertFalse(parser.mErr);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Confirms simple non-SSL non-TLS login
|
|
|
|
*/
|
|
|
|
public void testSimpleLogin() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// try to open it
|
|
|
|
setupOpenFolder(mockTransport, 0, null);
|
AI 146134: Add persistence API for remote stores & folders to use while
syncing. This provides a key-value store, per folder, that
can be used by network Stores to record persistent data such
as sync status, server keys, etc.
Note that, by definition, this only applies to remote folders
(e.g. IMAP, POP3). You'll see everywhere that LocalFolder is
passed null, and this is correct - LocalFolder *is* persistent
storage and does not need external help.
Note to reviewers: The core changes are Folder.java,
LocalStore.java, and LocalStoreUnitTests.java, so please give
them the bulk of your reviewer attention. The other files
are just following along with minor API changes. Of those,
the one worth close examination is MessagingController.java,
which is the only place in the system where remote Folders
are bonded with Local Folders and thus where this new API
comes into play.
Note to jham: Can you please take a look at
LocalStore.LocalFolder.setPersistentString() and recommend
better SQL foo than my primitive test-then-update-or-insert
logic, which is not transactional or threadsafe.
BUG=1786939
Automated import of CL 146134
2009-04-14 17:15:07 +00:00
|
|
|
mFolder.open(OpenMode.READ_ONLY, null);
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* TODO: Test with SSL negotiation (faked)
|
|
|
|
* TODO: Test with SSL required but not supported
|
|
|
|
* TODO: Test with TLS negotiation (faked)
|
|
|
|
* TODO: Test with TLS required but not supported
|
|
|
|
* TODO: Test calling getMessageCount(), getMessages(), etc.
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the operation of checkSettings(), which requires (a) a good open and (b) UIDL support.
|
|
|
|
*/
|
|
|
|
public void testCheckSettings() throws MessagingException {
|
|
|
|
|
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// scenario 1: CAPA returns -ERR, so we try UIDL explicitly
|
|
|
|
setupOpenFolder(mockTransport, 0, null);
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
mockTransport.expect("QUIT", "");
|
|
|
|
mStore.checkSettings();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// scenario 2: CAPA indicates UIDL, so we don't try UIDL
|
|
|
|
setupOpenFolder(mockTransport, 0, "UIDL");
|
|
|
|
mockTransport.expect("QUIT", "");
|
|
|
|
mStore.checkSettings();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// scenario 3: CAPA returns -ERR, and UIDL fails
|
|
|
|
try {
|
|
|
|
setupOpenFolder(mockTransport, 0, null);
|
|
|
|
mockTransport.expect("UIDL", "-ERR unsupported");
|
|
|
|
mockTransport.expect("QUIT", "");
|
|
|
|
mStore.checkSettings();
|
|
|
|
fail("MessagingException was expected due to UIDL unsupported.");
|
|
|
|
} catch (MessagingException me) {
|
|
|
|
// this is expected, so eat it
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-05 06:34:26 +00:00
|
|
|
/**
|
|
|
|
* Test a strange case that causes open to proceed without mCapabilities
|
|
|
|
* open - fail with "-" error code
|
|
|
|
* then check capabilities
|
|
|
|
*/
|
|
|
|
public void testCheckSettingsCapabilities() throws MessagingException {
|
|
|
|
|
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
|
|
|
|
|
|
|
// First, preload an open that fails for some reason
|
|
|
|
mockTransport.expect(null, "-ERR from the Mock Transport.");
|
|
|
|
|
|
|
|
// And watch it fail
|
|
|
|
try {
|
|
|
|
Pop3Store.Pop3Folder folder = mStore.new Pop3Folder("INBOX");
|
|
|
|
folder.open(OpenMode.READ_WRITE, null);
|
|
|
|
fail("Should have thrown exception");
|
|
|
|
} catch (MessagingException me) {
|
|
|
|
// Expected - continue.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now try again (assuming a slightly different connection setup - successful)
|
|
|
|
// Note, checkSettings is going to try to close the connection again, so we expect
|
|
|
|
// one extra QUIT before we spin it up again
|
|
|
|
mockTransport.expect("QUIT", "");
|
|
|
|
mockTransport.expectClose();
|
|
|
|
setupOpenFolder(mockTransport, 0, "UIDL");
|
|
|
|
mockTransport.expect("QUIT", "");
|
|
|
|
mStore.checkSettings();
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test small Store & Folder functions that manage folders & namespace
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
public void testStoreFoldersFunctions() {
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// getPersonalNamespaces() always returns INBOX folder
|
2011-02-10 21:47:35 +00:00
|
|
|
Folder[] folders = mStore.getAllFolders();
|
2009-03-04 03:32:22 +00:00
|
|
|
assertEquals(1, folders.length);
|
|
|
|
assertSame(mFolder, folders[0]);
|
|
|
|
|
|
|
|
// getName() returns the name we were created with. If "inbox", converts to INBOX
|
|
|
|
assertEquals("INBOX", mFolder.getName());
|
|
|
|
Pop3Store.Pop3Folder folderMixedCaseInbox = mStore.new Pop3Folder("iNbOx");
|
|
|
|
assertEquals("INBOX", folderMixedCaseInbox.getName());
|
|
|
|
Pop3Store.Pop3Folder folderNotInbox = mStore.new Pop3Folder("NOT-INBOX");
|
|
|
|
assertEquals("NOT-INBOX", folderNotInbox.getName());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// exists() true if name is INBOX
|
|
|
|
assertTrue(mFolder.exists());
|
|
|
|
assertTrue(folderMixedCaseInbox.exists());
|
|
|
|
assertFalse(folderNotInbox.exists());
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test small Folder functions that don't really do anything in Pop3
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
public void testSmallFolderFunctions() {
|
|
|
|
|
2009-06-25 06:53:32 +00:00
|
|
|
// getMode() returns OpenMode.READ_WRITE
|
|
|
|
assertEquals(OpenMode.READ_WRITE, mFolder.getMode());
|
2009-09-25 21:54:32 +00:00
|
|
|
|
|
|
|
// canCreate() && create() return false
|
|
|
|
assertFalse(mFolder.canCreate(FolderType.HOLDS_FOLDERS));
|
|
|
|
assertFalse(mFolder.canCreate(FolderType.HOLDS_MESSAGES));
|
2009-03-04 03:32:22 +00:00
|
|
|
assertFalse(mFolder.create(FolderType.HOLDS_FOLDERS));
|
|
|
|
assertFalse(mFolder.create(FolderType.HOLDS_MESSAGES));
|
2009-09-25 21:54:32 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// getUnreadMessageCount() always returns -1
|
|
|
|
assertEquals(-1, mFolder.getUnreadMessageCount());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// getMessages(MessageRetrievalListener listener) is unsupported
|
|
|
|
try {
|
|
|
|
mFolder.getMessages(null);
|
|
|
|
fail("Exception not thrown by getMessages()");
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
// expected - succeed
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// getMessages(String[] uids, MessageRetrievalListener listener) is unsupported
|
|
|
|
try {
|
|
|
|
mFolder.getMessages(null, null);
|
|
|
|
fail("Exception not thrown by getMessages()");
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
// expected - succeed
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// getPermanentFlags() returns { Flag.DELETED }
|
|
|
|
Flag[] flags = mFolder.getPermanentFlags();
|
|
|
|
assertEquals(1, flags.length);
|
|
|
|
assertEquals(Flag.DELETED, flags[0]);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// appendMessages(Message[] messages) does nothing
|
|
|
|
mFolder.appendMessages(null);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// delete(boolean recurse) does nothing
|
|
|
|
// TODO - it should!
|
|
|
|
mFolder.delete(false);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// expunge() returns null
|
|
|
|
assertNull(mFolder.expunge());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// copyMessages() is unsupported
|
|
|
|
try {
|
2009-04-24 18:54:42 +00:00
|
|
|
mFolder.copyMessages(null, null, null);
|
2009-03-04 03:32:22 +00:00
|
|
|
fail("Exception not thrown by copyMessages()");
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
// expected - succeed
|
|
|
|
}
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-04-15 19:58:19 +00:00
|
|
|
/**
|
|
|
|
* Lightweight test to confirm that POP3 hasn't implemented any folder roles yet.
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
public void testNoFolderRolesYet() {
|
2011-02-10 21:47:35 +00:00
|
|
|
Folder[] remoteFolders = mStore.getAllFolders();
|
2009-04-15 19:58:19 +00:00
|
|
|
for (Folder folder : remoteFolders) {
|
2011-04-19 18:32:06 +00:00
|
|
|
assertEquals(Folder.FolderRole.UNKNOWN, folder.getRole());
|
2009-04-15 19:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-01 23:36:34 +00:00
|
|
|
/**
|
|
|
|
* Lightweight test to confirm that POP3 isn't requesting structure prefetch.
|
|
|
|
*/
|
|
|
|
public void testNoStructurePrefetch() {
|
2011-04-19 18:32:06 +00:00
|
|
|
assertFalse(mStore.requireStructurePrefetch());
|
2009-05-01 23:36:34 +00:00
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-05-01 23:36:34 +00:00
|
|
|
/**
|
|
|
|
* Lightweight test to confirm that POP3 is requesting sent-message-upload.
|
|
|
|
*/
|
|
|
|
public void testSentUploadRequested() {
|
2011-04-19 18:32:06 +00:00
|
|
|
assertTrue(mStore.requireCopyMessageToSentFolder());
|
2009-05-01 23:36:34 +00:00
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the process of opening and indexing a mailbox with one unread message in it.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* TODO should create an instrumented listener to confirm all expected callbacks. Then use
|
|
|
|
* it everywhere we could have passed a message listener.
|
|
|
|
*/
|
|
|
|
public void testOneUnread() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
|
|
|
|
2009-06-25 06:53:32 +00:00
|
|
|
/**
|
|
|
|
* Test the process of opening and getting message by uid.
|
|
|
|
*/
|
|
|
|
public void testGetMessageByUid() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-06-25 06:53:32 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-06-25 06:53:32 +00:00
|
|
|
setupOpenFolder(mockTransport, 2, null);
|
|
|
|
mFolder.open(OpenMode.READ_WRITE, null);
|
|
|
|
// check message count
|
|
|
|
assertEquals(2, mFolder.getMessageCount());
|
|
|
|
|
|
|
|
// setup 2 messages
|
|
|
|
setupUidlSequence(mockTransport, 2);
|
|
|
|
String uid1 = getSingleMessageUID(1);
|
|
|
|
String uid2 = getSingleMessageUID(2);
|
|
|
|
String uid3 = getSingleMessageUID(3);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-06-25 06:53:32 +00:00
|
|
|
Message msg1 = mFolder.getMessage(uid1);
|
|
|
|
assertTrue("message with uid1", msg1 != null);
|
|
|
|
|
|
|
|
// uid3 does not exist
|
|
|
|
Message msg3 = mFolder.getMessage(uid3);
|
|
|
|
assertTrue("message with uid3", msg3 == null);
|
|
|
|
|
|
|
|
Message msg2 = mFolder.getMessage(uid2);
|
|
|
|
assertTrue("message with uid2", msg2 != null);
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* There are multiple versions of this test because we are simulating the steps of
|
2009-03-04 03:32:22 +00:00
|
|
|
* MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit
|
|
|
|
* further along in each case, to test various recovery points.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in
|
|
|
|
* Pop3Folder.getMessages(), due to a closure before the UIDL command completes.
|
2009-03-04 03:32:22 +00:00
|
|
|
*/
|
2009-09-16 19:20:38 +00:00
|
|
|
public void testCatchClosed1a() throws MessagingException {
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
openFolderWithMessage(mockTransport);
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// cause the next sequence to fail on the readLine() calls
|
|
|
|
mockTransport.closeInputStream();
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// index the message(s) - it should fail, because our stream is broken
|
|
|
|
try {
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
|
|
|
fail("Broken stream should cause getMessages() to throw.");
|
2009-09-16 19:20:38 +00:00
|
|
|
} catch(MessagingException me) {
|
|
|
|
// success
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
|
|
|
|
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
|
|
|
|
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* There are multiple versions of this test because we are simulating the steps of
|
|
|
|
* MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit
|
|
|
|
* further along in each case, to test various recovery points.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in
|
|
|
|
* Pop3Folder.getMessages(), due to non-numeric data in a multi-line UIDL.
|
|
|
|
*/
|
|
|
|
public void testCatchClosed1b() throws MessagingException {
|
|
|
|
|
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
|
|
|
|
|
|
|
openFolderWithMessage(mockTransport);
|
|
|
|
|
|
|
|
// index the message(s) - it should fail, because our stream is broken
|
|
|
|
try {
|
|
|
|
// setupUidlSequence(mockTransport, 1);
|
|
|
|
mockTransport.expect("UIDL", "+OK sending UIDL list");
|
|
|
|
mockTransport.expect(null, "bad-data" + " " + "THE-UIDL");
|
|
|
|
mockTransport.expect(null, ".");
|
|
|
|
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
fail("Bad UIDL should cause getMessages() to throw.");
|
|
|
|
} catch(MessagingException me) {
|
2009-03-04 03:32:22 +00:00
|
|
|
// success
|
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2009-09-16 19:20:38 +00:00
|
|
|
|
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* There are multiple versions of this test because we are simulating the steps of
|
|
|
|
* MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit
|
|
|
|
* further along in each case, to test various recovery points.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in
|
|
|
|
* Pop3Folder.getMessages(), due to non-numeric data in a single-line UIDL.
|
|
|
|
*/
|
|
|
|
public void testCatchClosed1c() throws MessagingException {
|
|
|
|
|
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
|
|
|
|
|
|
|
// openFolderWithMessage(mockTransport);
|
|
|
|
setupOpenFolder(mockTransport, 6000, null);
|
|
|
|
mFolder.open(OpenMode.READ_ONLY, null);
|
|
|
|
assertEquals(6000, mFolder.getMessageCount());
|
|
|
|
|
|
|
|
// index the message(s) - it should fail, because our stream is broken
|
|
|
|
try {
|
|
|
|
// setupUidlSequence(mockTransport, 1);
|
|
|
|
mockTransport.expect("UIDL 1", "+OK " + "bad-data" + " " + "THE-UIDL");
|
|
|
|
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
fail("Bad UIDL should cause getMessages() to throw.");
|
|
|
|
} catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
|
|
|
|
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* There are multiple versions of this test because we are simulating the steps of
|
2009-03-04 03:32:22 +00:00
|
|
|
* MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit
|
|
|
|
* further along in each case, to test various recovery points.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in
|
2009-03-04 03:32:22 +00:00
|
|
|
* Pop3Folder.fetch(), for a failure in the call to indexUids().
|
|
|
|
*/
|
|
|
|
public void testCatchClosed2() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
openFolderWithMessage(mockTransport);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
2011-04-19 18:32:06 +00:00
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// cause the next sequence to fail on the readLine() calls
|
|
|
|
mockTransport.closeInputStream();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
try {
|
|
|
|
// try the basic fetch of flags & envelope
|
|
|
|
setupListSequence(mockTransport, 1);
|
|
|
|
FetchProfile fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.FLAGS);
|
|
|
|
fp.add(FetchProfile.Item.ENVELOPE);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
|
|
|
|
fail("Broken stream should cause fetch() to throw.");
|
|
|
|
}
|
|
|
|
catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* There are multiple versions of this test because we have to check additional places where
|
|
|
|
* Pop3Store and/or Pop3Folder should be dealing with IOErrors.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in
|
2009-03-04 03:32:22 +00:00
|
|
|
* Pop3Folder.fetch(), for a failure in the call to fetchEnvelope().
|
|
|
|
*/
|
2009-09-16 19:20:38 +00:00
|
|
|
public void testCatchClosed2a() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
openFolderWithMessage(mockTransport);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
2011-04-19 18:32:06 +00:00
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
2009-09-16 19:20:38 +00:00
|
|
|
|
|
|
|
// try the basic fetch of flags & envelope, but the LIST command fails
|
|
|
|
setupBrokenListSequence(mockTransport, 1);
|
|
|
|
try {
|
|
|
|
FetchProfile fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.FLAGS);
|
|
|
|
fp.add(FetchProfile.Item.ENVELOPE);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
|
|
|
|
fail("Broken stream should cause fetch() to throw.");
|
|
|
|
} catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* There are multiple versions of this test because we are simulating the steps of
|
2009-03-04 03:32:22 +00:00
|
|
|
* MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit
|
|
|
|
* further along in each case, to test various recovery points.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the second IOExceptionHandler in
|
2009-03-04 03:32:22 +00:00
|
|
|
* Pop3Folder.fetch().
|
|
|
|
*/
|
|
|
|
public void testCatchClosed3() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
openFolderWithMessage(mockTransport);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
2011-04-19 18:32:06 +00:00
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
2009-03-04 03:32:22 +00:00
|
|
|
|
|
|
|
// try the basic fetch of flags & envelope
|
|
|
|
setupListSequence(mockTransport, 1);
|
|
|
|
FetchProfile fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.FLAGS);
|
|
|
|
fp.add(FetchProfile.Item.ENVELOPE);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
|
|
|
|
|
|
|
|
// cause the next sequence to fail on the readLine() calls
|
|
|
|
mockTransport.closeInputStream();
|
|
|
|
|
|
|
|
try {
|
|
|
|
// now try fetching the message
|
|
|
|
setupSingleMessage(mockTransport, 1, false);
|
|
|
|
fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.BODY);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
checkFetchedMessage(messages[0], 1, false);
|
|
|
|
fail("Broken stream should cause fetch() to throw.");
|
|
|
|
}
|
|
|
|
catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* There are multiple versions of this test because we have to check additional places where
|
|
|
|
* Pop3Store and/or Pop3Folder should be dealing with IOErrors.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in
|
2009-03-04 03:32:22 +00:00
|
|
|
* Pop3Folder.setFlags().
|
|
|
|
*/
|
|
|
|
public void testCatchClosed4() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
openFolderWithMessage(mockTransport);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// cause the next sequence to fail on the readLine() calls
|
|
|
|
mockTransport.closeInputStream();
|
|
|
|
|
|
|
|
// delete 'em all - should fail because of broken stream
|
|
|
|
try {
|
|
|
|
mockTransport.expect("DELE 1", "+OK message deleted");
|
|
|
|
mFolder.setFlags(messages, new Flag[] { Flag.DELETED }, true);
|
|
|
|
fail("Broken stream should cause fetch() to throw.");
|
|
|
|
}
|
|
|
|
catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll just repeat the above steps, without the failure.
|
|
|
|
// NOTE: everything from here down is copied from testOneUnread() and should be consolidated
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* There are multiple versions of this test because we have to check additional places where
|
|
|
|
* Pop3Store and/or Pop3Folder should be dealing with IOErrors.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in
|
2009-03-04 03:32:22 +00:00
|
|
|
* Pop3Folder.open().
|
|
|
|
*/
|
|
|
|
public void testCatchClosed5() {
|
|
|
|
// TODO cannot write this test until we can inject stream closures mid-sequence
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* There are multiple versions of this test because we have to check additional places where
|
|
|
|
* Pop3Store and/or Pop3Folder should be dealing with IOErrors.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the second IOExceptionHandler in
|
2009-09-16 19:20:38 +00:00
|
|
|
* Pop3Folder.open() (when it calls STAT and the response is empty of garbagey).
|
2009-03-04 03:32:22 +00:00
|
|
|
*/
|
2009-09-16 19:20:38 +00:00
|
|
|
public void testCatchClosed6a() throws MessagingException {
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// like openFolderWithMessage(mockTransport) but with a broken STAT report (empty response)
|
|
|
|
setupOpenFolder(mockTransport, -1, null);
|
|
|
|
try {
|
|
|
|
mFolder.open(OpenMode.READ_ONLY, null);
|
|
|
|
fail("Broken STAT should cause open() to throw.");
|
|
|
|
} catch(MessagingException me) {
|
|
|
|
// success
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// At this point the UI would display connection error, which is fine. Now, the real
|
|
|
|
// test is, can we recover? So I'll try a new connection, without the failure.
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// confirm that we're closed at this point
|
|
|
|
assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
// and confirm that the next connection will be OK
|
|
|
|
checkOneUnread(mockTransport);
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-09-16 19:20:38 +00:00
|
|
|
/**
|
|
|
|
* Test the scenario where the transport is "open" but not really (e.g. server closed). Two
|
|
|
|
* things should happen: We should see an intermediate failure that makes sense, and the next
|
|
|
|
* operation should reopen properly.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-09-16 19:20:38 +00:00
|
|
|
* There are multiple versions of this test because we have to check additional places where
|
|
|
|
* Pop3Store and/or Pop3Folder should be dealing with IOErrors.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
|
|
|
* This test confirms that Pop3Store needs to call close() in the second IOExceptionHandler in
|
2009-09-16 19:20:38 +00:00
|
|
|
* Pop3Folder.open() (when it calls STAT, and there is no response at all).
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
public void testCatchClosed6b() {
|
2009-03-04 03:32:22 +00:00
|
|
|
// TODO cannot write this test until we can inject stream closures mid-sequence
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
2011-04-19 18:32:06 +00:00
|
|
|
* Given an initialized mock transport, open it and attempt to "read" one unread message from
|
2009-03-04 03:32:22 +00:00
|
|
|
* it. This can be used as a basic test of functionality and it should be possible to call this
|
|
|
|
* repeatedly (if you close the folder between calls).
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param mockTransport the mock transport we're using
|
|
|
|
*/
|
|
|
|
private void checkOneUnread(MockTransport mockTransport) throws MessagingException {
|
|
|
|
openFolderWithMessage(mockTransport);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 1);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 1, null);
|
|
|
|
assertEquals(1, messages.length);
|
|
|
|
assertEquals(getSingleMessageUID(1), messages[0].getUid());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// try the basic fetch of flags & envelope
|
|
|
|
setupListSequence(mockTransport, 1);
|
|
|
|
FetchProfile fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.FLAGS);
|
|
|
|
fp.add(FetchProfile.Item.ENVELOPE);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
|
|
|
// A side effect of how messages work is that if you get fields that are empty,
|
2009-03-19 00:39:48 +00:00
|
|
|
// then empty arrays are written back into the parsed header fields (e.g. mTo, mFrom). The
|
|
|
|
// standard message parser needs to clear these before parsing. Make sure that this
|
|
|
|
// is happening. (This doesn't affect IMAP, which reads the headers directly via
|
|
|
|
// IMAP evelopes.)
|
|
|
|
MimeMessage message = (MimeMessage) messages[0];
|
|
|
|
message.getRecipients(RecipientType.TO);
|
|
|
|
message.getRecipients(RecipientType.CC);
|
|
|
|
message.getRecipients(RecipientType.BCC);
|
2009-03-04 03:32:22 +00:00
|
|
|
|
|
|
|
// now try fetching the message
|
|
|
|
setupSingleMessage(mockTransport, 1, false);
|
|
|
|
fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.BODY);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
checkFetchedMessage(messages[0], 1, false);
|
|
|
|
}
|
2010-04-12 17:56:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A group of tests to confirm that we're properly juggling the RETR and TOP commands.
|
|
|
|
* Some servers (hello, live.com) support TOP but don't support CAPA. So we ignore CAPA
|
|
|
|
* and just try TOP.
|
|
|
|
*/
|
|
|
|
public void testRetrVariants() throws MessagingException {
|
|
|
|
MockTransport mockTransport = openAndInjectMockTransport();
|
|
|
|
openFolderWithMessage(mockTransport);
|
|
|
|
|
|
|
|
// index the message(s)
|
|
|
|
setupUidlSequence(mockTransport, 2);
|
|
|
|
Message[] messages = mFolder.getMessages(1, 2, null);
|
|
|
|
assertEquals(2, messages.length);
|
|
|
|
|
|
|
|
// basic fetch of flags & envelope
|
|
|
|
setupListSequence(mockTransport, 2);
|
|
|
|
FetchProfile fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.FLAGS);
|
|
|
|
fp.add(FetchProfile.Item.ENVELOPE);
|
|
|
|
mFolder.fetch(messages, fp, null);
|
|
|
|
|
2011-04-19 18:32:06 +00:00
|
|
|
// A side effect of how messages work is that if you get fields that are empty,
|
2010-04-12 17:56:55 +00:00
|
|
|
// then empty arrays are written back into the parsed header fields (e.g. mTo, mFrom). The
|
|
|
|
// standard message parser needs to clear these before parsing. Make sure that this
|
|
|
|
// is happening. (This doesn't affect IMAP, which reads the headers directly via
|
|
|
|
// IMAP envelopes.)
|
|
|
|
for (Message message : messages) {
|
|
|
|
message.getRecipients(RecipientType.TO);
|
|
|
|
message.getRecipients(RecipientType.CC);
|
|
|
|
message.getRecipients(RecipientType.BCC);
|
|
|
|
}
|
|
|
|
|
|
|
|
// In the cases below, we fetch BODY_SANE which tries to load the first chunk of the
|
|
|
|
// message (not the entire thing) in order to quickly access the headers.
|
|
|
|
// In the first test, TOP succeeds
|
|
|
|
Message[] singleMessage = new Message[] { messages[0] };
|
|
|
|
setupSingleMessageTop(mockTransport, 1, true, true); // try TOP & succeed
|
|
|
|
fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.BODY_SANE);
|
|
|
|
mFolder.fetch(singleMessage, fp, null);
|
|
|
|
checkFetchedMessage(singleMessage[0], 1, false);
|
|
|
|
|
|
|
|
// In the 2nd test, TOP fails, so we should fall back to RETR
|
|
|
|
singleMessage[0] = messages[1];
|
|
|
|
setupSingleMessageTop(mockTransport, 2, true, false); // try TOP & fail
|
|
|
|
fp = new FetchProfile();
|
|
|
|
fp.add(FetchProfile.Item.BODY_SANE);
|
|
|
|
mFolder.fetch(singleMessage, fp, null);
|
|
|
|
checkFetchedMessage(singleMessage[0], 2, false);
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Set up a basic MockTransport. open it, and inject it into mStore
|
|
|
|
*/
|
|
|
|
private MockTransport openAndInjectMockTransport() {
|
|
|
|
// Create mock transport and inject it into the POP3Store that's already set up
|
|
|
|
MockTransport mockTransport = new MockTransport();
|
2009-09-29 22:28:43 +00:00
|
|
|
mockTransport.setSecurity(Transport.CONNECTION_SECURITY_NONE, false);
|
2009-03-04 03:32:22 +00:00
|
|
|
mStore.setTransport(mockTransport);
|
|
|
|
return mockTransport;
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Open a folder that's preloaded with one unread message.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param mockTransport the mock transport we're using
|
|
|
|
*/
|
|
|
|
private void openFolderWithMessage(MockTransport mockTransport) throws MessagingException {
|
|
|
|
// try to open it
|
|
|
|
setupOpenFolder(mockTransport, 1, null);
|
AI 146134: Add persistence API for remote stores & folders to use while
syncing. This provides a key-value store, per folder, that
can be used by network Stores to record persistent data such
as sync status, server keys, etc.
Note that, by definition, this only applies to remote folders
(e.g. IMAP, POP3). You'll see everywhere that LocalFolder is
passed null, and this is correct - LocalFolder *is* persistent
storage and does not need external help.
Note to reviewers: The core changes are Folder.java,
LocalStore.java, and LocalStoreUnitTests.java, so please give
them the bulk of your reviewer attention. The other files
are just following along with minor API changes. Of those,
the one worth close examination is MessagingController.java,
which is the only place in the system where remote Folders
are bonded with Local Folders and thus where this new API
comes into play.
Note to jham: Can you please take a look at
LocalStore.LocalFolder.setPersistentString() and recommend
better SQL foo than my primitive test-then-update-or-insert
logic, which is not transactional or threadsafe.
BUG=1786939
Automated import of CL 146134
2009-04-14 17:15:07 +00:00
|
|
|
mFolder.open(OpenMode.READ_ONLY, null);
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// check message count
|
|
|
|
assertEquals(1, mFolder.getMessageCount());
|
|
|
|
}
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Look at a fetched message and confirm that it is complete.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* TODO this needs to be more dynamic, not just hardcoded for empty message #1.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param message the fetched message to be checked
|
|
|
|
* @param msgNum the message number
|
|
|
|
*/
|
2011-04-19 18:32:06 +00:00
|
|
|
private void checkFetchedMessage(Message message, int msgNum, boolean body)
|
2009-03-04 03:32:22 +00:00
|
|
|
throws MessagingException {
|
|
|
|
// check To:
|
|
|
|
Address[] to = message.getRecipients(RecipientType.TO);
|
|
|
|
assertNotNull(to);
|
|
|
|
assertEquals(1, to.length);
|
|
|
|
assertEquals("Smith@Registry.Org", to[0].getAddress());
|
|
|
|
assertNull(to[0].getPersonal());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// check From:
|
|
|
|
Address[] from = message.getFrom();
|
|
|
|
assertNotNull(from);
|
|
|
|
assertEquals(1, from.length);
|
|
|
|
assertEquals("Jones@Registry.Org", from[0].getAddress());
|
|
|
|
assertNull(from[0].getPersonal());
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-19 00:39:48 +00:00
|
|
|
// check Cc:
|
|
|
|
Address[] cc = message.getRecipients(RecipientType.CC);
|
|
|
|
assertNotNull(cc);
|
|
|
|
assertEquals(1, cc.length);
|
|
|
|
assertEquals("Chris@Registry.Org", cc[0].getAddress());
|
|
|
|
assertNull(cc[0].getPersonal());
|
|
|
|
|
|
|
|
// check Reply-To:
|
|
|
|
Address[] replyto = message.getReplyTo();
|
|
|
|
assertNotNull(replyto);
|
|
|
|
assertEquals(1, replyto.length);
|
|
|
|
assertEquals("Roger@Registry.Org", replyto[0].getAddress());
|
|
|
|
assertNull(replyto[0].getPersonal());
|
2009-03-04 03:32:22 +00:00
|
|
|
|
|
|
|
// TODO date
|
2011-04-19 18:32:06 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
// TODO check body (if applicable)
|
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Helper which stuffs the mock with enough strings to satisfy a call to Pop3Folder.open()
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param mockTransport the mock transport we're using
|
2009-09-16 19:20:38 +00:00
|
|
|
* @param statCount the number of messages to indicate in the STAT, or -1 for broken STAT
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param capabilities if non-null, comma-separated list of capabilities
|
|
|
|
*/
|
|
|
|
private void setupOpenFolder(MockTransport mockTransport, int statCount, String capabilities) {
|
|
|
|
mockTransport.expect(null, "+OK Hello there from the Mock Transport.");
|
|
|
|
if (capabilities == null) {
|
|
|
|
mockTransport.expect("CAPA", "-ERR unimplemented");
|
|
|
|
} else {
|
|
|
|
mockTransport.expect("CAPA", "+OK capabilities follow");
|
|
|
|
mockTransport.expect(null, capabilities.split(",")); // one capability per line
|
|
|
|
mockTransport.expect(null, "."); // terminated by "."
|
|
|
|
}
|
|
|
|
mockTransport.expect("USER user", "+OK User name accepted");
|
|
|
|
mockTransport.expect("PASS password", "+OK Logged in");
|
2009-09-16 19:20:38 +00:00
|
|
|
if (statCount == -1) {
|
|
|
|
mockTransport.expect("STAT", "");
|
|
|
|
} else {
|
|
|
|
String stat = "+OK " + Integer.toString(statCount) + " "
|
|
|
|
+ Integer.toString(PER_MESSAGE_SIZE * statCount);
|
|
|
|
mockTransport.expect("STAT", stat);
|
|
|
|
}
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Setup expects for a UIDL on a mailbox with 0 or more messages in it.
|
|
|
|
* @param transport The mock transport to preload
|
|
|
|
* @param numMessages The number of messages to return from UIDL.
|
|
|
|
*/
|
|
|
|
private static void setupUidlSequence(MockTransport transport, int numMessages) {
|
2011-04-19 18:32:06 +00:00
|
|
|
transport.expect("UIDL", "+OK sending UIDL list");
|
2009-03-04 03:32:22 +00:00
|
|
|
for (int msgNum = 1; msgNum <= numMessages; ++msgNum) {
|
|
|
|
transport.expect(null, Integer.toString(msgNum) + " " + getSingleMessageUID(msgNum));
|
|
|
|
}
|
|
|
|
transport.expect(null, ".");
|
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Setup expects for a LIST on a mailbox with 0 or more messages in it.
|
|
|
|
* @param transport The mock transport to preload
|
|
|
|
* @param numMessages The number of messages to return from LIST.
|
|
|
|
*/
|
|
|
|
private static void setupListSequence(MockTransport transport, int numMessages) {
|
2011-04-19 18:32:06 +00:00
|
|
|
transport.expect("LIST", "+OK sending scan listing");
|
2009-03-04 03:32:22 +00:00
|
|
|
for (int msgNum = 1; msgNum <= numMessages; ++msgNum) {
|
2011-04-19 18:32:06 +00:00
|
|
|
transport.expect(null, Integer.toString(msgNum) + " " +
|
2009-03-04 03:32:22 +00:00
|
|
|
Integer.toString(PER_MESSAGE_SIZE * msgNum));
|
|
|
|
}
|
|
|
|
transport.expect(null, ".");
|
|
|
|
}
|
2009-09-16 19:20:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup expects for a LIST on a mailbox with 0 or more messages in it, except that
|
|
|
|
* this time the pipe fails, and we return empty lines.
|
|
|
|
* @param transport The mock transport to preload
|
|
|
|
* @param numMessages The number of messages to return from LIST.
|
|
|
|
*/
|
|
|
|
private static void setupBrokenListSequence(MockTransport transport, int numMessages) {
|
|
|
|
transport.expect("LIST", "");
|
|
|
|
for (int msgNum = 1; msgNum <= numMessages; ++msgNum) {
|
|
|
|
transport.expect(null, "");
|
|
|
|
}
|
|
|
|
transport.expect(null, "");
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
/**
|
|
|
|
* Setup a single message to be retrieved.
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* Per RFC822 here is a minimal message header:
|
|
|
|
* Date: 26 Aug 76 1429 EDT
|
|
|
|
* From: Jones@Registry.Org
|
|
|
|
* To: Smith@Registry.Org
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-19 00:39:48 +00:00
|
|
|
* We'll add the following fields to support additional tests:
|
|
|
|
* Cc: Chris@Registry.Org
|
|
|
|
* Reply-To: Roger@Registry.Org
|
2011-04-19 18:32:06 +00:00
|
|
|
*
|
2009-03-04 03:32:22 +00:00
|
|
|
* @param transport the mock transport to preload
|
|
|
|
* @param msgNum the message number to expect and return
|
|
|
|
* @param body if true, a non-empty body will be added
|
|
|
|
*/
|
|
|
|
private static void setupSingleMessage(MockTransport transport, int msgNum, boolean body) {
|
2010-04-12 17:56:55 +00:00
|
|
|
setupSingleMessageTop(transport, msgNum, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup a single message to be retrieved (headers only).
|
|
|
|
* This is very similar to setupSingleMessage() but is intended to test the BODY_SANE
|
|
|
|
* fetch mode.
|
|
|
|
* @param transport the mock transport
|
|
|
|
* @param msgNum the message number to expect and return
|
|
|
|
* @param topTry if true, the "client" is going to attempt the TOP command
|
|
|
|
* @param topSupported if true, the "server" supports the TOP command
|
|
|
|
*/
|
|
|
|
private static void setupSingleMessageTop(MockTransport transport, int msgNum,
|
|
|
|
boolean topTry, boolean topSupported) {
|
|
|
|
String msgNumString = Integer.toString(msgNum);
|
|
|
|
String topCommand = "TOP " + msgNumString + " 673";
|
|
|
|
String retrCommand = "RETR " + msgNumString;
|
|
|
|
|
|
|
|
if (topTry) {
|
|
|
|
if (topSupported) {
|
|
|
|
transport.expect(topCommand, "+OK message follows");
|
|
|
|
} else {
|
|
|
|
transport.expect(topCommand, "-ERR unsupported command");
|
|
|
|
transport.expect(retrCommand, "+OK message follows");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
transport.expect(retrCommand, "+OK message follows");
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:32:22 +00:00
|
|
|
transport.expect(null, "Date: 26 Aug 76 1429 EDT");
|
|
|
|
transport.expect(null, "From: Jones@Registry.Org");
|
|
|
|
transport.expect(null, "To: Smith@Registry.Org");
|
2009-03-19 00:39:48 +00:00
|
|
|
transport.expect(null, "CC: Chris@Registry.Org");
|
|
|
|
transport.expect(null, "Reply-To: Roger@Registry.Org");
|
2009-03-04 03:32:22 +00:00
|
|
|
transport.expect(null, "");
|
|
|
|
transport.expect(null, ".");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates a simple unique code for each message. Repeatable.
|
|
|
|
* @param msgNum The message number
|
|
|
|
* @return a string that can be used as the UID
|
|
|
|
*/
|
|
|
|
private static String getSingleMessageUID(int msgNum) {
|
|
|
|
final String UID_HEAD = "ABCDEF-";
|
|
|
|
final String UID_TAIL = "";
|
|
|
|
return UID_HEAD + Integer.toString(msgNum) + UID_TAIL;
|
|
|
|
}
|
|
|
|
}
|