Merge "Allow expect onRequestStatsUpdated with any token" into sc-dev am: f8adaf99c6

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/libs/net/+/15010113

Change-Id: Ia47190f25aea2f788ef60e96949d0a0663c16a7e
diff --git a/staticlibs/device/com/android/net/module/util/structs/NsHeader.java b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java
index 6e0aa50..2e8b77b 100644
--- a/staticlibs/device/com/android/net/module/util/structs/NsHeader.java
+++ b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java
@@ -50,8 +50,12 @@
     @Field(order = 1, type = Type.Ipv6Address)
     public Inet6Address target;
 
-    public NsHeader(final Inet6Address target) {
-        this.reserved = 0;
+    NsHeader(int reserved, final Inet6Address target) {
+        this.reserved = reserved;
         this.target = target;
     }
+
+    public NsHeader(final Inet6Address target) {
+        this(0, target);
+    }
 }
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
index b7062e7..f7151d7 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
@@ -148,7 +148,10 @@
     public static final int ICMPV6_ND_OPTION_RDNSS = 25;
     public static final int ICMPV6_ND_OPTION_PREF64 = 38;
 
+    public static final int ICMPV6_RS_HEADER_LEN = 8;
     public static final int ICMPV6_RA_HEADER_LEN = 16;
+    public static final int ICMPV6_NS_HEADER_LEN = 24;
+    public static final int ICMPV6_NA_HEADER_LEN = 24;
 
     public static final int NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER    = 1 << 31;
     public static final int NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED = 1 << 30;
diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp
index c9aad71..23835fe 100644
--- a/staticlibs/tests/unit/Android.bp
+++ b/staticlibs/tests/unit/Android.bp
@@ -24,7 +24,8 @@
     ],
     visibility: [
         "//frameworks/base/packages/Tethering/tests/integration",
-        "//packages/modules/Connectivity/Tethering/tests/integration",
+        "//packages/modules/Connectivity/tests:__subpackages__",
+        "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
         "//packages/modules/NetworkStack/tests/integration",
     ]
 }
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt
index 7aae8e3..39ce487 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt
@@ -54,12 +54,12 @@
     fun addResponse(
         uri: Uri,
         statusCode: Response.IStatus,
-        locationHeader: String? = null,
+        headers: Map<String, String>? = null,
         content: String = ""
     ) {
         addResponse(Request(uri.path
                 ?: "", Method.GET, uri.query ?: ""),
-                statusCode, locationHeader, content)
+                statusCode, headers, content)
     }
 
     /**
@@ -68,11 +68,13 @@
     fun addResponse(
         request: Request,
         statusCode: Response.IStatus,
-        locationHeader: String? = null,
+        headers: Map<String, String>? = null,
         content: String = ""
     ) {
         val response = newFixedLengthResponse(statusCode, "text/plain", content)
-        locationHeader?.let { response.addHeader("Location", it) }
+        headers?.forEach {
+            (key, value) -> response.addHeader(key, value)
+        }
         responses[request] = response
     }
 
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt
new file mode 100644
index 0000000..21bd60c
--- /dev/null
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testutils
+
+import android.net.NetworkCapabilities
+import android.net.NetworkProvider
+import android.net.NetworkRequest
+import android.util.Log
+import com.android.net.module.util.ArrayTrackRecord
+import kotlin.test.fail
+
+class TestableNetworkOfferCallback(val timeoutMs: Long, private val noCallbackTimeoutMs: Long)
+            : NetworkProvider.NetworkOfferCallback {
+    private val TAG = this::class.simpleName
+    val history = ArrayTrackRecord<CallbackEntry>().newReadHead()
+
+    sealed class CallbackEntry {
+        data class OnNetworkNeeded(val request: NetworkRequest) : CallbackEntry()
+        data class OnNetworkUnneeded(val request: NetworkRequest) : CallbackEntry()
+    }
+
+    /**
+     * Called by the system when a network for this offer is needed to satisfy some
+     * networking request.
+     */
+    override fun onNetworkNeeded(request: NetworkRequest) {
+        Log.d(TAG, "onNetworkNeeded $request")
+        history.add(CallbackEntry.OnNetworkNeeded(request))
+    }
+
+    /**
+     * Called by the system when this offer is no longer valuable for this request.
+     */
+    override fun onNetworkUnneeded(request: NetworkRequest) {
+        Log.d(TAG, "onNetworkUnneeded $request")
+        history.add(CallbackEntry.OnNetworkUnneeded(request))
+    }
+
+    inline fun <reified T : CallbackEntry> expectCallbackThat(
+        crossinline predicate: (T) -> Boolean
+    ) {
+        val event = history.poll(timeoutMs)
+                ?: fail("Did not receive callback after ${timeoutMs}ms")
+        if (event !is T || !predicate(event)) fail("Received unexpected callback $event")
+    }
+
+    fun expectOnNetworkNeeded(capabilities: NetworkCapabilities) =
+            expectCallbackThat<CallbackEntry.OnNetworkNeeded> {
+                it.request.canBeSatisfiedBy(capabilities)
+            }
+
+    fun expectOnNetworkUnneeded(capabilities: NetworkCapabilities) =
+            expectCallbackThat<CallbackEntry.OnNetworkUnneeded> {
+                it.request.canBeSatisfiedBy(capabilities)
+            }
+
+    fun assertNoCallback() {
+        val cb = history.poll(noCallbackTimeoutMs)
+        if (null != cb) fail("Expected no callback but got $cb")
+    }
+}
\ No newline at end of file