1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ons; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.doReturn; 24 25 import android.content.Context; 26 import android.content.SharedPreferences; 27 import android.telephony.SubscriptionInfo; 28 import android.telephony.SubscriptionManager; 29 30 import com.android.ons.ONSProfileActivator.Result; 31 import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 import org.mockito.Mock; 39 import org.mockito.MockitoAnnotations; 40 import org.mockito.Spy; 41 42 import java.util.HashMap; 43 import java.util.Map; 44 import java.util.Set; 45 46 @RunWith(JUnit4.class) 47 public class ONSStatsTest { 48 49 private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; 50 private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; 51 52 @Spy private Context mContext; 53 @Mock private SubscriptionManager mSubscriptionManager; 54 private SharedPreferences mSharedPreferences; 55 @Mock private SubscriptionInfo mSubInfoId1; 56 @Mock private SubscriptionInfo mSubInfoId2; 57 private ONSStats mONSStats; 58 59 private class FakeSharedPreferences implements SharedPreferences { 60 HashMap<String, Object> mMap = new HashMap<>(); 61 62 @Override getAll()63 public Map<String, ?> getAll() { 64 return mMap; 65 } 66 67 @Override getString(String key, String defValue)68 public String getString(String key, String defValue) { 69 return (String) mMap.getOrDefault(key, defValue); 70 } 71 72 @Override getStringSet(String key, Set<String> defValues)73 public Set<String> getStringSet(String key, Set<String> defValues) { 74 if (mMap.containsKey(key)) { 75 return (Set<String>) mMap.get(key); 76 } 77 return defValues; 78 } 79 80 @Override getInt(String key, int defValue)81 public int getInt(String key, int defValue) { 82 return (int) mMap.getOrDefault(key, defValue); 83 } 84 85 @Override getLong(String key, long defValue)86 public long getLong(String key, long defValue) { 87 return 0; // not used 88 } 89 90 @Override getFloat(String key, float defValue)91 public float getFloat(String key, float defValue) { 92 return (float) mMap.getOrDefault(key, defValue); 93 } 94 95 @Override getBoolean(String key, boolean defValue)96 public boolean getBoolean(String key, boolean defValue) { 97 return (boolean) mMap.getOrDefault(key, defValue); 98 } 99 100 @Override contains(String key)101 public boolean contains(String key) { 102 return mMap.containsKey(key); 103 } 104 105 @Override edit()106 public Editor edit() { 107 TestEditor editor = new TestEditor(); 108 editor.map = mMap; 109 return editor; 110 } 111 112 @Override registerOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)113 public void registerOnSharedPreferenceChangeListener( 114 OnSharedPreferenceChangeListener listener) {} 115 116 @Override unregisterOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)117 public void unregisterOnSharedPreferenceChangeListener( 118 OnSharedPreferenceChangeListener listener) {} 119 120 private class TestEditor implements SharedPreferences.Editor { 121 HashMap<String, Object> map = new HashMap<>(); 122 123 @Override putString(String key, String value)124 public SharedPreferences.Editor putString(String key, String value) { 125 map.put(key, value); 126 return this; 127 } 128 129 @Override putStringSet(String key, Set<String> values)130 public SharedPreferences.Editor putStringSet(String key, Set<String> values) { 131 map.put(key, values); 132 return this; 133 } 134 135 @Override putInt(String key, int value)136 public SharedPreferences.Editor putInt(String key, int value) { 137 map.put(key, value); 138 return this; 139 } 140 141 @Override putLong(String key, long value)142 public SharedPreferences.Editor putLong(String key, long value) { 143 map.put(key, value); 144 return this; 145 } 146 147 @Override putFloat(String key, float value)148 public SharedPreferences.Editor putFloat(String key, float value) { 149 map.put(key, value); 150 return this; 151 } 152 153 @Override putBoolean(String key, boolean value)154 public SharedPreferences.Editor putBoolean(String key, boolean value) { 155 map.put(key, value); 156 return this; 157 } 158 159 @Override remove(String key)160 public SharedPreferences.Editor remove(String key) { 161 map.remove(key); 162 return this; 163 } 164 165 @Override clear()166 public SharedPreferences.Editor clear() { 167 map.clear(); 168 return this; 169 } 170 171 @Override commit()172 public boolean commit() { 173 mMap = map; 174 return true; 175 } 176 177 @Override apply()178 public void apply() { 179 mMap = map; 180 } 181 } 182 ; 183 } 184 ; 185 186 @Before setUp()187 public void setUp() { 188 MockitoAnnotations.initMocks(this); 189 mSharedPreferences = new FakeSharedPreferences(); 190 doReturn(mSharedPreferences) 191 .when(mContext) 192 .getSharedPreferences(eq(ONS_ATOM_LOG_FILE), eq(Context.MODE_PRIVATE)); 193 doReturn(123).when(mSubInfoId1).getCarrierId(); 194 doReturn(456).when(mSubInfoId2).getCarrierId(); 195 doReturn(mSubInfoId1).when(mSubscriptionManager).getActiveSubscriptionInfo(1); 196 doReturn(mSubInfoId2).when(mSubscriptionManager).getActiveSubscriptionInfo(2); 197 mONSStats = new ONSStats(mContext, mSubscriptionManager); 198 } 199 200 @After tearDown()201 public void tearDown() { 202 mSharedPreferences.edit().clear().apply(); 203 } 204 205 @Test testLogEvent()206 public void testLogEvent() { 207 ONSStatsInfo info = 208 new ONSStatsInfo() 209 .setPrimarySimSubId(1) 210 .setProvisioningResult(Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE); 211 assertTrue(mONSStats.logEvent(info)); 212 } 213 214 @Test testIgnoredLogEvents()215 public void testIgnoredLogEvents() { 216 // ignored error codes should not log. 217 ONSStatsInfo info = new ONSStatsInfo().setProvisioningResult(Result.DOWNLOAD_REQUESTED); 218 assertFalse(mONSStats.logEvent(info)); 219 220 info = new ONSStatsInfo().setProvisioningResult(Result.ERR_NO_SIM_INSERTED); 221 assertFalse(mONSStats.logEvent(info)); 222 223 info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DUPLICATE_DOWNLOAD_REQUEST); 224 assertFalse(mONSStats.logEvent(info)); 225 226 info = new ONSStatsInfo().setProvisioningResult(Result.ERR_SWITCHING_TO_DUAL_SIM_MODE); 227 assertFalse(mONSStats.logEvent(info)); 228 } 229 230 @Test testRepeatedLogEvents()231 public void testRepeatedLogEvents() { 232 ONSStatsInfo info; 233 info = 234 new ONSStatsInfo() 235 .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) 236 .setDetailedErrCode(10011); 237 assertTrue(mONSStats.logEvent(info)); 238 239 // same result should not log consecutively 240 assertFalse(mONSStats.logEvent(info)); 241 assertFalse(mONSStats.logEvent(info)); 242 } 243 244 @Test testRepeatedAllowedLogEvents()245 public void testRepeatedAllowedLogEvents() { 246 ONSStatsInfo info; 247 info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND); 248 assertTrue(mONSStats.logEvent(info)); 249 250 // ERR_DOWNLOADED_ESIM_NOT_FOUND is allowed to log consecutively 251 assertTrue(mONSStats.logEvent(info)); 252 assertTrue(mONSStats.logEvent(info)); 253 254 info = 255 new ONSStatsInfo() 256 .setDownloadResult(DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED); 257 assertTrue(mONSStats.logEvent(info)); 258 259 // ERR_INSTALL_ESIM_PROFILE_FAILED is allowed to log consecutively 260 assertTrue(mONSStats.logEvent(info)); 261 assertTrue(mONSStats.logEvent(info)); 262 } 263 264 @Test testRepeatedSuccessLogEvents()265 public void testRepeatedSuccessLogEvents() { 266 ONSStatsInfo info; 267 info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS).setRetryCount(2); 268 269 // should log every time if eSIM is newly downloaded. 270 assertTrue(mONSStats.logEvent(info)); 271 assertTrue(mONSStats.logEvent(info)); 272 273 info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS); 274 // should log even if eSIM is already downloaded and event triggered just to group it. 275 assertTrue(mONSStats.logEvent(info)); 276 assertTrue(mONSStats.logEvent(info)); 277 } 278 279 @Test testRepeatedErrorWithInfoChangeLogEvents()280 public void testRepeatedErrorWithInfoChangeLogEvents() { 281 ONSStatsInfo info = 282 new ONSStatsInfo() 283 .setPrimarySimSubId(1) 284 .setProvisioningResult(Result.ERR_AUTO_PROVISIONING_DISABLED); 285 assertTrue(mONSStats.logEvent(info)); 286 287 // Same error should log if the info is changed. 288 info.setPrimarySimSubId(2); 289 assertTrue(mONSStats.logEvent(info)); 290 291 // no change in info 292 assertFalse(mONSStats.logEvent(info)); 293 } 294 295 @Test testDetailedErrorCodeLogEvents()296 public void testDetailedErrorCodeLogEvents() { 297 ONSStatsInfo info; 298 info = new ONSStatsInfo().setProvisioningResult(Result.ERR_WAITING_FOR_INTERNET_CONNECTION); 299 assertTrue(mONSStats.logEvent(info)); 300 301 // For provisioning errors; Result enum ordinal is set as detailed error code. 302 assertEquals( 303 Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), 304 mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); 305 assertEquals( 306 Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), info.getDetailedErrCode()); 307 308 // For Download errors; detailed error code is updated from EuiccManager. 309 info = 310 new ONSStatsInfo() 311 .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) 312 .setDetailedErrCode(10223); 313 assertTrue(mONSStats.logEvent(info)); 314 assertEquals(10223, mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); 315 assertEquals(10223, info.getDetailedErrCode()); 316 } 317 } 318