• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Builder()
209                         .setPrimarySimSubId(1)
210                         .setProvisioningResult(mContext, Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE)
211                         .build();
212         assertTrue(mONSStats.logEvent(info));
213     }
214 
215     @Test
testIgnoredLogEvents()216     public void testIgnoredLogEvents() {
217         // ignored error codes should not log.
218         ONSStatsInfo info =
219                 new ONSStatsInfo.Builder()
220                         .setProvisioningResult(mContext, Result.DOWNLOAD_REQUESTED)
221                         .build();
222         assertFalse(mONSStats.logEvent(info));
223 
224         info =
225                 new ONSStatsInfo.Builder()
226                         .setProvisioningResult(mContext, Result.ERR_NO_SIM_INSERTED)
227                         .build();
228         assertFalse(mONSStats.logEvent(info));
229 
230         info =
231                 new ONSStatsInfo.Builder()
232                         .setProvisioningResult(mContext, Result.ERR_DUPLICATE_DOWNLOAD_REQUEST)
233                         .build();
234         assertFalse(mONSStats.logEvent(info));
235 
236         info =
237                 new ONSStatsInfo.Builder()
238                         .setProvisioningResult(mContext, Result.ERR_SWITCHING_TO_DUAL_SIM_MODE)
239                         .build();
240         assertFalse(mONSStats.logEvent(info));
241     }
242 
243     @Test
testRepeatedLogEvents()244     public void testRepeatedLogEvents() {
245         ONSStatsInfo info;
246         info =
247                 new ONSStatsInfo.Builder()
248                         .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL)
249                         .setDetailedErrCode(10011)
250                         .build();
251         assertTrue(mONSStats.logEvent(info));
252 
253         // same result should not log consecutively
254         assertFalse(mONSStats.logEvent(info));
255         assertFalse(mONSStats.logEvent(info));
256     }
257 
258     @Test
testRepeatedAllowedLogEvents()259     public void testRepeatedAllowedLogEvents() {
260         ONSStatsInfo info;
261         info =
262                 new ONSStatsInfo.Builder()
263                         .setProvisioningResult(mContext, Result.ERR_DOWNLOADED_ESIM_NOT_FOUND)
264                         .build();
265         assertTrue(mONSStats.logEvent(info));
266 
267         // ERR_DOWNLOADED_ESIM_NOT_FOUND is allowed to log consecutively
268         assertTrue(mONSStats.logEvent(info));
269         assertTrue(mONSStats.logEvent(info));
270 
271         info =
272                 new ONSStatsInfo.Builder()
273                         .setDownloadResult(DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED)
274                         .build();
275         assertTrue(mONSStats.logEvent(info));
276 
277         // ERR_INSTALL_ESIM_PROFILE_FAILED is allowed to log consecutively
278         assertTrue(mONSStats.logEvent(info));
279         assertTrue(mONSStats.logEvent(info));
280     }
281 
282     @Test
testRepeatedSuccessLogEvents()283     public void testRepeatedSuccessLogEvents() {
284         ONSStatsInfo info;
285         info =
286                 new ONSStatsInfo.Builder()
287                 .setProvisioningResult(mContext, Result.SUCCESS)
288                 .setRetryCount(2)
289                 .build();
290 
291         // should log every time if eSIM is newly downloaded.
292         assertTrue(mONSStats.logEvent(info));
293         assertTrue(mONSStats.logEvent(info));
294 
295         info = new ONSStatsInfo.Builder().setProvisioningResult(mContext, Result.SUCCESS).build();
296         // should log even if eSIM is already downloaded and event triggered just to group it.
297         assertTrue(mONSStats.logEvent(info));
298         assertTrue(mONSStats.logEvent(info));
299     }
300 
301     @Test
testRepeatedErrorWithInfoChangeLogEvents()302     public void testRepeatedErrorWithInfoChangeLogEvents() {
303         ONSStatsInfo info =
304                 new ONSStatsInfo.Builder()
305                         .setPrimarySimSubId(1)
306                         .setProvisioningResult(mContext, Result.ERR_AUTO_PROVISIONING_DISABLED)
307                         .build();
308         assertTrue(mONSStats.logEvent(info));
309 
310         // Same error should log if the info is changed.
311         info = new ONSStatsInfo.Builder(info).setPrimarySimSubId(2).build();
312         assertTrue(mONSStats.logEvent(info));
313 
314         // no change in info
315         assertFalse(mONSStats.logEvent(info));
316     }
317 
318     @Test
testDetailedErrorCodeLogEvents()319     public void testDetailedErrorCodeLogEvents() {
320         ONSStatsInfo info;
321         info = new ONSStatsInfo.Builder()
322                 .setProvisioningResult(mContext, Result.ERR_WAITING_FOR_INTERNET_CONNECTION)
323                 .build();
324         assertTrue(mONSStats.logEvent(info));
325 
326         // For provisioning errors; Result enum ordinal is set as detailed error code.
327         assertEquals(
328                 Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(),
329                 mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1));
330         assertEquals(
331                 Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), info.detailedErrCode());
332 
333         // For Download errors; detailed error code is updated from EuiccManager.
334         info =
335                 new ONSStatsInfo.Builder(info)
336                         .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL)
337                         .setDetailedErrCode(10223)
338                         .build();
339         assertTrue(mONSStats.logEvent(info));
340         assertEquals(10223, mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1));
341         assertEquals(10223, info.detailedErrCode());
342     }
343 }
344