1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.tare;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.mockito.Mockito.doReturn;
23 import static org.mockito.Mockito.mock;
24 
25 import androidx.test.filters.SmallTest;
26 import androidx.test.runner.AndroidJUnit4;
27 
28 import com.android.internal.app.IBatteryStats;
29 
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 /** Test that the Analyst processes transactions correctly. */
37 @RunWith(AndroidJUnit4.class)
38 @SmallTest
39 public class AnalystTest {
40 
41     @Test
testInitialState()42     public void testInitialState() {
43         final Analyst analyst = new Analyst();
44         assertEquals(0, analyst.getReports().size());
45     }
46 
47     @Test
testBatteryLevelChange()48     public void testBatteryLevelChange() {
49         final Analyst analyst = new Analyst();
50 
51         Analyst.Report expected = new Analyst.Report();
52         expected.currentBatteryLevel = 75;
53         analyst.noteBatteryLevelChange(75);
54         assertEquals(1, analyst.getReports().size());
55         assertReportsEqual(expected, analyst.getReports().get(0));
56 
57         // Discharging
58         analyst.noteBatteryLevelChange(54);
59         expected.currentBatteryLevel = 54;
60         expected.cumulativeBatteryDischarge = 21;
61         assertEquals(1, analyst.getReports().size());
62         assertReportsEqual(expected, analyst.getReports().get(0));
63         analyst.noteBatteryLevelChange(50);
64         expected.currentBatteryLevel = 50;
65         expected.cumulativeBatteryDischarge = 25;
66         assertEquals(1, analyst.getReports().size());
67         assertReportsEqual(expected, analyst.getReports().get(0));
68 
69         // Charging
70         analyst.noteBatteryLevelChange(51);
71         expected.currentBatteryLevel = 51;
72         assertEquals(1, analyst.getReports().size());
73         assertReportsEqual(expected, analyst.getReports().get(0));
74         analyst.noteBatteryLevelChange(55);
75         expected.currentBatteryLevel = 55;
76         assertEquals(1, analyst.getReports().size());
77         assertReportsEqual(expected, analyst.getReports().get(0));
78 
79         // Reset
80         analyst.noteBatteryLevelChange(100);
81         assertEquals(2, analyst.getReports().size());
82         assertReportsEqual(expected, analyst.getReports().get(0));
83         expected.currentBatteryLevel = 100;
84         expected.cumulativeBatteryDischarge = 0;
85         assertReportsEqual(expected, analyst.getReports().get(1));
86     }
87 
88     @Test
testTransaction()89     public void testTransaction() {
90         runTestTransactions(new Analyst(), new Analyst.Report(), 1);
91     }
92 
93     @Test
testTransaction_PeriodChange()94     public void testTransaction_PeriodChange() throws Exception {
95         IBatteryStats iBatteryStats = mock(IBatteryStats.class);
96         final Analyst analyst = new Analyst(iBatteryStats);
97 
98         // Reset from enough discharge.
99         Analyst.Report expected = new Analyst.Report();
100         expected.currentBatteryLevel = 75;
101         analyst.noteBatteryLevelChange(75);
102 
103         runTestTransactions(analyst, expected, 1);
104 
105         expected.currentBatteryLevel = 49;
106         expected.cumulativeBatteryDischarge = 26;
107         analyst.noteBatteryLevelChange(49);
108 
109         runTestTransactions(analyst, expected, 1);
110 
111         expected = new Analyst.Report();
112         expected.currentBatteryLevel = 90;
113         analyst.noteBatteryLevelChange(90);
114         expected.cumulativeBatteryDischarge = 0;
115 
116         runTestTransactions(analyst, expected, 2);
117 
118         // Reset from report being long enough.
119         doReturn(Analyst.MIN_REPORT_DURATION_FOR_RESET)
120                 .when(iBatteryStats).computeBatteryScreenOffRealtimeMs();
121         expected.currentBatteryLevel = 85;
122         analyst.noteBatteryLevelChange(85);
123         expected.cumulativeBatteryDischarge = 5;
124         expected.screenOffDurationMs = Analyst.MIN_REPORT_DURATION_FOR_RESET;
125 
126         runTestTransactions(analyst, expected, 2);
127 
128         expected.currentBatteryLevel = 79;
129         analyst.noteBatteryLevelChange(79);
130         expected.cumulativeBatteryDischarge = 11;
131 
132         runTestTransactions(analyst, expected, 2);
133 
134         expected = new Analyst.Report();
135         expected.currentBatteryLevel = 80;
136         analyst.noteBatteryLevelChange(80);
137         expected.cumulativeBatteryDischarge = 0;
138         expected.screenOffDurationMs = 0;
139 
140         runTestTransactions(analyst, expected, 3);
141     }
142 
runTestTransactions(Analyst analyst, Analyst.Report lastExpectedReport, int numExpectedReports)143     private void runTestTransactions(Analyst analyst, Analyst.Report lastExpectedReport,
144             int numExpectedReports) {
145         Analyst.Report expected = lastExpectedReport;
146 
147         // Profit
148         analyst.noteTransaction(
149                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -51, 1));
150         expected.cumulativeProfit += 50;
151         expected.numProfitableActions += 1;
152         assertEquals(numExpectedReports, analyst.getReports().size());
153         assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
154 
155         // Loss
156         analyst.noteTransaction(
157                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -51, 100));
158         expected.cumulativeLoss += 49;
159         expected.numUnprofitableActions += 1;
160         assertEquals(numExpectedReports, analyst.getReports().size());
161         assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
162 
163         // Reward
164         analyst.noteTransaction(
165                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD, null, 51, 0));
166         expected.cumulativeRewards += 51;
167         expected.numRewards += 1;
168         assertEquals(numExpectedReports, analyst.getReports().size());
169         assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
170 
171         // Regulations
172         analyst.noteTransaction(
173                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, 25, 0));
174         expected.cumulativePositiveRegulations += 25;
175         expected.numPositiveRegulations += 1;
176         assertEquals(numExpectedReports, analyst.getReports().size());
177         assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
178         analyst.noteTransaction(
179                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, -25, 0));
180         expected.cumulativeNegativeRegulations += 25;
181         expected.numNegativeRegulations += 1;
182         assertEquals(numExpectedReports, analyst.getReports().size());
183         assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
184 
185         // No-ops
186         analyst.noteTransaction(
187                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -100, 100));
188         analyst.noteTransaction(
189                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, 0, 0));
190         analyst.noteTransaction(
191                 new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD, null, 0, 0));
192         assertEquals(numExpectedReports, analyst.getReports().size());
193     }
194 
195     @Test
testLoadReports()196     public void testLoadReports() {
197         final Analyst analyst = new Analyst();
198 
199         List<Analyst.Report> expected = new ArrayList<>();
200         analyst.loadReports(expected);
201         assertReportListsEqual(expected, analyst.getReports());
202 
203         Analyst.Report report1 = new Analyst.Report();
204         report1.cumulativeBatteryDischarge = 1;
205         report1.currentBatteryLevel = 2;
206         report1.cumulativeProfit = 3;
207         report1.numProfitableActions = 4;
208         report1.cumulativeLoss = 5;
209         report1.numUnprofitableActions = 6;
210         report1.cumulativeRewards = 7;
211         report1.numRewards = 8;
212         report1.cumulativePositiveRegulations = 9;
213         report1.numPositiveRegulations = 10;
214         report1.cumulativeNegativeRegulations = 11;
215         report1.numNegativeRegulations = 12;
216         expected.add(report1);
217         analyst.loadReports(expected);
218         assertReportListsEqual(expected, analyst.getReports());
219 
220         Analyst.Report report2 = new Analyst.Report();
221         report2.cumulativeBatteryDischarge = 10;
222         report2.currentBatteryLevel = 20;
223         report2.cumulativeProfit = 30;
224         report2.numProfitableActions = 40;
225         report2.cumulativeLoss = 50;
226         report2.numUnprofitableActions = 60;
227         report2.cumulativeRewards = 70;
228         report2.numRewards = 80;
229         report2.cumulativePositiveRegulations = 90;
230         report2.numPositiveRegulations = 100;
231         report2.cumulativeNegativeRegulations = 110;
232         report2.numNegativeRegulations = 120;
233         expected.add(report2);
234         analyst.loadReports(expected);
235         assertReportListsEqual(expected, analyst.getReports());
236     }
237 
assertReportsEqual(Analyst.Report expected, Analyst.Report actual)238     private void assertReportsEqual(Analyst.Report expected, Analyst.Report actual) {
239         if (expected == null) {
240             assertNull(actual);
241             return;
242         }
243         assertNotNull(actual);
244         assertEquals(expected.cumulativeBatteryDischarge, actual.cumulativeBatteryDischarge);
245         assertEquals(expected.currentBatteryLevel, actual.currentBatteryLevel);
246         assertEquals(expected.cumulativeProfit, actual.cumulativeProfit);
247         assertEquals(expected.numProfitableActions, actual.numProfitableActions);
248         assertEquals(expected.cumulativeLoss, actual.cumulativeLoss);
249         assertEquals(expected.numUnprofitableActions, actual.numUnprofitableActions);
250         assertEquals(expected.cumulativeRewards, actual.cumulativeRewards);
251         assertEquals(expected.numRewards, actual.numRewards);
252         assertEquals(expected.cumulativePositiveRegulations, actual.cumulativePositiveRegulations);
253         assertEquals(expected.numPositiveRegulations, actual.numPositiveRegulations);
254         assertEquals(expected.cumulativeNegativeRegulations, actual.cumulativeNegativeRegulations);
255         assertEquals(expected.numNegativeRegulations, actual.numNegativeRegulations);
256         assertEquals(expected.screenOffDurationMs, actual.screenOffDurationMs);
257         assertEquals(expected.screenOffDischargeMah, actual.screenOffDischargeMah);
258     }
259 
assertReportListsEqual(List<Analyst.Report> expected, List<Analyst.Report> actual)260     private void assertReportListsEqual(List<Analyst.Report> expected,
261             List<Analyst.Report> actual) {
262         if (expected == null) {
263             assertNull(actual);
264             return;
265         }
266         assertNotNull(actual);
267         assertEquals(expected.size(), actual.size());
268         for (int i = 0; i < expected.size(); ++i) {
269             assertReportsEqual(expected.get(i), actual.get(i));
270         }
271     }
272 }
273