1ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liupackage com.android.carrierconfig; 2ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 3ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.content.Context; 4ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.content.res.AssetManager; 5eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport android.content.res.Resources; 6ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.os.PersistableBundle; 7ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.service.carrier.CarrierIdentifier; 8eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport android.telephony.CarrierConfigManager; 9ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.test.InstrumentationTestCase; 10ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport android.util.Log; 11ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 12ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport java.io.IOException; 13ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport java.io.InputStream; 14eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport java.lang.reflect.Field; 15eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport java.lang.reflect.Modifier; 16eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport java.util.HashSet; 17eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseriimport java.util.Set; 18ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 19ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport junit.framework.AssertionFailedError; 20ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 21ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport org.xmlpull.v1.XmlPullParser; 22ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport org.xmlpull.v1.XmlPullParserException; 23ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liuimport org.xmlpull.v1.XmlPullParserFactory; 24ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 25ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liupublic class CarrierConfigTest extends InstrumentationTestCase { 26ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 27ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu /** 28ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * Iterate over all XML files in assets/ and ensure they parse without error. 29ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu */ 30ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu public void testAllFilesParse() { 31ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu forEachConfigXml(new ParserChecker() { 32ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu public void check(XmlPullParser parser) throws XmlPullParserException, IOException { 33ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu PersistableBundle b = DefaultCarrierConfigService.readConfigFromXml(parser, 34ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu new CarrierIdentifier("001", "001", "Test", "", "", "")); 35ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu assertNotNull("got null bundle", b); 36ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 37ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu }); 38ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 39ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 40ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu /** 41ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * Check that the config bundles in XML files have valid filter attributes. 42ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * This checks the attribute names only. 43ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu */ 44ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu public void testFilterValidAttributes() { 45ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu forEachConfigXml(new ParserChecker() { 46ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu public void check(XmlPullParser parser) throws XmlPullParserException, IOException { 47ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu int event; 48ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) { 49eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri if (event == XmlPullParser.START_TAG 50eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri && "carrier_config".equals(parser.getName())) { 51ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu for (int i = 0; i < parser.getAttributeCount(); ++i) { 52ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu String attribute = parser.getAttributeName(i); 53ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu switch (attribute) { 54ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "mcc": 55ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "mnc": 56ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "gid1": 57ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "gid2": 58ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "spn": 59ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu case "device": 60ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu break; 61ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu default: 62eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri fail("Unknown attribute '" + attribute 63eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri + "' at " + parser.getPositionDescription()); 64ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu break; 65ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 66ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 67ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 68ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 69ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 70ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu }); 71ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 72ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 73ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu /** 74eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri * Tests that the variable names in each XML file match actual keys in CarrierConfigManager. 75eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri */ 76eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri public void testVariableNames() { 77eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri final Set<String> varXmlNames = getCarrierConfigXmlNames(); 78eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // organize them into sets by type or unknown 79eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri forEachConfigXml(new ParserChecker() { 80eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri public void check(XmlPullParser parser) throws XmlPullParserException, IOException { 81eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri int event; 82eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) { 83eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri if (event == XmlPullParser.START_TAG) { 84eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri switch (parser.getName()) { 85eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "int": 86eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "boolean": 87eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "string": 88eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "int-array": 89eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "string-array": 90eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // NOTE: This doesn't check for other valid Bundle values, but it 91eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // is limited to the key types in CarrierConfigManager. 92eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri final String varName = parser.getAttributeValue(null, "name"); 93eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri assertNotNull("No 'name' attribute: " 94eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri + parser.getPositionDescription(), varName); 95eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri assertTrue("Unknown variable: '" + varName 96eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri + "' at " + parser.getPositionDescription(), 97eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri varXmlNames.contains(varName)); 98eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // TODO: Check that the type is correct. 99eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri break; 100eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "carrier_config_list": 101eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri case "carrier_config": 102eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // do nothing 103eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri break; 104eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri default: 105eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri fail("unexpected tag: '" + parser.getName() 106eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri + "' at " + parser.getPositionDescription()); 107eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri break; 108eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 109eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 110eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 111eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 112eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri }); 113eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 114eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri 115eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri /** 116ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * Utility for iterating over each XML document in the assets folder. 117ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * 118ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * This can be used with {@link #forEachConfigXml} to run checks on each XML document. 119ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * {@link #check} should {@link #fail} if the test does not pass. 120ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu */ 121ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu private interface ParserChecker { 122ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu void check(XmlPullParser parser) throws XmlPullParserException, IOException; 123ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 124ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 125ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu /** 126ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu * Utility for iterating over each XML document in the assets folder. 127ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu */ 128ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu private void forEachConfigXml(ParserChecker checker) { 129ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu AssetManager assetMgr = getInstrumentation().getTargetContext().getAssets(); 130ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu try { 131ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu String[] files = assetMgr.list(""); 132ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu assertNotNull("failed to list files", files); 133ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu assertTrue("no files", files.length > 0); 134ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu for (String fileName : files) { 135ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu try { 136ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu if (!fileName.startsWith("carrier_config_")) continue; 137ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 138ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 139ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu XmlPullParser parser = factory.newPullParser(); 140ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu parser.setInput(assetMgr.open(fileName), "utf-8"); 141ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 142ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu checker.check(parser); 143ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu 144ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } catch (Throwable e) { 145ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu throw new AssertionError("Problem in " + fileName + ": " + e.getMessage(), e); 146ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 147ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 148eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // Check vendor.xml too 149eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri try { 150eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri Resources res = getInstrumentation().getTargetContext().getResources(); 151eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri checker.check(res.getXml(R.xml.vendor)); 152eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } catch (Throwable e) { 153eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri throw new AssertionError("Problem in vendor.xml: " + e.getMessage(), e); 154eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 155ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } catch (IOException e) { 156ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu fail(e.toString()); 157ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 158ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu } 159eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri 160eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri /** 161eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri * Get the set of config variable names, as used in XML files. 162eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri */ 163eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri private Set<String> getCarrierConfigXmlNames() { 164eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri // get values of all KEY_ members of CarrierConfigManager 165eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri Field[] fields = CarrierConfigManager.class.getDeclaredFields(); 166eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri HashSet<String> varXmlNames = new HashSet<>(); 167eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri for (Field f : fields) { 168eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri if (!f.getName().startsWith("KEY_")) continue; 169eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri if ((f.getModifiers() & Modifier.STATIC) == 0) { 170eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri fail("non-static key in CarrierConfigManager: " + f.toString()); 171eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 172eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri try { 173eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri String value = (String) f.get(null); 174eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri varXmlNames.add(value); 175eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 176eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri catch (IllegalAccessException e) { 177eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri throw new AssertionError("Failed to get config key: " + e.getMessage(), e); 178eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 179eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 180eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri assertTrue("Found zero keys", varXmlNames.size() > 0); 181eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri return varXmlNames; 182eb8ef01791f3c35e28dcbd53f9352f0f81a6d361Jonathan Basseri } 183ee61e79b8c842f0fa33a48fa0d099435f5b2c617Junda Liu} 184