/* * MIT License * * Copyright (c) 2017 Inova IT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package si.inova.neatle.operation; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.os.Build; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.UUID; import si.inova.neatle.BuildConfig; import si.inova.neatle.Device; import si.inova.neatle.Neatle; import static junit.framework.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.N_MR1) public class SubscribeCommandTest { private UUID serviceUUID = Neatle.createUUID(1); private UUID characteristicUUID = Neatle.createUUID(2); private UUID clientCharacteristicConfig = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); @Mock private CommandObserver commandObserver; @Mock private CommandObserver operationCommandObserver; @Mock private BluetoothGatt gatt; @Mock private Device device; @Mock private BluetoothGattService gattService; @Mock private BluetoothGattCharacteristic gattCharacteristic; @Mock private BluetoothGattDescriptor gattDescriptor; private SubscribeCommand subscribeCommand; @Before public void setUp() { MockitoAnnotations.initMocks(this); subscribeCommand = new SubscribeCommand( SubscribeCommand.Type.SUBSCRIBE_NOTIFICATION, serviceUUID, characteristicUUID, commandObserver); } @Test public void testServiceNotFound() { when(gatt.getService(eq(serviceUUID))).thenReturn(null); subscribeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(subscribeCommand, Command.SERVICE_NOT_FOUND); } @Test public void testCharacteristicNotFound() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); subscribeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(subscribeCommand, Command.CHARACTERISTIC_NOT_FOUND); } @Test public void testDescriptorNotFound() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gattCharacteristic.getDescriptor(eq(clientCharacteristicConfig))).thenReturn(null); subscribeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(subscribeCommand, Command.DESCRIPTOR_NOT_FOUND); } @Test public void testSubscribeNotificationSuccess() { when(gattDescriptor.getValue()).thenReturn(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); checkCommandSuccess(SubscribeCommand.Type.SUBSCRIBE_NOTIFICATION); } @Test public void testSubscribeIndicationSuccess() { when(gattDescriptor.getValue()).thenReturn(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); checkCommandSuccess(SubscribeCommand.Type.SUBSCRIBE_INDICATION); } @Test public void testUnsubscribeSuccess() { when(gattDescriptor.getValue()).thenReturn(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); checkCommandSuccess(SubscribeCommand.Type.UNSUBSCRIBE); } @Test public void testCharacteristicNotificationFail() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gattCharacteristic.getDescriptor(eq(clientCharacteristicConfig))).thenReturn(gattDescriptor); when(gatt.setCharacteristicNotification(Mockito.eq(gattCharacteristic), Mockito.anyBoolean())).thenReturn(false); subscribeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(subscribeCommand, BluetoothGatt.GATT_FAILURE); } @Test public void testUnsubscribeWithListeners() { when(device.getCharacteristicsChangedListenerCount(characteristicUUID)).thenReturn(1); subscribeCommand = new SubscribeCommand( SubscribeCommand.Type.UNSUBSCRIBE, serviceUUID, characteristicUUID, commandObserver); subscribeCommand.execute(device, operationCommandObserver, gatt); CommandResult result = CommandResult.createEmptySuccess(characteristicUUID); verify(commandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); } @Test public void testWriteDescriptorFail() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gattCharacteristic.getDescriptor(eq(clientCharacteristicConfig))).thenReturn(gattDescriptor); when(gatt.setCharacteristicNotification(Mockito.eq(gattCharacteristic), Mockito.anyBoolean())).thenReturn(true); when(gatt.writeDescriptor(gattDescriptor)).thenReturn(false); subscribeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(subscribeCommand, BluetoothGatt.GATT_FAILURE); } @Test public void testWriteDescriptorSuccess() { setupDescriptorSuccess(); subscribeCommand.execute(device, operationCommandObserver, gatt); verify(commandObserver, times(0)).finished(Mockito.any(Command.class), Mockito.any(CommandResult.class)); verify(operationCommandObserver, times(0)).finished(Mockito.any(Command.class), Mockito.any(CommandResult.class)); } @Test public void testOnDescriptorWriteSuccess() { setupDescriptorSuccess(); subscribeCommand.execute(device, operationCommandObserver, gatt); subscribeCommand.onDescriptorWrite(gatt, gattDescriptor, BluetoothGatt.GATT_SUCCESS); CommandResult result = CommandResult.createEmptySuccess(characteristicUUID); verify(commandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); } @Test public void testOnDescriptorWriteFail() { setupDescriptorSuccess(); subscribeCommand.execute(device, operationCommandObserver, gatt); subscribeCommand.onDescriptorWrite(gatt, gattDescriptor, BluetoothGatt.GATT_FAILURE); verifyCommandFail(subscribeCommand, BluetoothGatt.GATT_FAILURE); } @Test public void testOnError() { setupDescriptorSuccess(); subscribeCommand.execute(device, operationCommandObserver, gatt); subscribeCommand.onError(BluetoothGatt.GATT_FAILURE); verifyCommandFail(subscribeCommand, BluetoothGatt.GATT_FAILURE); } @Test public void testOnStringBecauseWhyNot() { SubscribeCommand subNotif = new SubscribeCommand( SubscribeCommand.Type.SUBSCRIBE_NOTIFICATION, serviceUUID, characteristicUUID, commandObserver); SubscribeCommand subIndi = new SubscribeCommand( SubscribeCommand.Type.SUBSCRIBE_INDICATION, serviceUUID, characteristicUUID, commandObserver); SubscribeCommand unsub = new SubscribeCommand( SubscribeCommand.Type.UNSUBSCRIBE, serviceUUID, characteristicUUID, commandObserver); assertNotNull(subNotif.toString()); assertNotNull(subIndi.toString()); assertNotNull(unsub.toString()); } public void checkCommandSuccess(@SubscribeCommand.Type int type) { subscribeCommand.execute(device, operationCommandObserver, gatt); when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gattCharacteristic.getDescriptor(eq(clientCharacteristicConfig))).thenReturn(gattDescriptor); subscribeCommand = new SubscribeCommand( type, serviceUUID, characteristicUUID, commandObserver); subscribeCommand.execute(device, operationCommandObserver, gatt); CommandResult result = CommandResult.createEmptySuccess(characteristicUUID); verify(commandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); } private void setupDescriptorSuccess() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gattCharacteristic.getDescriptor(eq(clientCharacteristicConfig))).thenReturn(gattDescriptor); when(gatt.setCharacteristicNotification(Mockito.eq(gattCharacteristic), Mockito.anyBoolean())).thenReturn(true); when(gatt.writeDescriptor(gattDescriptor)).thenReturn(true); } private void verifyCommandFail(SubscribeCommand subscribeCommand, int failCode) { CommandResult result = CommandResult.createErrorResult(characteristicUUID, failCode); verify(commandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(subscribeCommand), refEq(result, "timestamp")); } }