196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * Licensed under the Apache License, Version 2.0 (the "License"); you may not 517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * use this file except in compliance with the License. You may obtain a copy of 617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * http://www.apache.org/licenses/LICENSE-2.0 996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 1217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 1317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * License for the specific language governing permissions and limitations under 1417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * the License. 1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.mail.transport; 1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xieimport android.content.Context; 2017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 2117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xieimport com.android.emailcommon.provider.HostAuth; 2217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xieimport com.android.mail.utils.LogUtils; 2317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 2417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xieimport junit.framework.Assert; 2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStream; 29be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadlerimport java.net.InetAddress; 3096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.ArrayList; 3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Arrays; 32af6724527e564d35dd27ac35e24dbced554792e5Makoto Onukiimport java.util.regex.Pattern; 33af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/** 3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a mock Transport that is used to test protocols that use MailTransport. 3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 3717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xiepublic class MockTransport extends MailTransport { 3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // All flags defining debug or development code settings must be FALSE 4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // when code is checked in or released. 4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static boolean DEBUG_LOG_STREAMS = true; 42a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static String LOG_TAG = "MockTransport"; 4496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 45f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki private static final String SPECIAL_RESPONSE_IOEXCEPTION = "!!!IOEXCEPTION!!!"; 46f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki 471a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler private boolean mTlsStarted = false; 48a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private boolean mOpen; 5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private boolean mInputOpen; 51be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler private InetAddress mLocalAddress; 52be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<String> mQueuedInput = new ArrayList<String>(); 54be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static class Transaction { 5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final int ACTION_INJECT_TEXT = 0; 57f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_CLIENT_CLOSE = 1; 58f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_IO_EXCEPTION = 2; 591a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public static final int ACTION_START_TLS = 3; 60a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int mAction; 6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String mPattern; 6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] mResponses; 64a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(String pattern, String[] responses) { 6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = ACTION_INJECT_TEXT; 6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = pattern; 6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = responses; 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 70a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(int otherType) { 7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = otherType; 7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = null; 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = null; 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 76a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String toString() { 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project switch (mAction) { 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_INJECT_TEXT: 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mPattern + ": " + Arrays.toString(mResponses); 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_CLIENT_CLOSE: 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "Expect the client to close"; 84f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case ACTION_IO_EXCEPTION: 85f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return "Expect IOException"; 861a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler case ACTION_START_TLS: 871a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return "Expect StartTls"; 8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project default: 8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "(Hmm. Unknown action.)"; 9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 93a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<Transaction> mPairs = new ArrayList<Transaction>(); 95c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 9617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static MockTransport createMockTransport(Context context) { 9717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie return new MockTransport(context, new HostAuth()); 9817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie } 9917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 10017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public MockTransport(Context context, HostAuth hostAuth) { 10117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie super(context, LOG_TAG, hostAuth); 10217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie } 10317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 104c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler /** 105c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * Give the mock a pattern to wait for. No response will be sent. 106c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * @param pattern Java RegEx to wait for 107c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler */ 108c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler public void expect(String pattern) { 10917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie expect(pattern, (String[]) null); 110c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } 111c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a response to send back. 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param response String to reply with, or null to acccept string but not respond to it 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String response) { 11817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie expect(pattern, (response == null) ? null : new String[] {response}); 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 120a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a multi-line response to send back. 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param responses Strings to reply with 12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String[] responses) { 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = new Transaction(pattern, responses); 12896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(pair); 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 130af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 131af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki /** 132af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * Same as {@link #expect(String, String[])}, but the first arg is taken literally, rather than 133af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * as a regexp. 134af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki */ 135af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki public void expectLiterally(String literal, String[] responses) { 136af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki expect("^" + Pattern.quote(literal) + "$", responses); 137af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki } 138af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 139a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki /** 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Tell the Mock Transport that we expect it to be closed. This will preserve 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the remaining entries in the expect() stream and allow us to "ride over" the close (which 14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * would normally reset everything). 14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expectClose() { 14596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(new Transaction(Transaction.ACTION_CLIENT_CLOSE)); 14696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 147a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 148f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void expectIOException() { 149f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mPairs.add(new Transaction(Transaction.ACTION_IO_EXCEPTION)); 150f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 151f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki 1521a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public void expectStartTls() { 1531a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mPairs.add(new Transaction(Transaction.ACTION_START_TLS)); 1541a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1551a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 156f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki private void sendResponse(Transaction pair) { 157f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki switch (pair.mAction) { 158f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_INJECT_TEXT: 159f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki for (String s : pair.mResponses) { 160f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(s); 161f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 162f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 163f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_IO_EXCEPTION: 164f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(SPECIAL_RESPONSE_IOEXCEPTION); 165f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 166f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki default: 167f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Assert.fail("Invalid action for sendResponse: " + pair.mAction); 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 1721a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler * Check that TLS was started 1731a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler */ 1741a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public boolean isTlsStarted() { 1751a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return mTlsStarted; 1761a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1771a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 1781a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler /** 179a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * This simulates a condition where the server has closed its side, causing 18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * reads to fail. 18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 18296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void closeInputStream() { 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 186ebece4dbdcdfee85a410a0d00c9b6739ee3e705eTodd Kennedy @Override 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void close() { 18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = false; 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // unless it was expected as part of a test, reset the stream 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mPairs.size() > 0) { 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction expect = mPairs.remove(0); 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (expect.mAction == Transaction.ACTION_CLIENT_CLOSE) { 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mQueuedInput.clear(); 19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.clear(); 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 201be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public void setMockLocalAddress(InetAddress address) { 202be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler mLocalAddress = address; 203be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 204be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 205e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public InputStream getInputStream() { 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockInputStream(); 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This normally serves as a pseudo-clone, for use by Imap. For the purposes of unit testing, 213a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * until we need something more complex, we'll just return the actual MockTransport. Then we 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * don't have to worry about dealing with test metadata like the expects list or socket state. 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 216e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 21717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public MockTransport clone() { 21817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie return this; 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 221e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public OutputStream getOutputStream() { 223af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki Assert.assertTrue(mOpen); 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockOutputStream(); 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 228e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean isOpen() { 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mOpen; 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 233e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 23417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public void open() /* 23517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * throws MessagingException, 23617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * CertificateValidationException 23717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie */{ 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = true; 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = true; 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This returns one string (if available) to the caller. Usually this simply pulls strings 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * from the mQueuedInput list, but if the list is empty, we also peek the expect list. This 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * supports banners, multi-line responses, and any other cases where we respond without 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * a specific expect pattern. 247a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If no response text is available, we assert (failing our test) as an underflow. 249a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the read text if DEBUG_LOG_STREAMS is true. 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String readLine() throws IOException { 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // if there's nothing to read, see if we can find a null-pattern 25817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // response 259f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if ((mQueuedInput.size() == 0) && (mPairs.size() > 0)) { 260f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Transaction pair = mPairs.get(0); 261f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mPattern == null) { 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.remove(0); 263f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 266f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (mQueuedInput.size() == 0) { 267f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki // MailTransport returns "" at EOS. 268560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(LOG_TAG, "Underflow reading from MockTransport"); 269f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return ""; 270f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String line = mQueuedInput.remove(0); 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 273560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(LOG_TAG, "<<< " + line); 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 275f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (SPECIAL_RESPONSE_IOEXCEPTION.equals(line)) { 276f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 277f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return line; 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 281e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 28217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public void reopenTls() /* throws MessagingException */{ 28396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 2841a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler Transaction expect = mPairs.remove(0); 2851a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler SmtpSenderUnitTests.assertTrue(expect.mAction == Transaction.ACTION_START_TLS); 2861a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mTlsStarted = true; 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 289e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler public void setSecurity(int connectionSecurity, boolean trustAllCertificates) { 29017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie mHostAuth.mFlags = 29117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie connectionSecurity & (trustAllCertificates ? HostAuth.FLAG_TRUST_ALL : 0xff); 29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 29417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public void setHost(String address) { 29517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie mHostAuth.mAddress = address; 29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 297a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 29817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie @Override 29917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public void setSoTimeout(int timeoutMilliseconds) /* throws SocketException */{} 30017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 30196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 30296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Accepts a single string (command or text) that was written by the code under test. 30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Because we are essentially mocking a server, we check to see if this string was expected. 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If the string was expected, we push the corresponding responses into the mQueuedInput 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * list, for subsequent calls to readLine(). If the string does not match, we assert 30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the mismatch. If no string was expected, we assert it as an overflow. 307a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the written text if DEBUG_LOG_STREAMS is true. 30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 310e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 311f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void writeLine(String s, String sensitiveReplacement) throws IOException { 31296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 313560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(LOG_TAG, ">>> " + s); 31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 31617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie SmtpSenderUnitTests.assertTrue( 31717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie "Overflow writing to MockTransport: Getting " + s, 0 != mPairs.size()); 31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = mPairs.remove(0); 319f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mAction == Transaction.ACTION_IO_EXCEPTION) { 320f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 321f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 322af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki SmtpSenderUnitTests.assertTrue("Unexpected string written to MockTransport: Actual=" + s 32317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie + " Expected=" + pair.mPattern, pair.mPattern != null && s.matches(pair.mPattern)); 32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (pair.mResponses != null) { 325f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 32696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 328a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 32996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an InputStream that satisfies the needs of getInputStream() 33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 33296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockInputStream extends InputStream { 33396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 334e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private byte[] mNextLine = null; 335e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private int mNextIndex = 0; 336a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 33796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 33896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Reads from the same input buffer as readLine() 33996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 34096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 34196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int read() throws IOException { 34296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 34396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException(); 34496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 345a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 34696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 34796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 34896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 349a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 35096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // previous line was exhausted so try to get another one 35196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String next = readLine(); 35296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (next == null) { 35396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 35496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextLine = (next + "\r\n").getBytes(); 35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextIndex = 0; 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 35896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 361a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 362a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki // no joy - throw an exception 363a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki throw new IOException(); 36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 366a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an OutputStream that satisfies the needs of getOutputStream() 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockOutputStream extends OutputStream { 37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 372e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private StringBuilder sb = new StringBuilder(); 37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 375f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void write(int oneByte) throws IOException { 376c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // CR or CRLF will immediately dump previous line (w/o CRLF) 377c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler if (oneByte == '\r') { 378c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler writeLine(sb.toString(), null); 379c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler sb = new StringBuilder(); 380c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else if (oneByte == '\n') { 381c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // swallow it 382c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else { 38317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie sb.append((char) oneByte); 38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 387be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 388e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 389be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public InetAddress getLocalAddress() { 390be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler if (isOpen()) { 391be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return mLocalAddress; 392be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } else { 393be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return null; 394be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 395be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 396a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy} 397