Implement wear history tracking
Bug: 32512551
Test: runtest -x packages/services/Car/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
runtest -x packages/services/Car/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
Change-Id: Id024f9378e0a762cbdfeead9267deeebfa86fd40
diff --git a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
index cd104f8..c45e5e3 100644
--- a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
+++ b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
@@ -16,11 +16,25 @@
package com.android.car;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.car.Car;
import android.car.storagemonitoring.CarStorageMonitoringManager;
import android.car.storagemonitoring.WearEstimate;
+import android.car.storagemonitoring.WearEstimateChange;
import android.test.suitebuilder.annotation.MediumTest;
+import android.util.JsonWriter;
+import android.util.Log;
+import com.android.car.storagemonitoring.WearEstimateRecord;
+import com.android.car.storagemonitoring.WearHistory;
import com.android.car.storagemonitoring.WearInformation;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/** Test the public entry points for the CarStorageMonitoringManager */
@MediumTest
@@ -28,13 +42,120 @@
private static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
private static final WearInformation DEFAULT_WEAR_INFORMATION =
- new WearInformation(10, 0, WearInformation.PRE_EOL_INFO_NORMAL);
+ new WearInformation(30, 0, WearInformation.PRE_EOL_INFO_NORMAL);
+
+ private static final class WearData {
+ static final WearData DEFAULT = new WearData(0, DEFAULT_WEAR_INFORMATION, null);
+
+ final long uptime;
+ @NonNull
+ final WearInformation wearInformation;
+ @Nullable
+ final WearHistory wearHistory;
+
+ WearData(long uptime, @Nullable WearInformation wearInformation, @Nullable WearHistory wearHistory) {
+ if (wearInformation == null) wearInformation = DEFAULT_WEAR_INFORMATION;
+ this.uptime = uptime;
+ this.wearInformation = wearInformation;
+ this.wearHistory = wearHistory;
+ }
+ }
+
+ private static final Map<String, WearData> PER_TEST_WEAR_DATA =
+ new HashMap<String, WearData>() {{
+ put("testReadWearHistory",
+ new WearData(6500, DEFAULT_WEAR_INFORMATION,
+ WearHistory.fromRecords(
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
+ .toWearEstimate(new WearEstimate(10, 0))
+ .atUptime(1000)
+ .atTimestamp(Instant.ofEpochMilli(5000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(10, 0))
+ .toWearEstimate(new WearEstimate(20, 0))
+ .atUptime(4000)
+ .atTimestamp(Instant.ofEpochMilli(12000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(20, 0))
+ .toWearEstimate(new WearEstimate(30, 0))
+ .atUptime(6500)
+ .atTimestamp(Instant.ofEpochMilli(17000)).build())));
+
+ put("testNotAcceptableWearEvent",
+ new WearData(2520006499L,
+ new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
+ WearHistory.fromRecords(
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
+ .toWearEstimate(new WearEstimate(10, 0))
+ .atUptime(1000)
+ .atTimestamp(Instant.ofEpochMilli(5000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(10, 0))
+ .toWearEstimate(new WearEstimate(20, 0))
+ .atUptime(4000)
+ .atTimestamp(Instant.ofEpochMilli(12000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(20, 0))
+ .toWearEstimate(new WearEstimate(30, 0))
+ .atUptime(6500)
+ .atTimestamp(Instant.ofEpochMilli(17000)).build())));
+
+ put("testAcceptableWearEvent",
+ new WearData(2520006501L,
+ new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
+ WearHistory.fromRecords(
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
+ .toWearEstimate(new WearEstimate(10, 0))
+ .atUptime(1000)
+ .atTimestamp(Instant.ofEpochMilli(5000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(10, 0))
+ .toWearEstimate(new WearEstimate(20, 0))
+ .atUptime(4000)
+ .atTimestamp(Instant.ofEpochMilli(12000)).build(),
+ WearEstimateRecord.Builder.newBuilder()
+ .fromWearEstimate(new WearEstimate(20, 0))
+ .toWearEstimate(new WearEstimate(30, 0))
+ .atUptime(6500)
+ .atTimestamp(Instant.ofEpochMilli(17000)).build())));
+ }};
private CarStorageMonitoringManager mCarStorageMonitoringManager;
@Override
protected synchronized void configureFakeSystemInterface() {
- setFlashWearInformation(DEFAULT_WEAR_INFORMATION);
+ try {
+ final String testName = getName();
+ final WearData wearData = PER_TEST_WEAR_DATA.getOrDefault(testName, WearData.DEFAULT);
+ final WearHistory wearHistory = wearData.wearHistory;
+
+ setFlashWearInformation(wearData.wearInformation);
+ setUptimeProvider( (boolean b) -> 0 );
+
+ if (wearHistory != null) {
+ File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(),
+ CarStorageMonitoringService.WEAR_INFO_FILENAME);
+ try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(wearHistoryFile))) {
+ wearHistory.writeToJson(jsonWriter);
+ }
+ }
+
+ if (wearData.uptime > 0) {
+ File uptimeFile = new File(getFakeSystemInterface().getFilesDir(),
+ CarStorageMonitoringService.UPTIME_TRACKER_FILENAME);
+ try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) {
+ jsonWriter.beginObject();
+ jsonWriter.name("uptime").value(wearData.uptime);
+ jsonWriter.endObject();
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "failed to configure fake system interface", e);
+ fail("failed to configure fake system interface instance");
+ }
}
@Override
@@ -57,4 +178,50 @@
assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateA, wearEstimate.typeA);
assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateB, wearEstimate.typeB);
}
+
+ public void testReadWearHistory() throws Exception {
+ final List<WearEstimateChange> wearEstimateChanges =
+ mCarStorageMonitoringManager.getWearEstimateHistory();
+
+ assertNotNull(wearEstimateChanges);
+ assertFalse(wearEstimateChanges.isEmpty());
+
+ final WearHistory expectedWearHistory = PER_TEST_WEAR_DATA.get(getName()).wearHistory;
+
+ assertEquals(expectedWearHistory.size(), wearEstimateChanges.size());
+ for (int i = 0; i < wearEstimateChanges.size(); ++i) {
+ final WearEstimateRecord expected = expectedWearHistory.get(i);
+ final WearEstimateChange actual = wearEstimateChanges.get(i);
+
+ assertTrue(expected.isSameAs(actual));
+ }
+ }
+
+ private void checkLastWearEvent(boolean isAcceptable) throws Exception {
+ final List<WearEstimateChange> wearEstimateChanges =
+ mCarStorageMonitoringManager.getWearEstimateHistory();
+
+ assertNotNull(wearEstimateChanges);
+ assertFalse(wearEstimateChanges.isEmpty());
+
+ final WearData wearData = PER_TEST_WEAR_DATA.get(getName());
+
+ final WearInformation expectedCurrentWear = wearData.wearInformation;
+ final WearEstimate expectedPreviousWear = wearData.wearHistory.getLast().getNewWearEstimate();
+
+ final WearEstimateChange actualCurrentWear =
+ wearEstimateChanges.get(wearEstimateChanges.size() - 1);
+
+ assertEquals(isAcceptable, actualCurrentWear.isAcceptableDegradation);
+ assertEquals(expectedCurrentWear.toWearEstimate(), actualCurrentWear.newEstimate);
+ assertEquals(expectedPreviousWear, actualCurrentWear.oldEstimate);
+ }
+
+ public void testNotAcceptableWearEvent() throws Exception {
+ checkLastWearEvent(false);
+ }
+
+ public void testAcceptableWearEvent() throws Exception {
+ checkLastWearEvent(true);
+ }
}