13fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi/*
23fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Copyright (C) 2017 The Android Open Source Project
33fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi *
43fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Licensed under the Apache License, Version 2.0 (the "License");
53fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * you may not use this file except in compliance with the License.
63fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * You may obtain a copy of the License at
73fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi *
83fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi *      http://www.apache.org/licenses/LICENSE-2.0
93fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi *
103fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Unless required by applicable law or agreed to in writing, software
113fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * distributed under the License is distributed on an "AS IS" BASIS,
123fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * See the License for the specific language governing permissions and
143fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * limitations under the License.
153fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */
163fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
173fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichipackage com.android.server.connectivity;
183fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
193fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.junit.Assert.assertFalse;
203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.junit.Assert.assertNull;
213fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.junit.Assert.assertTrue;
223fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.any;
233fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.eq;
243fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.times;
253fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.verify;
263fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.verifyNoMoreInteractions;
273fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport static org.mockito.Mockito.when;
283fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
293fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.net.ConnectivityManager;
303fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.net.InterfaceConfiguration;
313fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.net.LinkAddress;
323fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.net.LinkProperties;
333fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.net.NetworkInfo;
343fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.os.Handler;
353fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.os.INetworkManagementService;
363fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.os.test.TestLooper;
373fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.support.test.filters.SmallTest;
383fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport android.support.test.runner.AndroidJUnit4;
393fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
403fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport com.android.server.ConnectivityService;
413fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
423fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.junit.Before;
433fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.junit.Test;
443fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.junit.runner.RunWith;
453fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.mockito.ArgumentCaptor;
463fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.mockito.Mock;
473fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport org.mockito.MockitoAnnotations;
483fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
493fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi@RunWith(AndroidJUnit4.class)
503fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi@SmallTest
513fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichipublic class Nat464XlatTest {
523fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
533fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    static final String BASE_IFACE = "test0";
543fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    static final String STACKED_IFACE = "v4-test0";
553fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
563fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
573fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Mock ConnectivityService mConnectivity;
583fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Mock INetworkManagementService mNms;
593fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Mock InterfaceConfiguration mConfig;
603fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Mock NetworkAgentInfo mNai;
613fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
623fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    TestLooper mLooper;
633fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    Handler mHandler;
643fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
653fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    Nat464Xlat makeNat464Xlat() {
663fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        return new Nat464Xlat(mNms, mNai);
673fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
683fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
693fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Before
703fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    public void setUp() throws Exception {
713fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper = new TestLooper();
723fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mHandler = new Handler(mLooper.getLooper());
733fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
743fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        MockitoAnnotations.initMocks(this);
753fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
763fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mNai.linkProperties = new LinkProperties();
773fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mNai.linkProperties.setInterfaceName(BASE_IFACE);
783fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mNai.networkInfo = new NetworkInfo(null);
793fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
803fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        when(mNai.connService()).thenReturn(mConnectivity);
813fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        when(mNai.handler()).thenReturn(mHandler);
823fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
833fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
843fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        when(mConfig.getLinkAddress()).thenReturn(ADDR);
853fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
863fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
873fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Test
883fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    public void testNormalStartAndStop() throws Exception {
893fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        Nat464Xlat nat = makeNat464Xlat();
903fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
913fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
923fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService starts clat.
933fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.start();
943fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
953fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).registerObserver(eq(nat));
963fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).startClatd(eq(BASE_IFACE));
973fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
983fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // Stacked interface up notification arrives.
993fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceLinkStateChanged(STACKED_IFACE, true);
1003fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1013fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1023fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
1033fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
1043fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
1053fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertFalse(c.getValue().getStackedLinks().isEmpty());
1063fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
1073fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertRunning(nat);
1083fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1093fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
1103fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.stop();
1113fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1123fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).stopClatd(eq(BASE_IFACE));
1133fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
1143fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1153fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // Stacked interface removed notification arrives.
1163fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceRemoved(STACKED_IFACE);
1173fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1183fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1193fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).unregisterObserver(eq(nat));
1203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
1213fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue(c.getValue().getStackedLinks().isEmpty());
1223fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
1233fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertIdle(nat);
1243fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1253fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verifyNoMoreInteractions(mNms, mConnectivity);
1263fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
1273fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1283fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Test
1293fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    public void testClatdCrashWhileRunning() throws Exception {
1303fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        Nat464Xlat nat = makeNat464Xlat();
1313fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
1323fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1333fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService starts clat.
1343fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.start();
1353fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1363fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).registerObserver(eq(nat));
1373fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).startClatd(eq(BASE_IFACE));
1383fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1393fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // Stacked interface up notification arrives.
1403fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceLinkStateChanged(STACKED_IFACE, true);
1413fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1423fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1433fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
1443fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
1453fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
1463fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertFalse(c.getValue().getStackedLinks().isEmpty());
1473fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
1483fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertRunning(nat);
1493fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1503fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // Stacked interface removed notification arrives (clatd crashed, ...).
1513fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceRemoved(STACKED_IFACE);
1523fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1533fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1543fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).unregisterObserver(eq(nat));
1553fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).stopClatd(eq(BASE_IFACE));
1563fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
1573fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
1583fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue(c.getValue().getStackedLinks().isEmpty());
1593fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
1603fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertIdle(nat);
1613fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1623fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService stops clat: no-op.
1633fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.stop();
1643fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1653fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verifyNoMoreInteractions(mNms, mConnectivity);
1663fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
1673fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1683fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Test
1693fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    public void testStopBeforeClatdStarts() throws Exception {
1703fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        Nat464Xlat nat = makeNat464Xlat();
1713fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1723fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService starts clat.
1733fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.start();
1743fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1753fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).registerObserver(eq(nat));
1763fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).startClatd(eq(BASE_IFACE));
1773fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1783fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
1793fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.stop();
1803fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1813fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).unregisterObserver(eq(nat));
1823fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).stopClatd(eq(BASE_IFACE));
1833fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertIdle(nat);
1843fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1853fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // In-flight interface up notification arrives: no-op
1863fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceLinkStateChanged(STACKED_IFACE, true);
1873fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1883fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1893fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1903fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // Interface removed notification arrives after stopClatd() takes effect: no-op.
1913fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.interfaceRemoved(STACKED_IFACE);
1923fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        mLooper.dispatchNext();
1933fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1943fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertIdle(nat);
1953fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1963fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verifyNoMoreInteractions(mNms, mConnectivity);
1973fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
1983fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
1993fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    @Test
2003fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    public void testStopAndClatdNeverStarts() throws Exception {
2013fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        Nat464Xlat nat = makeNat464Xlat();
2023fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2033fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService starts clat.
2043fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.start();
2053fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2063fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).registerObserver(eq(nat));
2073fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).startClatd(eq(BASE_IFACE));
2083fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2093fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
2103fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        nat.stop();
2113fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2123fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).unregisterObserver(eq(nat));
2133fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verify(mNms).stopClatd(eq(BASE_IFACE));
2143fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertIdle(nat);
2153fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2163fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        verifyNoMoreInteractions(mNms, mConnectivity);
2173fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
2183fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2193fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    static void assertIdle(Nat464Xlat nat) {
2203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
2213fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
2223fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi
2233fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    static void assertRunning(Nat464Xlat nat) {
2243fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi        assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
2253fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi    }
2263fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi}
227