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.util.ArrayList; 2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Arrays; 29af6724527e564d35dd27ac35e24dbced554792e5Makoto Onukiimport java.util.regex.Pattern; 30af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 31af6724527e564d35dd27ac35e24dbced554792e5Makoto Onukiimport junit.framework.Assert; 3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/** 3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a mock Transport that is used to test protocols that use MailTransport. 3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MockTransport implements Transport { 3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // All flags defining debug or development code settings must be FALSE 3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // when code is checked in or released. 4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static boolean DEBUG_LOG_STREAMS = true; 41a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static String LOG_TAG = "MockTransport"; 4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 44f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki private static final String SPECIAL_RESPONSE_IOEXCEPTION = "!!!IOEXCEPTION!!!"; 45f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki 461a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler private boolean mTlsStarted = false; 47a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private boolean mOpen; 4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private boolean mInputOpen; 5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private int mConnectionSecurity; 51e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler private boolean mTrustCertificates; 52cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler private String mHost; 53be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler private InetAddress mLocalAddress; 54be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<String> mQueuedInput = new ArrayList<String>(); 56be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 5796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static class Transaction { 5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final int ACTION_INJECT_TEXT = 0; 59f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_CLIENT_CLOSE = 1; 60f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public static final int ACTION_IO_EXCEPTION = 2; 611a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public static final int ACTION_START_TLS = 3; 62a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int mAction; 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String mPattern; 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] mResponses; 66a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(String pattern, String[] responses) { 6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = ACTION_INJECT_TEXT; 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = pattern; 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = responses; 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 72a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction(int otherType) { 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mAction = otherType; 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPattern = null; 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mResponses = null; 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 78a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String toString() { 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project switch (mAction) { 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_INJECT_TEXT: 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mPattern + ": " + Arrays.toString(mResponses); 8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project case ACTION_CLIENT_CLOSE: 8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "Expect the client to close"; 86f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case ACTION_IO_EXCEPTION: 87f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return "Expect IOException"; 881a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler case ACTION_START_TLS: 891a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return "Expect StartTls"; 9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project default: 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "(Hmm. Unknown action.)"; 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 95a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private ArrayList<Transaction> mPairs = new ArrayList<Transaction>(); 97c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 98c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler /** 99c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * Give the mock a pattern to wait for. No response will be sent. 100c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * @param pattern Java RegEx to wait for 101c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler */ 102c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler public void expect(String pattern) { 103c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler expect(pattern, (String[])null); 104c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } 105c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a response to send back. 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param response String to reply with, or null to acccept string but not respond to it 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String response) { 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(pattern, (response == null) ? null : new String[] { response }); 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 114a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Give the mock a pattern to wait for and a multi-line response to send back. 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param pattern Java RegEx to wait for 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param responses Strings to reply with 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expect(String pattern, String[] responses) { 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = new Transaction(pattern, responses); 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(pair); 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 124af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 125af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki /** 126af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * Same as {@link #expect(String, String[])}, but the first arg is taken literally, rather than 127af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki * as a regexp. 128af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki */ 129af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki public void expectLiterally(String literal, String[] responses) { 130af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki expect("^" + Pattern.quote(literal) + "$", responses); 131af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki } 132af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 133a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki /** 13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Tell the Mock Transport that we expect it to be closed. This will preserve 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the remaining entries in the expect() stream and allow us to "ride over" the close (which 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * would normally reset everything). 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void expectClose() { 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.add(new Transaction(Transaction.ACTION_CLIENT_CLOSE)); 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 141a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 142f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void expectIOException() { 143f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mPairs.add(new Transaction(Transaction.ACTION_IO_EXCEPTION)); 144f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 145f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki 1461a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public void expectStartTls() { 1471a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mPairs.add(new Transaction(Transaction.ACTION_START_TLS)); 1481a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1491a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 150f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki private void sendResponse(Transaction pair) { 151f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki switch (pair.mAction) { 152f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_INJECT_TEXT: 153f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki for (String s : pair.mResponses) { 154f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(s); 155f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 156f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 157f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki case Transaction.ACTION_IO_EXCEPTION: 158f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki mQueuedInput.add(SPECIAL_RESPONSE_IOEXCEPTION); 159f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki break; 160f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki default: 161f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Assert.fail("Invalid action for sendResponse: " + pair.mAction); 16296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 165e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean canTrySslSecurity() { 167e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return (mConnectionSecurity == CONNECTION_SECURITY_SSL); 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 169a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 170e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean canTryTlsSecurity() { 172e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return (mConnectionSecurity == Transport.CONNECTION_SECURITY_TLS); 17396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 174e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler 175e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 176e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler public boolean canTrustAllCertificates() { 177e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler return mTrustCertificates; 178e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler } 179e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler 18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 1811a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler * Check that TLS was started 1821a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler */ 1831a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler public boolean isTlsStarted() { 1841a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler return mTlsStarted; 1851a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler } 1861a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler 1871a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler /** 188a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * This simulates a condition where the server has closed its side, causing 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * reads to fail. 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void closeInputStream() { 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 195ebece4dbdcdfee85a410a0d00c9b6739ee3e705eTodd Kennedy @Override 19696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void close() { 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = false; 19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = false; 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // unless it was expected as part of a test, reset the stream 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mPairs.size() > 0) { 20196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction expect = mPairs.remove(0); 20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (expect.mAction == Transaction.ACTION_CLIENT_CLOSE) { 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return; 20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mQueuedInput.clear(); 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.clear(); 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 210a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Override 211a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void setHost(String host) { 212cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler mHost = host; 213cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler } 214cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler 215e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getHost() { 217cb95fbe13554ee6b4e46d9fd3bcd983e09a688cbAndrew Stadler return mHost; 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 220be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public void setMockLocalAddress(InetAddress address) { 221be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler mLocalAddress = address; 222be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 223be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 224e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public InputStream getInputStream() { 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockInputStream(); 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This normally serves as a pseudo-clone, for use by Imap. For the purposes of unit testing, 232a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * until we need something more complex, we'll just return the actual MockTransport. Then we 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * don't have to worry about dealing with test metadata like the expects list or socket state. 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 235e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 236ebece4dbdcdfee85a410a0d00c9b6739ee3e705eTodd Kennedy public Transport clone() { 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return this; 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 240e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public OutputStream getOutputStream() { 242af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki Assert.assertTrue(mOpen); 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new MockOutputStream(); 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 246a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy @Override 247a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy public void setPort(int port) { 248a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy SmtpSenderUnitTests.fail("setPort() not implemented"); 249a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy } 250a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy 251e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getPort() { 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.fail("getPort() not implemented"); 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return 0; 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 257e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getSecurity() { 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mConnectionSecurity; 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 262e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean isOpen() { 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mOpen; 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 267e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void open() /* throws MessagingException, CertificateValidationException */ { 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mOpen = true; 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mInputOpen = true; 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This returns one string (if available) to the caller. Usually this simply pulls strings 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * from the mQueuedInput list, but if the list is empty, we also peek the expect list. This 27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * supports banners, multi-line responses, and any other cases where we respond without 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * a specific expect pattern. 278a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If no response text is available, we assert (failing our test) as an underflow. 280a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the read text if DEBUG_LOG_STREAMS is true. 28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 283e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 28496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String readLine() throws IOException { 28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // if there's nothing to read, see if we can find a null-pattern response 290f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if ((mQueuedInput.size() == 0) && (mPairs.size() > 0)) { 291f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Transaction pair = mPairs.get(0); 292f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mPattern == null) { 29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mPairs.remove(0); 294f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 29596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 297f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (mQueuedInput.size() == 0) { 298f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki // MailTransport returns "" at EOS. 299f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki Log.w(LOG_TAG, "Underflow reading from MockTransport"); 300f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki return ""; 301f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 30296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String line = mQueuedInput.remove(0); 30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Log.d(LOG_TAG, "<<< " + line); 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 306f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (SPECIAL_RESPONSE_IOEXCEPTION.equals(line)) { 307f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 308f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return line; 31096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 312e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 31396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void reopenTls() /* throws MessagingException */ { 31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 3151a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler Transaction expect = mPairs.remove(0); 3161a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler SmtpSenderUnitTests.assertTrue(expect.mAction == Transaction.ACTION_START_TLS); 3171a791e675ba5092569125bf09a9fcc721bd4c5e1Andy Stadler mTlsStarted = true; 31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 320e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 321e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler public void setSecurity(int connectionSecurity, boolean trustAllCertificates) { 32296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mConnectionSecurity = connectionSecurity; 323e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler mTrustCertificates = trustAllCertificates; 32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 326ebece4dbdcdfee85a410a0d00c9b6739ee3e705eTodd Kennedy @Override 32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setSoTimeout(int timeoutMilliseconds) /* throws SocketException */ { 32896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 329a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Accepts a single string (command or text) that was written by the code under test. 33296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Because we are essentially mocking a server, we check to see if this string was expected. 33396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * If the string was expected, we push the corresponding responses into the mQueuedInput 33496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * list, for subsequent calls to readLine(). If the string does not match, we assert 33596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the mismatch. If no string was expected, we assert it as an overflow. 336a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki * 33796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Logs the written text if DEBUG_LOG_STREAMS is true. 33896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 339e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 340f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void writeLine(String s, String sensitiveReplacement) throws IOException { 34196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (DEBUG_LOG_STREAMS) { 34296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Log.d(LOG_TAG, ">>> " + s); 34396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 34496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project SmtpSenderUnitTests.assertTrue(mOpen); 345af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki SmtpSenderUnitTests.assertTrue("Overflow writing to MockTransport: Getting " + s, 346af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki 0 != mPairs.size()); 34796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Transaction pair = mPairs.remove(0); 348f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki if (pair.mAction == Transaction.ACTION_IO_EXCEPTION) { 349f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki throw new IOException("Expected IOException."); 350f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki } 351af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki SmtpSenderUnitTests.assertTrue("Unexpected string written to MockTransport: Actual=" + s 352af6724527e564d35dd27ac35e24dbced554792e5Makoto Onuki + " Expected=" + pair.mPattern, 35396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project pair.mPattern != null && s.matches(pair.mPattern)); 35496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (pair.mResponses != null) { 355f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki sendResponse(pair); 35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 358a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an InputStream that satisfies the needs of getInputStream() 36196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 36296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockInputStream extends InputStream { 36396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 364e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private byte[] mNextLine = null; 365e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private int mNextIndex = 0; 366a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Reads from the same input buffer as readLine() 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int read() throws IOException { 37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!mInputOpen) { 37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException(); 37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 375a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 379a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // previous line was exhausted so try to get another one 38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String next = readLine(); 38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (next == null) { 38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IOException("Reading from MockTransport with closed input"); 38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextLine = (next + "\r\n").getBytes(); 38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mNextIndex = 0; 38796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 38896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mNextLine != null && mNextIndex < mNextLine.length) { 38996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mNextLine[mNextIndex++]; 39096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 391a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 392a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki // no joy - throw an exception 393a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki throw new IOException(); 39496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 39596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 396a599ee773d3bb6350ca775db717123faffbdbfe3Makoto Onuki 39796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 39896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is an OutputStream that satisfies the needs of getOutputStream() 39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 40096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private class MockOutputStream extends OutputStream { 40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 402e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy private StringBuilder sb = new StringBuilder(); 40396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 40496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 405f255081a85bd1680c6a2d2b7225aa45cd104cb66Makoto Onuki public void write(int oneByte) throws IOException { 406c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // CR or CRLF will immediately dump previous line (w/o CRLF) 407c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler if (oneByte == '\r') { 408c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler writeLine(sb.toString(), null); 409c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler sb = new StringBuilder(); 410c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else if (oneByte == '\n') { 411c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler // swallow it 412c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler } else { 41396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append((char)oneByte); 41496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 417be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler 418e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy @Override 419be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler public InetAddress getLocalAddress() { 420be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler if (isOpen()) { 421be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return mLocalAddress; 422be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } else { 423be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler return null; 424be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 425be2ef97220619a3acf6c3dd4eb4b8add26ff452aAndy Stadler } 426a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy} 427