WifiAwareStateManagerTest.java revision eb558d6b74ba14a5ff08866166b109dda8e0ab20
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.aware; 18 19import static org.hamcrest.core.IsEqual.equalTo; 20import static org.hamcrest.core.IsNull.notNullValue; 21import static org.hamcrest.core.IsNull.nullValue; 22import static org.junit.Assert.assertEquals; 23import static org.junit.Assert.assertTrue; 24import static org.mockito.ArgumentMatchers.any; 25import static org.mockito.ArgumentMatchers.anyBoolean; 26import static org.mockito.ArgumentMatchers.anyByte; 27import static org.mockito.ArgumentMatchers.anyInt; 28import static org.mockito.ArgumentMatchers.anyLong; 29import static org.mockito.ArgumentMatchers.anyShort; 30import static org.mockito.ArgumentMatchers.eq; 31import static org.mockito.ArgumentMatchers.isNull; 32import static org.mockito.Mockito.inOrder; 33import static org.mockito.Mockito.mock; 34import static org.mockito.Mockito.times; 35import static org.mockito.Mockito.verify; 36import static org.mockito.Mockito.verifyNoMoreInteractions; 37import static org.mockito.Mockito.when; 38 39import android.Manifest; 40import android.app.AppOpsManager; 41import android.app.test.MockAnswerUtil; 42import android.app.test.TestAlarmManager; 43import android.content.BroadcastReceiver; 44import android.content.Context; 45import android.content.Intent; 46import android.content.IntentFilter; 47import android.content.pm.PackageManager; 48import android.hardware.wifi.V1_0.NanStatusType; 49import android.net.ConnectivityManager; 50import android.net.wifi.RttManager; 51import android.net.wifi.aware.ConfigRequest; 52import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 53import android.net.wifi.aware.IWifiAwareEventCallback; 54import android.net.wifi.aware.PublishConfig; 55import android.net.wifi.aware.SubscribeConfig; 56import android.net.wifi.aware.WifiAwareManager; 57import android.os.Handler; 58import android.os.IPowerManager; 59import android.os.Message; 60import android.os.PowerManager; 61import android.os.UserHandle; 62import android.os.test.TestLooper; 63import android.test.suitebuilder.annotation.SmallTest; 64import android.util.Log; 65import android.util.SparseArray; 66 67import libcore.util.HexEncoding; 68 69import org.junit.Before; 70import org.junit.Rule; 71import org.junit.Test; 72import org.junit.rules.ErrorCollector; 73import org.mockito.ArgumentCaptor; 74import org.mockito.InOrder; 75import org.mockito.Mock; 76import org.mockito.MockitoAnnotations; 77 78import java.io.PrintWriter; 79import java.io.StringWriter; 80import java.lang.reflect.Field; 81import java.util.HashMap; 82import java.util.HashSet; 83import java.util.LinkedList; 84import java.util.Map; 85import java.util.Random; 86import java.util.Set; 87 88/** 89 * Unit test harness for WifiAwareStateManager. 90 */ 91@SmallTest 92public class WifiAwareStateManagerTest { 93 private TestLooper mMockLooper; 94 private Random mRandomNg = new Random(15687); 95 private WifiAwareStateManager mDut; 96 @Mock private WifiAwareNativeManager mMockNativeManager; 97 @Mock private WifiAwareNativeApi mMockNative; 98 @Mock private Context mMockContext; 99 @Mock private AppOpsManager mMockAppOpsManager; 100 @Mock private WifiAwareRttStateManager mMockAwareRttStateManager; 101 @Mock private WifiAwareMetrics mAwareMetricsMock; 102 TestAlarmManager mAlarmManager; 103 private PowerManager mMockPowerManager; 104 private BroadcastReceiver mPowerBcastReceiver; 105 @Mock private WifiAwareDataPathStateManager mMockAwareDataPathStatemanager; 106 107 @Rule 108 public ErrorCollector collector = new ErrorCollector(); 109 110 private static final byte[] ALL_ZERO_MAC = new byte[] {0, 0, 0, 0, 0, 0}; 111 112 /** 113 * Pre-test configuration. Initialize and install mocks. 114 */ 115 @Before 116 public void setUp() throws Exception { 117 MockitoAnnotations.initMocks(this); 118 119 mAlarmManager = new TestAlarmManager(); 120 when(mMockContext.getSystemService(Context.ALARM_SERVICE)) 121 .thenReturn(mAlarmManager.getAlarmManager()); 122 123 mMockLooper = new TestLooper(); 124 125 IPowerManager powerManagerService = mock(IPowerManager.class); 126 mMockPowerManager = new PowerManager(mMockContext, powerManagerService, 127 new Handler(mMockLooper.getLooper())); 128 129 when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( 130 mock(ConnectivityManager.class)); 131 when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager); 132 when(mMockContext.getSystemServiceName(PowerManager.class)).thenReturn( 133 Context.POWER_SERVICE); 134 when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); 135 when(mMockContext.checkPermission(eq(android.Manifest.permission.ACCESS_FINE_LOCATION), 136 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); 137 when(mMockContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), 138 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); 139 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_FINE_LOCATION), anyInt(), 140 any())).thenReturn(AppOpsManager.MODE_ERRORED); 141 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_COARSE_LOCATION), anyInt(), 142 any())).thenReturn(AppOpsManager.MODE_ERRORED); 143 when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false); 144 when(mMockPowerManager.isInteractive()).thenReturn(true); 145 146 ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass( 147 BroadcastReceiver.class); 148 mDut = new WifiAwareStateManager(); 149 mDut.setNative(mMockNativeManager, mMockNative); 150 mDut.start(mMockContext, mMockLooper.getLooper(), mAwareMetricsMock); 151 mDut.startLate(); 152 mMockLooper.dispatchAll(); 153 verify(mMockContext).registerReceiver(bcastRxCaptor.capture(), any(IntentFilter.class)); 154 mPowerBcastReceiver = bcastRxCaptor.getValue(); 155 installMocksInStateManager(mDut, mMockAwareRttStateManager, mMockAwareDataPathStatemanager); 156 157 when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), 158 anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(true); 159 when(mMockNative.disable(anyShort())).thenReturn(true); 160 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(true); 161 when(mMockNative.subscribe(anyShort(), anyByte(), any())) 162 .thenReturn(true); 163 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 164 any(), anyInt())).thenReturn(true); 165 when(mMockNative.stopPublish(anyShort(), anyByte())).thenReturn(true); 166 when(mMockNative.stopSubscribe(anyShort(), anyByte())).thenReturn(true); 167 when(mMockNative.getCapabilities(anyShort())).thenReturn(true); 168 } 169 170 /** 171 * Test that the set parameter shell command executor works when parameters are valid. 172 */ 173 @Test 174 public void testSetParameterShellCommandSuccess() { 175 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), 176 true); 177 } 178 179 /** 180 * Test that the set parameter shell command executor fails on incorrect name. 181 */ 182 @Test 183 public void testSetParameterShellCommandInvalidParameterName() { 184 setSettableParam("XXX", Integer.toString(1), false); 185 } 186 187 /** 188 * Test that the set parameter shell command executor fails on invalid value (not convertible 189 * to an int). 190 */ 191 @Test 192 public void testSetParameterShellCommandInvalidValue() { 193 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, "garbage", false); 194 } 195 196 /** 197 * Validate that Aware data-path interfaces are brought up and down correctly. 198 */ 199 @Test 200 public void testAwareDataPathInterfaceUpDown() throws Exception { 201 final int clientId = 12341; 202 final int uid = 1000; 203 final int pid = 2000; 204 final String callingPackage = "com.google.somePackage"; 205 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 206 207 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 208 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 209 InOrder inOrder = inOrder(mMockContext, mMockNative, mMockAwareDataPathStatemanager, 210 mockCallback); 211 212 // (1) enable usage 213 mDut.enableUsage(); 214 mMockLooper.dispatchAll(); 215 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 216 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 217 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 218 mMockLooper.dispatchAll(); 219 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 220 221 // (2) connect (enable Aware) 222 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 223 mMockLooper.dispatchAll(); 224 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 225 eq(false), eq(true), eq(true), eq(false)); 226 mDut.onConfigSuccessResponse(transactionId.getValue()); 227 mMockLooper.dispatchAll(); 228 inOrder.verify(mockCallback).onConnectSuccess(clientId); 229 inOrder.verify(mMockAwareDataPathStatemanager).createAllInterfaces(); 230 231 // (3) disconnect (disable Aware) 232 mDut.disconnect(clientId); 233 mMockLooper.dispatchAll(); 234 inOrder.verify(mMockNative).disable(transactionId.capture()); 235 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 236 mMockLooper.dispatchAll(); 237 inOrder.verify(mMockAwareDataPathStatemanager).deleteAllInterfaces(); 238 239 verifyNoMoreInteractions(mMockNative, mMockAwareDataPathStatemanager); 240 } 241 242 /** 243 * Validate that APIs aren't functional when usage is disabled. 244 */ 245 @Test 246 public void testDisableUsageDisablesApis() throws Exception { 247 final int clientId = 12314; 248 final int uid = 1000; 249 final int pid = 2000; 250 final String callingPackage = "com.google.somePackage"; 251 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 252 253 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 254 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 255 256 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 257 258 // (1) check initial state 259 mDut.enableUsage(); 260 mMockLooper.dispatchAll(); 261 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 262 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 263 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 264 mMockLooper.dispatchAll(); 265 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 266 267 // (2) disable usage and validate state 268 mDut.disableUsage(); 269 mMockLooper.dispatchAll(); 270 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 271 inOrder.verify(mMockNative).disable(transactionId.capture()); 272 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 273 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 274 275 // (3) try connecting and validate that get failure callback (though app should be aware of 276 // non-availability through state change broadcast and/or query API) 277 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 278 mMockLooper.dispatchAll(); 279 inOrder.verify(mockCallback).onConnectFail(anyInt()); 280 281 verifyNoMoreInteractions(mMockNative, mockCallback); 282 } 283 284 /** 285 * Validate that when API usage is disabled while in the middle of a connection that internal 286 * state is cleaned-up, and that all subsequent operations are NOP. Then enable usage again and 287 * validate that operates correctly. 288 */ 289 @Test 290 public void testDisableUsageFlow() throws Exception { 291 final int clientId = 12341; 292 final int uid = 1000; 293 final int pid = 2000; 294 final String callingPackage = "com.google.somePackage"; 295 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 296 297 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 298 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 299 ArgumentCaptor<SparseArray> sparseArrayCaptor = ArgumentCaptor.forClass(SparseArray.class); 300 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 301 InOrder inOrderM = inOrder(mAwareMetricsMock); 302 303 // (1) check initial state 304 mDut.enableUsage(); 305 mMockLooper.dispatchAll(); 306 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 307 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 308 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 309 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 310 mMockLooper.dispatchAll(); 311 312 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 313 314 // (2) connect (successfully) 315 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 316 mMockLooper.dispatchAll(); 317 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 318 eq(false), eq(true), eq(true), eq(false)); 319 mDut.onConfigSuccessResponse(transactionId.getValue()); 320 mMockLooper.dispatchAll(); 321 inOrder.verify(mockCallback).onConnectSuccess(clientId); 322 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), 323 sparseArrayCaptor.capture()); 324 collector.checkThat("num of clients", sparseArrayCaptor.getValue().size(), equalTo(1)); 325 326 // (3) disable usage & verify callbacks 327 mDut.disableUsage(); 328 mMockLooper.dispatchAll(); 329 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 330 inOrder.verify(mMockNative).disable(transactionId.capture()); 331 inOrderM.verify(mAwareMetricsMock).recordAttachSessionDuration(anyLong()); 332 inOrderM.verify(mAwareMetricsMock).recordDisableUsage(); 333 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 334 validateInternalClientInfoCleanedUp(clientId); 335 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 336 mMockLooper.dispatchAll(); 337 338 // (4) try connecting again and validate that get a failure 339 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 340 mMockLooper.dispatchAll(); 341 inOrder.verify(mockCallback).onConnectFail(anyInt()); 342 inOrderM.verify(mAwareMetricsMock).recordAttachStatus(NanStatusType.INTERNAL_FAILURE); 343 344 // (5) disable usage again and validate that not much happens 345 mDut.disableUsage(); 346 mMockLooper.dispatchAll(); 347 collector.checkThat("usage disabled", mDut.isUsageEnabled(), equalTo(false)); 348 349 // (6) enable usage 350 mDut.enableUsage(); 351 mMockLooper.dispatchAll(); 352 inOrderM.verify(mAwareMetricsMock).recordEnableUsage(); 353 collector.checkThat("usage enabled", mDut.isUsageEnabled(), equalTo(true)); 354 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 355 356 // (7) connect (should be successful) 357 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 358 mMockLooper.dispatchAll(); 359 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 360 eq(false), eq(true), eq(true), eq(false)); 361 mDut.onConfigSuccessResponse(transactionId.getValue()); 362 mMockLooper.dispatchAll(); 363 inOrder.verify(mockCallback).onConnectSuccess(clientId); 364 inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(uid), eq(false), 365 sparseArrayCaptor.capture()); 366 collector.checkThat("num of clients", sparseArrayCaptor.getValue().size(), equalTo(1)); 367 368 verifyNoMoreInteractions(mMockNative, mockCallback, mAwareMetricsMock); 369 } 370 371 /** 372 * Validates that a HAL failure on enable and configure results in failed callback. 373 */ 374 @Test 375 public void testHalFailureEnableAndConfigure() throws Exception { 376 final int clientId = 12341; 377 final int uid = 1000; 378 final int pid = 2000; 379 final String callingPackage = "com.google.somePackage"; 380 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 381 382 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 383 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 384 InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); 385 386 when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), 387 anyBoolean(), eq(true), eq(false))).thenReturn(false); 388 389 // (1) check initial state 390 mDut.enableUsage(); 391 mMockLooper.dispatchAll(); 392 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 393 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 394 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 395 mMockLooper.dispatchAll(); 396 397 // (2) connect with HAL failure 398 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 399 mMockLooper.dispatchAll(); 400 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 401 eq(false), eq(true), eq(true), eq(false)); 402 inOrder.verify(mockCallback).onConnectFail(NanStatusType.INTERNAL_FAILURE); 403 404 validateInternalClientInfoCleanedUp(clientId); 405 verifyNoMoreInteractions(mMockNative, mockCallback); 406 } 407 408 /** 409 * Validates that all events are delivered with correct arguments. Validates 410 * that IdentityChanged not delivered if configuration disables delivery. 411 */ 412 @Test 413 public void testAwareEventsDelivery() throws Exception { 414 final int clientId1 = 1005; 415 final int clientId2 = 1007; 416 final int clusterLow = 5; 417 final int clusterHigh = 100; 418 final int masterPref = 111; 419 final int uid = 1000; 420 final int pid = 2000; 421 final String callingPackage = "com.google.somePackage"; 422 final int reason = NanStatusType.INTERNAL_FAILURE; 423 final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false); 424 final byte[] someMac2 = HexEncoding.decode("060708090A0B".toCharArray(), false); 425 426 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 427 .setClusterHigh(clusterHigh).setMasterPreference(masterPref) 428 .build(); 429 430 IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); 431 IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); 432 ArgumentCaptor<Short> transactionIdCapture = ArgumentCaptor.forClass(Short.class); 433 InOrder inOrder = inOrder(mockCallback1, mockCallback2, mMockNative); 434 435 mDut.enableUsage(); 436 mMockLooper.dispatchAll(); 437 inOrder.verify(mMockNative).getCapabilities(transactionIdCapture.capture()); 438 mDut.onCapabilitiesUpdateResponse(transactionIdCapture.getValue(), getCapabilities()); 439 mMockLooper.dispatchAll(); 440 441 // (1) connect 1st and 2nd clients 442 mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest, false); 443 mMockLooper.dispatchAll(); 444 inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), 445 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 446 short transactionId = transactionIdCapture.getValue(); 447 mDut.onConfigSuccessResponse(transactionId); 448 mMockLooper.dispatchAll(); 449 inOrder.verify(mockCallback1).onConnectSuccess(clientId1); 450 451 mDut.connect(clientId2, uid, pid, callingPackage, mockCallback2, configRequest, true); 452 mMockLooper.dispatchAll(); 453 inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), 454 eq(configRequest), eq(true), eq(false), eq(true), eq(false)); 455 transactionId = transactionIdCapture.getValue(); 456 mDut.onConfigSuccessResponse(transactionId); 457 mMockLooper.dispatchAll(); 458 inOrder.verify(mockCallback2).onConnectSuccess(clientId2); 459 460 // (2) deliver Aware events - without LOCATIONING permission 461 mDut.onClusterChangeNotification(WifiAwareClientState.CLUSTER_CHANGE_EVENT_STARTED, 462 someMac); 463 mDut.onInterfaceAddressChangeNotification(someMac); 464 mMockLooper.dispatchAll(); 465 466 inOrder.verify(mockCallback2).onIdentityChanged(ALL_ZERO_MAC); 467 468 // (3) deliver new identity - still without LOCATIONING permission (should get an event) 469 mDut.onInterfaceAddressChangeNotification(someMac2); 470 mMockLooper.dispatchAll(); 471 472 inOrder.verify(mockCallback2).onIdentityChanged(ALL_ZERO_MAC); 473 474 // (4) deliver same identity - still without LOCATIONING permission (should 475 // not get an event) 476 mDut.onInterfaceAddressChangeNotification(someMac2); 477 mMockLooper.dispatchAll(); 478 479 // (5) deliver new identity - with LOCATIONING permission 480 when(mMockContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), 481 anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); 482 when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_COARSE_LOCATION), anyInt(), 483 any())).thenReturn(AppOpsManager.MODE_ALLOWED); 484 mDut.onInterfaceAddressChangeNotification(someMac); 485 mMockLooper.dispatchAll(); 486 487 inOrder.verify(mockCallback2).onIdentityChanged(someMac); 488 489 // (6) Aware down (no feedback) 490 mDut.onAwareDownNotification(reason); 491 mMockLooper.dispatchAll(); 492 493 validateInternalClientInfoCleanedUp(clientId1); 494 validateInternalClientInfoCleanedUp(clientId2); 495 496 verifyNoMoreInteractions(mockCallback1, mockCallback2, mMockNative); 497 } 498 499 /** 500 * Validate that when the HAL doesn't respond we get a TIMEOUT (which 501 * results in a failure response) at which point we can process additional 502 * commands. Steps: (1) connect, (2) publish - timeout, (3) publish + 503 * success. 504 */ 505 @Test 506 public void testHalNoResponseTimeout() throws Exception { 507 final int clientId = 12341; 508 final int uid = 1000; 509 final int pid = 2000; 510 final String callingPackage = "com.google.somePackage"; 511 final ConfigRequest configRequest = new ConfigRequest.Builder().build(); 512 final PublishConfig publishConfig = new PublishConfig.Builder().build(); 513 514 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 515 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 516 IWifiAwareDiscoverySessionCallback.class); 517 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 518 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 519 520 mDut.enableUsage(); 521 mMockLooper.dispatchAll(); 522 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 523 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 524 mMockLooper.dispatchAll(); 525 526 // (1) connect (successfully) 527 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 528 mMockLooper.dispatchAll(); 529 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 530 eq(false), eq(true), eq(true), eq(false)); 531 mDut.onConfigSuccessResponse(transactionId.getValue()); 532 mMockLooper.dispatchAll(); 533 inOrder.verify(mockCallback).onConnectSuccess(clientId); 534 535 // (2) publish + timeout 536 mDut.publish(clientId, publishConfig, mockSessionCallback); 537 mMockLooper.dispatchAll(); 538 inOrder.verify(mMockNative).publish(anyShort(), eq((byte) 0), eq(publishConfig)); 539 assertTrue(mAlarmManager.dispatch(WifiAwareStateManager.HAL_COMMAND_TIMEOUT_TAG)); 540 mMockLooper.dispatchAll(); 541 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 542 validateInternalNoSessions(clientId); 543 544 // (3) publish + success 545 mDut.publish(clientId, publishConfig, mockSessionCallback); 546 mMockLooper.dispatchAll(); 547 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 548 eq(publishConfig)); 549 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, (byte) 99); 550 mMockLooper.dispatchAll(); 551 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 552 553 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 554 } 555 556 /** 557 * Validates publish flow: (1) initial publish (2) fail informed by notification, (3) fail due 558 * to immediate HAL failure. Expected: get a failure callback. 559 */ 560 @Test 561 public void testPublishFail() throws Exception { 562 final int clientId = 1005; 563 final int uid = 1000; 564 final int pid = 2000; 565 final String callingPackage = "com.google.somePackage"; 566 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 567 568 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 569 PublishConfig publishConfig = new PublishConfig.Builder().build(); 570 571 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 572 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 573 IWifiAwareDiscoverySessionCallback.class); 574 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 575 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 576 577 mDut.enableUsage(); 578 mMockLooper.dispatchAll(); 579 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 580 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 581 mMockLooper.dispatchAll(); 582 583 // (0) connect 584 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 585 mMockLooper.dispatchAll(); 586 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 587 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 588 mDut.onConfigSuccessResponse(transactionId.getValue()); 589 mMockLooper.dispatchAll(); 590 inOrder.verify(mockCallback).onConnectSuccess(clientId); 591 592 // (1) initial publish 593 mDut.publish(clientId, publishConfig, mockSessionCallback); 594 mMockLooper.dispatchAll(); 595 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 596 eq(publishConfig)); 597 598 // (2) publish failure callback (i.e. firmware tried and failed) 599 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, reasonFail); 600 mMockLooper.dispatchAll(); 601 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 602 validateInternalNoSessions(clientId); 603 604 // (3) publish and get immediate failure (i.e. HAL failed) 605 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(false); 606 607 mDut.publish(clientId, publishConfig, mockSessionCallback); 608 mMockLooper.dispatchAll(); 609 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 610 eq(publishConfig)); 611 612 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 613 validateInternalNoSessions(clientId); 614 615 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 616 } 617 618 /** 619 * Validates the publish flow: (1) initial publish (2) success (3) 620 * termination (e.g. DONE) (4) update session attempt (5) terminateSession 621 * (6) update session attempt. Expected: session ID callback + session 622 * cleaned-up. 623 */ 624 @Test 625 public void testPublishSuccessTerminated() throws Exception { 626 final int clientId = 2005; 627 final int uid = 1000; 628 final int pid = 2000; 629 final String callingPackage = "com.google.somePackage"; 630 final int reasonTerminate = NanStatusType.SUCCESS; 631 final byte publishId = 15; 632 633 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 634 PublishConfig publishConfig = new PublishConfig.Builder().build(); 635 636 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 637 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 638 IWifiAwareDiscoverySessionCallback.class); 639 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 640 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 641 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 642 643 mDut.enableUsage(); 644 mMockLooper.dispatchAll(); 645 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 646 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 647 mMockLooper.dispatchAll(); 648 649 // (0) connect 650 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 651 mMockLooper.dispatchAll(); 652 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 653 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 654 mDut.onConfigSuccessResponse(transactionId.getValue()); 655 mMockLooper.dispatchAll(); 656 inOrder.verify(mockCallback).onConnectSuccess(clientId); 657 658 // (1) initial publish 659 mDut.publish(clientId, publishConfig, mockSessionCallback); 660 mMockLooper.dispatchAll(); 661 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 662 eq(publishConfig)); 663 664 // (2) publish success 665 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 666 mMockLooper.dispatchAll(); 667 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 668 669 // (3) publish termination (from firmware - not app!) 670 mDut.onSessionTerminatedNotification(publishId, reasonTerminate, true); 671 mMockLooper.dispatchAll(); 672 inOrder.verify(mockSessionCallback).onSessionTerminated(reasonTerminate); 673 674 // (4) app update session (race condition: app didn't get termination 675 // yet) 676 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 677 mMockLooper.dispatchAll(); 678 679 // (5) app terminates session 680 mDut.terminateSession(clientId, sessionId.getValue()); 681 mMockLooper.dispatchAll(); 682 683 // (6) app updates session (app already knows that terminated - will get 684 // a local FAIL). 685 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 686 mMockLooper.dispatchAll(); 687 688 validateInternalSessionInfoCleanedUp(clientId, sessionId.getValue()); 689 690 verifyNoMoreInteractions(mockSessionCallback, mMockNative); 691 } 692 693 /** 694 * Validate the publish flow: (1) initial publish + (2) success + (3) update + (4) update 695 * fails (callback from firmware) + (5) update + (6). Expected: session is still alive after 696 * update failure so second update succeeds (no callbacks) + (7) update + immediate failure from 697 * HAL + (8) update + failure for invalid ID (which should clean-up state) + (9) another update 698 * - should get no response. 699 */ 700 @Test 701 public void testPublishUpdateFail() throws Exception { 702 final int clientId = 2005; 703 final int uid = 1000; 704 final int pid = 2000; 705 final String callingPackage = "com.google.somePackage"; 706 final byte publishId = 15; 707 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 708 709 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 710 PublishConfig publishConfig = new PublishConfig.Builder().build(); 711 712 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 713 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 714 IWifiAwareDiscoverySessionCallback.class); 715 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 716 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 717 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 718 719 mDut.enableUsage(); 720 mMockLooper.dispatchAll(); 721 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 722 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 723 mMockLooper.dispatchAll(); 724 725 // (0) connect 726 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 727 mMockLooper.dispatchAll(); 728 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 729 eq(false), eq(true), eq(true), eq(false)); 730 mDut.onConfigSuccessResponse(transactionId.getValue()); 731 mMockLooper.dispatchAll(); 732 inOrder.verify(mockCallback).onConnectSuccess(clientId); 733 734 // (1) initial publish 735 mDut.publish(clientId, publishConfig, mockSessionCallback); 736 mMockLooper.dispatchAll(); 737 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 738 eq(publishConfig)); 739 740 // (2) publish success 741 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 742 mMockLooper.dispatchAll(); 743 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 744 745 // (3) update publish 746 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 747 mMockLooper.dispatchAll(); 748 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 749 eq(publishConfig)); 750 751 // (4) update fails 752 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, reasonFail); 753 mMockLooper.dispatchAll(); 754 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 755 756 // (5) another update publish 757 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 758 mMockLooper.dispatchAll(); 759 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 760 eq(publishConfig)); 761 762 // (6) update succeeds 763 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 764 mMockLooper.dispatchAll(); 765 inOrder.verify(mockSessionCallback).onSessionConfigSuccess(); 766 767 // (7) another update + immediate failure 768 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(false); 769 770 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 771 mMockLooper.dispatchAll(); 772 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 773 eq(publishConfig)); 774 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 775 776 // (8) an update with bad ID failure 777 when(mMockNative.publish(anyShort(), anyByte(), any())).thenReturn(true); 778 779 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 780 mMockLooper.dispatchAll(); 781 inOrder.verify(mMockNative).publish(transactionId.capture(), eq(publishId), 782 eq(publishConfig)); 783 mDut.onSessionConfigFailResponse(transactionId.getValue(), true, 784 NanStatusType.INVALID_SESSION_ID); 785 mMockLooper.dispatchAll(); 786 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INVALID_SESSION_ID); 787 788 // (9) try updating again - do nothing/get nothing 789 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 790 mMockLooper.dispatchAll(); 791 792 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 793 } 794 795 /** 796 * Validate race condition: publish pending but session terminated (due to 797 * disconnect - can't terminate such a session directly from app). Need to 798 * make sure that once publish succeeds (failure isn't a problem) the 799 * session is immediately terminated since no-one is listening for it. 800 */ 801 @Test 802 public void testDisconnectWhilePublishPending() throws Exception { 803 final int clientId = 2005; 804 final int uid = 1000; 805 final int pid = 2000; 806 final String callingPackage = "com.google.somePackage"; 807 final byte publishId = 15; 808 809 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 810 PublishConfig publishConfig = new PublishConfig.Builder().build(); 811 812 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 813 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 814 IWifiAwareDiscoverySessionCallback.class); 815 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 816 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 817 818 mDut.enableUsage(); 819 mMockLooper.dispatchAll(); 820 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 821 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 822 mMockLooper.dispatchAll(); 823 824 // (0) connect 825 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 826 mMockLooper.dispatchAll(); 827 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 828 eq(false), eq(true), eq(true), eq(false)); 829 mDut.onConfigSuccessResponse(transactionId.getValue()); 830 mMockLooper.dispatchAll(); 831 inOrder.verify(mockCallback).onConnectSuccess(clientId); 832 833 // (1) initial publish 834 mDut.publish(clientId, publishConfig, mockSessionCallback); 835 mMockLooper.dispatchAll(); 836 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 837 eq(publishConfig)); 838 839 // (2) disconnect (but doesn't get executed until get response for 840 // publish command) 841 mDut.disconnect(clientId); 842 mMockLooper.dispatchAll(); 843 844 // (3) publish success 845 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 846 mMockLooper.dispatchAll(); 847 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 848 inOrder.verify(mMockNative).stopPublish(transactionId.capture(), eq(publishId)); 849 inOrder.verify(mMockNative).disable(anyShort()); 850 851 validateInternalClientInfoCleanedUp(clientId); 852 853 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 854 } 855 856 /** 857 * Validates subscribe flow: (1) initial subscribe (2) fail (callback from firmware), (3) fail 858 * due to immeidate HAL failure. Expected: get a failure callback. 859 */ 860 @Test 861 public void testSubscribeFail() throws Exception { 862 final int clientId = 1005; 863 final int uid = 1000; 864 final int pid = 2000; 865 final String callingPackage = "com.google.somePackage"; 866 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 867 868 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 869 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 870 871 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 872 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 873 IWifiAwareDiscoverySessionCallback.class); 874 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 875 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 876 877 mDut.enableUsage(); 878 mMockLooper.dispatchAll(); 879 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 880 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 881 mMockLooper.dispatchAll(); 882 883 // (0) connect 884 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 885 mMockLooper.dispatchAll(); 886 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 887 eq(false), eq(true), eq(true), eq(false)); 888 mDut.onConfigSuccessResponse(transactionId.getValue()); 889 mMockLooper.dispatchAll(); 890 inOrder.verify(mockCallback).onConnectSuccess(clientId); 891 892 // (1) initial subscribe 893 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 894 mMockLooper.dispatchAll(); 895 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 896 eq(subscribeConfig)); 897 898 // (2) subscribe failure 899 mDut.onSessionConfigFailResponse(transactionId.getValue(), false, reasonFail); 900 mMockLooper.dispatchAll(); 901 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 902 validateInternalNoSessions(clientId); 903 904 // (3) subscribe and get immediate failure (i.e. HAL failed) 905 when(mMockNative.subscribe(anyShort(), anyByte(), any())) 906 .thenReturn(false); 907 908 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 909 mMockLooper.dispatchAll(); 910 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 911 eq(subscribeConfig)); 912 913 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 914 validateInternalNoSessions(clientId); 915 916 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 917 } 918 919 /** 920 * Validates the subscribe flow: (1) initial subscribe (2) success (3) 921 * termination (e.g. DONE) (4) update session attempt (5) terminateSession 922 * (6) update session attempt. Expected: session ID callback + session 923 * cleaned-up 924 */ 925 @Test 926 public void testSubscribeSuccessTerminated() throws Exception { 927 final int clientId = 2005; 928 final int uid = 1000; 929 final int pid = 2000; 930 final String callingPackage = "com.google.somePackage"; 931 final int reasonTerminate = NanStatusType.SUCCESS; 932 final byte subscribeId = 15; 933 934 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 935 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 936 937 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 938 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 939 IWifiAwareDiscoverySessionCallback.class); 940 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 941 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 942 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 943 944 mDut.enableUsage(); 945 mMockLooper.dispatchAll(); 946 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 947 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 948 mMockLooper.dispatchAll(); 949 950 // (0) connect 951 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 952 mMockLooper.dispatchAll(); 953 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 954 eq(false), eq(true), eq(true), eq(false)); 955 mDut.onConfigSuccessResponse(transactionId.getValue()); 956 mMockLooper.dispatchAll(); 957 inOrder.verify(mockCallback).onConnectSuccess(clientId); 958 959 // (1) initial subscribe 960 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 961 mMockLooper.dispatchAll(); 962 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 963 eq(subscribeConfig)); 964 965 // (2) subscribe success 966 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 967 mMockLooper.dispatchAll(); 968 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 969 970 // (3) subscribe termination (from firmware - not app!) 971 mDut.onSessionTerminatedNotification(subscribeId, reasonTerminate, false); 972 mMockLooper.dispatchAll(); 973 inOrder.verify(mockSessionCallback).onSessionTerminated(reasonTerminate); 974 975 // (4) app update session (race condition: app didn't get termination 976 // yet) 977 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 978 mMockLooper.dispatchAll(); 979 980 // (5) app terminates session 981 mDut.terminateSession(clientId, sessionId.getValue()); 982 mMockLooper.dispatchAll(); 983 984 // (6) app updates session 985 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 986 mMockLooper.dispatchAll(); 987 988 validateInternalSessionInfoCleanedUp(clientId, sessionId.getValue()); 989 990 verifyNoMoreInteractions(mockSessionCallback, mMockNative); 991 } 992 993 /** 994 * Validate the subscribe flow: (1) initial subscribe + (2) success + (3) update + (4) update 995 * fails (callback from firmware) + (5) update + (6). Expected: session is still alive after 996 * update failure so second update succeeds (no callbacks). + (7) update + immediate failure 997 * from HAL. 998 */ 999 @Test 1000 public void testSubscribeUpdateFail() throws Exception { 1001 final int clientId = 2005; 1002 final int uid = 1000; 1003 final int pid = 2000; 1004 final String callingPackage = "com.google.somePackage"; 1005 final byte subscribeId = 15; 1006 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 1007 1008 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1009 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1010 1011 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1012 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1013 IWifiAwareDiscoverySessionCallback.class); 1014 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1015 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1016 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1017 1018 mDut.enableUsage(); 1019 mMockLooper.dispatchAll(); 1020 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1021 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1022 mMockLooper.dispatchAll(); 1023 1024 // (0) connect 1025 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1026 mMockLooper.dispatchAll(); 1027 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1028 eq(false), eq(true), eq(true), eq(false)); 1029 mDut.onConfigSuccessResponse(transactionId.getValue()); 1030 mMockLooper.dispatchAll(); 1031 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1032 1033 // (1) initial subscribe 1034 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1035 mMockLooper.dispatchAll(); 1036 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1037 eq(subscribeConfig)); 1038 1039 // (2) subscribe success 1040 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1041 mMockLooper.dispatchAll(); 1042 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1043 1044 // (3) update subscribe 1045 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1046 mMockLooper.dispatchAll(); 1047 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1048 eq(subscribeConfig)); 1049 1050 // (4) update fails 1051 mDut.onSessionConfigFailResponse(transactionId.getValue(), false, reasonFail); 1052 mMockLooper.dispatchAll(); 1053 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1054 1055 // (5) another update subscribe 1056 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1057 mMockLooper.dispatchAll(); 1058 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1059 eq(subscribeConfig)); 1060 1061 // (6) update succeeds 1062 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1063 mMockLooper.dispatchAll(); 1064 inOrder.verify(mockSessionCallback).onSessionConfigSuccess(); 1065 1066 // (7) another update + immediate failure 1067 when(mMockNative.subscribe(anyShort(), anyByte(), any())) 1068 .thenReturn(false); 1069 1070 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 1071 mMockLooper.dispatchAll(); 1072 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq(subscribeId), 1073 eq(subscribeConfig)); 1074 inOrder.verify(mockSessionCallback).onSessionConfigFail(reasonFail); 1075 1076 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1077 } 1078 1079 /** 1080 * Validate race condition: subscribe pending but session terminated (due to 1081 * disconnect - can't terminate such a session directly from app). Need to 1082 * make sure that once subscribe succeeds (failure isn't a problem) the 1083 * session is immediately terminated since no-one is listening for it. 1084 */ 1085 @Test 1086 public void testDisconnectWhileSubscribePending() throws Exception { 1087 final int clientId = 2005; 1088 final int uid = 1000; 1089 final int pid = 2000; 1090 final String callingPackage = "com.google.somePackage"; 1091 final byte subscribeId = 15; 1092 1093 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1094 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1095 1096 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1097 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1098 IWifiAwareDiscoverySessionCallback.class); 1099 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1100 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1101 1102 mDut.enableUsage(); 1103 mMockLooper.dispatchAll(); 1104 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1105 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1106 mMockLooper.dispatchAll(); 1107 1108 // (0) connect 1109 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1110 mMockLooper.dispatchAll(); 1111 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1112 eq(false), eq(true), eq(true), eq(false)); 1113 mDut.onConfigSuccessResponse(transactionId.getValue()); 1114 mMockLooper.dispatchAll(); 1115 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1116 1117 // (1) initial subscribe 1118 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1119 mMockLooper.dispatchAll(); 1120 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1121 eq(subscribeConfig)); 1122 1123 // (2) disconnect (but doesn't get executed until get response for 1124 // subscribe command) 1125 mDut.disconnect(clientId); 1126 mMockLooper.dispatchAll(); 1127 1128 // (3) subscribe success 1129 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1130 mMockLooper.dispatchAll(); 1131 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 1132 inOrder.verify(mMockNative).stopSubscribe((short) 0, subscribeId); 1133 inOrder.verify(mMockNative).disable(anyShort()); 1134 1135 validateInternalClientInfoCleanedUp(clientId); 1136 1137 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1138 } 1139 1140 /** 1141 * Validate (1) subscribe (success), (2) match (i.e. discovery), (3) message reception, 1142 * (4) message transmission failed (after ok queuing), (5) message transmission success. 1143 */ 1144 @Test 1145 public void testMatchAndMessages() throws Exception { 1146 final int clientId = 1005; 1147 final int uid = 1000; 1148 final int pid = 2000; 1149 final String callingPackage = "com.google.somePackage"; 1150 final String serviceName = "some-service-name"; 1151 final String ssi = "some much longer and more arbitrary data"; 1152 final int reasonFail = NanStatusType.INTERNAL_FAILURE; 1153 final byte subscribeId = 15; 1154 final int requestorId = 22; 1155 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1156 final String peerSsi = "some peer ssi data"; 1157 final String peerMatchFilter = "filter binary array represented as string"; 1158 final String peerMsg = "some message from peer"; 1159 final int messageId = 6948; 1160 final int messageId2 = 6949; 1161 1162 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1163 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 1164 .setServiceSpecificInfo(ssi.getBytes()) 1165 .setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE) 1166 .build(); 1167 1168 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1169 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1170 IWifiAwareDiscoverySessionCallback.class); 1171 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1172 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1173 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1174 1175 mDut.enableUsage(); 1176 mMockLooper.dispatchAll(); 1177 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1178 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1179 mMockLooper.dispatchAll(); 1180 1181 // (0) connect 1182 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1183 mMockLooper.dispatchAll(); 1184 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 1185 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 1186 mDut.onConfigSuccessResponse(transactionId.getValue()); 1187 mMockLooper.dispatchAll(); 1188 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1189 1190 // (1) subscribe 1191 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1192 mMockLooper.dispatchAll(); 1193 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1194 eq(subscribeConfig)); 1195 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1196 mMockLooper.dispatchAll(); 1197 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1198 1199 // (2) match 1200 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1201 peerMatchFilter.getBytes()); 1202 mMockLooper.dispatchAll(); 1203 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 1204 peerMatchFilter.getBytes()); 1205 1206 // (3) message Rx 1207 mDut.onMessageReceivedNotification(subscribeId, requestorId, peerMac, peerMsg.getBytes()); 1208 mMockLooper.dispatchAll(); 1209 inOrder.verify(mockSessionCallback).onMessageReceived(requestorId, peerMsg.getBytes()); 1210 1211 // (4) message Tx successful queuing 1212 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), messageId, 0); 1213 mMockLooper.dispatchAll(); 1214 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1215 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1216 short tid1 = transactionId.getValue(); 1217 mDut.onMessageSendQueuedSuccessResponse(tid1); 1218 mMockLooper.dispatchAll(); 1219 1220 // (5) message Tx successful queuing 1221 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), messageId2, 1222 0); 1223 mMockLooper.dispatchAll(); 1224 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1225 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId2)); 1226 short tid2 = transactionId.getValue(); 1227 mDut.onMessageSendQueuedSuccessResponse(tid2); 1228 mMockLooper.dispatchAll(); 1229 1230 // (4) and (5) final Tx results (on-air results) 1231 mDut.onMessageSendFailNotification(tid1, reasonFail); 1232 mDut.onMessageSendSuccessNotification(tid2); 1233 mMockLooper.dispatchAll(); 1234 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, reasonFail); 1235 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId2); 1236 validateInternalSendMessageQueuesCleanedUp(messageId); 1237 validateInternalSendMessageQueuesCleanedUp(messageId2); 1238 1239 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1240 } 1241 1242 /** 1243 * Summary: in a single publish session interact with multiple peers 1244 * (different MAC addresses). 1245 */ 1246 @Test 1247 public void testMultipleMessageSources() throws Exception { 1248 final int clientId = 300; 1249 final int uid = 1000; 1250 final int pid = 2000; 1251 final String callingPackage = "com.google.somePackage"; 1252 final int clusterLow = 7; 1253 final int clusterHigh = 7; 1254 final int masterPref = 0; 1255 final String serviceName = "some-service-name"; 1256 final byte publishId = 88; 1257 final int peerId1 = 568; 1258 final int peerId2 = 873; 1259 final byte[] peerMac1 = HexEncoding.decode("000102030405".toCharArray(), false); 1260 final byte[] peerMac2 = HexEncoding.decode("060708090A0B".toCharArray(), false); 1261 final String msgFromPeer1 = "hey from 000102..."; 1262 final String msgFromPeer2 = "hey from 0607..."; 1263 final String msgToPeer1 = "hey there 000102..."; 1264 final String msgToPeer2 = "hey there 0506..."; 1265 final int msgToPeerId1 = 546; 1266 final int msgToPeerId2 = 9654; 1267 final int reason = NanStatusType.INTERNAL_FAILURE; 1268 1269 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 1270 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 1271 1272 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) 1273 .setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 1274 1275 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1276 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1277 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1278 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1279 IWifiAwareDiscoverySessionCallback.class); 1280 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 1281 1282 mDut.enableUsage(); 1283 mMockLooper.dispatchAll(); 1284 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1285 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1286 mMockLooper.dispatchAll(); 1287 1288 // (1) connect 1289 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1290 mMockLooper.dispatchAll(); 1291 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1292 eq(false), eq(true), eq(true), eq(false)); 1293 mDut.onConfigSuccessResponse(transactionId.getValue()); 1294 mMockLooper.dispatchAll(); 1295 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1296 1297 // (2) publish 1298 mDut.publish(clientId, publishConfig, mockSessionCallback); 1299 mMockLooper.dispatchAll(); 1300 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 1301 eq(publishConfig)); 1302 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 1303 mMockLooper.dispatchAll(); 1304 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1305 1306 // (3) message received from peers 1 & 2 1307 mDut.onMessageReceivedNotification(publishId, peerId1, peerMac1, msgFromPeer1.getBytes()); 1308 mDut.onMessageReceivedNotification(publishId, peerId2, peerMac2, msgFromPeer2.getBytes()); 1309 mMockLooper.dispatchAll(); 1310 inOrder.verify(mockSessionCallback).onMessageReceived(peerId1, msgFromPeer1.getBytes()); 1311 inOrder.verify(mockSessionCallback).onMessageReceived(peerId2, msgFromPeer2.getBytes()); 1312 1313 // (4) sending messages back to same peers: one Tx fails, other succeeds 1314 mDut.sendMessage(clientId, sessionId.getValue(), peerId2, msgToPeer2.getBytes(), 1315 msgToPeerId2, 0); 1316 mMockLooper.dispatchAll(); 1317 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), eq(peerId2), 1318 eq(peerMac2), eq(msgToPeer2.getBytes()), eq(msgToPeerId2)); 1319 short transactionIdVal = transactionId.getValue(); 1320 mDut.onMessageSendQueuedSuccessResponse(transactionIdVal); 1321 mDut.onMessageSendSuccessNotification(transactionIdVal); 1322 1323 mDut.sendMessage(clientId, sessionId.getValue(), peerId1, msgToPeer1.getBytes(), 1324 msgToPeerId1, 0); 1325 mMockLooper.dispatchAll(); 1326 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId2); 1327 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), eq(peerId1), 1328 eq(peerMac1), eq(msgToPeer1.getBytes()), eq(msgToPeerId1)); 1329 transactionIdVal = transactionId.getValue(); 1330 mDut.onMessageSendQueuedSuccessResponse(transactionIdVal); 1331 mDut.onMessageSendFailNotification(transactionIdVal, reason); 1332 mMockLooper.dispatchAll(); 1333 inOrder.verify(mockSessionCallback).onMessageSendFail(msgToPeerId1, reason); 1334 validateInternalSendMessageQueuesCleanedUp(msgToPeerId1); 1335 validateInternalSendMessageQueuesCleanedUp(msgToPeerId2); 1336 1337 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 1338 } 1339 1340 /** 1341 * Summary: interact with a peer which changed its identity (MAC address) 1342 * but which keeps its requestor instance ID. Should be transparent. 1343 */ 1344 @Test 1345 public void testMessageWhilePeerChangesIdentity() throws Exception { 1346 final int clientId = 300; 1347 final int uid = 1000; 1348 final int pid = 2000; 1349 final String callingPackage = "com.google.somePackage"; 1350 final int clusterLow = 7; 1351 final int clusterHigh = 7; 1352 final int masterPref = 0; 1353 final String serviceName = "some-service-name"; 1354 final byte publishId = 88; 1355 final int peerId = 568; 1356 final byte[] peerMacOrig = HexEncoding.decode("000102030405".toCharArray(), false); 1357 final byte[] peerMacLater = HexEncoding.decode("060708090A0B".toCharArray(), false); 1358 final String msgFromPeer1 = "hey from 000102..."; 1359 final String msgFromPeer2 = "hey from 0607..."; 1360 final String msgToPeer1 = "hey there 000102..."; 1361 final String msgToPeer2 = "hey there 0506..."; 1362 final int msgToPeerId1 = 546; 1363 final int msgToPeerId2 = 9654; 1364 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 1365 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 1366 1367 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) 1368 .setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 1369 1370 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1371 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1372 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1373 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1374 IWifiAwareDiscoverySessionCallback.class); 1375 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 1376 1377 mDut.enableUsage(); 1378 mMockLooper.dispatchAll(); 1379 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1380 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1381 mMockLooper.dispatchAll(); 1382 1383 // (1) connect 1384 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1385 mMockLooper.dispatchAll(); 1386 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1387 eq(false), eq(true), eq(true), eq(false)); 1388 mDut.onConfigSuccessResponse(transactionId.getValue()); 1389 mMockLooper.dispatchAll(); 1390 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1391 1392 // (2) publish 1393 mDut.publish(clientId, publishConfig, mockSessionCallback); 1394 mMockLooper.dispatchAll(); 1395 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 1396 eq(publishConfig)); 1397 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 1398 mMockLooper.dispatchAll(); 1399 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1400 1401 // (3) message received & responded to 1402 mDut.onMessageReceivedNotification(publishId, peerId, peerMacOrig, msgFromPeer1.getBytes()); 1403 mDut.sendMessage(clientId, sessionId.getValue(), peerId, msgToPeer1.getBytes(), 1404 msgToPeerId1, 0); 1405 mMockLooper.dispatchAll(); 1406 inOrder.verify(mockSessionCallback).onMessageReceived(peerId, msgFromPeer1.getBytes()); 1407 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), eq(peerId), 1408 eq(peerMacOrig), eq(msgToPeer1.getBytes()), eq(msgToPeerId1)); 1409 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1410 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1411 mMockLooper.dispatchAll(); 1412 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId1); 1413 validateInternalSendMessageQueuesCleanedUp(msgToPeerId1); 1414 1415 // (4) message received with same peer ID but different MAC 1416 mDut.onMessageReceivedNotification(publishId, peerId, peerMacLater, 1417 msgFromPeer2.getBytes()); 1418 mDut.sendMessage(clientId, sessionId.getValue(), peerId, msgToPeer2.getBytes(), 1419 msgToPeerId2, 0); 1420 mMockLooper.dispatchAll(); 1421 inOrder.verify(mockSessionCallback).onMessageReceived(peerId, msgFromPeer2.getBytes()); 1422 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(publishId), eq(peerId), 1423 eq(peerMacLater), eq(msgToPeer2.getBytes()), eq(msgToPeerId2)); 1424 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1425 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1426 mMockLooper.dispatchAll(); 1427 inOrder.verify(mockSessionCallback).onMessageSendSuccess(msgToPeerId2); 1428 validateInternalSendMessageQueuesCleanedUp(msgToPeerId2); 1429 1430 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 1431 } 1432 1433 /** 1434 * Validate that get failure (with correct code) when trying to send a 1435 * message to an invalid peer ID. 1436 */ 1437 @Test 1438 public void testSendMessageToInvalidPeerId() throws Exception { 1439 final int clientId = 1005; 1440 final int uid = 1000; 1441 final int pid = 2000; 1442 final String callingPackage = "com.google.somePackage"; 1443 final String ssi = "some much longer and more arbitrary data"; 1444 final byte subscribeId = 15; 1445 final int requestorId = 22; 1446 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1447 final String peerSsi = "some peer ssi data"; 1448 final String peerMatchFilter = "filter binary array represented as string"; 1449 final int messageId = 6948; 1450 1451 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1452 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1453 1454 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1455 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1456 IWifiAwareDiscoverySessionCallback.class); 1457 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1458 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1459 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1460 1461 mDut.enableUsage(); 1462 mMockLooper.dispatchAll(); 1463 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1464 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1465 mMockLooper.dispatchAll(); 1466 1467 // (1) connect 1468 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1469 mMockLooper.dispatchAll(); 1470 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1471 eq(false), eq(true), eq(true), eq(false)); 1472 mDut.onConfigSuccessResponse(transactionId.getValue()); 1473 mMockLooper.dispatchAll(); 1474 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1475 1476 // (2) subscribe & match 1477 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1478 mMockLooper.dispatchAll(); 1479 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1480 eq(subscribeConfig)); 1481 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1482 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1483 peerMatchFilter.getBytes()); 1484 mMockLooper.dispatchAll(); 1485 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1486 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 1487 peerMatchFilter.getBytes()); 1488 1489 // (3) send message to invalid peer ID 1490 mDut.sendMessage(clientId, sessionId.getValue(), requestorId + 5, ssi.getBytes(), 1491 messageId, 0); 1492 mMockLooper.dispatchAll(); 1493 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 1494 NanStatusType.INTERNAL_FAILURE); 1495 validateInternalSendMessageQueuesCleanedUp(messageId); 1496 1497 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1498 } 1499 1500 /** 1501 * Validate that on send message errors are handled correctly: immediate send error, queue fail 1502 * error (not queue full), and timeout. Behavior: correct callback is dispatched and a later 1503 * firmware notification is ignored. Intersperse with one successfull transmission. 1504 */ 1505 @Test 1506 public void testSendMessageErrorsImmediateQueueTimeout() throws Exception { 1507 final int clientId = 1005; 1508 final int uid = 1000; 1509 final int pid = 2000; 1510 final String callingPackage = "com.google.somePackage"; 1511 final String ssi = "some much longer and more arbitrary data"; 1512 final byte subscribeId = 15; 1513 final int requestorId = 22; 1514 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1515 final String peerSsi = "some peer ssi data"; 1516 final String peerMatchFilter = "filter binary array represented as string"; 1517 final int messageId = 6948; 1518 1519 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1520 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1521 1522 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1523 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1524 IWifiAwareDiscoverySessionCallback.class); 1525 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1526 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1527 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1528 1529 mDut.enableUsage(); 1530 mMockLooper.dispatchAll(); 1531 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1532 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1533 mMockLooper.dispatchAll(); 1534 1535 // (1) connect 1536 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1537 mMockLooper.dispatchAll(); 1538 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1539 eq(false), eq(true), eq(true), eq(false)); 1540 mDut.onConfigSuccessResponse(transactionId.getValue()); 1541 mMockLooper.dispatchAll(); 1542 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1543 1544 // (2) subscribe & match 1545 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1546 mMockLooper.dispatchAll(); 1547 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1548 eq(subscribeConfig)); 1549 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1550 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1551 peerMatchFilter.getBytes()); 1552 mMockLooper.dispatchAll(); 1553 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1554 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 1555 peerMatchFilter.getBytes()); 1556 1557 // (3) send 2 messages and enqueue successfully 1558 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), 1559 messageId, 0); 1560 mMockLooper.dispatchAll(); 1561 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1562 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1563 short transactionId1 = transactionId.getValue(); 1564 mDut.onMessageSendQueuedSuccessResponse(transactionId1); 1565 mMockLooper.dispatchAll(); 1566 1567 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), 1568 messageId + 1, 0); 1569 mMockLooper.dispatchAll(); 1570 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1571 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 1)); 1572 short transactionId2 = transactionId.getValue(); 1573 mDut.onMessageSendQueuedSuccessResponse(transactionId2); 1574 mMockLooper.dispatchAll(); 1575 1576 // (4) send a message and get a queueing failure (not queue full) 1577 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), messageId + 2, 1578 0); 1579 mMockLooper.dispatchAll(); 1580 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1581 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 2)); 1582 short transactionId3 = transactionId.getValue(); 1583 mDut.onMessageSendQueuedFailResponse(transactionId3, NanStatusType.INTERNAL_FAILURE); 1584 mMockLooper.dispatchAll(); 1585 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId + 2, 1586 NanStatusType.INTERNAL_FAILURE); 1587 validateInternalSendMessageQueuesCleanedUp(messageId + 2); 1588 1589 // (5) send a message and get an immediate failure (configure first) 1590 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 1591 any(), anyInt())).thenReturn(false); 1592 1593 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), messageId + 3, 1594 0); 1595 mMockLooper.dispatchAll(); 1596 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1597 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId + 3)); 1598 short transactionId4 = transactionId.getValue(); 1599 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId + 3, 1600 NanStatusType.INTERNAL_FAILURE); 1601 validateInternalSendMessageQueuesCleanedUp(messageId + 3); 1602 1603 // (6) message send timeout 1604 assertTrue(mAlarmManager.dispatch(WifiAwareStateManager.HAL_SEND_MESSAGE_TIMEOUT_TAG)); 1605 mMockLooper.dispatchAll(); 1606 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 1607 NanStatusType.INTERNAL_FAILURE); 1608 validateInternalSendMessageQueuesCleanedUp(messageId); 1609 1610 // (7) firmware response (unlikely - but good to check) 1611 mDut.onMessageSendSuccessNotification(transactionId1); 1612 mDut.onMessageSendSuccessNotification(transactionId2); 1613 1614 // bogus: these didn't even go to firmware or weren't queued 1615 mDut.onMessageSendSuccessNotification(transactionId3); 1616 mDut.onMessageSendFailNotification(transactionId4, NanStatusType.INTERNAL_FAILURE); 1617 mMockLooper.dispatchAll(); 1618 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId + 1); 1619 1620 validateInternalSendMessageQueuesCleanedUp(messageId + 1); 1621 1622 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1623 } 1624 1625 /** 1626 * Validate that when sending a message with a retry count the message is retried the specified 1627 * number of times. Scenario ending with success. 1628 */ 1629 @Test 1630 public void testSendMessageRetransmitSuccess() throws Exception { 1631 final int clientId = 1005; 1632 final int uid = 1000; 1633 final int pid = 2000; 1634 final String callingPackage = "com.google.somePackage"; 1635 final String ssi = "some much longer and more arbitrary data"; 1636 final byte subscribeId = 15; 1637 final int requestorId = 22; 1638 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1639 final String peerSsi = "some peer ssi data"; 1640 final String peerMatchFilter = "filter binary array represented as string"; 1641 final int messageId = 6948; 1642 final int retryCount = 3; 1643 1644 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1645 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1646 1647 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1648 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1649 IWifiAwareDiscoverySessionCallback.class); 1650 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1651 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1652 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1653 1654 mDut.enableUsage(); 1655 mMockLooper.dispatchAll(); 1656 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1657 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1658 mMockLooper.dispatchAll(); 1659 1660 // (1) connect 1661 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1662 mMockLooper.dispatchAll(); 1663 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1664 eq(false), eq(true), eq(true), eq(false)); 1665 mDut.onConfigSuccessResponse(transactionId.getValue()); 1666 mMockLooper.dispatchAll(); 1667 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1668 1669 // (2) subscribe & match 1670 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1671 mMockLooper.dispatchAll(); 1672 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1673 eq(subscribeConfig)); 1674 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1675 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1676 peerMatchFilter.getBytes()); 1677 mMockLooper.dispatchAll(); 1678 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1679 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 1680 peerMatchFilter.getBytes()); 1681 1682 // (3) send message and enqueue successfully 1683 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), 1684 messageId, retryCount); 1685 mMockLooper.dispatchAll(); 1686 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1687 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1688 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1689 mMockLooper.dispatchAll(); 1690 1691 // (4) loop and fail until reach retryCount 1692 for (int i = 0; i < retryCount; ++i) { 1693 mDut.onMessageSendFailNotification(transactionId.getValue(), NanStatusType.NO_OTA_ACK); 1694 mMockLooper.dispatchAll(); 1695 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1696 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1697 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1698 mMockLooper.dispatchAll(); 1699 } 1700 1701 // (5) succeed on last retry 1702 mDut.onMessageSendSuccessNotification(transactionId.getValue()); 1703 mMockLooper.dispatchAll(); 1704 1705 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 1706 validateInternalSendMessageQueuesCleanedUp(messageId); 1707 1708 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1709 } 1710 1711 /** 1712 * Validate that when sending a message with a retry count the message is retried the specified 1713 * number of times. Scenario ending with failure. 1714 */ 1715 @Test 1716 public void testSendMessageRetransmitFail() throws Exception { 1717 final int clientId = 1005; 1718 final int uid = 1000; 1719 final int pid = 2000; 1720 final String callingPackage = "com.google.somePackage"; 1721 final String ssi = "some much longer and more arbitrary data"; 1722 final byte subscribeId = 15; 1723 final int requestorId = 22; 1724 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1725 final String peerSsi = "some peer ssi data"; 1726 final String peerMatchFilter = "filter binary array represented as string"; 1727 final int messageId = 6948; 1728 final int retryCount = 3; 1729 1730 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1731 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 1732 1733 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1734 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1735 IWifiAwareDiscoverySessionCallback.class); 1736 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1737 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1738 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1739 1740 mDut.enableUsage(); 1741 mMockLooper.dispatchAll(); 1742 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1743 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1744 mMockLooper.dispatchAll(); 1745 1746 // (1) connect 1747 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1748 mMockLooper.dispatchAll(); 1749 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 1750 eq(false), eq(true), eq(true), eq(false)); 1751 mDut.onConfigSuccessResponse(transactionId.getValue()); 1752 mMockLooper.dispatchAll(); 1753 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1754 1755 // (2) subscribe & match 1756 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1757 mMockLooper.dispatchAll(); 1758 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1759 eq(subscribeConfig)); 1760 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1761 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 1762 peerMatchFilter.getBytes()); 1763 mMockLooper.dispatchAll(); 1764 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1765 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 1766 peerMatchFilter.getBytes()); 1767 1768 // (3) send message and enqueue successfully 1769 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, ssi.getBytes(), messageId, 1770 retryCount); 1771 mMockLooper.dispatchAll(); 1772 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1773 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1774 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1775 mMockLooper.dispatchAll(); 1776 1777 // (4) loop and fail until reach retryCount+1 1778 for (int i = 0; i < retryCount + 1; ++i) { 1779 mDut.onMessageSendFailNotification(transactionId.getValue(), NanStatusType.NO_OTA_ACK); 1780 mMockLooper.dispatchAll(); 1781 1782 if (i != retryCount) { 1783 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 1784 eq(requestorId), eq(peerMac), eq(ssi.getBytes()), eq(messageId)); 1785 mDut.onMessageSendQueuedSuccessResponse(transactionId.getValue()); 1786 mMockLooper.dispatchAll(); 1787 } 1788 } 1789 1790 inOrder.verify(mockSessionCallback).onMessageSendFail(messageId, 1791 NanStatusType.NO_OTA_ACK); 1792 validateInternalSendMessageQueuesCleanedUp(messageId); 1793 1794 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 1795 } 1796 1797 /** 1798 * Validate that the host-side message queue functions. Tests the perfect case of queue always 1799 * succeeds and all messages are received on first attempt. 1800 */ 1801 @Test 1802 public void testSendMessageQueueSequence() throws Exception { 1803 final int clientId = 1005; 1804 final int uid = 1000; 1805 final int pid = 2000; 1806 final String callingPackage = "com.google.somePackage"; 1807 final String serviceName = "some-service-name"; 1808 final byte subscribeId = 15; 1809 final int requestorId = 22; 1810 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1811 final int messageIdBase = 6948; 1812 final int numberOfMessages = 30; 1813 final int queueDepth = 6; 1814 1815 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1816 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 1817 .build(); 1818 1819 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1820 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1821 IWifiAwareDiscoverySessionCallback.class); 1822 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1823 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1824 ArgumentCaptor<Integer> messageIdCaptor = ArgumentCaptor.forClass(Integer.class); 1825 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1826 1827 mDut.enableUsage(); 1828 mMockLooper.dispatchAll(); 1829 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1830 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1831 mMockLooper.dispatchAll(); 1832 1833 // (0) connect 1834 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1835 mMockLooper.dispatchAll(); 1836 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 1837 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 1838 mDut.onConfigSuccessResponse(transactionId.getValue()); 1839 mMockLooper.dispatchAll(); 1840 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1841 1842 // (1) subscribe 1843 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1844 mMockLooper.dispatchAll(); 1845 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1846 eq(subscribeConfig)); 1847 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1848 mMockLooper.dispatchAll(); 1849 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1850 1851 // (2) match 1852 mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null); 1853 mMockLooper.dispatchAll(); 1854 inOrder.verify(mockSessionCallback).onMatch(requestorId, null, null); 1855 1856 // (3) transmit messages 1857 SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, 1858 null, null, null); 1859 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 1860 any(), anyInt())).thenAnswer(answerObj); 1861 1862 int remainingMessages = numberOfMessages; 1863 for (int i = 0; i < numberOfMessages; ++i) { 1864 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, null, messageIdBase + i, 1865 0); 1866 mMockLooper.dispatchAll(); 1867 // at 1/2 interval have the system simulate transmitting a queued message over-the-air 1868 if (i % 2 == 1) { 1869 assertTrue(answerObj.process()); 1870 remainingMessages--; 1871 mMockLooper.dispatchAll(); 1872 } 1873 } 1874 for (int i = 0; i < remainingMessages; ++i) { 1875 assertTrue(answerObj.process()); 1876 mMockLooper.dispatchAll(); 1877 } 1878 assertEquals("queue empty", 0, answerObj.queueSize()); 1879 1880 inOrder.verify(mockSessionCallback, times(numberOfMessages)).onMessageSendSuccess( 1881 messageIdCaptor.capture()); 1882 for (int i = 0; i < numberOfMessages; ++i) { 1883 assertEquals("message ID: " + i, (long) messageIdBase + i, 1884 (long) messageIdCaptor.getAllValues().get(i)); 1885 } 1886 1887 verifyNoMoreInteractions(mockCallback, mockSessionCallback); 1888 } 1889 1890 /** 1891 * Validate that the host-side message queue functions. A combination of imperfect conditions: 1892 * - Failure to queue: synchronous firmware error 1893 * - Failure to queue: asyncronous firmware error 1894 * - Failure to transmit: OTA (which will be retried) 1895 * - Failure to transmit: other 1896 */ 1897 @Test 1898 public void testSendMessageQueueSequenceImperfect() throws Exception { 1899 final int clientId = 1005; 1900 final int uid = 1000; 1901 final int pid = 2000; 1902 final String callingPackage = "com.google.somePackage"; 1903 final String serviceName = "some-service-name"; 1904 final byte subscribeId = 15; 1905 final int requestorId = 22; 1906 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 1907 final int messageIdBase = 6948; 1908 final int numberOfMessages = 300; 1909 final int queueDepth = 6; 1910 final int retransmitCount = 3; // not the maximum 1911 1912 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 1913 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 1914 .build(); 1915 1916 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 1917 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 1918 IWifiAwareDiscoverySessionCallback.class); 1919 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 1920 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 1921 ArgumentCaptor<Integer> messageIdCaptor = ArgumentCaptor.forClass(Integer.class); 1922 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 1923 1924 mDut.enableUsage(); 1925 mMockLooper.dispatchAll(); 1926 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 1927 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 1928 mMockLooper.dispatchAll(); 1929 1930 // (0) connect 1931 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 1932 mMockLooper.dispatchAll(); 1933 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 1934 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 1935 mDut.onConfigSuccessResponse(transactionId.getValue()); 1936 mMockLooper.dispatchAll(); 1937 inOrder.verify(mockCallback).onConnectSuccess(clientId); 1938 1939 // (1) subscribe 1940 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 1941 mMockLooper.dispatchAll(); 1942 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 1943 eq(subscribeConfig)); 1944 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 1945 mMockLooper.dispatchAll(); 1946 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 1947 1948 // (2) match 1949 mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null); 1950 mMockLooper.dispatchAll(); 1951 inOrder.verify(mockSessionCallback).onMatch(requestorId, null, null); 1952 1953 // (3) transmit messages: configure a mix of failures/success 1954 Set<Integer> failQueueCommandImmediately = new HashSet<>(); 1955 Set<Integer> failQueueCommandLater = new HashSet<>(); 1956 Map<Integer, Integer> numberOfRetries = new HashMap<>(); 1957 1958 int numOfSuccesses = 0; 1959 int numOfFailuresInternalFailure = 0; 1960 int numOfFailuresNoOta = 0; 1961 for (int i = 0; i < numberOfMessages; ++i) { 1962 // random results: 1963 // - 0-50: success 1964 // - 51-60: retransmit value (which will fail for >5) 1965 // - 61-70: fail queue later 1966 // - 71-80: fail queue immediately 1967 // - 81-90: fail retransmit with non-OTA failure 1968 int random = mRandomNg.nextInt(90); 1969 if (random <= 50) { 1970 numberOfRetries.put(messageIdBase + i, 0); 1971 numOfSuccesses++; 1972 } else if (random <= 60) { 1973 numberOfRetries.put(messageIdBase + i, random - 51); 1974 if (random - 51 > retransmitCount) { 1975 numOfFailuresNoOta++; 1976 } else { 1977 numOfSuccesses++; 1978 } 1979 } else if (random <= 70) { 1980 failQueueCommandLater.add(messageIdBase + i); 1981 numOfFailuresInternalFailure++; 1982 } else if (random <= 80) { 1983 failQueueCommandImmediately.add(messageIdBase + i); 1984 numOfFailuresInternalFailure++; 1985 } else { 1986 numberOfRetries.put(messageIdBase + i, -1); 1987 numOfFailuresInternalFailure++; 1988 } 1989 } 1990 1991 Log.v("WifiAwareStateManagerTest", 1992 "failQueueCommandImmediately=" + failQueueCommandImmediately 1993 + ", failQueueCommandLater=" + failQueueCommandLater + ", numberOfRetries=" 1994 + numberOfRetries + ", numOfSuccesses=" + numOfSuccesses 1995 + ", numOfFailuresInternalFailure=" + numOfFailuresInternalFailure 1996 + ", numOfFailuresNoOta=" + numOfFailuresNoOta); 1997 1998 SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, 1999 failQueueCommandImmediately, failQueueCommandLater, numberOfRetries); 2000 when(mMockNative.sendMessage(anyShort(), anyByte(), anyInt(), any(), 2001 any(), anyInt())).thenAnswer(answerObj); 2002 2003 for (int i = 0; i < numberOfMessages; ++i) { 2004 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, null, messageIdBase + i, 2005 retransmitCount); 2006 mMockLooper.dispatchAll(); 2007 } 2008 2009 while (answerObj.queueSize() != 0) { 2010 assertTrue(answerObj.process()); 2011 mMockLooper.dispatchAll(); 2012 } 2013 2014 verify(mockSessionCallback, times(numOfSuccesses)).onMessageSendSuccess(anyInt()); 2015 verify(mockSessionCallback, times(numOfFailuresInternalFailure)).onMessageSendFail(anyInt(), 2016 eq(NanStatusType.INTERNAL_FAILURE)); 2017 verify(mockSessionCallback, times(numOfFailuresNoOta)).onMessageSendFail(anyInt(), 2018 eq(NanStatusType.NO_OTA_ACK)); 2019 2020 verifyNoMoreInteractions(mockCallback, mockSessionCallback); 2021 } 2022 2023 /** 2024 * Validate that can send empty message successfully: null, byte[0], "" 2025 */ 2026 @Test 2027 public void testSendEmptyMessages() throws Exception { 2028 final int clientId = 1005; 2029 final int uid = 1000; 2030 final int pid = 2000; 2031 final String callingPackage = "com.google.somePackage"; 2032 final String serviceName = "some-service-name"; 2033 final String ssi = "some much longer and more arbitrary data"; 2034 final byte subscribeId = 15; 2035 final int requestorId = 22; 2036 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 2037 final String peerSsi = "some peer ssi data"; 2038 final String peerMatchFilter = "filter binary array represented as string"; 2039 final int messageId = 6948; 2040 2041 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2042 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) 2043 .setServiceSpecificInfo(ssi.getBytes()) 2044 .setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE) 2045 .build(); 2046 2047 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2048 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2049 IWifiAwareDiscoverySessionCallback.class); 2050 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2051 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2052 ArgumentCaptor<byte[]> byteArrayCaptor = ArgumentCaptor.forClass(byte[].class); 2053 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative); 2054 2055 mDut.enableUsage(); 2056 mMockLooper.dispatchAll(); 2057 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2058 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2059 mMockLooper.dispatchAll(); 2060 2061 // (0) connect 2062 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2063 mMockLooper.dispatchAll(); 2064 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2065 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2066 mDut.onConfigSuccessResponse(transactionId.getValue()); 2067 mMockLooper.dispatchAll(); 2068 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2069 2070 // (1) subscribe 2071 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2072 mMockLooper.dispatchAll(); 2073 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2074 eq(subscribeConfig)); 2075 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2076 mMockLooper.dispatchAll(); 2077 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2078 2079 // (2) match 2080 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 2081 peerMatchFilter.getBytes()); 2082 mMockLooper.dispatchAll(); 2083 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 2084 peerMatchFilter.getBytes()); 2085 2086 // (3) message null Tx successful queuing 2087 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, null, messageId, 0); 2088 mMockLooper.dispatchAll(); 2089 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2090 eq(requestorId), eq(peerMac), isNull(byte[].class), eq(messageId)); 2091 short tid = transactionId.getValue(); 2092 mDut.onMessageSendQueuedSuccessResponse(tid); 2093 mMockLooper.dispatchAll(); 2094 2095 // (4) final Tx results (on-air results) 2096 mDut.onMessageSendSuccessNotification(tid); 2097 mMockLooper.dispatchAll(); 2098 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2099 validateInternalSendMessageQueuesCleanedUp(messageId); 2100 2101 // (5) message byte[0] Tx successful queuing 2102 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, new byte[0], messageId, 0); 2103 mMockLooper.dispatchAll(); 2104 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2105 eq(requestorId), eq(peerMac), eq(new byte[0]), eq(messageId)); 2106 tid = transactionId.getValue(); 2107 mDut.onMessageSendQueuedSuccessResponse(tid); 2108 mMockLooper.dispatchAll(); 2109 2110 // (6) final Tx results (on-air results) 2111 mDut.onMessageSendSuccessNotification(tid); 2112 mMockLooper.dispatchAll(); 2113 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2114 validateInternalSendMessageQueuesCleanedUp(messageId); 2115 2116 // (7) message "" Tx successful queuing 2117 mDut.sendMessage(clientId, sessionId.getValue(), requestorId, "".getBytes(), messageId, 0); 2118 mMockLooper.dispatchAll(); 2119 inOrder.verify(mMockNative).sendMessage(transactionId.capture(), eq(subscribeId), 2120 eq(requestorId), eq(peerMac), byteArrayCaptor.capture(), eq(messageId)); 2121 collector.checkThat("Empty message contents", "", 2122 equalTo(new String(byteArrayCaptor.getValue()))); 2123 tid = transactionId.getValue(); 2124 mDut.onMessageSendQueuedSuccessResponse(tid); 2125 mMockLooper.dispatchAll(); 2126 2127 // (8) final Tx results (on-air results) 2128 mDut.onMessageSendSuccessNotification(tid); 2129 mMockLooper.dispatchAll(); 2130 inOrder.verify(mockSessionCallback).onMessageSendSuccess(messageId); 2131 validateInternalSendMessageQueuesCleanedUp(messageId); 2132 2133 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative); 2134 } 2135 2136 private class SendMessageQueueModelAnswer extends MockAnswerUtil.AnswerWithArguments { 2137 private final int mMaxQueueDepth; 2138 2139 // keyed by message ID 2140 private final Set<Integer> mFailQueueCommandImmediately; // return a false 2141 private final Set<Integer> mFailQueueCommandLater; // return an error != TX_QUEUE_FULL 2142 2143 // # of times to return NO_OTA_ACK before returning SUCCESS. So a 0 means success on first 2144 // try, a very large number means - never succeed (since max retry is 5). 2145 // a -1 impiles a non-OTA failure: on first attempt 2146 private final Map<Integer, Integer> mRetryLimit; 2147 2148 private final LinkedList<Short> mQueue = new LinkedList<>(); // transaction ID (tid) 2149 private final Map<Short, Integer> mMessageIdsByTid = new HashMap<>(); // tid -> message ID 2150 private final Map<Integer, Integer> mTriesUsedByMid = new HashMap<>(); // mid -> # of retx 2151 2152 SendMessageQueueModelAnswer(int maxQueueDepth, Set<Integer> failQueueCommandImmediately, 2153 Set<Integer> failQueueCommandLater, Map<Integer, Integer> numberOfRetries) { 2154 mMaxQueueDepth = maxQueueDepth; 2155 mFailQueueCommandImmediately = failQueueCommandImmediately; 2156 mFailQueueCommandLater = failQueueCommandLater; 2157 mRetryLimit = numberOfRetries; 2158 2159 if (mRetryLimit != null) { 2160 for (int mid : mRetryLimit.keySet()) { 2161 mTriesUsedByMid.put(mid, 0); 2162 } 2163 } 2164 } 2165 2166 public boolean answer(short transactionId, byte pubSubId, int requestorInstanceId, 2167 byte[] dest, byte[] message, int messageId) throws Exception { 2168 if (mFailQueueCommandImmediately != null && mFailQueueCommandImmediately.contains( 2169 messageId)) { 2170 return false; 2171 } 2172 2173 if (mFailQueueCommandLater != null && mFailQueueCommandLater.contains(messageId)) { 2174 mDut.onMessageSendQueuedFailResponse(transactionId, NanStatusType.INTERNAL_FAILURE); 2175 } else { 2176 if (mQueue.size() <= mMaxQueueDepth) { 2177 mQueue.addLast(transactionId); 2178 mMessageIdsByTid.put(transactionId, messageId); 2179 mDut.onMessageSendQueuedSuccessResponse(transactionId); 2180 } else { 2181 mDut.onMessageSendQueuedFailResponse(transactionId, 2182 NanStatusType.FOLLOWUP_TX_QUEUE_FULL); 2183 } 2184 } 2185 2186 return true; 2187 } 2188 2189 /** 2190 * Processes the first message in the queue: i.e. responds as if sent over-the-air 2191 * (successfully or failed) 2192 */ 2193 boolean process() { 2194 if (mQueue.size() == 0) { 2195 return false; 2196 } 2197 short tid = mQueue.poll(); 2198 int mid = mMessageIdsByTid.get(tid); 2199 2200 if (mRetryLimit != null && mRetryLimit.containsKey(mid)) { 2201 int numRetries = mRetryLimit.get(mid); 2202 if (numRetries == -1) { 2203 mDut.onMessageSendFailNotification(tid, NanStatusType.INTERNAL_FAILURE); 2204 } else { 2205 int currentRetries = mTriesUsedByMid.get(mid); 2206 if (currentRetries > numRetries) { 2207 return false; // shouldn't be retrying!? 2208 } else if (currentRetries == numRetries) { 2209 mDut.onMessageSendSuccessNotification(tid); 2210 } else { 2211 mDut.onMessageSendFailNotification(tid, NanStatusType.NO_OTA_ACK); 2212 } 2213 mTriesUsedByMid.put(mid, currentRetries + 1); 2214 } 2215 } else { 2216 mDut.onMessageSendSuccessNotification(tid); 2217 } 2218 2219 return true; 2220 } 2221 2222 /** 2223 * Returns the number of elements in the queue. 2224 */ 2225 int queueSize() { 2226 return mQueue.size(); 2227 } 2228 } 2229 2230 /** 2231 * Validate that start ranging function fills-in correct MAC addresses for peer IDs and 2232 * passed along to RTT module. 2233 */ 2234 @Test 2235 public void testStartRanging() throws Exception { 2236 final int clientId = 1005; 2237 final int uid = 1000; 2238 final int pid = 2000; 2239 final String callingPackage = "com.google.somePackage"; 2240 final byte subscribeId = 15; 2241 final int requestorId = 22; 2242 final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false); 2243 final String peerSsi = "some peer ssi data"; 2244 final String peerMatchFilter = "filter binary array represented as string"; 2245 final int rangingId = 18423; 2246 final RttManager.RttParams[] params = new RttManager.RttParams[2]; 2247 params[0] = new RttManager.RttParams(); 2248 params[0].bssid = Integer.toString(requestorId); 2249 params[1] = new RttManager.RttParams(); 2250 params[1].bssid = Integer.toString(requestorId + 5); 2251 2252 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2253 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 2254 2255 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2256 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2257 IWifiAwareDiscoverySessionCallback.class); 2258 2259 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2260 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2261 ArgumentCaptor<WifiAwareClientState> clientCaptor = 2262 ArgumentCaptor.forClass(WifiAwareClientState.class); 2263 ArgumentCaptor<RttManager.RttParams[]> rttParamsCaptor = 2264 ArgumentCaptor.forClass(RttManager.RttParams[].class); 2265 2266 InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative, 2267 mMockAwareRttStateManager); 2268 2269 mDut.enableUsage(); 2270 mMockLooper.dispatchAll(); 2271 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2272 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2273 mMockLooper.dispatchAll(); 2274 2275 // (1) connect 2276 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2277 mMockLooper.dispatchAll(); 2278 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2279 eq(false), eq(true), eq(true), eq(false)); 2280 mDut.onConfigSuccessResponse(transactionId.getValue()); 2281 mMockLooper.dispatchAll(); 2282 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2283 2284 // (2) subscribe & match 2285 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2286 mMockLooper.dispatchAll(); 2287 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2288 eq(subscribeConfig)); 2289 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2290 mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), 2291 peerMatchFilter.getBytes()); 2292 mMockLooper.dispatchAll(); 2293 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2294 inOrder.verify(mockSessionCallback).onMatch(requestorId, peerSsi.getBytes(), 2295 peerMatchFilter.getBytes()); 2296 2297 // (3) start ranging: pass along a valid peer ID and an invalid one 2298 mDut.startRanging(clientId, sessionId.getValue(), params, rangingId); 2299 mMockLooper.dispatchAll(); 2300 inOrder.verify(mMockAwareRttStateManager).startRanging(eq(rangingId), 2301 clientCaptor.capture(), rttParamsCaptor.capture()); 2302 collector.checkThat("RttParams[0].bssid", "06:07:08:09:0A:0B", 2303 equalTo(rttParamsCaptor.getValue()[0].bssid)); 2304 collector.checkThat("RttParams[1].bssid", "", equalTo(rttParamsCaptor.getValue()[1].bssid)); 2305 2306 verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative, 2307 mMockAwareRttStateManager); 2308 } 2309 2310 /** 2311 * Test sequence of configuration: (1) config1, (2) config2 - incompatible, 2312 * (3) config3 - compatible with config1 (requiring upgrade), (4) disconnect 2313 * config3 (should get a downgrade), (5) disconnect config1 (should get a 2314 * disable). 2315 */ 2316 @Test 2317 public void testConfigs() throws Exception { 2318 final int clientId1 = 9999; 2319 final int clientId2 = 1001; 2320 final int clientId3 = 1005; 2321 final int uid = 1000; 2322 final int pid = 2000; 2323 final String callingPackage = "com.google.somePackage"; 2324 final int masterPref1 = 111; 2325 final int masterPref3 = 115; 2326 final int dwInterval1Band24 = 2; 2327 final int dwInterval3Band24 = 1; 2328 final int dwInterval3Band5 = 0; 2329 2330 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2331 ArgumentCaptor<ConfigRequest> crCapture = ArgumentCaptor.forClass(ConfigRequest.class); 2332 2333 ConfigRequest configRequest1 = new ConfigRequest.Builder() 2334 .setClusterLow(5).setClusterHigh(100) 2335 .setMasterPreference(masterPref1) 2336 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval1Band24) 2337 .build(); 2338 2339 ConfigRequest configRequest2 = new ConfigRequest.Builder() 2340 .setSupport5gBand(true) // compatible 2341 .setClusterLow(7).setClusterHigh(155) // incompatible! 2342 .setMasterPreference(0) // compatible 2343 .build(); 2344 2345 ConfigRequest configRequest3 = new ConfigRequest.Builder() 2346 .setSupport5gBand(true) // compatible (will use true) 2347 .setClusterLow(5).setClusterHigh(100) // identical (hence compatible) 2348 .setMasterPreference(masterPref3) // compatible (will use max) 2349 // compatible: will use min 2350 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval3Band24) 2351 // compatible: will use interval3 since interval1 not init 2352 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwInterval3Band5) 2353 .build(); 2354 2355 IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); 2356 IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); 2357 IWifiAwareEventCallback mockCallback3 = mock(IWifiAwareEventCallback.class); 2358 2359 InOrder inOrder = inOrder(mMockNative, mockCallback1, mockCallback2, mockCallback3); 2360 2361 mDut.enableUsage(); 2362 mMockLooper.dispatchAll(); 2363 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2364 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2365 mMockLooper.dispatchAll(); 2366 2367 // (1) config1 (valid) 2368 mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest1, false); 2369 mMockLooper.dispatchAll(); 2370 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2371 crCapture.capture(), eq(false), eq(true), eq(true), eq(false)); 2372 collector.checkThat("merge: stage 1", crCapture.getValue(), equalTo(configRequest1)); 2373 mDut.onConfigSuccessResponse(transactionId.getValue()); 2374 mMockLooper.dispatchAll(); 2375 inOrder.verify(mockCallback1).onConnectSuccess(clientId1); 2376 2377 // (2) config2 (incompatible with config1) 2378 mDut.connect(clientId2, uid, pid, callingPackage, mockCallback2, configRequest2, false); 2379 mMockLooper.dispatchAll(); 2380 inOrder.verify(mockCallback2).onConnectFail(NanStatusType.INTERNAL_FAILURE); 2381 validateInternalClientInfoCleanedUp(clientId2); 2382 2383 // (3) config3 (compatible with config1) 2384 mDut.connect(clientId3, uid, pid, callingPackage, mockCallback3, configRequest3, true); 2385 mMockLooper.dispatchAll(); 2386 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2387 crCapture.capture(), eq(true), eq(false), eq(true), eq(false)); 2388 mDut.onConfigSuccessResponse(transactionId.getValue()); 2389 mMockLooper.dispatchAll(); 2390 inOrder.verify(mockCallback3).onConnectSuccess(clientId3); 2391 2392 collector.checkThat("support 5g: or", true, equalTo(crCapture.getValue().mSupport5gBand)); 2393 collector.checkThat("master preference: max", Math.max(masterPref1, masterPref3), 2394 equalTo(crCapture.getValue().mMasterPreference)); 2395 collector.checkThat("dw interval on 2.4: ~min", 2396 Math.min(dwInterval1Band24, dwInterval3Band24), 2397 equalTo(crCapture.getValue().mDiscoveryWindowInterval[ConfigRequest 2398 .NAN_BAND_24GHZ])); 2399 collector.checkThat("dw interval on 5: ~min", dwInterval3Band5, 2400 equalTo(crCapture.getValue().mDiscoveryWindowInterval[ConfigRequest 2401 .NAN_BAND_5GHZ])); 2402 2403 // (4) disconnect config3: downgrade to config1 2404 mDut.disconnect(clientId3); 2405 mMockLooper.dispatchAll(); 2406 validateInternalClientInfoCleanedUp(clientId3); 2407 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2408 crCapture.capture(), eq(false), eq(false), eq(true), eq(false)); 2409 2410 collector.checkThat("configRequest1", configRequest1, equalTo(crCapture.getValue())); 2411 2412 mDut.onConfigSuccessResponse(transactionId.getValue()); 2413 mMockLooper.dispatchAll(); 2414 2415 // (5) disconnect config1: disable 2416 mDut.disconnect(clientId1); 2417 mMockLooper.dispatchAll(); 2418 validateInternalClientInfoCleanedUp(clientId1); 2419 inOrder.verify(mMockNative).disable(anyShort()); 2420 2421 verifyNoMoreInteractions(mMockNative, mockCallback1, mockCallback2, mockCallback3); 2422 } 2423 2424 /** 2425 * Validate that identical configuration but with different identity callback requirements 2426 * trigger the correct HAL sequence. 2427 * 1. Attach w/o identity -> enable 2428 * 2. Attach w/o identity -> nop 2429 * 3. Attach w/ identity -> re-configure 2430 * 4. Attach w/o identity -> nop 2431 * 5. Attach w/ identity -> nop 2432 */ 2433 @Test 2434 public void testConfigsIdentityCallback() throws Exception { 2435 int clientId = 9999; 2436 final int uid = 1000; 2437 final int pid = 2000; 2438 final String callingPackage = "com.google.somePackage"; 2439 2440 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2441 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2442 2443 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2444 2445 InOrder inOrder = inOrder(mMockNative, mockCallback); 2446 2447 mDut.enableUsage(); 2448 mMockLooper.dispatchAll(); 2449 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2450 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2451 mMockLooper.dispatchAll(); 2452 2453 // (1) attach w/o identity 2454 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2455 mMockLooper.dispatchAll(); 2456 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2457 any(ConfigRequest.class), eq(false), eq(true), eq(true), eq(false)); 2458 mDut.onConfigSuccessResponse(transactionId.getValue()); 2459 mMockLooper.dispatchAll(); 2460 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2461 2462 // (2) attach w/o identity 2463 ++clientId; 2464 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2465 mMockLooper.dispatchAll(); 2466 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2467 2468 // (3) attach w/ identity 2469 ++clientId; 2470 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, true); 2471 mMockLooper.dispatchAll(); 2472 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2473 any(ConfigRequest.class), eq(true), eq(false), eq(true), eq(false)); 2474 mDut.onConfigSuccessResponse(transactionId.getValue()); 2475 mMockLooper.dispatchAll(); 2476 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2477 2478 // (4) attach w/o identity 2479 ++clientId; 2480 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2481 mMockLooper.dispatchAll(); 2482 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2483 2484 // (5) attach w/ identity 2485 ++clientId; 2486 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, true); 2487 mMockLooper.dispatchAll(); 2488 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2489 2490 verifyNoMoreInteractions(mMockNative, mockCallback); 2491 } 2492 2493 /** 2494 * Summary: disconnect a client while there are pending transactions. 2495 */ 2496 @Test 2497 public void testDisconnectWithPendingTransactions() throws Exception { 2498 final int clientId = 125; 2499 final int uid = 1000; 2500 final int pid = 2000; 2501 final String callingPackage = "com.google.somePackage"; 2502 final int clusterLow = 5; 2503 final int clusterHigh = 100; 2504 final int masterPref = 111; 2505 final String serviceName = "some-service-name"; 2506 final String ssi = "some much longer and more arbitrary data"; 2507 final byte publishId = 22; 2508 2509 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 2510 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 2511 2512 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( 2513 serviceName).setServiceSpecificInfo(ssi.getBytes()).setPublishType( 2514 PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 2515 2516 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2517 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2518 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2519 IWifiAwareDiscoverySessionCallback.class); 2520 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2521 2522 mDut.enableUsage(); 2523 mMockLooper.dispatchAll(); 2524 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2525 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2526 mMockLooper.dispatchAll(); 2527 2528 // (1) connect 2529 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2530 mMockLooper.dispatchAll(); 2531 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2532 eq(false), eq(true), eq(true), eq(false)); 2533 mDut.onConfigSuccessResponse(transactionId.getValue()); 2534 mMockLooper.dispatchAll(); 2535 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2536 2537 // (2) publish (no response yet) 2538 mDut.publish(clientId, publishConfig, mockSessionCallback); 2539 mMockLooper.dispatchAll(); 2540 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2541 eq(publishConfig)); 2542 2543 // (3) disconnect (but doesn't get executed until get a RESPONSE to the 2544 // previous publish) 2545 mDut.disconnect(clientId); 2546 mMockLooper.dispatchAll(); 2547 2548 // (4) get successful response to the publish 2549 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 2550 mMockLooper.dispatchAll(); 2551 inOrder.verify(mockSessionCallback).onSessionStarted(anyInt()); 2552 inOrder.verify(mMockNative).stopPublish((short) 0, publishId); 2553 inOrder.verify(mMockNative).disable(anyShort()); 2554 2555 validateInternalClientInfoCleanedUp(clientId); 2556 2557 // (5) trying to publish on the same client: NOP 2558 mDut.publish(clientId, publishConfig, mockSessionCallback); 2559 mMockLooper.dispatchAll(); 2560 2561 // (6) got some callback on original publishId - should be ignored 2562 mDut.onSessionTerminatedNotification(publishId, 0, true); 2563 mMockLooper.dispatchAll(); 2564 2565 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2566 } 2567 2568 /** 2569 * Validate that an unknown transaction (i.e. a callback from HAL with an 2570 * unknown type) is simply ignored - but also cleans up its state. 2571 */ 2572 @Test 2573 public void testUnknownTransactionType() throws Exception { 2574 final int clientId = 129; 2575 final int uid = 1000; 2576 final int pid = 2000; 2577 final String callingPackage = "com.google.somePackage"; 2578 final int clusterLow = 15; 2579 final int clusterHigh = 192; 2580 final int masterPref = 234; 2581 final String serviceName = "some-service-name"; 2582 final String ssi = "some much longer and more arbitrary data"; 2583 2584 ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow) 2585 .setClusterHigh(clusterHigh).setMasterPreference(masterPref).build(); 2586 2587 PublishConfig publishConfig = new PublishConfig.Builder().setServiceName( 2588 serviceName).setServiceSpecificInfo(ssi.getBytes()).setPublishType( 2589 PublishConfig.PUBLISH_TYPE_UNSOLICITED).build(); 2590 2591 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2592 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2593 IWifiAwareDiscoverySessionCallback mockPublishSessionCallback = mock( 2594 IWifiAwareDiscoverySessionCallback.class); 2595 InOrder inOrder = inOrder(mMockNative, mockCallback, mockPublishSessionCallback); 2596 2597 mDut.enableUsage(); 2598 mMockLooper.dispatchAll(); 2599 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2600 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2601 mMockLooper.dispatchAll(); 2602 2603 // (1) connect 2604 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2605 mMockLooper.dispatchAll(); 2606 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2607 eq(false), eq(true), eq(true), eq(false)); 2608 mDut.onConfigSuccessResponse(transactionId.getValue()); 2609 mMockLooper.dispatchAll(); 2610 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2611 2612 // (2) publish - no response 2613 mDut.publish(clientId, publishConfig, mockPublishSessionCallback); 2614 mMockLooper.dispatchAll(); 2615 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2616 eq(publishConfig)); 2617 2618 verifyNoMoreInteractions(mMockNative, mockCallback, mockPublishSessionCallback); 2619 } 2620 2621 /** 2622 * Validate that a NoOp transaction (i.e. a callback from HAL which doesn't 2623 * require any action except clearing up state) actually cleans up its state 2624 * (and does nothing else). 2625 */ 2626 @Test 2627 public void testNoOpTransaction() throws Exception { 2628 final int clientId = 1294; 2629 final int uid = 1000; 2630 final int pid = 2000; 2631 final String callingPackage = "com.google.somePackage"; 2632 2633 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2634 2635 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2636 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2637 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2638 IWifiAwareDiscoverySessionCallback.class); 2639 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2640 2641 mDut.enableUsage(); 2642 mMockLooper.dispatchAll(); 2643 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2644 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2645 mMockLooper.dispatchAll(); 2646 2647 // (1) connect (no response) 2648 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2649 mMockLooper.dispatchAll(); 2650 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2651 eq(false), eq(true), eq(true), eq(false)); 2652 2653 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2654 } 2655 2656 /** 2657 * Validate that getting callbacks from HAL with unknown (expired) 2658 * transaction ID or invalid publish/subscribe ID session doesn't have any 2659 * impact. 2660 */ 2661 @Test 2662 public void testInvalidCallbackIdParameters() throws Exception { 2663 final byte pubSubId = 125; 2664 final int clientId = 132; 2665 final int uid = 1000; 2666 final int pid = 2000; 2667 final String callingPackage = "com.google.somePackage"; 2668 2669 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2670 2671 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2672 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2673 InOrder inOrder = inOrder(mMockNative, mockCallback); 2674 2675 mDut.enableUsage(); 2676 mMockLooper.dispatchAll(); 2677 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2678 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2679 mMockLooper.dispatchAll(); 2680 2681 // (1) connect and succeed 2682 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2683 mMockLooper.dispatchAll(); 2684 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2685 eq(false), eq(true), eq(true), eq(false)); 2686 short transactionIdConfig = transactionId.getValue(); 2687 mDut.onConfigSuccessResponse(transactionIdConfig); 2688 mMockLooper.dispatchAll(); 2689 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2690 2691 // (2) use the same transaction ID to send a bunch of other responses 2692 mDut.onConfigSuccessResponse(transactionIdConfig); 2693 mDut.onConfigFailedResponse(transactionIdConfig, -1); 2694 mDut.onSessionConfigFailResponse(transactionIdConfig, true, -1); 2695 mDut.onMessageSendQueuedSuccessResponse(transactionIdConfig); 2696 mDut.onMessageSendQueuedFailResponse(transactionIdConfig, -1); 2697 mDut.onSessionConfigFailResponse(transactionIdConfig, false, -1); 2698 mDut.onMatchNotification(-1, -1, new byte[0], new byte[0], new byte[0]); 2699 mDut.onSessionTerminatedNotification(-1, -1, true); 2700 mDut.onSessionTerminatedNotification(-1, -1, false); 2701 mDut.onMessageReceivedNotification(-1, -1, new byte[0], new byte[0]); 2702 mDut.onSessionConfigSuccessResponse(transactionIdConfig, true, pubSubId); 2703 mDut.onSessionConfigSuccessResponse(transactionIdConfig, false, pubSubId); 2704 mMockLooper.dispatchAll(); 2705 2706 verifyNoMoreInteractions(mMockNative, mockCallback); 2707 } 2708 2709 /** 2710 * Validate that trying to update-subscribe on a publish session fails. 2711 */ 2712 @Test 2713 public void testSubscribeOnPublishSessionType() throws Exception { 2714 final int clientId = 188; 2715 final int uid = 1000; 2716 final int pid = 2000; 2717 final String callingPackage = "com.google.somePackage"; 2718 final byte publishId = 25; 2719 2720 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2721 PublishConfig publishConfig = new PublishConfig.Builder().build(); 2722 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 2723 2724 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2725 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2726 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2727 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2728 IWifiAwareDiscoverySessionCallback.class); 2729 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2730 2731 mDut.enableUsage(); 2732 mMockLooper.dispatchAll(); 2733 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2734 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2735 mMockLooper.dispatchAll(); 2736 2737 // (1) connect 2738 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2739 mMockLooper.dispatchAll(); 2740 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), 2741 eq(false), eq(true), eq(true), eq(false)); 2742 mDut.onConfigSuccessResponse(transactionId.getValue()); 2743 mMockLooper.dispatchAll(); 2744 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2745 2746 // (2) publish 2747 mDut.publish(clientId, publishConfig, mockSessionCallback); 2748 mMockLooper.dispatchAll(); 2749 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2750 eq(publishConfig)); 2751 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, publishId); 2752 mMockLooper.dispatchAll(); 2753 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2754 2755 // (3) update-subscribe -> failure 2756 mDut.updateSubscribe(clientId, sessionId.getValue(), subscribeConfig); 2757 mMockLooper.dispatchAll(); 2758 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2759 2760 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2761 } 2762 2763 /** 2764 * Validate that trying to (re)subscribe on a publish session or (re)publish 2765 * on a subscribe session fails. 2766 */ 2767 @Test 2768 public void testPublishOnSubscribeSessionType() throws Exception { 2769 final int clientId = 188; 2770 final int uid = 1000; 2771 final int pid = 2000; 2772 final String callingPackage = "com.google.somePackage"; 2773 final byte subscribeId = 25; 2774 2775 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2776 PublishConfig publishConfig = new PublishConfig.Builder().build(); 2777 SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); 2778 2779 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2780 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2781 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2782 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2783 IWifiAwareDiscoverySessionCallback.class); 2784 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2785 2786 mDut.enableUsage(); 2787 mMockLooper.dispatchAll(); 2788 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2789 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2790 mMockLooper.dispatchAll(); 2791 2792 // (1) connect 2793 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2794 mMockLooper.dispatchAll(); 2795 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2796 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2797 mDut.onConfigSuccessResponse(transactionId.getValue()); 2798 mMockLooper.dispatchAll(); 2799 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2800 2801 // (2) subscribe 2802 mDut.subscribe(clientId, subscribeConfig, mockSessionCallback); 2803 mMockLooper.dispatchAll(); 2804 inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0), 2805 eq(subscribeConfig)); 2806 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); 2807 mMockLooper.dispatchAll(); 2808 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2809 2810 // (3) update-publish -> error 2811 mDut.updatePublish(clientId, sessionId.getValue(), publishConfig); 2812 mMockLooper.dispatchAll(); 2813 inOrder.verify(mockSessionCallback).onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2814 2815 verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); 2816 } 2817 2818 /** 2819 * Validate that the session ID increments monotonically 2820 */ 2821 @Test 2822 public void testSessionIdIncrement() throws Exception { 2823 final int clientId = 188; 2824 final int uid = 1000; 2825 final int pid = 2000; 2826 final String callingPackage = "com.google.somePackage"; 2827 int loopCount = 100; 2828 2829 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2830 PublishConfig publishConfig = new PublishConfig.Builder().build(); 2831 2832 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2833 ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class); 2834 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2835 IWifiAwareDiscoverySessionCallback mockSessionCallback = mock( 2836 IWifiAwareDiscoverySessionCallback.class); 2837 InOrder inOrder = inOrder(mMockNative, mockCallback, mockSessionCallback); 2838 2839 mDut.enableUsage(); 2840 mMockLooper.dispatchAll(); 2841 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2842 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2843 mMockLooper.dispatchAll(); 2844 2845 // (1) connect 2846 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2847 mMockLooper.dispatchAll(); 2848 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2849 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2850 mDut.onConfigSuccessResponse(transactionId.getValue()); 2851 mMockLooper.dispatchAll(); 2852 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2853 2854 int prevId = 0; 2855 for (int i = 0; i < loopCount; ++i) { 2856 // (2) publish 2857 mDut.publish(clientId, publishConfig, mockSessionCallback); 2858 mMockLooper.dispatchAll(); 2859 inOrder.verify(mMockNative).publish(transactionId.capture(), eq((byte) 0), 2860 eq(publishConfig)); 2861 2862 // (3) publish-success 2863 mDut.onSessionConfigSuccessResponse(transactionId.getValue(), true, (byte) (i + 1)); 2864 mMockLooper.dispatchAll(); 2865 inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); 2866 2867 if (i != 0) { 2868 assertTrue("Session ID incrementing", sessionId.getValue() > prevId); 2869 } 2870 prevId = sessionId.getValue(); 2871 } 2872 } 2873 2874 /** 2875 * Validate configuration changes on power state changes when Aware is not disabled on doze. 2876 */ 2877 @Test 2878 public void testConfigOnPowerStateChanges() throws Exception { 2879 final int clientId = 188; 2880 final int uid = 1000; 2881 final int pid = 2000; 2882 final String callingPackage = "com.google.somePackage"; 2883 2884 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2885 2886 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(0), 2887 true); 2888 2889 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2890 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2891 InOrder inOrder = inOrder(mMockNative, mockCallback); 2892 2893 mDut.enableUsage(); 2894 mMockLooper.dispatchAll(); 2895 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2896 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2897 mMockLooper.dispatchAll(); 2898 2899 // (1) connect 2900 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2901 mMockLooper.dispatchAll(); 2902 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2903 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2904 mDut.onConfigSuccessResponse(transactionId.getValue()); 2905 mMockLooper.dispatchAll(); 2906 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2907 2908 // (2) power state change: SCREEN OFF 2909 simulatePowerStateChangeInteractive(false); 2910 mMockLooper.dispatchAll(); 2911 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2912 eq(configRequest), eq(false), eq(false), eq(false), eq(false)); 2913 mDut.onConfigSuccessResponse(transactionId.getValue()); 2914 mMockLooper.dispatchAll(); 2915 2916 // (3) power state change: DOZE 2917 simulatePowerStateChangeDoze(true); 2918 mMockLooper.dispatchAll(); 2919 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2920 eq(configRequest), eq(false), eq(false), eq(false), eq(true)); 2921 mDut.onConfigSuccessResponse(transactionId.getValue()); 2922 mMockLooper.dispatchAll(); 2923 2924 // (4) restore power state to default 2925 simulatePowerStateChangeInteractive(true); // effectively treated as no-doze 2926 mMockLooper.dispatchAll(); 2927 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2928 eq(configRequest), eq(false), eq(false), eq(true), eq(true)); 2929 mDut.onConfigSuccessResponse(transactionId.getValue()); 2930 mMockLooper.dispatchAll(); 2931 2932 verifyNoMoreInteractions(mMockNative, mockCallback); 2933 } 2934 2935 /** 2936 * Validate aware enable/disable during doze transitions. 2937 */ 2938 @Test 2939 public void testEnableDisableOnDoze() throws Exception { 2940 final int clientId = 188; 2941 final int uid = 1000; 2942 final int pid = 2000; 2943 final String callingPackage = "com.google.somePackage"; 2944 2945 setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), 2946 true); 2947 2948 ConfigRequest configRequest = new ConfigRequest.Builder().build(); 2949 2950 ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); 2951 IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); 2952 InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback); 2953 inOrder.verify(mMockNativeManager).start(); 2954 2955 mDut.enableUsage(); 2956 mMockLooper.dispatchAll(); 2957 inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); 2958 mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); 2959 mMockLooper.dispatchAll(); 2960 2961 // (1) connect 2962 mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); 2963 mMockLooper.dispatchAll(); 2964 inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), 2965 eq(configRequest), eq(false), eq(true), eq(true), eq(false)); 2966 mDut.onConfigSuccessResponse(transactionId.getValue()); 2967 mMockLooper.dispatchAll(); 2968 inOrder.verify(mockCallback).onConnectSuccess(clientId); 2969 2970 // (3) power state change: DOZE 2971 simulatePowerStateChangeDoze(true); 2972 mMockLooper.dispatchAll(); 2973 inOrder.verify(mMockNative).disable(transactionId.capture()); 2974 mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS); 2975 validateCorrectAwareStatusChangeBroadcast(inOrder, false); 2976 2977 // (4) power state change: SCREEN ON (but DOZE still on - fakish but expect no changes) 2978 simulatePowerStateChangeInteractive(false); 2979 mMockLooper.dispatchAll(); 2980 2981 // (5) power state change: DOZE OFF 2982 simulatePowerStateChangeDoze(false); 2983 mMockLooper.dispatchAll(); 2984 validateCorrectAwareStatusChangeBroadcast(inOrder, true); 2985 2986 verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback); 2987 } 2988 2989 /* 2990 * Tests of internal state of WifiAwareStateManager: very limited (not usually 2991 * a good idea). However, these test that the internal state is cleaned-up 2992 * appropriately. Alternatively would cause issues with memory leaks or 2993 * information leak between sessions. 2994 */ 2995 2996 /** 2997 * Utility routine used to validate that the internal state is cleaned-up 2998 * after a client is disconnected. To be used in every test which terminates 2999 * a client. 3000 * 3001 * @param clientId The ID of the client which should be deleted. 3002 */ 3003 private void validateInternalClientInfoCleanedUp(int clientId) throws Exception { 3004 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3005 collector.checkThat("Client record not cleared up for clientId=" + clientId, client, 3006 nullValue()); 3007 } 3008 3009 /** 3010 * Utility routine used to validate that the internal state is cleaned-up 3011 * (deleted) after a session is terminated through API (not callback!). To 3012 * be used in every test which terminates a session. 3013 * 3014 * @param clientId The ID of the client containing the session. 3015 * @param sessionId The ID of the terminated session. 3016 */ 3017 private void validateInternalSessionInfoCleanedUp(int clientId, int sessionId) 3018 throws Exception { 3019 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3020 collector.checkThat("Client record exists clientId=" + clientId, client, notNullValue()); 3021 WifiAwareDiscoverySessionState session = getInternalSessionState(client, sessionId); 3022 collector.checkThat("Client record not cleaned-up for sessionId=" + sessionId, session, 3023 nullValue()); 3024 } 3025 3026 /** 3027 * Utility routine used to validate that the internal state is cleaned-up 3028 * (deleted) correctly. Checks that a specific client has no sessions 3029 * attached to it. 3030 * 3031 * @param clientId The ID of the client which we want to check. 3032 */ 3033 private void validateInternalNoSessions(int clientId) throws Exception { 3034 WifiAwareClientState client = getInternalClientState(mDut, clientId); 3035 collector.checkThat("Client record exists clientId=" + clientId, client, notNullValue()); 3036 3037 Field field = WifiAwareClientState.class.getDeclaredField("mSessions"); 3038 field.setAccessible(true); 3039 @SuppressWarnings("unchecked") 3040 SparseArray<WifiAwareDiscoverySessionState> sessions = 3041 (SparseArray<WifiAwareDiscoverySessionState>) field.get(client); 3042 3043 collector.checkThat("No sessions exist for clientId=" + clientId, sessions.size(), 3044 equalTo(0)); 3045 } 3046 3047 /** 3048 * Validates that the broadcast sent on Aware status change is correct. 3049 * 3050 * @param expectedEnabled The expected change status - i.e. are we expected 3051 * to announce that Aware is enabled (true) or disabled (false). 3052 */ 3053 private void validateCorrectAwareStatusChangeBroadcast(InOrder inOrder, 3054 boolean expectedEnabled) { 3055 ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 3056 3057 inOrder.verify(mMockContext).sendBroadcastAsUser(intent.capture(), eq(UserHandle.ALL)); 3058 3059 collector.checkThat("intent action", intent.getValue().getAction(), 3060 equalTo(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)); 3061 } 3062 3063 /* 3064 * Utilities 3065 */ 3066 private void setSettableParam(String name, String value, boolean expectSuccess) { 3067 PrintWriter pwMock = mock(PrintWriter.class); 3068 WifiAwareShellCommand parentShellMock = mock(WifiAwareShellCommand.class); 3069 when(parentShellMock.getNextArgRequired()).thenReturn("set").thenReturn(name).thenReturn( 3070 value); 3071 when(parentShellMock.getErrPrintWriter()).thenReturn(pwMock); 3072 3073 collector.checkThat(mDut.onCommand(parentShellMock), equalTo(expectSuccess ? 0 : -1)); 3074 } 3075 3076 private void dumpDut(String prefix) { 3077 StringWriter sw = new StringWriter(); 3078 mDut.dump(null, new PrintWriter(sw), null); 3079 Log.e("WifiAwareStateManagerTest", prefix + sw.toString()); 3080 } 3081 3082 private static void installMocksInStateManager(WifiAwareStateManager awareStateManager, 3083 WifiAwareRttStateManager mockRtt, WifiAwareDataPathStateManager mockDpMgr) 3084 throws Exception { 3085 Field field = WifiAwareStateManager.class.getDeclaredField("mRtt"); 3086 field.setAccessible(true); 3087 field.set(awareStateManager, mockRtt); 3088 3089 field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr"); 3090 field.setAccessible(true); 3091 field.set(awareStateManager, mockDpMgr); 3092 } 3093 3094 private static WifiAwareClientState getInternalClientState(WifiAwareStateManager dut, 3095 int clientId) throws Exception { 3096 Field field = WifiAwareStateManager.class.getDeclaredField("mClients"); 3097 field.setAccessible(true); 3098 @SuppressWarnings("unchecked") 3099 SparseArray<WifiAwareClientState> clients = (SparseArray<WifiAwareClientState>) field.get( 3100 dut); 3101 3102 return clients.get(clientId); 3103 } 3104 3105 private static WifiAwareDiscoverySessionState getInternalSessionState( 3106 WifiAwareClientState client, int sessionId) throws Exception { 3107 Field field = WifiAwareClientState.class.getDeclaredField("mSessions"); 3108 field.setAccessible(true); 3109 @SuppressWarnings("unchecked") 3110 SparseArray<WifiAwareDiscoverySessionState> sessions = 3111 (SparseArray<WifiAwareDiscoverySessionState>) field.get(client); 3112 3113 return sessions.get(sessionId); 3114 } 3115 3116 private void validateInternalSendMessageQueuesCleanedUp(int messageId) throws Exception { 3117 Field field = WifiAwareStateManager.class.getDeclaredField("mSm"); 3118 field.setAccessible(true); 3119 WifiAwareStateManager.WifiAwareStateMachine sm = 3120 (WifiAwareStateManager.WifiAwareStateMachine) field.get(mDut); 3121 3122 field = WifiAwareStateManager.WifiAwareStateMachine.class.getDeclaredField( 3123 "mHostQueuedSendMessages"); 3124 field.setAccessible(true); 3125 SparseArray<Message> hostQueuedSendMessages = (SparseArray<Message>) field.get(sm); 3126 3127 field = WifiAwareStateManager.WifiAwareStateMachine.class.getDeclaredField( 3128 "mFwQueuedSendMessages"); 3129 field.setAccessible(true); 3130 Map<Short, Message> fwQueuedSendMessages = (Map<Short, Message>) field.get(sm); 3131 3132 for (int i = 0; i < hostQueuedSendMessages.size(); ++i) { 3133 Message msg = hostQueuedSendMessages.valueAt(i); 3134 if (msg.getData().getInt("message_id") == messageId) { 3135 collector.checkThat( 3136 "Message not cleared-up from host queue. Message ID=" + messageId, msg, 3137 nullValue()); 3138 } 3139 } 3140 3141 for (Message msg: fwQueuedSendMessages.values()) { 3142 if (msg.getData().getInt("message_id") == messageId) { 3143 collector.checkThat( 3144 "Message not cleared-up from firmware queue. Message ID=" + messageId, msg, 3145 nullValue()); 3146 } 3147 } 3148 } 3149 3150 /** 3151 * Simulate power state change due to doze. Changes the power manager return values and 3152 * dispatches a broadcast. 3153 */ 3154 private void simulatePowerStateChangeDoze(boolean isDozeOn) { 3155 when(mMockPowerManager.isDeviceIdleMode()).thenReturn(isDozeOn); 3156 3157 Intent intent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 3158 mPowerBcastReceiver.onReceive(mMockContext, intent); 3159 } 3160 3161 /** 3162 * Simulate power state change due to interactive mode change (screen on/off). Changes the power 3163 * manager return values and dispatches a broadcast. 3164 */ 3165 private void simulatePowerStateChangeInteractive(boolean isInteractive) { 3166 when(mMockPowerManager.isInteractive()).thenReturn(isInteractive); 3167 3168 Intent intent = new Intent( 3169 isInteractive ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF); 3170 mPowerBcastReceiver.onReceive(mMockContext, intent); 3171 } 3172 3173 private static Capabilities getCapabilities() { 3174 Capabilities cap = new Capabilities(); 3175 cap.maxConcurrentAwareClusters = 1; 3176 cap.maxPublishes = 2; 3177 cap.maxSubscribes = 2; 3178 cap.maxServiceNameLen = 255; 3179 cap.maxMatchFilterLen = 255; 3180 cap.maxTotalMatchFilterLen = 255; 3181 cap.maxServiceSpecificInfoLen = 255; 3182 cap.maxExtendedServiceSpecificInfoLen = 255; 3183 cap.maxNdiInterfaces = 1; 3184 cap.maxNdpSessions = 1; 3185 cap.maxAppInfoLen = 255; 3186 cap.maxQueuedTransmitMessages = 6; 3187 return cap; 3188 } 3189} 3190 3191