SettingsProviderTest.java revision 2849465ee19febd5135cb6ab8cb548a3c8ac6a24
1/*
2 * Copyright (C) 2015 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
17package com.android.providers.settings;
18
19import android.content.ContentResolver;
20import android.content.ContentValues;
21import android.database.ContentObserver;
22import android.database.Cursor;
23import android.net.Uri;
24import android.os.Handler;
25import android.os.Looper;
26import android.os.SystemClock;
27import android.os.UserHandle;
28import android.provider.Settings;
29import android.util.Log;
30
31import java.util.concurrent.atomic.AtomicBoolean;
32
33/**
34 * Tests for the SettingContentProvider.
35 *
36 * Before you run this test you must add a secondary user.
37 */
38public class SettingsProviderTest extends BaseSettingsProviderTest {
39    private static final String LOG_TAG = "SettingsProviderTest";
40
41    private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
42
43    private static final String[] NAME_VALUE_COLUMNS = new String[]{
44            Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
45    };
46
47    private final Object mLock = new Object();
48
49    public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception {
50        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER);
51    }
52
53    public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception {
54        if (mSecondaryUserId == UserHandle.USER_OWNER) {
55            Log.w(LOG_TAG, "No secondary user. Skipping "
56                    + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser");
57            return;
58        }
59        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
60    }
61
62    public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception {
63        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER);
64    }
65
66    public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception {
67        if (mSecondaryUserId == UserHandle.USER_OWNER) {
68            Log.w(LOG_TAG, "No secondary user. Skipping "
69                    + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser");
70            return;
71        }
72        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
73    }
74
75    public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception {
76        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER);
77    }
78
79    public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception {
80        if (mSecondaryUserId == UserHandle.USER_OWNER) {
81            Log.w(LOG_TAG, "No secondary user. Skipping "
82                    + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser");
83            return;
84        }
85        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
86    }
87
88    public void testSetAndGetGlobalViaProviderApi() throws Exception {
89        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
90    }
91
92    public void testSetAndGetSecureViaProviderApi() throws Exception {
93        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
94    }
95
96    public void testSetAndGetSystemViaProviderApi() throws Exception {
97        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
98    }
99
100    public void testSelectAllGlobalViaProviderApi() throws Exception {
101        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
102                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
103        try {
104            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
105                    FAKE_SETTING_NAME);
106        } finally {
107            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
108        }
109    }
110
111    public void testSelectAllSecureViaProviderApi() throws Exception {
112        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
113                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
114        try {
115            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
116                    FAKE_SETTING_NAME);
117        } finally {
118            deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
119        }
120    }
121
122    public void testSelectAllSystemViaProviderApi() throws Exception {
123        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
124                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
125        try {
126            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
127                    FAKE_SETTING_NAME);
128        } finally {
129            deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
130        }
131    }
132
133    public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
134        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
135    }
136
137    public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
138        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
139    }
140
141    public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
142        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
143    }
144
145    public void testBulkInsertGlobalViaProviderApi() throws Exception {
146        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
147    }
148
149    public void testBulkInsertSystemViaProviderApi() throws Exception {
150        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
151    }
152
153    public void testBulkInsertSecureViaProviderApi() throws Exception {
154        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
155    }
156
157    public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
158        int insertedCount = 0;
159        try {
160            for (; insertedCount < 1200; insertedCount++) {
161                Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
162                insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
163                        String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
164            }
165            fail("Adding app specific settings must be bound.");
166        } catch (Exception e) {
167            for (; insertedCount >= 0; insertedCount--) {
168                Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
169                deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
170                        String.valueOf(insertedCount));
171            }
172        }
173    }
174
175    public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
176        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
177    }
178
179    public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
180        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
181    }
182
183    public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
184        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
185    }
186
187    public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
188        // Make sure we have a clean slate.
189        deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
190
191        try {
192            // Insert the setting.
193            final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
194                    FAKE_SETTING_VALUE, false);
195            Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM),
196                    FAKE_SETTING_NAME);
197            assertEquals("Did not get expected Uri.", expectUri, uri);
198
199            // Make sure the first setting is there.
200            String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
201                    false, true);
202            assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
203        } finally {
204            // Clean up.
205            deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
206        }
207    }
208
209    private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
210        // Make sure we have a clean slate.
211        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
212
213        try {
214            // Insert the setting.
215            final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
216                    FAKE_SETTING_VALUE, false);
217            Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
218            assertEquals("Did not get expected Uri.", expectUri, uri);
219
220            // Make sure the first setting is there.
221            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false);
222            assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
223        } finally {
224            // Clean up.
225            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
226        }
227    }
228
229    private void toTestBulkInsertViaProviderApiForType(int type) {
230        // Make sure we have a clean slate.
231        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
232        deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
233
234        try {
235            Uri uri = getBaseUriForType(type);
236            ContentValues[] allValues = new ContentValues[2];
237
238            // Insert the first setting.
239            ContentValues firstValues = new ContentValues();
240            firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
241            firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
242            allValues[0] = firstValues;
243
244            // Insert the first setting.
245            ContentValues secondValues = new ContentValues();
246            secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
247            secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
248            allValues[1] = secondValues;
249
250            // Verify insertion count.
251            final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
252            assertSame("Couldn't insert both values", 2, insertCount);
253
254            // Make sure the first setting is there.
255            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
256            assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
257
258            // Make sure the second setting is there.
259            String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
260            assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
261        } finally {
262            // Clean up.
263            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
264            deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
265        }
266    }
267
268    private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
269        // Make sure it is not there.
270        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
271
272        // Now selection should return nothing.
273        String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
274        assertNull("Setting should not be present.", value);
275
276        // Insert the setting.
277        Uri uri = insertStringViaProviderApi(type,
278                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
279        Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
280        assertEquals("Did not get expected Uri.", expectUri, uri);
281
282        // Now selection should return the setting.
283        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
284        assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
285
286        // Update the setting.
287        final int changeCount = updateStringViaProviderApiSetting(type,
288                FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
289        assertEquals("Did not get expected change count.", 1, changeCount);
290
291        // Now selection should return the new setting.
292        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
293        assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
294
295        // Delete the setting.
296        final int deletedCount = deleteStringViaProviderApi(type,
297                FAKE_SETTING_NAME);
298        assertEquals("Did not get expected deleted count", 1, deletedCount);
299
300        // Now selection should return nothing.
301        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
302        assertNull("Setting should not be present.", value);
303    }
304
305    private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
306            throws Exception {
307        try {
308            // Change the setting and assert a successful change.
309            setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
310                    FAKE_SETTING_VALUE, userId);
311        } finally {
312            // Remove the setting.
313            setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
314        }
315    }
316
317    private void performSetAndGetSettingTestViaProviderApi(int type)
318            throws Exception {
319        try {
320            // Change the setting and assert a successful change.
321            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
322                    FAKE_SETTING_VALUE, true);
323        } finally {
324            // Remove the setting.
325            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
326                    true);
327        }
328    }
329
330    private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
331            final String name, final String value, final int userId) throws Exception {
332        setSettingAndAssertSuccessfulChange(new Runnable() {
333            @Override
334            public void run() {
335                setStringViaFrontEndApiSetting(type, name, value, userId);
336            }
337        }, type, name, value, userId);
338    }
339
340    private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
341            final String name, final String value, final boolean withTableRowUri)
342            throws Exception {
343        setSettingAndAssertSuccessfulChange(new Runnable() {
344            @Override
345            public void run() {
346                insertStringViaProviderApi(type, name, value, withTableRowUri);
347            }
348        }, type, name, value, UserHandle.USER_OWNER);
349    }
350
351    private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
352            final String name, final String value, final int userId) throws Exception {
353        ContentResolver contentResolver = getContext().getContentResolver();
354
355        final Uri settingUri = getBaseUriForType(type);
356
357        final AtomicBoolean success = new AtomicBoolean();
358
359        ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
360            public void onChange(boolean selfChange, Uri changeUri, int changeId) {
361                Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
362                assertEquals("Wrong change Uri", changeUri, settingUri);
363                assertEquals("Wrong user id", userId, changeId);
364                String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
365                assertEquals("Wrong setting value", value, changeValue);
366
367                success.set(true);
368
369                synchronized (mLock) {
370                    mLock.notifyAll();
371                }
372            }
373        };
374
375        contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
376
377        try {
378            setCommand.run();
379
380            final long startTimeMillis = SystemClock.uptimeMillis();
381            synchronized (mLock) {
382                if (success.get()) {
383                    return;
384                }
385                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
386                if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
387                    fail("Could not change setting for "
388                            + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
389                }
390                final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
391                        - elapsedTimeMillis;
392                try {
393                    mLock.wait(remainingTimeMillis);
394                } catch (InterruptedException ie) {
395                    /* ignore */
396                }
397            }
398        } finally {
399            contentResolver.unregisterContentObserver(contentObserver);
400        }
401    }
402
403    private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
404            String name) {
405        Uri uri = getBaseUriForType(type);
406
407        Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
408                null, null, null);
409
410        if (cursor == null || !cursor.moveToFirst()) {
411            fail("Nothing selected");
412        }
413
414        try {
415            final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
416
417            while (cursor.moveToNext()) {
418                String currentName = cursor.getString(nameColumnIdx);
419                if (name.equals(currentName)) {
420                    return;
421                }
422            }
423
424            fail("Not found setting: " + name);
425        } finally {
426            cursor.close();
427        }
428    }
429}
430