MockTransport.java revision a50fc99b0c433f0cde31ba1c7ab87fb9ea86345d
196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License. 696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 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 1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and 1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under 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 1996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Transport; 2096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 2196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.util.Log; 2296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 2396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 2496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStream; 26be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadlerimport java.net.InetAddress; 2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.net.URI; 2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.ArrayList; 2996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Arrays; 30af6724527e564d35dd27ac35e24dbced554792e5Makoto Onukiimport java.util.regex.Pattern; 31af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 32af6724527e564d35dd27ac35e24dbced554792e5Makoto Onukiimport junit.framework.Assert; 3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 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 */ 3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MockTransport implements Transport { 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; 5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private int mConnectionSecurity; 52e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler private boolean mTrustCertificates; 53cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler private String mHost; 54be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler private InetAddress mLocalAddress; 55be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<String> mQueuedInput = new ArrayList<String>(); 57be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static class Transaction { 5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final int ACTION_INJECT_TEXT = 0; 60f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_CLIENT_CLOSE = 1; 61f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_IO_EXCEPTION = 2; 621a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public static final int ACTION_START_TLS = 3; 63a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int mAction; 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String mPattern; 6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] mResponses; 67a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(String pattern, String[] responses) { 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = ACTION_INJECT_TEXT; 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = pattern; 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = responses; 7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 73a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(int otherType) { 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = otherType; 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = null; 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = null; 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 79a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String toString() { 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project switch (mAction) { 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_INJECT_TEXT: 8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mPattern + ": " + Arrays.toString(mResponses); 8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_CLIENT_CLOSE: 8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "Expect the client to close"; 87f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case ACTION_IO_EXCEPTION: 88f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return "Expect IOException"; 891a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler case ACTION_START_TLS: 901a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return "Expect StartTls"; 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project default: 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "(Hmm. Unknown action.)"; 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 96a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<Transaction> mPairs = new ArrayList<Transaction>(); 98c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 99c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler /** 100c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * Give the mock a pattern to wait for. No response will be sent. 101c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * @param pattern Java RegEx to wait for 102c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler */ 103c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler public void expect(String pattern) { 104c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler expect(pattern, (String[])null); 105c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } 106c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a response to send back. 10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param response String to reply with, or null to acccept string but not respond to it 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String response) { 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(pattern, (response == null) ? null : new String[] { response }); 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 115a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a multi-line response to send back. 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param responses Strings to reply with 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String[] responses) { 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = new Transaction(pattern, responses); 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(pair); 12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 125af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 126af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki /** 127af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * Same as {@link #expect(String, String[])}, but the first arg is taken literally, rather than 128af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * as a regexp. 129af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki */ 130af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki public void expectLiterally(String literal, String[] responses) { 131af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki expect("^" + Pattern.quote(literal) + "$", responses); 132af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki } 133af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 134a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki /** 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Tell the Mock Transport that we expect it to be closed. This will preserve 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the remaining entries in the expect() stream and allow us to "ride over" the close (which 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * would normally reset everything). 13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expectClose() { 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(new Transaction(Transaction.ACTION_CLIENT_CLOSE)); 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 142a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 143f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void expectIOException() { 144f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mPairs.add(new Transaction(Transaction.ACTION_IO_EXCEPTION)); 145f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 146f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki 1471a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public void expectStartTls() { 1481a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mPairs.add(new Transaction(Transaction.ACTION_START_TLS)); 1491a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1501a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 151f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki private void sendResponse(Transaction pair) { 152f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki switch (pair.mAction) { 153f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_INJECT_TEXT: 154f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki for (String s : pair.mResponses) { 155f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(s); 156f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 157f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 158f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_IO_EXCEPTION: 159f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(SPECIAL_RESPONSE_IOEXCEPTION); 160f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 161f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki default: 162f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Assert.fail("Invalid action for sendResponse: " + pair.mAction); 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean canTrySslSecurity() { 167e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return (mConnectionSecurity == CONNECTION_SECURITY_SSL); 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 169a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean canTryTlsSecurity() { 171e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return (mConnectionSecurity == Transport.CONNECTION_SECURITY_TLS); 17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 173e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler 174e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler public boolean canTrustAllCertificates() { 175e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return mTrustCertificates; 176e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler } 177e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler 17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 1791a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler * Check that TLS was started 1801a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler */ 1811a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public boolean isTlsStarted() { 1821a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return mTlsStarted; 1831a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1841a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 1851a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler /** 186a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * This simulates a condition where the server has closed its side, causing 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * reads to fail. 18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void closeInputStream() { 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void close() { 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = false; 19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 19696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // unless it was expected as part of a test, reset the stream 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mPairs.size() > 0) { 19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction expect = mPairs.remove(0); 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (expect.mAction == Transaction.ACTION_CLIENT_CLOSE) { 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 20196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mQueuedInput.clear(); 20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.clear(); 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 207a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Override 208a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void setHost(String host) { 209cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler mHost = host; 210cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler } 211cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler 21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getHost() { 213cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler return mHost; 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 216be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public void setMockLocalAddress(InetAddress address) { 217be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler mLocalAddress = address; 218be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 219be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public InputStream getInputStream() { 22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockInputStream(); 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This normally serves as a pseudo-clone, for use by Imap. For the purposes of unit testing, 227a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * until we need something more complex, we'll just return the actual MockTransport. Then we 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * don't have to worry about dealing with test metadata like the expects list or socket state. 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Transport newInstanceWithConfiguration() { 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return this; 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public OutputStream getOutputStream() { 235af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki Assert.assertTrue(mOpen); 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockOutputStream(); 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 239a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Override 240a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void setPort(int port) { 241a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy SmtpSenderUnitTests.fail("setPort() not implemented"); 242a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy } 243a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getPort() { 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.fail("getPort() not implemented"); 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return 0; 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getSecurity() { 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mConnectionSecurity; 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 253a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Deprecated 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String[] getUserInfoParts() { 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.fail("getUserInfoParts() not implemented"); 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean isOpen() { 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mOpen; 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void open() /* throws MessagingException, CertificateValidationException */ { 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = true; 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = true; 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This returns one string (if available) to the caller. Usually this simply pulls strings 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * from the mQueuedInput list, but if the list is empty, we also peek the expect list. This 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * supports banners, multi-line responses, and any other cases where we respond without 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * a specific expect pattern. 273a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If no response text is available, we assert (failing our test) as an underflow. 275a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the read text if DEBUG_LOG_STREAMS is true. 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String readLine() throws IOException { 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // if there's nothing to read, see if we can find a null-pattern response 284f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if ((mQueuedInput.size() == 0) && (mPairs.size() > 0)) { 285f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Transaction pair = mPairs.get(0); 286f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mPattern == null) { 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.remove(0); 288f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 291f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (mQueuedInput.size() == 0) { 292f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki // MailTransport returns "" at EOS. 293f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Log.w(LOG_TAG, "Underflow reading from MockTransport"); 294f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return ""; 295f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String line = mQueuedInput.remove(0); 29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Log.d(LOG_TAG, "<<< " + line); 29996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 300f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (SPECIAL_RESPONSE_IOEXCEPTION.equals(line)) { 301f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 302f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return line; 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void reopenTls() /* throws MessagingException */ { 30796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 3081a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler Transaction expect = mPairs.remove(0); 3091a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler SmtpSenderUnitTests.assertTrue(expect.mAction == Transaction.ACTION_START_TLS); 3101a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mTlsStarted = true; 31196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 313e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler public void setSecurity(int connectionSecurity, boolean trustAllCertificates) { 31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mConnectionSecurity = connectionSecurity; 315e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler mTrustCertificates = trustAllCertificates; 31696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setSoTimeout(int timeoutMilliseconds) /* throws SocketException */ { 31996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 320a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 321a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Deprecated 32296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setUri(URI uri, int defaultPort) { 32396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue("Don't call setUri on a mock transport", false); 32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 32696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Accepts a single string (command or text) that was written by the code under test. 32896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Because we are essentially mocking a server, we check to see if this string was expected. 32996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If the string was expected, we push the corresponding responses into the mQueuedInput 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * list, for subsequent calls to readLine(). If the string does not match, we assert 33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the mismatch. If no string was expected, we assert it as an overflow. 332a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 33396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the written text if DEBUG_LOG_STREAMS is true. 33496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 335f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void writeLine(String s, String sensitiveReplacement) throws IOException { 33696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 33796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Log.d(LOG_TAG, ">>> " + s); 33896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 340af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki SmtpSenderUnitTests.assertTrue("Overflow writing to MockTransport: Getting " + s, 341af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 0 != mPairs.size()); 34296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = mPairs.remove(0); 343f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mAction == Transaction.ACTION_IO_EXCEPTION) { 344f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 345f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 346af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki SmtpSenderUnitTests.assertTrue("Unexpected string written to MockTransport: Actual=" + s 347af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki + " Expected=" + pair.mPattern, 34896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project pair.mPattern != null && s.matches(pair.mPattern)); 34996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (pair.mResponses != null) { 350f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 35196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 353a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 35496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 35596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an InputStream that satisfies the needs of getInputStream() 35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockInputStream extends InputStream { 35896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte[] mNextLine = null; 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int mNextIndex = 0; 361a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 36296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 36396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Reads from the same input buffer as readLine() 36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 36696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int read() throws IOException { 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException(); 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 370a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 374a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // previous line was exhausted so try to get another one 37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String next = readLine(); 37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (next == null) { 37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextLine = (next + "\r\n").getBytes(); 38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextIndex = 0; 38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 386a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 387a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki // no joy - throw an exception 388a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki throw new IOException(); 38996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 39096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 391a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 39296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 39396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an OutputStream that satisfies the needs of getOutputStream() 39496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 39596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockOutputStream extends OutputStream { 39696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 39796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuilder sb = new StringBuilder(); 39896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 400f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void write(int oneByte) throws IOException { 401c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // CR or CRLF will immediately dump previous line (w/o CRLF) 402c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler if (oneByte == '\r') { 403c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler writeLine(sb.toString(), null); 404c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler sb = new StringBuilder(); 405c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else if (oneByte == '\n') { 406c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // swallow it 407c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else { 40896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append((char)oneByte); 40996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 412be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 413be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public InetAddress getLocalAddress() { 414be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler if (isOpen()) { 415be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return mLocalAddress; 416be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } else { 417be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return null; 418be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 419be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 420a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy} 421