1 /* 2 * Copyright (C) 2018 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.compatibility.common.tradefed.targetprep; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.fail; 21 import static org.mockito.Mockito.when; 22 23 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 24 import com.android.tradefed.build.BuildInfo; 25 import com.android.tradefed.build.IBuildInfo; 26 import com.android.tradefed.config.OptionSetter; 27 import com.android.tradefed.device.ITestDevice; 28 import com.android.tradefed.util.FileUtil; 29 30 import org.junit.After; 31 import org.junit.Before; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 import org.mockito.Mockito; 36 37 import java.io.File; 38 import java.io.FileOutputStream; 39 import java.io.IOException; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Set; 47 48 49 /** 50 * Unit test for {@link BusinessLogicPreparer}. 51 */ 52 53 @RunWith(JUnit4.class) 54 public class BusinessLogicPreparerTest { 55 private ITestDevice mMockDevice; 56 private IBuildInfo mMockBuildInfo; 57 private BusinessLogicPreparer mPreparer; 58 private Set<String> mPackages; 59 private File mTmpDir; 60 61 private static final String MEMORY_DEVICE_INFO_JSON = 62 "{\n" + 63 " \"low_ram_device\": false,\n" + 64 " \"memory_class\": 192,\n" + 65 " \"large_memory_class\": 512,\n" + 66 " \"total_memory\": 1902936064\n" + 67 "}\n"; 68 private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer"; 69 private static final String CONFIG_VERSION = "DYNAMIC_CONFIG_FILE:"; 70 private static final String CONFIG_FILE_CONTENT = 71 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 72 "<dynamicConfig>\n" + 73 " <entry key=\"remote_config_required\">\n" + 74 " <value>false</value>\n" + 75 " </entry>\n" + 76 " <entry key=\"business_logic_device_features\">\n" + 77 " <value>android.hardware.type.automotive</value>\n" + 78 " <value>android.hardware.type.television</value>\n" + 79 " <value>android.hardware.type.watch</value>\n" + 80 " <value>android.hardware.type.embedded</value>\n" + 81 " <value>android.hardware.type.pc</value>\n" + 82 " <value>android.software.leanback</value>\n" + 83 " </entry>\n" + 84 " <entry key=\"business_logic_device_properties\">\n" + 85 " <value>ro.product.brand</value>\n" + 86 " <value>ro.product.first_api_level</value>\n" + 87 " <value>ro.product.manufacturer</value>\n" + 88 " <value>ro.product.model</value>\n" + 89 " <value>ro.product.name</value>\n" + 90 " </entry>\n" + 91 " <entry key=\"business_logic_device_packages\">\n" + 92 " <value>com.google.android.gms</value>\n" + 93 " <value>com.android.vending</value>\n" + 94 " </entry>\n" + 95 " <entry key=\"business_logic_extended_device_info\">\n" + 96 " <value>MemoryDeviceInfo:total_memory</value>\n" + 97 " <value>MemoryDeviceInfo:low_ram_device</value>\n" + 98 " </entry>\n" + 99 "</dynamicConfig>\n"; 100 private static final String LIST_FEATURE_QUERY = "pm list features"; 101 private static final String FEATURE_WATCH = "android.hardware.type.watch"; 102 private static final String FEATURE_LEANBACK = "android.software.leanback"; 103 private static final String FEATURES = 104 "feature:" + FEATURE_WATCH + "\n" + 105 "feature:android.hardware.audio.low_latency\n" + 106 "feature:android.hardware.camera\n" + 107 "feature:android.hardware.microphone\n" + 108 "feature:android.hardware.nfc\n" + 109 "feature:android.hardware.telephony\n" + 110 "feature:android.hardware.wifi\n" + 111 "feature:" + FEATURE_LEANBACK + "\n"; 112 private static final String GOOGLE_SETTINGS_QUERY = 113 "content query --uri content://com.google.settings/partner"; 114 private static final String PARTNER_CONTENT = 115 "Row: 0 _id=35, name=use_location_for_services, value=1\n" + 116 "Row: 1 _id=57, name=network_location_opt_in, value=1\n" + 117 "Row: 2 _id=162, name=data_store_version, value=3\n" + 118 "Row: 3 _id=163, name=client_id, value=android-google\n" + 119 "Row: 4 _id=164, name=search_client_id, value=ms-android-google\n"; 120 private static final String RO_BRAND = "ro.product.brand"; 121 private static final String RO_FIRST_API_LEVEL = "ro.product.first_api_level"; 122 private static final String RO_MANIFACTURER = "ro.product.manufacturer"; 123 private static final String RO_MODEL = "ro.product.model"; 124 private static final String RO_NAME = "ro.product.name"; 125 private static final long MEMORY_SIZE = 1902936064; 126 127 private String serviceUrl = "https://androidpartner.googleapis.com/v1/dynamicconfig/" + 128 "suites/{suite-name}/modules/{module}/version/{version}?key=123"; 129 130 @Before setUp()131 public void setUp() throws Exception { 132 mTmpDir = FileUtil.createTempDir("business-logic-unit-tests"); 133 mMockDevice = Mockito.mock(ITestDevice.class); 134 mMockBuildInfo = new BuildInfo(); 135 mPreparer = new BusinessLogicPreparer() { 136 @Override 137 String getSuiteName() { 138 return "cts"; 139 } 140 }; 141 142 OptionSetter setter = new OptionSetter(mPreparer); 143 setter.setOptionValue("business-logic-url", serviceUrl); 144 setter.setOptionValue("business-logic-api-key", "fakeApiKey"); 145 setter.setOptionValue("version", "fakeVersion"); 146 } 147 148 @After tearDown()149 public void tearDown() throws Exception { 150 FileUtil.recursiveDelete(mTmpDir); 151 } 152 153 @Test testBuildRequestString_success()154 public void testBuildRequestString_success() throws Exception { 155 Map<String, String> attributes = new HashMap<>(); 156 // Create a memory device info JSON file for test. 157 File jsonPath = createTestDeviceInfoJSONFile("MemoryDeviceInfo", MEMORY_DEVICE_INFO_JSON); 158 mMockBuildInfo.setFile(DeviceInfoCollector.DEVICE_INFO_DIR, jsonPath, "v1"); 159 // Setup BuildInfo attributes. 160 mMockBuildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, "v1"); 161 testBuildRequestString(16, attributes); 162 } 163 164 @Test testBuildRequestString_deviceDirDoesntExists()165 public void testBuildRequestString_deviceDirDoesntExists() throws Exception { 166 Map<String, String> attributes = new HashMap<>(); 167 // Setup BuildInfo attributes. 168 attributes.put(CompatibilityBuildHelper.SUITE_VERSION, "v1"); 169 testBuildRequestString(14, attributes); 170 } 171 172 @Test testBuildRequestString_noDeviceInfoJSONFileExists()173 public void testBuildRequestString_noDeviceInfoJSONFileExists() throws Exception { 174 Map<String, String> attributes = new HashMap<>(); 175 // Create a memory device info JSON file for test. 176 File jsonPath = createTestDeviceInfoTextFile("MemoryDeviceInfo"); 177 mMockBuildInfo.setFile(DeviceInfoCollector.DEVICE_INFO_DIR, jsonPath, "v1"); 178 // Setup BuildInfo attributes. 179 mMockBuildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, "v1"); 180 testBuildRequestString(14, attributes); 181 } 182 testBuildRequestString(int expectedParams, Map<String, String> attributes)183 private void testBuildRequestString(int expectedParams, Map<String, String> attributes) throws Exception { 184 for (String key: attributes.keySet()) { 185 mMockBuildInfo.addBuildAttribute(key, attributes.get(key)); 186 } 187 when(mMockDevice.getProperty(MANUFACTURER_PROPERTY)).thenReturn("MANUFACTURER_NAME"); 188 // In getBusinessLogicFeatures 189 File configFile = createFileFromStr(CONFIG_FILE_CONTENT); 190 // BusinessLogicPreparer.getSuiteName() calls TestSuiteInfo.getName() 191 // That returns "tests" on local machine. 192 // That returns "gts" in presumit. 193 mMockBuildInfo.setFile(CONFIG_VERSION + "tests", configFile, CONFIG_VERSION + "tests"); 194 mMockBuildInfo.setFile(CONFIG_VERSION + "gts", configFile, CONFIG_VERSION + "gts"); 195 mMockBuildInfo.setFile(CONFIG_VERSION + "cts", configFile, CONFIG_VERSION + "cts"); 196 mMockBuildInfo.setFile(CONFIG_VERSION + "ats", configFile, CONFIG_VERSION + "ats"); 197 when(mMockDevice.executeShellCommand(LIST_FEATURE_QUERY)).thenReturn(FEATURES); 198 // In getBusinessLogicProperties. 199 when(mMockDevice.executeShellCommand(GOOGLE_SETTINGS_QUERY)).thenReturn(PARTNER_CONTENT); 200 when(mMockDevice.getProperty(RO_BRAND)).thenReturn("BRAND_NAME"); 201 when(mMockDevice.getProperty(RO_FIRST_API_LEVEL)).thenReturn("26"); 202 when(mMockDevice.getProperty(RO_MANIFACTURER)).thenReturn("MANUFACTURER_NAME"); 203 when(mMockDevice.getProperty(RO_MODEL)).thenReturn("fake_model"); 204 when(mMockDevice.getProperty(RO_NAME)).thenReturn("fake_name"); 205 // Extra info 206 List<String> pkgNameList = Arrays.asList("com.android.vending", "com.google.android.gms", 207 "com.google.android.youtube", "com.google.android.apps.photos"); 208 mPackages = new HashSet<>(pkgNameList); 209 when(mMockDevice.getInstalledPackageNames()).thenReturn(mPackages); 210 when(mMockDevice.getTotalMemory()).thenReturn(MEMORY_SIZE); 211 212 ArrayList<String> expectFeatures = new ArrayList<String>( 213 Arrays.asList(FEATURE_WATCH, FEATURE_LEANBACK)); 214 ArrayList<String> expectProperties = new ArrayList<String>( 215 Arrays.asList("search_client_id", "client_id", RO_BRAND, RO_FIRST_API_LEVEL, 216 RO_MANIFACTURER, RO_MODEL, RO_NAME)); 217 ArrayList<String> expectPropertyValues = new ArrayList<String>( 218 Arrays.asList("ms-android-google", "android-google", "BRAND_NAME", "26", "MANUFACTURER_NAME", 219 "fake_model", "fake_name")); 220 ArrayList<String> expectPackages = new ArrayList<String>(pkgNameList); 221 ArrayList<String> expectDeviceInfos = new ArrayList<String>( 222 Arrays.asList("MemoryDeviceInfo%3Atotal_memory%3A1902936064", 223 "MemoryDeviceInfo%3Alow_ram_device%3Afalse")); 224 225 String[] params = mPreparer.buildRequestParams(mMockDevice, mMockBuildInfo).split("&"); 226 assertEquals(expectedParams, params.length); 227 228 for (String param: params){ 229 String keyVal[] = param.split("="); 230 231 if(keyVal[0].startsWith("features")) { 232 if(expectFeatures.contains(keyVal[1])) { 233 expectFeatures.remove(keyVal[1]); 234 } else { 235 fail("Found unknown Feature string"); 236 } 237 } 238 if (keyVal[0].startsWith("properties")) { 239 String property[] = keyVal[1].split("%3A"); 240 if(expectProperties.contains(property[0])) { 241 assertEquals(expectPropertyValues.get(expectProperties.indexOf(property[0])), 242 property[1]); 243 expectProperties.remove(property[0]); 244 expectPropertyValues.remove(property[1]); 245 } else { 246 fail("Found unknown Property string"); 247 } 248 } 249 if (keyVal[0].startsWith("package")) { 250 if(expectPackages.contains(keyVal[1])) { 251 expectPackages.remove(keyVal[1]); 252 } else { 253 fail("Found unknown Package string"); 254 } 255 } 256 if (keyVal[0].startsWith("device_info")) { 257 if(expectDeviceInfos.contains(keyVal[1])) { 258 expectDeviceInfos.remove(keyVal[1]); 259 } else { 260 fail("Found unknown Feature string"); 261 } 262 } 263 } 264 assertEquals(expectFeatures.size(), 0); 265 assertEquals(expectProperties.size(), 0); 266 assertEquals(expectPackages.size(), 2); 267 } 268 createTestDeviceInfoJSONFile(String DeviceInfoClassName, String jsonStr)269 private File createTestDeviceInfoJSONFile(String DeviceInfoClassName, String jsonStr) 270 throws IOException { 271 File file = new File(mTmpDir, DeviceInfoClassName + ".deviceinfo.json"); 272 FileOutputStream stream = new FileOutputStream(file); 273 stream.write(jsonStr.getBytes()); 274 stream.flush(); 275 stream.close(); 276 return mTmpDir; 277 } 278 createTestDeviceInfoTextFile(String DeviceInfoClassName)279 private File createTestDeviceInfoTextFile(String DeviceInfoClassName) 280 throws IOException { 281 new File(mTmpDir, DeviceInfoClassName + ".deviceinfo.text"); 282 return mTmpDir; 283 } 284 createFileFromStr(String configStr)285 private File createFileFromStr(String configStr) throws IOException { 286 File file = File.createTempFile("test", "dynamic"); 287 FileOutputStream stream = new FileOutputStream(file); 288 stream.write(configStr.getBytes()); 289 stream.flush(); 290 stream.close(); 291 return file; 292 } 293 } 294