1 /* 2 * Copyright (C) 2019 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.server.am; 18 19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; 21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 23 24 import android.content.ContentResolver; 25 import android.os.SystemProperties; 26 import android.provider.Settings; 27 import android.text.TextUtils; 28 29 import com.android.dx.mockito.inline.extended.ExtendedMockito; 30 31 import org.junit.After; 32 import org.junit.Assert; 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.mockito.Answers; 36 import org.mockito.Mock; 37 import org.mockito.MockitoSession; 38 import org.mockito.quality.Strictness; 39 import org.mockito.stubbing.Answer; 40 41 import java.util.Arrays; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 46 /** 47 * Test SettingsToPropertiesMapper. 48 */ 49 public class SettingsToPropertiesMapperTest { 50 private static final String NAME_VALID_CHARACTERS_REGEX = "^[\\w\\-@:]*$"; 51 private static final String[] TEST_MAPPING = new String[] { 52 Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS 53 }; 54 55 private MockitoSession mSession; 56 57 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 58 private ContentResolver mMockContentResolver; 59 60 private SettingsToPropertiesMapper mTestMapper; 61 62 private HashMap<String, String> mSystemSettingsMap; 63 private HashMap<String, String> mGlobalSettingsMap; 64 65 @Before setUp()66 public void setUp() throws Exception { 67 mSession = 68 ExtendedMockito.mockitoSession().initMocks( 69 this) 70 .strictness(Strictness.LENIENT) 71 .spyStatic(SystemProperties.class) 72 .spyStatic(Settings.Global.class) 73 .spyStatic(SettingsToPropertiesMapper.class) 74 .startMocking(); 75 mSystemSettingsMap = new HashMap<>(); 76 mGlobalSettingsMap = new HashMap<>(); 77 78 // Mock SystemProperties setter and various getters 79 doAnswer((Answer<Void>) invocationOnMock -> { 80 String key = invocationOnMock.getArgument(0); 81 String value = invocationOnMock.getArgument(1); 82 83 mSystemSettingsMap.put(key, value); 84 return null; 85 } 86 ).when(() -> SystemProperties.set(anyString(), anyString())); 87 88 doAnswer((Answer<String>) invocationOnMock -> { 89 String key = invocationOnMock.getArgument(0); 90 91 String storedValue = mSystemSettingsMap.get(key); 92 return storedValue == null ? "" : storedValue; 93 } 94 ).when(() -> SystemProperties.get(anyString())); 95 96 // Mock Settings.Global methods 97 doAnswer((Answer<String>) invocationOnMock -> { 98 String key = invocationOnMock.getArgument(1); 99 100 return mGlobalSettingsMap.get(key); 101 } 102 ).when(() -> Settings.Global.getString(any(), anyString())); 103 104 mTestMapper = new SettingsToPropertiesMapper( 105 mMockContentResolver, TEST_MAPPING, new String[] {}); 106 } 107 108 @After tearDown()109 public void tearDown() throws Exception { 110 mSession.finishMocking(); 111 } 112 113 @Test validateRegisteredGlobalSettings()114 public void validateRegisteredGlobalSettings() { 115 HashSet<String> hashSet = new HashSet<>(); 116 for (String globalSetting : SettingsToPropertiesMapper.sGlobalSettings) { 117 if (hashSet.contains(globalSetting)) { 118 Assert.fail("globalSetting " 119 + globalSetting 120 + " is registered more than once in " 121 + "SettingsToPropertiesMapper.sGlobalSettings."); 122 } 123 hashSet.add(globalSetting); 124 if (TextUtils.isEmpty(globalSetting)) { 125 Assert.fail("empty globalSetting registered."); 126 } 127 if (!globalSetting.matches(NAME_VALID_CHARACTERS_REGEX)) { 128 Assert.fail(globalSetting + " contains invalid characters. " 129 + "Only alphanumeric characters, '-', '@', ':' and '_' are valid."); 130 } 131 } 132 } 133 134 @Test validateRegisteredDeviceConfigScopes()135 public void validateRegisteredDeviceConfigScopes() { 136 HashSet<String> hashSet = new HashSet<>(); 137 for (String deviceConfigScope : SettingsToPropertiesMapper.sDeviceConfigScopes) { 138 if (hashSet.contains(deviceConfigScope)) { 139 Assert.fail("deviceConfigScope " 140 + deviceConfigScope 141 + " is registered more than once in " 142 + "SettingsToPropertiesMapper.sDeviceConfigScopes."); 143 } 144 hashSet.add(deviceConfigScope); 145 if (TextUtils.isEmpty(deviceConfigScope)) { 146 Assert.fail("empty deviceConfigScope registered."); 147 } 148 if (!deviceConfigScope.matches(NAME_VALID_CHARACTERS_REGEX)) { 149 Assert.fail(deviceConfigScope + " contains invalid characters. " 150 + "Only alphanumeric characters, '-', '@', ':' and '_' are valid."); 151 } 152 } 153 } 154 155 @Test testUpdatePropertiesFromSettings()156 public void testUpdatePropertiesFromSettings() { 157 mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue"); 158 159 String systemPropertyName = "persist.device_config.global_settings." 160 + "sqlite_compatibility_wal_flags"; 161 162 mTestMapper.updatePropertiesFromSettings(); 163 String propValue = mSystemSettingsMap.get(systemPropertyName); 164 Assert.assertEquals("testValue", propValue); 165 166 mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2"); 167 mTestMapper.updatePropertyFromSetting( 168 Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, 169 systemPropertyName); 170 propValue = mSystemSettingsMap.get(systemPropertyName); 171 Assert.assertEquals("testValue2", propValue); 172 173 mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null); 174 mTestMapper.updatePropertyFromSetting( 175 Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, 176 systemPropertyName); 177 propValue = mSystemSettingsMap.get(systemPropertyName); 178 Assert.assertEquals("", propValue); 179 } 180 181 @Test testMakePropertyName()182 public void testMakePropertyName() { 183 try { 184 Assert.assertEquals("persist.device_config.test_category.test_flag", 185 SettingsToPropertiesMapper.makePropertyName("test_category", "test_flag")); 186 } catch (Exception e) { 187 Assert.fail("Unexpected exception: " + e.getMessage()); 188 } 189 190 try { 191 Assert.assertEquals(null, 192 SettingsToPropertiesMapper.makePropertyName("test_category!!!", "test_flag")); 193 } catch (Exception e) { 194 Assert.fail("Unexpected exception: " + e.getMessage()); 195 } 196 197 try { 198 Assert.assertEquals(null, 199 SettingsToPropertiesMapper.makePropertyName("test_category", ".test_flag")); 200 } catch (Exception e) { 201 Assert.fail("Unexpected exception: " + e.getMessage()); 202 } 203 } 204 205 @Test testUpdatePropertiesFromSettings_PropertyAndSettingNotPresent()206 public void testUpdatePropertiesFromSettings_PropertyAndSettingNotPresent() { 207 // Test that empty property will not be set if setting is not set 208 mTestMapper.updatePropertiesFromSettings(); 209 String propValue = mSystemSettingsMap.get("TestProperty"); 210 Assert.assertNull("Property should not be set if setting is null", propValue); 211 } 212 213 @Test testIsNativeFlagsResetPerformed()214 public void testIsNativeFlagsResetPerformed() { 215 mSystemSettingsMap.put("device_config.reset_performed", "true"); 216 Assert.assertTrue(mTestMapper.isNativeFlagsResetPerformed()); 217 218 mSystemSettingsMap.put("device_config.reset_performed", "false"); 219 Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed()); 220 221 mSystemSettingsMap.put("device_config.reset_performed", ""); 222 Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed()); 223 } 224 225 @Test testGetResetNativeCategories()226 public void testGetResetNativeCategories() { 227 doReturn("persist.device_config.category1.flag;" 228 + "persist.device_config.category2.flag;persist.device_config.category3.flag;" 229 + "persist.device_config.category3.flag2") 230 .when(() -> SettingsToPropertiesMapper.getResetFlagsFileContent()); 231 232 mSystemSettingsMap.put("device_config.reset_performed", ""); 233 Assert.assertEquals(mTestMapper.getResetNativeCategories().length, 0); 234 235 mSystemSettingsMap.put("device_config.reset_performed", "true"); 236 List<String> categories = Arrays.asList(mTestMapper.getResetNativeCategories()); 237 Assert.assertEquals(3, categories.size()); 238 Assert.assertTrue(categories.contains("category1")); 239 Assert.assertTrue(categories.contains("category2")); 240 Assert.assertTrue(categories.contains("category3")); 241 } 242 } 243