1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.internal.telephony.imsphone; 18 19 import android.os.HandlerThread; 20 import android.os.ParcelFileDescriptor; 21 import android.support.test.filters.FlakyTest; 22 import android.telecom.Connection; 23 24 import com.android.internal.telephony.TelephonyTest; 25 26 import org.junit.After; 27 import org.junit.Assert; 28 import org.junit.Before; 29 import org.junit.ComparisonFailure; 30 import org.junit.Test; 31 32 import java.io.IOException; 33 import java.io.InputStreamReader; 34 import java.io.OutputStreamWriter; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.TimeUnit; 37 38 public class ImsRttTextHandlerTest extends TelephonyTest { 39 private static final int TEST_TIMEOUT = 1000; 40 private static final int READ_BUFFER_SIZE = 1000; 41 private static final String LONG_TEXT = "No Soldier shall, in time of peace be quartered in " + 42 "any house, without the consent of the Owner, nor in time of war, but in a manner to " + 43 "be prescribed by law."; 44 45 char[] buffer = new char[READ_BUFFER_SIZE]; 46 47 public class MockNetworkWriter implements ImsRttTextHandler.NetworkWriter { 48 private String totalWritten = ""; 49 private int numWrites = 0; 50 51 @Override 52 public synchronized void write(String s) { 53 totalWritten += s; 54 numWrites += 1; 55 } 56 57 public synchronized void reset() { 58 totalWritten = ""; 59 numWrites = 0; 60 } 61 62 public synchronized String getContents() { 63 return totalWritten; 64 } 65 66 public synchronized int getNumWrites() { 67 return numWrites; 68 } 69 } 70 71 Connection.RttTextStream mRttTextStream; 72 MockNetworkWriter mNetworkWriter = new MockNetworkWriter(); 73 ImsRttTextHandler mRttTextHandler; 74 HandlerThread mHandlerThread; 75 76 OutputStreamWriter mPipeToHandler; 77 InputStreamReader mPipeFromHandler; 78 InputStreamReader mHandlerSideOfPipeToHandler; 79 80 @Before 81 public void setUp() throws Exception { 82 super.setUp(getClass().getSimpleName()); 83 mNetworkWriter.reset(); 84 mHandlerThread = new HandlerThread("TestImsRttTextHandler"); 85 mHandlerThread.start(); 86 mRttTextHandler = new ImsRttTextHandler(mHandlerThread.getLooper(), mNetworkWriter); 87 88 // Construct some pipes to use 89 ParcelFileDescriptor[] toTextHandler = ParcelFileDescriptor.createReliablePipe(); 90 ParcelFileDescriptor[] fromTextHandler = ParcelFileDescriptor.createReliablePipe(); 91 mRttTextStream = new Connection.RttTextStream(fromTextHandler[1],toTextHandler[0]); 92 93 mRttTextHandler.initialize(mRttTextStream); 94 95 mPipeFromHandler = new InputStreamReader( 96 new ParcelFileDescriptor.AutoCloseInputStream(fromTextHandler[0])); 97 mPipeToHandler = new OutputStreamWriter( 98 new ParcelFileDescriptor.AutoCloseOutputStream(toTextHandler[1])); 99 mHandlerSideOfPipeToHandler = new InputStreamReader( 100 new ParcelFileDescriptor.AutoCloseInputStream(toTextHandler[1])); 101 } 102 103 /** 104 * Test that the text handler won't send characters before a timeout or enough characters 105 * have accumulated. 106 */ 107 @Test 108 public void testProperCharacterBuffering() throws Exception { 109 // Send four characters 110 mPipeToHandler.write("abcd"); 111 mPipeToHandler.flush(); 112 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 113 // make sure at it hasn't been sent. 114 Assert.assertEquals("", mNetworkWriter.getContents()); 115 // Wait for 300ms 116 waitForHandlerActionDelayed(mRttTextHandler, TEST_TIMEOUT, 117 ImsRttTextHandler.MAX_BUFFERING_DELAY_MILLIS + 100); 118 // make sure that it has been sent and check that it's correct 119 Assert.assertEquals("abcd", mNetworkWriter.getContents()); 120 } 121 122 /** 123 * Test that the text handler sends after enough characters have been sent from in-call 124 * @throws Exception 125 */ 126 @FlakyTest 127 @Test 128 public void testSendAfterEnoughChars() throws Exception { 129 // Register a read notifier 130 CountDownLatch readNotifier = new CountDownLatch(1); 131 mRttTextHandler.setReadNotifier(readNotifier); 132 // Send four characters 133 mPipeToHandler.write("abcd"); 134 mPipeToHandler.flush(); 135 // Wait for the stream to consume the characters 136 readNotifier.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 137 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 138 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 139 // make sure at it hasn't been sent. 140 Assert.assertEquals("", mNetworkWriter.getContents()); 141 142 // Send the second part 143 Thread.sleep(10); 144 // Register a read notifier 145 readNotifier = new CountDownLatch(1); 146 mRttTextHandler.setReadNotifier(readNotifier); 147 // Send four more characters 148 mPipeToHandler.write("efgh"); 149 mPipeToHandler.flush(); 150 // Wait for the stream to consume the characters 151 boolean res = readNotifier.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 152 // Wait for the handler to write to the mock network writer 153 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 154 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 155 // make sure that all characters were sent. 156 try { 157 Assert.assertEquals("abcdefgh", mNetworkWriter.getContents()); 158 } catch (ComparisonFailure e) { 159 throw new ComparisonFailure(e.getMessage() 160 + ", network buffer=" + mRttTextHandler.getNetworkBufferText() 161 + ", res=" + res, 162 e.getExpected(), e.getActual()); 163 } 164 } 165 166 /** 167 * Test that the text handler sends its characters as a batch after enough of them have been 168 * buffered. 169 * @throws Exception 170 */ 171 @Test 172 public void testBufferedCharactersSentAsBatch() throws Exception { 173 // Send 5 characters, one at a time, pausing for 10ms between each one. 174 char[] characters = new char[] {'a', 'b', 'c', 'd', 'e'}; 175 for (char c : characters) { 176 mPipeToHandler.write(String.valueOf(c)); 177 mPipeToHandler.flush(); 178 Thread.sleep(10); 179 } 180 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 181 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 182 183 // Make sure that the ordering is correct and that there was only one write 184 Assert.assertEquals("abcde", mNetworkWriter.getContents()); 185 Assert.assertEquals(1, mNetworkWriter.getNumWrites()); 186 } 187 188 @Test 189 public void testProperThrottling() throws Exception { 190 // Send a lot of characters in rapid succession, 3 at a time 191 char[] characters = LONG_TEXT.toCharArray(); 192 for (int i = 0; i < characters.length; i += 3) { 193 String toSend = new String(characters, i, Math.min(3, characters.length - i)); 194 mPipeToHandler.write(toSend); 195 mPipeToHandler.flush(); 196 Thread.sleep(10); 197 } 198 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 199 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 200 201 // Wait one second and see how many characters are sent in that time. 202 int numCharsSoFar = mNetworkWriter.getContents().length(); 203 Thread.sleep(1000); 204 int numCharsInOneSec = mNetworkWriter.getContents().length() - numCharsSoFar; 205 Assert.assertTrue(numCharsInOneSec <= ImsRttTextHandler.MAX_CODEPOINTS_PER_SECOND); 206 207 // Wait 5 seconds for all the chars to make it through 208 Thread.sleep(5000); 209 Assert.assertEquals(LONG_TEXT, mNetworkWriter.getContents()); 210 } 211 212 @Test 213 public void testProperTransmissionFromNetworkToInCall() throws Exception { 214 // Make sure that nothing is in the pipe from the network to incall (us) 215 Assert.assertFalse(mPipeFromHandler.ready()); 216 // Send a chunk of text 217 mRttTextHandler.sendToInCall(LONG_TEXT); 218 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 219 // Make sure we get it immediately 220 Assert.assertEquals(LONG_TEXT, readAll(mPipeFromHandler)); 221 } 222 223 @After 224 public void tearDown() throws Exception { 225 mPipeFromHandler.close(); 226 mPipeToHandler.close(); 227 mRttTextHandler.tearDown(); 228 waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT); 229 mHandlerThread.quit(); 230 super.tearDown(); 231 } 232 233 private String readAll(InputStreamReader inputStreamReader) throws IOException { 234 if (!inputStreamReader.ready()) { 235 return null; 236 } 237 int len = inputStreamReader.read(buffer, 0, READ_BUFFER_SIZE); 238 return new String(buffer, 0, len); 239 } 240 } 241