Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2853503 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Add integration test for capport API"

parents b29fb469 60e502fb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.NETWORK_FACTORY"/>
    <!-- Obtain LinkProperties callbacks with sensitive fields -->
    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
    <uses-permission android:name="android.permission.NETWORK_STACK"/>
    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/>
    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+59 −6
Original line number Diff line number Diff line
@@ -28,10 +28,13 @@ import android.net.INetd
import android.net.INetworkPolicyManager
import android.net.INetworkStatsService
import android.net.LinkProperties
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkRequest
import android.net.TestNetworkStackClient
import android.net.Uri
import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
@@ -64,6 +67,8 @@ import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
import org.mockito.Spy
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail

@@ -110,6 +115,10 @@ class ConnectivityServiceIntegrationTest {
        private val bindingCondition = ConditionVariable(false)

        private val realContext get() = InstrumentationRegistry.getInstrumentation().context
        private val httpProbeUrl get() =
            realContext.getResources().getString(R.string.config_captive_portal_http_url)
        private val httpsProbeUrl get() =
            realContext.getResources().getString(R.string.config_captive_portal_https_url)

        private class InstrumentationServiceConnection : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
@@ -188,12 +197,8 @@ class ConnectivityServiceIntegrationTest {
        val testCallback = TestableNetworkCallback()

        cm.registerNetworkCallback(request, testCallback)
        nsInstrumentation.addHttpResponse(HttpResponse(
                "http://test.android.com",
                responseCode = 204, contentLength = 42, redirectUrl = null))
        nsInstrumentation.addHttpResponse(HttpResponse(
                "https://secure.test.android.com",
                responseCode = 204, contentLength = 42, redirectUrl = null))
        nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
        nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))

        val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context)
        networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
@@ -204,4 +209,52 @@ class ConnectivityServiceIntegrationTest {
        testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
        assertEquals(2, nsInstrumentation.getRequestUrls().size)
    }

    @Test
    fun testCapportApi() {
        val request = NetworkRequest.Builder()
                .clearCapabilities()
                .addCapability(NET_CAPABILITY_INTERNET)
                .build()
        val testCb = TestableNetworkCallback()
        val apiUrl = "https://capport.android.com"

        cm.registerNetworkCallback(request, testCb)
        nsInstrumentation.addHttpResponse(HttpResponse(
                apiUrl,
                """
                    |{
                    |  "captive": true,
                    |  "user-portal-url": "https://login.capport.android.com",
                    |  "venue-info-url": "https://venueinfo.capport.android.com"
                    |}
                """.trimMargin()))

        // Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the
        // HTTP probe as it should not be sent.
        // Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence
        // in that case.
        nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))

        val lp = LinkProperties()
        lp.captivePortalApiUrl = Uri.parse(apiUrl)
        val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, context)
        networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)

        na.addCapability(NET_CAPABILITY_INTERNET)
        na.connect()

        testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS)

        val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) {
            it.captivePortalData != null
        }.lp.captivePortalData
        assertNotNull(capportData)
        assertTrue(capportData.isCaptive)
        assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl)
        assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl)

        val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS)
        assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED))
    }
}
 No newline at end of file
+9 −4
Original line number Diff line number Diff line
@@ -22,16 +22,21 @@ import android.os.Parcelable
data class HttpResponse(
    val requestUrl: String,
    val responseCode: Int,
    val contentLength: Long,
    val redirectUrl: String?
    val content: String = "",
    val redirectUrl: String? = null
) : Parcelable {
    constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString())
    constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString())
    constructor(requestUrl: String, contentBody: String): this(
            requestUrl,
            responseCode = 200,
            content = contentBody,
            redirectUrl = null)

    override fun writeToParcel(dest: Parcel, flags: Int) {
        with(dest) {
            writeString(requestUrl)
            writeInt(responseCode)
            writeLong(contentLength)
            writeString(content)
            writeString(redirectUrl)
        }
    }
+3 −0
Original line number Diff line number Diff line
@@ -65,6 +65,9 @@ class NetworkStackInstrumentationService : Service() {
         *
         * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
         * used to mock the query response.
         *
         * <p>All requests that are expected to be sent must have a mock response: if an unexpected
         * request is seen, the test will fail.
         */
        override fun addHttpResponse(response: HttpResponse) {
            httpResponses.getValue(response.requestUrl).add(response)
+5 −1
Original line number Diff line number Diff line
@@ -33,9 +33,11 @@ import com.android.server.net.integrationtests.NetworkStackInstrumentationServic
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import java.io.ByteArrayInputStream
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLConnection
import java.nio.charset.StandardCharsets

private const val TEST_NETID = 42

@@ -71,11 +73,13 @@ class TestNetworkStackService : Service() {
        private inner class TestNetwork(netId: Int) : Network(netId) {
            override fun openConnection(url: URL): URLConnection {
                val response = InstrumentationConnector.processRequest(url)
                val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8)

                val connection = mock(HttpURLConnection::class.java)
                doReturn(response.responseCode).`when`(connection).responseCode
                doReturn(response.contentLength).`when`(connection).contentLengthLong
                doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong
                doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
                doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream
                return connection
            }
        }