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