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