157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass/*
257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * Copyright (C) 2017 The Android Open Source Project
357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass *
457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * Licensed under the Apache License, Version 2.0 (the "License");
557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * you may not use this file except in compliance with the License.
657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * You may obtain a copy of the License at
757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass *
857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass *      http://www.apache.org/licenses/LICENSE-2.0
957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass *
1057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * Unless required by applicable law or agreed to in writing, software
1157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * distributed under the License is distributed on an "AS IS" BASIS,
1257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * See the License for the specific language governing permissions and
1457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * limitations under the License.
1557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass */
1657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
1757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plasspackage com.android.server.wifi;
1857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
1957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport static org.junit.Assert.assertTrue;
2057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport static org.mockito.Mockito.doReturn;
2157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport static org.mockito.Mockito.when;
2257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
2357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport android.content.Context;
2457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport android.content.res.Resources;
2557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport android.net.wifi.WifiInfo;
2657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
2757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport com.android.internal.R;
2857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
2957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport org.junit.Before;
3057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport org.junit.Test;
3157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport org.mockito.Mock;
3257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport org.mockito.MockitoAnnotations;
3357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plassimport org.mockito.Spy;
3457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
3557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass/**
3657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass * Unit tests for {@link com.android.server.wifi.VelocityBasedConnectedScore}.
3757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass */
3857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plasspublic class VelocityBasedConnectedScoreTest {
3957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
4057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
4157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    class FakeClock extends Clock {
4257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        long mWallClockMillis = 1500000000000L;
4357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        int mStepMillis = 3001;
4457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
4557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        @Override
4657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        public long getWallClockMillis() {
4757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass            mWallClockMillis += mStepMillis;
4857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass            return mWallClockMillis;
4957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        }
5057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
5157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
5257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    FakeClock mClock;
5357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    VelocityBasedConnectedScore mVelocityBasedConnectedScore;
5457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    ScanDetailCache mScanDetailCache;
5557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    WifiInfo mWifiInfo;
5657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    int mRssiExitThreshold2GHz;
5757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    int mRssiExitThreshold5GHz;
5857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    @Mock Context mContext;
5957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    @Spy private MockResources mResources = new MockResources();
6057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
6157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    private int setupIntegerResource(int resourceName, int value) {
6257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        doReturn(value).when(mResources).getInteger(resourceName);
6357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        return value;
6457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
6557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
6657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    /**
6757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Sets up resource values for testing
6857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     *
6957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * See frameworks/base/core/res/res/values/config.xml
7057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     */
7157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    private void setUpResources(Resources resources) {
7257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mRssiExitThreshold2GHz = setupIntegerResource(
7357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz, -83);
7457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mRssiExitThreshold5GHz = setupIntegerResource(
7557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz, -80);
7657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
7757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
7857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    /**
7957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Sets up for unit test
8057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     */
8157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    @Before
8257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    public void setUp() throws Exception {
8357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        MockitoAnnotations.initMocks(this);
8457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        setUpResources(mResources);
8557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo = new WifiInfo();
8657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.setFrequency(2412);
8757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        when(mContext.getResources()).thenReturn(mResources);
8857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mClock = new FakeClock();
8979545bef4e8d6c1d891f7396665b5c457bc31617Michael Plass        mVelocityBasedConnectedScore = new VelocityBasedConnectedScore(
9079545bef4e8d6c1d891f7396665b5c457bc31617Michael Plass            new ScoringParams(mContext), mClock);
9157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
9257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
9357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    /**
941a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass     * Generate a score with no updates
951a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass     *
961a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass     * Expect no crash, passing score
971a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass     */
981a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass    @Test
991a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass    public void noCrashWhenNoData() throws Exception {
1001a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass        int score = mVelocityBasedConnectedScore.generateScore();
1011a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass        assertTrue(score > ConnectedScore.WIFI_TRANSITION_SCORE);
1021a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass    }
1031a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass
1041a0ff86a3520e9b79ded4746171a883a7f72fcdfMichael Plass    /**
10557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     *
10657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Low RSSI, but some data is moving and error rate is low.
10757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     *
10857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Expect a score above threshold.
10957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     */
11057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    @Test
11157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    public void allowLowRssiIfErrorRateIsLowAndSomeDataIsMoving() throws Exception {
11257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.setRssi(mRssiExitThreshold2GHz - 2);
11357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.setLinkSpeed(6); // Mbps
114442a0afdad6b7eb32a9098d927ecd65aa64df6eaMichael Plass        mWifiInfo.txSuccessRate = 2.1; // proportional to pps
11557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.txBadRate = .5;
116442a0afdad6b7eb32a9098d927ecd65aa64df6eaMichael Plass        mWifiInfo.rxSuccessRate = 2.1;
11757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        for (int i = 0; i < 10; i++) {
11857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass            mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
11957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass                    mClock.getWallClockMillis());
12057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        }
12157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        int score = mVelocityBasedConnectedScore.generateScore();
122b865ae432e451bedf561619ce50ff4430447046bMichael Plass        assertTrue(score > ConnectedScore.WIFI_TRANSITION_SCORE);
12366e108c8bcc57ac1b9eef2a165907b7444c2065aMichael Plass        // If we reset, should be below threshold after the first input
12466e108c8bcc57ac1b9eef2a165907b7444c2065aMichael Plass        mVelocityBasedConnectedScore.reset();
12566e108c8bcc57ac1b9eef2a165907b7444c2065aMichael Plass        mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo, mClock.getWallClockMillis());
12666e108c8bcc57ac1b9eef2a165907b7444c2065aMichael Plass        score = mVelocityBasedConnectedScore.generateScore();
12766e108c8bcc57ac1b9eef2a165907b7444c2065aMichael Plass        assertTrue(score < ConnectedScore.WIFI_TRANSITION_SCORE);
12857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
12957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass
13057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    /**
13157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     *
13257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Low RSSI, and almost no data is moving.
13357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     *
13457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     * Expect a score below threshold.
13557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass     */
13657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    @Test
13757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    public void disallowLowRssiIfDataIsNotMoving() throws Exception {
13857a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.setRssi(mRssiExitThreshold2GHz - 1);
13957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.setLinkSpeed(6); // Mbps
14057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.txSuccessRate = .1; // proportional to pps
14157a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.txBadRate = 0;
14257a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        mWifiInfo.rxSuccessRate = .1;
14357a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        for (int i = 0; i < 10; i++) {
14457a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass            mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
14557a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass                    mClock.getWallClockMillis());
14657a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        }
14757a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass        int score = mVelocityBasedConnectedScore.generateScore();
148b865ae432e451bedf561619ce50ff4430447046bMichael Plass        assertTrue(score < ConnectedScore.WIFI_TRANSITION_SCORE);
14957a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass    }
15057a1fc416cf86d489693e0c02eb8c684f98b4cdbMichael Plass}
151