summaryrefslogtreecommitdiff
path: root/tests/unittests/src/com
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:22:17 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:22:17 +0000
commit3466fd4eecbc152728a0f3ad3e2dacba45fd7a82 (patch)
treee03dc9d843034a476a34f3e1fb0d0a7accf4a17a /tests/unittests/src/com
parent65e30106a579db014c76b7d3a5cf0d2d3f349c63 (diff)
parent0a1ab1245ef3f64593d270f8cd5217a823e51c0c (diff)
downloadMms-3466fd4eecbc152728a0f3ad3e2dacba45fd7a82.tar.gz
Change-Id: Idd342b326565dc5018697a07333e93b14c8b29dd
Diffstat (limited to 'tests/unittests/src/com')
-rw-r--r--tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java148
-rw-r--r--tests/unittests/src/com/android/mms/service/metrics/MmsMetricsCollectorTest.java142
-rw-r--r--tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java154
-rw-r--r--tests/unittests/src/com/android/mms/service/metrics/PersistMmsAtomsStorageTest.java734
4 files changed, 1178 insertions, 0 deletions
diff --git a/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java b/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java
new file mode 100644
index 0000000..dd126e8
--- /dev/null
+++ b/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.os.Bundle;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.junit.Test;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.reset;
+
+import android.util.Log;
+
+public class MmsHttpClientTest {
+ // Mocked classes
+ private Context mContext;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+
+ // The raw phone number from TelephonyManager.getLine1Number
+ private static final String MACRO_LINE1 = "LINE1";
+ // The phone number without country code
+ private static final String MACRO_LINE1NOCOUNTRYCODE = "LINE1NOCOUNTRYCODE";
+ private String line1Number = "1234567890";
+ private String subscriberPhoneNumber = "0987654321";
+ private int subId = 1;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mTelephonyManager = mock(TelephonyManager.class);
+ mSubscriptionManager = mock(SubscriptionManager.class);
+
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt()))
+ .thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(SubscriptionManager.class))
+ .thenReturn(mSubscriptionManager);
+ }
+
+ @After
+ public void tearDown() {
+ mContext = null;
+ mTelephonyManager = null;
+ mSubscriptionManager = null;
+ }
+
+ @Test
+ public void getPhoneNumberForMacroLine1() {
+ String macro = MACRO_LINE1;
+ Bundle mmsConfig = new Bundle();
+ String emptyStr = "";
+ String phoneNo;
+
+ /* when getLine1Number returns valid number */
+ doReturn(line1Number).when(mTelephonyManager).getLine1Number();
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).isEqualTo(line1Number);
+ // getLine1NumberAPI should be called
+ verify(mTelephonyManager).getLine1Number();
+ // getPhoneNumber should never be called
+ verify(mSubscriptionManager, never()).getPhoneNumber(subId);
+
+ /* when getLine1Number returns empty string */
+ doReturn(emptyStr).when(mTelephonyManager).getLine1Number();
+ when(mSubscriptionManager.getPhoneNumber(subId)).thenReturn(subscriberPhoneNumber);
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).isEqualTo(subscriberPhoneNumber);
+ verify(mSubscriptionManager).getPhoneNumber(subId);
+
+ /* when getLine1Number returns null */
+ reset(mSubscriptionManager);
+ when(mSubscriptionManager.getPhoneNumber(subId)).thenReturn(subscriberPhoneNumber);
+ doReturn(null).when(mTelephonyManager).getLine1Number();
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).isEqualTo(subscriberPhoneNumber);
+ verify(mSubscriptionManager).getPhoneNumber(subId);
+ }
+
+ @Test
+ public void getPhoneNumberForMacroLine1CountryCode() throws Exception {
+ String macro = MACRO_LINE1NOCOUNTRYCODE;
+ String emptyStr = "";
+ String phoneNo;
+ Bundle mmsConfig = new Bundle();
+
+ /* when getLine1Number returns valid number */
+ doReturn(line1Number).when(mTelephonyManager).getLine1Number();
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).contains(line1Number);
+ // getLine1NumberAPI should be called
+ verify(mTelephonyManager).getLine1Number();
+ // getPhoneNumber should never be called
+ verify(mSubscriptionManager, never()).getPhoneNumber(subId);
+
+ /* when getLine1Number returns empty string */
+ doReturn(emptyStr).when(mTelephonyManager).getLine1Number();
+ when(mSubscriptionManager.getPhoneNumber(subId)).thenReturn(subscriberPhoneNumber);
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).contains(subscriberPhoneNumber);
+ verify(mSubscriptionManager).getPhoneNumber(subId);
+
+ /* when getLine1Number returns null */
+ reset(mSubscriptionManager);
+ when(mSubscriptionManager.getPhoneNumber(subId)).thenReturn(subscriberPhoneNumber);
+ doReturn(null).when(mTelephonyManager).getLine1Number();
+ phoneNo = MmsHttpClient.getMacroValue(mContext, macro, mmsConfig, subId);
+ assertThat(phoneNo).contains(subscriberPhoneNumber);
+ verify(mSubscriptionManager).getPhoneNumber(subId);
+ }
+}
diff --git a/tests/unittests/src/com/android/mms/service/metrics/MmsMetricsCollectorTest.java b/tests/unittests/src/com/android/mms/service/metrics/MmsMetricsCollectorTest.java
new file mode 100644
index 0000000..8d93739
--- /dev/null
+++ b/tests/unittests/src/com/android/mms/service/metrics/MmsMetricsCollectorTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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 com.android.mms.MmsStatsLog.INCOMING_MMS;
+import static com.android.mms.MmsStatsLog.OUTGOING_MMS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.StatsManager;
+import android.content.Context;
+import android.util.StatsEvent;
+
+import com.android.mms.IncomingMms;
+import com.android.mms.OutgoingMms;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MmsMetricsCollectorTest {
+ private static final long MIN_COOLDOWN_MILLIS = 23L * 3600L * 1000L;
+ Context mContext;
+ private PersistMmsAtomsStorage mPersistMmsAtomsStorage;
+ private MmsMetricsCollector mMmsMetricsCollector;
+
+ @Before
+ public void setUp() {
+ mContext = mock(Context.class);
+ mPersistMmsAtomsStorage = mock(PersistMmsAtomsStorage.class);
+ mMmsMetricsCollector = new MmsMetricsCollector(mContext, mPersistMmsAtomsStorage);
+ }
+
+ @After
+ public void tearDown() {
+ mContext = null;
+ mPersistMmsAtomsStorage = null;
+ mMmsMetricsCollector = null;
+ }
+
+ @Test
+ public void onPullAtom_incomingMms_empty() {
+ doReturn(new ArrayList<>()).when(mPersistMmsAtomsStorage).getIncomingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(INCOMING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_incomingMms_tooFrequent() {
+ doReturn(null).when(mPersistMmsAtomsStorage).getIncomingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(INCOMING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistMmsAtomsStorage, times(1))
+ .getIncomingMms(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistMmsAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_incomingMms_multipleMms() {
+ IncomingMms incomingMms = IncomingMms.newBuilder().build();
+ doReturn(Arrays.asList(incomingMms, incomingMms, incomingMms, incomingMms))
+ .when(mPersistMmsAtomsStorage).getIncomingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(INCOMING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(4);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_outgoingMms_empty() {
+ doReturn(new ArrayList<>()).when(mPersistMmsAtomsStorage).getOutgoingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(OUTGOING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_outgoingMms_tooFrequent() {
+ doReturn(null).when(mPersistMmsAtomsStorage).getOutgoingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(OUTGOING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistMmsAtomsStorage, times(1))
+ .getOutgoingMms(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistMmsAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_outgoingMms_multipleMms() {
+ OutgoingMms outgoingMms = OutgoingMms.newBuilder().build();
+ doReturn(Arrays.asList(outgoingMms, outgoingMms, outgoingMms, outgoingMms))
+ .when(mPersistMmsAtomsStorage).getOutgoingMms(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMmsMetricsCollector.onPullAtom(OUTGOING_MMS, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(4);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+} \ No newline at end of file
diff --git a/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java b/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java
new file mode 100644
index 0000000..2b2cae5
--- /dev/null
+++ b/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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 com.android.mms.MmsStatsLog.INCOMING_MMS__RESULT__MMS_RESULT_SUCCESS;
+import static com.android.mms.MmsStatsLog.OUTGOING_MMS__RESULT__MMS_RESULT_SUCCESS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.Activity;
+import android.content.Context;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.mms.IncomingMms;
+import com.android.mms.OutgoingMms;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.ArgumentCaptor;
+
+public class MmsStatsTest {
+ // Mocked classes
+ private Context mContext;
+ private PersistMmsAtomsStorage mPersistMmsAtomsStorage;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+
+ @Before
+ public void setUp() {
+ mContext = mock(Context.class);
+ mPersistMmsAtomsStorage = mock(PersistMmsAtomsStorage.class);
+ mTelephonyManager = mock(TelephonyManager.class);
+ mSubscriptionManager = mock(SubscriptionManager.class);
+
+ doReturn(mSubscriptionManager).when(mContext).getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ }
+
+ @After
+ public void tearDown() {
+ mContext = null;
+ mPersistMmsAtomsStorage = null;
+ mTelephonyManager = null;
+ }
+
+ @Test
+ public void addAtomToStorage_incomingMms_default() {
+ doReturn(null).when(mTelephonyManager).getServiceState();
+ doReturn(TelephonyManager.UNKNOWN_CARRIER_ID).when(mTelephonyManager).getSimCarrierId();
+ int inactiveSubId = 123;
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, inactiveSubId,
+ mTelephonyManager, null, true);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ ArgumentCaptor<IncomingMms> incomingMmsCaptor = ArgumentCaptor.forClass(IncomingMms.class);
+ verify(mPersistMmsAtomsStorage).addIncomingMms(incomingMmsCaptor.capture());
+ IncomingMms incomingMms = incomingMmsCaptor.getValue();
+ assertThat(incomingMms.getRat()).isEqualTo(TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertThat(incomingMms.getResult()).isEqualTo(INCOMING_MMS__RESULT__MMS_RESULT_SUCCESS);
+ assertThat(incomingMms.getRoaming()).isEqualTo(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+ assertThat(incomingMms.getSimSlotIndex()).isEqualTo(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ assertThat(incomingMms.getIsMultiSim()).isEqualTo(false);
+ assertThat(incomingMms.getIsEsim()).isEqualTo(false);
+ assertThat(incomingMms.getCarrierId()).isEqualTo(TelephonyManager.UNKNOWN_CARRIER_ID);
+ assertThat(incomingMms.getMmsCount()).isEqualTo(1);
+ assertThat(incomingMms.getRetryId()).isEqualTo(0);
+ assertThat(incomingMms.getHandledByCarrierApp()).isEqualTo(false);
+ assertThat(incomingMms.getIsManagedProfile()).isEqualTo(false);
+ verifyNoMoreInteractions(mPersistMmsAtomsStorage);
+ }
+
+ @Test
+ public void addAtomToStorage_outgoingMms_default() {
+ doReturn(null).when(mTelephonyManager).getServiceState();
+ doReturn(TelephonyManager.UNKNOWN_CARRIER_ID).when(mTelephonyManager).getSimCarrierId();
+ int inactiveSubId = 123;
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, inactiveSubId,
+ mTelephonyManager, null, false);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ ArgumentCaptor<OutgoingMms> outgoingMmsCaptor = ArgumentCaptor.forClass(OutgoingMms.class);
+ verify(mPersistMmsAtomsStorage).addOutgoingMms(outgoingMmsCaptor.capture());
+ OutgoingMms outgoingMms = outgoingMmsCaptor.getValue();
+ assertThat(outgoingMms.getRat()).isEqualTo(TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertThat(outgoingMms.getResult()).isEqualTo(OUTGOING_MMS__RESULT__MMS_RESULT_SUCCESS);
+ assertThat(outgoingMms.getRoaming()).isEqualTo(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+ assertThat(outgoingMms.getSimSlotIndex()).isEqualTo(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ assertThat(outgoingMms.getIsMultiSim()).isEqualTo(false);
+ assertThat(outgoingMms.getIsEsim()).isEqualTo(false);
+ assertThat(outgoingMms.getCarrierId()).isEqualTo(TelephonyManager.UNKNOWN_CARRIER_ID);
+ assertThat(outgoingMms.getMmsCount()).isEqualTo(1);
+ assertThat(outgoingMms.getRetryId()).isEqualTo(0);
+ assertThat(outgoingMms.getHandledByCarrierApp()).isEqualTo(false);
+ assertThat(outgoingMms.getIsFromDefaultApp()).isEqualTo(false);
+ assertThat(outgoingMms.getIsManagedProfile()).isEqualTo(false);
+ verifyNoMoreInteractions(mPersistMmsAtomsStorage);
+ }
+
+ @Test
+ public void getDataRoamingType_serviceState_notNull() {
+ ServiceState serviceState = mock(ServiceState.class);
+ doReturn(serviceState).when(mTelephonyManager).getServiceState();
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, 1,
+ mTelephonyManager, null, true);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ ArgumentCaptor<IncomingMms> incomingMmsCaptor = ArgumentCaptor.forClass(IncomingMms.class);
+ verify(mPersistMmsAtomsStorage).addIncomingMms(incomingMmsCaptor.capture());
+ IncomingMms incomingMms = incomingMmsCaptor.getValue();
+ assertThat(incomingMms.getRoaming()).isEqualTo(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+ }
+
+
+ @Test
+ public void isDefaultMmsApp_subId_inactive() {
+ int inactiveSubId = 123;
+ doReturn(false).when(mSubscriptionManager)
+ .isActiveSubscriptionId(eq(inactiveSubId));
+
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, inactiveSubId,
+ mTelephonyManager, null, false);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ // getSubscriptionUserHandle should not be called if subID is inactive.
+ verify(mSubscriptionManager, never()).getSubscriptionUserHandle(eq(inactiveSubId));
+ }
+} \ No newline at end of file
diff --git a/tests/unittests/src/com/android/mms/service/metrics/PersistMmsAtomsStorageTest.java b/tests/unittests/src/com/android/mms/service/metrics/PersistMmsAtomsStorageTest.java
new file mode 100644
index 0000000..7f604bc
--- /dev/null
+++ b/tests/unittests/src/com/android/mms/service/metrics/PersistMmsAtomsStorageTest.java
@@ -0,0 +1,734 @@
+/*
+ * 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;
+ }
+ }
+} \ No newline at end of file