NetworkScoreServiceTest.java revision a5172f69ca02f5338b4c36ad5e9b57b9fb4fd8d2
1/*
2 * Copyright (C) 2012 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;
18
19import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
20import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
21import static android.net.NetworkScoreManager.CACHE_FILTER_NONE;
22
23import static junit.framework.Assert.assertEquals;
24import static junit.framework.Assert.assertFalse;
25import static junit.framework.Assert.assertNotNull;
26import static junit.framework.Assert.assertNull;
27import static junit.framework.Assert.assertSame;
28import static junit.framework.Assert.assertTrue;
29import static junit.framework.Assert.fail;
30
31import static org.mockito.Matchers.any;
32import static org.mockito.Matchers.anyInt;
33import static org.mockito.Matchers.anyListOf;
34import static org.mockito.Matchers.anyString;
35import static org.mockito.Matchers.eq;
36import static org.mockito.Matchers.isA;
37import static org.mockito.Mockito.atLeastOnce;
38import static org.mockito.Mockito.doAnswer;
39import static org.mockito.Mockito.doThrow;
40import static org.mockito.Mockito.mock;
41import static org.mockito.Mockito.times;
42import static org.mockito.Mockito.verify;
43import static org.mockito.Mockito.verifyNoMoreInteractions;
44import static org.mockito.Mockito.verifyZeroInteractions;
45import static org.mockito.Mockito.when;
46
47import android.Manifest.permission;
48import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.ServiceConnection;
53import android.content.pm.PackageManager;
54import android.content.res.Resources;
55import android.net.INetworkRecommendationProvider;
56import android.net.INetworkScoreCache;
57import android.net.NetworkKey;
58import android.net.NetworkScoreManager;
59import android.net.NetworkScorerAppManager;
60import android.net.NetworkScorerAppManager.NetworkScorerAppData;
61import android.net.RecommendationRequest;
62import android.net.RecommendationResult;
63import android.net.ScoredNetwork;
64import android.net.Uri;
65import android.net.WifiKey;
66import android.net.wifi.ScanResult;
67import android.net.wifi.WifiConfiguration;
68import android.net.wifi.WifiInfo;
69import android.net.wifi.WifiSsid;
70import android.os.Binder;
71import android.os.Bundle;
72import android.os.Handler;
73import android.os.HandlerThread;
74import android.os.IBinder;
75import android.os.IRemoteCallback;
76import android.os.Looper;
77import android.os.Message;
78import android.os.RemoteCallback;
79import android.os.RemoteException;
80import android.os.UserHandle;
81import android.provider.Settings;
82import android.support.test.InstrumentationRegistry;
83import android.support.test.filters.MediumTest;
84import android.support.test.runner.AndroidJUnit4;
85
86import com.android.server.devicepolicy.MockUtils;
87
88import com.google.android.collect.Lists;
89
90import org.junit.After;
91import org.junit.Before;
92import org.junit.Test;
93import org.junit.runner.RunWith;
94import org.mockito.ArgumentCaptor;
95import org.mockito.Captor;
96import org.mockito.Mock;
97import org.mockito.MockitoAnnotations;
98import org.mockito.invocation.InvocationOnMock;
99import org.mockito.stubbing.Answer;
100
101import java.io.FileDescriptor;
102import java.io.PrintWriter;
103import java.io.StringWriter;
104import java.util.ArrayList;
105import java.util.Collections;
106import java.util.List;
107import java.util.concurrent.CountDownLatch;
108import java.util.concurrent.TimeUnit;
109import java.util.function.UnaryOperator;
110
111/**
112 * Tests for {@link NetworkScoreService}.
113 */
114@RunWith(AndroidJUnit4.class)
115@MediumTest
116public class NetworkScoreServiceTest {
117    private static final String SSID = "ssid";
118    private static final String SSID_2 = "ssid_2";
119    private static final String SSID_3 = "ssid_3";
120    private static final ComponentName RECOMMENDATION_SERVICE_COMP =
121            new ComponentName("newPackageName", "newScoringServiceClass");
122    private static final ScoredNetwork SCORED_NETWORK =
123            new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
124                    null /* rssiCurve*/);
125    private static final ScoredNetwork SCORED_NETWORK_2 =
126            new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
127                    null /* rssiCurve*/);
128    private static final NetworkScorerAppData NEW_SCORER =
129        new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
130
131    @Mock private NetworkScorerAppManager mNetworkScorerAppManager;
132    @Mock private Context mContext;
133    @Mock private Resources mResources;
134    @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
135    @Mock private IBinder mIBinder, mIBinder2;
136    @Mock private INetworkRecommendationProvider mRecommendationProvider;
137    @Mock private UnaryOperator<List<ScoredNetwork>> mCurrentNetworkFilter;
138    @Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
139    @Mock private WifiInfo mWifiInfo;
140    @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
141
142    private ContentResolver mContentResolver;
143    private NetworkScoreService mNetworkScoreService;
144    private RecommendationRequest mRecommendationRequest;
145    private RemoteCallback mRemoteCallback;
146    private OnResultListener mOnResultListener;
147    private HandlerThread mHandlerThread;
148    private List<ScanResult> mScanResults;
149
150    private static String quote(String str) {
151        return String.format("\"%s\"", str);
152    }
153
154    @Before
155    public void setUp() throws Exception {
156        MockitoAnnotations.initMocks(this);
157        when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder);
158        when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2);
159        mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
160        when(mContext.getContentResolver()).thenReturn(mContentResolver);
161        when(mContext.getResources()).thenReturn(mResources);
162        when(mWifiInfo.getSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.ssid);
163        when(mWifiInfo.getBSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.bssid);
164        mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
165        mHandlerThread.start();
166        mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
167                mHandlerThread.getLooper());
168        WifiConfiguration configuration = new WifiConfiguration();
169        configuration.SSID = "NetworkScoreServiceTest_SSID";
170        configuration.BSSID = "NetworkScoreServiceTest_BSSID";
171        mRecommendationRequest = new RecommendationRequest.Builder()
172            .setDefaultWifiConfig(configuration).build();
173        mOnResultListener = new OnResultListener();
174        mRemoteCallback = new RemoteCallback(mOnResultListener);
175        Settings.Global.putLong(mContentResolver,
176                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L);
177        mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
178        populateScanResults();
179    }
180
181    private void populateScanResults() {
182        mScanResults = new ArrayList<>();
183        mScanResults.add(createScanResult(SSID, SCORED_NETWORK.networkKey.wifiKey.bssid));
184        mScanResults.add(createScanResult(SSID_2, SCORED_NETWORK_2.networkKey.wifiKey.bssid));
185        mScanResults.add(createScanResult(SSID_3, "10:10:00:00:10:10"));
186    }
187
188    private ScanResult createScanResult(String ssid, String bssid) {
189        ScanResult result = new ScanResult();
190        result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
191        result.BSSID = bssid;
192        return result;
193    }
194
195    @After
196    public void tearDown() throws Exception {
197        mHandlerThread.quitSafely();
198    }
199
200    @Test
201    public void testSystemRunning() {
202        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
203
204        mNetworkScoreService.systemRunning();
205
206        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
207                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
208                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
209                any(ServiceConnection.class),
210                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
211                eq(UserHandle.SYSTEM));
212    }
213
214    @Test
215    public void testRequestScores_noPermission() throws Exception {
216        doThrow(new SecurityException()).when(mContext)
217            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
218                anyString());
219        try {
220            mNetworkScoreService.requestScores(null);
221            fail("REQUEST_NETWORK_SCORES not enforced.");
222        } catch (SecurityException e) {
223            // expected
224        }
225    }
226
227    @Test
228    public void testRequestScores_providerNotConnected() throws Exception {
229        assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0]));
230        verifyZeroInteractions(mRecommendationProvider);
231    }
232
233    @Test
234    public void testRequestScores_providerThrowsRemoteException() throws Exception {
235        injectProvider();
236        doThrow(new RemoteException()).when(mRecommendationProvider)
237            .requestScores(any(NetworkKey[].class));
238
239        assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0]));
240    }
241
242    @Test
243    public void testRequestScores_providerAvailable() throws Exception {
244        injectProvider();
245
246        final NetworkKey[] networks = new NetworkKey[0];
247        assertTrue(mNetworkScoreService.requestScores(networks));
248        verify(mRecommendationProvider).requestScores(networks);
249    }
250
251    @Test
252    public void testRequestRecommendation_noPermission() throws Exception {
253        doThrow(new SecurityException()).when(mContext)
254            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
255                anyString());
256        try {
257            mNetworkScoreService.requestRecommendation(mRecommendationRequest);
258            fail("REQUEST_NETWORK_SCORES not enforced.");
259        } catch (SecurityException e) {
260            // expected
261        }
262    }
263
264    @Test
265    public void testRequestRecommendation_mainThread() throws Exception {
266        when(mContext.getMainLooper()).thenReturn(Looper.myLooper());
267        try {
268            mNetworkScoreService.requestRecommendation(mRecommendationRequest);
269            fail("requestRecommendation run on main thread.");
270        } catch (RuntimeException e) {
271            // expected
272        }
273    }
274
275    @Test
276    public void testRequestRecommendation_providerNotConnected() throws Exception {
277        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
278
279        final RecommendationResult result =
280                mNetworkScoreService.requestRecommendation(mRecommendationRequest);
281        assertNotNull(result);
282        assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
283                result.getWifiConfiguration());
284    }
285
286    @Test
287    public void testRequestRecommendation_providerThrowsRemoteException() throws Exception {
288        injectProvider();
289        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
290        doThrow(new RemoteException()).when(mRecommendationProvider)
291                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
292                        anyInt());
293
294        final RecommendationResult result =
295                mNetworkScoreService.requestRecommendation(mRecommendationRequest);
296        assertNotNull(result);
297        assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
298                result.getWifiConfiguration());
299    }
300
301    @Test
302    public void testRequestRecommendation_resultReturned() throws Exception {
303        injectProvider();
304        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
305        final WifiConfiguration wifiConfiguration = new WifiConfiguration();
306        wifiConfiguration.SSID = "testRequestRecommendation_resultReturned_SSID";
307        wifiConfiguration.BSSID = "testRequestRecommendation_resultReturned_BSSID";
308        final RecommendationResult providerResult = RecommendationResult
309                .createConnectRecommendation(wifiConfiguration);
310        final Bundle bundle = new Bundle();
311        bundle.putParcelable(EXTRA_RECOMMENDATION_RESULT, providerResult);
312        doAnswer(invocation -> {
313            bundle.putInt(EXTRA_SEQUENCE, invocation.getArgumentAt(2, int.class));
314            invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle);
315            return null;
316        }).when(mRecommendationProvider)
317                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
318                        anyInt());
319
320        final RecommendationResult result =
321                mNetworkScoreService.requestRecommendation(mRecommendationRequest);
322        assertNotNull(result);
323        assertEquals(providerResult.getWifiConfiguration().SSID,
324                result.getWifiConfiguration().SSID);
325        assertEquals(providerResult.getWifiConfiguration().BSSID,
326                result.getWifiConfiguration().BSSID);
327    }
328
329    @Test
330    public void testRequestRecommendationAsync_noPermission() throws Exception {
331        doThrow(new SecurityException()).when(mContext)
332                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
333                        anyString());
334        try {
335            mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
336                    mRemoteCallback);
337            fail("REQUEST_NETWORK_SCORES not enforced.");
338        } catch (SecurityException e) {
339            // expected
340        }
341    }
342
343    @Test
344    public void testRequestRecommendationAsync_providerNotConnected() throws Exception {
345        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
346                mRemoteCallback);
347        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
348        assertTrue(callbackRan);
349        verifyZeroInteractions(mRecommendationProvider);
350    }
351
352    @Test
353    public void testRequestRecommendationAsync_requestTimesOut() throws Exception {
354        injectProvider();
355        Settings.Global.putLong(mContentResolver,
356                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, 1L);
357        mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
358        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
359                mRemoteCallback);
360        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
361        assertTrue(callbackRan);
362        verify(mRecommendationProvider).requestRecommendation(eq(mRecommendationRequest),
363                isA(IRemoteCallback.Stub.class), anyInt());
364
365        assertTrue(mOnResultListener.receivedBundle.containsKey(EXTRA_RECOMMENDATION_RESULT));
366        RecommendationResult result =
367                mOnResultListener.receivedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT);
368        assertTrue(result.hasRecommendation());
369        assertEquals(mRecommendationRequest.getDefaultWifiConfig().SSID,
370                result.getWifiConfiguration().SSID);
371    }
372
373    @Test
374    public void testRequestRecommendationAsync_requestSucceeds() throws Exception {
375        injectProvider();
376        final Bundle bundle = new Bundle();
377        doAnswer(invocation -> {
378            invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle);
379            return null;
380        }).when(mRecommendationProvider)
381                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
382                        anyInt());
383
384        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
385                mRemoteCallback);
386        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
387        assertTrue(callbackRan);
388        // If it's not the same instance then something else ran the callback.
389        assertSame(bundle, mOnResultListener.receivedBundle);
390    }
391
392    @Test
393    public void testRequestRecommendationAsync_requestThrowsRemoteException() throws Exception {
394        injectProvider();
395        doThrow(new RemoteException()).when(mRecommendationProvider)
396                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
397                        anyInt());
398
399        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
400                mRemoteCallback);
401        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
402        assertTrue(callbackRan);
403    }
404
405    @Test
406    public void dispatchingContentObserver_nullUri() throws Exception {
407        NetworkScoreService.DispatchingContentObserver observer =
408                new NetworkScoreService.DispatchingContentObserver(mContext, null /*handler*/);
409
410        observer.onChange(false, null);
411        // nothing to assert or verify but since we passed in a null handler we'd see a NPE
412        // if it were interacted with.
413    }
414
415    @Test
416    public void dispatchingContentObserver_dispatchUri() throws Exception {
417        final CountDownHandler handler = new CountDownHandler(mHandlerThread.getLooper());
418        NetworkScoreService.DispatchingContentObserver observer =
419                new NetworkScoreService.DispatchingContentObserver(mContext, handler);
420        Uri uri = Uri.parse("content://settings/global/network_score_service_test");
421        int expectedWhat = 24;
422        observer.observe(uri, expectedWhat);
423
424        observer.onChange(false, uri);
425        final boolean msgHandled = handler.latch.await(3, TimeUnit.SECONDS);
426        assertTrue(msgHandled);
427        assertEquals(expectedWhat, handler.receivedWhat);
428    }
429
430    @Test
431    public void oneTimeCallback_multipleCallbacks() throws Exception {
432        NetworkScoreService.OneTimeCallback callback =
433                new NetworkScoreService.OneTimeCallback(mRemoteCallback);
434        callback.sendResult(null);
435        callback.sendResult(null);
436        assertEquals(1, mOnResultListener.resultCount);
437    }
438
439    @Test
440    public void testUpdateScores_notActiveScorer() {
441        bindToScorer(false /*callerIsScorer*/);
442
443        try {
444            mNetworkScoreService.updateScores(new ScoredNetwork[0]);
445            fail("SecurityException expected");
446        } catch (SecurityException e) {
447            // expected
448        }
449    }
450
451    @Test
452    public void testUpdateScores_oneRegisteredCache() throws RemoteException {
453        bindToScorer(true /*callerIsScorer*/);
454
455        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
456                mNetworkScoreCache, CACHE_FILTER_NONE);
457
458        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
459
460        verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture());
461
462        assertEquals(1, mScoredNetworkCaptor.getValue().size());
463        assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0));
464    }
465
466    @Test
467    public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
468        bindToScorer(true /*callerIsScorer*/);
469
470        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
471                mNetworkScoreCache, CACHE_FILTER_NONE);
472        mNetworkScoreService.registerNetworkScoreCache(
473                NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE);
474
475        // updateScores should update both caches
476        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
477
478        verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class));
479        verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class));
480
481        mNetworkScoreService.unregisterNetworkScoreCache(
482                NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
483
484        // updateScores should only update the first cache since the 2nd has been unregistered
485        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
486
487        verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class));
488
489        mNetworkScoreService.unregisterNetworkScoreCache(
490                NetworkKey.TYPE_WIFI, mNetworkScoreCache);
491
492        // updateScores should not update any caches since they are both unregistered
493        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
494
495        // The register and unregister calls grab the binder from the score cache.
496        verify(mNetworkScoreCache, atLeastOnce()).asBinder();
497        verify(mNetworkScoreCache2, atLeastOnce()).asBinder();
498        verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2);
499    }
500
501    @Test
502    public void testClearScores_notActiveScorer_noRequestNetworkScoresPermission() {
503        bindToScorer(false /*callerIsScorer*/);
504        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
505            .thenReturn(PackageManager.PERMISSION_DENIED);
506        try {
507            mNetworkScoreService.clearScores();
508            fail("SecurityException expected");
509        } catch (SecurityException e) {
510            // expected
511        }
512    }
513
514    @Test
515    public void testClearScores_activeScorer_noRequestNetworkScoresPermission() {
516        bindToScorer(true /*callerIsScorer*/);
517        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
518            .thenReturn(PackageManager.PERMISSION_DENIED);
519
520        mNetworkScoreService.clearScores();
521    }
522
523    @Test
524    public void testClearScores_activeScorer() throws RemoteException {
525        bindToScorer(true /*callerIsScorer*/);
526
527        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
528                CACHE_FILTER_NONE);
529        mNetworkScoreService.clearScores();
530
531        verify(mNetworkScoreCache).clearScores();
532    }
533
534    @Test
535    public void testClearScores_notActiveScorer_hasRequestNetworkScoresPermission()
536            throws RemoteException {
537        bindToScorer(false /*callerIsScorer*/);
538        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
539                .thenReturn(PackageManager.PERMISSION_GRANTED);
540
541        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
542                CACHE_FILTER_NONE);
543        mNetworkScoreService.clearScores();
544
545        verify(mNetworkScoreCache).clearScores();
546    }
547
548    @Test
549    public void testSetActiveScorer_noScoreNetworksPermission() {
550        doThrow(new SecurityException()).when(mContext)
551                .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
552
553        try {
554            mNetworkScoreService.setActiveScorer(null);
555            fail("SecurityException expected");
556        } catch (SecurityException e) {
557            // expected
558        }
559    }
560
561    @Test
562    public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() {
563        bindToScorer(false /*callerIsScorer*/);
564        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
565                .thenReturn(PackageManager.PERMISSION_DENIED);
566
567        try {
568            mNetworkScoreService.disableScoring();
569            fail("SecurityException expected");
570        } catch (SecurityException e) {
571            // expected
572        }
573    }
574
575    @Test
576    public void testRegisterNetworkScoreCache_noRequestNetworkScoresPermission() {
577        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
578                eq(permission.REQUEST_NETWORK_SCORES), anyString());
579
580        try {
581            mNetworkScoreService.registerNetworkScoreCache(
582                NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE);
583            fail("SecurityException expected");
584        } catch (SecurityException e) {
585            // expected
586        }
587    }
588
589    @Test
590    public void testUnregisterNetworkScoreCache_noRequestNetworkScoresPermission() {
591        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
592                eq(permission.REQUEST_NETWORK_SCORES), anyString());
593
594        try {
595            mNetworkScoreService.unregisterNetworkScoreCache(
596                    NetworkKey.TYPE_WIFI, mNetworkScoreCache);
597            fail("SecurityException expected");
598        } catch (SecurityException e) {
599            // expected
600        }
601    }
602
603    @Test
604    public void testDump_noDumpPermission() {
605        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
606                eq(permission.DUMP), anyString());
607
608        try {
609            mNetworkScoreService.dump(
610                    new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]);
611            fail("SecurityException expected");
612        } catch (SecurityException e) {
613            // expected
614        }
615    }
616
617    @Test
618    public void testDump_doesNotCrash() {
619        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
620        StringWriter stringWriter = new StringWriter();
621
622        mNetworkScoreService.dump(
623                new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
624
625        assertFalse(stringWriter.toString().isEmpty());
626    }
627
628    @Test
629    public void testIsCallerActiveScorer_noBoundService() throws Exception {
630        mNetworkScoreService.systemRunning();
631
632        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
633    }
634
635    @Test
636    public void testIsCallerActiveScorer_boundServiceIsNotCaller() throws Exception {
637        bindToScorer(false /*callerIsScorer*/);
638
639        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
640    }
641
642    @Test
643    public void testIsCallerActiveScorer_boundServiceIsCaller() throws Exception {
644        bindToScorer(true /*callerIsScorer*/);
645
646        assertTrue(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
647    }
648
649    @Test
650    public void testGetActiveScorerPackage_notActive() throws Exception {
651        mNetworkScoreService.systemRunning();
652
653        assertNull(mNetworkScoreService.getActiveScorerPackage());
654    }
655
656    @Test
657    public void testGetActiveScorerPackage_active() throws Exception {
658        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
659        mNetworkScoreService.systemRunning();
660
661        assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
662                mNetworkScoreService.getActiveScorerPackage());
663    }
664
665    @Test
666    public void testCacheUpdatingConsumer_nullFilter() throws Exception {
667        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
668        NetworkScoreService.FilteringCacheUpdatingConsumer consumer =
669                new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
670                        new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI,
671                        mCurrentNetworkFilter, mScanResultsFilter);
672
673        consumer.accept(mNetworkScoreCache, null /*cookie*/);
674
675        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
676        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
677    }
678
679    @Test
680    public void testCacheUpdatingConsumer_noneFilter() throws Exception {
681        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
682        NetworkScoreService.FilteringCacheUpdatingConsumer
683                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
684                new ArrayList<>(scoredNetworkList),
685                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
686
687        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
688
689        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
690        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
691    }
692
693    @Test
694    public void testCacheUpdatingConsumer_unknownFilter() throws Exception {
695        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
696        NetworkScoreService.FilteringCacheUpdatingConsumer
697                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
698                new ArrayList<>(scoredNetworkList),
699                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
700
701        consumer.accept(mNetworkScoreCache, -1 /*cookie*/);
702
703        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
704        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
705    }
706
707    @Test
708    public void testCacheUpdatingConsumer_nonIntFilter() throws Exception {
709        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
710        NetworkScoreService.FilteringCacheUpdatingConsumer
711                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
712                new ArrayList<>(scoredNetworkList),
713                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
714
715        consumer.accept(mNetworkScoreCache, "not an int" /*cookie*/);
716
717        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
718        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
719    }
720
721    @Test
722    public void testCacheUpdatingConsumer_emptyScoreList() throws Exception {
723        NetworkScoreService.FilteringCacheUpdatingConsumer
724                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
725                Collections.emptyList(),
726                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
727
728        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
729
730        verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
731    }
732
733    @Test
734    public void testCacheUpdatingConsumer_currentNetworkFilter() throws Exception {
735        List<ScoredNetwork> scoredNetworkList =
736                Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
737        NetworkScoreService.FilteringCacheUpdatingConsumer
738                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
739                new ArrayList<>(scoredNetworkList),
740                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
741
742        List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
743        filteredList.remove(SCORED_NETWORK);
744        when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
745        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
746
747        verify(mNetworkScoreCache).updateScores(filteredList);
748        verifyZeroInteractions(mScanResultsFilter);
749    }
750
751    @Test
752    public void testCacheUpdatingConsumer_scanResultsFilter() throws Exception {
753        List<ScoredNetwork> scoredNetworkList =
754                Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
755        NetworkScoreService.FilteringCacheUpdatingConsumer
756                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
757                new ArrayList<>(scoredNetworkList),
758                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
759
760        List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
761        filteredList.remove(SCORED_NETWORK);
762        when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
763        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
764
765        verify(mNetworkScoreCache).updateScores(filteredList);
766        verifyZeroInteractions(mCurrentNetworkFilter);
767    }
768
769    @Test
770    public void testCurrentNetworkScoreCacheFilter_nullWifiInfo() throws Exception {
771        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
772                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> null /*WifiInfo*/);
773
774        List<ScoredNetwork> actualList =
775                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
776
777        assertTrue(actualList.isEmpty());
778    }
779
780    @Test
781    public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
782        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
783                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
784
785        List<ScoredNetwork> actualList =
786                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
787
788        List<ScoredNetwork> expectedList = Collections.singletonList(SCORED_NETWORK);
789        assertEquals(expectedList, actualList);
790    }
791
792    @Test
793    public void testCurrentNetworkScoreCacheFilter_currentNetworkNotInList() throws Exception {
794        when(mWifiInfo.getSSID()).thenReturn("\"notInList\"");
795        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
796                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
797
798        List<ScoredNetwork> actualList =
799                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
800
801        assertTrue(actualList.isEmpty());
802    }
803
804    @Test
805    public void testScanResultsScoreCacheFilter_emptyScanResults() throws Exception {
806        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
807                new NetworkScoreService.ScanResultsScoreCacheFilter(Collections::emptyList);
808
809        List<ScoredNetwork> actualList =
810                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
811
812        assertTrue(actualList.isEmpty());
813    }
814
815    @Test
816    public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
817        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
818                new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);
819
820        ScoredNetwork unmatchedScore =
821                new ScoredNetwork(new NetworkKey(new WifiKey(quote("newSsid"),
822                        "00:00:00:00:00:00")), null /* rssiCurve*/);
823
824        List<ScoredNetwork> actualList =
825                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2,
826                        unmatchedScore));
827
828        List<ScoredNetwork> expectedList = Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
829        assertEquals(expectedList, actualList);
830    }
831
832    @Test
833    public void testGetActiveScorer_notConnected_canRequestScores() throws Exception {
834        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
835                .thenReturn(PackageManager.PERMISSION_GRANTED);
836        assertNull(mNetworkScoreService.getActiveScorer());
837    }
838
839    @Test
840    public void testGetActiveScorer_notConnected_canNotRequestScores() throws Exception {
841        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
842                .thenReturn(PackageManager.PERMISSION_DENIED);
843        try {
844            mNetworkScoreService.getActiveScorer();
845            fail("SecurityException expected.");
846        } catch (SecurityException e) {
847            // expected
848        }
849    }
850
851    @Test
852    public void testGetActiveScorer_connected_canRequestScores()
853            throws Exception {
854        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
855                .thenReturn(PackageManager.PERMISSION_GRANTED);
856        NetworkScorerAppData expectedAppData =
857                new NetworkScorerAppData(Binder.getCallingUid(), RECOMMENDATION_SERVICE_COMP);
858        bindToScorer(expectedAppData);
859        assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
860    }
861
862    @Test
863    public void testGetActiveScorer_connected_canNotRequestScores()
864            throws Exception {
865        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
866                .thenReturn(PackageManager.PERMISSION_DENIED);
867        bindToScorer(false);
868        try {
869            mNetworkScoreService.getActiveScorer();
870            fail("SecurityException expected.");
871        } catch (SecurityException e) {
872            // expected
873        }
874    }
875
876    // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
877    private void injectProvider() {
878        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
879        when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
880                isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() {
881            @Override
882            public Boolean answer(InvocationOnMock invocation) throws Throwable {
883                IBinder mockBinder = mock(IBinder.class);
884                when(mockBinder.queryLocalInterface(anyString()))
885                        .thenReturn(mRecommendationProvider);
886                invocation.getArgumentAt(1, ServiceConnection.class)
887                        .onServiceConnected(NEW_SCORER.getRecommendationServiceComponent(),
888                                mockBinder);
889                return true;
890            }
891        });
892        mNetworkScoreService.systemRunning();
893    }
894
895    private void bindToScorer(boolean callerIsScorer) {
896        final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
897        NetworkScorerAppData appData =
898                new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
899        bindToScorer(appData);
900    }
901
902    private void bindToScorer(NetworkScorerAppData appData) {
903        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
904        when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
905                isA(UserHandle.class))).thenReturn(true);
906        mNetworkScoreService.systemRunning();
907    }
908
909    private static class OnResultListener implements RemoteCallback.OnResultListener {
910        private final CountDownLatch countDownLatch = new CountDownLatch(1);
911        private int resultCount;
912        private Bundle receivedBundle;
913
914        @Override
915        public void onResult(Bundle result) {
916            countDownLatch.countDown();
917            resultCount++;
918            receivedBundle = result;
919        }
920    }
921
922    private static class CountDownHandler extends Handler {
923        CountDownLatch latch = new CountDownLatch(1);
924        int receivedWhat;
925
926        CountDownHandler(Looper looper) {
927            super(looper);
928        }
929
930        @Override
931        public void handleMessage(Message msg) {
932            latch.countDown();
933            receivedWhat = msg.what;
934        }
935    }
936}
937