1/*
2 * Copyright (C) 2017 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.settings.fuelgauge.anomaly.checker;
18
19import static com.google.common.truth.Truth.assertThat;
20
21import static org.mockito.ArgumentMatchers.nullable;
22import static org.mockito.Matchers.any;
23import static org.mockito.Matchers.anyLong;
24import static org.mockito.Matchers.eq;
25import static org.mockito.Mockito.doReturn;
26import static org.mockito.Mockito.spy;
27
28import android.content.Context;
29import android.content.pm.ApplicationInfo;
30import android.os.BatteryStats;
31import android.text.format.DateUtils;
32
33import com.android.internal.os.BatterySipper;
34import com.android.internal.os.BatteryStatsHelper;
35import com.android.settings.TestConfig;
36import com.android.settings.fuelgauge.BatteryUtils;
37import com.android.settings.fuelgauge.anomaly.Anomaly;
38import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
39import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
40import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
41import com.android.settings.testutils.SettingsRobolectricTestRunner;
42
43import org.junit.Before;
44import org.junit.Test;
45import org.junit.runner.RunWith;
46import org.mockito.Mock;
47import org.mockito.MockitoAnnotations;
48import org.robolectric.RuntimeEnvironment;
49import org.robolectric.annotation.Config;
50import org.robolectric.util.ReflectionHelpers;
51
52import java.util.ArrayList;
53import java.util.List;
54
55@RunWith(SettingsRobolectricTestRunner.class)
56@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
57public class BluetoothScanAnomalyDetectorTest {
58    private static final String TARGET_PACKAGE_NAME = "com.android.app";
59    private static final int ANOMALY_UID = 111;
60    private static final int NORMAL_UID = 222;
61    private static final int TARGET_UID = 333;
62    private static final long ANOMALY_BLUETOOTH_SCANNING_TIME = DateUtils.HOUR_IN_MILLIS;
63    private static final long NORMAL_BLUETOOTH_SCANNING_TIME = DateUtils.MINUTE_IN_MILLIS;
64    @Mock
65    private BatteryStatsHelper mBatteryStatsHelper;
66    @Mock
67    private BatterySipper mAnomalySipper;
68    @Mock
69    private BatterySipper mNormalSipper;
70    @Mock
71    private BatterySipper mTargetSipper;
72    @Mock
73    private BatteryStats.Uid mAnomalyUid;
74    @Mock
75    private BatteryStats.Uid mNormalUid;
76    @Mock
77    private BatteryStats.Uid mTargetUid;
78    @Mock
79    private BatteryUtils mBatteryUtils;
80    @Mock
81    private AnomalyDetectionPolicy mPolicy;
82    @Mock
83    private AnomalyAction mAnomalyAction;
84    @Mock
85    private AnomalyUtils mAnomalyUtils;
86
87    private BluetoothScanAnomalyDetector mBluetoothScanAnomalyDetector;
88    private Context mContext;
89    private List<BatterySipper> mUsageList;
90
91    @Before
92    public void setUp() {
93        MockitoAnnotations.initMocks(this);
94
95        mContext = spy(RuntimeEnvironment.application);
96        ReflectionHelpers.setField(mPolicy, "bluetoothScanThreshold",
97                30 * DateUtils.MINUTE_IN_MILLIS);
98        doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(any());
99
100        mAnomalySipper.uidObj = mAnomalyUid;
101        doReturn(ANOMALY_UID).when(mAnomalyUid).getUid();
102        mNormalSipper.uidObj = mNormalUid;
103        doReturn(NORMAL_UID).when(mNormalUid).getUid();
104        mTargetSipper.uidObj = mTargetUid;
105        doReturn(TARGET_UID).when(mTargetUid).getUid();
106
107        mUsageList = new ArrayList<>();
108        mUsageList.add(mAnomalySipper);
109        mUsageList.add(mNormalSipper);
110        mUsageList.add(mTargetSipper);
111        doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
112
113        mBluetoothScanAnomalyDetector = spy(new BluetoothScanAnomalyDetector(mContext, mPolicy,
114                mAnomalyUtils));
115        mBluetoothScanAnomalyDetector.mBatteryUtils = mBatteryUtils;
116        doReturn(false).when(mBatteryUtils).shouldHideSipper(any());
117        doReturn(true).when(mAnomalyAction).isActionActive(any());
118
119        doReturn(ANOMALY_BLUETOOTH_SCANNING_TIME).when(
120                mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mAnomalyUid),
121                anyLong());
122        doReturn(ANOMALY_BLUETOOTH_SCANNING_TIME).when(
123                mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mTargetUid),
124                anyLong());
125        doReturn(NORMAL_BLUETOOTH_SCANNING_TIME).when(
126                mBluetoothScanAnomalyDetector).getBluetoothUnoptimizedBgTimeMs(eq(mNormalUid),
127                anyLong());
128    }
129
130    @Test
131    public void testDetectAnomalies_containsAnomaly_detectIt() {
132        doReturn(-1).when(mBatteryUtils).getPackageUid(nullable(String.class));
133        final Anomaly anomaly = createBluetoothAnomaly(ANOMALY_UID);
134        final Anomaly targetAnomaly = createBluetoothAnomaly(TARGET_UID);
135
136        List<Anomaly> mAnomalies = mBluetoothScanAnomalyDetector.detectAnomalies(
137                mBatteryStatsHelper);
138
139        assertThat(mAnomalies).containsExactly(anomaly, targetAnomaly);
140    }
141
142    @Test
143    public void testDetectAnomalies_detectTargetAnomaly_detectIt() {
144        doReturn(TARGET_UID).when(mBatteryUtils).getPackageUid(TARGET_PACKAGE_NAME);
145        final Anomaly targetAnomaly = createBluetoothAnomaly(TARGET_UID);
146
147        List<Anomaly> mAnomalies = mBluetoothScanAnomalyDetector.detectAnomalies(
148                mBatteryStatsHelper, TARGET_PACKAGE_NAME);
149
150        assertThat(mAnomalies).containsExactly(targetAnomaly);
151
152    }
153
154    private Anomaly createBluetoothAnomaly(int uid) {
155        return new Anomaly.Builder()
156                .setUid(uid)
157                .setType(Anomaly.AnomalyType.BLUETOOTH_SCAN)
158                .setBluetoothScanningTimeMs(ANOMALY_BLUETOOTH_SCANNING_TIME)
159                .build();
160    }
161
162}
163