blob: c3d1481867397df729852dc132db04d1dedf6ba7 [file] [log] [blame]
/*
* Copyright (C) 2016 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.app.test.MockAnswerUtil;
import android.app.test.TestAlarmManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.MacAddress;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiMigration;
import android.net.wifi.util.HexEncoding;
import android.os.Handler;
import android.os.UserHandle;
import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.util.FastPrintWriter;
import com.android.server.wifi.WifiConfigStore.StoreData;
import com.android.server.wifi.WifiConfigStore.StoreFile;
import com.android.server.wifi.util.ArrayUtils;
import com.android.server.wifi.util.EncryptedData;
import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
import com.android.server.wifi.util.XmlUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.stubbing.Answer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
/**
* Unit tests for {@link com.android.server.wifi.WifiConfigStore}.
*/
@SmallTest
public class WifiConfigStoreTest extends WifiBaseTest {
private static final String TEST_USER_DATA = "UserData";
private static final String TEST_SHARE_DATA = "ShareData";
private static final String TEST_CREATOR_NAME = "CreatorName";
private static final MacAddress TEST_RANDOMIZED_MAC =
MacAddress.fromString("da:a1:19:c4:26:fa");
private static final int TEST_SUB_ID = 2;
private static final String TEST_DATA_XML_STRING_FORMAT =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"3\" />\n"
+ "<NetworkList>\n"
+ "<Network>\n"
+ "<WifiConfiguration>\n"
+ "<string name=\"ConfigKey\">%s</string>\n"
+ "<string name=\"SSID\">%s</string>\n"
+ "<null name=\"PreSharedKey\" />\n"
+ "<null name=\"WEPKeys\" />\n"
+ "<int name=\"WEPTxKeyIndex\" value=\"0\" />\n"
+ "<boolean name=\"HiddenSSID\" value=\"false\" />\n"
+ "<boolean name=\"RequirePMF\" value=\"false\" />\n"
+ "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">01</byte-array>\n"
+ "<byte-array name=\"AllowedProtocols\" num=\"1\">03</byte-array>\n"
+ "<byte-array name=\"AllowedAuthAlgos\" num=\"0\"></byte-array>\n"
+ "<byte-array name=\"AllowedGroupCiphers\" num=\"0\"></byte-array>\n"
+ "<byte-array name=\"AllowedPairwiseCiphers\" num=\"0\"></byte-array>\n"
+ "<byte-array name=\"AllowedGroupMgmtCiphers\" num=\"0\"></byte-array>\n"
+ "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n"
+ "<boolean name=\"Shared\" value=\"%s\" />\n"
+ "<boolean name=\"AutoJoinEnabled\" value=\"true\" />\n"
+ "<int name=\"DeletionPriority\" value=\"0\" />\n"
+ "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n"
+ "<SecurityParamsList>\n"
+ "<SecurityParams>\n"
+ "<int name=\"SecurityType\" value=\"0\" />\n"
+ "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n"
+ "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n"
+ "<boolean name=\"IsAddedByAutoUpgrade\" value=\"false\" />\n"
+ "</SecurityParams>\n"
+ "<SecurityParams>\n"
+ "<int name=\"SecurityType\" value=\"6\" />\n"
+ "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n"
+ "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n"
+ "<boolean name=\"IsAddedByAutoUpgrade\" value=\"true\" />\n"
+ "</SecurityParams>\n"
+ "</SecurityParamsList>\n"
+ "<boolean name=\"Trusted\" value=\"true\" />\n"
+ "<boolean name=\"OemPaid\" value=\"false\" />\n"
+ "<boolean name=\"OemPrivate\" value=\"false\" />\n"
+ "<boolean name=\"CarrierMerged\" value=\"false\" />\n"
+ "<null name=\"BSSID\" />\n"
+ "<int name=\"Status\" value=\"2\" />\n"
+ "<null name=\"FQDN\" />\n"
+ "<null name=\"ProviderFriendlyName\" />\n"
+ "<null name=\"LinkedNetworksList\" />\n"
+ "<null name=\"DefaultGwMacAddress\" />\n"
+ "<boolean name=\"ValidatedInternetAccess\" value=\"false\" />\n"
+ "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
+ "<boolean name=\"MeteredHint\" value=\"false\" />\n"
+ "<int name=\"MeteredOverride\" value=\"0\" />\n"
+ "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
+ "<int name=\"CreatorUid\" value=\"%d\" />\n"
+ "<string name=\"CreatorName\">%s</string>\n"
+ "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
+ "<null name=\"LastUpdateName\" />\n"
+ "<int name=\"LastConnectUid\" value=\"0\" />\n"
+ "<boolean name=\"IsLegacyPasspointConfig\" value=\"false\" />\n"
+ "<long-array name=\"RoamingConsortiumOIs\" num=\"0\" />\n"
+ "<string name=\"RandomizedMacAddress\">%s</string>\n"
+ "<int name=\"MacRandomizationSetting\" value=\"3\" />\n"
+ "<int name=\"CarrierId\" value=\"-1\" />\n"
+ "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
+ "<int name=\"SubscriptionId\" value=\"%d\" />\n"
+ "</WifiConfiguration>\n"
+ "<NetworkStatus>\n"
+ "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
+ "<string name=\"DisableReason\">NETWORK_SELECTION_ENABLE</string>\n"
+ "<null name=\"ConnectChoice\" />\n"
+ "<int name=\"ConnectChoiceRssi\" value=\"0\" />\n"
+ "<boolean name=\"HasEverConnected\" value=\"false\" />\n"
+ "<boolean name=\"CaptivePortalNeverDetected\" value=\"true\" />\n"
+ "</NetworkStatus>\n"
+ "<IpConfiguration>\n"
+ "<string name=\"IpAssignment\">DHCP</string>\n"
+ "<string name=\"ProxySettings\">NONE</string>\n"
+ "</IpConfiguration>\n"
+ "</Network>\n"
+ "</NetworkList>\n"
+ "</WifiConfigStoreData>\n";
private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"1\" />\n"
+ "<%s/>n"
+ "</WifiConfigStoreData>\n";
private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"1\" />\n"
+ "<%s/>n"
+ "<%s/>n"
+ "</WifiConfigStoreData>\n";
private static final String TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"2\" />\n"
+ "<Integrity>\n"
+ "<byte-array name=\"EncryptedData\" num=\"48\">%s</byte-array>\n"
+ "<byte-array name=\"IV\" num=\"12\">%s</byte-array>\n"
+ "</Integrity>\n"
+ "<%s />\n"
+ "</WifiConfigStoreData>\n";
private static final String TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"3\" />\n"
+ "<%s />\n"
+ "</WifiConfigStoreData>\n";
// Test mocks
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
private TestAlarmManager mAlarmManager;
private TestLooper mLooper;
@Mock private Clock mClock;
@Mock private WifiMetrics mWifiMetrics;
@Mock private WifiConfigStoreEncryptionUtil mEncryptionUtil;
private MockStoreFile mSharedStore;
private MockStoreFile mSharedSoftApStore;
private MockStoreFile mUserStore;
private MockStoreFile mUserNetworkSuggestionsStore;
private List<StoreFile> mUserStores = new ArrayList<StoreFile>();
private MockStoreData mSharedStoreData;
private MockStoreData mUserStoreData;
private MockitoSession mSession;
private @Mock WifiCarrierInfoStoreManagerData.DataSource mDataSource;
/**
* Test instance of WifiConfigStore.
*/
private WifiConfigStore mWifiConfigStore;
/**
* Setup mocks before the test starts.
*/
private void setupMocks() throws Exception {
MockitoAnnotations.initMocks(this);
mAlarmManager = new TestAlarmManager();
mLooper = new TestLooper();
when(mContext.getSystemService(Context.ALARM_SERVICE))
.thenReturn(mAlarmManager.getAlarmManager());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME);
when(mEncryptionUtil.encrypt(any(byte[].class)))
.thenReturn(new EncryptedData(new byte[0], new byte[0]));
when(mEncryptionUtil.decrypt(any(EncryptedData.class)))
.thenReturn(new byte[0]);
mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
mSharedSoftApStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_SOFTAP);
mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL);
mUserNetworkSuggestionsStore =
new MockStoreFile(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
mUserStores.add(mUserStore);
mUserStores.add(mUserNetworkSuggestionsStore);
mSharedStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
mUserStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_USER_GENERAL);
mSession = ExtendedMockito.mockitoSession()
.mockStatic(WifiMigration.class, withSettings().lenient())
.startMocking();
when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(anyInt())).thenReturn(null);
when(WifiMigration.convertAndRetrieveUserConfigStoreFile(anyInt(), any())).thenReturn(null);
}
/**
* Setup the test environment.
*/
@Before
public void setUp() throws Exception {
setupMocks();
mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock,
mWifiMetrics, Arrays.asList(mSharedStore, mSharedSoftApStore));
// Enable verbose logging before tests.
mWifiConfigStore.enableVerboseLogging(true);
}
/**
* Called after each test
*/
@After
public void cleanup() {
validateMockitoUsage();
if (mSession != null) {
mSession.finishMocking();
}
}
/**
* Verify that no write occurs if there is {@link StoreData} registered for any
* {@link StoreFile}.
*
* @throws Exception
*/
@Test
public void testWriteWithNoStoreData() throws Exception {
// Perform force write to both share and user store file.
mWifiConfigStore.setUserStores(mUserStores);
mWifiConfigStore.write(true);
assertFalse(mSharedStore.isStoreWritten());
assertFalse(mUserStore.isStoreWritten());
assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
verify(mWifiMetrics, never()).noteWifiConfigStoreWriteDuration(anyInt());
}
/**
* Tests the write API with the force flag set to true.
* Expected behavior: This should trigger an immediate write to the store files and no alarms
* should be started.
*/
@Test
public void testForceWrite() throws Exception {
// Register data container.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
mWifiConfigStore.write(true);
assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertTrue(mSharedStore.isStoreWritten());
assertTrue(mUserStore.isStoreWritten());
assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
}
/**
* Tests the write API with the force flag set to false.
* Expected behavior: This should set an alarm to write to the store files.
*/
@Test
public void testBufferedWrite() throws Exception {
// Register data container.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
mWifiConfigStore.write(false);
assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertFalse(mSharedStore.isStoreWritten());
assertFalse(mUserStore.isStoreWritten());
assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
// Now send the alarm and ensure that the writes happen.
mAlarmManager.dispatch(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG);
mLooper.dispatchAll();
assertTrue(mSharedStore.isStoreWritten());
assertTrue(mUserStore.isStoreWritten());
assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
}
/**
* Tests the force write after a buffered write.
* Expected behaviour: The force write should override the previous buffered write and stop the
* buffer write alarms.
*/
@Test
public void testForceWriteAfterBufferedWrite() throws Exception {
// Register a test data container with bogus data.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
mSharedStoreData.setData("abcds");
mUserStoreData.setData("asdfa");
// Perform buffered write for both user and share store file.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
mWifiConfigStore.write(false);
assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertFalse(mSharedStore.isStoreWritten());
assertFalse(mUserStore.isStoreWritten());
// Update the container with new set of data. The send a force write and ensure that the
// writes have been performed and alarms have been stopped and updated data are written.
mUserStoreData.setData(TEST_USER_DATA);
mSharedStoreData.setData(TEST_SHARE_DATA);
mWifiConfigStore.write(true);
assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertTrue(mSharedStore.isStoreWritten());
assertTrue(mUserStore.isStoreWritten());
// Verify correct data are loaded to the data container after a read.
mWifiConfigStore.read();
assertEquals(TEST_USER_DATA, mUserStoreData.getData());
assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
}
/**
* Tests the force write with no new data after a buffered write.
* Expected behaviour: The force write should flush the previous buffered write and stop the
* buffer write alarms.
*/
@Test
public void testForceWriteWithNoNewDataAfterBufferedWrite() throws Exception {
// Register a test data container with bogus data.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
mSharedStoreData.setData("abcds");
mUserStoreData.setData("asdfa");
// Perform buffered write for both user and share store file.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
mWifiConfigStore.write(false);
assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertFalse(mSharedStore.isStoreWritten());
assertFalse(mUserStore.isStoreWritten());
// Containers have no new data.
mUserStoreData.setHasAnyNewData(false);
mSharedStoreData.setHasAnyNewData(false);
mWifiConfigStore.write(true);
assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
assertTrue(mSharedStore.isStoreWritten());
assertTrue(mUserStore.isStoreWritten());
// Verify correct data are loaded to the data container after a read.
mWifiConfigStore.read();
assertEquals("abcds", mSharedStoreData.getData());
assertEquals("asdfa", mUserStoreData.getData());
}
/**
* Tests the read API behaviour after a write to the store files.
* Expected behaviour: The read should return the same data that was last written.
*/
@Test
public void testReadAfterWrite() throws Exception {
// Register data container.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
// Read both share and user config store.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
// Verify no data is read.
assertNull(mUserStoreData.getData());
assertNull(mSharedStoreData.getData());
// Write share and user data.
mUserStoreData.setData(TEST_USER_DATA);
mSharedStoreData.setData(TEST_SHARE_DATA);
mWifiConfigStore.write(true);
// Read and verify the data content in the data container.
mWifiConfigStore.read();
assertEquals(TEST_USER_DATA, mUserStoreData.getData());
assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
verify(mWifiMetrics, times(2)).noteWifiConfigStoreReadDuration(anyInt());
verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
}
/**
* Tests the read API behaviour when the shared store file is empty and the user store
* is not yet visible (user not yet unlocked).
* Expected behaviour: The read should return an empty store data instance when the file not
* found exception is raised.
*/
@Test
public void testReadWithNoSharedStoreFileAndUserStoreNotVisible() throws Exception {
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
// Reading the mock store without a write should simulate the file not found case because
// |readRawData| would return null.
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
mWifiConfigStore.read();
// Ensure that we got the call to deserialize empty shared data, but no user data.
verify(sharedStoreData).resetData();
verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(userStoreData, never()).resetData();
verify(userStoreData, never()).deserializeData(any(), anyInt(), anyInt(), any());
}
/**
* Tests the read API behaviour when there are no user/shared store files on the device.
* Expected behaviour: The read should return an empty store data instance when the file not
* found exception is raised.
*/
@Test
public void testReadWithNoStoreFiles() throws Exception {
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
// Reading the mock store without a write should simulate the file not found case because
// |readRawData| would return null.
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
// Read both share and user config store.
mWifiConfigStore.setUserStores(mUserStores);
mWifiConfigStore.read();
// Ensure that we got the call to deserialize empty shared & user data.
verify(userStoreData).resetData();
verify(userStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(sharedStoreData).resetData();
verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
}
/**
* Tests the read API behaviour after a write to the shared store file when the user
* store file is null.
* Expected behaviour: The read should return the same data that was last written.
*/
@Test
public void testReadAfterWriteWithNoUserStore() throws Exception {
// Setup data container.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mSharedStoreData.setData(TEST_SHARE_DATA);
// Perform write for the share store file.
mWifiConfigStore.write(true);
mWifiConfigStore.read();
// Verify data content for both user and share data.
assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
}
/**
* Verifies that a read operation will reset the data in the data container, to avoid
* any stale data from previous read.
*
* @throws Exception
*/
@Test
public void testReadWillResetStoreData() throws Exception {
// Register and setup store data.
mWifiConfigStore.registerStoreData(mSharedStoreData);
mWifiConfigStore.registerStoreData(mUserStoreData);
// Perform force write with empty data content to both user and share store file.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
mWifiConfigStore.write(true);
// Setup data container with some value.
mUserStoreData.setData(TEST_USER_DATA);
mSharedStoreData.setData(TEST_SHARE_DATA);
// Perform read of both user and share store file and verify data in the data container
// is in sync (empty) with what is in the file.
mWifiConfigStore.read();
assertNull(mSharedStoreData.getData());
assertNull(mUserStoreData.getData());
}
/**
* Verify that a store file contained WiFi configuration store data (network list and
* deleted ephemeral SSID list) using the predefined test XML data is read and parsed
* correctly.
*
* @throws Exception
*/
@Test
public void testReadWifiConfigStoreData() throws Exception {
// Setup network list.
NetworkListStoreData networkList = new NetworkListUserStoreData(mContext);
mWifiConfigStore.registerStoreData(networkList);
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
openNetwork.creatorName = TEST_CREATOR_NAME;
openNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC);
List<WifiConfiguration> userConfigs = new ArrayList<>();
openNetwork.subscriptionId = TEST_SUB_ID;
userConfigs.add(openNetwork);
// Setup user store XML bytes.
String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
openNetwork.getKey().replaceAll("\"", "&quot;"),
openNetwork.SSID.replaceAll("\"", "&quot;"),
openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName,
openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId);
byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8);
mUserStore.storeRawDataToWrite(xmlBytes);
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore(
userConfigs, networkList.getConfigurations());
}
/**
* Verify that the WiFi configuration store data containing network list and deleted
* ephemeral SSID list are serialized correctly, matches the predefined test XML data.
*
* @throws Exception
*/
@Test
public void testWriteWifiConfigStoreData() throws Exception {
// Setup user store.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
// Setup network list store data.
NetworkListStoreData networkList = new NetworkListUserStoreData(mContext);
mWifiConfigStore.registerStoreData(networkList);
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenOweNetwork();
openNetwork.creatorName = TEST_CREATOR_NAME;
openNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC);
openNetwork.subscriptionId = TEST_SUB_ID;
List<WifiConfiguration> userConfigs = new ArrayList<>();
userConfigs.add(openNetwork);
networkList.setConfigurations(userConfigs);
// Setup expected XML bytes.
String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
openNetwork.getKey().replaceAll("\"", "&quot;"),
openNetwork.SSID.replaceAll("\"", "&quot;"),
openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName,
openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId);
mWifiConfigStore.write(true);
// Verify the user store content.
assertEquals(xmlString, new String(mUserStore.getStoreBytes()));
}
/**
* Verify that a store file contained WiFi configuration store data (network list and
* deleted ephemeral SSID list) using the predefined test XML data is read and parsed
* correctly.
*
* @throws Exception
*/
@Test
public void testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem()
throws Exception {
// Set both the user store & shared store files.
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
String storeData1Name = "test1";
String storeData2Name = "test2";
StoreData storeData1 = mock(StoreData.class);
StoreData storeData2 = mock(StoreData.class);
assertTrue(mWifiConfigStore.registerStoreData(storeData1));
assertTrue(mWifiConfigStore.registerStoreData(storeData2));
String fileContentsXmlStringWithOnlyStoreData1 =
String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData1Name);
String fileContentsXmlStringWithOnlyStoreData2 =
String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData2Name);
String fileContentsXmlStringWithStoreData1AndStoreData2 =
String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE,
storeData1Name, storeData2Name);
// Scenario 1: StoreData1 in shared store file.
when(storeData1.getName()).thenReturn(storeData1Name);
when(storeData2.getName()).thenReturn(storeData2Name);
when(storeData1.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
when(storeData2.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
when(storeData1.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(storeData2.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes());
mUserStore.storeRawDataToWrite(null);
mWifiConfigStore.read();
verify(storeData1)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(storeData2).deserializeData(eq(null), anyInt(), anyInt(), any());
reset(storeData1, storeData2);
// Scenario 2: StoreData2 in user store file.
when(storeData1.getName()).thenReturn(storeData1Name);
when(storeData2.getName()).thenReturn(storeData2Name);
when(storeData1.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
when(storeData2.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
when(storeData1.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
when(storeData2.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
mSharedStore.storeRawDataToWrite(null);
mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes());
mWifiConfigStore.read();
verify(storeData1).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(storeData2)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
reset(storeData1, storeData2);
// Scenario 3: StoreData1 in shared store file & StoreData2 in user store file.
when(storeData1.getName()).thenReturn(storeData1Name);
when(storeData2.getName()).thenReturn(storeData2Name);
when(storeData1.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
when(storeData2.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
when(storeData1.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(storeData2.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes());
mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes());
mWifiConfigStore.read();
verify(storeData1)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(storeData2)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
reset(storeData1, storeData2);
// Scenario 4: StoreData1 & StoreData2 in shared store file.
when(storeData1.getName()).thenReturn(storeData1Name);
when(storeData2.getName()).thenReturn(storeData2Name);
when(storeData1.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
when(storeData2.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
when(storeData1.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(storeData2.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
mSharedStore.storeRawDataToWrite(
fileContentsXmlStringWithStoreData1AndStoreData2.getBytes());
mUserStore.storeRawDataToWrite(null);
mWifiConfigStore.read();
verify(storeData1)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
verify(storeData2)
.deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
reset(storeData1, storeData2);
}
/**
* Tests the write API behavior when all the store data's registered for a given store file
* has no new data to write.
* Expected behaviour: The write should not trigger a new file write for that specific store
* file.
*/
@Test
public void testWriteWithNoNewData() throws Exception {
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true);
when(sharedStoreData.getName()).thenReturn("sharedStoreData");
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
when(userStoreData.hasNewDataToSerialize()).thenReturn(true);
when(userStoreData.getName()).thenReturn("userStoreData");
StoreData userStoreNetworkSuggestionsData =
mock(StoreData.class);
when(userStoreNetworkSuggestionsData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
when(userStoreNetworkSuggestionsData.hasNewDataToSerialize()).thenReturn(false);
when(userStoreNetworkSuggestionsData.getName())
.thenReturn("userStoreNetworkSuggestionsData");
assertTrue(mWifiConfigStore.registerStoreData(sharedStoreData));
assertTrue(mWifiConfigStore.registerStoreData(userStoreData));
assertTrue(mWifiConfigStore.registerStoreData(userStoreNetworkSuggestionsData));
// Write both share and user config store.
mWifiConfigStore.setUserStores(mUserStores);
// Now trigger a write.
mWifiConfigStore.write(true);
verify(sharedStoreData).hasNewDataToSerialize();
verify(userStoreData).hasNewDataToSerialize();
verify(userStoreNetworkSuggestionsData).hasNewDataToSerialize();
// Verify that we serialized data from the first 2 data source, but not from the last one.
verify(sharedStoreData).serializeData(any(), any());
verify(userStoreData).serializeData(any(), any());
verify(userStoreNetworkSuggestionsData, never()).serializeData(any(), any());
}
/**
* Verify that we gracefully skip unknown section when reading an user store file.
*/
@Test
public void testReadUserStoreContainedUnknownSection() throws Exception {
String storeFileData =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"1\" />\n"
+ "<UnknownTag>\n" // No StoreData registered to handle this tag.
+ "</UnknownTag>\n"
+ "</WifiConfigStoreData>\n";
mUserStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8));
mWifiConfigStore.switchUserStoresAndRead(mUserStores);
}
/**
* Verify that we gracefully skip unknown section when reading a shared store file.
*/
@Test
public void testReadShareStoreContainedUnknownSection() throws Exception {
String storeFileData =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<WifiConfigStoreData>\n"
+ "<int name=\"Version\" value=\"1\" />\n"
+ "<UnknownTag>\n" // No StoreData registered to handle this tag.
+ "</UnknownTag>\n"
+ "</WifiConfigStoreData>\n";
mSharedStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8));
mWifiConfigStore.read();
}
/**
* Tests the read API behaviour when the config store file is version 1.
* Expected behaviour: The read should be successful and send the data to the corresponding
* {@link StoreData} instance.
*/
@Test
public void testReadVersion1StoreFile() throws Exception {
// Register data container.
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
when(sharedStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
when(userStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
// Read both share and user config store.
mWifiConfigStore.setUserStores(mUserStores);
// Now store some content in the shared and user data files.
mUserStore.storeRawDataToWrite(
String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE,
TEST_USER_DATA).getBytes());
mSharedStore.storeRawDataToWrite(
String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE,
TEST_SHARE_DATA).getBytes());
// Read and verify the data content in the store file (metadata stripped out) has been sent
// to the corresponding store data when integrity check passes.
mWifiConfigStore.read();
verify(sharedStoreData, times(1)).deserializeDataForSection(
any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_SHARE_DATA));
verify(userStoreData, times(1)).deserializeDataForSection(
any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_USER_DATA));
}
/**
* Tests the read API behaviour to ensure that the integrity data is parsed from the file.
*/
@Test
public void testReadVersion2StoreFile() throws Exception {
byte[] encryptedData = new byte[0];
byte[] iv = new byte[0];
Random random = new Random();
random.nextBytes(encryptedData);
random.nextBytes(iv);
// Register data container.
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
when(sharedStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true);
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
when(userStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
when(userStoreData.hasNewDataToSerialize()).thenReturn(true);
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
// Read both share and user config store.
mWifiConfigStore.setUserStores(mUserStores);
// Now store some content in the shared and user data files with encrypted data from above.
mUserStore.storeRawDataToWrite(
String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE,
HexEncoding.encodeToString(encryptedData),
HexEncoding.encodeToString(iv),
TEST_USER_DATA).getBytes());
mSharedStore.storeRawDataToWrite(
String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE,
HexEncoding.encodeToString(encryptedData),
HexEncoding.encodeToString(iv),
TEST_SHARE_DATA).getBytes());
// Read and verify the data content in the store file (metadata stripped out) has been sent
// to the corresponding store data.
mWifiConfigStore.read();
verify(sharedStoreData, times(1))
.deserializeDataForSection(any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(),
eq(TEST_SHARE_DATA));
verify(userStoreData, times(1))
.deserializeDataForSection(any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(),
eq(TEST_USER_DATA));
}
/**
* Tests the complete migration path all the way from reading from the migration stream to
* parsing the XML data and sending it to the appropriate registered data sources.
*/
@Test
public void testMigration() throws Exception {
// Setup both shared & user store migrations.
StoreFile sharedStoreFile1 = mock(StoreFile.class);
when(sharedStoreFile1.getFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
StoreFile sharedStoreFile2 = mock(StoreFile.class);
when(sharedStoreFile2.getFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_SOFTAP);
StoreFile userStoreFile1 = mock(StoreFile.class);
when(userStoreFile1.getFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
StoreFile userStoreFile2 = mock(StoreFile.class);
when(userStoreFile2.getFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock,
mWifiMetrics, Arrays.asList(sharedStoreFile1, sharedStoreFile2));
mWifiConfigStore.setUserStores(Arrays.asList(userStoreFile1, userStoreFile2));
// Register data container.
StoreData sharedStoreData = mock(StoreData.class);
when(sharedStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
when(sharedStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
StoreData userStoreData = mock(StoreData.class);
when(userStoreData.getStoreFileId())
.thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
when(userStoreData.getSectionsToParse())
.thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
// Migration data
InputStream sharedStream1 = mock(InputStream.class);
InputStream sharedStream2 = mock(InputStream.class);
InputStream userStream1 = mock(InputStream.class);
InputStream userStream2 = mock(InputStream.class);
when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(
WifiMigration.STORE_FILE_SHARED_GENERAL))
.thenReturn(sharedStream1);
when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(
WifiMigration.STORE_FILE_SHARED_SOFTAP))
.thenReturn(sharedStream2);
when(WifiMigration.convertAndRetrieveUserConfigStoreFile(
eq(WifiMigration.STORE_FILE_USER_GENERAL), any()))
.thenReturn(userStream1);
when(WifiMigration.convertAndRetrieveUserConfigStoreFile(
eq(WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS), any()))
.thenReturn(userStream2);
byte[] sharedStoreXmlBytes =
String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE,
TEST_SHARE_DATA).getBytes();
byte[] userStoreXmlBytes =
String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE,
TEST_USER_DATA).getBytes();
when(sharedStream1.available())
.thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0.
.thenReturn(0);
when(sharedStream2.available())
.thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0.
.thenReturn(0);
when(userStream1.available())
.thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0.
.thenReturn(0);
when(userStream2.available())
.thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0.
.thenReturn(0);
Answer sharedStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() {
public int answer(byte[] b, int off, int len) {
System.arraycopy(sharedStoreXmlBytes, 0, b, 0, sharedStoreXmlBytes.length);
return sharedStoreXmlBytes.length;
}
};
Answer userStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() {
public int answer(byte[] b, int off, int len) {
System.arraycopy(userStoreXmlBytes, 0, b, 0, userStoreXmlBytes.length);
return userStoreXmlBytes.length;
}
};
when(sharedStream1.read(any(byte[].class), anyInt(), anyInt()))
.thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0.
.thenReturn(0);
when(sharedStream2.read(any(byte[].class), anyInt(), anyInt()))
.thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0.
.thenReturn(0);
when(userStream1.read(any(byte[].class), anyInt(), anyInt()))
.thenAnswer(userStreamReadAnswer) // first time return file contents, then 0.
.thenReturn(0);
when(userStream2.read(any(byte[].class), anyInt(), anyInt()))
.thenAnswer(userStreamReadAnswer) // first time return file contents, then 0.
.thenReturn(0);
// Trigger read.
mWifiConfigStore.read();
// Verify that we read the data out of all the migration streams & we didn't read
// from the files on disk.
verify(sharedStream1, times(2)).available();
verify(sharedStream1, times(2)).read(any(), anyInt(), anyInt());
verify(sharedStream2, times(2)).available();
verify(sharedStream2, times(2)).read(any(), anyInt(), anyInt());
verify(userStream1, times(2)).available();
verify(userStream1, times(2)).read(any(), anyInt(), anyInt());
verify(userStream2, times(2)).available();
verify(userStream2, times(2)).read(any(), anyInt(), anyInt());
// Verify that we correctly deserialized the data and sent it to the corresponding sources.
verify(sharedStoreData, times(1))
.deserializeDataForSection(any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(),
eq(TEST_SHARE_DATA));
verify(userStoreData, times(1))
.deserializeDataForSection(any(XmlPullParser.class), anyInt(),
eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(),
eq(TEST_USER_DATA));
// Verify we did not read from the real store files.
verify(sharedStoreFile1, never()).readRawData();
verify(sharedStoreFile2, never()).readRawData();
verify(userStoreFile1, never()).readRawData();
verify(userStoreFile2, never()).readRawData();
}
/**
* Mock Store File to redirect all file writes from WifiConfigStore to local buffers.
* This can be used to examine the data output by WifiConfigStore.
*/
private class MockStoreFile extends StoreFile {
private byte[] mStoreBytes;
private boolean mStoreWritten;
MockStoreFile(@WifiConfigStore.StoreFileId int fileId) {
super(new File("MockStoreFile"), fileId, UserHandle.ALL, mEncryptionUtil);
}
@Override
public byte[] readRawData() {
return mStoreBytes;
}
@Override
public void storeRawDataToWrite(byte[] data) {
mStoreBytes = data;
mStoreWritten = false;
}
@Override
public void writeBufferedRawData() {
if (!ArrayUtils.isEmpty(mStoreBytes)) {
mStoreWritten = true;
}
}
public byte[] getStoreBytes() {
return mStoreBytes;
}
public boolean isStoreWritten() {
return mStoreWritten;
}
}
/**
* Mock data container for providing test data for the store file.
*/
private class MockStoreData implements StoreData {
private static final String XML_TAG_TEST_HEADER = "TestHeader";
private static final String XML_TAG_TEST_DATA = "TestData";
private @WifiConfigStore.StoreFileId int mFileId;
private String mData;
private boolean mHasAnyNewData = true;
MockStoreData(@WifiConfigStore.StoreFileId int fileId) {
mFileId = fileId;
}
@Override
public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)
throws XmlPullParserException, IOException {
XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mData);
}
@Override
public void deserializeData(XmlPullParser in, int outerTagDepth, int version,
WifiConfigStoreEncryptionUtil encryptionUtil)
throws XmlPullParserException, IOException {
if (in == null) {
return;
}
mData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA);
}
@Override
public void resetData() {
mData = null;
}
@Override
public boolean hasNewDataToSerialize() {
return mHasAnyNewData;
}
@Override
public String getName() {
return XML_TAG_TEST_HEADER;
}
@Override
public @WifiConfigStore.StoreFileId int getStoreFileId() {
return mFileId;
}
public String getData() {
return mData;
}
public void setData(String data) {
mData = data;
}
public void setHasAnyNewData(boolean hasAnyNewData) {
mHasAnyNewData = hasAnyNewData;
}
}
/**
* Verify dump will not crash when no UserStores set.
*/
@Test
public void testDump() {
final FileDescriptor fd = new FileDescriptor();
final FileOutputStream fout = new FileOutputStream(fd);
final PrintWriter pw = new FastPrintWriter(fout);
mWifiConfigStore.dump(fd, pw, new String[0]);
mWifiConfigStore.setUserStores(mUserStores);
mWifiConfigStore.dump(fd, pw, new String[0]);
}
}