• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.wifi;
18 
19 import static org.junit.Assert.*;
20 import static org.mockito.Mockito.*;
21 
22 import android.app.test.MockAnswerUtil;
23 import android.app.test.TestAlarmManager;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.net.MacAddress;
27 import android.net.wifi.WifiConfiguration;
28 import android.net.wifi.WifiMigration;
29 import android.net.wifi.util.HexEncoding;
30 import android.os.Handler;
31 import android.os.UserHandle;
32 import android.os.test.TestLooper;
33 
34 import androidx.test.filters.SmallTest;
35 
36 import com.android.dx.mockito.inline.extended.ExtendedMockito;
37 import com.android.internal.util.FastPrintWriter;
38 import com.android.server.wifi.WifiConfigStore.StoreData;
39 import com.android.server.wifi.WifiConfigStore.StoreFile;
40 import com.android.server.wifi.util.ArrayUtils;
41 import com.android.server.wifi.util.EncryptedData;
42 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
43 import com.android.server.wifi.util.XmlUtil;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.mockito.Mock;
49 import org.mockito.MockitoAnnotations;
50 import org.mockito.MockitoSession;
51 import org.mockito.stubbing.Answer;
52 import org.xmlpull.v1.XmlPullParser;
53 import org.xmlpull.v1.XmlPullParserException;
54 import org.xmlpull.v1.XmlSerializer;
55 
56 import java.io.File;
57 import java.io.FileDescriptor;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.io.PrintWriter;
62 import java.nio.charset.StandardCharsets;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.Collections;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Random;
69 
70 /**
71  * Unit tests for {@link com.android.server.wifi.WifiConfigStore}.
72  */
73 @SmallTest
74 public class WifiConfigStoreTest extends WifiBaseTest {
75     private static final String TEST_USER_DATA = "UserData";
76     private static final String TEST_SHARE_DATA = "ShareData";
77     private static final String TEST_CREATOR_NAME = "CreatorName";
78     private static final MacAddress TEST_RANDOMIZED_MAC =
79             MacAddress.fromString("da:a1:19:c4:26:fa");
80     private static final int TEST_SUB_ID = 2;
81 
82     private static final String TEST_DATA_XML_STRING_FORMAT =
83             "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
84                     + "<WifiConfigStoreData>\n"
85                     + "<int name=\"Version\" value=\"3\" />\n"
86                     + "<NetworkList>\n"
87                     + "<Network>\n"
88                     + "<WifiConfiguration>\n"
89                     + "<string name=\"ConfigKey\">%s</string>\n"
90                     + "<string name=\"SSID\">%s</string>\n"
91                     + "<null name=\"PreSharedKey\" />\n"
92                     + "<null name=\"WEPKeys\" />\n"
93                     + "<int name=\"WEPTxKeyIndex\" value=\"0\" />\n"
94                     + "<boolean name=\"HiddenSSID\" value=\"false\" />\n"
95                     + "<boolean name=\"RequirePMF\" value=\"false\" />\n"
96                     + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">01</byte-array>\n"
97                     + "<byte-array name=\"AllowedProtocols\" num=\"1\">03</byte-array>\n"
98                     + "<byte-array name=\"AllowedAuthAlgos\" num=\"0\"></byte-array>\n"
99                     + "<byte-array name=\"AllowedGroupCiphers\" num=\"0\"></byte-array>\n"
100                     + "<byte-array name=\"AllowedPairwiseCiphers\" num=\"0\"></byte-array>\n"
101                     + "<byte-array name=\"AllowedGroupMgmtCiphers\" num=\"0\"></byte-array>\n"
102                     + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n"
103                     + "<boolean name=\"Shared\" value=\"%s\" />\n"
104                     + "<boolean name=\"AutoJoinEnabled\" value=\"true\" />\n"
105                     + "<int name=\"DeletionPriority\" value=\"0\" />\n"
106                     + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n"
107                     + "<SecurityParamsList>\n"
108                     + "<SecurityParams>\n"
109                     + "<int name=\"SecurityType\" value=\"0\" />\n"
110                     + "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n"
111                     + "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n"
112                     + "<boolean name=\"IsAddedByAutoUpgrade\" value=\"false\" />\n"
113                     + "</SecurityParams>\n"
114                     + "<SecurityParams>\n"
115                     + "<int name=\"SecurityType\" value=\"6\" />\n"
116                     + "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n"
117                     + "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n"
118                     + "<boolean name=\"IsAddedByAutoUpgrade\" value=\"true\" />\n"
119                     + "</SecurityParams>\n"
120                     + "</SecurityParamsList>\n"
121                     + "<boolean name=\"Trusted\" value=\"true\" />\n"
122                     + "<boolean name=\"OemPaid\" value=\"false\" />\n"
123                     + "<boolean name=\"OemPrivate\" value=\"false\" />\n"
124                     + "<boolean name=\"CarrierMerged\" value=\"false\" />\n"
125                     + "<null name=\"BSSID\" />\n"
126                     + "<int name=\"Status\" value=\"2\" />\n"
127                     + "<null name=\"FQDN\" />\n"
128                     + "<null name=\"ProviderFriendlyName\" />\n"
129                     + "<null name=\"LinkedNetworksList\" />\n"
130                     + "<null name=\"DefaultGwMacAddress\" />\n"
131                     + "<boolean name=\"ValidatedInternetAccess\" value=\"false\" />\n"
132                     + "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
133                     + "<boolean name=\"MeteredHint\" value=\"false\" />\n"
134                     + "<int name=\"MeteredOverride\" value=\"0\" />\n"
135                     + "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
136                     + "<int name=\"CreatorUid\" value=\"%d\" />\n"
137                     + "<string name=\"CreatorName\">%s</string>\n"
138                     + "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
139                     + "<null name=\"LastUpdateName\" />\n"
140                     + "<int name=\"LastConnectUid\" value=\"0\" />\n"
141                     + "<boolean name=\"IsLegacyPasspointConfig\" value=\"false\" />\n"
142                     + "<long-array name=\"RoamingConsortiumOIs\" num=\"0\" />\n"
143                     + "<string name=\"RandomizedMacAddress\">%s</string>\n"
144                     + "<int name=\"MacRandomizationSetting\" value=\"3\" />\n"
145                     + "<int name=\"CarrierId\" value=\"-1\" />\n"
146                     + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
147                     + "<int name=\"SubscriptionId\" value=\"%d\" />\n"
148                     + "</WifiConfiguration>\n"
149                     + "<NetworkStatus>\n"
150                     + "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
151                     + "<string name=\"DisableReason\">NETWORK_SELECTION_ENABLE</string>\n"
152                     + "<null name=\"ConnectChoice\" />\n"
153                     + "<int name=\"ConnectChoiceRssi\" value=\"0\" />\n"
154                     + "<boolean name=\"HasEverConnected\" value=\"false\" />\n"
155                     + "<boolean name=\"CaptivePortalNeverDetected\" value=\"true\" />\n"
156                     + "</NetworkStatus>\n"
157                     + "<IpConfiguration>\n"
158                     + "<string name=\"IpAssignment\">DHCP</string>\n"
159                     + "<string name=\"ProxySettings\">NONE</string>\n"
160                     + "</IpConfiguration>\n"
161                     + "</Network>\n"
162                     + "</NetworkList>\n"
163                     + "</WifiConfigStoreData>\n";
164 
165     private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE =
166             "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
167                     + "<WifiConfigStoreData>\n"
168                     + "<int name=\"Version\" value=\"1\" />\n"
169                     + "<%s/>n"
170                     + "</WifiConfigStoreData>\n";
171     private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE =
172             "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
173                     + "<WifiConfigStoreData>\n"
174                     + "<int name=\"Version\" value=\"1\" />\n"
175                     + "<%s/>n"
176                     + "<%s/>n"
177                     + "</WifiConfigStoreData>\n";
178     private static final String TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE =
179             "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
180                     + "<WifiConfigStoreData>\n"
181                     + "<int name=\"Version\" value=\"2\" />\n"
182                     + "<Integrity>\n"
183                     + "<byte-array name=\"EncryptedData\" num=\"48\">%s</byte-array>\n"
184                     + "<byte-array name=\"IV\" num=\"12\">%s</byte-array>\n"
185                     + "</Integrity>\n"
186                     + "<%s />\n"
187                     + "</WifiConfigStoreData>\n";
188     private static final String TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE =
189             "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
190                     + "<WifiConfigStoreData>\n"
191                     + "<int name=\"Version\" value=\"3\" />\n"
192                     + "<%s />\n"
193                     + "</WifiConfigStoreData>\n";
194     // Test mocks
195     @Mock private Context mContext;
196     @Mock private PackageManager mPackageManager;
197     private TestAlarmManager mAlarmManager;
198     private TestLooper mLooper;
199     @Mock private Clock mClock;
200     @Mock private WifiMetrics mWifiMetrics;
201     @Mock private WifiConfigStoreEncryptionUtil mEncryptionUtil;
202     private MockStoreFile mSharedStore;
203     private MockStoreFile mSharedSoftApStore;
204     private MockStoreFile mUserStore;
205     private MockStoreFile mUserNetworkSuggestionsStore;
206     private List<StoreFile> mUserStores = new ArrayList<StoreFile>();
207     private MockStoreData mSharedStoreData;
208     private MockStoreData mUserStoreData;
209     private MockitoSession mSession;
210     private @Mock WifiCarrierInfoStoreManagerData.DataSource mDataSource;
211 
212     /**
213      * Test instance of WifiConfigStore.
214      */
215     private WifiConfigStore mWifiConfigStore;
216 
217     /**
218      * Setup mocks before the test starts.
219      */
setupMocks()220     private void setupMocks() throws Exception {
221         MockitoAnnotations.initMocks(this);
222         mAlarmManager = new TestAlarmManager();
223         mLooper = new TestLooper();
224         when(mContext.getSystemService(Context.ALARM_SERVICE))
225                 .thenReturn(mAlarmManager.getAlarmManager());
226         when(mContext.getPackageManager()).thenReturn(mPackageManager);
227         when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME);
228         when(mEncryptionUtil.encrypt(any(byte[].class)))
229                 .thenReturn(new EncryptedData(new byte[0], new byte[0]));
230         when(mEncryptionUtil.decrypt(any(EncryptedData.class)))
231                 .thenReturn(new byte[0]);
232         mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
233         mSharedSoftApStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_SOFTAP);
234         mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL);
235         mUserNetworkSuggestionsStore =
236                 new MockStoreFile(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
237         mUserStores.add(mUserStore);
238         mUserStores.add(mUserNetworkSuggestionsStore);
239 
240         mSharedStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
241         mUserStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_USER_GENERAL);
242 
243         mSession = ExtendedMockito.mockitoSession()
244                 .mockStatic(WifiMigration.class, withSettings().lenient())
245                 .startMocking();
246         when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(anyInt())).thenReturn(null);
247         when(WifiMigration.convertAndRetrieveUserConfigStoreFile(anyInt(), any())).thenReturn(null);
248     }
249 
250     /**
251      * Setup the test environment.
252      */
253     @Before
setUp()254     public void setUp() throws Exception {
255         setupMocks();
256 
257         mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock,
258                 mWifiMetrics, Arrays.asList(mSharedStore, mSharedSoftApStore));
259         // Enable verbose logging before tests.
260         mWifiConfigStore.enableVerboseLogging(true);
261     }
262 
263     /**
264      * Called after each test
265      */
266     @After
cleanup()267     public void cleanup() {
268         validateMockitoUsage();
269         if (mSession != null) {
270             mSession.finishMocking();
271         }
272     }
273 
274     /**
275      * Verify that no write occurs if there is {@link StoreData} registered for any
276      * {@link StoreFile}.
277      *
278      * @throws Exception
279      */
280     @Test
testWriteWithNoStoreData()281     public void testWriteWithNoStoreData() throws Exception {
282         // Perform force write to both share and user store file.
283         mWifiConfigStore.setUserStores(mUserStores);
284         mWifiConfigStore.write(true);
285 
286         assertFalse(mSharedStore.isStoreWritten());
287         assertFalse(mUserStore.isStoreWritten());
288         assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
289 
290         verify(mWifiMetrics, never()).noteWifiConfigStoreWriteDuration(anyInt());
291     }
292 
293     /**
294      * Tests the write API with the force flag set to true.
295      * Expected behavior: This should trigger an immediate write to the store files and no alarms
296      * should be started.
297      */
298     @Test
testForceWrite()299     public void testForceWrite() throws Exception {
300         // Register data container.
301         mWifiConfigStore.registerStoreData(mSharedStoreData);
302         mWifiConfigStore.registerStoreData(mUserStoreData);
303 
304         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
305         mWifiConfigStore.write(true);
306 
307         assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
308         assertTrue(mSharedStore.isStoreWritten());
309         assertTrue(mUserStore.isStoreWritten());
310         assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
311 
312         verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
313     }
314 
315     /**
316      * Tests the write API with the force flag set to false.
317      * Expected behavior: This should set an alarm to write to the store files.
318      */
319     @Test
testBufferedWrite()320     public void testBufferedWrite() throws Exception {
321         // Register data container.
322         mWifiConfigStore.registerStoreData(mSharedStoreData);
323         mWifiConfigStore.registerStoreData(mUserStoreData);
324 
325         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
326         mWifiConfigStore.write(false);
327 
328         assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
329         assertFalse(mSharedStore.isStoreWritten());
330         assertFalse(mUserStore.isStoreWritten());
331         assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
332 
333         // Now send the alarm and ensure that the writes happen.
334         mAlarmManager.dispatch(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG);
335         mLooper.dispatchAll();
336         assertTrue(mSharedStore.isStoreWritten());
337         assertTrue(mUserStore.isStoreWritten());
338         assertFalse(mUserNetworkSuggestionsStore.isStoreWritten());
339 
340         verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
341     }
342 
343     /**
344      * Tests the force write after a buffered write.
345      * Expected behaviour: The force write should override the previous buffered write and stop the
346      * buffer write alarms.
347      */
348     @Test
testForceWriteAfterBufferedWrite()349     public void testForceWriteAfterBufferedWrite() throws Exception {
350         // Register a test data container with bogus data.
351         mWifiConfigStore.registerStoreData(mSharedStoreData);
352         mWifiConfigStore.registerStoreData(mUserStoreData);
353 
354         mSharedStoreData.setData("abcds");
355         mUserStoreData.setData("asdfa");
356 
357         // Perform buffered write for both user and share store file.
358         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
359         mWifiConfigStore.write(false);
360 
361         assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
362         assertFalse(mSharedStore.isStoreWritten());
363         assertFalse(mUserStore.isStoreWritten());
364 
365         // Update the container with new set of data. The send a force write and ensure that the
366         // writes have been performed and alarms have been stopped and updated data are written.
367         mUserStoreData.setData(TEST_USER_DATA);
368         mSharedStoreData.setData(TEST_SHARE_DATA);
369         mWifiConfigStore.write(true);
370 
371         assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
372         assertTrue(mSharedStore.isStoreWritten());
373         assertTrue(mUserStore.isStoreWritten());
374 
375         // Verify correct data are loaded to the data container after a read.
376         mWifiConfigStore.read();
377         assertEquals(TEST_USER_DATA, mUserStoreData.getData());
378         assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
379     }
380 
381     /**
382      * Tests the force write with no new data after a buffered write.
383      * Expected behaviour: The force write should flush the previous buffered write and stop the
384      * buffer write alarms.
385      */
386     @Test
testForceWriteWithNoNewDataAfterBufferedWrite()387     public void testForceWriteWithNoNewDataAfterBufferedWrite() throws Exception {
388         // Register a test data container with bogus data.
389         mWifiConfigStore.registerStoreData(mSharedStoreData);
390         mWifiConfigStore.registerStoreData(mUserStoreData);
391 
392         mSharedStoreData.setData("abcds");
393         mUserStoreData.setData("asdfa");
394 
395         // Perform buffered write for both user and share store file.
396         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
397         mWifiConfigStore.write(false);
398 
399         assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
400         assertFalse(mSharedStore.isStoreWritten());
401         assertFalse(mUserStore.isStoreWritten());
402 
403         // Containers have no new data.
404         mUserStoreData.setHasAnyNewData(false);
405         mSharedStoreData.setHasAnyNewData(false);
406         mWifiConfigStore.write(true);
407 
408         assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG));
409         assertTrue(mSharedStore.isStoreWritten());
410         assertTrue(mUserStore.isStoreWritten());
411 
412         // Verify correct data are loaded to the data container after a read.
413         mWifiConfigStore.read();
414         assertEquals("abcds", mSharedStoreData.getData());
415         assertEquals("asdfa", mUserStoreData.getData());
416     }
417 
418 
419     /**
420      * Tests the read API behaviour after a write to the store files.
421      * Expected behaviour: The read should return the same data that was last written.
422      */
423     @Test
testReadAfterWrite()424     public void testReadAfterWrite() throws Exception {
425         // Register data container.
426         mWifiConfigStore.registerStoreData(mSharedStoreData);
427         mWifiConfigStore.registerStoreData(mUserStoreData);
428 
429         // Read both share and user config store.
430         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
431 
432         // Verify no data is read.
433         assertNull(mUserStoreData.getData());
434         assertNull(mSharedStoreData.getData());
435 
436         // Write share and user data.
437         mUserStoreData.setData(TEST_USER_DATA);
438         mSharedStoreData.setData(TEST_SHARE_DATA);
439         mWifiConfigStore.write(true);
440 
441         // Read and verify the data content in the data container.
442         mWifiConfigStore.read();
443         assertEquals(TEST_USER_DATA, mUserStoreData.getData());
444         assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
445 
446         verify(mWifiMetrics, times(2)).noteWifiConfigStoreReadDuration(anyInt());
447         verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt());
448     }
449 
450     /**
451      * Tests the read API behaviour when the shared store file is empty and the user store
452      * is not yet visible (user not yet unlocked).
453      * Expected behaviour: The read should return an empty store data instance when the file not
454      * found exception is raised.
455      */
456     @Test
testReadWithNoSharedStoreFileAndUserStoreNotVisible()457     public void testReadWithNoSharedStoreFileAndUserStoreNotVisible() throws Exception {
458         StoreData sharedStoreData = mock(StoreData.class);
459         when(sharedStoreData.getStoreFileId())
460                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
461         StoreData userStoreData = mock(StoreData.class);
462         when(userStoreData.getStoreFileId())
463                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
464 
465         // Reading the mock store without a write should simulate the file not found case because
466         // |readRawData| would return null.
467         mWifiConfigStore.registerStoreData(sharedStoreData);
468         mWifiConfigStore.registerStoreData(userStoreData);
469         mWifiConfigStore.read();
470 
471         // Ensure that we got the call to deserialize empty shared data, but no user data.
472         verify(sharedStoreData).resetData();
473         verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
474         verify(userStoreData, never()).resetData();
475         verify(userStoreData, never()).deserializeData(any(), anyInt(), anyInt(), any());
476     }
477 
478     /**
479      * Tests the read API behaviour when there are no user/shared store files on the device.
480      * Expected behaviour: The read should return an empty store data instance when the file not
481      * found exception is raised.
482      */
483     @Test
testReadWithNoStoreFiles()484     public void testReadWithNoStoreFiles() throws Exception {
485         StoreData sharedStoreData = mock(StoreData.class);
486         when(sharedStoreData.getStoreFileId())
487                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
488         StoreData userStoreData = mock(StoreData.class);
489         when(userStoreData.getStoreFileId())
490                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
491 
492         // Reading the mock store without a write should simulate the file not found case because
493         // |readRawData| would return null.
494         mWifiConfigStore.registerStoreData(sharedStoreData);
495         mWifiConfigStore.registerStoreData(userStoreData);
496         // Read both share and user config store.
497         mWifiConfigStore.setUserStores(mUserStores);
498         mWifiConfigStore.read();
499 
500         // Ensure that we got the call to deserialize empty shared & user data.
501         verify(userStoreData).resetData();
502         verify(userStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
503         verify(sharedStoreData).resetData();
504         verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any());
505     }
506 
507     /**
508      * Tests the read API behaviour after a write to the shared store file when the user
509      * store file is null.
510      * Expected behaviour: The read should return the same data that was last written.
511      */
512     @Test
testReadAfterWriteWithNoUserStore()513     public void testReadAfterWriteWithNoUserStore() throws Exception {
514         // Setup data container.
515         mWifiConfigStore.registerStoreData(mSharedStoreData);
516         mSharedStoreData.setData(TEST_SHARE_DATA);
517 
518         // Perform write for the share store file.
519         mWifiConfigStore.write(true);
520         mWifiConfigStore.read();
521         // Verify data content for both user and share data.
522         assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData());
523     }
524 
525     /**
526      * Verifies that a read operation will reset the data in the data container, to avoid
527      * any stale data from previous read.
528      *
529      * @throws Exception
530      */
531     @Test
testReadWillResetStoreData()532     public void testReadWillResetStoreData() throws Exception {
533         // Register and setup store data.
534         mWifiConfigStore.registerStoreData(mSharedStoreData);
535         mWifiConfigStore.registerStoreData(mUserStoreData);
536 
537         // Perform force write with empty data content to both user and share store file.
538         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
539         mWifiConfigStore.write(true);
540 
541         // Setup data container with some value.
542         mUserStoreData.setData(TEST_USER_DATA);
543         mSharedStoreData.setData(TEST_SHARE_DATA);
544 
545         // Perform read of both user and share store file and verify data in the data container
546         // is in sync (empty) with what is in the file.
547         mWifiConfigStore.read();
548         assertNull(mSharedStoreData.getData());
549         assertNull(mUserStoreData.getData());
550     }
551 
552     /**
553      * Verify that a store file contained WiFi configuration store data (network list and
554      * deleted ephemeral SSID list) using the predefined test XML data is read and parsed
555      * correctly.
556      *
557      * @throws Exception
558      */
559     @Test
testReadWifiConfigStoreData()560     public void testReadWifiConfigStoreData() throws Exception {
561         // Setup network list.
562         NetworkListStoreData networkList = new NetworkListUserStoreData(mContext);
563         mWifiConfigStore.registerStoreData(networkList);
564         WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
565         openNetwork.creatorName = TEST_CREATOR_NAME;
566         openNetwork.setIpConfiguration(
567                 WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
568         openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC);
569         List<WifiConfiguration> userConfigs = new ArrayList<>();
570         openNetwork.subscriptionId = TEST_SUB_ID;
571         userConfigs.add(openNetwork);
572 
573         // Setup user store XML bytes.
574         String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
575                 openNetwork.getKey().replaceAll("\"", "&quot;"),
576                 openNetwork.SSID.replaceAll("\"", "&quot;"),
577                 openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName,
578                 openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId);
579         byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8);
580         mUserStore.storeRawDataToWrite(xmlBytes);
581 
582         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
583         WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore(
584                 userConfigs, networkList.getConfigurations());
585     }
586 
587     /**
588      * Verify that the WiFi configuration store data containing network list and deleted
589      * ephemeral SSID list are serialized correctly, matches the predefined test XML data.
590      *
591      * @throws Exception
592      */
593     @Test
testWriteWifiConfigStoreData()594     public void testWriteWifiConfigStoreData() throws Exception {
595         // Setup user store.
596         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
597 
598         // Setup network list store data.
599         NetworkListStoreData networkList = new NetworkListUserStoreData(mContext);
600         mWifiConfigStore.registerStoreData(networkList);
601         WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenOweNetwork();
602         openNetwork.creatorName = TEST_CREATOR_NAME;
603         openNetwork.setIpConfiguration(
604                 WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
605         openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC);
606         openNetwork.subscriptionId = TEST_SUB_ID;
607         List<WifiConfiguration> userConfigs = new ArrayList<>();
608         userConfigs.add(openNetwork);
609         networkList.setConfigurations(userConfigs);
610 
611         // Setup expected XML bytes.
612         String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
613                 openNetwork.getKey().replaceAll("\"", "&quot;"),
614                 openNetwork.SSID.replaceAll("\"", "&quot;"),
615                 openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName,
616                 openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId);
617 
618         mWifiConfigStore.write(true);
619         // Verify the user store content.
620         assertEquals(xmlString, new String(mUserStore.getStoreBytes()));
621     }
622 
623     /**
624      * Verify that a store file contained WiFi configuration store data (network list and
625      * deleted ephemeral SSID list) using the predefined test XML data is read and parsed
626      * correctly.
627      *
628      * @throws Exception
629      */
630     @Test
testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem()631     public void testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem()
632             throws Exception {
633         // Set both the user store & shared store files.
634         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
635 
636         String storeData1Name = "test1";
637         String storeData2Name = "test2";
638         StoreData storeData1 = mock(StoreData.class);
639         StoreData storeData2 = mock(StoreData.class);
640 
641         assertTrue(mWifiConfigStore.registerStoreData(storeData1));
642         assertTrue(mWifiConfigStore.registerStoreData(storeData2));
643 
644         String fileContentsXmlStringWithOnlyStoreData1 =
645                 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData1Name);
646         String fileContentsXmlStringWithOnlyStoreData2 =
647                 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData2Name);
648         String fileContentsXmlStringWithStoreData1AndStoreData2 =
649                 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE,
650                         storeData1Name, storeData2Name);
651 
652         // Scenario 1: StoreData1 in shared store file.
653         when(storeData1.getName()).thenReturn(storeData1Name);
654         when(storeData2.getName()).thenReturn(storeData2Name);
655         when(storeData1.getSectionsToParse())
656                 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
657         when(storeData2.getSectionsToParse())
658                 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
659         when(storeData1.getStoreFileId())
660                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
661         when(storeData2.getStoreFileId())
662                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
663         mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes());
664         mUserStore.storeRawDataToWrite(null);
665 
666         mWifiConfigStore.read();
667         verify(storeData1)
668                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
669         verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
670         verify(storeData2).deserializeData(eq(null), anyInt(), anyInt(), any());
671         reset(storeData1, storeData2);
672 
673         // Scenario 2: StoreData2 in user store file.
674         when(storeData1.getName()).thenReturn(storeData1Name);
675         when(storeData2.getName()).thenReturn(storeData2Name);
676         when(storeData1.getSectionsToParse())
677                 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
678         when(storeData2.getSectionsToParse())
679                 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
680         when(storeData1.getStoreFileId())
681                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
682         when(storeData2.getStoreFileId())
683                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
684         mSharedStore.storeRawDataToWrite(null);
685         mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes());
686 
687         mWifiConfigStore.read();
688         verify(storeData1).deserializeData(eq(null), anyInt(), anyInt(), any());
689         verify(storeData2)
690                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
691         verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
692         reset(storeData1, storeData2);
693 
694         // Scenario 3: StoreData1 in shared store file & StoreData2 in user store file.
695         when(storeData1.getName()).thenReturn(storeData1Name);
696         when(storeData2.getName()).thenReturn(storeData2Name);
697         when(storeData1.getSectionsToParse())
698                 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
699         when(storeData2.getSectionsToParse())
700                 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
701         when(storeData1.getStoreFileId())
702                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
703         when(storeData2.getStoreFileId())
704                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
705         mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes());
706         mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes());
707 
708         mWifiConfigStore.read();
709         verify(storeData1)
710                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
711         verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
712         verify(storeData2)
713                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
714         verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
715         reset(storeData1, storeData2);
716 
717         // Scenario 4: StoreData1 & StoreData2 in shared store file.
718         when(storeData1.getName()).thenReturn(storeData1Name);
719         when(storeData2.getName()).thenReturn(storeData2Name);
720         when(storeData1.getSectionsToParse())
721                 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name)));
722         when(storeData2.getSectionsToParse())
723                 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name)));
724         when(storeData1.getStoreFileId())
725                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
726         when(storeData2.getStoreFileId())
727                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
728         mSharedStore.storeRawDataToWrite(
729                 fileContentsXmlStringWithStoreData1AndStoreData2.getBytes());
730         mUserStore.storeRawDataToWrite(null);
731 
732         mWifiConfigStore.read();
733         verify(storeData1)
734                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
735         verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
736         verify(storeData2)
737                 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString());
738         verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any());
739         reset(storeData1, storeData2);
740     }
741 
742     /**
743      * Tests the write API behavior when all the store data's registered for a given store file
744      * has no new data to write.
745      * Expected behaviour: The write should not trigger a new file write for that specific store
746      * file.
747      */
748     @Test
testWriteWithNoNewData()749     public void testWriteWithNoNewData() throws Exception {
750         StoreData sharedStoreData = mock(StoreData.class);
751         when(sharedStoreData.getStoreFileId())
752                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
753         when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true);
754         when(sharedStoreData.getName()).thenReturn("sharedStoreData");
755 
756         StoreData userStoreData = mock(StoreData.class);
757         when(userStoreData.getStoreFileId())
758                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
759         when(userStoreData.hasNewDataToSerialize()).thenReturn(true);
760         when(userStoreData.getName()).thenReturn("userStoreData");
761 
762         StoreData userStoreNetworkSuggestionsData =
763                 mock(StoreData.class);
764         when(userStoreNetworkSuggestionsData.getStoreFileId())
765                 .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
766         when(userStoreNetworkSuggestionsData.hasNewDataToSerialize()).thenReturn(false);
767         when(userStoreNetworkSuggestionsData.getName())
768                 .thenReturn("userStoreNetworkSuggestionsData");
769 
770         assertTrue(mWifiConfigStore.registerStoreData(sharedStoreData));
771         assertTrue(mWifiConfigStore.registerStoreData(userStoreData));
772         assertTrue(mWifiConfigStore.registerStoreData(userStoreNetworkSuggestionsData));
773 
774         // Write both share and user config store.
775         mWifiConfigStore.setUserStores(mUserStores);
776 
777         // Now trigger a write.
778         mWifiConfigStore.write(true);
779 
780         verify(sharedStoreData).hasNewDataToSerialize();
781         verify(userStoreData).hasNewDataToSerialize();
782         verify(userStoreNetworkSuggestionsData).hasNewDataToSerialize();
783 
784         // Verify that we serialized data from the first 2 data source, but not from the last one.
785         verify(sharedStoreData).serializeData(any(), any());
786         verify(userStoreData).serializeData(any(), any());
787         verify(userStoreNetworkSuggestionsData, never()).serializeData(any(), any());
788     }
789 
790     /**
791      * Verify that we gracefully skip unknown section when reading an user store file.
792      */
793     @Test
testReadUserStoreContainedUnknownSection()794     public void testReadUserStoreContainedUnknownSection() throws Exception {
795         String storeFileData =
796                 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
797                         + "<WifiConfigStoreData>\n"
798                         + "<int name=\"Version\" value=\"1\" />\n"
799                         + "<UnknownTag>\n"    // No StoreData registered to handle this tag.
800                         + "</UnknownTag>\n"
801                         + "</WifiConfigStoreData>\n";
802         mUserStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8));
803         mWifiConfigStore.switchUserStoresAndRead(mUserStores);
804     }
805 
806     /**
807      * Verify that we gracefully skip unknown section when reading a shared store file.
808      */
809     @Test
testReadShareStoreContainedUnknownSection()810     public void testReadShareStoreContainedUnknownSection() throws Exception {
811         String storeFileData =
812                 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
813                         + "<WifiConfigStoreData>\n"
814                         + "<int name=\"Version\" value=\"1\" />\n"
815                         + "<UnknownTag>\n"    // No StoreData registered to handle this tag.
816                         + "</UnknownTag>\n"
817                         + "</WifiConfigStoreData>\n";
818         mSharedStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8));
819         mWifiConfigStore.read();
820     }
821 
822     /**
823      * Tests the read API behaviour when the config store file is version 1.
824      * Expected behaviour: The read should be successful and send the data to the corresponding
825      *                     {@link StoreData} instance.
826      */
827     @Test
testReadVersion1StoreFile()828     public void testReadVersion1StoreFile() throws Exception {
829         // Register data container.
830         StoreData sharedStoreData = mock(StoreData.class);
831         when(sharedStoreData.getStoreFileId())
832                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
833         when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
834         when(sharedStoreData.getSectionsToParse())
835                 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
836         StoreData userStoreData = mock(StoreData.class);
837         when(userStoreData.getStoreFileId())
838                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
839         when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
840         when(userStoreData.getSectionsToParse())
841                 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
842         mWifiConfigStore.registerStoreData(sharedStoreData);
843         mWifiConfigStore.registerStoreData(userStoreData);
844 
845         // Read both share and user config store.
846         mWifiConfigStore.setUserStores(mUserStores);
847 
848         // Now store some content in the shared and user data files.
849         mUserStore.storeRawDataToWrite(
850                 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE,
851                         TEST_USER_DATA).getBytes());
852         mSharedStore.storeRawDataToWrite(
853                 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE,
854                         TEST_SHARE_DATA).getBytes());
855 
856         // Read and verify the data content in the store file (metadata stripped out) has been sent
857         // to the corresponding store data when integrity check passes.
858         mWifiConfigStore.read();
859         verify(sharedStoreData, times(1)).deserializeDataForSection(
860                 any(XmlPullParser.class), anyInt(),
861                 eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_SHARE_DATA));
862         verify(userStoreData, times(1)).deserializeDataForSection(
863                 any(XmlPullParser.class), anyInt(),
864                 eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_USER_DATA));
865     }
866 
867     /**
868      * Tests the read API behaviour to ensure that the integrity data is parsed from the file.
869      */
870     @Test
testReadVersion2StoreFile()871     public void testReadVersion2StoreFile() throws Exception {
872         byte[] encryptedData = new byte[0];
873         byte[] iv = new byte[0];
874         Random random = new Random();
875         random.nextBytes(encryptedData);
876         random.nextBytes(iv);
877 
878         // Register data container.
879         StoreData sharedStoreData = mock(StoreData.class);
880         when(sharedStoreData.getStoreFileId())
881                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
882         when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
883         when(sharedStoreData.getSectionsToParse())
884                 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
885         when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true);
886         StoreData userStoreData = mock(StoreData.class);
887         when(userStoreData.getStoreFileId())
888                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
889         when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
890         when(userStoreData.getSectionsToParse())
891                 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
892         when(userStoreData.hasNewDataToSerialize()).thenReturn(true);
893         mWifiConfigStore.registerStoreData(sharedStoreData);
894         mWifiConfigStore.registerStoreData(userStoreData);
895 
896         // Read both share and user config store.
897         mWifiConfigStore.setUserStores(mUserStores);
898 
899         // Now store some content in the shared and user data files with encrypted data from above.
900         mUserStore.storeRawDataToWrite(
901                 String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE,
902                         HexEncoding.encodeToString(encryptedData),
903                         HexEncoding.encodeToString(iv),
904                         TEST_USER_DATA).getBytes());
905         mSharedStore.storeRawDataToWrite(
906                 String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE,
907                         HexEncoding.encodeToString(encryptedData),
908                         HexEncoding.encodeToString(iv),
909                         TEST_SHARE_DATA).getBytes());
910 
911         // Read and verify the data content in the store file (metadata stripped out) has been sent
912         // to the corresponding store data.
913         mWifiConfigStore.read();
914         verify(sharedStoreData, times(1))
915                 .deserializeDataForSection(any(XmlPullParser.class), anyInt(),
916                         eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(),
917                         eq(TEST_SHARE_DATA));
918         verify(userStoreData, times(1))
919                 .deserializeDataForSection(any(XmlPullParser.class), anyInt(),
920                         eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(),
921                         eq(TEST_USER_DATA));
922     }
923 
924     /**
925      * Tests the complete migration path all the way from reading from the migration stream to
926      * parsing the XML data and sending it to the appropriate registered data sources.
927      */
928     @Test
testMigration()929     public void testMigration() throws Exception {
930         // Setup both shared & user store migrations.
931         StoreFile sharedStoreFile1 = mock(StoreFile.class);
932         when(sharedStoreFile1.getFileId())
933                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
934         StoreFile sharedStoreFile2 = mock(StoreFile.class);
935         when(sharedStoreFile2.getFileId())
936                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_SOFTAP);
937         StoreFile userStoreFile1 = mock(StoreFile.class);
938         when(userStoreFile1.getFileId())
939                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
940         StoreFile userStoreFile2 = mock(StoreFile.class);
941         when(userStoreFile2.getFileId())
942                 .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS);
943         mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock,
944                 mWifiMetrics, Arrays.asList(sharedStoreFile1, sharedStoreFile2));
945         mWifiConfigStore.setUserStores(Arrays.asList(userStoreFile1, userStoreFile2));
946 
947         // Register data container.
948         StoreData sharedStoreData = mock(StoreData.class);
949         when(sharedStoreData.getStoreFileId())
950                 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL);
951         when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA);
952         when(sharedStoreData.getSectionsToParse())
953                 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA)));
954         StoreData userStoreData = mock(StoreData.class);
955         when(userStoreData.getStoreFileId())
956                 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL);
957         when(userStoreData.getName()).thenReturn(TEST_USER_DATA);
958         when(userStoreData.getSectionsToParse())
959                 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA)));
960         mWifiConfigStore.registerStoreData(sharedStoreData);
961         mWifiConfigStore.registerStoreData(userStoreData);
962 
963         // Migration data
964         InputStream sharedStream1 = mock(InputStream.class);
965         InputStream sharedStream2 = mock(InputStream.class);
966         InputStream userStream1 = mock(InputStream.class);
967         InputStream userStream2 = mock(InputStream.class);
968         when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(
969                 WifiMigration.STORE_FILE_SHARED_GENERAL))
970                 .thenReturn(sharedStream1);
971         when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(
972                 WifiMigration.STORE_FILE_SHARED_SOFTAP))
973                 .thenReturn(sharedStream2);
974         when(WifiMigration.convertAndRetrieveUserConfigStoreFile(
975                 eq(WifiMigration.STORE_FILE_USER_GENERAL), any()))
976                 .thenReturn(userStream1);
977         when(WifiMigration.convertAndRetrieveUserConfigStoreFile(
978                 eq(WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS), any()))
979                 .thenReturn(userStream2);
980 
981         byte[] sharedStoreXmlBytes =
982                 String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE,
983                         TEST_SHARE_DATA).getBytes();
984         byte[] userStoreXmlBytes =
985                 String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE,
986                         TEST_USER_DATA).getBytes();
987         when(sharedStream1.available())
988                 .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0.
989                 .thenReturn(0);
990         when(sharedStream2.available())
991                 .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0.
992                 .thenReturn(0);
993         when(userStream1.available())
994                 .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0.
995                 .thenReturn(0);
996         when(userStream2.available())
997                 .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0.
998                 .thenReturn(0);
999         Answer sharedStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() {
1000             public int answer(byte[] b, int off, int len) {
1001                 System.arraycopy(sharedStoreXmlBytes, 0, b, 0, sharedStoreXmlBytes.length);
1002                 return sharedStoreXmlBytes.length;
1003             }
1004         };
1005         Answer userStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() {
1006             public int answer(byte[] b, int off, int len) {
1007                 System.arraycopy(userStoreXmlBytes, 0, b, 0, userStoreXmlBytes.length);
1008                 return userStoreXmlBytes.length;
1009             }
1010         };
1011         when(sharedStream1.read(any(byte[].class), anyInt(), anyInt()))
1012                 .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0.
1013                 .thenReturn(0);
1014         when(sharedStream2.read(any(byte[].class), anyInt(), anyInt()))
1015                 .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0.
1016                 .thenReturn(0);
1017         when(userStream1.read(any(byte[].class), anyInt(), anyInt()))
1018                 .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0.
1019                 .thenReturn(0);
1020         when(userStream2.read(any(byte[].class), anyInt(), anyInt()))
1021                 .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0.
1022                 .thenReturn(0);
1023 
1024         // Trigger read.
1025         mWifiConfigStore.read();
1026 
1027         // Verify that we read the data out of all the migration streams & we didn't read
1028         // from the files on disk.
1029         verify(sharedStream1, times(2)).available();
1030         verify(sharedStream1, times(2)).read(any(), anyInt(), anyInt());
1031         verify(sharedStream2, times(2)).available();
1032         verify(sharedStream2, times(2)).read(any(), anyInt(), anyInt());
1033         verify(userStream1, times(2)).available();
1034         verify(userStream1, times(2)).read(any(), anyInt(), anyInt());
1035         verify(userStream2, times(2)).available();
1036         verify(userStream2, times(2)).read(any(), anyInt(), anyInt());
1037 
1038         // Verify that we correctly deserialized the data and sent it to the corresponding sources.
1039         verify(sharedStoreData, times(1))
1040                 .deserializeDataForSection(any(XmlPullParser.class), anyInt(),
1041                         eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(),
1042                         eq(TEST_SHARE_DATA));
1043         verify(userStoreData, times(1))
1044                 .deserializeDataForSection(any(XmlPullParser.class), anyInt(),
1045                         eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(),
1046                         eq(TEST_USER_DATA));
1047 
1048         // Verify we did not read from the real store files.
1049         verify(sharedStoreFile1, never()).readRawData();
1050         verify(sharedStoreFile2, never()).readRawData();
1051         verify(userStoreFile1, never()).readRawData();
1052         verify(userStoreFile2, never()).readRawData();
1053     }
1054 
1055     /**
1056      * Mock Store File to redirect all file writes from WifiConfigStore to local buffers.
1057      * This can be used to examine the data output by WifiConfigStore.
1058      */
1059     private class MockStoreFile extends StoreFile {
1060         private byte[] mStoreBytes;
1061         private boolean mStoreWritten;
1062 
MockStoreFile(@ifiConfigStore.StoreFileId int fileId)1063         MockStoreFile(@WifiConfigStore.StoreFileId int fileId) {
1064             super(new File("MockStoreFile"), fileId, UserHandle.ALL, mEncryptionUtil);
1065         }
1066 
1067         @Override
readRawData()1068         public byte[] readRawData() {
1069             return mStoreBytes;
1070         }
1071 
1072         @Override
storeRawDataToWrite(byte[] data)1073         public void storeRawDataToWrite(byte[] data) {
1074             mStoreBytes = data;
1075             mStoreWritten = false;
1076         }
1077 
1078         @Override
writeBufferedRawData()1079         public void writeBufferedRawData() {
1080             if (!ArrayUtils.isEmpty(mStoreBytes)) {
1081                 mStoreWritten = true;
1082             }
1083         }
1084 
getStoreBytes()1085         public byte[] getStoreBytes() {
1086             return mStoreBytes;
1087         }
1088 
isStoreWritten()1089         public boolean isStoreWritten() {
1090             return mStoreWritten;
1091         }
1092     }
1093 
1094     /**
1095      * Mock data container for providing test data for the store file.
1096      */
1097     private class MockStoreData implements StoreData {
1098         private static final String XML_TAG_TEST_HEADER = "TestHeader";
1099         private static final String XML_TAG_TEST_DATA = "TestData";
1100 
1101         private @WifiConfigStore.StoreFileId int mFileId;
1102         private String mData;
1103         private boolean mHasAnyNewData = true;
1104 
MockStoreData(@ifiConfigStore.StoreFileId int fileId)1105         MockStoreData(@WifiConfigStore.StoreFileId int fileId) {
1106             mFileId = fileId;
1107         }
1108 
1109         @Override
serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)1110         public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)
1111                 throws XmlPullParserException, IOException {
1112             XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mData);
1113         }
1114 
1115         @Override
deserializeData(XmlPullParser in, int outerTagDepth, int version, WifiConfigStoreEncryptionUtil encryptionUtil)1116         public void deserializeData(XmlPullParser in, int outerTagDepth, int version,
1117                 WifiConfigStoreEncryptionUtil encryptionUtil)
1118                 throws XmlPullParserException, IOException {
1119             if (in == null) {
1120                 return;
1121             }
1122             mData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA);
1123         }
1124 
1125         @Override
resetData()1126         public void resetData() {
1127             mData = null;
1128         }
1129 
1130         @Override
hasNewDataToSerialize()1131         public boolean hasNewDataToSerialize() {
1132             return mHasAnyNewData;
1133         }
1134 
1135         @Override
getName()1136         public String getName() {
1137             return XML_TAG_TEST_HEADER;
1138         }
1139 
1140         @Override
getStoreFileId()1141         public @WifiConfigStore.StoreFileId int getStoreFileId() {
1142             return mFileId;
1143         }
1144 
getData()1145         public String getData() {
1146             return mData;
1147         }
1148 
setData(String data)1149         public void setData(String data) {
1150             mData = data;
1151         }
1152 
setHasAnyNewData(boolean hasAnyNewData)1153         public void setHasAnyNewData(boolean hasAnyNewData) {
1154             mHasAnyNewData = hasAnyNewData;
1155         }
1156     }
1157 
1158     /**
1159      * Verify dump will not crash when no UserStores set.
1160      */
1161     @Test
testDump()1162     public void testDump() {
1163         final FileDescriptor fd = new FileDescriptor();
1164         final FileOutputStream fout = new FileOutputStream(fd);
1165         final PrintWriter pw = new FastPrintWriter(fout);
1166         mWifiConfigStore.dump(fd, pw, new String[0]);
1167 
1168         mWifiConfigStore.setUserStores(mUserStores);
1169         mWifiConfigStore.dump(fd, pw, new String[0]);
1170     }
1171 }
1172