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