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
17package com.android.server.backup;
18
19import static com.google.common.truth.Truth.assertThat;
20
21import android.content.ContentResolver;
22import android.content.Context;
23import android.os.Handler;
24import android.platform.test.annotations.Presubmit;
25import android.provider.Settings;
26import android.util.KeyValueSettingObserver;
27import com.android.server.testing.FrameworkRobolectricTestRunner;
28import com.android.server.testing.SystemLoaderClasses;
29import com.android.server.testing.SystemLoaderPackages;
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
33import org.junit.runner.RunWith;
34import org.robolectric.RuntimeEnvironment;
35import org.robolectric.annotation.Config;
36
37@RunWith(FrameworkRobolectricTestRunner.class)
38@Config(manifest = Config.NONE, sdk = 26)
39@SystemLoaderPackages({"com.android.server.backup"})
40@SystemLoaderClasses({KeyValueSettingObserver.class})
41@Presubmit
42public class BackupManagerConstantsTest {
43    private static final String PACKAGE_NAME = "some.package.name";
44    private static final String ANOTHER_PACKAGE_NAME = "another.package.name";
45
46    private ContentResolver mContentResolver;
47    private BackupManagerConstants mConstants;
48
49    @Before
50    public void setUp() {
51        final Context context = RuntimeEnvironment.application.getApplicationContext();
52
53        mContentResolver = context.getContentResolver();
54        mConstants = new BackupManagerConstants(new Handler(), mContentResolver);
55        mConstants.start();
56    }
57
58    @After
59    public void tearDown() {
60        mConstants.stop();
61    }
62
63    @Test
64    public void testGetConstants_afterConstructorWithStart_returnsDefaultValues() {
65        long keyValueBackupIntervalMilliseconds =
66                mConstants.getKeyValueBackupIntervalMilliseconds();
67        long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
68        boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging();
69        int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
70        long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
71        boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging();
72        int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType();
73        String[] backupFinishedNotificationReceivers =
74                mConstants.getBackupFinishedNotificationReceivers();
75
76        assertThat(keyValueBackupIntervalMilliseconds)
77                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
78        assertThat(keyValueBackupFuzzMilliseconds)
79                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
80        assertThat(keyValueBackupRequireCharging)
81                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
82        assertThat(keyValueBackupRequiredNetworkType)
83                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
84        assertThat(fullBackupIntervalMilliseconds)
85                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
86        assertThat(fullBackupRequireCharging)
87                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
88        assertThat(fullBackupRequiredNetworkType)
89                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
90        assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]);
91    }
92
93    /**
94     * Tests that if there is a setting change when we are not currently observing the setting, that
95     * once we start observing again, we receive the most up-to-date value.
96     */
97    @Test
98    public void testGetConstant_withSettingChangeBeforeStart_updatesValues() {
99        mConstants.stop();
100        long testInterval =
101                BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2;
102        final String setting =
103                BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS + "=" + testInterval;
104        putStringAndNotify(setting);
105
106        mConstants.start();
107
108        long keyValueBackupIntervalMilliseconds =
109                mConstants.getKeyValueBackupIntervalMilliseconds();
110        assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testInterval);
111    }
112
113    @Test
114    public void testGetConstants_whenSettingIsNull_returnsDefaultValues() {
115        putStringAndNotify(null);
116
117        long keyValueBackupIntervalMilliseconds =
118                mConstants.getKeyValueBackupIntervalMilliseconds();
119        long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
120        boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging();
121        int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
122        long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
123        boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging();
124        int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType();
125        String[] backupFinishedNotificationReceivers =
126                mConstants.getBackupFinishedNotificationReceivers();
127
128        assertThat(keyValueBackupIntervalMilliseconds)
129                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
130        assertThat(keyValueBackupFuzzMilliseconds)
131                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
132        assertThat(keyValueBackupRequireCharging)
133                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
134        assertThat(keyValueBackupRequiredNetworkType)
135                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
136        assertThat(fullBackupIntervalMilliseconds)
137                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
138        assertThat(fullBackupRequireCharging)
139                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
140        assertThat(fullBackupRequiredNetworkType)
141                .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
142        assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]);
143    }
144
145    /**
146     * Test passing in a malformed setting string. The setting expects
147     * "key1=value,key2=value,key3=value..." but we pass in "key1=,value"
148     */
149    @Test
150    public void testGetConstant_whenSettingIsMalformed_doesNotUpdateParamsOrThrow() {
151        long testFuzz = BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS * 2;
152        final String invalidSettingFormat =
153                BackupManagerConstants.KEY_VALUE_BACKUP_FUZZ_MILLISECONDS + "=," + testFuzz;
154        putStringAndNotify(invalidSettingFormat);
155
156        long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds();
157
158        assertThat(keyValueBackupFuzzMilliseconds)
159                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
160    }
161
162    /**
163     * Test passing in an invalid value type. {@link
164     * BackupManagerConstants#KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE} expects an integer, but we
165     * pass in a boolean.
166     */
167    @Test
168    public void testGetConstant_whenSettingHasInvalidType_doesNotUpdateParamsOrThrow() {
169        boolean testValue = true;
170        final String invalidSettingType =
171                BackupManagerConstants.KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE + "=" + testValue;
172        putStringAndNotify(invalidSettingType);
173
174        int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType();
175
176        assertThat(keyValueBackupRequiredNetworkType)
177                .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
178    }
179
180    @Test
181    public void testGetConstants_afterSettingChange_updatesValues() {
182        long testKVInterval =
183                BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2;
184        long testFullInterval =
185                BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS * 2;
186        final String intervalSetting =
187                BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS
188                        + "="
189                        + testKVInterval
190                        + ","
191                        + BackupManagerConstants.FULL_BACKUP_INTERVAL_MILLISECONDS
192                        + "="
193                        + testFullInterval;
194        putStringAndNotify(intervalSetting);
195
196        long keyValueBackupIntervalMilliseconds =
197                mConstants.getKeyValueBackupIntervalMilliseconds();
198        long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds();
199
200        assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testKVInterval);
201        assertThat(fullBackupIntervalMilliseconds).isEqualTo(testFullInterval);
202    }
203
204    @Test
205    public void testBackupNotificationReceivers_afterSetting_updatesAndParsesCorrectly() {
206        final String receiversSetting =
207                BackupManagerConstants.BACKUP_FINISHED_NOTIFICATION_RECEIVERS
208                        + "="
209                        + PACKAGE_NAME
210                        + ':'
211                        + ANOTHER_PACKAGE_NAME;
212        putStringAndNotify(receiversSetting);
213
214        String[] backupFinishedNotificationReceivers =
215                mConstants.getBackupFinishedNotificationReceivers();
216        assertThat(backupFinishedNotificationReceivers)
217                .isEqualTo(new String[] {PACKAGE_NAME, ANOTHER_PACKAGE_NAME});
218    }
219
220    /**
221     * Robolectric does not notify observers of changes to settings so we have to trigger it here.
222     * Currently, the mock of {@link Settings.Secure#putString(ContentResolver, String, String)}
223     * only stores the value. TODO: Implement properly in ShadowSettings.
224     */
225    private void putStringAndNotify(String value) {
226        Settings.Secure.putString(
227                mContentResolver, Settings.Secure.BACKUP_MANAGER_CONSTANTS, value);
228
229        // We pass null as the observer since notifyChange iterates over all available observers and
230        // we don't have access to the local observer.
231        mContentResolver.notifyChange(
232                Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS),
233                /*observer*/ null);
234    }
235}
236