blob: 7f604bc861818dae673f6f50da4b326a174e35ea [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mms.service.metrics;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.annotation.Nullable;
import com.android.mms.IncomingMms;
import com.android.mms.OutgoingMms;
import com.android.mms.PersistMmsAtoms;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class PersistMmsAtomsStorageTest {
private static final String TEST_FILE = "PersistMmsAtomsStorageTest.pb";
@Rule
public TemporaryFolder mFolder = new TemporaryFolder();
private File mTestFile;
private static final long START_TIME_MILLIS = 2000L;
private static final int CARRIER1_ID = 1435;
private static final int CARRIER2_ID = 1187;
private TestablePersistMmsAtomsStorage mTestablePersistMmsAtomsStorage;
// IncomingMms
private List<IncomingMms> mIncomingMmsList;
private IncomingMms mIncomingMms1Proto;
private IncomingMms mIncomingMms2Proto;
// OutgoingMms
private List<OutgoingMms> mOutgoingMmsList;
private OutgoingMms mOutgoingMms1Proto;
private OutgoingMms mOutgoingMms2Proto;
// Mocked classes
private Context mContext;
private PackageManager mPackageManager;
private FileOutputStream mTestFileOutputStream;
// Comparator to compare proto objects
private static final Comparator<Object> sProtoComparator =
new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2) {
return 0;
}
if (o1 == null) {
return -1;
}
if (o2 == null) {
return 1;
}
assertEquals(o1.getClass(), o2.getClass());
return o1.toString().compareTo(o2.toString());
}
};
@Before
public void setUp() throws Exception {
mTestFileOutputStream = mock(FileOutputStream.class);
mContext = mock(Context.class);
mPackageManager = mock(PackageManager.class);
makeTestData();
// By default, test loading with real file IO and saving with mocks.
mTestFile = mFolder.newFile(TEST_FILE);
doReturn(false).when(mPackageManager).
hasSystemFeature(PackageManager.FEATURE_RAM_LOW);
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mTestFileOutputStream).when(mContext).openFileOutput(anyString(), anyInt());
doReturn(mTestFile).when(mContext).getFileStreamPath(anyString());
}
@After
public void tearDown() {
mTestFile.delete();
mTestFile = null;
mFolder = null;
mIncomingMmsList = null;
mIncomingMms1Proto = null;
mIncomingMms2Proto = null;
mOutgoingMmsList = null;
mOutgoingMms1Proto = null;
mOutgoingMms2Proto = null;
mTestablePersistMmsAtomsStorage = null;
mTestFileOutputStream = null;
mPackageManager = null;
mContext = null;
}
@Test
public void loadAtoms_fileNotExist() {
mTestFile.delete();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// No exception should be thrown, storage should be empty, pull time should be start time.
assertAllPullTimestampEquals(START_TIME_MILLIS);
assertStorageIsEmptyForAllAtoms();
}
@Test
public void loadAtoms_unreadable() throws Exception {
createEmptyTestFile();
mTestFile.setReadable(false);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// No exception should be thrown, storage should be empty, pull time should be start time.
assertAllPullTimestampEquals(START_TIME_MILLIS);
assertStorageIsEmptyForAllAtoms();
}
@Test
public void loadAtoms_emptyProto() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// No exception should be thrown, storage should be empty, pull time should be start time.
assertAllPullTimestampEquals(START_TIME_MILLIS);
assertStorageIsEmptyForAllAtoms();
}
@Test
public void loadAtoms_malformedFile() throws Exception {
FileOutputStream stream = new FileOutputStream(mTestFile);
stream.write("This is not a proto file.".getBytes(StandardCharsets.UTF_8));
stream.close();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// No exception should be thrown, storage should be empty, pull time should be start time.
assertAllPullTimestampEquals(START_TIME_MILLIS);
assertStorageIsEmptyForAllAtoms();
}
@Test
public void loadAtoms_pullTimeMissing() throws Exception {
// Create test file with lastPullTimeMillis = 0L, i.e. default/unknown.
createTestFile(0L);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// No exception should be thrown, storage should be match, pull time should be start time.
assertAllPullTimestampEquals(START_TIME_MILLIS);
assertProtoListEqualsIgnoringOrder(mIncomingMmsList,
mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
assertProtoListEqualsIgnoringOrder(mOutgoingMmsList,
mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
@Test
public void loadAtoms_validContents() throws Exception {
createTestFile(100L);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
// No exception should be thrown, storage and pull time should match.
assertAllPullTimestampEquals(100L);
assertProtoListEqualsIgnoringOrder(mIncomingMmsList,
mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
assertProtoListEqualsIgnoringOrder(mOutgoingMmsList,
mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
@Test
public void addIncomingMms_emptyProto() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addIncomingMms(mIncomingMms1Proto);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// IncomingMms should be added successfully, there should not be any OutgoingMms,
// changes should be saved.
verifyCurrentStateSavedToFileOnce();
assertProtoListIsEmpty(mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
List<IncomingMms> expectedIncomingMmsList = new ArrayList<>();
expectedIncomingMmsList.add(mIncomingMms1Proto);
assertProtoListEquals(expectedIncomingMmsList,
mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
}
@Test
public void addIncomingMms_withExistingEntries() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addIncomingMms(mIncomingMms1Proto);
mTestablePersistMmsAtomsStorage.addIncomingMms(mIncomingMms2Proto);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// IncomingMms should be added successfully.
verifyCurrentStateSavedToFileOnce();
List<IncomingMms> expectedIncomingMmsList = Arrays.asList(mIncomingMms1Proto,
mIncomingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedIncomingMmsList,
mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
}
@Test
public void addIncomingMms_updateExistingEntries() throws Exception {
createTestFile(START_TIME_MILLIS);
// Add copy of mIncomingMms1Proto.
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addIncomingMms(copyOf(mIncomingMms1Proto));
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// mIncomingMms1Proto's mms count should be increased by 1 and avgIntervalMillis
// should be updated correctly.
verifyCurrentStateSavedToFileOnce();
IncomingMms newIncomingMm1Proto = copyOf(mIncomingMms1Proto);
newIncomingMm1Proto = newIncomingMm1Proto.toBuilder()
.setMmsCount(2)
.setAvgIntervalMillis(mIncomingMms1Proto.getAvgIntervalMillis())
.build();
List<IncomingMms> expectedIncomingMmsList = Arrays.asList(newIncomingMm1Proto,
mIncomingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedIncomingMmsList,
mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
}
@Test
public void addIncomingMms_tooManyEntries() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
// Add 26 mms whereas max size is 25.
IncomingMms mms = IncomingMms.newBuilder()
.setRoaming(ServiceState.ROAMING_TYPE_DOMESTIC)
.setSimSlotIndex(0)
.setIsMultiSim(false)
.setIsEsim(false)
.setCarrierId(CARRIER1_ID)
.setMmsCount(1)
.setAvgIntervalMillis(500L)
.setRetryId(0)
.setHandledByCarrierApp(false)
.build();
for (int ratType = 0; ratType < 5; ratType++) {
for (int resultType = 0; resultType < 5; resultType++) {
mms = mms.toBuilder().setRat(ratType).setResult(resultType).build();
mTestablePersistMmsAtomsStorage.addIncomingMms(mms);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
}
}
// Add 26th mms 5 times
IncomingMms lastMms = copyOf(mms);
lastMms = lastMms.toBuilder().setRat(6).setResult(6).build();
for (int i = 0; i < 5; i++) {
mTestablePersistMmsAtomsStorage.addIncomingMms(lastMms);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
}
// Last mms should be present in storage.
assertHasMmsAndCountAvg(mTestablePersistMmsAtomsStorage.getIncomingMms(0L),
lastMms, 5L, lastMms.getAvgIntervalMillis());
}
@Test
public void getIncomingMms_tooFrequent() throws Exception {
createTestFile(START_TIME_MILLIS);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
// Pull interval less than minimum.
mTestablePersistMmsAtomsStorage.incTimeMillis(50L);
List<IncomingMms> incomingMmsList = mTestablePersistMmsAtomsStorage
.getIncomingMms(100L);
// Should be denied.
assertNull(incomingMmsList);
}
@Test
public void getIncomingMms_withSavedAtoms() throws Exception {
createTestFile(START_TIME_MILLIS);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
List<IncomingMms> incomingMmsList1 = mTestablePersistMmsAtomsStorage
.getIncomingMms(50L);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
List<IncomingMms> incomingMmsList2 = mTestablePersistMmsAtomsStorage
.getIncomingMms(50L);
// First set of results should be equal to file contents.
List<IncomingMms> expectedIncomingMmsList = Arrays.asList(mIncomingMms1Proto,
mIncomingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedIncomingMmsList, incomingMmsList1);
// Second set of results should be empty.
expectedIncomingMmsList = new ArrayList<>();
assertProtoListEqualsIgnoringOrder(expectedIncomingMmsList, incomingMmsList2);
// Corresponding pull timestamp should be updated and saved.
assertEquals(START_TIME_MILLIS + 200L, mTestablePersistMmsAtomsStorage
.getAtomsProto().getIncomingMmsPullTimestampMillis());
InOrder inOrder = inOrder(mTestFileOutputStream);
assertEquals(START_TIME_MILLIS + 100L,
getAtomsWritten(inOrder).getIncomingMmsPullTimestampMillis());
assertEquals(START_TIME_MILLIS + 200L,
getAtomsWritten(inOrder).getIncomingMmsPullTimestampMillis());
inOrder.verifyNoMoreInteractions();
}
@Test
public void addOutgoingMms_emptyProto() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addOutgoingMms(mOutgoingMms1Proto);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// OutgoingMms should be added successfully, there should not be any IncomingMms,
// changes should be saved.
verifyCurrentStateSavedToFileOnce();
assertProtoListIsEmpty(mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
List<OutgoingMms> expectedOutgoingMmsList = new ArrayList<>();
expectedOutgoingMmsList.add(mOutgoingMms1Proto);
assertProtoListEquals(expectedOutgoingMmsList,
mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
@Test
public void addOutgoingMms_withExistingEntries() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addOutgoingMms(mOutgoingMms1Proto);
mTestablePersistMmsAtomsStorage.addOutgoingMms(mOutgoingMms2Proto);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// OutgoingMms should be added successfully
verifyCurrentStateSavedToFileOnce();
List<OutgoingMms> expectedOutgoingMmsList = Arrays.asList(mOutgoingMms1Proto,
mOutgoingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedOutgoingMmsList,
mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
@Test
public void addOutgoingMms_updateExistingEntries() throws Exception {
createTestFile(START_TIME_MILLIS);
// Add copy of mOutgoingMms1Proto
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.addOutgoingMms(copyOf(mOutgoingMms1Proto));
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
// mOutgoingMms1Proto's mms count should be increased by 1 and avgIntervalMillis
// should be updated correctly.
verifyCurrentStateSavedToFileOnce();
OutgoingMms newOutgoingMm1Proto = copyOf(mOutgoingMms1Proto);
newOutgoingMm1Proto = newOutgoingMm1Proto.toBuilder()
.setMmsCount(2)
.setAvgIntervalMillis(mOutgoingMms1Proto.getAvgIntervalMillis())
.build();
List<OutgoingMms> expectedOutgoingMmsList = Arrays.asList(newOutgoingMm1Proto,
mOutgoingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedOutgoingMmsList,
mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
@Test
public void addOutgoingMms_tooManyEntries() throws Exception {
createEmptyTestFile();
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
// Add 26 mms whereas max size is 25.
OutgoingMms mms = OutgoingMms.newBuilder()
.setRoaming(ServiceState.ROAMING_TYPE_DOMESTIC)
.setSimSlotIndex(0)
.setIsMultiSim(false)
.setIsEsim(false)
.setCarrierId(CARRIER1_ID)
.setMmsCount(1)
.setAvgIntervalMillis(500L)
.setIsFromDefaultApp(true)
.setHandledByCarrierApp(false)
.setRetryId(0)
.build();
for (int ratType = 0; ratType < 5; ratType++) {
for (int resultType = 0; resultType < 5; resultType++) {
mms = mms.toBuilder().setRat(ratType).setResult(resultType).build();
mTestablePersistMmsAtomsStorage.addOutgoingMms(mms);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
}
}
// Add 26th mms 5 times
OutgoingMms lastMms = copyOf(mms);
lastMms = lastMms.toBuilder().setRat(6).setResult(6).build();
for (int i = 0; i < 5; i++) {
mTestablePersistMmsAtomsStorage.addOutgoingMms(lastMms);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
}
// Last mms should be present in storage.
assertHasMmsAndCountAvg(mTestablePersistMmsAtomsStorage.getOutgoingMms(0L),
lastMms, 5L, lastMms.getAvgIntervalMillis());
}
@Test
public void getOutgoingMms_tooFrequent() throws Exception {
createTestFile(START_TIME_MILLIS);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
// Pull interval less than minimum.
mTestablePersistMmsAtomsStorage.incTimeMillis(50L);
List<OutgoingMms> outgoingMmsList = mTestablePersistMmsAtomsStorage
.getOutgoingMms(100L);
// Should be denied.
assertNull(outgoingMmsList);
}
@Test
public void getOutgoingMms_withSavedAtoms() throws Exception {
createTestFile(START_TIME_MILLIS);
mTestablePersistMmsAtomsStorage = new TestablePersistMmsAtomsStorage(mContext);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
List<OutgoingMms> outgoingMmsList1 = mTestablePersistMmsAtomsStorage
.getOutgoingMms(50L);
mTestablePersistMmsAtomsStorage.incTimeMillis(100L);
List<OutgoingMms> outgoingMmsList2 = mTestablePersistMmsAtomsStorage
.getOutgoingMms(50L);
// First set of results should be equal to file contents.
List<OutgoingMms> expectedOutgoingMmsList = Arrays.asList(mOutgoingMms1Proto,
mOutgoingMms2Proto);
assertProtoListEqualsIgnoringOrder(expectedOutgoingMmsList, outgoingMmsList1);
// Second set of results should be empty.
expectedOutgoingMmsList = new ArrayList<>();
assertProtoListEqualsIgnoringOrder(expectedOutgoingMmsList, outgoingMmsList2);
// Corresponding pull timestamp should be updated and saved.
assertEquals(START_TIME_MILLIS + 200L, mTestablePersistMmsAtomsStorage
.getAtomsProto().getOutgoingMmsPullTimestampMillis());
InOrder inOrder = inOrder(mTestFileOutputStream);
assertEquals(START_TIME_MILLIS + 100L,
getAtomsWritten(inOrder).getOutgoingMmsPullTimestampMillis());
assertEquals(START_TIME_MILLIS + 200L,
getAtomsWritten(inOrder).getOutgoingMmsPullTimestampMillis());
inOrder.verifyNoMoreInteractions();
}
/** Utilities */
private void assertAllPullTimestampEquals(long timestamp) {
assertEquals(timestamp, mTestablePersistMmsAtomsStorage.getAtomsProto()
.getIncomingMmsPullTimestampMillis());
assertEquals(timestamp, mTestablePersistMmsAtomsStorage.getAtomsProto()
.getOutgoingMmsPullTimestampMillis());
}
private void assertStorageIsEmptyForAllAtoms() {
assertProtoListIsEmpty(mTestablePersistMmsAtomsStorage.getIncomingMms(0L));
assertProtoListIsEmpty(mTestablePersistMmsAtomsStorage.getOutgoingMms(0L));
}
private static <T> void assertProtoListIsEmpty(@Nullable List<T> list) {
assertNotNull(list);
assertEquals(0, list.size());
}
private static <T> void assertProtoListEquals(@Nullable List<T> expected,
@Nullable List<T> actual) {
assertNotNull(expected);
assertNotNull(actual);
String message =
"Expected:\n" + expected.stream().map(Object::toString).collect(
Collectors.joining(", "))
+ "\nGot:\n" + actual.stream().map(Object::toString).collect(
Collectors.joining(", "));
assertEquals(message, expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
assertTrue(message, expected.get(i).equals(actual.get(i)));
}
}
private static <T> void assertProtoListEqualsIgnoringOrder(@Nullable List<T> expected,
@Nullable List<T> actual) {
assertNotNull(expected);
assertNotNull(actual);
expected = new ArrayList<>(expected);
actual = new ArrayList<>(actual);
Collections.sort(expected, sProtoComparator);
Collections.sort(actual, sProtoComparator);
assertProtoListEquals(expected, actual);
}
private static void assertHasMmsAndCountAvg(@Nullable List<IncomingMms> incomingMmsList,
@Nullable IncomingMms expectedMms, long expectedCount, long expectedAvg) {
assertNotNull(incomingMmsList);
assertNotNull(expectedMms);
long actualCount = -1;
long actualAvg = -1;
for (IncomingMms mms : incomingMmsList) {
if (mms.getRat() == expectedMms.getRat()
&& mms.getResult() == expectedMms.getResult()
&& mms.getRoaming() == expectedMms.getRoaming()
&& mms.getSimSlotIndex() == expectedMms.getSimSlotIndex()
&& mms.getIsMultiSim() == expectedMms.getIsMultiSim()
&& mms.getIsEsim() == expectedMms.getIsEsim()
&& mms.getCarrierId() == expectedMms.getCarrierId()
&& mms.getRetryId() == expectedMms.getRetryId()
&& mms.getHandledByCarrierApp() == expectedMms.getHandledByCarrierApp()) {
actualCount = mms.getMmsCount();
actualAvg = mms.getAvgIntervalMillis();
}
}
assertEquals(expectedCount, actualCount);
assertEquals(expectedAvg, actualAvg);
}
private static void assertHasMmsAndCountAvg(@Nullable List<OutgoingMms> outgoingMmsList,
@Nullable OutgoingMms expectedMms, long expectedCount, long expectedAvg) {
assertNotNull(outgoingMmsList);
assertNotNull(expectedMms);
long actualCount = -1;
long actualAvg = -1;
for (OutgoingMms mms : outgoingMmsList) {
if (mms.getRat() == expectedMms.getRat()
&& mms.getResult() == expectedMms.getResult()
&& mms.getRoaming() == expectedMms.getRoaming()
&& mms.getSimSlotIndex() == expectedMms.getSimSlotIndex()
&& mms.getIsMultiSim() == expectedMms.getIsMultiSim()
&& mms.getIsEsim() == expectedMms.getIsEsim()
&& mms.getCarrierId() == expectedMms.getCarrierId()
&& mms.getIsFromDefaultApp() == expectedMms.getIsFromDefaultApp()
&& mms.getRetryId() == expectedMms.getRetryId()
&& mms.getHandledByCarrierApp() == expectedMms.getHandledByCarrierApp()) {
actualCount = mms.getMmsCount();
actualAvg = mms.getAvgIntervalMillis();
}
}
assertEquals(expectedCount, actualCount);
assertEquals(expectedAvg, actualAvg);
}
private void verifyCurrentStateSavedToFileOnce() throws Exception {
InOrder inOrder = inOrder(mTestFileOutputStream);
inOrder.verify(mTestFileOutputStream, times(1))
.write(eq(mTestablePersistMmsAtomsStorage.getAtomsProto().toByteArray()));
inOrder.verify(mTestFileOutputStream, times(1)).close();
inOrder.verifyNoMoreInteractions();
}
private PersistMmsAtoms getAtomsWritten(@Nullable InOrder inOrder) throws Exception {
if (inOrder == null) {
inOrder = inOrder(mTestFileOutputStream);
}
ArgumentCaptor bytesCaptor = ArgumentCaptor.forClass(Object.class);
inOrder.verify(mTestFileOutputStream, times(1))
.write((byte[]) bytesCaptor.capture());
PersistMmsAtoms savedAtoms = PersistMmsAtoms.parseFrom((byte[]) bytesCaptor.getValue());
inOrder.verify(mTestFileOutputStream, times(1)).close();
return savedAtoms;
}
private static IncomingMms copyOf(IncomingMms source) {
return source.toBuilder().build();
}
private static OutgoingMms copyOf(OutgoingMms source) {
return source.toBuilder().build();
}
private void makeTestData() {
mIncomingMms1Proto = IncomingMms.newBuilder()
.setRat(TelephonyManager.NETWORK_TYPE_LTE)
.setResult(1)
.setRoaming(ServiceState.ROAMING_TYPE_NOT_ROAMING)
.setSimSlotIndex(0)
.setIsMultiSim(true)
.setIsEsim(false)
.setCarrierId(CARRIER1_ID)
.setAvgIntervalMillis(500L)
.setMmsCount(1)
.setRetryId(0)
.setHandledByCarrierApp(false)
.build();
mIncomingMms2Proto = IncomingMms.newBuilder()
.setRat(TelephonyManager.NETWORK_TYPE_LTE)
.setResult(1)
.setRoaming(ServiceState.ROAMING_TYPE_NOT_ROAMING)
.setSimSlotIndex(1)
.setIsMultiSim(false)
.setIsEsim(false)
.setCarrierId(CARRIER2_ID)
.setAvgIntervalMillis(500L)
.setMmsCount(1)
.setRetryId(0)
.setHandledByCarrierApp(false)
.build();
mIncomingMmsList = new ArrayList<>();
mIncomingMmsList.add(mIncomingMms1Proto);
mIncomingMmsList.add(mIncomingMms2Proto);
mOutgoingMms1Proto = OutgoingMms.newBuilder()
.setRat(0)
.setResult(1)
.setRoaming(0)
.setSimSlotIndex(0)
.setIsMultiSim(true)
.setIsEsim(false)
.setCarrierId(CARRIER1_ID)
.setAvgIntervalMillis(500L)
.setMmsCount(1)
.setIsFromDefaultApp(true)
.setRetryId(0)
.setHandledByCarrierApp(false)
.build();
mOutgoingMms2Proto = OutgoingMms.newBuilder()
.setRat(0)
.setResult(1)
.setRoaming(0)
.setSimSlotIndex(0)
.setIsMultiSim(false)
.setIsEsim(false)
.setCarrierId(CARRIER2_ID)
.setAvgIntervalMillis(500L)
.setMmsCount(1)
.setIsFromDefaultApp(true)
.setRetryId(0)
.setHandledByCarrierApp(false)
.build();
mOutgoingMmsList = new ArrayList<>();
mOutgoingMmsList.add(mOutgoingMms1Proto);
mOutgoingMmsList.add(mOutgoingMms2Proto);
}
private void createEmptyTestFile() throws Exception {
PersistMmsAtoms atoms = PersistMmsAtoms.newBuilder().build();
FileOutputStream stream = new FileOutputStream(mTestFile);
stream.write(atoms.toByteArray());
stream.close();
}
private void createTestFile(long lastPullTimeMillis) throws Exception {
PersistMmsAtoms atoms = PersistMmsAtoms.newBuilder()
.setBuildFingerprint(Build.FINGERPRINT)
.setIncomingMmsPullTimestampMillis(lastPullTimeMillis)
.setOutgoingMmsPullTimestampMillis(lastPullTimeMillis)
.addAllIncomingMms(mIncomingMmsList)
.addAllOutgoingMms(mOutgoingMmsList)
.build();
FileOutputStream stream = new FileOutputStream(mTestFile);
stream.write(atoms.toByteArray());
stream.close();
}
private static class TestablePersistMmsAtomsStorage extends PersistMmsAtomsStorage {
private long mTimeMillis = START_TIME_MILLIS;
TestablePersistMmsAtomsStorage(Context context) {
super(context);
// Remove delay for saving to persistent storage during tests.
mSaveImmediately = true;
}
@Override
protected long getWallTimeMillis() {
// NOTE: super class constructor will be executed before private field is set, which
// gives the wrong start time (mTimeMillis will have its default value of 0L).
return mTimeMillis == 0L ? START_TIME_MILLIS : mTimeMillis;
}
private void incTimeMillis(long timeMillis) {
mTimeMillis += timeMillis;
}
private PersistMmsAtoms getAtomsProto() {
// NOTE: unlike other methods in PersistAtomsStorage, this is not synchronized, but
// should be fine since the test is single-threaded.
return mPersistMmsAtoms;
}
}
}