1 /* 2 * Copyright 2022 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.server.bluetooth; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertThrows; 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.Mockito.any; 24 import static org.mockito.Mockito.eq; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.bluetooth.BluetoothAdapter; 31 import android.content.Context; 32 import android.os.Binder; 33 import android.os.RemoteException; 34 35 import androidx.test.filters.SmallTest; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.server.bluetooth.BluetoothShellCommand.BluetoothCommand; 39 40 import com.google.common.truth.Expect; 41 42 import org.junit.Before; 43 import org.junit.Rule; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 49 import java.io.FileDescriptor; 50 import java.io.PrintWriter; 51 52 @SmallTest 53 @RunWith(AndroidJUnit4.class) 54 public class BluetoothShellCommandTest { 55 @Rule public final Expect expect = Expect.create(); 56 57 @Mock 58 BluetoothManagerService mManagerService; 59 60 @Mock 61 Context mContext; 62 63 BluetoothShellCommand mShellCommand; 64 65 @Before setUp()66 public void setUp() throws Exception { 67 MockitoAnnotations.initMocks(this); 68 mShellCommand = new BluetoothShellCommand(mManagerService, mContext); 69 mShellCommand.init( 70 mock(Binder.class), mock(FileDescriptor.class), mock(FileDescriptor.class), 71 mock(FileDescriptor.class), new String[0], -1); 72 } 73 74 @Test enableCommand()75 public void enableCommand() throws Exception { 76 BluetoothCommand enableCmd = mShellCommand.new Enable(); 77 String cmdName = "enable"; 78 79 assertThat(enableCmd.getName()).isEqualTo(cmdName); 80 assertThat(enableCmd.isMatch(cmdName)).isTrue(); 81 assertThat(enableCmd.isPrivileged()).isFalse(); 82 when(mManagerService.enable(any())).thenReturn(true); 83 assertThat(enableCmd.exec(cmdName)).isEqualTo(0); 84 } 85 86 @Test disableCommand()87 public void disableCommand() throws Exception { 88 BluetoothCommand disableCmd = mShellCommand.new Disable(); 89 String cmdName = "disable"; 90 91 assertThat(disableCmd.getName()).isEqualTo(cmdName); 92 assertThat(disableCmd.isMatch(cmdName)).isTrue(); 93 assertThat(disableCmd.isPrivileged()).isFalse(); 94 when(mManagerService.disable(any(), anyBoolean())).thenReturn(true); 95 assertThat(disableCmd.exec(cmdName)).isEqualTo(0); 96 } 97 98 @Test waitForStateCommand()99 public void waitForStateCommand() throws Exception { 100 BluetoothCommand waitCmd = mShellCommand.new WaitForAdapterState(); 101 102 expect.that(waitCmd.getName()).isEqualTo("wait-for-state"); 103 String[] validCmd = { 104 "wait-for-state:STATE_OFF", 105 "wait-for-state:STATE_ON", 106 }; 107 for (String m : validCmd) { 108 expect.that(waitCmd.isMatch(m)).isTrue(); 109 } 110 String[] falseCmd = { 111 "wait-for-stateSTATE_ON", 112 "wait-for-foo:STATE_ON", 113 }; 114 for (String m : falseCmd) { 115 expect.that(waitCmd.isMatch(m)).isFalse(); 116 } 117 String[] throwCmd = { 118 "wait-for-state:STATE_BLE_TURNING_ON", 119 "wait-for-state:STATE_ON:STATE_OFF", 120 "wait-for-state::STATE_ON", 121 "wait-for-state:STATE_ON:", 122 }; 123 for (String m : throwCmd) { 124 assertThrows(m, IllegalArgumentException.class, () -> waitCmd.isMatch(m)); 125 } 126 127 expect.that(waitCmd.isPrivileged()).isFalse(); 128 when(mManagerService.waitForManagerState(eq(BluetoothAdapter.STATE_OFF))).thenReturn(true); 129 130 expect.that(waitCmd.exec(validCmd[0])).isEqualTo(0); 131 } 132 133 @Test onCommand_withNullString_callsOnHelp()134 public void onCommand_withNullString_callsOnHelp() { 135 BluetoothShellCommand command = spy(mShellCommand); 136 137 command.onCommand(null); 138 139 verify(command).onHelp(); 140 } 141 142 @Test onCommand_withEnableString_callsEnableCommand()143 public void onCommand_withEnableString_callsEnableCommand() throws Exception { 144 BluetoothCommand enableCmd = spy(mShellCommand.new Enable()); 145 mShellCommand.mBluetoothCommands[0] = enableCmd; 146 147 mShellCommand.onCommand("enable"); 148 149 verify(enableCmd).exec(eq("enable")); 150 } 151 152 @Test onCommand_withPrivilegedCommandName_throwsSecurityException()153 public void onCommand_withPrivilegedCommandName_throwsSecurityException() { 154 final String privilegedCommandName = "test_privileged_cmd_name"; 155 BluetoothCommand privilegedCommand = 156 mShellCommand.new BluetoothCommand(true, privilegedCommandName) { 157 @Override 158 int exec(String cmd) throws RemoteException { 159 return 0; 160 } 161 @Override 162 public void onHelp(PrintWriter pw) { } 163 }; 164 mShellCommand.mBluetoothCommands[0] = privilegedCommand; 165 166 assertThrows(SecurityException.class, 167 () -> mShellCommand.onCommand(privilegedCommandName)); 168 } 169 } 170