Add a test that brings up an L2cap server network

Test: TH
Change-Id: I9f2d750a822ce1790c9a766415ffc494a47d9287
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
index 489c3ad..32ba5c0 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
@@ -17,25 +17,34 @@
 package com.android.server
 
 import android.bluetooth.BluetoothAdapter
-import android.bluetooth.BluetoothManager
 import android.bluetooth.BluetoothServerSocket
 import android.bluetooth.BluetoothSocket
+import android.net.INetworkMonitor
+import android.net.INetworkMonitorCallbacks
+import android.net.IpPrefix
 import android.net.L2capNetworkSpecifier
 import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_6LOWPAN
 import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_NONE
 import android.net.L2capNetworkSpecifier.ROLE_SERVER
+import android.net.LinkAddress
+import android.net.LinkProperties
 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
 import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
 import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
 import android.net.NetworkRequest
 import android.net.NetworkSpecifier
+import android.net.RouteInfo
 import android.os.Build
 import android.os.HandlerThread
+import android.os.ParcelFileDescriptor
+import com.android.server.net.L2capNetwork.L2capIpClient
+import com.android.server.net.L2capPacketForwarder
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.DevSdkIgnoreRunner
 import com.android.testutils.RecorderCallback.CallbackEntry.Reserved
 import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable
 import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.anyNetwork
 import com.android.testutils.waitForIdle
 import java.io.IOException
 import java.util.Optional
@@ -47,10 +56,12 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.isNull
 import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.doThrow
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 
 private const val PSM = 0x85
 private val REMOTE_MAC = byteArrayOf(1, 2, 3, 4, 5, 6)
@@ -64,10 +75,16 @@
 @IgnoreUpTo(Build.VERSION_CODES.R)
 @DevSdkIgnoreRunner.MonitorThreadLeak
 class CSL2capProviderTest : CSTest() {
+    private val networkMonitor = mock<INetworkMonitor>()
+
     private val btAdapter = mock<BluetoothAdapter>()
     private val btServerSocket = mock<BluetoothServerSocket>()
     private val btSocket = mock<BluetoothSocket>()
+    private val tunInterface = mock<ParcelFileDescriptor>()
+    private val l2capIpClient = mock<L2capIpClient>()
+    private val packetForwarder = mock<L2capPacketForwarder>()
     private val providerDeps = mock<L2capNetworkProvider.Dependencies>()
+
     // BlockingQueue does not support put(null) operations, as null is used as an internal sentinel
     // value. Therefore, use Optional<BluetoothSocket> where an empty optional signals the
     // BluetoothServerSocket#close() operation.
@@ -96,6 +113,30 @@
         }.`when`(btServerSocket).close()
 
         doReturn(handlerThread).`when`(providerDeps).getHandlerThread()
+        doReturn(tunInterface).`when`(providerDeps).createTunInterface(any())
+        doReturn(packetForwarder).`when`(providerDeps)
+                .createL2capPacketForwarder(any(), any(), any(), any(), any())
+        doReturn(l2capIpClient).`when`(providerDeps).createL2capIpClient(any(), any(), any())
+
+        val lp = LinkProperties()
+        val ifname = "l2cap-tun0"
+        lp.setInterfaceName(ifname)
+        lp.addLinkAddress(LinkAddress("fe80::1/64"))
+        lp.addRoute(RouteInfo(IpPrefix("fe80::/64"), null /* nextHop */, ifname))
+        doReturn(lp).`when`(l2capIpClient).start()
+
+        // Note: In order to properly register a NetworkAgent, a NetworkMonitor must be created for
+        // the agent. CSAgentWrapper already does some of this, but requires adding additional
+        // Dependencies to the production code. Create a mocked NM inside this test instead.
+        doAnswer { i ->
+            val cb = i.arguments[2] as INetworkMonitorCallbacks
+            cb.onNetworkMonitorCreated(networkMonitor)
+        }.`when`(networkStack).makeNetworkMonitor(
+                any() /* network */,
+                isNull() /* name */,
+                any() /* callbacks */
+        )
+
         provider = L2capNetworkProvider(providerDeps, context)
         provider.start()
     }
@@ -241,4 +282,25 @@
         cb2.expect<Reserved>()
         cb2.assertNoCallback()
     }
+
+    @Test
+    fun testServerNetwork() {
+        val specifier = L2capNetworkSpecifier.Builder()
+                .setRole(ROLE_SERVER)
+                .setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
+                .build()
+        val nr = REQUEST.copyWithSpecifier(specifier)
+        val cb = reserveNetwork(nr)
+        cb.expect<Reserved>()
+
+        // Unblock BluetoothServerSocket#accept()
+        doReturn(true).`when`(btSocket).isConnected()
+        acceptQueue.put(Optional.of(btSocket))
+
+        cb.expectAvailableCallbacks(anyNetwork(), validated = false)
+        cb.assertNoCallback()
+        // Verify that packet forwarding was started.
+        // TODO: stop mocking L2capPacketForwarder.
+        verify(providerDeps).createL2capPacketForwarder(any(), any(), any(), any(), any())
+    }
 }