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