Home | History | Annotate | Download | only in imsphone
      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