• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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.google.android.iwlan.epdg;
18 
19 import static android.net.DnsResolver.TYPE_A;
20 import static android.net.DnsResolver.TYPE_AAAA;
21 
22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
23 
24 import static org.junit.Assert.*;
25 import static org.mockito.Mockito.*;
26 
27 import static java.util.stream.Collectors.toList;
28 
29 import android.content.Context;
30 import android.content.SharedPreferences;
31 import android.net.DnsResolver;
32 import android.net.InetAddresses;
33 import android.net.Network;
34 import android.os.Handler;
35 import android.os.Looper;
36 import android.os.PersistableBundle;
37 import android.telephony.CarrierConfigManager;
38 import android.telephony.CellIdentityGsm;
39 import android.telephony.CellIdentityLte;
40 import android.telephony.CellIdentityNr;
41 import android.telephony.CellIdentityWcdma;
42 import android.telephony.CellInfo;
43 import android.telephony.CellInfoGsm;
44 import android.telephony.CellInfoLte;
45 import android.telephony.CellInfoNr;
46 import android.telephony.CellInfoWcdma;
47 import android.telephony.SubscriptionInfo;
48 import android.telephony.SubscriptionManager;
49 import android.telephony.TelephonyManager;
50 import android.util.Log;
51 
52 import com.google.android.iwlan.ErrorPolicyManager;
53 import com.google.android.iwlan.IwlanError;
54 
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.mockito.Mock;
59 import org.mockito.MockitoAnnotations;
60 import org.mockito.MockitoSession;
61 import org.mockito.invocation.InvocationOnMock;
62 import org.mockito.stubbing.Answer;
63 
64 import java.net.InetAddress;
65 import java.net.UnknownHostException;
66 import java.util.*;
67 import java.util.concurrent.CountDownLatch;
68 import java.util.concurrent.Executor;
69 import java.util.concurrent.TimeUnit;
70 
71 public class EpdgSelectorTest {
72     private static final String TAG = "EpdgSelectorTest";
73     private EpdgSelector mEpdgSelector;
74     public static final int DEFAULT_SLOT_INDEX = 0;
75 
76     private static final String TEST_IP_ADDRESS = "127.0.0.1";
77     private static final String TEST_IP_ADDRESS_1 = "127.0.0.2";
78     private static final String TEST_IP_ADDRESS_2 = "127.0.0.3";
79     private static final String TEST_IP_ADDRESS_3 = "127.0.0.4";
80     private static final String TEST_IP_ADDRESS_4 = "127.0.0.5";
81     private static final String TEST_IP_ADDRESS_5 = "127.0.0.6";
82     private static final String TEST_IPV6_ADDRESS = "0000:0000:0000:0000:0000:0000:0000:0001";
83 
84     private static int testPcoIdIPv6 = 0xFF01;
85     private static int testPcoIdIPv4 = 0xFF02;
86 
87     private String testPcoString = "testPcoData";
88     private byte[] pcoData = testPcoString.getBytes();
89     private List<String> ehplmnList = new ArrayList<String>();
90 
91     @Mock private Context mMockContext;
92     @Mock private Network mMockNetwork;
93     @Mock private ErrorPolicyManager mMockErrorPolicyManager;
94     @Mock private SubscriptionManager mMockSubscriptionManager;
95     @Mock private SubscriptionInfo mMockSubscriptionInfo;
96     @Mock private CarrierConfigManager mMockCarrierConfigManager;
97     @Mock private TelephonyManager mMockTelephonyManager;
98     @Mock private SharedPreferences mMockSharedPreferences;
99     @Mock private CellInfoGsm mMockCellInfoGsm;
100     @Mock private CellIdentityGsm mMockCellIdentityGsm;
101     @Mock private CellInfoWcdma mMockCellInfoWcdma;
102     @Mock private CellIdentityWcdma mMockCellIdentityWcdma;
103     @Mock private CellInfoLte mMockCellInfoLte;
104     @Mock private CellIdentityLte mMockCellIdentityLte;
105     @Mock private CellInfoNr mMockCellInfoNr;
106     @Mock private CellIdentityNr mMockCellIdentityNr;
107     @Mock private DnsResolver mMockDnsResolver;
108 
109     private PersistableBundle mTestBundle;
110     private FakeDns mFakeDns;
111     MockitoSession mStaticMockSession;
112 
113     @Before
setUp()114     public void setUp() throws Exception {
115         MockitoAnnotations.initMocks(this);
116         mStaticMockSession =
117                 mockitoSession()
118                         .mockStatic(DnsResolver.class)
119                         .mockStatic(ErrorPolicyManager.class)
120                         .startMocking();
121 
122         when(ErrorPolicyManager.getInstance(mMockContext, DEFAULT_SLOT_INDEX))
123                 .thenReturn(mMockErrorPolicyManager);
124         mEpdgSelector = new EpdgSelector(mMockContext, DEFAULT_SLOT_INDEX);
125 
126         when(mMockContext.getSystemService(eq(SubscriptionManager.class)))
127                 .thenReturn(mMockSubscriptionManager);
128 
129         when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt()))
130                 .thenReturn(mMockSubscriptionInfo);
131 
132         when(mMockSubscriptionInfo.getMccString()).thenReturn("311");
133 
134         when(mMockSubscriptionInfo.getMncString()).thenReturn("120");
135 
136         when(mMockContext.getSystemService(eq(TelephonyManager.class)))
137                 .thenReturn(mMockTelephonyManager);
138 
139         when(mMockTelephonyManager.createForSubscriptionId(anyInt()))
140                 .thenReturn(mMockTelephonyManager);
141 
142         ehplmnList.add("300120");
143         when(mMockTelephonyManager.getEquivalentHomePlmns()).thenReturn(ehplmnList);
144 
145         when(mMockTelephonyManager.getSimCountryIso()).thenReturn("ca");
146 
147         when(mMockContext.getSharedPreferences(anyString(), anyInt()))
148                 .thenReturn(mMockSharedPreferences);
149 
150         when(mMockSharedPreferences.getString(any(), any())).thenReturn("US");
151 
152         // Mock carrier configs with test bundle
153         mTestBundle = new PersistableBundle();
154         when(mMockContext.getSystemService(eq(CarrierConfigManager.class)))
155                 .thenReturn(mMockCarrierConfigManager);
156         when(mMockCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mTestBundle);
157 
158         lenient().when(DnsResolver.getInstance()).thenReturn(mMockDnsResolver);
159 
160         mFakeDns = new FakeDns();
161         mFakeDns.startMocking();
162     }
163 
164     @After
cleanUp()165     public void cleanUp() throws Exception {
166         mStaticMockSession.finishMocking();
167         mFakeDns.clearAll();
168     }
169 
170     @Test
testStaticMethodPass()171     public void testStaticMethodPass() throws Exception {
172         // Set DnsResolver query mock
173         final String testStaticAddress = "epdg.epc.mnc088.mcc888.pub.3gppnetwork.org";
174         mFakeDns.setAnswer(testStaticAddress, new String[] {TEST_IP_ADDRESS}, TYPE_A);
175 
176         // Set carrier config mock
177         mTestBundle.putIntArray(
178                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
179                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_STATIC});
180         mTestBundle.putString(
181                 CarrierConfigManager.Iwlan.KEY_EPDG_STATIC_ADDRESS_STRING, testStaticAddress);
182 
183         ArrayList<InetAddress> testInetAddresses =
184                 getValidatedServerListWithDefaultParams(false /*isEmergency*/);
185 
186         InetAddress expectedAddress = InetAddress.getByName(TEST_IP_ADDRESS);
187 
188         assertEquals(testInetAddresses.size(), 1);
189         assertEquals(testInetAddresses.get(0), expectedAddress);
190     }
191 
192     @Test
testRoamStaticMethodPass()193     public void testRoamStaticMethodPass() throws Exception {
194         // Set DnsResolver query mock
195         final String testRoamStaticAddress = "epdg.epc.mnc088.mcc888.pub.3gppnetwork.org";
196         mFakeDns.setAnswer(testRoamStaticAddress, new String[] {TEST_IP_ADDRESS}, TYPE_A);
197 
198         // Set carrier config mock
199         mTestBundle.putIntArray(
200                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
201                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_STATIC});
202         mTestBundle.putString(
203                 CarrierConfigManager.Iwlan.KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING,
204                 testRoamStaticAddress);
205 
206         ArrayList<InetAddress> testInetAddresses =
207                 getValidatedServerListWithDefaultParams(false /*isEmergency*/);
208 
209         InetAddress expectedAddress = InetAddress.getByName(TEST_IP_ADDRESS);
210 
211         assertEquals(testInetAddresses.size(), 1);
212         assertEquals(testInetAddresses.get(0), expectedAddress);
213     }
214 
215     @Test
testPlmnResolutionMethod()216     public void testPlmnResolutionMethod() throws Exception {
217         testPlmnResolutionMethod(false);
218     }
219 
220     @Test
testPlmnResolutionMethodForEmergency()221     public void testPlmnResolutionMethodForEmergency() throws Exception {
222         testPlmnResolutionMethod(true);
223     }
224 
225     @Test
testPlmnResolutionMethodWithNoPlmnInCarrierConfig()226     public void testPlmnResolutionMethodWithNoPlmnInCarrierConfig() throws Exception {
227         // setUp() fills default values for mcc-mnc
228         String expectedFqdn1 = "epdg.epc.mnc120.mcc311.pub.3gppnetwork.org";
229         String expectedFqdn2 = "epdg.epc.mnc120.mcc300.pub.3gppnetwork.org";
230 
231         mFakeDns.setAnswer(expectedFqdn1, new String[] {TEST_IP_ADDRESS_1}, TYPE_A);
232         mFakeDns.setAnswer(expectedFqdn2, new String[] {TEST_IP_ADDRESS_2}, TYPE_A);
233 
234         ArrayList<InetAddress> testInetAddresses =
235                 getValidatedServerListWithDefaultParams(false /*isEmergency*/);
236 
237         assertEquals(testInetAddresses.size(), 2);
238         assertTrue(testInetAddresses.contains(InetAddress.getByName(TEST_IP_ADDRESS_1)));
239         assertTrue(testInetAddresses.contains(InetAddress.getByName(TEST_IP_ADDRESS_2)));
240     }
241 
testPlmnResolutionMethod(boolean isEmergency)242     private void testPlmnResolutionMethod(boolean isEmergency) throws Exception {
243         String expectedFqdnFromHplmn = "epdg.epc.mnc120.mcc311.pub.3gppnetwork.org";
244         String expectedFqdnFromEHplmn = "epdg.epc.mnc120.mcc300.pub.3gppnetwork.org";
245         String expectedFqdnFromConfig = "epdg.epc.mnc480.mcc310.pub.3gppnetwork.org";
246 
247         mTestBundle.putIntArray(
248                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
249                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_PLMN});
250         mTestBundle.putStringArray(
251                 CarrierConfigManager.Iwlan.KEY_MCC_MNCS_STRING_ARRAY,
252                 new String[] {"310-480", "300-120", "311-120"});
253 
254         mFakeDns.setAnswer(expectedFqdnFromHplmn, new String[] {TEST_IP_ADDRESS}, TYPE_A);
255         mFakeDns.setAnswer(expectedFqdnFromEHplmn, new String[] {TEST_IP_ADDRESS_1}, TYPE_A);
256         mFakeDns.setAnswer(expectedFqdnFromConfig, new String[] {TEST_IP_ADDRESS_2}, TYPE_A);
257         mFakeDns.setAnswer(
258                 "sos." + expectedFqdnFromHplmn, new String[] {TEST_IP_ADDRESS_3}, TYPE_A);
259         mFakeDns.setAnswer(
260                 "sos." + expectedFqdnFromEHplmn, new String[] {TEST_IP_ADDRESS_4}, TYPE_A);
261         mFakeDns.setAnswer(
262                 "sos." + expectedFqdnFromConfig, new String[] {TEST_IP_ADDRESS_5}, TYPE_A);
263 
264         ArrayList<InetAddress> testInetAddresses =
265                 getValidatedServerListWithDefaultParams(isEmergency);
266 
267         if (isEmergency) {
268             assertEquals(6, testInetAddresses.size());
269             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_3), testInetAddresses.get(0));
270             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS), testInetAddresses.get(1));
271             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_4), testInetAddresses.get(2));
272             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_1), testInetAddresses.get(3));
273             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_5), testInetAddresses.get(4));
274             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_2), testInetAddresses.get(5));
275         } else {
276             assertEquals(3, testInetAddresses.size());
277             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS), testInetAddresses.get(0));
278             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_1), testInetAddresses.get(1));
279             assertEquals(InetAddress.getByName(TEST_IP_ADDRESS_2), testInetAddresses.get(2));
280         }
281     }
282 
283     @Test
testCarrierConfigStaticAddressList()284     public void testCarrierConfigStaticAddressList() throws Exception {
285         // Set Network.getAllByName mock
286         final String addr1 = "epdg.epc.mnc480.mcc310.pub.3gppnetwork.org";
287         final String addr2 = "epdg.epc.mnc120.mcc300.pub.3gppnetwork.org";
288         final String addr3 = "epdg.epc.mnc120.mcc311.pub.3gppnetwork.org";
289         final String testStaticAddress = addr1 + "," + addr2 + "," + addr3;
290 
291         mFakeDns.setAnswer(addr1, new String[] {TEST_IP_ADDRESS_1}, TYPE_A);
292         mFakeDns.setAnswer(addr2, new String[] {TEST_IP_ADDRESS_2}, TYPE_A);
293         mFakeDns.setAnswer(addr3, new String[] {TEST_IP_ADDRESS}, TYPE_A);
294 
295         // Set carrier config mock
296         mTestBundle.putIntArray(
297                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
298                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_STATIC});
299         mTestBundle.putString(
300                 CarrierConfigManager.Iwlan.KEY_EPDG_STATIC_ADDRESS_STRING, testStaticAddress);
301 
302         ArrayList<InetAddress> testInetAddresses =
303                 getValidatedServerListWithDefaultParams(false /*isEmergency*/);
304 
305         assertEquals(testInetAddresses.size(), 3);
306         assertEquals(testInetAddresses.get(0), InetAddress.getByName(TEST_IP_ADDRESS_1));
307         assertEquals(testInetAddresses.get(1), InetAddress.getByName(TEST_IP_ADDRESS_2));
308         assertEquals(testInetAddresses.get(2), InetAddress.getByName(TEST_IP_ADDRESS));
309     }
310 
getValidatedServerListWithDefaultParams(boolean isEmergency)311     private ArrayList<InetAddress> getValidatedServerListWithDefaultParams(boolean isEmergency)
312             throws Exception {
313         ArrayList<InetAddress> testInetAddresses = new ArrayList<InetAddress>();
314         final CountDownLatch latch = new CountDownLatch(1);
315         IwlanError ret =
316                 mEpdgSelector.getValidatedServerList(
317                         1234,
318                         EpdgSelector.PROTO_FILTER_IPV4V6,
319                         false /* isRoaming */,
320                         isEmergency,
321                         mMockNetwork,
322                         new EpdgSelector.EpdgSelectorCallback() {
323                             @Override
324                             public void onServerListChanged(
325                                     int transactionId, ArrayList<InetAddress> validIPList) {
326                                 assertEquals(transactionId, 1234);
327 
328                                 for (InetAddress mInetAddress : validIPList) {
329                                     testInetAddresses.add(mInetAddress);
330                                 }
331                                 Log.d(TAG, "onServerListChanged received");
332                                 latch.countDown();
333                             }
334 
335                             @Override
336                             public void onError(int transactionId, IwlanError epdgSelectorError) {
337                                 Log.d(TAG, "onError received");
338                                 latch.countDown();
339                             }
340                         });
341 
342         assertEquals(ret.getErrorType(), IwlanError.NO_ERROR);
343         latch.await(1, TimeUnit.SECONDS);
344         return testInetAddresses;
345     }
346 
347     @Test
testSetPcoData()348     public void testSetPcoData() throws Exception {
349         addTestPcoIdsToTestConfigBundle();
350 
351         boolean retIPv6 = mEpdgSelector.setPcoData(testPcoIdIPv6, pcoData);
352         boolean retIPv4 = mEpdgSelector.setPcoData(testPcoIdIPv4, pcoData);
353         boolean retIncorrect = mEpdgSelector.setPcoData(0xFF00, pcoData);
354 
355         assertTrue(retIPv6);
356         assertTrue(retIPv4);
357         assertFalse(retIncorrect);
358     }
359 
360     @Test
testPcoResolutionMethod()361     public void testPcoResolutionMethod() throws Exception {
362         mTestBundle.putIntArray(
363                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
364                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_PCO});
365         addTestPcoIdsToTestConfigBundle();
366 
367         mEpdgSelector.clearPcoData();
368         boolean retIPv6 =
369                 mEpdgSelector.setPcoData(
370                         testPcoIdIPv6, InetAddress.getByName(TEST_IPV6_ADDRESS).getAddress());
371         boolean retIPv4 =
372                 mEpdgSelector.setPcoData(
373                         testPcoIdIPv4, InetAddress.getByName(TEST_IP_ADDRESS).getAddress());
374 
375         ArrayList<InetAddress> testInetAddresses =
376                 getValidatedServerListWithDefaultParams(false /* isEmergency */);
377 
378         assertEquals(testInetAddresses.size(), 2);
379         assertTrue(testInetAddresses.contains(InetAddress.getByName(TEST_IP_ADDRESS)));
380         assertTrue(testInetAddresses.contains(InetAddress.getByName(TEST_IPV6_ADDRESS)));
381     }
382 
addTestPcoIdsToTestConfigBundle()383     private void addTestPcoIdsToTestConfigBundle() {
384         mTestBundle.putInt(CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV6_INT, testPcoIdIPv6);
385         mTestBundle.putInt(CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV4_INT, testPcoIdIPv4);
386     }
387 
388     @Test
testCellularResolutionMethod()389     public void testCellularResolutionMethod() throws Exception {
390         testCellularResolutionMethod(false);
391     }
392 
393     @Test
testCellularResolutionMethodForEmergency()394     public void testCellularResolutionMethodForEmergency() throws Exception {
395         testCellularResolutionMethod(true);
396     }
397 
testCellularResolutionMethod(boolean isEmergency)398     private void testCellularResolutionMethod(boolean isEmergency) throws Exception {
399         int testMcc = 311;
400         int testMnc = 120;
401         String testMccString = "311";
402         String testMncString = "120";
403         int testLac = 65484;
404         int testTac = 65484;
405         int testNrTac = 16764074;
406 
407         List<CellInfo> fakeCellInfoArray = new ArrayList<CellInfo>();
408 
409         mTestBundle.putIntArray(
410                 CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
411                 new int[] {CarrierConfigManager.Iwlan.EPDG_ADDRESS_CELLULAR_LOC});
412 
413         // Set cell info mock
414         fakeCellInfoArray.add(mMockCellInfoGsm);
415         when(mMockCellInfoGsm.isRegistered()).thenReturn(true);
416         when(mMockCellInfoGsm.getCellIdentity()).thenReturn(mMockCellIdentityGsm);
417         when(mMockCellIdentityGsm.getMcc()).thenReturn(testMcc);
418         when(mMockCellIdentityGsm.getMnc()).thenReturn(testMnc);
419         when(mMockCellIdentityGsm.getLac()).thenReturn(testLac);
420 
421         fakeCellInfoArray.add(mMockCellInfoWcdma);
422         when(mMockCellInfoWcdma.isRegistered()).thenReturn(true);
423         when(mMockCellInfoWcdma.getCellIdentity()).thenReturn(mMockCellIdentityWcdma);
424         when(mMockCellIdentityWcdma.getMcc()).thenReturn(testMcc);
425         when(mMockCellIdentityWcdma.getMnc()).thenReturn(testMnc);
426         when(mMockCellIdentityWcdma.getLac()).thenReturn(testLac);
427 
428         fakeCellInfoArray.add(mMockCellInfoLte);
429         when(mMockCellInfoLte.isRegistered()).thenReturn(true);
430         when(mMockCellInfoLte.getCellIdentity()).thenReturn(mMockCellIdentityLte);
431         when(mMockCellIdentityLte.getMcc()).thenReturn(testMcc);
432         when(mMockCellIdentityLte.getMnc()).thenReturn(testMnc);
433         when(mMockCellIdentityLte.getTac()).thenReturn(testTac);
434 
435         fakeCellInfoArray.add(mMockCellInfoNr);
436         when(mMockCellInfoNr.isRegistered()).thenReturn(true);
437         when(mMockCellInfoNr.getCellIdentity()).thenReturn(mMockCellIdentityNr);
438         when(mMockCellIdentityNr.getMccString()).thenReturn(testMccString);
439         when(mMockCellIdentityNr.getMncString()).thenReturn(testMncString);
440         when(mMockCellIdentityNr.getTac()).thenReturn(testNrTac);
441 
442         when(mMockTelephonyManager.getAllCellInfo()).thenReturn(fakeCellInfoArray);
443 
444         setAnswerForCellularMethod(isEmergency, 311, 120);
445         setAnswerForCellularMethod(isEmergency, 300, 120);
446 
447         ArrayList<InetAddress> testInetAddresses =
448                 getValidatedServerListWithDefaultParams(isEmergency);
449 
450         assertEquals(testInetAddresses.size(), 3);
451         assertEquals(testInetAddresses.get(0), InetAddress.getByName(TEST_IP_ADDRESS));
452         assertEquals(testInetAddresses.get(1), InetAddress.getByName(TEST_IP_ADDRESS_1));
453         assertEquals(testInetAddresses.get(2), InetAddress.getByName(TEST_IP_ADDRESS_2));
454     }
455 
setAnswerForCellularMethod(boolean isEmergency, int mcc, int mnc)456     private void setAnswerForCellularMethod(boolean isEmergency, int mcc, int mnc)
457             throws Exception {
458         String expectedFqdn1 =
459                 (isEmergency)
460                         ? "lacffcc.sos.epdg.epc.mnc" + mnc + ".mcc" + mcc + ".pub.3gppnetwork.org"
461                         : "lacffcc.epdg.epc.mnc" + mnc + ".mcc" + mcc + ".pub.3gppnetwork.org";
462         String expectedFqdn2 =
463                 (isEmergency)
464                         ? "tac-lbcc.tac-hbff.tac.sos.epdg.epc.mnc"
465                                 + mnc
466                                 + ".mcc"
467                                 + mcc
468                                 + ".pub.3gppnetwork.org"
469                         : "tac-lbcc.tac-hbff.tac.epdg.epc.mnc"
470                                 + mnc
471                                 + ".mcc"
472                                 + mcc
473                                 + ".pub.3gppnetwork.org";
474         String expectedFqdn3 =
475                 (isEmergency)
476                         ? "tac-lbaa.tac-mbcc.tac-hbff.5gstac.sos.epdg.epc.mnc"
477                                 + mnc
478                                 + ".mcc"
479                                 + mcc
480                                 + ".pub.3gppnetwork.org"
481                         : "tac-lbaa.tac-mbcc.tac-hbff.5gstac.epdg.epc.mnc"
482                                 + mnc
483                                 + ".mcc"
484                                 + mcc
485                                 + ".pub.3gppnetwork.org";
486 
487         mFakeDns.setAnswer(expectedFqdn1, new String[] {TEST_IP_ADDRESS}, TYPE_A);
488         mFakeDns.setAnswer(expectedFqdn2, new String[] {TEST_IP_ADDRESS_1}, TYPE_A);
489         mFakeDns.setAnswer(expectedFqdn3, new String[] {TEST_IP_ADDRESS_2}, TYPE_A);
490     }
491 
492     /**
493      * Fakes DNS responses.
494      *
495      * <p>Allows test methods to configure the IP addresses that will be resolved by
496      * Network#getAllByName and by DnsResolver#query.
497      */
498     class FakeDns {
499         /** Data class to record the Dns entry. */
500         class DnsEntry {
501             final String mHostname;
502             final int mType;
503             final List<InetAddress> mAddresses;
504 
DnsEntry(String host, int type, List<InetAddress> addr)505             DnsEntry(String host, int type, List<InetAddress> addr) {
506                 mHostname = host;
507                 mType = type;
508                 mAddresses = addr;
509             }
510             // Full match or partial match that target host contains the entry hostname to support
511             // random private dns probe hostname.
matches(String hostname, int type)512             private boolean matches(String hostname, int type) {
513                 return hostname.equals(mHostname) && type == mType;
514             }
515         }
516 
517         private final ArrayList<DnsEntry> mAnswers = new ArrayList<DnsEntry>();
518 
519         /** Clears all DNS entries. */
clearAll()520         private synchronized void clearAll() {
521             mAnswers.clear();
522         }
523 
524         /** Returns the answer for a given name and type on the given mock network. */
getAnswer(Object mock, String hostname, int type)525         private synchronized List<InetAddress> getAnswer(Object mock, String hostname, int type) {
526             return mAnswers.stream()
527                     .filter(e -> e.matches(hostname, type))
528                     .map(answer -> answer.mAddresses)
529                     .findFirst()
530                     .orElse(null);
531         }
532 
533         /** Sets the answer for a given name and type. */
setAnswer(String hostname, String[] answer, int type)534         private synchronized void setAnswer(String hostname, String[] answer, int type)
535                 throws UnknownHostException {
536             DnsEntry record = new DnsEntry(hostname, type, generateAnswer(answer));
537             // Remove the existing one.
538             mAnswers.removeIf(entry -> entry.matches(hostname, type));
539             // Add or replace a new record.
540             mAnswers.add(record);
541         }
542 
generateAnswer(String[] answer)543         private List<InetAddress> generateAnswer(String[] answer) {
544             if (answer == null) return new ArrayList<>();
545             return Arrays.stream(answer)
546                     .map(addr -> InetAddresses.parseNumericAddress(addr))
547                     .collect(toList());
548         }
549 
550         // Regardless of the type, depends on what the responses contained in the network.
queryAllTypes(Object mock, String hostname)551         private List<InetAddress> queryAllTypes(Object mock, String hostname) {
552             List<InetAddress> answer = new ArrayList<>();
553             addAllIfNotNull(answer, getAnswer(mock, hostname, TYPE_A));
554             addAllIfNotNull(answer, getAnswer(mock, hostname, TYPE_AAAA));
555             return answer;
556         }
557 
addAllIfNotNull(List<InetAddress> list, List<InetAddress> c)558         private void addAllIfNotNull(List<InetAddress> list, List<InetAddress> c) {
559             if (c != null) {
560                 list.addAll(c);
561             }
562         }
563 
564         /** Starts mocking DNS queries. */
startMocking()565         private void startMocking() throws UnknownHostException {
566             doAnswer(
567                             invocation -> {
568                                 return mockQuery(
569                                         invocation,
570                                         1 /* posHostname */,
571                                         3 /* posExecutor */,
572                                         5 /* posCallback */,
573                                         -1 /* posType */);
574                             })
575                     .when(mMockDnsResolver)
576                     .query(any(), any(), anyInt(), any(), any(), any());
577         }
578 
579         // Mocking queries on DnsResolver#query.
mockQuery( InvocationOnMock invocation, int posHostname, int posExecutor, int posCallback, int posType)580         private Answer mockQuery(
581                 InvocationOnMock invocation,
582                 int posHostname,
583                 int posExecutor,
584                 int posCallback,
585                 int posType) {
586             String hostname = (String) invocation.getArgument(posHostname);
587             Executor executor = (Executor) invocation.getArgument(posExecutor);
588             DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(posCallback);
589             List<InetAddress> answer;
590 
591             answer = queryAllTypes(invocation.getMock(), hostname);
592 
593             if (answer != null && answer.size() > 0) {
594                 new Handler(Looper.getMainLooper())
595                         .post(
596                                 () -> {
597                                     executor.execute(() -> callback.onAnswer(answer, 0));
598                                 });
599             }
600             // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
601             return null;
602         }
603     }
604 }
605