• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.car.storagemonitoring;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.Mockito.doAnswer;
27 import static org.mockito.Mockito.doReturn;
28 
29 import android.car.storagemonitoring.IoStats;
30 import android.car.storagemonitoring.IoStatsEntry;
31 import android.car.storagemonitoring.LifetimeWriteInfo;
32 import android.car.storagemonitoring.UidIoRecord;
33 import android.car.storagemonitoring.WearEstimate;
34 import android.car.storagemonitoring.WearEstimateChange;
35 import android.hardware.health.V2_0.IHealth;
36 import android.hardware.health.V2_0.IHealth.getStorageInfoCallback;
37 import android.hardware.health.V2_0.Result;
38 import android.hardware.health.V2_0.StorageInfo;
39 import android.os.Parcel;
40 import android.test.suitebuilder.annotation.MediumTest;
41 import android.util.JsonReader;
42 import android.util.JsonWriter;
43 import android.util.SparseArray;
44 
45 import com.android.car.test.utils.TemporaryDirectory;
46 import com.android.car.test.utils.TemporaryFile;
47 
48 import org.json.JSONObject;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.Mock;
52 import org.mockito.junit.MockitoJUnitRunner;
53 
54 import java.io.FileWriter;
55 import java.io.StringReader;
56 import java.io.StringWriter;
57 import java.nio.file.Files;
58 import java.time.Instant;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collections;
62 import java.util.List;
63 
64 /**
65  * Tests the storage monitoring API in CarService.
66  */
67 @RunWith(MockitoJUnitRunner.class)
68 @MediumTest
69 public class CarStorageMonitoringTest {
70     static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
71 
72     @Mock private IHealth mMockedHal;
73     @Mock private HealthServiceWearInfoProvider.IHealthSupplier mHealthServiceSupplier;
74 
75     @Test
testEMmcWearInformationProvider()76     public void testEMmcWearInformationProvider() throws Exception {
77         try (TemporaryFile lifetimeFile = new TemporaryFile(TAG)) {
78             try (TemporaryFile eolFile = new TemporaryFile(TAG)) {
79                 lifetimeFile.write("0x05 0x00");
80                 eolFile.write("01");
81 
82                 EMmcWearInformationProvider wearInfoProvider = new EMmcWearInformationProvider(
83                         lifetimeFile.getFile(), eolFile.getFile());
84 
85                 WearInformation wearInformation = wearInfoProvider.load();
86 
87                 assertThat(wearInformation).isNotNull();
88                 assertThat(wearInformation.lifetimeEstimateA).isEqualTo(40);
89                 assertThat(wearInformation.lifetimeEstimateB)
90                     .isEqualTo(WearInformation.UNKNOWN_LIFETIME_ESTIMATE);
91                 assertThat(wearInformation.preEolInfo)
92                     .isEqualTo(WearInformation.PRE_EOL_INFO_NORMAL);
93             }
94         }
95     }
96 
97     @Test
testUfsWearInformationProvider()98     public void testUfsWearInformationProvider() throws Exception {
99         try (TemporaryFile lifetimeFile = new TemporaryFile(TAG)) {
100             lifetimeFile.write("ufs version: 1.0\n" +
101                     "Health Descriptor[Byte offset 0x2]: bPreEOLInfo = 0x2\n" +
102                     "Health Descriptor[Byte offset 0x1]: bDescriptionIDN = 0x1\n" +
103                     "Health Descriptor[Byte offset 0x3]: bDeviceLifeTimeEstA = 0x0\n" +
104                     "Health Descriptor[Byte offset 0x5]: VendorPropInfo = somedatahere\n" +
105                     "Health Descriptor[Byte offset 0x4]: bDeviceLifeTimeEstB = 0xA\n");
106 
107             UfsWearInformationProvider wearInfoProvider = new UfsWearInformationProvider(
108                 lifetimeFile.getFile());
109 
110             WearInformation wearInformation = wearInfoProvider.load();
111 
112             assertThat(wearInformation).isNotNull();
113             assertThat(wearInformation.lifetimeEstimateB).isEqualTo(90);
114             assertThat(wearInformation.preEolInfo).isEqualTo(WearInformation.PRE_EOL_INFO_WARNING);
115             assertThat(wearInformation.lifetimeEstimateA)
116                 .isEqualTo(WearInformation.UNKNOWN_LIFETIME_ESTIMATE);
117         }
118     }
119 
120     @Test
testHealthServiceWearInformationProvider()121     public void testHealthServiceWearInformationProvider() throws Exception {
122         StorageInfo storageInfo = new StorageInfo();
123         storageInfo.eol = WearInformation.PRE_EOL_INFO_NORMAL;
124         storageInfo.lifetimeA = 3;
125         storageInfo.lifetimeB = WearInformation.UNKNOWN_LIFETIME_ESTIMATE;
126         storageInfo.attr.isInternal = true;
127         HealthServiceWearInfoProvider wearInfoProvider = new HealthServiceWearInfoProvider();
128         wearInfoProvider.setHealthSupplier(mHealthServiceSupplier);
129 
130         doReturn(mMockedHal)
131             .when(mHealthServiceSupplier).get(anyString());
132         doAnswer((invocation) -> {
133             ArrayList<StorageInfo> list = new ArrayList<StorageInfo>();
134             list.add(storageInfo);
135             ((IHealth.getStorageInfoCallback) invocation.getArguments()[0])
136                 .onValues(Result.SUCCESS, list);
137             return null;
138         }).when(mMockedHal).getStorageInfo(any(getStorageInfoCallback.class));
139         WearInformation wearInformation = wearInfoProvider.load();
140 
141         assertThat(wearInformation).isNotNull();
142         assertThat(wearInformation.lifetimeEstimateA).isEqualTo(20);
143         assertThat(wearInformation.lifetimeEstimateB).isEqualTo(storageInfo.lifetimeB);
144         assertThat(wearInformation.preEolInfo).isEqualTo(storageInfo.eol);
145     }
146 
147     @Test
148     @SuppressWarnings("TruthSelfEquals")
149     // TODO: use EqualsTester to check equality with itself,
150     // Remove @SuppressWarnings("TruthSelfEquals") at other places too
testWearEstimateEquality()151     public void testWearEstimateEquality() {
152         WearEstimate wearEstimate1 = new WearEstimate(10, 20);
153         WearEstimate wearEstimate2 = new WearEstimate(10, 20);
154         WearEstimate wearEstimate3 = new WearEstimate(20, 30);
155         assertThat(wearEstimate1).isEqualTo(wearEstimate1);
156         assertThat(wearEstimate2).isEqualTo(wearEstimate1);
157         assertThat(wearEstimate1).isNotSameInstanceAs(wearEstimate3);
158     }
159 
160     @Test
testWearEstimateParcel()161     public void testWearEstimateParcel() throws Exception {
162         WearEstimate originalWearEstimate = new WearEstimate(10, 20);
163         Parcel p = Parcel.obtain();
164         originalWearEstimate.writeToParcel(p, 0);
165         p.setDataPosition(0);
166         WearEstimate newWearEstimate = new WearEstimate(p);
167         assertThat(newWearEstimate).isEqualTo(originalWearEstimate);
168         p.recycle();
169     }
170 
171     @Test
172     @SuppressWarnings("TruthSelfEquals")
testWearEstimateChangeEquality()173     public void testWearEstimateChangeEquality() {
174         WearEstimateChange wearEstimateChange1 = new WearEstimateChange(
175                 new WearEstimate(10, 20),
176                 new WearEstimate(20, 30),
177                 5000L,
178                 Instant.now(),
179                 false);
180         WearEstimateChange wearEstimateChange2 = new WearEstimateChange(
181             new WearEstimate(10, 20),
182             new WearEstimate(20, 30),
183             5000L,
184             wearEstimateChange1.dateAtChange,
185             false);
186         assertThat(wearEstimateChange1).isEqualTo(wearEstimateChange1);
187         assertThat(wearEstimateChange2).isEqualTo(wearEstimateChange1);
188         WearEstimateChange wearEstimateChange3 = new WearEstimateChange(
189             new WearEstimate(10, 30),
190             new WearEstimate(20, 30),
191             3000L,
192             Instant.now(),
193             true);
194         assertThat(wearEstimateChange1).isNotSameInstanceAs(wearEstimateChange3);
195     }
196 
197     @Test
testWearEstimateChangeParcel()198     public void testWearEstimateChangeParcel() throws Exception {
199         WearEstimateChange originalWearEstimateChange = new WearEstimateChange(
200                 new WearEstimate(10, 0),
201                 new WearEstimate(20, 10),
202                 123456789L,
203                 Instant.now(),
204                 false);
205         Parcel p = Parcel.obtain();
206         originalWearEstimateChange.writeToParcel(p, 0);
207         p.setDataPosition(0);
208         WearEstimateChange newWearEstimateChange = new WearEstimateChange(p);
209         assertThat(newWearEstimateChange).isEqualTo(originalWearEstimateChange);
210         p.recycle();
211     }
212 
213     @Test
testWearEstimateJson()214     public void testWearEstimateJson() throws Exception {
215         WearEstimate originalWearEstimate = new WearEstimate(20, 0);
216         StringWriter stringWriter = new StringWriter(1024);
217         JsonWriter jsonWriter = new JsonWriter(stringWriter);
218         originalWearEstimate.writeToJson(jsonWriter);
219         StringReader stringReader = new StringReader(stringWriter.toString());
220         JsonReader jsonReader = new JsonReader(stringReader);
221         WearEstimate newWearEstimate = new WearEstimate(jsonReader);
222         assertThat(newWearEstimate).isEqualTo(originalWearEstimate);
223     }
224 
225     @Test
testWearEstimateRecordJson()226     public void testWearEstimateRecordJson() throws Exception {
227         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
228             WearEstimateRecord originalWearEstimateRecord = new WearEstimateRecord(new WearEstimate(10, 20),
229                 new WearEstimate(10, 30), 5000, Instant.ofEpochMilli(1000));
230             try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(temporaryFile.getFile()))) {
231                 originalWearEstimateRecord.writeToJson(jsonWriter);
232             }
233             JSONObject jsonObject = new JSONObject(
234                     new String(Files.readAllBytes(temporaryFile.getPath())));
235             WearEstimateRecord newWearEstimateRecord = new WearEstimateRecord(jsonObject);
236             assertThat(newWearEstimateRecord).isEqualTo(originalWearEstimateRecord);
237         }
238     }
239 
240     @Test
241     @SuppressWarnings("TruthSelfEquals")
testWearEstimateRecordEquality()242     public void testWearEstimateRecordEquality() throws Exception {
243         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(WearEstimate.UNKNOWN_ESTIMATE,
244                 new WearEstimate(10, 20), 5000, Instant.ofEpochMilli(2000));
245         WearEstimateRecord wearEstimateRecord2 = new WearEstimateRecord(WearEstimate.UNKNOWN_ESTIMATE,
246             new WearEstimate(10, 20), 5000, Instant.ofEpochMilli(2000));
247         WearEstimateRecord wearEstimateRecord3 = new WearEstimateRecord(WearEstimate.UNKNOWN_ESTIMATE,
248             new WearEstimate(10, 40), 5000, Instant.ofEpochMilli(1000));
249 
250         assertThat(wearEstimateRecord1).isEqualTo(wearEstimateRecord1);
251         assertThat(wearEstimateRecord2).isEqualTo(wearEstimateRecord1);
252         assertThat(wearEstimateRecord1).isNotSameInstanceAs(wearEstimateRecord3);
253     }
254 
255     @Test
testWearHistoryJson()256     public void testWearHistoryJson() throws Exception {
257         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
258             WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
259                 WearEstimate.UNKNOWN_ESTIMATE,
260                 new WearEstimate(10, 20), 5000, Instant.ofEpochMilli(2000));
261             WearEstimateRecord wearEstimateRecord2 = new WearEstimateRecord(
262                 wearEstimateRecord1.getOldWearEstimate(),
263                 new WearEstimate(10, 40), 9000, Instant.ofEpochMilli(16000));
264             WearEstimateRecord wearEstimateRecord3 = new WearEstimateRecord(
265                 wearEstimateRecord2.getOldWearEstimate(),
266                 new WearEstimate(20, 40), 12000, Instant.ofEpochMilli(21000));
267             WearHistory originalWearHistory = WearHistory.fromRecords(wearEstimateRecord1,
268                 wearEstimateRecord2, wearEstimateRecord3);
269             try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(temporaryFile.getFile()))) {
270                 originalWearHistory.writeToJson(jsonWriter);
271             }
272             JSONObject jsonObject = new JSONObject(
273                 new String(Files.readAllBytes(temporaryFile.getPath())));
274             WearHistory newWearHistory = new WearHistory(jsonObject);
275             assertThat(newWearHistory).isEqualTo(originalWearHistory);
276         }
277     }
278 
279     @Test
280     @SuppressWarnings("TruthSelfEquals")
testWearHistoryEquality()281     public void testWearHistoryEquality() throws Exception {
282         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
283             WearEstimate.UNKNOWN_ESTIMATE,
284             new WearEstimate(10, 20), 5000, Instant.ofEpochMilli(2000));
285         WearEstimateRecord wearEstimateRecord2 = new WearEstimateRecord(
286             wearEstimateRecord1.getOldWearEstimate(),
287             new WearEstimate(10, 40), 9000, Instant.ofEpochMilli(16000));
288         WearEstimateRecord wearEstimateRecord3 = new WearEstimateRecord(
289             wearEstimateRecord2.getOldWearEstimate(),
290             new WearEstimate(20, 40), 12000, Instant.ofEpochMilli(21000));
291         WearEstimateRecord wearEstimateRecord4 = new WearEstimateRecord(
292             wearEstimateRecord3.getOldWearEstimate(),
293             new WearEstimate(30, 50), 17000, Instant.ofEpochMilli(34000));
294         WearEstimateRecord wearEstimateRecord5 = new WearEstimateRecord(
295             wearEstimateRecord3.getOldWearEstimate(),
296             new WearEstimate(20, 50), 15000, Instant.ofEpochMilli(34000));
297 
298         WearHistory wearHistory1 = WearHistory.fromRecords(wearEstimateRecord1,
299             wearEstimateRecord2, wearEstimateRecord3, wearEstimateRecord4);
300         WearHistory wearHistory2 = WearHistory.fromRecords(wearEstimateRecord4,
301             wearEstimateRecord1, wearEstimateRecord2, wearEstimateRecord3);
302         WearHistory wearHistory3 = WearHistory.fromRecords(wearEstimateRecord1,
303             wearEstimateRecord2, wearEstimateRecord3, wearEstimateRecord5);
304 
305         assertThat(wearHistory1).isEqualTo(wearHistory1);
306         assertThat(wearHistory2).isEqualTo(wearHistory1);
307         assertThat(wearHistory1).isNotSameInstanceAs(wearHistory3);
308     }
309 
310     @Test
testWearHistoryToChanges()311     public void testWearHistoryToChanges() {
312         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
313             WearEstimate.UNKNOWN_ESTIMATE,
314             new WearEstimate(10, 20), 3600000, Instant.ofEpochMilli(2000));
315         WearEstimateRecord wearEstimateRecord2 = new WearEstimateRecord(
316             wearEstimateRecord1.getOldWearEstimate(),
317             new WearEstimate(10, 40), 172000000, Instant.ofEpochMilli(16000));
318         WearEstimateRecord wearEstimateRecord3 = new WearEstimateRecord(
319             wearEstimateRecord2.getOldWearEstimate(),
320             new WearEstimate(20, 40), 172000001, Instant.ofEpochMilli(21000));
321 
322         WearHistory wearHistory = WearHistory.fromRecords(wearEstimateRecord1,
323             wearEstimateRecord2, wearEstimateRecord3);
324 
325         List<WearEstimateChange> wearEstimateChanges = wearHistory.toWearEstimateChanges(1);
326 
327         assertThat(wearEstimateChanges.size()).isEqualTo(3);
328         WearEstimateChange unknownToOne = wearEstimateChanges.get(0);
329         WearEstimateChange oneToTwo = wearEstimateChanges.get(1);
330         WearEstimateChange twoToThree = wearEstimateChanges.get(2);
331 
332         assertThat(wearEstimateRecord1.getOldWearEstimate()).isEqualTo(unknownToOne.oldEstimate);
333         assertThat(wearEstimateRecord1.getNewWearEstimate()).isEqualTo(unknownToOne.newEstimate);
334         assertThat(wearEstimateRecord1.getTotalCarServiceUptime())
335             .isEqualTo(unknownToOne.uptimeAtChange);
336         assertThat(wearEstimateRecord1.getUnixTimestamp()).isEqualTo(unknownToOne.dateAtChange);
337         assertThat(unknownToOne.isAcceptableDegradation).isTrue();
338 
339         assertThat(wearEstimateRecord2.getOldWearEstimate()).isEqualTo(oneToTwo.oldEstimate);
340         assertThat(wearEstimateRecord2.getNewWearEstimate()).isEqualTo(oneToTwo.newEstimate);
341         assertThat(wearEstimateRecord2.getTotalCarServiceUptime())
342             .isEqualTo(oneToTwo.uptimeAtChange);
343         assertThat(wearEstimateRecord2.getUnixTimestamp()).isEqualTo(oneToTwo.dateAtChange);
344         assertThat(oneToTwo.isAcceptableDegradation).isTrue();
345 
346         assertThat(wearEstimateRecord3.getOldWearEstimate()).isEqualTo(twoToThree.oldEstimate);
347         assertThat(wearEstimateRecord3.getNewWearEstimate()).isEqualTo(twoToThree.newEstimate);
348         assertThat(wearEstimateRecord3.getTotalCarServiceUptime())
349             .isEqualTo(twoToThree.uptimeAtChange);
350         assertThat(wearEstimateRecord3.getUnixTimestamp()).isEqualTo(twoToThree.dateAtChange);
351         assertThat(twoToThree.isAcceptableDegradation).isFalse();
352     }
353 
354     @Test
testUidIoStatEntry()355     public void testUidIoStatEntry() throws Exception {
356         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
357             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
358                 + "1006 489007 196802 0 20480 51474 2048 1024 2048 1 1\n");
359 
360             ProcfsUidIoStatsProvider statsProvider = new ProcfsUidIoStatsProvider(
361                     statsFile.getPath());
362 
363             SparseArray<UidIoRecord> entries = statsProvider.load();
364 
365             assertThat(entries).isNotNull();
366             assertThat(entries.size()).isEqualTo(2);
367 
368             IoStatsEntry entry = new IoStatsEntry(entries.get(0), 1234);
369             assertThat(entry).isNotNull();
370             assertThat(entry.uid).isEqualTo(0);
371             assertThat(entry.runtimeMillis).isEqualTo(1234);
372             assertThat(entry.foreground.bytesRead).isEqualTo(256797495);
373             assertThat(entry.foreground.bytesWritten).isEqualTo(181736102);
374             assertThat(entry.foreground.bytesReadFromStorage).isEqualTo(362132480);
375             assertThat(entry.foreground.bytesWrittenToStorage).isEqualTo(947167232);
376             assertThat(entry.foreground.fsyncCalls).isEqualTo(250);
377             assertThat(entry.background.bytesRead).isEqualTo(0);
378             assertThat(entry.background.bytesWritten).isEqualTo(0);
379             assertThat(entry.background.bytesReadFromStorage).isEqualTo(0);
380             assertThat(entry.background.bytesWrittenToStorage).isEqualTo(0);
381             assertThat(entry.background.fsyncCalls).isEqualTo(0);
382 
383             entry = new IoStatsEntry(entries.get(1006), 4321);
384             assertThat(entry).isNotNull();
385             assertThat(entry.uid).isEqualTo(1006);
386             assertThat(entry.runtimeMillis).isEqualTo(4321);
387             assertThat(entry.foreground.bytesRead).isEqualTo(489007);
388             assertThat(entry.foreground.bytesWritten).isEqualTo(196802);
389             assertThat(entry.foreground.bytesReadFromStorage).isEqualTo(0);
390             assertThat(entry.foreground.bytesWrittenToStorage).isEqualTo(20480);
391             assertThat(entry.foreground.fsyncCalls).isEqualTo(1);
392             assertThat(entry.background.bytesRead).isEqualTo(51474);
393             assertThat(entry.background.bytesWritten).isEqualTo(2048);
394             assertThat(entry.background.bytesReadFromStorage).isEqualTo(1024);
395             assertThat(entry.background.bytesWrittenToStorage).isEqualTo(2048);
396             assertThat(entry.background.fsyncCalls).isEqualTo(1);
397         }
398     }
399 
400     @Test
testUidIoStatEntryMissingFields()401     public void testUidIoStatEntryMissingFields() throws Exception {
402         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
403             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
404                 + "1 2 3 4 5 6 7 8 9\n");
405 
406             ProcfsUidIoStatsProvider statsProvider = new ProcfsUidIoStatsProvider(
407                 statsFile.getPath());
408 
409             SparseArray<UidIoRecord> entries = statsProvider.load();
410 
411             assertThat(entries).isNull();
412         }
413     }
414 
415     @Test
testUidIoStatEntryNonNumericFields()416     public void testUidIoStatEntryNonNumericFields() throws Exception {
417         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
418             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
419                 + "notanumber 489007 196802 0 20480 51474 2048 1024 2048 1 1\n");
420 
421             ProcfsUidIoStatsProvider statsProvider = new ProcfsUidIoStatsProvider(
422                 statsFile.getPath());
423 
424             SparseArray<UidIoRecord> entries = statsProvider.load();
425 
426             assertThat(entries).isNull();
427         }
428     }
429 
430     @Test
431     @SuppressWarnings("TruthSelfEquals")
testUidIoStatEntryEquality()432     public void testUidIoStatEntryEquality() throws Exception {
433         IoStatsEntry statEntry1 = new IoStatsEntry(10, 1234,
434             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
435             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
436         IoStatsEntry statEntry2 = new IoStatsEntry(10, 1234,
437             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
438             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
439         IoStatsEntry statEntry3 = new IoStatsEntry(30, 4567,
440             new IoStatsEntry.Metrics(1, 20, 30, 42, 50),
441             new IoStatsEntry.Metrics(10, 200, 300, 420, 500));
442         IoStatsEntry statEntry4 = new IoStatsEntry(11, 6541,
443             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
444             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
445         IoStatsEntry statEntry5 = new IoStatsEntry(10, 1234,
446             new IoStatsEntry.Metrics(10, 20, 30, 40, 0),
447             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
448 
449         assertThat(statEntry1).isEqualTo(statEntry1);
450         assertThat(statEntry2).isEqualTo(statEntry1);
451         assertThat(statEntry1).isNotSameInstanceAs(statEntry3);
452         assertThat(statEntry1).isNotSameInstanceAs(statEntry4);
453         assertThat(statEntry1).isNotSameInstanceAs(statEntry5);
454     }
455 
456     @Test
testUidIoStatEntryParcel()457     public void testUidIoStatEntryParcel() throws Exception {
458         IoStatsEntry statEntry = new IoStatsEntry(10, 5000,
459             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
460             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
461         Parcel p = Parcel.obtain();
462         statEntry.writeToParcel(p, 0);
463         p.setDataPosition(0);
464         IoStatsEntry other = new IoStatsEntry(p);
465         assertThat(statEntry).isEqualTo(other);
466     }
467 
468     @Test
testUidIoStatEntryJson()469     public void testUidIoStatEntryJson() throws Exception {
470         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
471             IoStatsEntry statEntry = new IoStatsEntry(10, 1200,
472                 new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
473                 new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
474             try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(temporaryFile.getFile()))) {
475                 statEntry.writeToJson(jsonWriter);
476             }
477             JSONObject jsonObject = new JSONObject(
478                 new String(Files.readAllBytes(temporaryFile.getPath())));
479             IoStatsEntry other = new IoStatsEntry(jsonObject);
480             assertThat(other).isEqualTo(statEntry);
481         }
482     }
483 
484 
485     @Test
testUidIoStatEntryDelta()486     public void testUidIoStatEntryDelta() throws Exception {
487         IoStatsEntry statEntry1 = new IoStatsEntry(10, 1000,
488             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
489             new IoStatsEntry.Metrics(60, 70, 80, 90, 100));
490 
491         IoStatsEntry statEntry2 = new IoStatsEntry(10,2000,
492             new IoStatsEntry.Metrics(110, 120, 130, 140, 150),
493             new IoStatsEntry.Metrics(260, 370, 480, 500, 110));
494 
495         IoStatsEntry statEntry3 = new IoStatsEntry(30, 3000,
496             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
497             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
498 
499 
500         IoStatsEntry delta21 = statEntry2.delta(statEntry1);
501         assertThat(delta21).isNotNull();
502         assertThat(delta21.uid).isEqualTo(statEntry1.uid);
503 
504         assertThat(delta21.runtimeMillis).isEqualTo(1000);
505         assertThat(delta21.foreground.bytesRead).isEqualTo(100);
506         assertThat(delta21.foreground.bytesWritten).isEqualTo(100);
507         assertThat(delta21.foreground.bytesReadFromStorage).isEqualTo(100);
508         assertThat(delta21.foreground.bytesWrittenToStorage).isEqualTo(100);
509         assertThat(delta21.foreground.fsyncCalls).isEqualTo(100);
510 
511         assertThat(delta21.background.bytesRead).isEqualTo(200);
512         assertThat(delta21.background.bytesWritten).isEqualTo(300);
513         assertThat(delta21.background.bytesReadFromStorage).isEqualTo(400);
514         assertThat(delta21.background.bytesWrittenToStorage).isEqualTo(410);
515         assertThat(delta21.background.fsyncCalls).isEqualTo(10);
516 
517         try {
518             IoStatsEntry delta31 = statEntry3.delta(statEntry1);
519             fail("delta only allowed on stats for matching user ID");
520         } catch (IllegalArgumentException e) {
521             // test passed
522         }
523     }
524 
525     @Test
testUidIoStatsRecordDelta()526     public void testUidIoStatsRecordDelta() throws Exception {
527         IoStatsEntry statEntry = new IoStatsEntry(10, 1000,
528             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
529             new IoStatsEntry.Metrics(60, 70, 80, 90, 100));
530 
531         UidIoRecord statRecord = new UidIoRecord(10,
532             20, 20, 30, 50, 70,
533             80, 70, 80, 100, 110);
534 
535         UidIoRecord delta = statRecord.delta(statEntry);
536 
537         assertThat(delta).isNotNull();
538         assertThat(delta.uid).isEqualTo(statRecord.uid);
539 
540         assertThat(delta.foreground_rchar).isEqualTo(10);
541         assertThat(delta.foreground_wchar).isEqualTo(0);
542         assertThat(delta.foreground_read_bytes).isEqualTo(0);
543         assertThat(delta.foreground_write_bytes).isEqualTo(10);
544         assertThat(delta.foreground_fsync).isEqualTo(20);
545 
546         assertThat(delta.background_rchar).isEqualTo(20);
547         assertThat(delta.background_wchar).isEqualTo(0);
548         assertThat(delta.background_read_bytes).isEqualTo(0);
549         assertThat(delta.background_write_bytes).isEqualTo(10);
550         assertThat(delta.background_fsync).isEqualTo(10);
551 
552         statRecord = new UidIoRecord(30,
553             20, 20, 30, 50, 70,
554             80, 70, 80, 100, 110);
555 
556         try {
557             statRecord.delta(statEntry);
558             fail("delta only allowed on records for matching user ID");
559         } catch (IllegalArgumentException e) {
560             // test passed
561         }
562     }
563 
564     @Test
565     @SuppressWarnings("TruthSelfEquals")
testUidIoStatsDelta()566     public void testUidIoStatsDelta() throws Exception {
567         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
568             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
569             new IoStatsEntry.Metrics(60, 70, 80, 90, 100));
570 
571         IoStatsEntry entry20 = new IoStatsEntry(20, 2000,
572             new IoStatsEntry.Metrics(200, 60, 100, 30, 40),
573             new IoStatsEntry.Metrics(20, 10, 20, 0, 0));
574 
575         IoStatsEntry entry30 = new IoStatsEntry(30, 2000,
576             new IoStatsEntry.Metrics(50, 100, 100, 30, 40),
577             new IoStatsEntry.Metrics(30, 0, 0, 0, 0));
578 
579         ArrayList<IoStatsEntry> statsEntries1 = new ArrayList<IoStatsEntry>() {{
580             add(entry10);
581             add(entry20);
582         }};
583 
584         ArrayList<IoStatsEntry> statsEntries2 = new ArrayList<IoStatsEntry>() {{
585             add(entry20);
586             add(entry30);
587         }};
588 
589         IoStats delta1 = new IoStats(statsEntries1, 5000);
590         IoStats delta2 = new IoStats(statsEntries1, 5000);
591         IoStats delta3 = new IoStats(statsEntries2, 3000);
592         IoStats delta4 = new IoStats(statsEntries1, 5000);
593 
594         assertThat(delta1).isEqualTo(delta1);
595         assertThat(delta2).isEqualTo(delta1);
596         assertThat(delta1).isNotSameInstanceAs(delta3);
597         assertThat(delta3).isNotSameInstanceAs(delta4);
598     }
599 
600     @Test
testUidIoStatsTotals()601     public void testUidIoStatsTotals() throws Exception {
602         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
603             new IoStatsEntry.Metrics(20, 0, 10, 0, 0),
604             new IoStatsEntry.Metrics(10, 50, 0, 20, 2));
605 
606         IoStatsEntry entry20 = new IoStatsEntry(20, 1000,
607             new IoStatsEntry.Metrics(100, 200, 50, 200, 1),
608             new IoStatsEntry.Metrics(0, 30, 10, 0, 1));
609 
610         ArrayList<IoStatsEntry> statsEntries = new ArrayList<IoStatsEntry>() {{
611             add(entry10);
612             add(entry20);
613         }};
614 
615         IoStats delta = new IoStats(statsEntries, 5000);
616 
617         IoStatsEntry.Metrics foregroundTotals = delta.getForegroundTotals();
618         IoStatsEntry.Metrics backgroundTotals = delta.getBackgroundTotals();
619         IoStatsEntry.Metrics overallTotals = delta.getTotals();
620 
621         assertThat(foregroundTotals.bytesRead).isEqualTo(120);
622         assertThat(foregroundTotals.bytesWritten).isEqualTo(200);
623         assertThat(foregroundTotals.bytesReadFromStorage).isEqualTo(60);
624         assertThat(foregroundTotals.bytesWrittenToStorage).isEqualTo(200);
625         assertThat(foregroundTotals.fsyncCalls).isEqualTo(1);
626 
627 
628         assertThat(backgroundTotals.bytesRead).isEqualTo(10);
629         assertThat(backgroundTotals.bytesWritten).isEqualTo(80);
630         assertThat(backgroundTotals.bytesReadFromStorage).isEqualTo(10);
631         assertThat(backgroundTotals.bytesWrittenToStorage).isEqualTo(20);
632         assertThat(backgroundTotals.fsyncCalls).isEqualTo(3);
633 
634         assertThat(overallTotals.bytesRead).isEqualTo(130);
635         assertThat(overallTotals.bytesWritten).isEqualTo(280);
636         assertThat(overallTotals.bytesReadFromStorage).isEqualTo(70);
637         assertThat(overallTotals.bytesWrittenToStorage).isEqualTo(220);
638         assertThat(overallTotals.fsyncCalls).isEqualTo(4);
639     }
640 
641     @Test
testUidIoStatsDeltaParcel()642     public void testUidIoStatsDeltaParcel() throws Exception {
643         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
644             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
645             new IoStatsEntry.Metrics(60, 70, 80, 90, 100));
646 
647         IoStatsEntry entry20 = new IoStatsEntry(20, 2000,
648             new IoStatsEntry.Metrics(200, 60, 100, 30, 40),
649             new IoStatsEntry.Metrics(20, 10, 20, 0, 0));
650 
651         ArrayList<IoStatsEntry> statsEntries = new ArrayList<IoStatsEntry>() {{
652             add(entry10);
653             add(entry20);
654         }};
655 
656         IoStats statsDelta = new IoStats(statsEntries, 5000);
657 
658         Parcel p = Parcel.obtain();
659         statsDelta.writeToParcel(p, 0);
660         p.setDataPosition(0);
661 
662         IoStats parceledStatsDelta = new IoStats(p);
663 
664         assertThat(parceledStatsDelta.getTimestamp()).isEqualTo(statsDelta.getTimestamp());
665 
666         assertEquals(2, parceledStatsDelta.getStats().stream()
667                 .filter(e -> e.equals(entry10) || e.equals(entry20))
668                 .count());
669     }
670 
671     @Test
testUidIoStatsDeltaJson()672     public void testUidIoStatsDeltaJson() throws Exception {
673         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
674             IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
675                 new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
676                 new IoStatsEntry.Metrics(60, 70, 80, 90, 100));
677 
678             IoStatsEntry entry20 = new IoStatsEntry(20, 2000,
679                 new IoStatsEntry.Metrics(200, 60, 100, 30, 40),
680                 new IoStatsEntry.Metrics(20, 10, 20, 0, 0));
681 
682             ArrayList<IoStatsEntry> statsEntries = new ArrayList<IoStatsEntry>() {{
683                 add(entry10);
684                 add(entry20);
685             }};
686 
687             IoStats statsDelta = new IoStats(statsEntries, 5000);
688             try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(temporaryFile.getFile()))) {
689                 statsDelta.writeToJson(jsonWriter);
690             }
691             JSONObject jsonObject = new JSONObject(
692                 new String(Files.readAllBytes(temporaryFile.getPath())));
693             IoStats other = new IoStats(jsonObject);
694             assertThat(other).isEqualTo(statsDelta);
695         }
696     }
697 
698     @Test
testLifetimeWriteInfo()699     public void testLifetimeWriteInfo() throws Exception {
700         try (TemporaryDirectory temporaryDirectory = new TemporaryDirectory(TAG)) {
701             try (TemporaryDirectory ext4 = temporaryDirectory.getSubdirectory("ext4");
702                  TemporaryDirectory f2fs = temporaryDirectory.getSubdirectory("f2fs")) {
703                 try(TemporaryDirectory ext4_part1 = ext4.getSubdirectory("part1");
704                     TemporaryDirectory f2fs_part1 = f2fs.getSubdirectory("part1");
705                     TemporaryDirectory ext4_part2 = ext4.getSubdirectory("part2");
706                     TemporaryDirectory f2f2_notpart = f2fs.getSubdirectory("nopart")) {
707                     Files.write(ext4_part1.getPath().resolve("lifetime_write_kbytes"),
708                         Collections.singleton("123"));
709                     Files.write(f2fs_part1.getPath().resolve("lifetime_write_kbytes"),
710                         Collections.singleton("250"));
711                     Files.write(ext4_part2.getPath().resolve("lifetime_write_kbytes"),
712                         Collections.singleton("2147483660"));
713 
714                     LifetimeWriteInfo expected_ext4_part1 =
715                         new LifetimeWriteInfo("part1", "ext4", 123*1024);
716                     LifetimeWriteInfo expected_f2fs_part1 =
717                         new LifetimeWriteInfo("part1", "f2fs", 250*1024);
718                     LifetimeWriteInfo expected_ext4_part2 =
719                         new LifetimeWriteInfo("part2", "ext4", 2147483660L*1024);
720 
721                     SysfsLifetimeWriteInfoProvider sysfsLifetimeWriteInfoProvider =
722                         new SysfsLifetimeWriteInfoProvider(temporaryDirectory.getDirectory());
723 
724                     LifetimeWriteInfo[] writeInfos = sysfsLifetimeWriteInfoProvider.load();
725 
726                     assertThat(writeInfos).isNotNull();
727                     assertThat(writeInfos.length).isEqualTo(3);
728                     assertTrue(Arrays.stream(writeInfos).anyMatch(
729                             li -> li.equals(expected_ext4_part1)));
730                     assertTrue(Arrays.stream(writeInfos).anyMatch(
731                             li -> li.equals(expected_ext4_part2)));
732                     assertTrue(Arrays.stream(writeInfos).anyMatch(
733                             li -> li.equals(expected_f2fs_part1)));
734                 }
735             }
736         }
737     }
738 
739     @Test
740     @SuppressWarnings("TruthSelfEquals")
testLifetimeWriteInfoEquality()741     public void testLifetimeWriteInfoEquality() throws Exception {
742         LifetimeWriteInfo writeInfo = new LifetimeWriteInfo("part1", "ext4", 123);
743         LifetimeWriteInfo writeInfoEq = new LifetimeWriteInfo("part1", "ext4", 123);
744 
745         LifetimeWriteInfo writeInfoNeq1 = new LifetimeWriteInfo("part2", "ext4", 123);
746         LifetimeWriteInfo writeInfoNeq2 = new LifetimeWriteInfo("part1", "f2fs", 123);
747         LifetimeWriteInfo writeInfoNeq3 = new LifetimeWriteInfo("part1", "ext4", 100);
748 
749         assertThat(writeInfo).isEqualTo(writeInfo);
750         assertThat(writeInfoEq).isEqualTo(writeInfo);
751         assertThat(writeInfo).isNotSameInstanceAs(writeInfoNeq1);
752         assertThat(writeInfo).isNotSameInstanceAs(writeInfoNeq2);
753         assertThat(writeInfo).isNotSameInstanceAs(writeInfoNeq3);
754     }
755 
756     @Test
testLifetimeWriteInfoParcel()757     public void testLifetimeWriteInfoParcel() throws Exception {
758         LifetimeWriteInfo lifetimeWriteInfo = new LifetimeWriteInfo("part1", "ext4", 1024);
759 
760         Parcel p = Parcel.obtain();
761         lifetimeWriteInfo.writeToParcel(p, 0);
762         p.setDataPosition(0);
763 
764         LifetimeWriteInfo parceled = new LifetimeWriteInfo(p);
765 
766         assertThat(parceled).isEqualTo(lifetimeWriteInfo);
767     }
768 
769     @Test
testLifetimeWriteInfoJson()770     public void testLifetimeWriteInfoJson() throws Exception {
771         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
772             LifetimeWriteInfo lifetimeWriteInfo = new LifetimeWriteInfo("part1", "ext4", 1024);
773 
774             try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(temporaryFile.getFile()))) {
775                 lifetimeWriteInfo.writeToJson(jsonWriter);
776             }
777             JSONObject jsonObject = new JSONObject(
778                 new String(Files.readAllBytes(temporaryFile.getPath())));
779             LifetimeWriteInfo other = new LifetimeWriteInfo(jsonObject);
780             assertThat(other).isEqualTo(lifetimeWriteInfo);
781         }
782     }
783 }
784