/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.test.suitebuilder.annotation.SmallTest; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.util.XmlUtilTest; import org.junit.Before; import org.junit.Test; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Unit tests for {@link com.android.server.wifi.NetworksListStoreData}. */ @SmallTest public class NetworkListStoreDataTest { private static final String TEST_SSID = "WifiConfigStoreDataSSID_"; private static final String TEST_CONNECT_CHOICE = "XmlUtilConnectChoice"; private static final long TEST_CONNECT_CHOICE_TIMESTAMP = 0x4566; private static final String SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT = "\n" + "\n" + "%s\n" + "%s\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "01\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "NETWORK_SELECTION_ENABLED\n" + "NETWORK_SELECTION_ENABLE\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "DHCP\n" + "NONE\n" + "\n" + "\n"; private static final String SINGLE_EAP_NETWORK_DATA_XML_STRING_FORMAT = "\n" + "\n" + "%s\n" + "%s\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "0c\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "NETWORK_SELECTION_ENABLED\n" + "NETWORK_SELECTION_ENABLE\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "DHCP\n" + "NONE\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n"; private NetworkListStoreData mNetworkListStoreData; @Before public void setUp() throws Exception { mNetworkListStoreData = new NetworkListStoreData(); } /** * Helper function for serializing configuration data to a XML block. * * @param shared Flag indicating serializing shared or user configurations * @return byte[] of the XML data * @throws Exception */ private byte[] serializeData(boolean shared) throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); mNetworkListStoreData.serializeData(out, shared); out.flush(); return outputStream.toByteArray(); } /** * Helper function for parsing configuration data from a XML block. * * @param data XML data to parse from * @param shared Flag indicating parsing of shared or user configurations * @return List of WifiConfiguration parsed * @throws Exception */ private List deserializeData(byte[] data, boolean shared) throws Exception { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); mNetworkListStoreData.deserializeData(in, in.getDepth(), shared); if (shared) { return mNetworkListStoreData.getSharedConfigurations(); } else { return mNetworkListStoreData.getUserConfigurations(); } } /** * Helper function for generating a network list for testing purpose. The network list * will contained an open and an EAP network. * * @param shared Flag indicating shared network * @return List of WifiConfiguration */ private List getTestNetworksConfig(boolean shared) { WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); openNetwork.shared = shared; openNetwork.setIpConfiguration( WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy()); WifiConfiguration eapNetwork = WifiConfigurationTestUtil.createEapNetwork(); eapNetwork.shared = shared; eapNetwork.setIpConfiguration( WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy()); List networkList = new ArrayList<>(); networkList.add(openNetwork); networkList.add(eapNetwork); return networkList; } /** * Helper function for generating XML block containing two networks, an open and an EAP * network. * * @param openNetwork The WifiConfiguration for an open network * @param eapNetwork The WifiConfiguration for an EAP network * @return byte[] of the XML data */ private byte[] getTestNetworksXmlBytes(WifiConfiguration openNetwork, WifiConfiguration eapNetwork) { String openNetworkXml = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT, openNetwork.configKey().replaceAll("\"", """), openNetwork.SSID.replaceAll("\"", """), openNetwork.shared, openNetwork.creatorUid); String eapNetworkXml = String.format(SINGLE_EAP_NETWORK_DATA_XML_STRING_FORMAT, eapNetwork.configKey().replaceAll("\"", """), eapNetwork.SSID.replaceAll("\"", """), eapNetwork.shared, eapNetwork.creatorUid); return (openNetworkXml + eapNetworkXml).getBytes(StandardCharsets.UTF_8); } /** * Verify that serializing the store data without any configuration doesn't cause any crash * and no data should be serialized. * * @throws Exception */ @Test public void serializeEmptyConfigs() throws Exception { assertEquals(0, serializeData(true /* shared */).length); assertEquals(0, serializeData(false /* shared */).length); } /** * Verify that parsing an empty data doesn't cause any crash and no configuration should * be parsed. * * @throws Exception */ @Test public void deserializeEmptyData() throws Exception { assertTrue(deserializeData(new byte[0], true /* shared */).isEmpty()); assertTrue(deserializeData(new byte[0], false /* shared */).isEmpty()); } /** * Verify that NetworkListStoreData does support share data. * * @throws Exception */ @Test public void supportShareData() throws Exception { assertTrue(mNetworkListStoreData.supportShareData()); } /** * Verify that the shared configurations (containing an open and an EAP network) are serialized * correctly, matching the expected XML string. * * @throws Exception */ @Test public void serializeSharedConfigurations() throws Exception { List networkList = getTestNetworksConfig(true /* shared */); mNetworkListStoreData.setSharedConfigurations(networkList); byte[] expectedData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); assertTrue(Arrays.equals(expectedData, serializeData(true /* shared */))); } /** * Verify that the shared configurations are parsed correctly from a XML string containing * test networks (an open and an EAP network). * @throws Exception */ @Test public void deserializeSharedConfigurations() throws Exception { List networkList = getTestNetworksConfig(true /* shared */); byte[] xmlData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( networkList, deserializeData(xmlData, true /* shared */)); } /** * Verify that the user configurations (containing an open and an EAP network) are serialized * correctly, matching the expected XML string. * * @throws Exception */ @Test public void serializeUserConfigurations() throws Exception { List networkList = getTestNetworksConfig(false /* shared */); mNetworkListStoreData.setUserConfigurations(networkList); byte[] expectedData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); assertTrue(Arrays.equals(expectedData, serializeData(false /* shared */))); } /** * Verify that the user configurations are parsed correctly from a XML string containing * test networks (an open and an EAP network). * @throws Exception */ @Test public void deserializeUserConfigurations() throws Exception { List networkList = getTestNetworksConfig(false /* shared */); byte[] xmlData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( networkList, deserializeData(xmlData, false /* shared */)); } /** * Verify that a XmlPullParserException will be thrown when parsing a block * containing an unknown tag. * * @throws Exception */ @Test(expected = XmlPullParserException.class) public void parseNetworkWithUnknownTag() throws Exception { String configFormat = "\n" + "\n" + "%s\n" + "%s\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "01\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "NETWORK_SELECTION_ENABLED\n" + "NETWORK_SELECTION_ENABLE\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "DHCP\n" + "NONE\n" + "\n" + "" // Unknown tag. + "\n" + "" + "\n"; WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); byte[] xmlData = String.format(configFormat, openNetwork.configKey().replaceAll("\"", """), openNetwork.SSID.replaceAll("\"", """), openNetwork.shared, openNetwork.creatorUid).getBytes(StandardCharsets.UTF_8); deserializeData(xmlData, true); } /** * Verify that a XmlPullParseException will be thrown when parsing a network configuration * containing a mismatched config key. * * @throws Exception */ @Test(expected = XmlPullParserException.class) public void parseNetworkWithMismatchConfigKey() throws Exception { WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT, "InvalidConfigKey", openNetwork.SSID.replaceAll("\"", """), openNetwork.shared, openNetwork.creatorUid).getBytes(StandardCharsets.UTF_8); deserializeData(xmlData, true); } /** * Tests that an invalid data in one of the WifiConfiguration object parsing would be skipped * gracefully. The other networks in the XML should still be parsed out correctly. */ @Test public void parseNetworkListWithOneNetworkIllegalArgException() throws Exception { WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); WifiConfiguration eapNetwork = WifiConfigurationTestUtil.createEapNetwork(); String xmlString = new String(getTestNetworksXmlBytes(openNetwork, eapNetwork)); // Manipulate the XML data to set the EAP method to None, this should raise an Illegal // argument exception in WifiEnterpriseConfig.setEapMethod(). xmlString = xmlString.replaceAll( String.format(XmlUtilTest.XML_STRING_EAP_METHOD_REPLACE_FORMAT, eapNetwork.enterpriseConfig.getEapMethod()), String.format(XmlUtilTest.XML_STRING_EAP_METHOD_REPLACE_FORMAT, WifiEnterpriseConfig.Eap.NONE)); List retrievedNetworkList = deserializeData(xmlString.getBytes(StandardCharsets.UTF_8), true /* shared */); // Retrieved network should not contain the eap network. assertEquals(1, retrievedNetworkList.size()); for (WifiConfiguration network : retrievedNetworkList) { assertNotEquals(eapNetwork.SSID, network.SSID); } } }