1 /* 2 * Copyright (C) 2017 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 package android.carrierapi.cts; 17 18 import static junit.framework.TestCase.assertEquals; 19 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.fail; 23 24 import android.content.ContentResolver; 25 import android.content.ContentValues; 26 import android.content.pm.PackageManager; 27 import android.database.Cursor; 28 import android.database.sqlite.SQLiteException; 29 import android.net.Uri; 30 import android.provider.Telephony.Carriers; 31 import android.util.Log; 32 33 import androidx.test.InstrumentationRegistry; 34 import androidx.test.runner.AndroidJUnit4; 35 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.Arrays; 41 import java.util.HashMap; 42 import java.util.Map; 43 44 /** 45 * Build, install and run the tests by running the commands below: 46 * make cts -j64 47 * cts-tradefed run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.ApnDatabaseTest 48 */ 49 @RunWith(AndroidJUnit4.class) 50 public class ApnDatabaseTest { 51 private static final String TAG = "ApnDatabaseTest"; 52 53 private ContentResolver mContentResolver; 54 private PackageManager mPackageManager; 55 private boolean mHasCellular; 56 57 private static final String NAME = "carrierName"; 58 private static final String APN = "apn"; 59 private static final String PROXY = "proxy"; 60 private static final String PORT = "port"; 61 private static final String MMSC = "mmsc"; 62 private static final String MMSPROXY = "mmsproxy"; 63 private static final String MMSPORT = "mmsport"; 64 private static final String NUMERIC = "numeric"; 65 private static final String USER = "user"; 66 private static final String PASSWORD = "password"; 67 private static final String AUTH_TYPE = "auth_type"; 68 private static final String TYPE = "type"; 69 private static final String PROTOCOL = "protocol"; 70 private static final String ROAMING_PROTOCOL = "roaming_protocol"; 71 private static final String CARRIER_ENABLED = "true"; 72 private static final String NETWORK_TYPE_BITMASK = "0"; 73 private static final String BEARER = "0"; 74 75 private static final Map<String, String> APN_MAP = new HashMap<String,String>() {{ 76 put(Carriers.NAME, NAME); 77 put(Carriers.APN, APN); 78 put(Carriers.PROXY, PROXY); 79 put(Carriers.PORT, PORT); 80 put(Carriers.MMSC, MMSC); 81 put(Carriers.MMSPROXY, MMSPROXY); 82 put(Carriers.MMSPORT, MMSPORT); 83 put(Carriers.NUMERIC, NUMERIC); 84 put(Carriers.USER, USER); 85 put(Carriers.PASSWORD, PASSWORD); 86 put(Carriers.AUTH_TYPE, AUTH_TYPE); 87 put(Carriers.TYPE, TYPE); 88 put(Carriers.PROTOCOL, PROTOCOL); 89 put(Carriers.ROAMING_PROTOCOL, ROAMING_PROTOCOL); 90 put(Carriers.CARRIER_ENABLED, CARRIER_ENABLED); 91 put(Carriers.NETWORK_TYPE_BITMASK, NETWORK_TYPE_BITMASK); 92 put(Carriers.BEARER, BEARER); 93 }}; 94 95 // Faked network type bitmask and its compatible bearer bitmask. 96 private static final int NETWORK_TYPE_BITMASK_NUMBER = 1 << (13 - 1); 97 private static final int RIL_RADIO_TECHNOLOGY_BITMASK_NUMBER = 1 << (14 - 1); 98 99 @Before 100 public void setUp() throws Exception { 101 mContentResolver = InstrumentationRegistry.getContext().getContentResolver(); 102 mPackageManager = InstrumentationRegistry.getContext().getPackageManager(); 103 // Checks whether the cellular stack should be running on this device. 104 mHasCellular = mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); 105 if (!mHasCellular) { 106 Log.e(TAG, "No cellular support, all tests will be skipped."); 107 } 108 } 109 110 private void failMessage() { 111 fail("This test requires a SIM card with carrier privilege rule on it.\n" + 112 "Visit https://source.android.com/devices/tech/config/uicc.html"); 113 } 114 115 /** 116 * Test inserting, querying, updating and deleting values in carriers table. 117 * Verify that the inserted values match the result of the query and are deleted. 118 */ 119 @Test 120 public void testValidCase() { 121 if (!mHasCellular) return; 122 Uri uri = Carriers.CONTENT_URI; 123 // CONTENT_URI = Uri.parse("content://telephony/carriers"); 124 // Create A set of column_name/value pairs to add to the database. 125 ContentValues contentValues = makeDefaultContentValues(); 126 127 try { 128 // Insert the value into database. 129 Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString()); 130 Uri newUri = mContentResolver.insert(uri, contentValues); 131 assertNotNull("Failed to insert to table", newUri); 132 133 // Get the values in table. 134 final String selection = Carriers.NUMERIC + "=?"; 135 String[] selectionArgs = { NUMERIC }; 136 String[] apnProjection = APN_MAP.keySet().toArray(new String[APN_MAP.size()]); 137 Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(apnProjection) 138 + "\ntestInsertCarriers selection: " + selection 139 + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 140 Cursor cursor = mContentResolver.query( 141 uri, apnProjection, selection, selectionArgs, null); 142 143 // Verify that the inserted value match the results of the query 144 assertNotNull("Failed to query the table", cursor); 145 assertEquals("Unexpected number of APNs returned by cursor", 146 1, cursor.getCount()); 147 cursor.moveToFirst(); 148 for (Map.Entry<String, String> entry: APN_MAP.entrySet()) { 149 assertEquals( 150 "Unexpected value returned by cursor", 151 cursor.getString(cursor.getColumnIndex(entry.getKey())), entry.getValue()); 152 } 153 154 // update the apn 155 final String newApn = "newapn"; 156 Log.d(TAG, "Update the APN field to: " + newApn); 157 contentValues.put(Carriers.APN, newApn); 158 final int updateCount = mContentResolver.update(uri, contentValues, selection, 159 selectionArgs); 160 assertEquals("Unexpected number of rows updated", 1, updateCount); 161 162 // Verify the updated value 163 cursor = mContentResolver.query(uri, apnProjection, selection, selectionArgs, null); 164 assertNotNull("Failed to query the table", cursor); 165 assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount()); 166 cursor.moveToFirst(); 167 assertEquals("Unexpected value returned by cursor", 168 cursor.getString(cursor.getColumnIndex(Carriers.APN)), newApn); 169 170 // delete test content 171 final String selectionToDelete = Carriers.NUMERIC + "=?"; 172 String[] selectionArgsToDelete = { NUMERIC }; 173 Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete 174 + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 175 int numRowsDeleted = mContentResolver.delete( 176 uri, selectionToDelete, selectionArgsToDelete); 177 assertEquals("Unexpected number of rows deleted",1, numRowsDeleted); 178 179 // verify that deleted values are gone 180 cursor = mContentResolver.query(uri, apnProjection, selection, selectionArgs, null); 181 assertEquals("Unexpected number of rows deleted", 0, cursor.getCount()); 182 } catch (SecurityException e) { 183 failMessage(); 184 } 185 } 186 187 @Test 188 public void testQueryConflictCase() { 189 if (!mHasCellular) return; 190 String invalidColumn = "random"; 191 Uri uri = Carriers.CONTENT_URI; 192 // CONTENT_URI = Uri.parse("content://telephony/carriers"); 193 // Create A set of column_name/value pairs to add to the database. 194 ContentValues contentValues = new ContentValues(); 195 contentValues.put(Carriers.NAME, NAME); 196 contentValues.put(Carriers.APN, APN); 197 contentValues.put(Carriers.PORT, PORT); 198 contentValues.put(Carriers.PROTOCOL, PROTOCOL); 199 contentValues.put(Carriers.NUMERIC, NUMERIC); 200 201 try { 202 // Insert the value into database. 203 Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString()); 204 Uri newUri = mContentResolver.insert(uri, contentValues); 205 assertNotNull("Failed to insert to table", newUri); 206 207 // Try to get the value with invalid selection 208 final String[] testProjection = 209 { 210 Carriers.NAME, 211 Carriers.APN, 212 Carriers.PORT, 213 Carriers.PROTOCOL, 214 Carriers.NUMERIC, 215 }; 216 final String selection = invalidColumn + "=?"; 217 String[] selectionArgs = { invalidColumn }; 218 Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection) 219 + "\ntestInsertCarriers selection: " + selection 220 + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 221 Cursor cursor = mContentResolver.query( 222 uri, testProjection, selection, selectionArgs, null); 223 assertNull("Failed to query the table",cursor); 224 225 // delete test content 226 final String selectionToDelete = Carriers.NAME + "=?"; 227 String[] selectionArgsToDelete = { NAME }; 228 Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete 229 + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 230 int numRowsDeleted = mContentResolver.delete( 231 uri, selectionToDelete, selectionArgsToDelete); 232 assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted); 233 234 // verify that deleted values are gone 235 cursor = mContentResolver.query( 236 uri, testProjection, selectionToDelete, selectionArgsToDelete, null); 237 assertEquals("Unexpected number of rows deleted", 0, cursor.getCount()); 238 } catch (SecurityException e) { 239 failMessage(); 240 } 241 } 242 243 @Test 244 public void testUpdateConflictCase() { 245 if (!mHasCellular) return; 246 Uri uri = Carriers.CONTENT_URI; 247 // CONTENT_URI = Uri.parse("content://telephony/carriers"); 248 // Create A set of column_name/value pairs to add to the database. 249 ContentValues contentValues = new ContentValues(); 250 contentValues.put(Carriers.NAME, NAME); 251 contentValues.put(Carriers.APN, APN); 252 contentValues.put(Carriers.PORT, PORT); 253 contentValues.put(Carriers.PROTOCOL, PROTOCOL); 254 contentValues.put(Carriers.NUMERIC, NUMERIC); 255 256 try { 257 // Insert the value into database. 258 Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString()); 259 Uri newUri = mContentResolver.insert(uri, contentValues); 260 assertNotNull("Failed to insert to table", newUri); 261 262 // Try to get the value with invalid selection 263 final String[] testProjection = 264 { 265 Carriers.NAME, 266 Carriers.APN, 267 Carriers.PORT, 268 Carriers.PROTOCOL, 269 Carriers.NUMERIC, 270 }; 271 String selection = Carriers.NAME + "=?"; 272 String[] selectionArgs = { NAME }; 273 Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection) 274 + "\ntestInsertCarriers selection: " + selection 275 + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 276 Cursor cursor = mContentResolver.query( 277 uri, testProjection, selection, selectionArgs, null); 278 assertEquals("Unexpected number of APNs returned by cursor", 279 1, cursor.getCount()); 280 281 // Update the table with invalid column 282 String invalidColumn = "random"; 283 contentValues.put(invalidColumn, invalidColumn); 284 try { 285 mContentResolver.update(uri, contentValues, selection, selectionArgs); 286 fail(); 287 } catch (SQLiteException e) { 288 // Expected: If there's no such a column, an exception will be thrown and the 289 // Activity Manager will kill this process shortly. 290 } 291 292 // delete test content 293 final String selectionToDelete = Carriers.NAME + "=?"; 294 String[] selectionArgsToDelete = { NAME }; 295 Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete 296 + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 297 int numRowsDeleted = mContentResolver.delete( 298 uri, selectionToDelete, selectionArgsToDelete); 299 assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted); 300 301 // verify that deleted values are gone 302 cursor = mContentResolver.query( 303 uri, testProjection, selectionToDelete, selectionArgsToDelete, null); 304 assertEquals("Unexpected number of rows deleted", 0, cursor.getCount()); 305 } catch (SecurityException e) { 306 failMessage(); 307 } 308 } 309 310 @Test 311 public void testDeleteConflictCase() { 312 if (!mHasCellular) return; 313 String invalidColumn = "random"; 314 Uri uri = Carriers.CONTENT_URI; 315 // CONTENT_URI = Uri.parse("content://telephony/carriers"); 316 // Create A set of column_name/value pairs to add to the database. 317 ContentValues contentValues = new ContentValues(); 318 contentValues.put(Carriers.NAME, NAME); 319 contentValues.put(Carriers.APN, APN); 320 contentValues.put(Carriers.PORT, PORT); 321 contentValues.put(Carriers.PROTOCOL, PROTOCOL); 322 contentValues.put(Carriers.NUMERIC, NUMERIC); 323 324 try { 325 // Insert the value into database. 326 Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString()); 327 Uri newUri = mContentResolver.insert(uri, contentValues); 328 assertNotNull("Failed to insert to table", newUri); 329 330 // Get the values in table. 331 final String[] testProjection = 332 { 333 Carriers.NAME, 334 Carriers.APN, 335 Carriers.PORT, 336 Carriers.PROTOCOL, 337 Carriers.NUMERIC, 338 }; 339 String selection = Carriers.NAME + "=?"; 340 String[] selectionArgs = { NAME }; 341 Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection) 342 + "\ntestInsertCarriers selection: " + selection 343 + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 344 Cursor cursor = mContentResolver.query( 345 uri, testProjection, selection, selectionArgs, null); 346 assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount()); 347 348 // try to delete with invalid selection 349 String selectionToDelete = invalidColumn + "=?"; 350 String[] selectionArgsToDelete = { invalidColumn }; 351 Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete 352 + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 353 354 try { 355 mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete); 356 fail(); 357 } catch (SQLiteException e) { 358 // Expected: If there's no such a column, an exception will be thrown and the 359 // Activity Manager will kill this process shortly. 360 } 361 362 // verify that deleted value is still there 363 selection = Carriers.NAME + "=?"; 364 selectionArgs[0] = NAME; 365 cursor = mContentResolver.query(uri, testProjection, selection, selectionArgs, null); 366 assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount()); 367 368 // delete test content 369 selectionToDelete = Carriers.NAME + "=?"; 370 selectionArgsToDelete[0] = NAME; 371 Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete 372 + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs)); 373 int numRowsDeleted = mContentResolver.delete( 374 uri, selectionToDelete, selectionArgsToDelete); 375 assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted); 376 377 // verify that deleted values are gone 378 cursor = mContentResolver.query(uri, testProjection, selection, selectionArgs, null); 379 assertEquals("Unexpected number of rows deleted", 0, cursor.getCount()); 380 } catch (SecurityException e) { 381 failMessage(); 382 } 383 } 384 385 private ContentValues makeDefaultContentValues() { 386 ContentValues contentValues = new ContentValues(); 387 for (Map.Entry<String, String> entry: APN_MAP.entrySet()) { 388 contentValues.put(entry.getKey(), entry.getValue()); 389 } 390 return contentValues; 391 } 392 }