blob: 5b783109a84bee614bd634d4f1c49c08c0bc41da [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkrecommendation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.net.NetworkKey;
import android.net.NetworkRecommendationProvider;
import android.net.NetworkScoreManager;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.RssiCurve;
import android.net.ScoredNetwork;
import android.net.WifiKey;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiSsid;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Tests the recommendation provider directly, to test internals of the provider rather than the
* service's API.
*/
@RunWith(AndroidJUnit4.class)
public class DefaultNetworkRecommendationProviderTest {
private static final String GOOD_METERED_NETWORK_STRING_UNQUOTED = "Metered";
private static final String GOOD_METERED_NETWORK_STRING = "\"Metered\",aa:bb:cc:dd:ee:ff" +
"|10,-128,-128,-128,-128,-128,-128,-128,-128,20,20,20,20,-128|1|0|4K";
private static final RssiCurve GOOD_METERED_NETWORK_CURVE = new RssiCurve(
DefaultNetworkRecommendationProvider.CONSTANT_CURVE_START, 10 /* bucketWidth */,
new byte[]{-128, -128, -128, -128, -128, -128, -128, -128, 20, 20, 20, 20, -128},
0 /* defaultActiveNetworkBoost */);
private static final ScoredNetwork GOOD_METERED_NETWORK = new ScoredNetwork(
new NetworkKey(new WifiKey("\"Metered\"", "aa:bb:cc:dd:ee:ff")),
GOOD_METERED_NETWORK_CURVE, true /* meteredHint */, new Bundle());
private static final String GOOD_CAPTIVE_NETWORK_STRING_UNQUOTED = "Captive";
private static final String GOOD_CAPTIVE_NETWORK_STRING =
"\"Captive\",ff:ee:dd:cc:bb:aa"
+ "|18,-128,-128,-128,-128,-128,-128,21,21,21,-128|0|1|HD";
private static final RssiCurve GOOD_CAPTIVE_NETWORK_CURVE = new RssiCurve(
DefaultNetworkRecommendationProvider.CONSTANT_CURVE_START, 18 /* bucketWidth */,
new byte[]{-128, -128, -128, -128, -128, -128, 21, 21, 21, -128},
0 /* defaultActiveNetworkBoost */);
private static final ScoredNetwork GOOD_CAPTIVE_NETWORK;
static {
Bundle attributes = new Bundle();
attributes.putBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL, true);
GOOD_CAPTIVE_NETWORK = new ScoredNetwork(
new NetworkKey(new WifiKey("\"Captive\"", "ff:ee:dd:cc:bb:aa")),
GOOD_CAPTIVE_NETWORK_CURVE, false /* meteredHint */, attributes);
}
private static final String ANY_NETWORK_STRING_UNQUOTED = "AnySsid";
private static final String ANY_NETWORK_STRING =
"\"AnySsid\",00:00:00:00:00:00"
+ "|18,-128,-128,-128,-128,-128,-128,22,22,22,-128|0|0|NONE";
private static final RssiCurve ANY_NETWORK_CURVE = new RssiCurve(
DefaultNetworkRecommendationProvider.CONSTANT_CURVE_START, 18 /* bucketWidth */,
new byte[]{-128, -128, -128, -128, -128, -128, 22, 22, 22, -128},
0 /* defaultActiveNetworkBoost */);
private static final ScoredNetwork ANY_NETWORK = new ScoredNetwork(
new NetworkKey(new WifiKey("\"AnySsid\"", "ee:ee:ee:ee:ee:ee")),
ANY_NETWORK_CURVE, false /* meteredHint */, new Bundle());
private static final String ANY_NETWORK_SPECIFIC_STRING_UNQUOTED = "AnySsid";
private static final String ANY_NETWORK_SPECIFIC_STRING =
"\"AnySsid\",ee:ee:ee:ee:ee:ee"
+ "|18,-128,-128,-128,-128,-128,-128,23,23,23,-128|0|0|NONE";
private static final RssiCurve ANY_NETWORK_SPECIFIC_CURVE = new RssiCurve(
DefaultNetworkRecommendationProvider.CONSTANT_CURVE_START, 18 /* bucketWidth */,
new byte[]{-128, -128, -128, -128, -128, -128, 23, 23, 23, -128},
0 /* defaultActiveNetworkBoost */);
private static final ScoredNetwork ANY_NETWORK_SPECIFIC = new ScoredNetwork(
new NetworkKey(new WifiKey("\"AnySsid\"", "ee:ee:ee:ee:ee:ee")),
ANY_NETWORK_SPECIFIC_CURVE, false /* meteredHint */, new Bundle());
private static final String BAD_NETWORK_STRING_UNQUOTED = "Bad";
private static final String BAD_NETWORK_STRING =
"\"Bad\",aa:bb:cc:dd:ee:ff"
+ "|10,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128"
+ "|1|0|SD";
private static final RssiCurve BAD_NETWORK_CURVE =
new RssiCurve(
DefaultNetworkRecommendationProvider.CONSTANT_CURVE_START,
10 /* bucketWidth */,
new byte[] {-128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128},
0 /* defaultActiveNetworkBoost */);
private static final ScoredNetwork BAD_NETWORK =
new ScoredNetwork(
new NetworkKey(new WifiKey("\"Bad\"", "aa:bb:cc:dd:ee:ff")),
BAD_NETWORK_CURVE,
true /* meteredHint */,
new Bundle());
@Mock
private NetworkRecommendationProvider.ResultCallback mCallback;
@Mock
private NetworkScoreManager mNetworkScoreManager;
private DefaultNetworkRecommendationProvider.ScoreStorage mStorage;
private DefaultNetworkRecommendationProvider mProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mStorage = new DefaultNetworkRecommendationProvider.ScoreStorage();
mProvider = new DefaultNetworkRecommendationProvider(
new Handler(Looper.getMainLooper()), mNetworkScoreManager, mStorage);
}
@Test
public void basicRecommendation() throws Exception {
ScanResult[] scanResults = new ScanResult[6];
for (int i = 0; i < 3; i++) {
scanResults[i] = TestUtil.createMockScanResult(i);
}
// For now we add directly to storage, but when we start calling
// networkScoreManager.updateScores, we'll have to adjust this test.
mProvider.addScoreForTest(GOOD_METERED_NETWORK);
{
ScanResult scanResult = new ScanResult();
scanResult.level = 115;
scanResult.SSID = GOOD_METERED_NETWORK_STRING_UNQUOTED;
scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(
GOOD_METERED_NETWORK_STRING_UNQUOTED);
scanResult.BSSID = GOOD_METERED_NETWORK.networkKey.wifiKey.bssid;
scanResult.capabilities = "[ESS]";
scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
scanResults[3] = scanResult;
}
for (int i = 4; i < 6; i++) {
scanResults[i] = TestUtil.createMockScanResult(i);
}
RecommendationRequest request = new RecommendationRequest.Builder()
.setScanResults(scanResults)
.build();
RecommendationResult result = verifyAndCaptureResult(request);
assertEquals(GOOD_METERED_NETWORK.networkKey.wifiKey.ssid,
result.getWifiConfiguration().SSID);
}
@Test
public void recommendation_noScans_returnsCurrentConfig() throws Exception {
ScanResult[] scanResults = new ScanResult[0];
WifiConfiguration expectedConfig = new WifiConfiguration();
expectedConfig.SSID = "ssid";
expectedConfig.BSSID = "bssid";
RecommendationRequest request = new RecommendationRequest.Builder()
.setScanResults(scanResults)
.setDefaultWifiConfig(expectedConfig)
.build();
RecommendationResult result = verifyAndCaptureResult(request);
assertEquals(expectedConfig, result.getWifiConfiguration());
}
@Test
public void recommendation_noScans_noCurrentConfig_returnsEmpty() throws Exception {
ScanResult[] scanResults = new ScanResult[0];
RecommendationRequest request = new RecommendationRequest.Builder()
.setScanResults(scanResults)
.build();
RecommendationResult result = verifyAndCaptureResult(request);
assertNull(result.getWifiConfiguration());
}
@Test
public void scoreNetworks() throws Exception {
NetworkKey[] keys =
new NetworkKey[]{GOOD_METERED_NETWORK.networkKey, GOOD_CAPTIVE_NETWORK.networkKey};
mProvider.onRequestScores(keys);
verify(mNetworkScoreManager).updateScores(Mockito.any());
}
@Test
public void scoreNetworks_empty() throws Exception {
NetworkKey[] keys = new NetworkKey[]{};
mProvider.onRequestScores(keys);
verify(mNetworkScoreManager, times(0)).updateScores(Mockito.any());
}
@Test
public void dumpAddScores_goodMetered() {
String[] args = {"netrec", "addScore", GOOD_METERED_NETWORK_STRING};
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()), args);
ScoredNetwork[] scoredNetworks = verifyAndCaptureScoredNetworks();
assertEquals(1, scoredNetworks.length);
ScoredNetwork score = scoredNetworks[0];
assertEquals(GOOD_METERED_NETWORK.networkKey.wifiKey.ssid, score.networkKey.wifiKey.ssid);
assertEquals(GOOD_METERED_NETWORK.networkKey.wifiKey.bssid, score.networkKey.wifiKey.bssid);
assertEquals(GOOD_METERED_NETWORK.meteredHint, score.meteredHint);
assertEquals(
GOOD_METERED_NETWORK.attributes.getBoolean(
ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL),
score.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL));
assertEquals("Network curve does not match", GOOD_METERED_NETWORK_CURVE, score.rssiCurve);
assertEquals(
"Badge curve does not match",
DefaultNetworkRecommendationProvider.BADGE_CURVE_4K,
(RssiCurve) score.attributes.getParcelable(
ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE));
}
@Test
public void dumpAddScores_bad() {
String[] args = {"netrec", "addScore", BAD_NETWORK_STRING};
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()), args);
ScoredNetwork[] scoredNetworks = verifyAndCaptureScoredNetworks();
assertEquals(1, scoredNetworks.length);
ScoredNetwork score = scoredNetworks[0];
assertEquals(BAD_NETWORK.networkKey.wifiKey.ssid, score.networkKey.wifiKey.ssid);
assertEquals(BAD_NETWORK.networkKey.wifiKey.bssid, score.networkKey.wifiKey.bssid);
assertEquals(BAD_NETWORK.meteredHint, score.meteredHint);
assertEquals(
BAD_NETWORK.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL),
score.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL));
assertEquals("Network curve does not match", BAD_NETWORK_CURVE, score.rssiCurve);
assertEquals(
"Badge curve does not match",
DefaultNetworkRecommendationProvider.BADGE_CURVE_SD,
(RssiCurve) score.attributes.getParcelable(
ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE));
}
@Test
public void dumpAddScores_goodCaptivePortal() {
String[] args = {"addScore", GOOD_CAPTIVE_NETWORK_STRING};
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()), args);
ScoredNetwork[] scoredNetworks = verifyAndCaptureScoredNetworks();
assertEquals(1, scoredNetworks.length);
ScoredNetwork score = scoredNetworks[0];
assertEquals(GOOD_CAPTIVE_NETWORK.networkKey.wifiKey.ssid, score.networkKey.wifiKey.ssid);
assertEquals(GOOD_CAPTIVE_NETWORK.networkKey.wifiKey.bssid, score.networkKey.wifiKey.bssid);
assertEquals(GOOD_CAPTIVE_NETWORK.meteredHint, score.meteredHint);
assertEquals(
GOOD_CAPTIVE_NETWORK.attributes.getBoolean(
ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL),
score.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL));
assertEquals("Network curve does not match.", GOOD_CAPTIVE_NETWORK_CURVE, score.rssiCurve);
assertEquals(
"Badge curve does not match",
DefaultNetworkRecommendationProvider.BADGE_CURVE_HD,
(RssiCurve) score.attributes.getParcelable(
ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE));
}
@Test
public void dumpAddScores_anySsid() {
String[] args = {"addScore", ANY_NETWORK_STRING};
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()), args);
// We don't update the platform with the any bssid score, but we do store it.
verify(mNetworkScoreManager, times(0)).updateScores(Mockito.any());
// We do store and serve the score, though:
ScoredNetwork score = mStorage.get(ANY_NETWORK.networkKey);
assertNotNull(score);
assertEquals(ANY_NETWORK.networkKey, score.networkKey);
assertEquals(ANY_NETWORK.meteredHint, score.meteredHint);
assertEquals(
ANY_NETWORK.attributes.getBoolean(
ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL),
score.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL));
assertEquals("Network curve does not match", ANY_NETWORK_CURVE, score.rssiCurve);
assertNull(
"Badge curve should not be set.",
(RssiCurve) score.attributes.getParcelable(
ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE));
}
@Test
public void dumpAddScores_anySsid_useMoreSpecific() {
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()),
new String[] {"addScore", ANY_NETWORK_STRING});
verify(mNetworkScoreManager, times(0)).updateScores(Mockito.any());
mProvider.dump(null /* fd */, new PrintWriter(new StringWriter()),
new String[] {"addScore", ANY_NETWORK_SPECIFIC_STRING});
verify(mNetworkScoreManager).updateScores(Mockito.any());
// We don't update the platform with the any bssid score, but we do store it.
ScoredNetwork score = mStorage.get(ANY_NETWORK.networkKey);
assertNotNull(score);
assertEquals(ANY_NETWORK_SPECIFIC.networkKey, score.networkKey);
assertEquals(ANY_NETWORK_SPECIFIC.meteredHint, score.meteredHint);
assertEquals(
ANY_NETWORK_SPECIFIC.attributes.getBoolean(
ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL),
score.attributes.getBoolean(ScoredNetwork.ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL));
assertEquals("Network curve does not match", ANY_NETWORK_SPECIFIC_CURVE, score.rssiCurve);
assertNull(
"Badge curve should not be set.",
(RssiCurve) score.attributes.getParcelable(
ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE));
}
private RecommendationResult verifyAndCaptureResult(
RecommendationRequest request) {
mProvider.onRequestRecommendation(request, mCallback);
ArgumentCaptor<RecommendationResult> resultCaptor =
ArgumentCaptor.forClass(RecommendationResult.class);
verify(mCallback).onResult(resultCaptor.capture());
return resultCaptor.getValue();
}
private ScoredNetwork[] verifyAndCaptureScoredNetworks() {
ArgumentCaptor<ScoredNetwork[]> resultCaptor = ArgumentCaptor.forClass(
ScoredNetwork[].class);
verify(mNetworkScoreManager).updateScores(resultCaptor.capture());
return resultCaptor.getValue();
}
}