1/* 2 * Copyright (C) 2016 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 17package com.android.server.wifi; 18 19import static org.junit.Assert.assertEquals; 20import static org.mockito.Matchers.any; 21import static org.mockito.Matchers.anyInt; 22import static org.mockito.Mockito.atLeastOnce; 23import static org.mockito.Mockito.mock; 24import static org.mockito.Mockito.times; 25import static org.mockito.Mockito.validateMockitoUsage; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.verifyNoMoreInteractions; 28import static org.mockito.Mockito.when; 29 30import android.content.BroadcastReceiver; 31import android.content.Context; 32import android.content.IntentFilter; 33import android.net.wifi.IWificond; 34import android.net.wifi.RttManager; 35import android.net.wifi.RttManager.ParcelableRttParams; 36import android.net.wifi.RttManager.ResponderConfig; 37import android.net.wifi.WifiManager; 38import android.os.Handler; 39import android.os.Message; 40import android.os.test.TestLooper; 41import android.test.suitebuilder.annotation.SmallTest; 42 43import com.android.internal.util.test.BidirectionalAsyncChannel; 44 45import org.junit.After; 46import org.junit.Before; 47import org.junit.Test; 48import org.mockito.ArgumentCaptor; 49import org.mockito.Mock; 50import org.mockito.MockitoAnnotations; 51 52/** 53 * Unit test for {@link com.android.server.wifi.RttService} 54 */ 55@SmallTest 56public class RttServiceTest { 57 58 // Some constants for running Rtt tests. 59 private static final String MAC = "12:34:56:78:9A:BC"; 60 private static final int CLIENT_KEY1 = 1; 61 private static final int CLIENT_KEY2 = 2; 62 63 @Mock 64 Context mContext; 65 @Mock 66 WifiNative mWifiNative; 67 TestLooper mLooper; 68 @Mock 69 WifiInjector mWifiInjector; 70 @Mock 71 IWificond mWificond; 72 73 RttService.RttServiceImpl mRttServiceImpl; 74 ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = ArgumentCaptor 75 .forClass(BroadcastReceiver.class); 76 77 @Before 78 public void setUp() throws Exception { 79 MockitoAnnotations.initMocks(this); 80 mLooper = new TestLooper(); 81 when(mWifiInjector.makeWificond()).thenReturn(mWificond); 82 when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative); 83 mRttServiceImpl = new RttService.RttServiceImpl(mContext, mLooper.getLooper(), 84 mWifiInjector); 85 mRttServiceImpl.startService(); 86 } 87 88 @After 89 public void cleanup() { 90 validateMockitoUsage(); 91 } 92 93 private void startWifi() { 94 verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), 95 any(IntentFilter.class)); 96 TestUtil.sendWifiScanAvailable(mBroadcastReceiverCaptor.getValue(), 97 mContext, WifiManager.WIFI_STATE_ENABLED); 98 } 99 100 // Create and connect a bi-directional async channel. 101 private BidirectionalAsyncChannel connectChannel(Handler handler) { 102 BidirectionalAsyncChannel channel = new BidirectionalAsyncChannel(); 103 channel.connect(mLooper.getLooper(), mRttServiceImpl.getMessenger(), 104 handler); 105 mLooper.dispatchAll(); 106 channel.assertConnected(); 107 return channel; 108 } 109 110 private void sendRangingRequestFailed(BidirectionalAsyncChannel channel, Handler handler, 111 int clientKey, ParcelableRttParams params) { 112 Message message = sendRangingRequest(channel, handler, clientKey, params); 113 assertEquals("ranging request did not fail", 114 RttManager.CMD_OP_FAILED, message.what); 115 verifyNoMoreInteractions(mWifiNative); 116 } 117 118 // Send rtt ranging request message and verify failure. 119 private Message sendRangingRequest(BidirectionalAsyncChannel channel, Handler handler, 120 int clientKey, ParcelableRttParams params) { 121 Message message = new Message(); 122 message.what = RttManager.CMD_OP_START_RANGING; 123 message.arg2 = clientKey; 124 message.obj = params; 125 channel.sendMessage(message); 126 mLooper.dispatchAll(); 127 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 128 verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture()); 129 return messageCaptor.getValue(); 130 } 131 132 // Send enable responder message and verify success. 133 private void sendEnableResponderSucceed(BidirectionalAsyncChannel channel, 134 Handler handler, int clientKey) { 135 Message message = sendEnableResponder(channel, handler, clientKey, 136 createResponderConfig()); 137 verify(mWifiNative).enableRttResponder(anyInt()); 138 assertEquals("reponse status is not success", 139 RttManager.CMD_OP_ENALBE_RESPONDER_SUCCEEDED, message.what); 140 String actualMac = ((ResponderConfig) message.obj).macAddress; 141 assertEquals("mac address mismatch", MAC, actualMac); 142 } 143 144 // Send enable responder message and verify failure. 145 private void sendEnableResponderFailed(BidirectionalAsyncChannel channel, 146 Handler handler, int clientKey, int reason) { 147 Message message = sendEnableResponder(channel, handler, clientKey, null); 148 assertEquals("reponse status is not failure", 149 RttManager.CMD_OP_ENALBE_RESPONDER_FAILED, message.what); 150 assertEquals("failure reason is not " + reason, 151 reason, message.arg1); 152 } 153 154 private Message sendEnableResponder(BidirectionalAsyncChannel channel, Handler handler, 155 int clientKey, ResponderConfig config) { 156 when(mWifiNative.enableRttResponder(anyInt())).thenReturn(config); 157 when(mWifiNative.getMacAddress()).thenReturn(MAC); 158 Message message = new Message(); 159 message.what = RttManager.CMD_OP_ENABLE_RESPONDER; 160 message.arg2 = clientKey; 161 channel.sendMessage(message); 162 mLooper.dispatchAll(); 163 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 164 verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture()); 165 return messageCaptor.getValue(); 166 } 167 168 private void sendDisableResponder(BidirectionalAsyncChannel channel, int key, boolean success) { 169 when(mWifiNative.disableRttResponder()).thenReturn(success); 170 Message message = new Message(); 171 message.what = RttManager.CMD_OP_DISABLE_RESPONDER; 172 message.arg2 = key; 173 channel.sendMessage(message); 174 mLooper.dispatchAll(); 175 } 176 177 private ResponderConfig createResponderConfig() { 178 ResponderConfig config = new ResponderConfig(); 179 config.macAddress = MAC; 180 return config; 181 } 182 183 @Test 184 public void testEnableResponderSuccess() throws Exception { 185 startWifi(); 186 Handler handler = mock(Handler.class); 187 BidirectionalAsyncChannel channel = connectChannel(handler); 188 // Successfully enabled responder. 189 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 190 } 191 192 @Test 193 public void testEnableResponderSecondTime() throws Exception { 194 startWifi(); 195 Handler handler = mock(Handler.class); 196 BidirectionalAsyncChannel channel = connectChannel(handler); 197 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 198 // Calling enabling responder with the same key should succeed. 199 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 200 } 201 202 @Test 203 public void testEnableResponderMultiClient() throws Exception { 204 startWifi(); 205 Handler handler = mock(Handler.class); 206 BidirectionalAsyncChannel channel = connectChannel(handler); 207 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 208 sendEnableResponderSucceed(channel, handler, CLIENT_KEY2); 209 // Native method should be called only once when multiple clients enabled responder. 210 verify(mWifiNative, times(1)).enableRttResponder(anyInt()); 211 } 212 213 @Test 214 public void testDisableResponderSuccess() throws Exception { 215 startWifi(); 216 Handler handler = mock(Handler.class); 217 BidirectionalAsyncChannel channel = connectChannel(handler); 218 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 219 // Disable after successfully enabling. 220 sendDisableResponder(channel, CLIENT_KEY1, false); 221 verify(mWifiNative).disableRttResponder(); 222 } 223 224 /** 225 * Enable responder failed because of internal error. 226 */ 227 @Test 228 public void testEnableResponderFailure() throws Exception { 229 startWifi(); 230 Handler handler = mock(Handler.class); 231 when(mWifiNative.enableRttResponder(anyInt())).thenReturn(null); 232 BidirectionalAsyncChannel channel = connectChannel(handler); 233 // Disable failed. 234 sendEnableResponderFailed(channel, handler, CLIENT_KEY1, RttManager.REASON_UNSPECIFIED); 235 } 236 237 @Test 238 public void testDisableResponderNotStarted() throws Exception { 239 startWifi(); 240 Handler handler = mock(Handler.class); 241 BidirectionalAsyncChannel channel = connectChannel(handler); 242 // Disable without enabling should fail. 243 sendDisableResponder(channel, CLIENT_KEY1, false); 244 // Native disable method shouldn't be called. 245 verifyNoMoreInteractions(mWifiNative); 246 } 247 248 @Test 249 public void testDisableResponderMultiClient() throws Exception { 250 startWifi(); 251 Handler handler = mock(Handler.class); 252 BidirectionalAsyncChannel channel = connectChannel(handler); 253 sendEnableResponderSucceed(channel, handler, CLIENT_KEY1); 254 sendEnableResponderSucceed(channel, handler, CLIENT_KEY2); 255 // Two clients enabled, one client disabled. 256 sendDisableResponder(channel, CLIENT_KEY1, true); 257 verify(mWifiNative, times(1)).getMacAddress(); 258 verifyNoMoreInteractions(mWifiNative); 259 } 260 261 /** 262 * Enable responder failed because wifi is not enabled. 263 */ 264 @Test 265 public void testEnableResponderFailedWifiDisabled() throws Exception { 266 Handler handler = mock(Handler.class); 267 BidirectionalAsyncChannel channel = connectChannel(handler); 268 // Wifi is disabled as startWifi() is not invoked. 269 sendEnableResponderFailed(channel, handler, CLIENT_KEY1, RttManager.REASON_NOT_AVAILABLE); 270 verifyNoMoreInteractions(mWifiNative); 271 } 272 273 /** 274 * Test RTT ranging with empty RttParams. 275 */ 276 @Test 277 public void testInitiatorEmptyParams() throws Exception { 278 startWifi(); 279 Handler handler = mock(Handler.class); 280 BidirectionalAsyncChannel channel = connectChannel(handler); 281 sendRangingRequestFailed(channel, handler, CLIENT_KEY1, new ParcelableRttParams(null)); 282 } 283} 284