blob: 882bf9d56022d34d6e05b7bf194b06b58bad864c [file] [log] [blame]
package com.android.networkstack.tethering.companionproxy.protocol;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.ignoreStubs;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.os.ParcelFileDescriptor;
import com.android.networkstack.tethering.companionproxy.io.AsyncFile;
import com.android.networkstack.tethering.companionproxy.io.BufferedFile;
import com.android.networkstack.tethering.companionproxy.io.EventManager;
import com.android.networkstack.tethering.companionproxy.io.FileHandle;
import com.android.networkstack.tethering.companionproxy.io.ReadableDataAnswer;
import com.android.networkstack.tethering.companionproxy.util.ReadableByteBuffer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class StreamingPacketFileTest {
private static final int MAX_PACKET_SIZE = 100;
@Mock EventManager mockEventManager;
@Mock PacketFile.Listener mockFileListener;
@Mock AsyncFile mockAsyncFile;
@Mock ParcelFileDescriptor mockParcelFileDescriptor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@After
public void tearDown() throws Exception {
verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager));
}
@Test
public void continueReadingAndClose() throws Exception {
final int maxBufferedInboundPackets = 3;
final int maxBufferedOutboundPackets = 5;
final StreamingPacketFile file =
createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets);
final BufferedFile bufferedFile = file.getUnderlyingFileForTest();
assertEquals(maxBufferedInboundPackets * (MAX_PACKET_SIZE + 2),
bufferedFile.getInboundBufferFreeSizeForTest());
assertEquals(maxBufferedOutboundPackets * (MAX_PACKET_SIZE + 2),
bufferedFile.getOutboundBufferFreeSize());
assertEquals(bufferedFile.getOutboundBufferFreeSize() - 2,
file.getOutboundFreeSize());
file.continueReading();
verify(mockAsyncFile).enableReadEvents(true);
file.close();
verify(mockAsyncFile).close();
}
@Test
public void enqueueOutboundPacket() throws Exception {
final int maxBufferedInboundPackets = 10;
final int maxBufferedOutboundPackets = 20;
final StreamingPacketFile file =
createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets);
final BufferedFile bufferedFile = file.getUnderlyingFileForTest();
final byte[] packet1 = new byte[11];
final byte[] packet2 = new byte[12];
packet1[0] = (byte) 1;
packet2[0] = (byte) 2;
assertEquals(0, bufferedFile.getOutboundBufferSize());
when(mockAsyncFile.write(any(), anyInt(), anyInt())).thenReturn(0);
assertTrue(file.enqueueOutboundPacket(packet1, 0, packet1.length));
verify(mockAsyncFile).enableWriteEvents(true);
assertEquals(packet1.length + 2, bufferedFile.getOutboundBufferSize());
checkAndResetMocks();
final int totalLen = packet1.length + packet2.length + 4;
final ArgumentCaptor<byte[]> arrayCaptor = ArgumentCaptor.forClass(byte[].class);
final ArgumentCaptor<Integer> posCaptor = ArgumentCaptor.forClass(Integer.class);
final ArgumentCaptor<Integer> lenCaptor = ArgumentCaptor.forClass(Integer.class);
when(mockAsyncFile.write(
arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture())).thenReturn(totalLen);
assertTrue(file.enqueueOutboundPacket(packet2, 0, packet2.length));
assertEquals(0, bufferedFile.getInboundBuffer().size());
assertEquals(0, bufferedFile.getOutboundBufferSize());
assertEquals(0, posCaptor.getValue().intValue());
assertEquals(totalLen, lenCaptor.getValue().intValue());
final byte[] capturedData = arrayCaptor.getValue();
assertEquals(packet1.length, NetUtils.decodeNetworkUnsignedInt16(capturedData, 0));
assertEquals(packet2.length,
NetUtils.decodeNetworkUnsignedInt16(capturedData, packet1.length + 2));
assertEquals(packet1[0], capturedData[2]);
assertEquals(packet2[0], capturedData[packet1.length + 4]);
}
@Test
public void onInboundPacket() throws Exception {
final int maxBufferedInboundPackets = 10;
final int maxBufferedOutboundPackets = 20;
final StreamingPacketFile file =
createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets);
final BufferedFile bufferedFile = file.getUnderlyingFileForTest();
final ReadableByteBuffer inboundBuffer = bufferedFile.getInboundBuffer();
final int len1 = 11;
final int len2 = 12;
final byte[] data = new byte[len1 + len2 + 4];
NetUtils.encodeNetworkUnsignedInt16(len1, data, 0);
NetUtils.encodeNetworkUnsignedInt16(len2, data, 11 + 2);
data[2] = (byte) 1;
data[len1 + 4] = (byte) 2;
final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data);
final ArgumentCaptor<byte[]> arrayCaptor = ArgumentCaptor.forClass(byte[].class);
final ArgumentCaptor<Integer> posCaptor = ArgumentCaptor.forClass(Integer.class);
final ArgumentCaptor<Integer> lenCaptor = ArgumentCaptor.forClass(Integer.class);
when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer);
when(mockFileListener.onPreambleData(any(), eq(0), eq(data.length))).thenReturn(0);
bufferedFile.onReadReady(mockAsyncFile);
verify(mockAsyncFile).enableReadEvents(true);
verify(mockFileListener).onInboundBuffered(data.length, data.length);
verify(mockFileListener).onInboundPacket(
arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture());
verify(mockEventManager).execute(any());
byte[] capturedData = arrayCaptor.getValue();
assertEquals(2, posCaptor.getValue().intValue());
assertEquals(len1, lenCaptor.getValue().intValue());
assertEquals((byte) 1, capturedData[2]);
checkAndResetMocks();
when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer);
file.onBufferedFileInboundData(0);
verify(mockFileListener).onInboundPacket(
arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture());
verify(mockEventManager).execute(any());
capturedData = arrayCaptor.getValue();
assertEquals(2, posCaptor.getValue().intValue());
assertEquals(len2, lenCaptor.getValue().intValue());
assertEquals((byte) 2, capturedData[2]);
assertEquals(0, bufferedFile.getOutboundBufferSize());
assertEquals(0, inboundBuffer.size());
}
@Test
public void onReadReady_preambleData() throws Exception {
final int maxBufferedInboundPackets = 10;
final int maxBufferedOutboundPackets = 20;
final StreamingPacketFile file =
createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets);
final BufferedFile bufferedFile = file.getUnderlyingFileForTest();
final ReadableByteBuffer inboundBuffer = bufferedFile.getInboundBuffer();
final int preambleLen = 23;
final int len1 = 11;
final byte[] data = new byte[preambleLen + 2 + len1];
NetUtils.encodeNetworkUnsignedInt16(len1, data, preambleLen);
data[preambleLen + 2] = (byte) 1;
final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data);
when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer);
when(mockFileListener.onPreambleData(any(), eq(0), eq(data.length))).thenReturn(5);
when(mockFileListener.onPreambleData(
any(), eq(0), eq(data.length - 5))).thenReturn(preambleLen - 5);
when(mockFileListener.onPreambleData(
any(), eq(0), eq(data.length - preambleLen))).thenReturn(0);
bufferedFile.onReadReady(mockAsyncFile);
final ArgumentCaptor<byte[]> arrayCaptor = ArgumentCaptor.forClass(byte[].class);
final ArgumentCaptor<Integer> posCaptor = ArgumentCaptor.forClass(Integer.class);
final ArgumentCaptor<Integer> lenCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mockFileListener).onInboundBuffered(data.length, data.length);
verify(mockFileListener).onInboundPacket(
arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture());
verify(mockEventManager).execute(any());
verify(mockAsyncFile).enableReadEvents(true);
final byte[] capturedData = arrayCaptor.getValue();
assertEquals(2, posCaptor.getValue().intValue());
assertEquals(len1, lenCaptor.getValue().intValue());
assertEquals((byte) 1, capturedData[2]);
assertEquals(0, bufferedFile.getOutboundBufferSize());
assertEquals(0, inboundBuffer.size());
}
@Test
public void shutdownReading() throws Exception {
final int maxBufferedInboundPackets = 10;
final int maxBufferedOutboundPackets = 20;
final StreamingPacketFile file =
createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets);
final BufferedFile bufferedFile = file.getUnderlyingFileForTest();
final byte[] data = new byte[100];
final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data);
when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer);
doAnswer(new Answer() {
@Override public Object answer(InvocationOnMock invocation) {
file.shutdownReading();
return Integer.valueOf(-1);
}}).when(mockFileListener).onPreambleData(any(), anyInt(), anyInt());
bufferedFile.onReadReady(mockAsyncFile);
verify(mockFileListener).onInboundBuffered(data.length, data.length);
verify(mockAsyncFile).enableReadEvents(false);
assertEquals(0, bufferedFile.getInboundBuffer().size());
}
private void checkAndResetMocks() {
verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager,
mockParcelFileDescriptor));
reset(mockFileListener, mockAsyncFile, mockEventManager);
}
private StreamingPacketFile createFile(
int maxBufferedInboundPackets, int maxBufferedOutboundPackets) throws Exception {
when(mockEventManager.registerFile(any(), any())).thenReturn(mockAsyncFile);
return new StreamingPacketFile(
mockEventManager,
FileHandle.fromFileDescriptor(mockParcelFileDescriptor),
mockFileListener,
MAX_PACKET_SIZE,
maxBufferedInboundPackets,
maxBufferedOutboundPackets);
}
}