blob: 4ab4ec2d4fdb89912cb7288e1ce7bb935c5edd88 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.connecteddevice.transport.spp;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothSocket;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.shadow.api.Shadow;
@RunWith(AndroidJUnit4.class)
public class ReadMessageTaskTest {
private static final int TESTED_MESSAGE_SPLITS = 3;
private final byte[] testData1 = "data1".getBytes(UTF_8);
private final byte[] testData2 = "testData2".getBytes(UTF_8);
private final byte[] completedEmptyTestMessage = new byte[18];
private final int messageSplitLength = completedEmptyTestMessage.length / TESTED_MESSAGE_SPLITS;
private ReadMessageTask readMessageTask;
private Executor executor;
private final Executor callbackExecutor = directExecutor();
private final BluetoothSocket shadowBluetoothSocket = Shadow.newInstanceOf(BluetoothSocket.class);
@Mock private ReadMessageTask.Callback mockCallback;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Before
public void setUp() throws IOException {
readMessageTask =
new ReadMessageTask(shadowBluetoothSocket.getInputStream(), mockCallback, callbackExecutor);
executor = Executors.newSingleThreadExecutor();
}
@Test
public void testRun_oneMessage_informCallback() throws IOException {
shadowOf(shadowBluetoothSocket)
.getInputStreamFeeder()
.write(SppManager.wrapWithArrayLength(testData1));
executor.execute(readMessageTask);
verify(mockCallback, timeout(1000)).onMessageReceived(testData1);
}
@Test
public void testRun_twoCombinedMessage_informCallback() throws IOException {
shadowOf(shadowBluetoothSocket)
.getInputStreamFeeder()
.write(SppManager.wrapWithArrayLength(testData1));
shadowOf(shadowBluetoothSocket)
.getInputStreamFeeder()
.write(SppManager.wrapWithArrayLength(testData2));
executor.execute(readMessageTask);
verify(mockCallback, timeout(1000)).onMessageReceived(testData1);
verify(mockCallback, timeout(1000)).onMessageReceived(testData2);
}
@Test
public void testReadData_splittedMessages_readSuccessfully(){
FakeInputStream fakeInputStream = new FakeInputStream(messageSplitLength);
assertThat(readMessageTask.readData(fakeInputStream, completedEmptyTestMessage)).isTrue();
assertThat(fakeInputStream.methodCalls).isEqualTo(TESTED_MESSAGE_SPLITS);
}
@Test
public void testCancel_stopReadingMessage() throws IOException{
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(readMessageTask);
readMessageTask.cancel();
shadowOf(shadowBluetoothSocket).getInputStreamFeeder().write(testData1);
verify(mockCallback, timeout(1000).times(0)).onMessageReceived(testData1);
}
@Test
public void testRun_onMessageReadError() throws IOException{
ExecutorService executor = Executors.newSingleThreadExecutor();
shadowOf(shadowBluetoothSocket).getInputStreamFeeder().close();
executor.execute(readMessageTask);
verify(mockCallback, timeout(1000)).onMessageReadError();
}
/**
* Fake input stream that can track the number of [read] method calls and should only be used in
* test.
*/
private static class FakeInputStream extends InputStream {
int methodCalls = 0;
int messageSplitLength = 0;
public FakeInputStream(int messageSplitLength) {
this.messageSplitLength = messageSplitLength;
}
@Override
public int read(byte[] b, int off, int len) {
methodCalls++;
return messageSplitLength;
}
@Override
public int read() {
return 0;
}
}
}