Move net unit tests to packages/Connectivity
Move the tests together with packages/Connectivity code, so both can be moved to packages/modules/Connectivity together. Also reorganize unit tests in a unit/ directory, as other tests (integration/, common/ etc.) have been added in tests/net since they were created. This makes the directory structure consistent. Test: atest FrameworksNetTests Bug: 187814163 Merged-In: I254ffd1c08ec058d594b4ea55cbae5505f8497cc Change-Id: I254ffd1c08ec058d594b4ea55cbae5505f8497cc
This commit is contained in:
8
tests/OWNERS
Normal file
8
tests/OWNERS
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
set noparent
|
||||||
|
|
||||||
|
codewiz@google.com
|
||||||
|
jchalard@google.com
|
||||||
|
junyulai@google.com
|
||||||
|
lorenzo@google.com
|
||||||
|
reminv@google.com
|
||||||
|
satk@google.com
|
||||||
34
tests/TEST_MAPPING
Normal file
34
tests/TEST_MAPPING
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"presubmit": [
|
||||||
|
{
|
||||||
|
"name": "FrameworksNetIntegrationTests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"postsubmit": [
|
||||||
|
{
|
||||||
|
"name": "FrameworksNetDeflakeTest"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auto-postsubmit": [
|
||||||
|
// Test tag for automotive targets. These are only running in postsubmit so as to harden the
|
||||||
|
// automotive targets to avoid introducing additional test flake and build time. The plan for
|
||||||
|
// presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
|
||||||
|
// Additionally, this tag is used in targeted test suites to limit resource usage on the test
|
||||||
|
// infra during the hardening phase.
|
||||||
|
// TODO: this tag to be removed once the above is no longer an issue.
|
||||||
|
{
|
||||||
|
"name": "FrameworksNetTests"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FrameworksNetIntegrationTests"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FrameworksNetDeflakeTest"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"imports": [
|
||||||
|
{
|
||||||
|
"path": "packages/modules/Connectivity"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
44
tests/common/Android.bp
Normal file
44
tests/common/Android.bp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2019 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Tests in this folder are included both in unit tests and CTS.
|
||||||
|
// They must be fast and stable, and exercise public or test APIs.
|
||||||
|
package {
|
||||||
|
// See: http://go/android-license-faq
|
||||||
|
// A large-scale-change added 'default_applicable_licenses' to import
|
||||||
|
// all of the 'license_kinds' from "frameworks_base_license"
|
||||||
|
// to get the below license kinds:
|
||||||
|
// SPDX-license-identifier-Apache-2.0
|
||||||
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "FrameworksNetCommonTests",
|
||||||
|
srcs: ["java/**/*.java", "java/**/*.kt"],
|
||||||
|
static_libs: [
|
||||||
|
"androidx.core_core",
|
||||||
|
"androidx.test.rules",
|
||||||
|
"junit",
|
||||||
|
"mockito-target-minus-junit4",
|
||||||
|
"modules-utils-build",
|
||||||
|
"net-tests-utils",
|
||||||
|
"net-utils-framework-common",
|
||||||
|
"platform-test-annotations",
|
||||||
|
],
|
||||||
|
libs: [
|
||||||
|
"android.test.base.stubs",
|
||||||
|
],
|
||||||
|
}
|
||||||
52
tests/common/java/ParseExceptionTest.kt
Normal file
52
tests/common/java/ParseExceptionTest.kt
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.net.ParseException
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import junit.framework.Assert.assertEquals
|
||||||
|
import junit.framework.Assert.assertNull
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ParseExceptionTest {
|
||||||
|
@get:Rule
|
||||||
|
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.R)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstructor_WithCause() {
|
||||||
|
val testMessage = "Test message"
|
||||||
|
val base = Exception("Test")
|
||||||
|
val exception = ParseException(testMessage, base)
|
||||||
|
|
||||||
|
assertEquals(testMessage, exception.response)
|
||||||
|
assertEquals(base, exception.cause)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstructor_NoCause() {
|
||||||
|
val testMessage = "Test message"
|
||||||
|
val exception = ParseException(testMessage)
|
||||||
|
|
||||||
|
assertEquals(testMessage, exception.response)
|
||||||
|
assertNull(exception.cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
190
tests/common/java/android/net/CaptivePortalDataTest.kt
Normal file
190
tests/common/java/android/net/CaptivePortalDataTest.kt
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.modules.utils.build.SdkLevel
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import com.android.testutils.assertParcelingIsLossless
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
class CaptivePortalDataTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
private val data = CaptivePortalData.Builder()
|
||||||
|
.setRefreshTime(123L)
|
||||||
|
.setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
|
||||||
|
.setVenueInfoUrl(Uri.parse("https://venue.example.com/test"))
|
||||||
|
.setSessionExtendable(true)
|
||||||
|
.setBytesRemaining(456L)
|
||||||
|
.setExpiryTime(789L)
|
||||||
|
.setCaptive(true)
|
||||||
|
.apply {
|
||||||
|
if (SdkLevel.isAtLeastS()) {
|
||||||
|
setVenueFriendlyName("venue friendly name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private val dataFromPasspoint = CaptivePortalData.Builder()
|
||||||
|
.setCaptive(true)
|
||||||
|
.apply {
|
||||||
|
if (SdkLevel.isAtLeastS()) {
|
||||||
|
setVenueFriendlyName("venue friendly name")
|
||||||
|
setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
|
||||||
|
setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private fun makeBuilder() = CaptivePortalData.Builder(data)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
|
||||||
|
assertParcelSane(data, fieldCount)
|
||||||
|
assertParcelSane(dataFromPasspoint, fieldCount)
|
||||||
|
|
||||||
|
assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
|
||||||
|
assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEquals() {
|
||||||
|
assertEquals(data, makeBuilder().build())
|
||||||
|
|
||||||
|
assertNotEqualsAfterChange { it.setRefreshTime(456L) }
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) }
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(null) }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueInfoUrl(null) }
|
||||||
|
assertNotEqualsAfterChange { it.setSessionExtendable(false) }
|
||||||
|
assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
|
||||||
|
assertNotEqualsAfterChange { it.setExpiryTime(12L) }
|
||||||
|
assertNotEqualsAfterChange { it.setCaptive(false) }
|
||||||
|
|
||||||
|
if (SdkLevel.isAtLeastS()) {
|
||||||
|
assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
|
||||||
|
|
||||||
|
assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(
|
||||||
|
Uri.parse("https://tc.example.com/passpoint")) }
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(
|
||||||
|
Uri.parse("https://tc.example.com/passpoint"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(
|
||||||
|
Uri.parse("https://tc.example.com/other"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
|
||||||
|
assertNotEqualsAfterChange { it.setUserPortalUrl(
|
||||||
|
Uri.parse("https://tc.example.com/passpoint"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueInfoUrl(
|
||||||
|
Uri.parse("https://venue.example.com/passpoint")) }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueInfoUrl(
|
||||||
|
Uri.parse("https://venue.example.com/other"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
|
||||||
|
assertNotEqualsAfterChange { it.setVenueInfoUrl(
|
||||||
|
Uri.parse("https://venue.example.com/passpoint"),
|
||||||
|
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUserPortalUrl() {
|
||||||
|
assertEquals(Uri.parse("https://portal.example.com/test"), data.userPortalUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testVenueInfoUrl() {
|
||||||
|
assertEquals(Uri.parse("https://venue.example.com/test"), data.venueInfoUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsSessionExtendable() {
|
||||||
|
assertTrue(data.isSessionExtendable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testByteLimit() {
|
||||||
|
assertEquals(456L, data.byteLimit)
|
||||||
|
// Test byteLimit unset.
|
||||||
|
assertEquals(-1L, CaptivePortalData.Builder(null).build().byteLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRefreshTimeMillis() {
|
||||||
|
assertEquals(123L, data.refreshTimeMillis)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExpiryTimeMillis() {
|
||||||
|
assertEquals(789L, data.expiryTimeMillis)
|
||||||
|
// Test expiryTimeMillis unset.
|
||||||
|
assertEquals(-1L, CaptivePortalData.Builder(null).build().expiryTimeMillis)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsCaptive() {
|
||||||
|
assertTrue(data.isCaptive)
|
||||||
|
assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
fun testVenueFriendlyName() {
|
||||||
|
assertEquals("venue friendly name", data.venueFriendlyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
fun testGetVenueInfoUrlSource() {
|
||||||
|
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
|
||||||
|
data.venueInfoUrlSource)
|
||||||
|
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
|
||||||
|
dataFromPasspoint.venueInfoUrlSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
fun testGetUserPortalUrlSource() {
|
||||||
|
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
|
||||||
|
data.userPortalUrlSource)
|
||||||
|
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
|
||||||
|
dataFromPasspoint.userPortalUrlSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
|
||||||
|
CaptivePortalData.Builder(this).apply { mutator(this) }.build()
|
||||||
|
|
||||||
|
private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) {
|
||||||
|
assertNotEquals(data, data.mutate(mutator))
|
||||||
|
}
|
||||||
|
}
|
||||||
121
tests/common/java/android/net/CaptivePortalTest.java
Normal file
121
tests/common/java/android/net/CaptivePortalTest.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class CaptivePortalTest {
|
||||||
|
@Rule
|
||||||
|
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
|
private static final int DEFAULT_TIMEOUT_MS = 5000;
|
||||||
|
private static final String TEST_PACKAGE_NAME = "com.google.android.test";
|
||||||
|
|
||||||
|
private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
|
||||||
|
int mCode = -1;
|
||||||
|
String mPackageName = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appResponse(final int response) throws RemoteException {
|
||||||
|
mCode = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appRequest(final int request) throws RemoteException {
|
||||||
|
mCode = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only @Override on R-
|
||||||
|
public void logEvent(int eventId, String packageName) throws RemoteException {
|
||||||
|
mCode = eventId;
|
||||||
|
mPackageName = packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface TestFunctor {
|
||||||
|
void useCaptivePortal(CaptivePortal o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
|
||||||
|
final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
|
||||||
|
f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReportCaptivePortalDismissed() {
|
||||||
|
final MyCaptivePortalImpl result =
|
||||||
|
runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
|
||||||
|
assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoreNetwork() {
|
||||||
|
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
|
||||||
|
assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUseNetwork() {
|
||||||
|
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
|
||||||
|
assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
@Test
|
||||||
|
public void testReevaluateNetwork() {
|
||||||
|
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
|
||||||
|
assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
@Test
|
||||||
|
public void testLogEvent() {
|
||||||
|
/**
|
||||||
|
* From S testLogEvent is expected to do nothing but shouldn't crash (the API
|
||||||
|
* logEvent has been deprecated).
|
||||||
|
*/
|
||||||
|
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
|
||||||
|
0,
|
||||||
|
TEST_PACKAGE_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@IgnoreAfter(Build.VERSION_CODES.R)
|
||||||
|
@Test
|
||||||
|
public void testLogEvent_UntilR() {
|
||||||
|
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
|
||||||
|
42, TEST_PACKAGE_NAME));
|
||||||
|
assertEquals(result.mCode, 42);
|
||||||
|
assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
113
tests/common/java/android/net/DependenciesTest.java
Normal file
113
tests/common/java/android/net/DependenciesTest.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple class that tests dependencies to java standard tools from the
|
||||||
|
* Network stack. These tests are not meant to be comprehensive tests of
|
||||||
|
* the relevant APIs : such tests belong in the relevant test suite for
|
||||||
|
* these dependencies. Instead, this just makes sure coverage is present
|
||||||
|
* by calling the methods in the exact way (or a representative way of how)
|
||||||
|
* they are called in the network stack.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class DependenciesTest {
|
||||||
|
// Used to in ipmemorystore's RegularMaintenanceJobService to convert
|
||||||
|
// 24 hours into seconds
|
||||||
|
@Test
|
||||||
|
public void testTimeUnit() {
|
||||||
|
final int hours = 24;
|
||||||
|
final long inSeconds = TimeUnit.HOURS.toMillis(hours);
|
||||||
|
assertEquals(inSeconds, hours * 60 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] makeTrivialArray(final int size) {
|
||||||
|
final byte[] src = new byte[size];
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
src[i] = (byte) i;
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used in ApfFilter to find an IP address from a byte array
|
||||||
|
@Test
|
||||||
|
public void testArrays() {
|
||||||
|
final int size = 128;
|
||||||
|
final byte[] src = makeTrivialArray(size);
|
||||||
|
|
||||||
|
// Test copy
|
||||||
|
final int copySize = 16;
|
||||||
|
final int offset = 24;
|
||||||
|
final byte[] expected = new byte[copySize];
|
||||||
|
for (int i = 0; i < copySize; ++i) {
|
||||||
|
expected[i] = (byte) (offset + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
final byte[] copy = Arrays.copyOfRange(src, offset, offset + copySize);
|
||||||
|
assertArrayEquals(expected, copy);
|
||||||
|
assertArrayEquals(new byte[0], Arrays.copyOfRange(src, size, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used mainly in the Dhcp code
|
||||||
|
@Test
|
||||||
|
public void testCopyOf() {
|
||||||
|
final byte[] src = makeTrivialArray(128);
|
||||||
|
final byte[] copy = Arrays.copyOf(src, src.length);
|
||||||
|
assertArrayEquals(src, copy);
|
||||||
|
assertFalse(src == copy);
|
||||||
|
|
||||||
|
assertArrayEquals(new byte[0], Arrays.copyOf(src, 0));
|
||||||
|
|
||||||
|
final int excess = 16;
|
||||||
|
final byte[] biggerCopy = Arrays.copyOf(src, src.length + excess);
|
||||||
|
for (int i = src.length; i < src.length + excess; ++i) {
|
||||||
|
assertEquals(0, biggerCopy[i]);
|
||||||
|
}
|
||||||
|
for (int i = src.length - 1; i >= 0; --i) {
|
||||||
|
assertEquals(src[i], biggerCopy[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used mainly in DnsUtils but also various other places
|
||||||
|
@Test
|
||||||
|
public void testAsList() {
|
||||||
|
final int size = 24;
|
||||||
|
final Object[] src = new Object[size];
|
||||||
|
final ArrayList<Object> expected = new ArrayList<>(size);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final Object o = new Object();
|
||||||
|
src[i] = o;
|
||||||
|
expected.add(o);
|
||||||
|
}
|
||||||
|
assertEquals(expected, Arrays.asList(src));
|
||||||
|
}
|
||||||
|
}
|
||||||
112
tests/common/java/android/net/DhcpInfoTest.java
Normal file
112
tests/common/java/android/net/DhcpInfoTest.java
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
|
||||||
|
import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class DhcpInfoTest {
|
||||||
|
private static final String STR_ADDR1 = "255.255.255.255";
|
||||||
|
private static final String STR_ADDR2 = "127.0.0.1";
|
||||||
|
private static final String STR_ADDR3 = "192.168.1.1";
|
||||||
|
private static final String STR_ADDR4 = "192.168.1.0";
|
||||||
|
private static final int LEASE_TIME = 9999;
|
||||||
|
|
||||||
|
private int ipToInteger(String ipString) throws Exception {
|
||||||
|
return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DhcpInfo createDhcpInfoObject() throws Exception {
|
||||||
|
final DhcpInfo dhcpInfo = new DhcpInfo();
|
||||||
|
dhcpInfo.ipAddress = ipToInteger(STR_ADDR1);
|
||||||
|
dhcpInfo.gateway = ipToInteger(STR_ADDR2);
|
||||||
|
dhcpInfo.netmask = ipToInteger(STR_ADDR3);
|
||||||
|
dhcpInfo.dns1 = ipToInteger(STR_ADDR4);
|
||||||
|
dhcpInfo.dns2 = ipToInteger(STR_ADDR4);
|
||||||
|
dhcpInfo.serverAddress = ipToInteger(STR_ADDR2);
|
||||||
|
dhcpInfo.leaseDuration = LEASE_TIME;
|
||||||
|
return dhcpInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() {
|
||||||
|
new DhcpInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToString() throws Exception {
|
||||||
|
final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 "
|
||||||
|
+ "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds";
|
||||||
|
|
||||||
|
DhcpInfo dhcpInfo = new DhcpInfo();
|
||||||
|
|
||||||
|
// Test default string.
|
||||||
|
assertEquals(expectedDefault, dhcpInfo.toString());
|
||||||
|
|
||||||
|
dhcpInfo = createDhcpInfoObject();
|
||||||
|
|
||||||
|
final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask "
|
||||||
|
+ STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server "
|
||||||
|
+ STR_ADDR2 + " lease " + LEASE_TIME + " seconds";
|
||||||
|
// Test with new values
|
||||||
|
assertEquals(expected, dhcpInfo.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) {
|
||||||
|
if (left == null && right == null) return true;
|
||||||
|
|
||||||
|
if (left == null || right == null) return false;
|
||||||
|
|
||||||
|
return left.ipAddress == right.ipAddress
|
||||||
|
&& left.gateway == right.gateway
|
||||||
|
&& left.netmask == right.netmask
|
||||||
|
&& left.dns1 == right.dns1
|
||||||
|
&& left.dns2 == right.dns2
|
||||||
|
&& left.serverAddress == right.serverAddress
|
||||||
|
&& left.leaseDuration == right.leaseDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelDhcpInfo() throws Exception {
|
||||||
|
// Cannot use assertParcelSane() here because this requires .equals() to work as
|
||||||
|
// defined, but DhcpInfo has a different legacy behavior that we cannot change.
|
||||||
|
final DhcpInfo dhcpInfo = createDhcpInfoObject();
|
||||||
|
assertFieldCountEquals(7, DhcpInfo.class);
|
||||||
|
|
||||||
|
final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo);
|
||||||
|
assertTrue(dhcpInfoEquals(null, null));
|
||||||
|
assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip));
|
||||||
|
assertFalse(dhcpInfoEquals(dhcpInfo, null));
|
||||||
|
assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip));
|
||||||
|
}
|
||||||
|
}
|
||||||
374
tests/common/java/android/net/IpPrefixTest.java
Normal file
374
tests/common/java/android/net/IpPrefixTest.java
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class IpPrefixTest {
|
||||||
|
|
||||||
|
private static InetAddress address(String addr) {
|
||||||
|
return InetAddress.parseNumericAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly cast everything to byte because "error: possible loss of precision".
|
||||||
|
private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
|
||||||
|
private static final byte[] IPV6_BYTES = {
|
||||||
|
(byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
|
||||||
|
(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
|
||||||
|
(byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||||
|
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() {
|
||||||
|
IpPrefix p;
|
||||||
|
try {
|
||||||
|
p = new IpPrefix((byte[]) null, 9);
|
||||||
|
fail("Expected NullPointerException: null byte array");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix((InetAddress) null, 10);
|
||||||
|
fail("Expected NullPointerException: null InetAddress");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix((String) null);
|
||||||
|
fail("Expected NullPointerException: null String");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] b2 = {1, 2, 3, 4, 5};
|
||||||
|
p = new IpPrefix(b2, 29);
|
||||||
|
fail("Expected IllegalArgumentException: invalid array length");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("1.2.3.4");
|
||||||
|
fail("Expected IllegalArgumentException: no prefix length");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("1.2.3.4/");
|
||||||
|
fail("Expected IllegalArgumentException: empty prefix length");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("foo/32");
|
||||||
|
fail("Expected IllegalArgumentException: invalid address");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("1/32");
|
||||||
|
fail("Expected IllegalArgumentException: deprecated IPv4 format");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("1.2.3.256/32");
|
||||||
|
fail("Expected IllegalArgumentException: invalid IPv4 address");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("foo/32");
|
||||||
|
fail("Expected IllegalArgumentException: non-address");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix("f00:::/32");
|
||||||
|
fail("Expected IllegalArgumentException: invalid IPv6 address");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
p = new IpPrefix("/64");
|
||||||
|
assertEquals("::/64", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix("/128");
|
||||||
|
assertEquals("::1/128", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix("[2001:db8::123]/64");
|
||||||
|
assertEquals("2001:db8::/64", p.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTruncation() {
|
||||||
|
IpPrefix p;
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 32);
|
||||||
|
assertEquals("192.0.2.4/32", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 29);
|
||||||
|
assertEquals("192.0.2.0/29", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 8);
|
||||||
|
assertEquals("192.0.0.0/8", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 0);
|
||||||
|
assertEquals("0.0.0.0/0", p.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 33);
|
||||||
|
fail("Expected IllegalArgumentException: invalid prefix length");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix(IPV4_BYTES, 128);
|
||||||
|
fail("Expected IllegalArgumentException: invalid prefix length");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix(IPV4_BYTES, -1);
|
||||||
|
fail("Expected IllegalArgumentException: negative prefix length");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 128);
|
||||||
|
assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 122);
|
||||||
|
assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 64);
|
||||||
|
assertEquals("2001:db8:dead:beef::/64", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 3);
|
||||||
|
assertEquals("2000::/3", p.toString());
|
||||||
|
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 0);
|
||||||
|
assertEquals("::/0", p.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix(IPV6_BYTES, -1);
|
||||||
|
fail("Expected IllegalArgumentException: negative prefix length");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = new IpPrefix(IPV6_BYTES, 129);
|
||||||
|
fail("Expected IllegalArgumentException: negative prefix length");
|
||||||
|
} catch (RuntimeException expected) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
IpPrefix p1, p2;
|
||||||
|
|
||||||
|
p1 = new IpPrefix("192.0.2.251/23");
|
||||||
|
p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
|
||||||
|
assertEqualBothWays(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("192.0.2.5/23");
|
||||||
|
assertEqualBothWays(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("192.0.2.5/24");
|
||||||
|
assertNotEqualEitherWay(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("192.0.4.5/23");
|
||||||
|
assertNotEqualEitherWay(p1, p2);
|
||||||
|
|
||||||
|
|
||||||
|
p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
|
||||||
|
p2 = new IpPrefix(IPV6_BYTES, 122);
|
||||||
|
assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
|
||||||
|
assertEqualBothWays(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
|
||||||
|
assertEqualBothWays(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
|
||||||
|
assertNotEqualEitherWay(p1, p2);
|
||||||
|
|
||||||
|
p1 = new IpPrefix("2001:db8:dead:beef::/122");
|
||||||
|
assertNotEqualEitherWay(p1, p2);
|
||||||
|
|
||||||
|
// 192.0.2.4/32 != c000:0204::/32.
|
||||||
|
byte[] ipv6bytes = new byte[16];
|
||||||
|
System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
|
||||||
|
p1 = new IpPrefix(ipv6bytes, 32);
|
||||||
|
assertEqualBothWays(p1, new IpPrefix("c000:0204::/32"));
|
||||||
|
|
||||||
|
p2 = new IpPrefix(IPV4_BYTES, 32);
|
||||||
|
assertNotEqualEitherWay(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsInetAddress() {
|
||||||
|
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
|
||||||
|
assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
|
||||||
|
assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
|
||||||
|
assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
|
||||||
|
assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
|
||||||
|
assertFalse(p.contains(address("2001:4868:4860::8888")));
|
||||||
|
assertFalse(p.contains(address("8.8.8.8")));
|
||||||
|
|
||||||
|
p = new IpPrefix("192.0.2.0/23");
|
||||||
|
assertTrue(p.contains(address("192.0.2.43")));
|
||||||
|
assertTrue(p.contains(address("192.0.3.21")));
|
||||||
|
assertFalse(p.contains(address("192.0.0.21")));
|
||||||
|
assertFalse(p.contains(address("8.8.8.8")));
|
||||||
|
assertFalse(p.contains(address("2001:4868:4860::8888")));
|
||||||
|
|
||||||
|
IpPrefix ipv6Default = new IpPrefix("::/0");
|
||||||
|
assertTrue(ipv6Default.contains(address("2001:db8::f00")));
|
||||||
|
assertFalse(ipv6Default.contains(address("192.0.2.1")));
|
||||||
|
|
||||||
|
IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
|
||||||
|
assertTrue(ipv4Default.contains(address("255.255.255.255")));
|
||||||
|
assertTrue(ipv4Default.contains(address("192.0.2.1")));
|
||||||
|
assertFalse(ipv4Default.contains(address("2001:db8::f00")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsIpPrefix() {
|
||||||
|
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
|
||||||
|
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
|
||||||
|
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
|
||||||
|
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
|
||||||
|
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
|
||||||
|
|
||||||
|
assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
|
||||||
|
assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
|
||||||
|
assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
|
||||||
|
assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
|
||||||
|
|
||||||
|
assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
|
||||||
|
|
||||||
|
assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
|
||||||
|
assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
|
||||||
|
assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
|
||||||
|
assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
|
||||||
|
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
|
||||||
|
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
|
||||||
|
|
||||||
|
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00d/64")));
|
||||||
|
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00d/120")));
|
||||||
|
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00d/32")));
|
||||||
|
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
|
||||||
|
new IpPrefix("2006:db8:f00::ace:d00d/96")));
|
||||||
|
|
||||||
|
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00d/128")));
|
||||||
|
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:ccaf/110")));
|
||||||
|
|
||||||
|
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00e/128")));
|
||||||
|
assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHashCode() {
|
||||||
|
IpPrefix p = new IpPrefix(new byte[4], 0);
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
final IpPrefix oldP = p;
|
||||||
|
if (random.nextBoolean()) {
|
||||||
|
// IPv4.
|
||||||
|
byte[] b = new byte[4];
|
||||||
|
random.nextBytes(b);
|
||||||
|
p = new IpPrefix(b, random.nextInt(33));
|
||||||
|
} else {
|
||||||
|
// IPv6.
|
||||||
|
byte[] b = new byte[16];
|
||||||
|
random.nextBytes(b);
|
||||||
|
p = new IpPrefix(b, random.nextInt(129));
|
||||||
|
}
|
||||||
|
if (p.equals(oldP)) {
|
||||||
|
assertEquals(p.hashCode(), oldP.hashCode());
|
||||||
|
}
|
||||||
|
if (p.hashCode() != oldP.hashCode()) {
|
||||||
|
assertNotEquals(p, oldP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHashCodeIsNotConstant() {
|
||||||
|
IpPrefix[] prefixes = {
|
||||||
|
new IpPrefix("2001:db8:f00::ace:d00d/127"),
|
||||||
|
new IpPrefix("192.0.2.0/23"),
|
||||||
|
new IpPrefix("::/0"),
|
||||||
|
new IpPrefix("0.0.0.0/0"),
|
||||||
|
};
|
||||||
|
for (int i = 0; i < prefixes.length; i++) {
|
||||||
|
for (int j = i + 1; j < prefixes.length; j++) {
|
||||||
|
assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappedAddressesAreBroken() {
|
||||||
|
// 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
|
||||||
|
// we are unable to comprehend that.
|
||||||
|
byte[] ipv6bytes = {
|
||||||
|
(byte) 0, (byte) 0, (byte) 0, (byte) 0,
|
||||||
|
(byte) 0, (byte) 0, (byte) 0, (byte) 0,
|
||||||
|
(byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
|
||||||
|
(byte) 192, (byte) 0, (byte) 2, (byte) 0};
|
||||||
|
IpPrefix p = new IpPrefix(ipv6bytes, 120);
|
||||||
|
assertEquals(16, p.getRawAddress().length); // Fine.
|
||||||
|
assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine.
|
||||||
|
|
||||||
|
// Broken.
|
||||||
|
assertEquals("192.0.2.0/120", p.toString());
|
||||||
|
assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParceling() {
|
||||||
|
IpPrefix p;
|
||||||
|
|
||||||
|
p = new IpPrefix("2001:4860:db8::/64");
|
||||||
|
assertParcelingIsLossless(p);
|
||||||
|
assertTrue(p.isIPv6());
|
||||||
|
|
||||||
|
p = new IpPrefix("192.0.2.0/25");
|
||||||
|
assertParcelingIsLossless(p);
|
||||||
|
assertTrue(p.isIPv4());
|
||||||
|
|
||||||
|
assertFieldCountEquals(2, IpPrefix.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
120
tests/common/java/android/net/KeepalivePacketDataTest.kt
Normal file
120
tests/common/java/android/net/KeepalivePacketDataTest.kt
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
|
||||||
|
import android.net.InvalidPacketException.ERROR_INVALID_PORT
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.util.Arrays
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class KeepalivePacketDataTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
private val INVALID_PORT = 65537
|
||||||
|
private val TEST_DST_PORT = 4244
|
||||||
|
private val TEST_SRC_PORT = 4243
|
||||||
|
|
||||||
|
private val TESTBYTES = byteArrayOf(12, 31, 22, 44)
|
||||||
|
private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
|
||||||
|
private val TEST_DST_ADDRV4 = "198.168.0.1".address()
|
||||||
|
private val TEST_ADDRV6 = "2001:db8::1".address()
|
||||||
|
|
||||||
|
private fun String.address() = InetAddresses.parseNumericAddress(this)
|
||||||
|
|
||||||
|
// Add for test because constructor of KeepalivePacketData is protected.
|
||||||
|
private inner class TestKeepalivePacketData(
|
||||||
|
srcAddress: InetAddress? = TEST_SRC_ADDRV4,
|
||||||
|
srcPort: Int = TEST_SRC_PORT,
|
||||||
|
dstAddress: InetAddress? = TEST_DST_ADDRV4,
|
||||||
|
dstPort: Int = TEST_DST_PORT,
|
||||||
|
data: ByteArray = TESTBYTES
|
||||||
|
) : KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testConstructor() {
|
||||||
|
var data: TestKeepalivePacketData
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = TestKeepalivePacketData(srcAddress = null)
|
||||||
|
fail("Null src address should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = TestKeepalivePacketData(dstAddress = null)
|
||||||
|
fail("Null dst address should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = TestKeepalivePacketData(dstAddress = TEST_ADDRV6)
|
||||||
|
fail("Ip family mismatched should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = TestKeepalivePacketData(srcPort = INVALID_PORT)
|
||||||
|
fail("Invalid srcPort should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_PORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = TestKeepalivePacketData(dstPort = INVALID_PORT)
|
||||||
|
fail("Invalid dstPort should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_PORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testSrcAddress() = assertEquals(TEST_SRC_ADDRV4, TestKeepalivePacketData().srcAddress)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testDstAddress() = assertEquals(TEST_DST_ADDRV4, TestKeepalivePacketData().dstAddress)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testSrcPort() = assertEquals(TEST_SRC_PORT, TestKeepalivePacketData().srcPort)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testDstPort() = assertEquals(TEST_DST_PORT, TestKeepalivePacketData().dstPort)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testPacket() = assertTrue(Arrays.equals(TESTBYTES, TestKeepalivePacketData().packet))
|
||||||
|
}
|
||||||
518
tests/common/java/android/net/LinkAddressTest.java
Normal file
518
tests/common/java/android/net/LinkAddressTest.java
Normal file
@@ -0,0 +1,518 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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 android.net;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.IFA_F_DADFAILED;
|
||||||
|
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
||||||
|
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
||||||
|
import static android.system.OsConstants.IFA_F_PERMANENT;
|
||||||
|
import static android.system.OsConstants.IFA_F_TEMPORARY;
|
||||||
|
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_HOST;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_LINK;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_SITE;
|
||||||
|
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||||
|
|
||||||
|
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InterfaceAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class LinkAddressTest {
|
||||||
|
@Rule
|
||||||
|
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
|
private static final String V4 = "192.0.2.1";
|
||||||
|
private static final String V6 = "2001:db8::1";
|
||||||
|
private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
|
||||||
|
private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstants() {
|
||||||
|
// RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
|
||||||
|
assertNotEquals(0, RT_SCOPE_HOST);
|
||||||
|
assertNotEquals(0, RT_SCOPE_LINK);
|
||||||
|
assertNotEquals(0, RT_SCOPE_SITE);
|
||||||
|
|
||||||
|
assertNotEquals(0, IFA_F_DEPRECATED);
|
||||||
|
assertNotEquals(0, IFA_F_PERMANENT);
|
||||||
|
assertNotEquals(0, IFA_F_TENTATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructors() throws SocketException {
|
||||||
|
LinkAddress address;
|
||||||
|
|
||||||
|
// Valid addresses work as expected.
|
||||||
|
address = new LinkAddress(V4_ADDRESS, 25);
|
||||||
|
assertEquals(V4_ADDRESS, address.getAddress());
|
||||||
|
assertEquals(25, address.getPrefixLength());
|
||||||
|
assertEquals(0, address.getFlags());
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
|
||||||
|
assertTrue(address.isIpv4());
|
||||||
|
|
||||||
|
address = new LinkAddress(V6_ADDRESS, 127);
|
||||||
|
assertEquals(V6_ADDRESS, address.getAddress());
|
||||||
|
assertEquals(127, address.getPrefixLength());
|
||||||
|
assertEquals(0, address.getFlags());
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
|
||||||
|
assertTrue(address.isIpv6());
|
||||||
|
|
||||||
|
// Nonsensical flags/scopes or combinations thereof are acceptable.
|
||||||
|
address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
|
||||||
|
assertEquals(V6_ADDRESS, address.getAddress());
|
||||||
|
assertEquals(64, address.getPrefixLength());
|
||||||
|
assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
|
||||||
|
assertEquals(RT_SCOPE_LINK, address.getScope());
|
||||||
|
assertTrue(address.isIpv6());
|
||||||
|
|
||||||
|
address = new LinkAddress(V4 + "/23", 123, 456);
|
||||||
|
assertEquals(V4_ADDRESS, address.getAddress());
|
||||||
|
assertEquals(23, address.getPrefixLength());
|
||||||
|
assertEquals(123, address.getFlags());
|
||||||
|
assertEquals(456, address.getScope());
|
||||||
|
assertTrue(address.isIpv4());
|
||||||
|
|
||||||
|
address = new LinkAddress("/64", 1 /* flags */, 2 /* scope */);
|
||||||
|
assertEquals(Inet6Address.LOOPBACK, address.getAddress());
|
||||||
|
assertEquals(64, address.getPrefixLength());
|
||||||
|
assertEquals(1, address.getFlags());
|
||||||
|
assertEquals(2, address.getScope());
|
||||||
|
assertTrue(address.isIpv6());
|
||||||
|
|
||||||
|
address = new LinkAddress("[2001:db8::123]/64", 3 /* flags */, 4 /* scope */);
|
||||||
|
assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), address.getAddress());
|
||||||
|
assertEquals(64, address.getPrefixLength());
|
||||||
|
assertEquals(3, address.getFlags());
|
||||||
|
assertEquals(4, address.getScope());
|
||||||
|
assertTrue(address.isIpv6());
|
||||||
|
|
||||||
|
// InterfaceAddress doesn't have a constructor. Fetch some from an interface.
|
||||||
|
List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
|
||||||
|
|
||||||
|
// We expect to find 127.0.0.1/8 and ::1/128, in any order.
|
||||||
|
LinkAddress ipv4Loopback, ipv6Loopback;
|
||||||
|
assertEquals(2, addrs.size());
|
||||||
|
if (addrs.get(0).getAddress() instanceof Inet4Address) {
|
||||||
|
ipv4Loopback = new LinkAddress(addrs.get(0));
|
||||||
|
ipv6Loopback = new LinkAddress(addrs.get(1));
|
||||||
|
} else {
|
||||||
|
ipv4Loopback = new LinkAddress(addrs.get(1));
|
||||||
|
ipv6Loopback = new LinkAddress(addrs.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
|
||||||
|
assertEquals(8, ipv4Loopback.getPrefixLength());
|
||||||
|
|
||||||
|
assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
|
||||||
|
assertEquals(128, ipv6Loopback.getPrefixLength());
|
||||||
|
|
||||||
|
// Null addresses are rejected.
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(null, 24);
|
||||||
|
fail("Null InetAddress should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
|
||||||
|
fail("Null string should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress((InterfaceAddress) null);
|
||||||
|
fail("Null string should cause NullPointerException");
|
||||||
|
} catch(NullPointerException expected) {}
|
||||||
|
|
||||||
|
// Invalid prefix lengths are rejected.
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V4_ADDRESS, -1);
|
||||||
|
fail("Negative IPv4 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V6_ADDRESS, -1);
|
||||||
|
fail("Negative IPv6 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V4_ADDRESS, 33);
|
||||||
|
fail("/33 IPv4 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
|
||||||
|
fail("/33 IPv4 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
|
||||||
|
fail("/129 IPv6 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
|
||||||
|
fail("/129 IPv6 prefix length should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
// Multicast addresses are rejected.
|
||||||
|
try {
|
||||||
|
address = new LinkAddress("224.0.0.2/32");
|
||||||
|
fail("IPv4 multicast address should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = new LinkAddress("ff02::1/128");
|
||||||
|
fail("IPv6 multicast address should cause IllegalArgumentException");
|
||||||
|
} catch(IllegalArgumentException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressScopes() {
|
||||||
|
assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
|
||||||
|
assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
|
||||||
|
|
||||||
|
assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
|
||||||
|
assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
|
||||||
|
assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
|
||||||
|
assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
|
||||||
|
|
||||||
|
assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
|
||||||
|
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
|
||||||
|
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
|
||||||
|
assertTrue(l1 + " unexpectedly does not have same address as " + l2,
|
||||||
|
l1.isSameAddressAs(l2));
|
||||||
|
assertTrue(l2 + " unexpectedly does not have same address as " + l1,
|
||||||
|
l2.isSameAddressAs(l1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
|
||||||
|
assertFalse(l1 + " unexpectedly has same address as " + l2,
|
||||||
|
l1.isSameAddressAs(l2));
|
||||||
|
assertFalse(l2 + " unexpectedly has same address as " + l1,
|
||||||
|
l1.isSameAddressAs(l2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualsAndSameAddressAs() {
|
||||||
|
LinkAddress l1, l2, l3;
|
||||||
|
|
||||||
|
l1 = new LinkAddress("2001:db8::1/64");
|
||||||
|
l2 = new LinkAddress("2001:db8::1/64");
|
||||||
|
assertEqualBothWays(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress("2001:db8::1/65");
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsNotSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress("2001:db8::2/64");
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsNotSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
|
||||||
|
l1 = new LinkAddress("192.0.2.1/24");
|
||||||
|
l2 = new LinkAddress("192.0.2.1/24");
|
||||||
|
assertEqualBothWays(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress("192.0.2.1/23");
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsNotSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress("192.0.2.2/24");
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsNotSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
|
||||||
|
// Check equals() and isSameAddressAs() on identical addresses with different flags.
|
||||||
|
l1 = new LinkAddress(V6_ADDRESS, 64);
|
||||||
|
l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertEqualBothWays(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
// Check equals() and isSameAddressAs() on identical addresses with different scope.
|
||||||
|
l1 = new LinkAddress(V4_ADDRESS, 24);
|
||||||
|
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertEqualBothWays(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
// Addresses with the same start or end bytes aren't equal between families.
|
||||||
|
l1 = new LinkAddress("32.1.13.184/24");
|
||||||
|
l2 = new LinkAddress("2001:db8::1/24");
|
||||||
|
l3 = new LinkAddress("::2001:db8/24");
|
||||||
|
|
||||||
|
byte[] ipv4Bytes = l1.getAddress().getAddress();
|
||||||
|
byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
|
||||||
|
byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
|
||||||
|
assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
|
||||||
|
assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
|
||||||
|
|
||||||
|
assertNotEqualEitherWay(l1, l2);
|
||||||
|
assertIsNotSameAddressAs(l1, l2);
|
||||||
|
|
||||||
|
assertNotEqualEitherWay(l1, l3);
|
||||||
|
assertIsNotSameAddressAs(l1, l3);
|
||||||
|
|
||||||
|
// Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
|
||||||
|
// TODO: Investigate fixing this.
|
||||||
|
String addressString = V4 + "/24";
|
||||||
|
l1 = new LinkAddress(addressString);
|
||||||
|
l2 = new LinkAddress("::ffff:" + addressString);
|
||||||
|
assertEqualBothWays(l1, l2);
|
||||||
|
assertIsSameAddressAs(l1, l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHashCode() {
|
||||||
|
LinkAddress l1, l2;
|
||||||
|
|
||||||
|
l1 = new LinkAddress(V4_ADDRESS, 23);
|
||||||
|
l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
|
||||||
|
assertNotEquals(l1.hashCode(), l2.hashCode());
|
||||||
|
|
||||||
|
l1 = new LinkAddress(V6_ADDRESS, 128);
|
||||||
|
l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotEquals(l1.hashCode(), l2.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParceling() {
|
||||||
|
LinkAddress l;
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
|
||||||
|
assertParcelingIsLossless(l);
|
||||||
|
|
||||||
|
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
|
||||||
|
assertParcelingIsLossless(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testLifetimeParceling() {
|
||||||
|
final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
|
||||||
|
assertParcelingIsLossless(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreAfter(Build.VERSION_CODES.Q)
|
||||||
|
public void testFieldCount_Q() {
|
||||||
|
assertFieldCountEquals(4, LinkAddress.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testFieldCount() {
|
||||||
|
// Make sure any new field is covered by the above parceling tests when changing this number
|
||||||
|
assertFieldCountEquals(6, LinkAddress.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testDeprecationTime() {
|
||||||
|
try {
|
||||||
|
new LinkAddress(V6_ADDRESS, 64, 0, 456,
|
||||||
|
LinkAddress.LIFETIME_UNKNOWN, 100000L);
|
||||||
|
fail("Only one time provided should cause exception");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
new LinkAddress(V6_ADDRESS, 64, 0, 456,
|
||||||
|
200000L, 100000L);
|
||||||
|
fail("deprecation time later than expiration time should cause exception");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
new LinkAddress(V6_ADDRESS, 64, 0, 456,
|
||||||
|
-2, 100000L);
|
||||||
|
fail("negative deprecation time should cause exception");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
|
||||||
|
assertEquals(100000L, addr.getDeprecationTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testExpirationTime() {
|
||||||
|
try {
|
||||||
|
new LinkAddress(V6_ADDRESS, 64, 0, 456,
|
||||||
|
200000L, LinkAddress.LIFETIME_UNKNOWN);
|
||||||
|
fail("Only one time provided should cause exception");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
new LinkAddress(V6_ADDRESS, 64, 0, 456,
|
||||||
|
100000L, -2);
|
||||||
|
fail("negative expiration time should cause exception");
|
||||||
|
} catch (IllegalArgumentException expected) { }
|
||||||
|
|
||||||
|
LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
|
||||||
|
assertEquals(200000L, addr.getExpirationTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFlags() {
|
||||||
|
LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
|
||||||
|
assertEquals(123, l.getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testGetFlags_Deprecation() {
|
||||||
|
// Test if deprecated bit was added/remove automatically based on the provided deprecation
|
||||||
|
// time
|
||||||
|
LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
|
||||||
|
1L, LinkAddress.LIFETIME_PERMANENT);
|
||||||
|
// Check if the flag is added automatically.
|
||||||
|
assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
|
||||||
|
SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
|
||||||
|
// Check if the flag is removed automatically.
|
||||||
|
assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
|
||||||
|
LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
|
||||||
|
// Check if the permanent flag is added.
|
||||||
|
assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
|
||||||
|
1000L, SystemClock.elapsedRealtime() + 100000L);
|
||||||
|
// Check if the permanent flag is removed
|
||||||
|
assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertGlobalPreferred(LinkAddress l, String msg) {
|
||||||
|
assertTrue(msg, l.isGlobalPreferred());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotGlobalPreferred(LinkAddress l, String msg) {
|
||||||
|
assertFalse(msg, l.isGlobalPreferred());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsGlobalPreferred() {
|
||||||
|
LinkAddress l;
|
||||||
|
|
||||||
|
l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v4,global,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v4-rfc1918,global,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE);
|
||||||
|
assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST);
|
||||||
|
assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v6,global,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v6,global,permanent");
|
||||||
|
|
||||||
|
// IPv6 ULAs are not acceptable "global preferred" addresses.
|
||||||
|
l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,ula1,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,ula2,noflags");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v6,global,tempaddr");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED),
|
||||||
|
RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED),
|
||||||
|
RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,site-local,tempaddr");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK);
|
||||||
|
assertNotGlobalPreferred(l, "v6,link-local,tempaddr");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST);
|
||||||
|
assertNotGlobalPreferred(l, "v6,node-local,tempaddr");
|
||||||
|
|
||||||
|
l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST);
|
||||||
|
assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE),
|
||||||
|
RT_SCOPE_UNIVERSE);
|
||||||
|
assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative");
|
||||||
|
|
||||||
|
l = new LinkAddress(V6_ADDRESS, 64,
|
||||||
|
(IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
|
||||||
|
RT_SCOPE_UNIVERSE);
|
||||||
|
assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testIsGlobalPreferred_DeprecatedInFuture() {
|
||||||
|
final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
|
||||||
|
RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
|
||||||
|
SystemClock.elapsedRealtime() + 200000);
|
||||||
|
// Although the deprecated bit is set, but the deprecation time is in the future, test
|
||||||
|
// if the flag is removed automatically.
|
||||||
|
assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
|
||||||
|
}
|
||||||
|
}
|
||||||
1271
tests/common/java/android/net/LinkPropertiesTest.java
Normal file
1271
tests/common/java/android/net/LinkPropertiesTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.net.wifi.aware.DiscoverySession
|
||||||
|
import android.net.wifi.aware.PeerHandle
|
||||||
|
import android.net.wifi.aware.WifiAwareNetworkSpecifier
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mockito
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class MatchAllNetworkSpecifierTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
private val specifier = MatchAllNetworkSpecifier()
|
||||||
|
private val discoverySession = Mockito.mock(DiscoverySession::class.java)
|
||||||
|
private val peerHandle = Mockito.mock(PeerHandle::class.java)
|
||||||
|
private val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
|
||||||
|
peerHandle).build()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcel() {
|
||||||
|
assertParcelSane(MatchAllNetworkSpecifier(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
@IgnoreAfter(Build.VERSION_CODES.R)
|
||||||
|
// Only run this test on Android R.
|
||||||
|
// The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
|
||||||
|
// method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
|
||||||
|
fun testCanBeSatisfiedBy_OnlyForR() {
|
||||||
|
// MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
|
||||||
|
// canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
|
||||||
|
// NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
|
||||||
|
// Although it's not meeting the expectation, the behavior still needs to be verified.
|
||||||
|
assertFalse(specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException::class)
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
fun testCanBeSatisfiedBy() {
|
||||||
|
specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
114
tests/common/java/android/net/NattKeepalivePacketDataTest.kt
Normal file
114
tests/common/java/android/net/NattKeepalivePacketDataTest.kt
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
|
||||||
|
import android.net.InvalidPacketException.ERROR_INVALID_PORT
|
||||||
|
import android.net.NattSocketKeepalive.NATT_PORT
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertEqualBothWays
|
||||||
|
import com.android.testutils.assertFieldCountEquals
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.parcelingRoundTrip
|
||||||
|
import java.net.InetAddress
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotEquals
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NattKeepalivePacketDataTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
/* Refer to the definition in {@code NattKeepalivePacketData} */
|
||||||
|
private val IPV4_HEADER_LENGTH = 20
|
||||||
|
private val UDP_HEADER_LENGTH = 8
|
||||||
|
|
||||||
|
private val TEST_PORT = 4243
|
||||||
|
private val TEST_PORT2 = 4244
|
||||||
|
private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
|
||||||
|
private val TEST_DST_ADDRV4 = "198.168.0.1".address()
|
||||||
|
private val TEST_ADDRV6 = "2001:db8::1".address()
|
||||||
|
|
||||||
|
private fun String.address() = InetAddresses.parseNumericAddress(this)
|
||||||
|
private fun nattKeepalivePacket(
|
||||||
|
srcAddress: InetAddress? = TEST_SRC_ADDRV4,
|
||||||
|
srcPort: Int = TEST_PORT,
|
||||||
|
dstAddress: InetAddress? = TEST_DST_ADDRV4,
|
||||||
|
dstPort: Int = NATT_PORT
|
||||||
|
) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort)
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testConstructor() {
|
||||||
|
try {
|
||||||
|
nattKeepalivePacket(dstPort = TEST_PORT)
|
||||||
|
fail("Dst port is not NATT port should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_PORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
nattKeepalivePacket(srcAddress = TEST_ADDRV6)
|
||||||
|
fail("A v6 srcAddress should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
nattKeepalivePacket(dstAddress = TEST_ADDRV6)
|
||||||
|
fail("A v6 dstAddress should cause exception")
|
||||||
|
} catch (e: InvalidPacketException) {
|
||||||
|
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
parcelingRoundTrip(
|
||||||
|
NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT,
|
||||||
|
byteArrayOf(12, 31, 22, 44)))
|
||||||
|
fail("Invalid data should cause exception")
|
||||||
|
} catch (e: IllegalArgumentException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testParcel() {
|
||||||
|
assertParcelSane(nattKeepalivePacket(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testEquals() {
|
||||||
|
assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket())
|
||||||
|
assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket())
|
||||||
|
assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket())
|
||||||
|
// Test src port only because dst port have to be NATT_PORT
|
||||||
|
assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket())
|
||||||
|
// Make sure the parceling test is updated if fields are added in the base class.
|
||||||
|
assertFieldCountEquals(5, KeepalivePacketData::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testHashCode() {
|
||||||
|
assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode())
|
||||||
|
}
|
||||||
|
}
|
||||||
91
tests/common/java/android/net/NetworkAgentConfigTest.kt
Normal file
91
tests/common/java/android/net/NetworkAgentConfigTest.kt
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.modules.utils.build.SdkLevel.isAtLeastS
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NetworkAgentConfigTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testParcelNetworkAgentConfig() {
|
||||||
|
val config = NetworkAgentConfig.Builder().apply {
|
||||||
|
setExplicitlySelected(true)
|
||||||
|
setLegacyType(ConnectivityManager.TYPE_ETHERNET)
|
||||||
|
setSubscriberId("MySubId")
|
||||||
|
setPartialConnectivityAcceptable(false)
|
||||||
|
setUnvalidatedConnectivityAcceptable(true)
|
||||||
|
if (isAtLeastS()) {
|
||||||
|
setBypassableVpn(true)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
if (isAtLeastS()) {
|
||||||
|
// From S, the config will have 12 items
|
||||||
|
assertParcelSane(config, 12)
|
||||||
|
} else {
|
||||||
|
// For R or below, the config will have 10 items
|
||||||
|
assertParcelSane(config, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testBuilder() {
|
||||||
|
val config = NetworkAgentConfig.Builder().apply {
|
||||||
|
setExplicitlySelected(true)
|
||||||
|
setLegacyType(ConnectivityManager.TYPE_ETHERNET)
|
||||||
|
setSubscriberId("MySubId")
|
||||||
|
setPartialConnectivityAcceptable(false)
|
||||||
|
setUnvalidatedConnectivityAcceptable(true)
|
||||||
|
setLegacyTypeName("TEST_NETWORK")
|
||||||
|
if (isAtLeastS()) {
|
||||||
|
setNat64DetectionEnabled(false)
|
||||||
|
setProvisioningNotificationEnabled(false)
|
||||||
|
setBypassableVpn(true)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
assertTrue(config.isExplicitlySelected())
|
||||||
|
assertEquals(ConnectivityManager.TYPE_ETHERNET, config.getLegacyType())
|
||||||
|
assertEquals("MySubId", config.getSubscriberId())
|
||||||
|
assertFalse(config.isPartialConnectivityAcceptable())
|
||||||
|
assertTrue(config.isUnvalidatedConnectivityAcceptable())
|
||||||
|
assertEquals("TEST_NETWORK", config.getLegacyTypeName())
|
||||||
|
if (isAtLeastS()) {
|
||||||
|
assertFalse(config.isNat64DetectionEnabled())
|
||||||
|
assertFalse(config.isProvisioningNotificationEnabled())
|
||||||
|
assertTrue(config.isBypassableVpn())
|
||||||
|
} else {
|
||||||
|
assertTrue(config.isNat64DetectionEnabled())
|
||||||
|
assertTrue(config.isProvisioningNotificationEnabled())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1152
tests/common/java/android/net/NetworkCapabilitiesTest.java
Normal file
1152
tests/common/java/android/net/NetworkCapabilitiesTest.java
Normal file
File diff suppressed because it is too large
Load Diff
201
tests/common/java/android/net/NetworkProviderTest.kt
Normal file
201
tests/common/java/android/net/NetworkProviderTest.kt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.app.Instrumentation
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_TEST
|
||||||
|
import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
|
||||||
|
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
|
||||||
|
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.HandlerThread
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.test.InstrumentationRegistry
|
||||||
|
import com.android.net.module.util.ArrayTrackRecord
|
||||||
|
import com.android.testutils.CompatUtil
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import com.android.testutils.isDevSdkInRange
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
|
private const val DEFAULT_TIMEOUT_MS = 5000L
|
||||||
|
private val instrumentation: Instrumentation
|
||||||
|
get() = InstrumentationRegistry.getInstrumentation()
|
||||||
|
private val context: Context get() = InstrumentationRegistry.getContext()
|
||||||
|
private val PROVIDER_NAME = "NetworkProviderTest"
|
||||||
|
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
class NetworkProviderTest {
|
||||||
|
private val mCm = context.getSystemService(ConnectivityManager::class.java)
|
||||||
|
private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
instrumentation.getUiAutomation().adoptShellPermissionIdentity()
|
||||||
|
mHandlerThread.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
mHandlerThread.quitSafely()
|
||||||
|
instrumentation.getUiAutomation().dropShellPermissionIdentity()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestNetworkProvider(context: Context, looper: Looper) :
|
||||||
|
NetworkProvider(context, looper, PROVIDER_NAME) {
|
||||||
|
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
|
||||||
|
|
||||||
|
sealed class CallbackEntry {
|
||||||
|
data class OnNetworkRequested(
|
||||||
|
val request: NetworkRequest,
|
||||||
|
val score: Int,
|
||||||
|
val id: Int
|
||||||
|
) : CallbackEntry()
|
||||||
|
data class OnNetworkRequestWithdrawn(val request: NetworkRequest) : CallbackEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
|
||||||
|
seenEvents.add(OnNetworkRequested(request, score, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
|
||||||
|
seenEvents.add(OnNetworkRequestWithdrawn(request))
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : CallbackEntry> expectCallback(
|
||||||
|
crossinline predicate: (T) -> Boolean
|
||||||
|
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
|
||||||
|
return TestNetworkProvider(ctx, mHandlerThread.looper)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnNetworkRequested() {
|
||||||
|
val provider = createNetworkProvider()
|
||||||
|
assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
|
||||||
|
mCm.registerNetworkProvider(provider)
|
||||||
|
assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
|
||||||
|
|
||||||
|
val specifier = CompatUtil.makeTestNetworkSpecifier(
|
||||||
|
UUID.randomUUID().toString())
|
||||||
|
val nr: NetworkRequest = NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_TEST)
|
||||||
|
.setNetworkSpecifier(specifier)
|
||||||
|
.build()
|
||||||
|
val cb = ConnectivityManager.NetworkCallback()
|
||||||
|
mCm.requestNetwork(nr, cb)
|
||||||
|
provider.expectCallback<OnNetworkRequested>() { callback ->
|
||||||
|
callback.request.getNetworkSpecifier() == specifier &&
|
||||||
|
callback.request.hasTransport(TRANSPORT_TEST)
|
||||||
|
}
|
||||||
|
|
||||||
|
val initialScore = 40
|
||||||
|
val updatedScore = 60
|
||||||
|
val nc = NetworkCapabilities().apply {
|
||||||
|
addTransportType(NetworkCapabilities.TRANSPORT_TEST)
|
||||||
|
removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||||
|
removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||||
|
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
|
||||||
|
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
|
||||||
|
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
|
||||||
|
setNetworkSpecifier(specifier)
|
||||||
|
}
|
||||||
|
val lp = LinkProperties()
|
||||||
|
val config = NetworkAgentConfig.Builder().build()
|
||||||
|
val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
|
||||||
|
initialScore, config, provider) {}
|
||||||
|
|
||||||
|
provider.expectCallback<OnNetworkRequested>() { callback ->
|
||||||
|
callback.request.getNetworkSpecifier() == specifier &&
|
||||||
|
callback.score == initialScore &&
|
||||||
|
callback.id == agent.providerId
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.sendNetworkScore(updatedScore)
|
||||||
|
provider.expectCallback<OnNetworkRequested>() { callback ->
|
||||||
|
callback.request.getNetworkSpecifier() == specifier &&
|
||||||
|
callback.score == updatedScore &&
|
||||||
|
callback.id == agent.providerId
|
||||||
|
}
|
||||||
|
|
||||||
|
mCm.unregisterNetworkCallback(cb)
|
||||||
|
provider.expectCallback<OnNetworkRequestWithdrawn>() { callback ->
|
||||||
|
callback.request.getNetworkSpecifier() == specifier &&
|
||||||
|
callback.request.hasTransport(TRANSPORT_TEST)
|
||||||
|
}
|
||||||
|
mCm.unregisterNetworkProvider(provider)
|
||||||
|
// Provider id should be ID_NONE after unregister network provider
|
||||||
|
assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
|
||||||
|
// unregisterNetworkProvider should not crash even if it's called on an
|
||||||
|
// already unregistered provider.
|
||||||
|
mCm.unregisterNetworkProvider(provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestNetworkCallback : ConnectivityManager.NetworkCallback() {
|
||||||
|
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
|
||||||
|
sealed class CallbackEntry {
|
||||||
|
object OnUnavailable : CallbackEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnavailable() {
|
||||||
|
seenEvents.add(OnUnavailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : CallbackEntry> expectCallback(
|
||||||
|
crossinline predicate: (T) -> Boolean
|
||||||
|
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDeclareNetworkRequestUnfulfillable() {
|
||||||
|
val mockContext = mock(Context::class.java)
|
||||||
|
doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
|
||||||
|
val provider = createNetworkProvider(mockContext)
|
||||||
|
// ConnectivityManager not required at creation time after R
|
||||||
|
if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
|
||||||
|
verifyNoMoreInteractions(mockContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
mCm.registerNetworkProvider(provider)
|
||||||
|
|
||||||
|
val specifier = CompatUtil.makeTestNetworkSpecifier(
|
||||||
|
UUID.randomUUID().toString())
|
||||||
|
val nr: NetworkRequest = NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_TEST)
|
||||||
|
.setNetworkSpecifier(specifier)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val cb = TestNetworkCallback()
|
||||||
|
mCm.requestNetwork(nr, cb)
|
||||||
|
provider.declareNetworkRequestUnfulfillable(nr)
|
||||||
|
cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
|
||||||
|
mCm.unregisterNetworkProvider(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
67
tests/common/java/android/net/NetworkSpecifierTest.kt
Normal file
67
tests/common/java/android/net/NetworkSpecifierTest.kt
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
class NetworkSpecifierTest {
|
||||||
|
private class TestNetworkSpecifier(
|
||||||
|
val intData: Int = 123,
|
||||||
|
val stringData: String = "init"
|
||||||
|
) : NetworkSpecifier() {
|
||||||
|
override fun canBeSatisfiedBy(other: NetworkSpecifier?): Boolean =
|
||||||
|
other != null &&
|
||||||
|
other is TestNetworkSpecifier &&
|
||||||
|
other.intData >= intData &&
|
||||||
|
stringData.equals(other.stringData)
|
||||||
|
|
||||||
|
override fun redact(): NetworkSpecifier = TestNetworkSpecifier(intData, "redact")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRedact() {
|
||||||
|
val ns: TestNetworkSpecifier = TestNetworkSpecifier()
|
||||||
|
val redactNs = ns.redact()
|
||||||
|
assertTrue(redactNs is TestNetworkSpecifier)
|
||||||
|
assertEquals(ns.intData, redactNs.intData)
|
||||||
|
assertNotEquals(ns.stringData, redactNs.stringData)
|
||||||
|
assertTrue("redact".equals(redactNs.stringData))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testcanBeSatisfiedBy() {
|
||||||
|
val target: TestNetworkSpecifier = TestNetworkSpecifier()
|
||||||
|
assertFalse(target.canBeSatisfiedBy(null))
|
||||||
|
assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier()))
|
||||||
|
val otherNs = TelephonyNetworkSpecifier.Builder().setSubscriptionId(123).build()
|
||||||
|
assertFalse(target.canBeSatisfiedBy(otherNs))
|
||||||
|
assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 999)))
|
||||||
|
assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 1)))
|
||||||
|
assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(stringData = "diff")))
|
||||||
|
}
|
||||||
|
}
|
||||||
51
tests/common/java/android/net/NetworkStackTest.java
Normal file
51
tests/common/java/android/net/NetworkStackTest.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class NetworkStackTest {
|
||||||
|
@Rule
|
||||||
|
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
|
@Mock private IBinder mConnectorBinder;
|
||||||
|
|
||||||
|
@Before public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testGetService() {
|
||||||
|
NetworkStack.setServiceForTest(mConnectorBinder);
|
||||||
|
assertEquals(NetworkStack.getService(), mConnectorBinder);
|
||||||
|
}
|
||||||
|
}
|
||||||
73
tests/common/java/android/net/NetworkStateSnapshotTest.kt
Normal file
73
tests/common/java/android/net/NetworkStateSnapshotTest.kt
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager.TYPE_NONE
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIFI
|
||||||
|
import android.net.InetAddresses.parseNumericAddress
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.net.Inet4Address
|
||||||
|
import java.net.Inet6Address
|
||||||
|
|
||||||
|
private const val TEST_IMSI = "imsi1"
|
||||||
|
private const val TEST_SSID = "SSID1"
|
||||||
|
private const val TEST_NETID = 123
|
||||||
|
|
||||||
|
private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
|
||||||
|
private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
|
||||||
|
private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
|
||||||
|
private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
|
||||||
|
private val TEST_IFACE = "fake0"
|
||||||
|
private val TEST_LINK_PROPERTIES = LinkProperties().apply {
|
||||||
|
interfaceName = TEST_IFACE
|
||||||
|
addLinkAddress(TEST_IPV4_LINKADDR)
|
||||||
|
addLinkAddress(TEST_IPV6_LINKADDR)
|
||||||
|
|
||||||
|
// Add default routes
|
||||||
|
addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
|
||||||
|
addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val TEST_CAPABILITIES = NetworkCapabilities().apply {
|
||||||
|
addTransportType(TRANSPORT_WIFI)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
|
||||||
|
setSSID(TEST_SSID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
class NetworkStateSnapshotTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
|
||||||
|
LinkProperties(), null, TYPE_NONE)
|
||||||
|
val snapshot = NetworkStateSnapshot(
|
||||||
|
Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
|
||||||
|
assertParcelSane(emptySnapshot, 5)
|
||||||
|
assertParcelSane(snapshot, 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
160
tests/common/java/android/net/NetworkTest.java
Normal file
160
tests/common/java/android/net/NetworkTest.java
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.platform.test.annotations.AppModeFull;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NetworkTest {
|
||||||
|
final Network mNetwork = new Network(99);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindSocketOfInvalidFdThrows() throws Exception {
|
||||||
|
|
||||||
|
final FileDescriptor fd = new FileDescriptor();
|
||||||
|
assertFalse(fd.valid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNetwork.bindSocket(fd);
|
||||||
|
fail("SocketException not thrown");
|
||||||
|
} catch (SocketException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindSocketOfNonSocketFdThrows() throws Exception {
|
||||||
|
final File devNull = new File("/dev/null");
|
||||||
|
assertTrue(devNull.canRead());
|
||||||
|
|
||||||
|
final FileInputStream fis = new FileInputStream(devNull);
|
||||||
|
assertTrue(null != fis.getFD());
|
||||||
|
assertTrue(fis.getFD().valid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNetwork.bindSocket(fis.getFD());
|
||||||
|
fail("SocketException not thrown");
|
||||||
|
} catch (SocketException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@AppModeFull(reason = "Socket cannot bind in instant app mode")
|
||||||
|
public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
|
||||||
|
final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
|
||||||
|
mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
|
||||||
|
assertTrue(mDgramSocket.isConnected());
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNetwork.bindSocket(mDgramSocket);
|
||||||
|
fail("SocketException not thrown");
|
||||||
|
} catch (SocketException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindSocketOfLocalSocketThrows() throws Exception {
|
||||||
|
final LocalSocket mLocalClient = new LocalSocket();
|
||||||
|
mLocalClient.bind(new LocalSocketAddress("testClient"));
|
||||||
|
assertTrue(mLocalClient.getFileDescriptor().valid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNetwork.bindSocket(mLocalClient.getFileDescriptor());
|
||||||
|
fail("SocketException not thrown");
|
||||||
|
} catch (SocketException expected) {}
|
||||||
|
|
||||||
|
final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
|
||||||
|
mLocalClient.connect(mLocalServer.getLocalSocketAddress());
|
||||||
|
assertTrue(mLocalClient.isConnected());
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNetwork.bindSocket(mLocalClient.getFileDescriptor());
|
||||||
|
fail("SocketException not thrown");
|
||||||
|
} catch (SocketException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testZeroIsObviousForDebugging() {
|
||||||
|
Network zero = new Network(0);
|
||||||
|
assertEquals(0, zero.hashCode());
|
||||||
|
assertEquals(0, zero.getNetworkHandle());
|
||||||
|
assertEquals("0", zero.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkHandle() {
|
||||||
|
Network one = new Network(1);
|
||||||
|
Network two = new Network(2);
|
||||||
|
Network three = new Network(3);
|
||||||
|
|
||||||
|
// None of the hashcodes are zero.
|
||||||
|
assertNotEquals(0, one.hashCode());
|
||||||
|
assertNotEquals(0, two.hashCode());
|
||||||
|
assertNotEquals(0, three.hashCode());
|
||||||
|
|
||||||
|
// All the hashcodes are distinct.
|
||||||
|
assertNotEquals(one.hashCode(), two.hashCode());
|
||||||
|
assertNotEquals(one.hashCode(), three.hashCode());
|
||||||
|
assertNotEquals(two.hashCode(), three.hashCode());
|
||||||
|
|
||||||
|
// None of the handles are zero.
|
||||||
|
assertNotEquals(0, one.getNetworkHandle());
|
||||||
|
assertNotEquals(0, two.getNetworkHandle());
|
||||||
|
assertNotEquals(0, three.getNetworkHandle());
|
||||||
|
|
||||||
|
// All the handles are distinct.
|
||||||
|
assertNotEquals(one.getNetworkHandle(), two.getNetworkHandle());
|
||||||
|
assertNotEquals(one.getNetworkHandle(), three.getNetworkHandle());
|
||||||
|
assertNotEquals(two.getNetworkHandle(), three.getNetworkHandle());
|
||||||
|
|
||||||
|
// The handles are not equal to the hashcodes.
|
||||||
|
assertNotEquals(one.hashCode(), one.getNetworkHandle());
|
||||||
|
assertNotEquals(two.hashCode(), two.getNetworkHandle());
|
||||||
|
assertNotEquals(three.hashCode(), three.getNetworkHandle());
|
||||||
|
|
||||||
|
// Adjust as necessary to test an implementation's specific constants.
|
||||||
|
// When running with runtest, "adb logcat -s TestRunner" can be useful.
|
||||||
|
assertEquals(7700664333L, one.getNetworkHandle());
|
||||||
|
assertEquals(11995631629L, two.getNetworkHandle());
|
||||||
|
assertEquals(16290598925L, three.getNetworkHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPrivateDnsBypassingCopy() {
|
||||||
|
final Network copy = mNetwork.getPrivateDnsBypassingCopy();
|
||||||
|
assertEquals(mNetwork.netId, copy.netId);
|
||||||
|
assertNotEquals(copy.netId, copy.getNetIdForResolv());
|
||||||
|
assertNotEquals(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
|
||||||
|
}
|
||||||
|
}
|
||||||
152
tests/common/java/android/net/OemNetworkPreferencesTest.java
Normal file
152
tests/common/java/android/net/OemNetworkPreferencesTest.java
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.MiscAsserts.assertThrows;
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
@RunWith(DevSdkIgnoreRunner.class)
|
||||||
|
@SmallTest
|
||||||
|
public class OemNetworkPreferencesTest {
|
||||||
|
|
||||||
|
private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
|
||||||
|
private static final String TEST_PACKAGE = "com.google.apps.contacts";
|
||||||
|
|
||||||
|
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuilderAddNetworkPreferenceRequiresNonNullPackageName() {
|
||||||
|
assertThrows(NullPointerException.class,
|
||||||
|
() -> mBuilder.addNetworkPreference(null, TEST_PREF));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
|
||||||
|
assertThrows(NullPointerException.class,
|
||||||
|
() -> mBuilder.clearNetworkPreference(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkPreferenceReturnsCorrectValue() {
|
||||||
|
final int expectedNumberOfMappings = 1;
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
|
||||||
|
final Map<String, Integer> networkPreferences =
|
||||||
|
mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertEquals(expectedNumberOfMappings, networkPreferences.size());
|
||||||
|
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkPreferenceReturnsUnmodifiableValue() {
|
||||||
|
final String newPackage = "new.com.google.apps.contacts";
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
|
||||||
|
final Map<String, Integer> networkPreferences =
|
||||||
|
mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertThrows(UnsupportedOperationException.class,
|
||||||
|
() -> networkPreferences.put(newPackage, TEST_PREF));
|
||||||
|
|
||||||
|
assertThrows(UnsupportedOperationException.class,
|
||||||
|
() -> networkPreferences.remove(TEST_PACKAGE));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToStringReturnsCorrectValue() {
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
|
||||||
|
final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
|
||||||
|
|
||||||
|
assertTrue(networkPreferencesString.contains(Integer.toString(TEST_PREF)));
|
||||||
|
assertTrue(networkPreferencesString.contains(TEST_PACKAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOemNetworkPreferencesParcelable() {
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
|
||||||
|
final OemNetworkPreferences prefs = mBuilder.build();
|
||||||
|
|
||||||
|
assertParcelSane(prefs, 1 /* fieldCount */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddNetworkPreferenceOverwritesPriorPreference() {
|
||||||
|
final int newPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
Map<String, Integer> networkPreferences =
|
||||||
|
mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
|
||||||
|
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, newPref);
|
||||||
|
networkPreferences = mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), newPref);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveNetworkPreferenceRemovesValue() {
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
Map<String, Integer> networkPreferences =
|
||||||
|
mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
|
||||||
|
mBuilder.clearNetworkPreference(TEST_PACKAGE);
|
||||||
|
networkPreferences = mBuilder.build().getNetworkPreferences();
|
||||||
|
|
||||||
|
assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructorByOemNetworkPreferencesSetsValue() {
|
||||||
|
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
|
||||||
|
OemNetworkPreferences networkPreference = mBuilder.build();
|
||||||
|
|
||||||
|
final Map<String, Integer> networkPreferences =
|
||||||
|
new OemNetworkPreferences
|
||||||
|
.Builder(networkPreference)
|
||||||
|
.build()
|
||||||
|
.getNetworkPreferences();
|
||||||
|
|
||||||
|
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
|
||||||
|
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
|
||||||
|
}
|
||||||
|
}
|
||||||
434
tests/common/java/android/net/RouteInfoTest.java
Normal file
434
tests/common/java/android/net/RouteInfoTest.java
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.RouteInfo.RTN_UNREACHABLE;
|
||||||
|
|
||||||
|
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
|
||||||
|
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.core.os.BuildCompat;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class RouteInfoTest {
|
||||||
|
@Rule
|
||||||
|
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
|
private static final int INVALID_ROUTE_TYPE = -1;
|
||||||
|
|
||||||
|
private InetAddress Address(String addr) {
|
||||||
|
return InetAddresses.parseNumericAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IpPrefix Prefix(String prefix) {
|
||||||
|
return new IpPrefix(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAtLeastR() {
|
||||||
|
// BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
|
||||||
|
return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() {
|
||||||
|
RouteInfo r;
|
||||||
|
// Invalid input.
|
||||||
|
try {
|
||||||
|
r = new RouteInfo((IpPrefix) null, null, "rmnet0");
|
||||||
|
fail("Expected RuntimeException: destination and gateway null");
|
||||||
|
} catch (RuntimeException e) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
|
||||||
|
INVALID_ROUTE_TYPE);
|
||||||
|
fail("Invalid route type should cause exception");
|
||||||
|
} catch (IllegalArgumentException e) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
|
||||||
|
RTN_UNREACHABLE);
|
||||||
|
fail("Address family mismatch should cause exception");
|
||||||
|
} catch (IllegalArgumentException e) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
|
||||||
|
RTN_UNREACHABLE);
|
||||||
|
fail("Address family mismatch should cause exception");
|
||||||
|
} catch (IllegalArgumentException e) { }
|
||||||
|
|
||||||
|
// Null destination is default route.
|
||||||
|
r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
|
||||||
|
assertEquals(Prefix("::/0"), r.getDestination());
|
||||||
|
assertEquals(Address("2001:db8::1"), r.getGateway());
|
||||||
|
assertNull(r.getInterface());
|
||||||
|
|
||||||
|
r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
|
||||||
|
assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
|
||||||
|
assertEquals(Address("192.0.2.1"), r.getGateway());
|
||||||
|
assertEquals("wlan0", r.getInterface());
|
||||||
|
|
||||||
|
// Null gateway sets gateway to unspecified address (why?).
|
||||||
|
r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
|
||||||
|
assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
|
||||||
|
assertEquals(Address("::"), r.getGateway());
|
||||||
|
assertEquals("lo", r.getInterface());
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.5/24"), null);
|
||||||
|
assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
|
||||||
|
assertEquals(Address("0.0.0.0"), r.getGateway());
|
||||||
|
assertNull(r.getInterface());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMatches() {
|
||||||
|
class PatchedRouteInfo {
|
||||||
|
private final RouteInfo mRouteInfo;
|
||||||
|
|
||||||
|
public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
|
||||||
|
mRouteInfo = new RouteInfo(destination, gateway, iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(InetAddress destination) {
|
||||||
|
return mRouteInfo.matches(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PatchedRouteInfo r;
|
||||||
|
|
||||||
|
r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
|
||||||
|
assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
|
||||||
|
assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
|
||||||
|
assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
|
||||||
|
assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
|
||||||
|
assertFalse(r.matches(Address("2001:4868:4860::8888")));
|
||||||
|
assertFalse(r.matches(Address("8.8.8.8")));
|
||||||
|
|
||||||
|
r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
|
||||||
|
assertTrue(r.matches(Address("192.0.2.43")));
|
||||||
|
assertTrue(r.matches(Address("192.0.3.21")));
|
||||||
|
assertFalse(r.matches(Address("192.0.0.21")));
|
||||||
|
assertFalse(r.matches(Address("8.8.8.8")));
|
||||||
|
|
||||||
|
PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
|
||||||
|
assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
|
||||||
|
assertFalse(ipv6Default.matches(Address("192.0.2.1")));
|
||||||
|
|
||||||
|
PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
|
||||||
|
assertTrue(ipv4Default.matches(Address("255.255.255.255")));
|
||||||
|
assertTrue(ipv4Default.matches(Address("192.0.2.1")));
|
||||||
|
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
// IPv4
|
||||||
|
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
|
||||||
|
RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
|
||||||
|
assertEqualBothWays(r1, r2);
|
||||||
|
|
||||||
|
RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
|
||||||
|
RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
|
||||||
|
RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
|
||||||
|
assertNotEqualEitherWay(r1, r3);
|
||||||
|
assertNotEqualEitherWay(r1, r4);
|
||||||
|
assertNotEqualEitherWay(r1, r5);
|
||||||
|
|
||||||
|
// IPv6
|
||||||
|
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
|
||||||
|
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertEqualBothWays(r1, r2);
|
||||||
|
|
||||||
|
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
|
||||||
|
r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
|
||||||
|
r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
|
||||||
|
assertNotEqualEitherWay(r1, r3);
|
||||||
|
assertNotEqualEitherWay(r1, r4);
|
||||||
|
assertNotEqualEitherWay(r1, r5);
|
||||||
|
|
||||||
|
// Interfaces (but not destinations or gateways) can be null.
|
||||||
|
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
|
||||||
|
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
|
||||||
|
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertEqualBothWays(r1, r2);
|
||||||
|
assertNotEqualEitherWay(r1, r3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHostAndDefaultRoutes() {
|
||||||
|
RouteInfo r;
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertTrue(r.isDefaultRoute());
|
||||||
|
assertTrue(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertTrue(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertTrue(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
|
||||||
|
assertTrue(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertTrue(r.isIPv4UnreachableDefault());
|
||||||
|
assertFalse(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
|
||||||
|
assertFalse(r.isHostRoute());
|
||||||
|
assertFalse(r.isDefaultRoute());
|
||||||
|
assertFalse(r.isIPv4Default());
|
||||||
|
assertFalse(r.isIPv6Default());
|
||||||
|
if (isAtLeastR()) {
|
||||||
|
assertFalse(r.isIPv4UnreachableDefault());
|
||||||
|
assertTrue(r.isIPv6UnreachableDefault());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTruncation() {
|
||||||
|
LinkAddress l;
|
||||||
|
RouteInfo r;
|
||||||
|
|
||||||
|
l = new LinkAddress("192.0.2.5/30");
|
||||||
|
r = new RouteInfo(l, Address("192.0.2.1"), "wlan0");
|
||||||
|
assertEquals("192.0.2.4", r.getDestination().getAddress().getHostAddress());
|
||||||
|
|
||||||
|
l = new LinkAddress("2001:db8:1:f::5/63");
|
||||||
|
r = new RouteInfo(l, Address("2001:db8:5::1"), "wlan0");
|
||||||
|
assertEquals("2001:db8:1:e::", r.getDestination().getAddress().getHostAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
|
||||||
|
// there's nothing we can do with them, we don't want to crash if, e.g., someone calls
|
||||||
|
// requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
|
||||||
|
@Test
|
||||||
|
public void testMulticastRoute() {
|
||||||
|
RouteInfo r;
|
||||||
|
r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
|
||||||
|
r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), "wlan0");
|
||||||
|
// No exceptions? Good.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParceling() {
|
||||||
|
RouteInfo r;
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testMtuParceling() {
|
||||||
|
final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
|
||||||
|
RTN_UNREACHABLE, 1450 /* mtu */);
|
||||||
|
assertParcelingIsLossless(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreAfter(Build.VERSION_CODES.Q)
|
||||||
|
public void testFieldCount_Q() {
|
||||||
|
assertFieldCountEquals(6, RouteInfo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testFieldCount() {
|
||||||
|
// Make sure any new field is covered by the above parceling tests when changing this number
|
||||||
|
assertFieldCountEquals(7, RouteInfo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testMtu() {
|
||||||
|
RouteInfo r;
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
|
||||||
|
RouteInfo.RTN_UNICAST, 1500);
|
||||||
|
assertEquals(1500, r.getMtu());
|
||||||
|
|
||||||
|
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
|
||||||
|
assertEquals(0, r.getMtu());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
public void testRouteKey() {
|
||||||
|
RouteInfo.RouteKey k1, k2;
|
||||||
|
// Only prefix, null gateway and null interface
|
||||||
|
k1 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
|
||||||
|
assertEquals(k1, k2);
|
||||||
|
assertEquals(k1.hashCode(), k2.hashCode());
|
||||||
|
|
||||||
|
// With prefix, gateway and interface. Type and MTU does not affect RouteKey equality
|
||||||
|
k1 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
|
||||||
|
RTN_UNREACHABLE, 1450).getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
|
||||||
|
RouteInfo.RTN_UNICAST, 1400).getRouteKey();
|
||||||
|
assertEquals(k1, k2);
|
||||||
|
assertEquals(k1.hashCode(), k2.hashCode());
|
||||||
|
|
||||||
|
// Different scope IDs are ignored by the kernel, so we consider them equal here too.
|
||||||
|
k1 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%1"), "wlan0").getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%2"), "wlan0").getRouteKey();
|
||||||
|
assertEquals(k1, k2);
|
||||||
|
assertEquals(k1.hashCode(), k2.hashCode());
|
||||||
|
|
||||||
|
// Different prefix
|
||||||
|
k1 = new RouteInfo(Prefix("192.0.2.0/24"), null).getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("192.0.3.0/24"), null).getRouteKey();
|
||||||
|
assertNotEquals(k1, k2);
|
||||||
|
|
||||||
|
// Different gateway
|
||||||
|
k1 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), null).getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::2"), null).getRouteKey();
|
||||||
|
assertNotEquals(k1, k2);
|
||||||
|
|
||||||
|
// Different interface
|
||||||
|
k1 = new RouteInfo(Prefix("ff02::1/128"), null, "tun0").getRouteKey();
|
||||||
|
k2 = new RouteInfo(Prefix("ff02::1/128"), null, "tun1").getRouteKey();
|
||||||
|
assertNotEquals(k1, k2);
|
||||||
|
}
|
||||||
|
}
|
||||||
269
tests/common/java/android/net/StaticIpConfigurationTest.java
Normal file
269
tests/common/java/android/net/StaticIpConfigurationTest.java
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class StaticIpConfigurationTest {
|
||||||
|
|
||||||
|
private static final String ADDRSTR = "192.0.2.2/25";
|
||||||
|
private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
|
||||||
|
private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
|
||||||
|
private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
|
||||||
|
private static final InetAddress DNS1 = IpAddress("8.8.8.8");
|
||||||
|
private static final InetAddress DNS2 = IpAddress("8.8.4.4");
|
||||||
|
private static final InetAddress DNS3 = IpAddress("4.2.2.2");
|
||||||
|
private static final String IFACE = "eth0";
|
||||||
|
private static final String FAKE_DOMAINS = "google.com";
|
||||||
|
|
||||||
|
private static InetAddress IpAddress(String addr) {
|
||||||
|
return InetAddress.parseNumericAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkEmpty(StaticIpConfiguration s) {
|
||||||
|
assertNull(s.ipAddress);
|
||||||
|
assertNull(s.gateway);
|
||||||
|
assertNull(s.domains);
|
||||||
|
assertEquals(0, s.dnsServers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private StaticIpConfiguration makeTestObject() {
|
||||||
|
StaticIpConfiguration s = new StaticIpConfiguration();
|
||||||
|
s.ipAddress = ADDR;
|
||||||
|
s.gateway = GATEWAY;
|
||||||
|
s.dnsServers.add(DNS1);
|
||||||
|
s.dnsServers.add(DNS2);
|
||||||
|
s.dnsServers.add(DNS3);
|
||||||
|
s.domains = FAKE_DOMAINS;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() {
|
||||||
|
StaticIpConfiguration s = new StaticIpConfiguration();
|
||||||
|
checkEmpty(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCopyAndClear() {
|
||||||
|
StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
|
||||||
|
checkEmpty(empty);
|
||||||
|
|
||||||
|
StaticIpConfiguration s1 = makeTestObject();
|
||||||
|
StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
|
||||||
|
assertEquals(s1, s2);
|
||||||
|
s2.clear();
|
||||||
|
assertEquals(empty, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHashCodeAndEquals() {
|
||||||
|
HashSet<Integer> hashCodes = new HashSet();
|
||||||
|
hashCodes.add(0);
|
||||||
|
|
||||||
|
StaticIpConfiguration s = new StaticIpConfiguration();
|
||||||
|
// Check that this hash code is nonzero and different from all the ones seen so far.
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.ipAddress = ADDR;
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.gateway = GATEWAY;
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.dnsServers.add(DNS1);
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.dnsServers.add(DNS2);
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.dnsServers.add(DNS3);
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
s.domains = "example.com";
|
||||||
|
assertTrue(hashCodes.add(s.hashCode()));
|
||||||
|
|
||||||
|
assertFalse(s.equals(null));
|
||||||
|
assertEquals(s, s);
|
||||||
|
|
||||||
|
StaticIpConfiguration s2 = new StaticIpConfiguration(s);
|
||||||
|
assertEquals(s, s2);
|
||||||
|
|
||||||
|
s.ipAddress = new LinkAddress(DNS1, 32);
|
||||||
|
assertNotEquals(s, s2);
|
||||||
|
|
||||||
|
s2 = new StaticIpConfiguration(s);
|
||||||
|
s.domains = "foo";
|
||||||
|
assertNotEquals(s, s2);
|
||||||
|
|
||||||
|
s2 = new StaticIpConfiguration(s);
|
||||||
|
s.gateway = DNS2;
|
||||||
|
assertNotEquals(s, s2);
|
||||||
|
|
||||||
|
s2 = new StaticIpConfiguration(s);
|
||||||
|
s.dnsServers.add(DNS3);
|
||||||
|
assertNotEquals(s, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToLinkProperties() {
|
||||||
|
LinkProperties expected = new LinkProperties();
|
||||||
|
expected.setInterfaceName(IFACE);
|
||||||
|
|
||||||
|
StaticIpConfiguration s = new StaticIpConfiguration();
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
|
||||||
|
s.ipAddress = ADDR;
|
||||||
|
expected.addLinkAddress(ADDR);
|
||||||
|
expected.addRoute(connectedRoute);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.gateway = GATEWAY;
|
||||||
|
RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
|
||||||
|
expected.addRoute(defaultRoute);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.gateway = OFFLINKGATEWAY;
|
||||||
|
expected.removeRoute(defaultRoute);
|
||||||
|
defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
|
||||||
|
expected.addRoute(defaultRoute);
|
||||||
|
|
||||||
|
RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
|
||||||
|
expected.addRoute(gatewayRoute);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.dnsServers.add(DNS1);
|
||||||
|
expected.addDnsServer(DNS1);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.dnsServers.add(DNS2);
|
||||||
|
s.dnsServers.add(DNS3);
|
||||||
|
expected.addDnsServer(DNS2);
|
||||||
|
expected.addDnsServer(DNS3);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.domains = FAKE_DOMAINS;
|
||||||
|
expected.setDomains(FAKE_DOMAINS);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
s.gateway = null;
|
||||||
|
expected.removeRoute(defaultRoute);
|
||||||
|
expected.removeRoute(gatewayRoute);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
|
||||||
|
// Without knowing the IP address, we don't have a directly-connected route, so we can't
|
||||||
|
// tell if the gateway is off-link or not and we don't add a host route. This isn't a real
|
||||||
|
// configuration, but we should at least not crash.
|
||||||
|
s.gateway = OFFLINKGATEWAY;
|
||||||
|
s.ipAddress = null;
|
||||||
|
expected.removeLinkAddress(ADDR);
|
||||||
|
expected.removeRoute(connectedRoute);
|
||||||
|
expected.addRoute(defaultRoute);
|
||||||
|
assertEquals(expected, s.toLinkProperties(IFACE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
|
||||||
|
Parcel p = Parcel.obtain();
|
||||||
|
StaticIpConfiguration s2 = null;
|
||||||
|
try {
|
||||||
|
s.writeToParcel(p, 0);
|
||||||
|
p.setDataPosition(0);
|
||||||
|
s2 = StaticIpConfiguration.readFromParcel(p);
|
||||||
|
} finally {
|
||||||
|
p.recycle();
|
||||||
|
}
|
||||||
|
assertNotNull(s2);
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParceling() {
|
||||||
|
StaticIpConfiguration s = makeTestObject();
|
||||||
|
StaticIpConfiguration s2 = passThroughParcel(s);
|
||||||
|
assertEquals(s, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuilder() {
|
||||||
|
final ArrayList<InetAddress> dnsServers = new ArrayList<>();
|
||||||
|
dnsServers.add(DNS1);
|
||||||
|
|
||||||
|
final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
|
||||||
|
.setIpAddress(ADDR)
|
||||||
|
.setGateway(GATEWAY)
|
||||||
|
.setDomains(FAKE_DOMAINS)
|
||||||
|
.setDnsServers(dnsServers)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(s.ipAddress, s.getIpAddress());
|
||||||
|
assertEquals(ADDR, s.getIpAddress());
|
||||||
|
assertEquals(s.gateway, s.getGateway());
|
||||||
|
assertEquals(GATEWAY, s.getGateway());
|
||||||
|
assertEquals(s.domains, s.getDomains());
|
||||||
|
assertEquals(FAKE_DOMAINS, s.getDomains());
|
||||||
|
assertTrue(s.dnsServers.equals(s.getDnsServers()));
|
||||||
|
assertEquals(1, s.getDnsServers().size());
|
||||||
|
assertEquals(DNS1, s.getDnsServers().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDnsServers() {
|
||||||
|
final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
|
||||||
|
checkEmpty(s);
|
||||||
|
|
||||||
|
s.addDnsServer(DNS1);
|
||||||
|
assertEquals(1, s.getDnsServers().size());
|
||||||
|
assertEquals(DNS1, s.getDnsServers().get(0));
|
||||||
|
|
||||||
|
s.addDnsServer(DNS2);
|
||||||
|
s.addDnsServer(DNS3);
|
||||||
|
assertEquals(3, s.getDnsServers().size());
|
||||||
|
assertEquals(DNS2, s.getDnsServers().get(1));
|
||||||
|
assertEquals(DNS3, s.getDnsServers().get(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRoutes() {
|
||||||
|
final StaticIpConfiguration s = makeTestObject();
|
||||||
|
final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
|
||||||
|
|
||||||
|
assertEquals(2, routeInfoList.size());
|
||||||
|
assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
|
||||||
|
assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
106
tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
Normal file
106
tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.net.InetAddresses.parseNumericAddress
|
||||||
|
import android.os.Build
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import com.android.testutils.assertFieldCountEquals
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.net.InetAddress
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) // TcpKeepalivePacketData added to SDK in S
|
||||||
|
class TcpKeepalivePacketDataTest {
|
||||||
|
private fun makeData(
|
||||||
|
srcAddress: InetAddress = parseNumericAddress("192.0.2.123"),
|
||||||
|
srcPort: Int = 1234,
|
||||||
|
dstAddress: InetAddress = parseNumericAddress("192.0.2.231"),
|
||||||
|
dstPort: Int = 4321,
|
||||||
|
data: ByteArray = byteArrayOf(1, 2, 3),
|
||||||
|
tcpSeq: Int = 135,
|
||||||
|
tcpAck: Int = 246,
|
||||||
|
tcpWnd: Int = 1234,
|
||||||
|
tcpWndScale: Int = 2,
|
||||||
|
ipTos: Int = 0x12,
|
||||||
|
ipTtl: Int = 10
|
||||||
|
) = TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data, tcpSeq, tcpAck,
|
||||||
|
tcpWnd, tcpWndScale, ipTos, ipTtl)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEquals() {
|
||||||
|
val data1 = makeData()
|
||||||
|
val data2 = makeData()
|
||||||
|
assertEquals(data1, data2)
|
||||||
|
assertEquals(data1.hashCode(), data2.hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNotEquals() {
|
||||||
|
assertNotEquals(makeData(srcAddress = parseNumericAddress("192.0.2.124")), makeData())
|
||||||
|
assertNotEquals(makeData(srcPort = 1235), makeData())
|
||||||
|
assertNotEquals(makeData(dstAddress = parseNumericAddress("192.0.2.232")), makeData())
|
||||||
|
assertNotEquals(makeData(dstPort = 4322), makeData())
|
||||||
|
// .equals does not test .packet, as it should be generated from the other fields
|
||||||
|
assertNotEquals(makeData(tcpSeq = 136), makeData())
|
||||||
|
assertNotEquals(makeData(tcpAck = 247), makeData())
|
||||||
|
assertNotEquals(makeData(tcpWnd = 1235), makeData())
|
||||||
|
assertNotEquals(makeData(tcpWndScale = 3), makeData())
|
||||||
|
assertNotEquals(makeData(ipTos = 0x14), makeData())
|
||||||
|
assertNotEquals(makeData(ipTtl = 11), makeData())
|
||||||
|
|
||||||
|
// Update above assertions if field is added
|
||||||
|
assertFieldCountEquals(5, KeepalivePacketData::class.java)
|
||||||
|
assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
assertParcelSane(makeData(), fieldCount = 6) { a, b ->
|
||||||
|
// .equals() does not verify .packet
|
||||||
|
a == b && a.packet contentEquals b.packet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString() {
|
||||||
|
val data = makeData()
|
||||||
|
val str = data.toString()
|
||||||
|
|
||||||
|
assertTrue(str.contains(data.srcAddress.hostAddress))
|
||||||
|
assertTrue(str.contains(data.srcPort.toString()))
|
||||||
|
assertTrue(str.contains(data.dstAddress.hostAddress))
|
||||||
|
assertTrue(str.contains(data.dstPort.toString()))
|
||||||
|
// .packet not included in toString()
|
||||||
|
assertTrue(str.contains(data.getTcpSeq().toString()))
|
||||||
|
assertTrue(str.contains(data.getTcpAck().toString()))
|
||||||
|
assertTrue(str.contains(data.getTcpWindow().toString()))
|
||||||
|
assertTrue(str.contains(data.getTcpWindowScale().toString()))
|
||||||
|
assertTrue(str.contains(data.getIpTos().toString()))
|
||||||
|
assertTrue(str.contains(data.getIpTtl().toString()))
|
||||||
|
|
||||||
|
// Update above assertions if field is added
|
||||||
|
assertFieldCountEquals(5, KeepalivePacketData::class.java)
|
||||||
|
assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
113
tests/common/java/android/net/UidRangeTest.java
Normal file
113
tests/common/java/android/net/UidRangeTest.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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 android.net;
|
||||||
|
|
||||||
|
import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
|
||||||
|
import static android.os.UserHandle.SYSTEM;
|
||||||
|
import static android.os.UserHandle.USER_SYSTEM;
|
||||||
|
import static android.os.UserHandle.getUid;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class UidRangeTest {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
|
||||||
|
* UidRangeParcel objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleItemUidRangeAllowed() {
|
||||||
|
new UidRange(123, 123);
|
||||||
|
new UidRange(0, 0);
|
||||||
|
new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNegativeUidsDisallowed() {
|
||||||
|
try {
|
||||||
|
new UidRange(-2, 100);
|
||||||
|
fail("Exception not thrown for negative start UID");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new UidRange(-200, -100);
|
||||||
|
fail("Exception not thrown for negative stop UID");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopLessThanStartDisallowed() {
|
||||||
|
final int x = 4195000;
|
||||||
|
try {
|
||||||
|
new UidRange(x, x - 1);
|
||||||
|
fail("Exception not thrown for negative-length UID range");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetStartAndEndUser() throws Exception {
|
||||||
|
final UidRange uidRangeOfPrimaryUser = new UidRange(
|
||||||
|
getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
|
||||||
|
final UidRange uidRangeOfSecondaryUser = new UidRange(
|
||||||
|
getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
|
||||||
|
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
|
||||||
|
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
|
||||||
|
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
|
||||||
|
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
|
||||||
|
|
||||||
|
final UidRange uidRangeForDifferentUsers = new UidRange(
|
||||||
|
getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
|
||||||
|
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
|
||||||
|
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
public void testCreateForUser() throws Exception {
|
||||||
|
final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
|
||||||
|
final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
|
||||||
|
UserHandle.of(USER_SYSTEM + 1));
|
||||||
|
assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
|
||||||
|
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
|
||||||
|
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
|
||||||
|
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
|
||||||
|
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
50
tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
Normal file
50
tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
private const val TEST_OWNER_UID = 123
|
||||||
|
private const val TEST_IFACE = "test_tun0"
|
||||||
|
private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
class UnderlyingNetworkInfoTest {
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
|
||||||
|
assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
|
||||||
|
assertEquals(TEST_IFACE, testInfo.iface)
|
||||||
|
assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
|
||||||
|
assertParcelSane(testInfo, 3)
|
||||||
|
|
||||||
|
val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
|
||||||
|
assertEquals(0, emptyInfo.ownerUid)
|
||||||
|
assertEquals(String(), emptyInfo.iface)
|
||||||
|
assertEquals(listOf(), emptyInfo.underlyingIfaces)
|
||||||
|
assertParcelSane(emptyInfo, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
99
tests/common/java/android/net/apf/ApfCapabilitiesTest.java
Normal file
99
tests/common/java/android/net/apf/ApfCapabilitiesTest.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.apf;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class ApfCapabilitiesTest {
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = InstrumentationRegistry.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructAndParcel() {
|
||||||
|
final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
|
||||||
|
assertEquals(123, caps.apfVersionSupported);
|
||||||
|
assertEquals(456, caps.maximumApfProgramSize);
|
||||||
|
assertEquals(789, caps.apfPacketFormat);
|
||||||
|
|
||||||
|
assertParcelSane(caps, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
|
||||||
|
assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
|
||||||
|
assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
|
||||||
|
assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasDataAccess() {
|
||||||
|
//hasDataAccess is only supported starting at apf version 4.
|
||||||
|
ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3);
|
||||||
|
assertFalse(caps.hasDataAccess());
|
||||||
|
|
||||||
|
caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6);
|
||||||
|
assertTrue(caps.hasDataAccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetApfDrop8023Frames() {
|
||||||
|
// Get com.android.internal.R.bool.config_apfDrop802_3Frames. The test cannot directly
|
||||||
|
// use R.bool.config_apfDrop802_3Frames because that is not a stable resource ID.
|
||||||
|
final int resId = mContext.getResources().getIdentifier("config_apfDrop802_3Frames",
|
||||||
|
"bool", "android");
|
||||||
|
final boolean shouldDrop8023Frames = mContext.getResources().getBoolean(resId);
|
||||||
|
final boolean actual = ApfCapabilities.getApfDrop8023Frames();
|
||||||
|
assertEquals(shouldDrop8023Frames, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetApfEtherTypeBlackList() {
|
||||||
|
// Get com.android.internal.R.array.config_apfEthTypeBlackList. The test cannot directly
|
||||||
|
// use R.array.config_apfEthTypeBlackList because that is not a stable resource ID.
|
||||||
|
final int resId = mContext.getResources().getIdentifier("config_apfEthTypeBlackList",
|
||||||
|
"array", "android");
|
||||||
|
final int[] blacklistedEtherTypeArray = mContext.getResources().getIntArray(resId);
|
||||||
|
final int[] actual = ApfCapabilities.getApfEtherTypeBlackList();
|
||||||
|
assertNotNull(actual);
|
||||||
|
assertTrue(Arrays.equals(blacklistedEtherTypeArray, actual));
|
||||||
|
}
|
||||||
|
}
|
||||||
72
tests/common/java/android/net/metrics/ApfProgramEventTest.kt
Normal file
72
tests/common/java/android/net/metrics/ApfProgramEventTest.kt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class ApfProgramEventTest {
|
||||||
|
private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuilderAndParcel() {
|
||||||
|
val apfProgramEvent = ApfProgramEvent.Builder()
|
||||||
|
.setLifetime(1)
|
||||||
|
.setActualLifetime(2)
|
||||||
|
.setFilteredRas(3)
|
||||||
|
.setCurrentRas(4)
|
||||||
|
.setProgramLength(5)
|
||||||
|
.setFlags(true, true)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
assertEquals(1, apfProgramEvent.lifetime)
|
||||||
|
assertEquals(2, apfProgramEvent.actualLifetime)
|
||||||
|
assertEquals(3, apfProgramEvent.filteredRas)
|
||||||
|
assertEquals(4, apfProgramEvent.currentRas)
|
||||||
|
assertEquals(5, apfProgramEvent.programLength)
|
||||||
|
assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
|
||||||
|
|
||||||
|
assertParcelSane(apfProgramEvent, 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFlagsFor() {
|
||||||
|
var flags = ApfProgramEvent.flagsFor(false, false)
|
||||||
|
assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
|
||||||
|
assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
|
||||||
|
|
||||||
|
flags = ApfProgramEvent.flagsFor(true, false)
|
||||||
|
assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
|
||||||
|
assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
|
||||||
|
|
||||||
|
flags = ApfProgramEvent.flagsFor(false, true)
|
||||||
|
assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
|
||||||
|
assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
|
||||||
|
|
||||||
|
flags = ApfProgramEvent.flagsFor(true, true)
|
||||||
|
assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
|
||||||
|
assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
|
||||||
|
}
|
||||||
|
}
|
||||||
57
tests/common/java/android/net/metrics/ApfStatsTest.kt
Normal file
57
tests/common/java/android/net/metrics/ApfStatsTest.kt
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class ApfStatsTest {
|
||||||
|
@Test
|
||||||
|
fun testBuilderAndParcel() {
|
||||||
|
val apfStats = ApfStats.Builder()
|
||||||
|
.setDurationMs(Long.MAX_VALUE)
|
||||||
|
.setReceivedRas(1)
|
||||||
|
.setMatchingRas(2)
|
||||||
|
.setDroppedRas(3)
|
||||||
|
.setZeroLifetimeRas(4)
|
||||||
|
.setParseErrors(5)
|
||||||
|
.setProgramUpdates(6)
|
||||||
|
.setProgramUpdatesAll(7)
|
||||||
|
.setProgramUpdatesAllowingMulticast(8)
|
||||||
|
.setMaxProgramSize(9)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
assertEquals(Long.MAX_VALUE, apfStats.durationMs)
|
||||||
|
assertEquals(1, apfStats.receivedRas)
|
||||||
|
assertEquals(2, apfStats.matchingRas)
|
||||||
|
assertEquals(3, apfStats.droppedRas)
|
||||||
|
assertEquals(4, apfStats.zeroLifetimeRas)
|
||||||
|
assertEquals(5, apfStats.parseErrors)
|
||||||
|
assertEquals(6, apfStats.programUpdates)
|
||||||
|
assertEquals(7, apfStats.programUpdatesAll)
|
||||||
|
assertEquals(8, apfStats.programUpdatesAllowingMulticast)
|
||||||
|
assertEquals(9, apfStats.maxProgramSize)
|
||||||
|
|
||||||
|
assertParcelSane(apfStats, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
43
tests/common/java/android/net/metrics/DhcpClientEventTest.kt
Normal file
43
tests/common/java/android/net/metrics/DhcpClientEventTest.kt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
private const val FAKE_MESSAGE = "test"
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class DhcpClientEventTest {
|
||||||
|
@Test
|
||||||
|
fun testBuilderAndParcel() {
|
||||||
|
val dhcpClientEvent = DhcpClientEvent.Builder()
|
||||||
|
.setMsg(FAKE_MESSAGE)
|
||||||
|
.setDurationMs(Integer.MAX_VALUE)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
assertEquals(FAKE_MESSAGE, dhcpClientEvent.msg)
|
||||||
|
assertEquals(Integer.MAX_VALUE, dhcpClientEvent.durationMs)
|
||||||
|
|
||||||
|
assertParcelSane(dhcpClientEvent, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
65
tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
Normal file
65
tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package android.net.metrics
|
||||||
|
|
||||||
|
import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
|
||||||
|
import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.parcelingRoundTrip
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
private const val TEST_ERROR_CODE = 12345
|
||||||
|
//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
|
||||||
|
private const val DHCP_SUBNET_MASK = 1
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class DhcpErrorEventTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstructor() {
|
||||||
|
val event = DhcpErrorEvent(TEST_ERROR_CODE)
|
||||||
|
assertEquals(TEST_ERROR_CODE, event.errorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
val event = DhcpErrorEvent(TEST_ERROR_CODE)
|
||||||
|
val parceled = parcelingRoundTrip(event)
|
||||||
|
assertEquals(TEST_ERROR_CODE, parceled.errorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testErrorCodeWithOption() {
|
||||||
|
val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
|
||||||
|
assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
|
||||||
|
assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString() {
|
||||||
|
val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
|
||||||
|
val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
|
||||||
|
it.type == Int::class.javaPrimitiveType
|
||||||
|
&& Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
|
||||||
|
&& it.name !in names
|
||||||
|
}
|
||||||
|
|
||||||
|
errorFields.forEach {
|
||||||
|
val intValue = it.getInt(null)
|
||||||
|
val stringValue = DhcpErrorEvent(intValue).toString()
|
||||||
|
assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
|
||||||
|
stringValue),
|
||||||
|
stringValue.contains(it.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString_InvalidErrorCode() {
|
||||||
|
assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
161
tests/common/java/android/net/metrics/IpConnectivityLogTest.java
Normal file
161
tests/common/java/android/net/metrics/IpConnectivityLogTest.java
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.net.ConnectivityMetricsEvent;
|
||||||
|
import android.net.IIpConnectivityMetrics;
|
||||||
|
import android.net.Network;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.util.BitUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class IpConnectivityLogTest {
|
||||||
|
private static final int FAKE_NET_ID = 100;
|
||||||
|
private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
|
||||||
|
private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
|
||||||
|
private static final String FAKE_INTERFACE_NAME = "test";
|
||||||
|
private static final IpReachabilityEvent FAKE_EV =
|
||||||
|
new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
|
||||||
|
|
||||||
|
@Mock IIpConnectivityMetrics mMockService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoggingEvents() throws Exception {
|
||||||
|
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
|
||||||
|
|
||||||
|
assertTrue(logger.log(FAKE_EV));
|
||||||
|
assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
|
||||||
|
assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
|
||||||
|
assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
|
||||||
|
assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
|
||||||
|
assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
|
||||||
|
FAKE_INTERFACE_NAME)));
|
||||||
|
|
||||||
|
List<ConnectivityMetricsEvent> got = verifyEvents(6);
|
||||||
|
assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
|
||||||
|
assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
|
||||||
|
assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
|
||||||
|
TRANSPORT_WIFI, null), got.get(2));
|
||||||
|
assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
|
||||||
|
TRANSPORT_WIFI, null), got.get(3));
|
||||||
|
assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
|
||||||
|
got.get(4));
|
||||||
|
assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
|
||||||
|
TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoggingEventsWithMultipleCallers() throws Exception {
|
||||||
|
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
|
||||||
|
|
||||||
|
final int nCallers = 10;
|
||||||
|
final int nEvents = 10;
|
||||||
|
for (int n = 0; n < nCallers; n++) {
|
||||||
|
final int i = n;
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
for (int j = 0; j < nEvents; j++) {
|
||||||
|
assertTrue(logger.log(makeExpectedEvent(
|
||||||
|
FAKE_TIME_STAMP + i * 100 + j,
|
||||||
|
FAKE_NET_ID + i * 100 + j,
|
||||||
|
((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
|
||||||
|
FAKE_INTERFACE_NAME)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
|
||||||
|
Collections.sort(got, EVENT_COMPARATOR);
|
||||||
|
Iterator<ConnectivityMetricsEvent> iter = got.iterator();
|
||||||
|
for (int i = 0; i < nCallers; i++) {
|
||||||
|
for (int j = 0; j < nEvents; j++) {
|
||||||
|
final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
|
||||||
|
final int expectedNetId = FAKE_NET_ID + i * 100 + j;
|
||||||
|
final long expectedTransports =
|
||||||
|
((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
|
||||||
|
assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
|
||||||
|
expectedTransports, FAKE_INTERFACE_NAME), iter.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
|
||||||
|
ArgumentCaptor<ConnectivityMetricsEvent> captor =
|
||||||
|
ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
|
||||||
|
verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
|
||||||
|
return captor.getAllValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
|
||||||
|
return verifyEvents(n, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
|
||||||
|
String ifname) {
|
||||||
|
ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
|
||||||
|
ev.timestamp = timestamp;
|
||||||
|
ev.data = FAKE_EV;
|
||||||
|
ev.netId = netId;
|
||||||
|
ev.transports = transports;
|
||||||
|
ev.ifname = ifname;
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
|
||||||
|
private void assertEventsEqual(ConnectivityMetricsEvent expected,
|
||||||
|
ConnectivityMetricsEvent got) {
|
||||||
|
assertEquals(expected.data, got.data);
|
||||||
|
assertEquals(expected.timestamp, got.timestamp);
|
||||||
|
assertEquals(expected.netId, got.netId);
|
||||||
|
assertEquals(expected.transports, got.transports);
|
||||||
|
assertEquals(expected.ifname, got.ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
|
||||||
|
Comparator.comparingLong((ev) -> ev.timestamp);
|
||||||
|
}
|
||||||
39
tests/common/java/android/net/metrics/IpManagerEventTest.kt
Normal file
39
tests/common/java/android/net/metrics/IpManagerEventTest.kt
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class IpManagerEventTest {
|
||||||
|
@Test
|
||||||
|
fun testConstructorAndParcel() {
|
||||||
|
(IpManagerEvent.PROVISIONING_OK..IpManagerEvent.ERROR_INTERFACE_NOT_FOUND).forEach {
|
||||||
|
val ipManagerEvent = IpManagerEvent(it, Long.MAX_VALUE)
|
||||||
|
assertEquals(it, ipManagerEvent.eventType)
|
||||||
|
assertEquals(Long.MAX_VALUE, ipManagerEvent.durationMs)
|
||||||
|
|
||||||
|
assertParcelSane(ipManagerEvent, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class IpReachabilityEventTest {
|
||||||
|
@Test
|
||||||
|
fun testConstructorAndParcel() {
|
||||||
|
(IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
|
||||||
|
val ipReachabilityEvent = IpReachabilityEvent(it)
|
||||||
|
assertEquals(it, ipReachabilityEvent.eventType)
|
||||||
|
|
||||||
|
assertParcelSane(ipReachabilityEvent, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
tests/common/java/android/net/metrics/NetworkEventTest.kt
Normal file
43
tests/common/java/android/net/metrics/NetworkEventTest.kt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NetworkEventTest {
|
||||||
|
@Test
|
||||||
|
fun testConstructorAndParcel() {
|
||||||
|
(NetworkEvent.NETWORK_CONNECTED..NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY).forEach {
|
||||||
|
var networkEvent = NetworkEvent(it)
|
||||||
|
assertEquals(it, networkEvent.eventType)
|
||||||
|
assertEquals(0, networkEvent.durationMs)
|
||||||
|
|
||||||
|
networkEvent = NetworkEvent(it, Long.MAX_VALUE)
|
||||||
|
assertEquals(it, networkEvent.eventType)
|
||||||
|
assertEquals(Long.MAX_VALUE, networkEvent.durationMs)
|
||||||
|
|
||||||
|
assertParcelSane(networkEvent, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
tests/common/java/android/net/metrics/RaEventTest.kt
Normal file
72
tests/common/java/android/net/metrics/RaEventTest.kt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
private const val NO_LIFETIME: Long = -1L
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class RaEventTest {
|
||||||
|
@Test
|
||||||
|
fun testConstructorAndParcel() {
|
||||||
|
var raEvent = RaEvent.Builder().build()
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.routerLifetime)
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
|
||||||
|
assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
|
||||||
|
|
||||||
|
raEvent = RaEvent.Builder()
|
||||||
|
.updateRouterLifetime(1)
|
||||||
|
.updatePrefixValidLifetime(2)
|
||||||
|
.updatePrefixPreferredLifetime(3)
|
||||||
|
.updateRouteInfoLifetime(4)
|
||||||
|
.updateRdnssLifetime(5)
|
||||||
|
.updateDnsslLifetime(6)
|
||||||
|
.build()
|
||||||
|
assertEquals(1, raEvent.routerLifetime)
|
||||||
|
assertEquals(2, raEvent.prefixValidLifetime)
|
||||||
|
assertEquals(3, raEvent.prefixPreferredLifetime)
|
||||||
|
assertEquals(4, raEvent.routeInfoLifetime)
|
||||||
|
assertEquals(5, raEvent.rdnssLifetime)
|
||||||
|
assertEquals(6, raEvent.dnsslLifetime)
|
||||||
|
|
||||||
|
raEvent = RaEvent.Builder()
|
||||||
|
.updateRouterLifetime(Long.MIN_VALUE)
|
||||||
|
.updateRouterLifetime(Long.MAX_VALUE)
|
||||||
|
.build()
|
||||||
|
assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
|
||||||
|
|
||||||
|
raEvent = RaEvent(1, 2, 3, 4, 5, 6)
|
||||||
|
assertEquals(1, raEvent.routerLifetime)
|
||||||
|
assertEquals(2, raEvent.prefixValidLifetime)
|
||||||
|
assertEquals(3, raEvent.prefixPreferredLifetime)
|
||||||
|
assertEquals(4, raEvent.routeInfoLifetime)
|
||||||
|
assertEquals(5, raEvent.rdnssLifetime)
|
||||||
|
assertEquals(6, raEvent.dnsslLifetime)
|
||||||
|
|
||||||
|
assertParcelSane(raEvent, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.metrics
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
private const val FIRST_VALIDATION: Int = 1 shl 8
|
||||||
|
private const val REVALIDATION: Int = 2 shl 8
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class ValidationProbeEventTest {
|
||||||
|
private infix fun Int.hasType(type: Int) = (type and this) == type
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuilderAndParcel() {
|
||||||
|
var validationProbeEvent = ValidationProbeEvent.Builder()
|
||||||
|
.setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
|
||||||
|
|
||||||
|
assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
|
||||||
|
|
||||||
|
validationProbeEvent = ValidationProbeEvent.Builder()
|
||||||
|
.setDurationMs(Long.MAX_VALUE)
|
||||||
|
.setProbeType(ValidationProbeEvent.PROBE_DNS, true)
|
||||||
|
.setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
|
||||||
|
assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
|
||||||
|
assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
|
||||||
|
assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
|
||||||
|
|
||||||
|
assertParcelSane(validationProbeEvent, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetProbeName() {
|
||||||
|
val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
|
||||||
|
it.type == Int::class.javaPrimitiveType
|
||||||
|
&& Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
|
||||||
|
&& it.name.contains("PROBE")
|
||||||
|
}
|
||||||
|
|
||||||
|
probeFields.forEach {
|
||||||
|
val intValue = it.getInt(null)
|
||||||
|
val stringValue = ValidationProbeEvent.getProbeName(intValue)
|
||||||
|
assertEquals(it.name, stringValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
209
tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
Normal file
209
tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net.netstats
|
||||||
|
|
||||||
|
import android.net.NetworkStats
|
||||||
|
import android.net.NetworkStats.DEFAULT_NETWORK_NO
|
||||||
|
import android.net.NetworkStats.DEFAULT_NETWORK_YES
|
||||||
|
import android.net.NetworkStats.Entry
|
||||||
|
import android.net.NetworkStats.IFACE_VT
|
||||||
|
import android.net.NetworkStats.METERED_NO
|
||||||
|
import android.net.NetworkStats.METERED_YES
|
||||||
|
import android.net.NetworkStats.ROAMING_NO
|
||||||
|
import android.net.NetworkStats.ROAMING_YES
|
||||||
|
import android.net.NetworkStats.SET_DEFAULT
|
||||||
|
import android.net.NetworkStats.SET_FOREGROUND
|
||||||
|
import android.net.NetworkStats.TAG_NONE
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.assertFieldCountEquals
|
||||||
|
import com.android.testutils.assertNetworkStatsEquals
|
||||||
|
import com.android.testutils.assertParcelingIsLossless
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NetworkStatsApiTest {
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
|
||||||
|
|
||||||
|
private val testStatsEmpty = NetworkStats(0L, 0)
|
||||||
|
|
||||||
|
// Note that these variables need to be initialized outside of constructor, initialize
|
||||||
|
// here with methods that don't exist in Q devices will result in crash.
|
||||||
|
|
||||||
|
// stats1 and stats2 will have some entries with common keys, which are expected to
|
||||||
|
// be merged if performing add on these 2 stats.
|
||||||
|
private lateinit var testStats1: NetworkStats
|
||||||
|
private lateinit var testStats2: NetworkStats
|
||||||
|
|
||||||
|
// This is a result of adding stats1 and stats2, while the merging of common key items is
|
||||||
|
// subject to test later, this should not be initialized with for a loop to add stats1
|
||||||
|
// and stats2 above.
|
||||||
|
private lateinit var testStats3: NetworkStats
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TEST_IFACE = "test0"
|
||||||
|
private const val TEST_UID1 = 1001
|
||||||
|
private const val TEST_UID2 = 1002
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
testStats1 = NetworkStats(0L, 0)
|
||||||
|
// Entries which only appear in set1.
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
|
||||||
|
// Entries which are common for set1 and set2.
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
|
||||||
|
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
|
||||||
|
assertEquals(8, testStats1.size())
|
||||||
|
|
||||||
|
testStats2 = NetworkStats(0L, 0)
|
||||||
|
// Entries which are common for set1 and set2.
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
|
||||||
|
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
|
||||||
|
// Entry which only appears in set2.
|
||||||
|
.addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
|
||||||
|
assertEquals(5, testStats2.size())
|
||||||
|
|
||||||
|
testStats3 = NetworkStats(0L, 9)
|
||||||
|
// Entries which are unique either in stats1 or stats2.
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
|
||||||
|
.addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
|
||||||
|
// Entries which are common for stats1 and stats2 are being merged.
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
|
||||||
|
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
|
||||||
|
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
|
||||||
|
assertEquals(9, testStats3.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddEntry() {
|
||||||
|
val expectedEntriesInStats2 = arrayOf(
|
||||||
|
Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
|
||||||
|
Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
|
||||||
|
Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
|
||||||
|
Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
|
||||||
|
Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
|
||||||
|
|
||||||
|
// While testStats* are already initialized with addEntry, verify content added
|
||||||
|
// matches expectation.
|
||||||
|
for (i in expectedEntriesInStats2.indices) {
|
||||||
|
val entry = testStats2.getValues(i, null)
|
||||||
|
assertEquals(expectedEntriesInStats2[i], entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify entry updated with addEntry.
|
||||||
|
val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
|
||||||
|
assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
|
||||||
|
stats.getValues(3, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAdd() {
|
||||||
|
var stats = NetworkStats(0L, 0)
|
||||||
|
assertNetworkStatsEquals(testStatsEmpty, stats)
|
||||||
|
stats = stats.add(testStats2)
|
||||||
|
assertNetworkStatsEquals(testStats2, stats)
|
||||||
|
stats = stats.add(testStats1)
|
||||||
|
// EMPTY + STATS2 + STATS1 = STATS3
|
||||||
|
assertNetworkStatsEquals(testStats3, stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
assertParcelingIsLossless(testStatsEmpty)
|
||||||
|
assertParcelingIsLossless(testStats1)
|
||||||
|
assertParcelingIsLossless(testStats2)
|
||||||
|
assertFieldCountEquals(15, NetworkStats::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDescribeContents() {
|
||||||
|
assertEquals(0, testStatsEmpty.describeContents())
|
||||||
|
assertEquals(0, testStats1.describeContents())
|
||||||
|
assertEquals(0, testStats2.describeContents())
|
||||||
|
assertEquals(0, testStats3.describeContents())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSubtract() {
|
||||||
|
// STATS3 - STATS2 = STATS1
|
||||||
|
assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
|
||||||
|
// STATS3 - STATS1 = STATS2
|
||||||
|
assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMethodsDontModifyReceiver() {
|
||||||
|
listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
|
||||||
|
val origStats = it.clone()
|
||||||
|
it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
|
||||||
|
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
|
||||||
|
it.add(testStats3)
|
||||||
|
it.subtract(testStats1)
|
||||||
|
assertNetworkStatsEquals(origStats, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
tests/common/java/android/net/util/SocketUtilsTest.kt
Normal file
90
tests/common/java/android/net/util/SocketUtilsTest.kt
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.util
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.system.NetlinkSocketAddress
|
||||||
|
import android.system.Os
|
||||||
|
import android.system.OsConstants.AF_INET
|
||||||
|
import android.system.OsConstants.ETH_P_ALL
|
||||||
|
import android.system.OsConstants.IPPROTO_UDP
|
||||||
|
import android.system.OsConstants.RTMGRP_NEIGH
|
||||||
|
import android.system.OsConstants.SOCK_DGRAM
|
||||||
|
import android.system.PacketSocketAddress
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
private const val TEST_INDEX = 123
|
||||||
|
private const val TEST_PORT = 555
|
||||||
|
private const val FF_BYTE = 0xff.toByte()
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class SocketUtilsTest {
|
||||||
|
@Rule @JvmField
|
||||||
|
val ignoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMakeNetlinkSocketAddress() {
|
||||||
|
val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
|
||||||
|
if (nlAddress is NetlinkSocketAddress) {
|
||||||
|
assertEquals(TEST_PORT, nlAddress.getPortId())
|
||||||
|
assertEquals(RTMGRP_NEIGH, nlAddress.getGroupsMask())
|
||||||
|
} else {
|
||||||
|
fail("Not NetlinkSocketAddress object")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMakePacketSocketAddress_Q() {
|
||||||
|
val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
|
||||||
|
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
|
||||||
|
|
||||||
|
val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
|
||||||
|
assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
|
||||||
|
fun testMakePacketSocketAddress() {
|
||||||
|
val pkAddress = SocketUtils.makePacketSocketAddress(
|
||||||
|
ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
|
||||||
|
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCloseSocket() {
|
||||||
|
// Expect no exception happening with null object.
|
||||||
|
SocketUtils.closeSocket(null)
|
||||||
|
|
||||||
|
val fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
||||||
|
assertTrue(fd.valid())
|
||||||
|
SocketUtils.closeSocket(fd)
|
||||||
|
assertFalse(fd.valid())
|
||||||
|
// Expecting socket should be still invalid even closed socket again.
|
||||||
|
SocketUtils.closeSocket(fd)
|
||||||
|
assertFalse(fd.valid())
|
||||||
|
}
|
||||||
|
}
|
||||||
39
tests/deflake/Android.bp
Normal file
39
tests/deflake/Android.bp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2019 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 {
|
||||||
|
// See: http://go/android-license-faq
|
||||||
|
// A large-scale-change added 'default_applicable_licenses' to import
|
||||||
|
// all of the 'license_kinds' from "frameworks_base_license"
|
||||||
|
// to get the below license kinds:
|
||||||
|
// SPDX-license-identifier-Apache-2.0
|
||||||
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_test_host {
|
||||||
|
name: "FrameworksNetDeflakeTest",
|
||||||
|
srcs: ["src/**/*.kt"],
|
||||||
|
libs: [
|
||||||
|
"junit",
|
||||||
|
"tradefed",
|
||||||
|
],
|
||||||
|
static_libs: [
|
||||||
|
"kotlin-test",
|
||||||
|
"net-host-tests-utils",
|
||||||
|
],
|
||||||
|
data: [":FrameworksNetTests"],
|
||||||
|
test_suites: ["device-tests"],
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net
|
||||||
|
|
||||||
|
import com.android.testutils.host.DeflakeHostTestBase
|
||||||
|
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(DeviceJUnit4ClassRunner::class)
|
||||||
|
class FrameworksNetDeflakeTest: DeflakeHostTestBase() {
|
||||||
|
override val runCount = 20
|
||||||
|
override val testApkFilename = "FrameworksNetTests.apk"
|
||||||
|
override val testClasses = listOf("com.android.server.ConnectivityServiceTest")
|
||||||
|
}
|
||||||
76
tests/integration/Android.bp
Normal file
76
tests/integration/Android.bp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2019 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 {
|
||||||
|
// See: http://go/android-license-faq
|
||||||
|
// A large-scale-change added 'default_applicable_licenses' to import
|
||||||
|
// all of the 'license_kinds' from "frameworks_base_license"
|
||||||
|
// to get the below license kinds:
|
||||||
|
// SPDX-license-identifier-Apache-2.0
|
||||||
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
|
}
|
||||||
|
|
||||||
|
android_test {
|
||||||
|
name: "FrameworksNetIntegrationTests",
|
||||||
|
platform_apis: true,
|
||||||
|
certificate: "platform",
|
||||||
|
srcs: [
|
||||||
|
"src/**/*.kt",
|
||||||
|
"src/**/*.aidl",
|
||||||
|
],
|
||||||
|
libs: [
|
||||||
|
"android.test.mock",
|
||||||
|
],
|
||||||
|
static_libs: [
|
||||||
|
"NetworkStackApiStableLib",
|
||||||
|
"androidx.test.ext.junit",
|
||||||
|
"frameworks-net-integration-testutils",
|
||||||
|
"kotlin-reflect",
|
||||||
|
"mockito-target-extended-minus-junit4",
|
||||||
|
"net-tests-utils",
|
||||||
|
"service-connectivity",
|
||||||
|
"services.core",
|
||||||
|
"services.net",
|
||||||
|
"testables",
|
||||||
|
],
|
||||||
|
test_suites: ["device-tests"],
|
||||||
|
use_embedded_native_libs: true,
|
||||||
|
jni_libs: [
|
||||||
|
// For mockito extended
|
||||||
|
"libdexmakerjvmtiagent",
|
||||||
|
"libstaticjvmtiagent",
|
||||||
|
// android_library does not include JNI libs: include NetworkStack dependencies here
|
||||||
|
"libnativehelper_compat_libc++",
|
||||||
|
"libnetworkstackutilsjni",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utilities for testing framework code both in integration and unit tests.
|
||||||
|
java_library {
|
||||||
|
name: "frameworks-net-integration-testutils",
|
||||||
|
srcs: ["util/**/*.java", "util/**/*.kt"],
|
||||||
|
static_libs: [
|
||||||
|
"androidx.annotation_annotation",
|
||||||
|
"androidx.test.rules",
|
||||||
|
"junit",
|
||||||
|
"net-tests-utils",
|
||||||
|
],
|
||||||
|
libs: [
|
||||||
|
"service-connectivity",
|
||||||
|
"services.core",
|
||||||
|
"services.net",
|
||||||
|
],
|
||||||
|
}
|
||||||
73
tests/integration/AndroidManifest.xml
Normal file
73
tests/integration/AndroidManifest.xml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.server.net.integrationtests">
|
||||||
|
|
||||||
|
<!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
|
||||||
|
<!-- PermissionMonitor sets network permissions for each user -->
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_USERS"/>
|
||||||
|
<!-- ConnectivityService sends notifications to BatteryStats -->
|
||||||
|
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
|
||||||
|
<!-- Reading network status -->
|
||||||
|
<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"/>
|
||||||
|
<!-- Reading DeviceConfig flags -->
|
||||||
|
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
|
||||||
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
|
||||||
|
<!-- Querying the resources package -->
|
||||||
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||||
|
<application android:debuggable="true">
|
||||||
|
<uses-library android:name="android.test.runner"/>
|
||||||
|
|
||||||
|
<!-- This manifest is merged with the base manifest of the real NetworkStack app.
|
||||||
|
Remove the NetworkStackService from the base (real) manifest, and replace with a test
|
||||||
|
service that responds to the same intent -->
|
||||||
|
<service android:name=".TestNetworkStackService"
|
||||||
|
android:process="com.android.server.net.integrationtests.testnetworkstack"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.net.INetworkStackConnector.Test"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
<service android:name=".NetworkStackInstrumentationService"
|
||||||
|
android:process="com.android.server.net.integrationtests.testnetworkstack"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name=".INetworkStackInstrumentation"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
<service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
|
||||||
|
android:process="com.android.server.net.integrationtests.testnetworkstack"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE"/>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
android:targetPackage="com.android.server.net.integrationtests"
|
||||||
|
android:label="Frameworks Net Integration Tests"/>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
15
tests/integration/res/values/config.xml
Normal file
15
tests/integration/res/values/config.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!--
|
||||||
|
Override configuration for testing. The below settings use the config_ variants, which are
|
||||||
|
normally used by RROs to override the setting with highest priority. -->
|
||||||
|
<integer name="config_captive_portal_dns_probe_timeout">12500</integer>
|
||||||
|
<string name="config_captive_portal_http_url" translatable="false">http://test.android.com</string>
|
||||||
|
<string name="config_captive_portal_https_url" translatable="false">https://secure.test.android.com</string>
|
||||||
|
<string-array name="config_captive_portal_fallback_urls" translatable="false">
|
||||||
|
<item>http://fallback1.android.com</item>
|
||||||
|
<item>http://fallback2.android.com</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
80
tests/integration/src/android/net/TestNetworkStackClient.kt
Normal file
80
tests/integration/src/android/net/TestNetworkStackClient.kt
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.android.server.net.integrationtests.TestNetworkStackService
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.spy
|
||||||
|
import org.mockito.Mockito.timeout
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
const val TEST_ACTION_SUFFIX = ".Test"
|
||||||
|
|
||||||
|
class TestNetworkStackClient(context: Context) : NetworkStackClient(TestDependencies(context)) {
|
||||||
|
// TODO: consider switching to TrackRecord for more expressive checks
|
||||||
|
private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
|
||||||
|
|
||||||
|
private class TestDependencies(private val context: Context) : Dependencies {
|
||||||
|
override fun addToServiceManager(service: IBinder) = Unit
|
||||||
|
override fun checkCallerUid() = Unit
|
||||||
|
|
||||||
|
override fun getConnectivityModuleConnector(): ConnectivityModuleConnector {
|
||||||
|
return ConnectivityModuleConnector { _, _, _, inSystemProcess ->
|
||||||
|
getNetworkStackIntent(inSystemProcess)
|
||||||
|
}.also { it.init(context) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNetworkStackIntent(inSystemProcess: Boolean): Intent? {
|
||||||
|
// Simulate out-of-system-process config: in-process service not found (null intent)
|
||||||
|
if (inSystemProcess) return null
|
||||||
|
val intent = Intent(INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX)
|
||||||
|
val serviceName = TestNetworkStackService::class.qualifiedName
|
||||||
|
?: fail("TestNetworkStackService name not found")
|
||||||
|
intent.component = ComponentName(context.packageName, serviceName)
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// base may be an instance of an inaccessible subclass, so non-spyable.
|
||||||
|
// Use a known open class that delegates to the original instance for all methods except
|
||||||
|
// asBinder. asBinder needs to use its own non-delegated implementation as otherwise it would
|
||||||
|
// return a binder token to a class that is not spied on.
|
||||||
|
open class NetworkMonitorCallbacksWrapper(private val base: INetworkMonitorCallbacks) :
|
||||||
|
INetworkMonitorCallbacks.Stub(), INetworkMonitorCallbacks by base {
|
||||||
|
// asBinder is implemented by both base class and delegate: specify explicitly
|
||||||
|
override fun asBinder(): IBinder {
|
||||||
|
return super.asBinder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun makeNetworkMonitor(network: Network, name: String?, cb: INetworkMonitorCallbacks) {
|
||||||
|
val cbSpy = spy(NetworkMonitorCallbacksWrapper(cb))
|
||||||
|
lastCallbacks[network] = cbSpy
|
||||||
|
super.makeNetworkMonitor(network, name, cbSpy)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyNetworkMonitorCreated(network: Network, timeoutMs: Long) {
|
||||||
|
val cb = lastCallbacks[network]
|
||||||
|
?: fail("NetworkMonitor for network $network not requested")
|
||||||
|
verify(cb, timeout(timeoutMs)).onNetworkMonitorCreated(any())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests
|
||||||
|
|
||||||
|
import android.app.usage.NetworkStatsManager
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.BIND_AUTO_CREATE
|
||||||
|
import android.content.Context.BIND_IMPORTANT
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.IDnsResolver
|
||||||
|
import android.net.INetd
|
||||||
|
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
|
||||||
|
import android.os.SystemConfigManager
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.testing.TestableContext
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.android.server.ConnectivityService
|
||||||
|
import com.android.server.NetworkAgentWrapper
|
||||||
|
import com.android.server.TestNetIdManager
|
||||||
|
import com.android.server.connectivity.MockableSystemProperties
|
||||||
|
import com.android.server.connectivity.ProxyTracker
|
||||||
|
import com.android.testutils.TestableNetworkCallback
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.AdditionalAnswers
|
||||||
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.anyInt
|
||||||
|
import org.mockito.Mockito.doNothing
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.eq
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
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
|
||||||
|
|
||||||
|
const val SERVICE_BIND_TIMEOUT_MS = 5_000L
|
||||||
|
const val TEST_TIMEOUT_MS = 10_000L
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that exercises an instrumented version of ConnectivityService against an instrumented
|
||||||
|
* NetworkStack in a different test process.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ConnectivityServiceIntegrationTest {
|
||||||
|
// lateinit used here for mocks as they need to be reinitialized between each test and the test
|
||||||
|
// should crash if they are used before being initialized.
|
||||||
|
@Mock
|
||||||
|
private lateinit var statsManager: NetworkStatsManager
|
||||||
|
@Mock
|
||||||
|
private lateinit var log: IpConnectivityLog
|
||||||
|
@Mock
|
||||||
|
private lateinit var netd: INetd
|
||||||
|
@Mock
|
||||||
|
private lateinit var dnsResolver: IDnsResolver
|
||||||
|
@Mock
|
||||||
|
private lateinit var systemConfigManager: SystemConfigManager
|
||||||
|
@Spy
|
||||||
|
private var context = TestableContext(realContext)
|
||||||
|
|
||||||
|
// lateinit for these three classes under test, as they should be reset to a different instance
|
||||||
|
// for every test but should always be initialized before use (or the test should crash).
|
||||||
|
private lateinit var networkStackClient: TestNetworkStackClient
|
||||||
|
private lateinit var service: ConnectivityService
|
||||||
|
private lateinit var cm: ConnectivityManager
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// lateinit for this binder token, as it must be initialized before any test code is run
|
||||||
|
// and use of it before init should crash the test.
|
||||||
|
private lateinit var nsInstrumentation: INetworkStackInstrumentation
|
||||||
|
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?) {
|
||||||
|
Log.i("TestNetworkStack", "Service connected")
|
||||||
|
try {
|
||||||
|
if (service == null) fail("Error binding to NetworkStack instrumentation")
|
||||||
|
if (::nsInstrumentation.isInitialized) fail("Service already connected")
|
||||||
|
nsInstrumentation = INetworkStackInstrumentation.Stub.asInterface(service)
|
||||||
|
} finally {
|
||||||
|
bindingCondition.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun setUpClass() {
|
||||||
|
val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
|
||||||
|
intent.action = INetworkStackInstrumentation::class.qualifiedName
|
||||||
|
assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
|
||||||
|
BIND_AUTO_CREATE or BIND_IMPORTANT),
|
||||||
|
"Error binding to instrumentation service")
|
||||||
|
assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
|
||||||
|
"Timed out binding to instrumentation service " +
|
||||||
|
"after $SERVICE_BIND_TIMEOUT_MS ms")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
val asUserCtx = mock(Context::class.java, AdditionalAnswers.delegatesTo<Context>(context))
|
||||||
|
doReturn(UserHandle.ALL).`when`(asUserCtx).user
|
||||||
|
doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
|
||||||
|
doNothing().`when`(context).sendStickyBroadcast(any(), any())
|
||||||
|
doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context)
|
||||||
|
.getSystemServiceName(SystemConfigManager::class.java)
|
||||||
|
doReturn(systemConfigManager).`when`(context)
|
||||||
|
.getSystemService(Context.SYSTEM_CONFIG_SERVICE)
|
||||||
|
doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
|
||||||
|
|
||||||
|
networkStackClient = TestNetworkStackClient(realContext)
|
||||||
|
networkStackClient.init()
|
||||||
|
networkStackClient.start()
|
||||||
|
|
||||||
|
service = TestConnectivityService(makeDependencies())
|
||||||
|
cm = ConnectivityManager(context, service)
|
||||||
|
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
|
||||||
|
context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager)
|
||||||
|
|
||||||
|
service.systemReadyInternal()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
|
||||||
|
context, dnsResolver, log, netd, deps)
|
||||||
|
|
||||||
|
private fun makeDependencies(): ConnectivityService.Dependencies {
|
||||||
|
val deps = spy(ConnectivityService.Dependencies())
|
||||||
|
doReturn(networkStackClient).`when`(deps).networkStack
|
||||||
|
doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
|
||||||
|
doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
|
||||||
|
doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
nsInstrumentation.clearAllState()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testValidation() {
|
||||||
|
val request = NetworkRequest.Builder()
|
||||||
|
.clearCapabilities()
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.build()
|
||||||
|
val testCallback = TestableNetworkCallback()
|
||||||
|
|
||||||
|
cm.registerNetworkCallback(request, testCallback)
|
||||||
|
nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
|
||||||
|
nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
|
||||||
|
|
||||||
|
val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
|
||||||
|
context)
|
||||||
|
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
|
||||||
|
|
||||||
|
na.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
na.connect()
|
||||||
|
|
||||||
|
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, null /* ncTemplate */, 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests;
|
||||||
|
|
||||||
|
parcelable HttpResponse;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
data class HttpResponse(
|
||||||
|
val requestUrl: String,
|
||||||
|
val responseCode: Int,
|
||||||
|
val content: String = "",
|
||||||
|
val redirectUrl: String? = null
|
||||||
|
) : Parcelable {
|
||||||
|
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)
|
||||||
|
writeString(content)
|
||||||
|
writeString(redirectUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents() = 0
|
||||||
|
companion object CREATOR : Parcelable.Creator<HttpResponse> {
|
||||||
|
override fun createFromParcel(source: Parcel) = HttpResponse(source)
|
||||||
|
override fun newArray(size: Int) = arrayOfNulls<HttpResponse?>(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests;
|
||||||
|
|
||||||
|
import com.android.server.net.integrationtests.HttpResponse;
|
||||||
|
|
||||||
|
interface INetworkStackInstrumentation {
|
||||||
|
void clearAllState();
|
||||||
|
void addHttpResponse(in HttpResponse response);
|
||||||
|
List<String> getRequestUrls();
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instrumentation interface for the NetworkStack that allows controlling behavior to
|
||||||
|
* facilitate integration tests.
|
||||||
|
*/
|
||||||
|
class NetworkStackInstrumentationService : Service() {
|
||||||
|
override fun onBind(intent: Intent) = InstrumentationConnector.asBinder()
|
||||||
|
|
||||||
|
object InstrumentationConnector : INetworkStackInstrumentation.Stub() {
|
||||||
|
private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>()
|
||||||
|
.run {
|
||||||
|
withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } }
|
||||||
|
}
|
||||||
|
private val httpRequestUrls = Collections.synchronizedList(ArrayList<String>())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an HTTP request is being processed by NetworkMonitor. Returns the response
|
||||||
|
* that should be simulated.
|
||||||
|
*/
|
||||||
|
fun processRequest(url: URL): HttpResponse {
|
||||||
|
val strUrl = url.toString()
|
||||||
|
httpRequestUrls.add(strUrl)
|
||||||
|
return httpResponses[strUrl]?.poll()
|
||||||
|
?: fail("No mocked response for request: $strUrl. " +
|
||||||
|
"Mocked URL keys are: ${httpResponses.keys}")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all state of this connector. This is intended for use between two tests, so all
|
||||||
|
* state should be reset as if the connector was just created.
|
||||||
|
*/
|
||||||
|
override fun clearAllState() {
|
||||||
|
httpResponses.clear()
|
||||||
|
httpRequestUrls.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a response to a future HTTP request.
|
||||||
|
*
|
||||||
|
* <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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ordered list of request URLs that have been sent by NetworkMonitor, and were
|
||||||
|
* answered based on mock responses.
|
||||||
|
*/
|
||||||
|
override fun getRequestUrls(): List<String> {
|
||||||
|
return ArrayList(httpRequestUrls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net.integrationtests
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.INetworkMonitorCallbacks
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.metrics.IpConnectivityLog
|
||||||
|
import android.net.util.SharedLog
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.android.networkstack.netlink.TcpSocketTracker
|
||||||
|
import com.android.server.NetworkStackService
|
||||||
|
import com.android.server.NetworkStackService.NetworkMonitorConnector
|
||||||
|
import com.android.server.NetworkStackService.NetworkStackConnector
|
||||||
|
import com.android.server.connectivity.NetworkMonitor
|
||||||
|
import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
|
||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
|
||||||
|
* through [NetworkStackInstrumentationService].
|
||||||
|
* Useful in tests to create test instrumented NetworkStack components that can receive
|
||||||
|
* instrumentation commands through [NetworkStackInstrumentationService].
|
||||||
|
*/
|
||||||
|
class TestNetworkStackService : Service() {
|
||||||
|
override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
|
||||||
|
|
||||||
|
private fun makeTestContext() = spy(applicationContext).also {
|
||||||
|
doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
|
||||||
|
override fun enforceNetworkStackCallingPermission() = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
|
||||||
|
NetworkMonitor.Dependencies() {
|
||||||
|
override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
|
||||||
|
context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
|
||||||
|
|
||||||
|
private val network = Network(TEST_NETID)
|
||||||
|
private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
|
||||||
|
|
||||||
|
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(responseBytes.size.toLong()).`when`(connection).contentLengthLong
|
||||||
|
doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
|
||||||
|
doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun makeNetworkMonitor(
|
||||||
|
network: Network,
|
||||||
|
name: String?,
|
||||||
|
cb: INetworkMonitorCallbacks
|
||||||
|
) {
|
||||||
|
val nm = NetworkMonitor(this@TestNetworkStackService, cb,
|
||||||
|
this.network,
|
||||||
|
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
|
||||||
|
mock(NetworkStackService.NetworkStackServiceManager::class.java),
|
||||||
|
NetworkMonitorDeps(privateDnsBypassNetwork),
|
||||||
|
mock(TcpSocketTracker::class.java))
|
||||||
|
cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:JvmName("ConnectivityServiceTestUtils")
|
||||||
|
|
||||||
|
package com.android.server
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager.TYPE_BLUETOOTH
|
||||||
|
import android.net.ConnectivityManager.TYPE_ETHERNET
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE
|
||||||
|
import android.net.ConnectivityManager.TYPE_NONE
|
||||||
|
import android.net.ConnectivityManager.TYPE_TEST
|
||||||
|
import android.net.ConnectivityManager.TYPE_VPN
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIFI
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_TEST
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_VPN
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||||
|
|
||||||
|
fun transportToLegacyType(transport: Int) = when (transport) {
|
||||||
|
TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
|
||||||
|
TRANSPORT_CELLULAR -> TYPE_MOBILE
|
||||||
|
TRANSPORT_ETHERNET -> TYPE_ETHERNET
|
||||||
|
TRANSPORT_TEST -> TYPE_TEST
|
||||||
|
TRANSPORT_VPN -> TYPE_VPN
|
||||||
|
TRANSPORT_WIFI -> TYPE_WIFI
|
||||||
|
else -> TYPE_NONE
|
||||||
|
}
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
|
||||||
|
|
||||||
|
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
import android.net.Network;
|
||||||
|
import android.net.NetworkAgent;
|
||||||
|
import android.net.NetworkAgentConfig;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.NetworkProvider;
|
||||||
|
import android.net.NetworkSpecifier;
|
||||||
|
import android.net.QosFilter;
|
||||||
|
import android.net.SocketKeepalive;
|
||||||
|
import android.os.ConditionVariable;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Range;
|
||||||
|
|
||||||
|
import com.android.net.module.util.ArrayTrackRecord;
|
||||||
|
import com.android.server.connectivity.ConnectivityConstants;
|
||||||
|
import com.android.testutils.HandlerUtils;
|
||||||
|
import com.android.testutils.TestableNetworkCallback;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
|
||||||
|
private final NetworkCapabilities mNetworkCapabilities;
|
||||||
|
private final HandlerThread mHandlerThread;
|
||||||
|
private final Context mContext;
|
||||||
|
private final String mLogTag;
|
||||||
|
private final NetworkAgentConfig mNetworkAgentConfig;
|
||||||
|
|
||||||
|
private final ConditionVariable mDisconnected = new ConditionVariable();
|
||||||
|
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
|
||||||
|
private final AtomicBoolean mConnected = new AtomicBoolean(false);
|
||||||
|
private int mScore;
|
||||||
|
private NetworkAgent mNetworkAgent;
|
||||||
|
private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
|
||||||
|
private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
|
||||||
|
// Controls how test network agent is going to wait before responding to keepalive
|
||||||
|
// start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
|
||||||
|
private long mKeepaliveResponseDelay = 0L;
|
||||||
|
private Integer mExpectedKeepaliveSlot = null;
|
||||||
|
private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
|
||||||
|
new ArrayTrackRecord<CallbackType>().newReadHead();
|
||||||
|
|
||||||
|
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
||||||
|
NetworkCapabilities ncTemplate, Context context) throws Exception {
|
||||||
|
final int type = transportToLegacyType(transport);
|
||||||
|
final String typeName = ConnectivityManager.getNetworkTypeName(type);
|
||||||
|
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
|
||||||
|
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
|
||||||
|
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
|
mNetworkCapabilities.addTransportType(transport);
|
||||||
|
switch (transport) {
|
||||||
|
case TRANSPORT_ETHERNET:
|
||||||
|
mScore = 70;
|
||||||
|
break;
|
||||||
|
case TRANSPORT_WIFI:
|
||||||
|
mScore = 60;
|
||||||
|
break;
|
||||||
|
case TRANSPORT_CELLULAR:
|
||||||
|
mScore = 50;
|
||||||
|
break;
|
||||||
|
case TRANSPORT_WIFI_AWARE:
|
||||||
|
mScore = 20;
|
||||||
|
break;
|
||||||
|
case TRANSPORT_VPN:
|
||||||
|
mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
|
||||||
|
// VPNs deduce the SUSPENDED capability from their underlying networks and there
|
||||||
|
// is no public API to let VPN services set it.
|
||||||
|
mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
|
||||||
|
mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("unimplemented network type");
|
||||||
|
}
|
||||||
|
mContext = context;
|
||||||
|
mLogTag = "Mock-" + typeName;
|
||||||
|
mHandlerThread = new HandlerThread(mLogTag);
|
||||||
|
mHandlerThread.start();
|
||||||
|
|
||||||
|
// extraInfo is set to "" by default in NetworkAgentConfig.
|
||||||
|
final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : "";
|
||||||
|
mNetworkAgentConfig = new NetworkAgentConfig.Builder()
|
||||||
|
.setLegacyType(type)
|
||||||
|
.setLegacyTypeName(typeName)
|
||||||
|
.setLegacyExtraInfo(extraInfo)
|
||||||
|
.build();
|
||||||
|
mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
|
||||||
|
final NetworkAgentConfig nac) throws Exception {
|
||||||
|
return new InstrumentedNetworkAgent(this, linkProperties, nac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InstrumentedNetworkAgent extends NetworkAgent {
|
||||||
|
private final NetworkAgentWrapper mWrapper;
|
||||||
|
private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider";
|
||||||
|
|
||||||
|
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
|
||||||
|
NetworkAgentConfig nac) {
|
||||||
|
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
|
||||||
|
wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
|
||||||
|
new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
|
||||||
|
PROVIDER_NAME));
|
||||||
|
mWrapper = wrapper;
|
||||||
|
register();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwanted() {
|
||||||
|
mWrapper.mDisconnected.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSocketKeepalive(Message msg) {
|
||||||
|
int slot = msg.arg1;
|
||||||
|
if (mWrapper.mExpectedKeepaliveSlot != null) {
|
||||||
|
assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
|
||||||
|
}
|
||||||
|
mWrapper.mHandlerThread.getThreadHandler().postDelayed(
|
||||||
|
() -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
|
||||||
|
mWrapper.mKeepaliveResponseDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopSocketKeepalive(Message msg) {
|
||||||
|
final int slot = msg.arg1;
|
||||||
|
mWrapper.mHandlerThread.getThreadHandler().postDelayed(
|
||||||
|
() -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
|
||||||
|
mWrapper.mKeepaliveResponseDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQosCallbackRegistered(final int qosCallbackId,
|
||||||
|
final @NonNull QosFilter filter) {
|
||||||
|
Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
|
||||||
|
mWrapper.mCallbackHistory.add(
|
||||||
|
new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQosCallbackUnregistered(final int qosCallbackId) {
|
||||||
|
Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
|
||||||
|
mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void preventAutomaticReconnect() {
|
||||||
|
mWrapper.mPreventReconnectReceived.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addKeepalivePacketFilter(Message msg) {
|
||||||
|
Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeKeepalivePacketFilter(Message msg) {
|
||||||
|
Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void adjustScore(int change) {
|
||||||
|
mScore += change;
|
||||||
|
mNetworkAgent.sendNetworkScore(mScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScore() {
|
||||||
|
return mScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
|
||||||
|
mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCapability(int capability) {
|
||||||
|
mNetworkCapabilities.addCapability(capability);
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCapability(int capability) {
|
||||||
|
mNetworkCapabilities.removeCapability(capability);
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUids(Set<Range<Integer>> uids) {
|
||||||
|
mNetworkCapabilities.setUids(uids);
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignalStrength(int signalStrength) {
|
||||||
|
mNetworkCapabilities.setSignalStrength(signalStrength);
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
|
||||||
|
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
|
||||||
|
mNetworkCapabilities.set(nc);
|
||||||
|
if (sendToConnectivityService) {
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() {
|
||||||
|
if (!mConnected.compareAndSet(false /* expect */, true /* update */)) {
|
||||||
|
// compareAndSet returns false when the value couldn't be updated because it did not
|
||||||
|
// match the expected value.
|
||||||
|
fail("Test NetworkAgents can only be connected once");
|
||||||
|
}
|
||||||
|
mNetworkAgent.markConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void suspend() {
|
||||||
|
removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume() {
|
||||||
|
addCapability(NET_CAPABILITY_NOT_SUSPENDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
mNetworkAgent.unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Network getNetwork() {
|
||||||
|
return mNetworkAgent.getNetwork();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expectPreventReconnectReceived(long timeoutMs) {
|
||||||
|
assertTrue(mPreventReconnectReceived.block(timeoutMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expectDisconnected(long timeoutMs) {
|
||||||
|
assertTrue(mDisconnected.block(timeoutMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendLinkProperties(LinkProperties lp) {
|
||||||
|
mNetworkAgent.sendLinkProperties(lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartKeepaliveEvent(int reason) {
|
||||||
|
mStartKeepaliveError = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStopKeepaliveEvent(int reason) {
|
||||||
|
mStopKeepaliveError = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeepaliveResponseDelay(long delay) {
|
||||||
|
mKeepaliveResponseDelay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectedKeepaliveSlot(Integer slot) {
|
||||||
|
mExpectedKeepaliveSlot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkAgent getNetworkAgent() {
|
||||||
|
return mNetworkAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkCapabilities getNetworkCapabilities() {
|
||||||
|
return mNetworkCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLegacyType() {
|
||||||
|
return mNetworkAgentConfig.getLegacyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtraInfo() {
|
||||||
|
return mNetworkAgentConfig.getLegacyExtraInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
|
||||||
|
return mCallbackHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitForIdle(long timeoutMs) {
|
||||||
|
HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class CallbackType {
|
||||||
|
final int mQosCallbackId;
|
||||||
|
|
||||||
|
protected CallbackType(final int qosCallbackId) {
|
||||||
|
mQosCallbackId = qosCallbackId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OnQosCallbackRegister extends CallbackType {
|
||||||
|
final QosFilter mFilter;
|
||||||
|
OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
|
||||||
|
super(qosCallbackId);
|
||||||
|
mFilter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
|
||||||
|
return mQosCallbackId == that.mQosCallbackId
|
||||||
|
&& Objects.equals(mFilter, that.mFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mQosCallbackId, mFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OnQosCallbackUnregister extends CallbackType {
|
||||||
|
OnQosCallbackUnregister(final int qosCallbackId) {
|
||||||
|
super(qosCallbackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
|
||||||
|
return mQosCallbackId == that.mQosCallbackId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mQosCallbackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBypassableVpn() {
|
||||||
|
return mNetworkAgentConfig.isBypassableVpn();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
|
||||||
|
* than starting from [NetIdManager.MIN_NET_ID] and increasing.
|
||||||
|
*
|
||||||
|
* Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
|
||||||
|
* overlapping with netIDs used by the real ConnectivityService on the device.
|
||||||
|
*
|
||||||
|
* IDs may still overlap if many networks have been used on the device (so the "real" netIDs
|
||||||
|
* are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
|
||||||
|
* is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
|
||||||
|
* the real ConnectivityService could start using netIds that have been used by the test in the
|
||||||
|
* past.
|
||||||
|
*/
|
||||||
|
class TestNetIdManager : NetIdManager() {
|
||||||
|
private val nextId = AtomicInteger(MAX_NET_ID)
|
||||||
|
override fun reserveNetId() = nextId.decrementAndGet()
|
||||||
|
override fun releaseNetId(id: Int) = Unit
|
||||||
|
fun peekNextNetId() = nextId.get() - 1
|
||||||
|
}
|
||||||
31
tests/smoketest/Android.bp
Normal file
31
tests/smoketest/Android.bp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// This test exists only because the jni_libs list for these tests is difficult to
|
||||||
|
// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
|
||||||
|
// fails to load that library unless *all* the dependencies of that library are explicitly
|
||||||
|
// listed in jni_libs. This means that whenever any of the dependencies changes the test
|
||||||
|
// starts failing and breaking presubmits in frameworks/base. We cannot easily put
|
||||||
|
// FrameworksNetTests into global presubmit because they are at times flaky, but this
|
||||||
|
// test is effectively empty beyond validating that the libraries load correctly, and
|
||||||
|
// thus should be stable enough to put in global presubmit.
|
||||||
|
//
|
||||||
|
// TODO: remove this hack when there is a better solution for jni_libs that includes
|
||||||
|
// dependent libraries.
|
||||||
|
package {
|
||||||
|
// See: http://go/android-license-faq
|
||||||
|
// A large-scale-change added 'default_applicable_licenses' to import
|
||||||
|
// all of the 'license_kinds' from "frameworks_base_license"
|
||||||
|
// to get the below license kinds:
|
||||||
|
// SPDX-license-identifier-Apache-2.0
|
||||||
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
|
}
|
||||||
|
|
||||||
|
android_test {
|
||||||
|
name: "FrameworksNetSmokeTests",
|
||||||
|
defaults: ["FrameworksNetTests-jni-defaults"],
|
||||||
|
srcs: ["java/SmokeTest.java"],
|
||||||
|
test_suites: ["device-tests"],
|
||||||
|
static_libs: [
|
||||||
|
"androidx.test.rules",
|
||||||
|
"mockito-target-minus-junit4",
|
||||||
|
"services.core",
|
||||||
|
],
|
||||||
|
}
|
||||||
27
tests/smoketest/AndroidManifest.xml
Normal file
27
tests/smoketest/AndroidManifest.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.frameworks.tests.net.smoketest">
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<instrumentation
|
||||||
|
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
android:targetPackage="com.android.frameworks.tests.net.smoketest"
|
||||||
|
android:label="Frameworks Networking Smoke Tests" />
|
||||||
|
</manifest>
|
||||||
28
tests/smoketest/AndroidTest.xml
Normal file
28
tests/smoketest/AndroidTest.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 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.
|
||||||
|
-->
|
||||||
|
<configuration description="Runs Frameworks Networking Smoke Tests.">
|
||||||
|
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
|
||||||
|
<option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
|
||||||
|
</target_preparer>
|
||||||
|
|
||||||
|
<option name="test-suite-tag" value="apct" />
|
||||||
|
<option name="test-tag" value="FrameworksNetSmokeTests" />
|
||||||
|
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||||
|
<option name="package" value="com.android.frameworks.tests.net.smoketest" />
|
||||||
|
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||||
|
<option name="hidden-api-checks" value="false"/>
|
||||||
|
</test>
|
||||||
|
</configuration>
|
||||||
33
tests/smoketest/java/SmokeTest.java
Normal file
33
tests/smoketest/java/SmokeTest.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public final class SmokeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadJni() {
|
||||||
|
System.loadLibrary("networkstatsfactorytestjni");
|
||||||
|
assertEquals(0, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
87
tests/unit/Android.bp
Normal file
87
tests/unit/Android.bp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
//########################################################################
|
||||||
|
// Build FrameworksNetTests package
|
||||||
|
//########################################################################
|
||||||
|
package {
|
||||||
|
// See: http://go/android-license-faq
|
||||||
|
// A large-scale-change added 'default_applicable_licenses' to import
|
||||||
|
// all of the 'license_kinds' from "frameworks_base_license"
|
||||||
|
// to get the below license kinds:
|
||||||
|
// SPDX-license-identifier-Apache-2.0
|
||||||
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_defaults {
|
||||||
|
name: "FrameworksNetTests-jni-defaults",
|
||||||
|
jni_libs: [
|
||||||
|
"ld-android",
|
||||||
|
"libbacktrace",
|
||||||
|
"libbase",
|
||||||
|
"libbinder",
|
||||||
|
"libbpf",
|
||||||
|
"libbpf_android",
|
||||||
|
"libc++",
|
||||||
|
"libcgrouprc",
|
||||||
|
"libcrypto",
|
||||||
|
"libcutils",
|
||||||
|
"libdl_android",
|
||||||
|
"libhidl-gen-utils",
|
||||||
|
"libhidlbase",
|
||||||
|
"libjsoncpp",
|
||||||
|
"liblog",
|
||||||
|
"liblzma",
|
||||||
|
"libnativehelper",
|
||||||
|
"libnetdbpf",
|
||||||
|
"libnetdutils",
|
||||||
|
"libnetworkstatsfactorytestjni",
|
||||||
|
"libpackagelistparser",
|
||||||
|
"libpcre2",
|
||||||
|
"libprocessgroup",
|
||||||
|
"libselinux",
|
||||||
|
"libtinyxml2",
|
||||||
|
"libui",
|
||||||
|
"libunwindstack",
|
||||||
|
"libutils",
|
||||||
|
"libutilscallstack",
|
||||||
|
"libvndksupport",
|
||||||
|
"libziparchive",
|
||||||
|
"libz",
|
||||||
|
"netd_aidl_interface-V5-cpp",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
android_test {
|
||||||
|
name: "FrameworksNetTests",
|
||||||
|
defaults: ["FrameworksNetTests-jni-defaults"],
|
||||||
|
srcs: [
|
||||||
|
"java/**/*.java",
|
||||||
|
"java/**/*.kt",
|
||||||
|
],
|
||||||
|
platform_apis: true,
|
||||||
|
test_suites: ["device-tests"],
|
||||||
|
certificate: "platform",
|
||||||
|
jarjar_rules: "jarjar-rules.txt",
|
||||||
|
static_libs: [
|
||||||
|
"androidx.test.rules",
|
||||||
|
"bouncycastle-repackaged-unbundled",
|
||||||
|
"FrameworksNetCommonTests",
|
||||||
|
"frameworks-base-testutils",
|
||||||
|
"frameworks-net-integration-testutils",
|
||||||
|
"framework-protos",
|
||||||
|
"mockito-target-minus-junit4",
|
||||||
|
"net-tests-utils",
|
||||||
|
"platform-test-annotations",
|
||||||
|
"service-connectivity-pre-jarjar",
|
||||||
|
"services.core",
|
||||||
|
"services.net",
|
||||||
|
],
|
||||||
|
libs: [
|
||||||
|
"android.net.ipsec.ike.stubs.module_lib",
|
||||||
|
"android.test.runner",
|
||||||
|
"android.test.base",
|
||||||
|
"android.test.mock",
|
||||||
|
"ServiceConnectivityResources",
|
||||||
|
],
|
||||||
|
jni_libs: [
|
||||||
|
"libservice-connectivity",
|
||||||
|
],
|
||||||
|
}
|
||||||
62
tests/unit/AndroidManifest.xml
Normal file
62
tests/unit/AndroidManifest.xml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.frameworks.tests.net">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_LOGS" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||||
|
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
|
||||||
|
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
|
||||||
|
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
|
||||||
|
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
|
||||||
|
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
|
||||||
|
<uses-permission android:name="android.permission.NETWORK_STACK" />
|
||||||
|
<uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
|
||||||
|
<uses-permission android:name="android.permission.NETWORK_FACTORY" />
|
||||||
|
<uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
|
||||||
|
<uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
<uses-library android:name="android.net.ipsec.ike" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<instrumentation
|
||||||
|
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
android:targetPackage="com.android.frameworks.tests.net"
|
||||||
|
android:label="Frameworks Networking Tests" />
|
||||||
|
</manifest>
|
||||||
28
tests/unit/AndroidTest.xml
Normal file
28
tests/unit/AndroidTest.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2017 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.
|
||||||
|
-->
|
||||||
|
<configuration description="Runs Frameworks Networking Tests.">
|
||||||
|
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
|
||||||
|
<option name="test-file-name" value="FrameworksNetTests.apk" />
|
||||||
|
</target_preparer>
|
||||||
|
|
||||||
|
<option name="test-suite-tag" value="apct" />
|
||||||
|
<option name="test-tag" value="FrameworksNetTests" />
|
||||||
|
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||||
|
<option name="package" value="com.android.frameworks.tests.net" />
|
||||||
|
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||||
|
<option name="hidden-api-checks" value="false"/>
|
||||||
|
</test>
|
||||||
|
</configuration>
|
||||||
2
tests/unit/jarjar-rules.txt
Normal file
2
tests/unit/jarjar-rules.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Module library in frameworks/libs/net
|
||||||
|
rule com.android.net.module.util.** android.net.frameworktests.util.@1
|
||||||
212
tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
Normal file
212
tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 android.app.usage;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.INetworkStatsService;
|
||||||
|
import android.net.INetworkStatsSession;
|
||||||
|
import android.net.NetworkStats.Entry;
|
||||||
|
import android.net.NetworkStatsHistory;
|
||||||
|
import android.net.NetworkTemplate;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NetworkStatsManagerTest {
|
||||||
|
|
||||||
|
private @Mock INetworkStatsService mService;
|
||||||
|
private @Mock INetworkStatsSession mStatsSession;
|
||||||
|
|
||||||
|
private NetworkStatsManager mManager;
|
||||||
|
|
||||||
|
// TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
|
||||||
|
private static final int MATCH_MOBILE_ALL = 1;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryDetails() throws RemoteException {
|
||||||
|
final String subscriberId = "subid";
|
||||||
|
final long startTime = 1;
|
||||||
|
final long endTime = 100;
|
||||||
|
final int uid1 = 10001;
|
||||||
|
final int uid2 = 10002;
|
||||||
|
final int uid3 = 10003;
|
||||||
|
|
||||||
|
Entry uid1Entry1 = new Entry("if1", uid1,
|
||||||
|
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
|
||||||
|
100, 10, 200, 20, 0);
|
||||||
|
|
||||||
|
Entry uid1Entry2 = new Entry(
|
||||||
|
"if2", uid1,
|
||||||
|
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
|
||||||
|
100, 10, 200, 20, 0);
|
||||||
|
|
||||||
|
Entry uid2Entry1 = new Entry("if1", uid2,
|
||||||
|
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
|
||||||
|
150, 10, 250, 20, 0);
|
||||||
|
|
||||||
|
Entry uid2Entry2 = new Entry(
|
||||||
|
"if2", uid2,
|
||||||
|
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
|
||||||
|
150, 10, 250, 20, 0);
|
||||||
|
|
||||||
|
NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
|
||||||
|
history1.recordData(10, 20, uid1Entry1);
|
||||||
|
history1.recordData(20, 30, uid1Entry2);
|
||||||
|
|
||||||
|
NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
|
||||||
|
history1.recordData(30, 40, uid2Entry1);
|
||||||
|
history1.recordData(35, 45, uid2Entry2);
|
||||||
|
|
||||||
|
|
||||||
|
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
|
||||||
|
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
|
||||||
|
|
||||||
|
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
|
||||||
|
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
|
||||||
|
eq(android.net.NetworkStats.TAG_NONE),
|
||||||
|
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
|
||||||
|
.then((InvocationOnMock inv) -> {
|
||||||
|
NetworkTemplate template = inv.getArgument(0);
|
||||||
|
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
|
||||||
|
assertEquals(subscriberId, template.getSubscriberId());
|
||||||
|
return history1;
|
||||||
|
});
|
||||||
|
|
||||||
|
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
|
||||||
|
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
|
||||||
|
eq(android.net.NetworkStats.TAG_NONE),
|
||||||
|
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
|
||||||
|
.then((InvocationOnMock inv) -> {
|
||||||
|
NetworkTemplate template = inv.getArgument(0);
|
||||||
|
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
|
||||||
|
assertEquals(subscriberId, template.getSubscriberId());
|
||||||
|
return history2;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
NetworkStats stats = mManager.queryDetails(
|
||||||
|
ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
|
||||||
|
|
||||||
|
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
|
||||||
|
|
||||||
|
// First 2 buckets exactly match entry timings
|
||||||
|
assertTrue(stats.getNextBucket(bucket));
|
||||||
|
assertEquals(10, bucket.getStartTimeStamp());
|
||||||
|
assertEquals(20, bucket.getEndTimeStamp());
|
||||||
|
assertBucketMatches(uid1Entry1, bucket);
|
||||||
|
|
||||||
|
assertTrue(stats.getNextBucket(bucket));
|
||||||
|
assertEquals(20, bucket.getStartTimeStamp());
|
||||||
|
assertEquals(30, bucket.getEndTimeStamp());
|
||||||
|
assertBucketMatches(uid1Entry2, bucket);
|
||||||
|
|
||||||
|
// 30 -> 40: contains uid2Entry1 and half of uid2Entry2
|
||||||
|
assertTrue(stats.getNextBucket(bucket));
|
||||||
|
assertEquals(30, bucket.getStartTimeStamp());
|
||||||
|
assertEquals(40, bucket.getEndTimeStamp());
|
||||||
|
assertEquals(225, bucket.getRxBytes());
|
||||||
|
assertEquals(15, bucket.getRxPackets());
|
||||||
|
assertEquals(375, bucket.getTxBytes());
|
||||||
|
assertEquals(30, bucket.getTxPackets());
|
||||||
|
|
||||||
|
// 40 -> 50: contains half of uid2Entry2
|
||||||
|
assertTrue(stats.getNextBucket(bucket));
|
||||||
|
assertEquals(40, bucket.getStartTimeStamp());
|
||||||
|
assertEquals(50, bucket.getEndTimeStamp());
|
||||||
|
assertEquals(75, bucket.getRxBytes());
|
||||||
|
assertEquals(5, bucket.getRxPackets());
|
||||||
|
assertEquals(125, bucket.getTxBytes());
|
||||||
|
assertEquals(10, bucket.getTxPackets());
|
||||||
|
|
||||||
|
assertFalse(stats.hasNextBucket());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryDetails_NoSubscriberId() throws RemoteException {
|
||||||
|
final long startTime = 1;
|
||||||
|
final long endTime = 100;
|
||||||
|
final int uid1 = 10001;
|
||||||
|
final int uid2 = 10002;
|
||||||
|
|
||||||
|
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
|
||||||
|
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
|
||||||
|
|
||||||
|
NetworkStats stats = mManager.queryDetails(
|
||||||
|
ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
|
||||||
|
|
||||||
|
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
|
||||||
|
anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
|
||||||
|
.thenReturn(new NetworkStatsHistory(10, 0));
|
||||||
|
|
||||||
|
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
|
||||||
|
argThat((NetworkTemplate t) ->
|
||||||
|
// No subscriberId: MATCH_MOBILE_WILDCARD template
|
||||||
|
t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
|
||||||
|
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
|
||||||
|
eq(android.net.NetworkStats.TAG_NONE),
|
||||||
|
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
|
||||||
|
|
||||||
|
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
|
||||||
|
argThat((NetworkTemplate t) ->
|
||||||
|
// No subscriberId: MATCH_MOBILE_WILDCARD template
|
||||||
|
t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
|
||||||
|
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
|
||||||
|
eq(android.net.NetworkStats.TAG_NONE),
|
||||||
|
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
|
||||||
|
|
||||||
|
assertFalse(stats.hasNextBucket());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
|
||||||
|
assertEquals(expected.uid, actual.getUid());
|
||||||
|
assertEquals(expected.rxBytes, actual.getRxBytes());
|
||||||
|
assertEquals(expected.rxPackets, actual.getRxPackets());
|
||||||
|
assertEquals(expected.txBytes, actual.getTxBytes());
|
||||||
|
assertEquals(expected.txPackets, actual.getTxPackets());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder;
|
||||||
|
import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
|
||||||
|
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
|
||||||
|
import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class ConnectivityDiagnosticsManagerTest {
|
||||||
|
private static final int NET_ID = 1;
|
||||||
|
private static final int DETECTION_METHOD = 2;
|
||||||
|
private static final long TIMESTAMP = 10L;
|
||||||
|
private static final String INTERFACE_NAME = "interface";
|
||||||
|
private static final String BUNDLE_KEY = "key";
|
||||||
|
private static final String BUNDLE_VALUE = "value";
|
||||||
|
|
||||||
|
private static final Executor INLINE_EXECUTOR = x -> x.run();
|
||||||
|
|
||||||
|
@Mock private IConnectivityManager mService;
|
||||||
|
@Mock private ConnectivityDiagnosticsCallback mCb;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private ConnectivityDiagnosticsBinder mBinder;
|
||||||
|
private ConnectivityDiagnosticsManager mManager;
|
||||||
|
|
||||||
|
private String mPackageName;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = InstrumentationRegistry.getContext();
|
||||||
|
|
||||||
|
mService = mock(IConnectivityManager.class);
|
||||||
|
mCb = mock(ConnectivityDiagnosticsCallback.class);
|
||||||
|
|
||||||
|
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
|
||||||
|
mManager = new ConnectivityDiagnosticsManager(mContext, mService);
|
||||||
|
|
||||||
|
mPackageName = mContext.getOpPackageName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
// clear ConnectivityDiagnosticsManager callbacks map
|
||||||
|
ConnectivityDiagnosticsManager.sCallbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectivityReport createSampleConnectivityReport() {
|
||||||
|
final LinkProperties linkProperties = new LinkProperties();
|
||||||
|
linkProperties.setInterfaceName(INTERFACE_NAME);
|
||||||
|
|
||||||
|
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
|
||||||
|
networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
|
||||||
|
|
||||||
|
final PersistableBundle bundle = new PersistableBundle();
|
||||||
|
bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
|
||||||
|
|
||||||
|
return new ConnectivityReport(
|
||||||
|
new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectivityReport createDefaultConnectivityReport() {
|
||||||
|
return new ConnectivityReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistableBundleEquals() {
|
||||||
|
assertFalse(
|
||||||
|
ConnectivityDiagnosticsManager.persistableBundleEquals(
|
||||||
|
null, PersistableBundle.EMPTY));
|
||||||
|
assertFalse(
|
||||||
|
ConnectivityDiagnosticsManager.persistableBundleEquals(
|
||||||
|
PersistableBundle.EMPTY, null));
|
||||||
|
assertTrue(
|
||||||
|
ConnectivityDiagnosticsManager.persistableBundleEquals(
|
||||||
|
PersistableBundle.EMPTY, PersistableBundle.EMPTY));
|
||||||
|
|
||||||
|
final PersistableBundle a = new PersistableBundle();
|
||||||
|
a.putString(BUNDLE_KEY, BUNDLE_VALUE);
|
||||||
|
|
||||||
|
final PersistableBundle b = new PersistableBundle();
|
||||||
|
b.putString(BUNDLE_KEY, BUNDLE_VALUE);
|
||||||
|
|
||||||
|
final PersistableBundle c = new PersistableBundle();
|
||||||
|
c.putString(BUNDLE_KEY, null);
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
|
||||||
|
assertFalse(
|
||||||
|
ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
|
||||||
|
|
||||||
|
assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
|
||||||
|
assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
|
||||||
|
|
||||||
|
assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
|
||||||
|
assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityReportEquals() {
|
||||||
|
final ConnectivityReport defaultReport = createDefaultConnectivityReport();
|
||||||
|
final ConnectivityReport sampleReport = createSampleConnectivityReport();
|
||||||
|
assertEquals(sampleReport, createSampleConnectivityReport());
|
||||||
|
assertEquals(defaultReport, createDefaultConnectivityReport());
|
||||||
|
|
||||||
|
final LinkProperties linkProperties = sampleReport.getLinkProperties();
|
||||||
|
final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
|
||||||
|
final PersistableBundle bundle = sampleReport.getAdditionalInfo();
|
||||||
|
|
||||||
|
assertNotEquals(
|
||||||
|
createDefaultConnectivityReport(),
|
||||||
|
new ConnectivityReport(
|
||||||
|
new Network(NET_ID),
|
||||||
|
0L,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
createDefaultConnectivityReport(),
|
||||||
|
new ConnectivityReport(
|
||||||
|
new Network(0),
|
||||||
|
TIMESTAMP,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
createDefaultConnectivityReport(),
|
||||||
|
new ConnectivityReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
linkProperties,
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
createDefaultConnectivityReport(),
|
||||||
|
new ConnectivityReport(
|
||||||
|
new Network(0),
|
||||||
|
TIMESTAMP,
|
||||||
|
new LinkProperties(),
|
||||||
|
networkCapabilities,
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
createDefaultConnectivityReport(),
|
||||||
|
new ConnectivityReport(
|
||||||
|
new Network(0),
|
||||||
|
TIMESTAMP,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
bundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityReportParcelUnparcel() {
|
||||||
|
assertParcelSane(createSampleConnectivityReport(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataStallReport createSampleDataStallReport() {
|
||||||
|
final LinkProperties linkProperties = new LinkProperties();
|
||||||
|
linkProperties.setInterfaceName(INTERFACE_NAME);
|
||||||
|
|
||||||
|
final PersistableBundle bundle = new PersistableBundle();
|
||||||
|
bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
|
||||||
|
|
||||||
|
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
|
||||||
|
networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
|
||||||
|
|
||||||
|
return new DataStallReport(
|
||||||
|
new Network(NET_ID),
|
||||||
|
TIMESTAMP,
|
||||||
|
DETECTION_METHOD,
|
||||||
|
linkProperties,
|
||||||
|
networkCapabilities,
|
||||||
|
bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataStallReport createDefaultDataStallReport() {
|
||||||
|
return new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDataStallReportEquals() {
|
||||||
|
final DataStallReport defaultReport = createDefaultDataStallReport();
|
||||||
|
final DataStallReport sampleReport = createSampleDataStallReport();
|
||||||
|
assertEquals(sampleReport, createSampleDataStallReport());
|
||||||
|
assertEquals(defaultReport, createDefaultDataStallReport());
|
||||||
|
|
||||||
|
final LinkProperties linkProperties = sampleReport.getLinkProperties();
|
||||||
|
final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
|
||||||
|
final PersistableBundle bundle = sampleReport.getStallDetails();
|
||||||
|
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(NET_ID),
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
TIMESTAMP,
|
||||||
|
0,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
DETECTION_METHOD,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
linkProperties,
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
new LinkProperties(),
|
||||||
|
networkCapabilities,
|
||||||
|
PersistableBundle.EMPTY));
|
||||||
|
assertNotEquals(
|
||||||
|
defaultReport,
|
||||||
|
new DataStallReport(
|
||||||
|
new Network(0),
|
||||||
|
0L,
|
||||||
|
0,
|
||||||
|
new LinkProperties(),
|
||||||
|
new NetworkCapabilities(),
|
||||||
|
bundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDataStallReportParcelUnparcel() {
|
||||||
|
assertParcelSane(createSampleDataStallReport(), 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable() {
|
||||||
|
mBinder.onConnectivityReportAvailable(createSampleConnectivityReport());
|
||||||
|
|
||||||
|
// The callback will be invoked synchronously by inline executor. Immediately check the
|
||||||
|
// latch without waiting.
|
||||||
|
verify(mCb).onConnectivityReportAvailable(eq(createSampleConnectivityReport()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
|
||||||
|
mBinder.onDataStallSuspected(createSampleDataStallReport());
|
||||||
|
|
||||||
|
// The callback will be invoked synchronously by inline executor. Immediately check the
|
||||||
|
// latch without waiting.
|
||||||
|
verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
|
||||||
|
final Network n = new Network(NET_ID);
|
||||||
|
final boolean connectivity = true;
|
||||||
|
|
||||||
|
mBinder.onNetworkConnectivityReported(n, connectivity);
|
||||||
|
|
||||||
|
// The callback will be invoked synchronously by inline executor. Immediately check the
|
||||||
|
// latch without waiting.
|
||||||
|
verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
|
||||||
|
final NetworkRequest request = new NetworkRequest.Builder().build();
|
||||||
|
|
||||||
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
|
||||||
|
verify(mService).registerConnectivityDiagnosticsCallback(
|
||||||
|
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
|
||||||
|
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
|
||||||
|
final NetworkRequest request = new NetworkRequest.Builder().build();
|
||||||
|
|
||||||
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
fail("Duplicate callback registration should fail");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
|
||||||
|
final NetworkRequest request = new NetworkRequest.Builder().build();
|
||||||
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
|
||||||
|
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
|
||||||
|
|
||||||
|
verify(mService).unregisterConnectivityDiagnosticsCallback(
|
||||||
|
any(ConnectivityDiagnosticsBinder.class));
|
||||||
|
assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
||||||
|
|
||||||
|
// verify that re-registering is successful
|
||||||
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
|
||||||
|
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
|
||||||
|
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
|
||||||
|
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mService);
|
||||||
|
}
|
||||||
|
}
|
||||||
430
tests/unit/java/android/net/ConnectivityManagerTest.java
Normal file
430
tests/unit/java/android/net/ConnectivityManagerTest.java
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.ConnectivityManager.TYPE_NONE;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
|
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
|
||||||
|
import static android.net.NetworkRequest.Type.REQUEST;
|
||||||
|
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
|
||||||
|
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class ConnectivityManagerTest {
|
||||||
|
|
||||||
|
@Mock Context mCtx;
|
||||||
|
@Mock IConnectivityManager mService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NetworkCapabilities verifyNetworkCapabilities(
|
||||||
|
int legacyType, int transportType, int... capabilities) {
|
||||||
|
final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
|
||||||
|
assertNotNull(nc);
|
||||||
|
assertTrue(nc.hasTransport(transportType));
|
||||||
|
for (int capability : capabilities) {
|
||||||
|
assertTrue(nc.hasCapability(capability));
|
||||||
|
}
|
||||||
|
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
|
||||||
|
verifyNetworkCapabilities(
|
||||||
|
legacyType,
|
||||||
|
transportType,
|
||||||
|
NET_CAPABILITY_INTERNET,
|
||||||
|
NET_CAPABILITY_NOT_RESTRICTED,
|
||||||
|
NET_CAPABILITY_NOT_VPN,
|
||||||
|
NET_CAPABILITY_TRUSTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
|
||||||
|
final NetworkCapabilities nc = verifyNetworkCapabilities(
|
||||||
|
legacyType,
|
||||||
|
TRANSPORT_CELLULAR,
|
||||||
|
capability,
|
||||||
|
NET_CAPABILITY_NOT_VPN,
|
||||||
|
NET_CAPABILITY_TRUSTED);
|
||||||
|
|
||||||
|
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
|
||||||
|
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobile() {
|
||||||
|
verifyUnrestrictedNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileCbs() {
|
||||||
|
verifyRestrictedMobileNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileDun() {
|
||||||
|
verifyRestrictedMobileNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileFota() {
|
||||||
|
verifyRestrictedMobileNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileHipri() {
|
||||||
|
verifyUnrestrictedNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileIms() {
|
||||||
|
verifyRestrictedMobileNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileMms() {
|
||||||
|
final NetworkCapabilities nc = verifyNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_MMS,
|
||||||
|
TRANSPORT_CELLULAR,
|
||||||
|
NET_CAPABILITY_MMS,
|
||||||
|
NET_CAPABILITY_NOT_VPN,
|
||||||
|
NET_CAPABILITY_TRUSTED);
|
||||||
|
|
||||||
|
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeMobileSupl() {
|
||||||
|
final NetworkCapabilities nc = verifyNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_MOBILE_SUPL,
|
||||||
|
TRANSPORT_CELLULAR,
|
||||||
|
NET_CAPABILITY_SUPL,
|
||||||
|
NET_CAPABILITY_NOT_VPN,
|
||||||
|
NET_CAPABILITY_TRUSTED);
|
||||||
|
|
||||||
|
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeWifi() {
|
||||||
|
verifyUnrestrictedNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeWifiP2p() {
|
||||||
|
final NetworkCapabilities nc = verifyNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_WIFI_P2P,
|
||||||
|
TRANSPORT_WIFI,
|
||||||
|
NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
|
||||||
|
NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
|
||||||
|
|
||||||
|
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeBluetooth() {
|
||||||
|
verifyUnrestrictedNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesForTypeEthernet() {
|
||||||
|
verifyUnrestrictedNetworkCapabilities(
|
||||||
|
ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallbackRelease() throws Exception {
|
||||||
|
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
|
||||||
|
NetworkRequest request = makeRequest(1);
|
||||||
|
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
|
||||||
|
|
||||||
|
// register callback
|
||||||
|
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
|
||||||
|
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
|
||||||
|
manager.requestNetwork(request, callback, handler);
|
||||||
|
|
||||||
|
// callback triggers
|
||||||
|
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
|
||||||
|
verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
|
||||||
|
any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
|
||||||
|
|
||||||
|
// unregister callback
|
||||||
|
manager.unregisterNetworkCallback(callback);
|
||||||
|
verify(mService, times(1)).releaseNetworkRequest(request);
|
||||||
|
|
||||||
|
// callback does not trigger anymore.
|
||||||
|
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
|
||||||
|
verify(callback, timeout(500).times(0)).onLosing(any(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallbackRecycling() throws Exception {
|
||||||
|
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
|
||||||
|
NetworkRequest req1 = makeRequest(1);
|
||||||
|
NetworkRequest req2 = makeRequest(2);
|
||||||
|
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
|
||||||
|
|
||||||
|
// register callback
|
||||||
|
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
|
||||||
|
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
|
||||||
|
manager.requestNetwork(req1, callback, handler);
|
||||||
|
|
||||||
|
// callback triggers
|
||||||
|
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
|
||||||
|
verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
|
||||||
|
any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
|
||||||
|
|
||||||
|
// unregister callback
|
||||||
|
manager.unregisterNetworkCallback(callback);
|
||||||
|
verify(mService, times(1)).releaseNetworkRequest(req1);
|
||||||
|
|
||||||
|
// callback does not trigger anymore.
|
||||||
|
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
|
||||||
|
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
|
||||||
|
|
||||||
|
// callback can be registered again
|
||||||
|
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
|
||||||
|
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
|
||||||
|
manager.requestNetwork(req2, callback, handler);
|
||||||
|
|
||||||
|
// callback triggers
|
||||||
|
captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
|
||||||
|
verify(callback, timeout(100).times(1)).onLost(any());
|
||||||
|
|
||||||
|
// unregister callback
|
||||||
|
manager.unregisterNetworkCallback(callback);
|
||||||
|
verify(mService, times(1)).releaseNetworkRequest(req2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: turn on this test when request callback 1:1 mapping is enforced
|
||||||
|
//@Test
|
||||||
|
private void noDoubleCallbackRegistration() throws Exception {
|
||||||
|
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
|
||||||
|
NetworkRequest request = makeRequest(1);
|
||||||
|
NetworkCallback callback = new ConnectivityManager.NetworkCallback();
|
||||||
|
ApplicationInfo info = new ApplicationInfo();
|
||||||
|
// TODO: update version when starting to enforce 1:1 mapping
|
||||||
|
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
|
||||||
|
|
||||||
|
when(mCtx.getApplicationInfo()).thenReturn(info);
|
||||||
|
when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
|
||||||
|
anyInt(), any(), nullable(String.class))).thenReturn(request);
|
||||||
|
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
manager.requestNetwork(request, callback, handler);
|
||||||
|
|
||||||
|
// callback is already registered, reregistration should fail.
|
||||||
|
Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
|
||||||
|
expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
|
||||||
|
|
||||||
|
manager.unregisterNetworkCallback(callback);
|
||||||
|
verify(mService, times(1)).releaseNetworkRequest(request);
|
||||||
|
|
||||||
|
// unregistering the callback should make it registrable again.
|
||||||
|
manager.requestNetwork(request, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArgumentValidation() throws Exception {
|
||||||
|
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
|
||||||
|
|
||||||
|
NetworkRequest request = mock(NetworkRequest.class);
|
||||||
|
NetworkCallback callback = mock(NetworkCallback.class);
|
||||||
|
Handler handler = mock(Handler.class);
|
||||||
|
NetworkCallback nullCallback = null;
|
||||||
|
PendingIntent nullIntent = null;
|
||||||
|
|
||||||
|
mustFail(() -> { manager.requestNetwork(null, callback); });
|
||||||
|
mustFail(() -> { manager.requestNetwork(request, nullCallback); });
|
||||||
|
mustFail(() -> { manager.requestNetwork(request, callback, null); });
|
||||||
|
mustFail(() -> { manager.requestNetwork(request, callback, -1); });
|
||||||
|
mustFail(() -> { manager.requestNetwork(request, nullIntent); });
|
||||||
|
|
||||||
|
mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); });
|
||||||
|
mustFail(() -> { manager.registerNetworkCallback(request, null, handler); });
|
||||||
|
mustFail(() -> { manager.registerNetworkCallback(request, callback, null); });
|
||||||
|
mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); });
|
||||||
|
|
||||||
|
mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
|
||||||
|
mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
|
||||||
|
|
||||||
|
mustFail(() -> { manager.registerSystemDefaultNetworkCallback(null, handler); });
|
||||||
|
mustFail(() -> { manager.registerSystemDefaultNetworkCallback(callback, null); });
|
||||||
|
|
||||||
|
mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
|
||||||
|
mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
|
||||||
|
mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mustFail(Runnable fn) {
|
||||||
|
try {
|
||||||
|
fn.run();
|
||||||
|
fail();
|
||||||
|
} catch (Exception expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequestType() throws Exception {
|
||||||
|
final String testPkgName = "MyPackage";
|
||||||
|
final String testAttributionTag = "MyTag";
|
||||||
|
final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
|
||||||
|
when(mCtx.getOpPackageName()).thenReturn(testPkgName);
|
||||||
|
when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
|
||||||
|
final NetworkRequest request = makeRequest(1);
|
||||||
|
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
|
||||||
|
|
||||||
|
manager.requestNetwork(request, callback);
|
||||||
|
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
|
||||||
|
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
reset(mService);
|
||||||
|
|
||||||
|
// Verify that register network callback does not calls requestNetwork at all.
|
||||||
|
manager.registerNetworkCallback(request, callback);
|
||||||
|
verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
|
||||||
|
anyInt(), anyInt(), any(), any());
|
||||||
|
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
reset(mService);
|
||||||
|
|
||||||
|
Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
|
||||||
|
|
||||||
|
manager.registerDefaultNetworkCallback(callback);
|
||||||
|
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
|
||||||
|
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
reset(mService);
|
||||||
|
|
||||||
|
manager.registerDefaultNetworkCallbackForUid(42, callback, handler);
|
||||||
|
verify(mService).requestNetwork(eq(42), eq(null),
|
||||||
|
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
|
||||||
|
manager.requestBackgroundNetwork(request, callback, handler);
|
||||||
|
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
|
||||||
|
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
reset(mService);
|
||||||
|
|
||||||
|
manager.registerSystemDefaultNetworkCallback(callback, handler);
|
||||||
|
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
|
||||||
|
eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
|
||||||
|
eq(testPkgName), eq(testAttributionTag));
|
||||||
|
reset(mService);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Message makeMessage(NetworkRequest req, int messageType) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
|
||||||
|
// Pass default objects as we don't care which get passed here
|
||||||
|
bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
|
||||||
|
bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
|
||||||
|
bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
|
||||||
|
Message msg = Message.obtain();
|
||||||
|
msg.what = messageType;
|
||||||
|
msg.setData(bundle);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NetworkRequest makeRequest(int requestId) {
|
||||||
|
NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
|
||||||
|
return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
|
||||||
|
requestId, NetworkRequest.Type.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
|
||||||
|
try {
|
||||||
|
block.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (t.getClass().equals(throwableType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail("expected exception of type " + throwableType + ", but was " + t.getClass());
|
||||||
|
}
|
||||||
|
fail("expected exception of type " + throwableType);
|
||||||
|
}
|
||||||
|
}
|
||||||
439
tests/unit/java/android/net/Ikev2VpnProfileTest.java
Normal file
439
tests/unit/java/android/net/Ikev2VpnProfileTest.java
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.test.mock.MockContext;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.net.VpnProfile;
|
||||||
|
import com.android.net.module.util.ProxyUtils;
|
||||||
|
import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
|
/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class Ikev2VpnProfileTest {
|
||||||
|
private static final String SERVER_ADDR_STRING = "1.2.3.4";
|
||||||
|
private static final String IDENTITY_STRING = "Identity";
|
||||||
|
private static final String USERNAME_STRING = "username";
|
||||||
|
private static final String PASSWORD_STRING = "pa55w0rd";
|
||||||
|
private static final String EXCL_LIST = "exclList";
|
||||||
|
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
|
||||||
|
private static final int TEST_MTU = 1300;
|
||||||
|
|
||||||
|
private final MockContext mMockContext =
|
||||||
|
new MockContext() {
|
||||||
|
@Override
|
||||||
|
public String getOpPackageName() {
|
||||||
|
return "fooPackage";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy(
|
||||||
|
SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST));
|
||||||
|
|
||||||
|
private X509Certificate mUserCert;
|
||||||
|
private X509Certificate mServerRootCa;
|
||||||
|
private PrivateKey mPrivateKey;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mServerRootCa = generateRandomCertAndKeyPair().cert;
|
||||||
|
|
||||||
|
final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
|
||||||
|
mUserCert = userCertKey.cert;
|
||||||
|
mPrivateKey = userCertKey.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
|
||||||
|
final Ikev2VpnProfile.Builder builder =
|
||||||
|
new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
|
||||||
|
|
||||||
|
builder.setBypassable(true);
|
||||||
|
builder.setProxy(mProxy);
|
||||||
|
builder.setMaxMtu(TEST_MTU);
|
||||||
|
builder.setMetered(true);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildValidProfileWithOptions() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertNotNull(profile);
|
||||||
|
|
||||||
|
// Check non-auth parameters correctly stored
|
||||||
|
assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
|
||||||
|
assertEquals(IDENTITY_STRING, profile.getUserIdentity());
|
||||||
|
assertEquals(mProxy, profile.getProxyInfo());
|
||||||
|
assertTrue(profile.isBypassable());
|
||||||
|
assertTrue(profile.isMetered());
|
||||||
|
assertEquals(TEST_MTU, profile.getMaxMtu());
|
||||||
|
assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildUsernamePasswordProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertNotNull(profile);
|
||||||
|
|
||||||
|
assertEquals(USERNAME_STRING, profile.getUsername());
|
||||||
|
assertEquals(PASSWORD_STRING, profile.getPassword());
|
||||||
|
assertEquals(mServerRootCa, profile.getServerRootCaCert());
|
||||||
|
|
||||||
|
assertNull(profile.getPresharedKey());
|
||||||
|
assertNull(profile.getRsaPrivateKey());
|
||||||
|
assertNull(profile.getUserCert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildDigitalSignatureProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertNotNull(profile);
|
||||||
|
|
||||||
|
assertEquals(profile.getUserCert(), mUserCert);
|
||||||
|
assertEquals(mPrivateKey, profile.getRsaPrivateKey());
|
||||||
|
assertEquals(profile.getServerRootCaCert(), mServerRootCa);
|
||||||
|
|
||||||
|
assertNull(profile.getPresharedKey());
|
||||||
|
assertNull(profile.getUsername());
|
||||||
|
assertNull(profile.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildPresharedKeyProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertNotNull(profile);
|
||||||
|
|
||||||
|
assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
|
||||||
|
|
||||||
|
assertNull(profile.getServerRootCaCert());
|
||||||
|
assertNull(profile.getUsername());
|
||||||
|
assertNull(profile.getPassword());
|
||||||
|
assertNull(profile.getRsaPrivateKey());
|
||||||
|
assertNull(profile.getUserCert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildWithAllowedAlgorithmsAead() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
|
||||||
|
List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
|
||||||
|
builder.setAllowedAlgorithms(allowedAlgorithms);
|
||||||
|
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
|
||||||
|
List<String> allowedAlgorithms =
|
||||||
|
Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
|
||||||
|
builder.setAllowedAlgorithms(allowedAlgorithms);
|
||||||
|
|
||||||
|
final Ikev2VpnProfile profile = builder.build();
|
||||||
|
assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAllowedAlgorithmsEmptyList() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setAllowedAlgorithms(new ArrayList<>());
|
||||||
|
fail("Expected exception due to no valid algorithm set");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAllowedAlgorithmsInvalidList() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
List<String> allowedAlgorithms = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
|
||||||
|
fail("Expected exception due to missing encryption");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
|
||||||
|
fail("Expected exception due to missing authentication");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
List<String> allowedAlgorithms = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
|
||||||
|
fail("Expected exception due to insecure algorithm");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
|
||||||
|
fail("Expected exception due to insecure algorithm");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildNoAuthMethodSet() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.build();
|
||||||
|
fail("Expected exception due to lack of auth method");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildInvalidMtu() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.setMaxMtu(500);
|
||||||
|
fail("Expected exception due to too-small MTU");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyVpnProfileCommon(VpnProfile profile) {
|
||||||
|
assertEquals(SERVER_ADDR_STRING, profile.server);
|
||||||
|
assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
|
||||||
|
assertEquals(mProxy, profile.proxy);
|
||||||
|
assertTrue(profile.isBypassable);
|
||||||
|
assertTrue(profile.isMetered);
|
||||||
|
assertEquals(TEST_MTU, profile.maxMtu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPskConvertToVpnProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
|
||||||
|
verifyVpnProfileCommon(profile);
|
||||||
|
assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
|
||||||
|
|
||||||
|
// Check nothing else is set
|
||||||
|
assertEquals("", profile.username);
|
||||||
|
assertEquals("", profile.password);
|
||||||
|
assertEquals("", profile.ipsecUserCert);
|
||||||
|
assertEquals("", profile.ipsecCaCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUsernamePasswordConvertToVpnProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
|
||||||
|
verifyVpnProfileCommon(profile);
|
||||||
|
assertEquals(USERNAME_STRING, profile.username);
|
||||||
|
assertEquals(PASSWORD_STRING, profile.password);
|
||||||
|
assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
|
||||||
|
|
||||||
|
// Check nothing else is set
|
||||||
|
assertEquals("", profile.ipsecUserCert);
|
||||||
|
assertEquals("", profile.ipsecSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRsaConvertToVpnProfile() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
|
||||||
|
final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
|
||||||
|
+ Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
|
||||||
|
verifyVpnProfileCommon(profile);
|
||||||
|
assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
|
||||||
|
assertEquals(
|
||||||
|
expectedSecret,
|
||||||
|
profile.ipsecSecret);
|
||||||
|
assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
|
||||||
|
|
||||||
|
// Check nothing else is set
|
||||||
|
assertEquals("", profile.username);
|
||||||
|
assertEquals("", profile.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
profile.username = USERNAME_STRING;
|
||||||
|
profile.password = PASSWORD_STRING;
|
||||||
|
profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
|
||||||
|
profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
|
||||||
|
|
||||||
|
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
|
||||||
|
assertNull(result.getUsername());
|
||||||
|
assertNull(result.getPassword());
|
||||||
|
assertNull(result.getUserCert());
|
||||||
|
assertNull(result.getRsaPrivateKey());
|
||||||
|
assertNull(result.getServerRootCaCert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
profile.ipsecSecret = new String(PSK_BYTES);
|
||||||
|
profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
|
||||||
|
|
||||||
|
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
|
||||||
|
assertNull(result.getPresharedKey());
|
||||||
|
assertNull(result.getUserCert());
|
||||||
|
assertNull(result.getRsaPrivateKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
|
||||||
|
final VpnProfile profile = builder.build().toVpnProfile();
|
||||||
|
profile.username = USERNAME_STRING;
|
||||||
|
profile.password = PASSWORD_STRING;
|
||||||
|
|
||||||
|
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
|
||||||
|
assertNull(result.getUsername());
|
||||||
|
assertNull(result.getPassword());
|
||||||
|
assertNull(result.getPresharedKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPskConversionIsLossless() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthPsk(PSK_BYTES);
|
||||||
|
final Ikev2VpnProfile ikeProfile = builder.build();
|
||||||
|
|
||||||
|
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUsernamePasswordConversionIsLossless() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
|
||||||
|
final Ikev2VpnProfile ikeProfile = builder.build();
|
||||||
|
|
||||||
|
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRsaConversionIsLossless() throws Exception {
|
||||||
|
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
|
||||||
|
|
||||||
|
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
|
||||||
|
final Ikev2VpnProfile ikeProfile = builder.build();
|
||||||
|
|
||||||
|
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CertificateAndKey {
|
||||||
|
public final X509Certificate cert;
|
||||||
|
public final PrivateKey key;
|
||||||
|
|
||||||
|
CertificateAndKey(X509Certificate cert, PrivateKey key) {
|
||||||
|
this.cert = cert;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
|
||||||
|
final Date validityBeginDate =
|
||||||
|
new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
|
||||||
|
final Date validityEndDate =
|
||||||
|
new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
|
||||||
|
|
||||||
|
// Generate a keypair
|
||||||
|
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyPairGenerator.initialize(512);
|
||||||
|
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||||
|
|
||||||
|
final X500Principal dnName = new X500Principal("CN=test.android.com");
|
||||||
|
final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
|
||||||
|
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
|
||||||
|
certGen.setSubjectDN(dnName);
|
||||||
|
certGen.setIssuerDN(dnName);
|
||||||
|
certGen.setNotBefore(validityBeginDate);
|
||||||
|
certGen.setNotAfter(validityEndDate);
|
||||||
|
certGen.setPublicKey(keyPair.getPublic());
|
||||||
|
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
|
||||||
|
|
||||||
|
final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
|
||||||
|
return new CertificateAndKey(cert, keyPair.getPrivate());
|
||||||
|
}
|
||||||
|
}
|
||||||
332
tests/unit/java/android/net/IpMemoryStoreTest.java
Normal file
332
tests/unit/java/android/net/IpMemoryStoreTest.java
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ipmemorystore.Blob;
|
||||||
|
import android.net.ipmemorystore.IOnStatusListener;
|
||||||
|
import android.net.ipmemorystore.NetworkAttributes;
|
||||||
|
import android.net.ipmemorystore.NetworkAttributesParcelable;
|
||||||
|
import android.net.ipmemorystore.Status;
|
||||||
|
import android.net.networkstack.ModuleNetworkStackClient;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class IpMemoryStoreTest {
|
||||||
|
private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
|
||||||
|
private static final String TEST_CLIENT_ID = "testClientId";
|
||||||
|
private static final String TEST_DATA_NAME = "testData";
|
||||||
|
private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
|
||||||
|
private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
|
||||||
|
-128, 0, 89, 112, 91, -34 };
|
||||||
|
private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
|
||||||
|
"hint", 219);
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
Context mMockContext;
|
||||||
|
@Mock
|
||||||
|
ModuleNetworkStackClient mModuleNetworkStackClient;
|
||||||
|
@Mock
|
||||||
|
IIpMemoryStore mMockService;
|
||||||
|
@Mock
|
||||||
|
IOnStatusListener mIOnStatusListener;
|
||||||
|
IpMemoryStore mStore;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startIpMemoryStore(boolean supplyService) {
|
||||||
|
if (supplyService) {
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IIpMemoryStoreCallbacks) invocation.getArgument(0))
|
||||||
|
.onIpMemoryStoreFetched(mMockService);
|
||||||
|
return null;
|
||||||
|
}).when(mModuleNetworkStackClient).fetchIpMemoryStore(any());
|
||||||
|
} else {
|
||||||
|
doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
|
||||||
|
}
|
||||||
|
mStore = new IpMemoryStore(mMockContext) {
|
||||||
|
@Override
|
||||||
|
protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) {
|
||||||
|
return mModuleNetworkStackClient;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
|
||||||
|
return new NetworkAttributes.Builder()
|
||||||
|
.setCluster(hint)
|
||||||
|
.setMtu(mtu)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkAttributes() throws Exception {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
|
||||||
|
mNapCaptor.capture(), any());
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
|
|
||||||
|
mStore.retrieveNetworkAttributes(l2Key,
|
||||||
|
(status, key, attr) -> {
|
||||||
|
assertTrue("Retrieve network attributes not successful : "
|
||||||
|
+ status.resultCode, status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
|
||||||
|
});
|
||||||
|
|
||||||
|
verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrivateData() throws RemoteException {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
final Blob b = new Blob();
|
||||||
|
b.data = TEST_BLOB_DATA;
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
||||||
|
status -> {
|
||||||
|
assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
|
||||||
|
});
|
||||||
|
verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
|
||||||
|
eq(b), any());
|
||||||
|
|
||||||
|
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
|
||||||
|
(status, key, name, data) -> {
|
||||||
|
assertTrue("Retrieve blob status not successful : " + status.resultCode,
|
||||||
|
status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(name, TEST_DATA_NAME);
|
||||||
|
assertTrue(Arrays.equals(b.data, data.data));
|
||||||
|
});
|
||||||
|
verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
|
||||||
|
eq(TEST_OTHER_DATA_NAME), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindL2Key()
|
||||||
|
throws UnknownHostException, RemoteException, Exception {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
|
||||||
|
(status, key) -> {
|
||||||
|
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||||
|
status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
});
|
||||||
|
verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsSameNetwork() throws UnknownHostException, RemoteException {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
final String l2Key1 = "fakeKey1";
|
||||||
|
final String l2Key2 = "fakeKey2";
|
||||||
|
|
||||||
|
mStore.isSameNetwork(l2Key1, l2Key2,
|
||||||
|
(status, answer) -> {
|
||||||
|
assertFalse("Retrieve network sameness suspiciously successful : "
|
||||||
|
+ status.resultCode, status.isSuccess());
|
||||||
|
assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
|
||||||
|
assertNull(answer);
|
||||||
|
});
|
||||||
|
verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnqueuedIpMsRequests() throws Exception {
|
||||||
|
startIpMemoryStore(false /* supplyService */);
|
||||||
|
|
||||||
|
final Blob b = new Blob();
|
||||||
|
b.data = TEST_BLOB_DATA;
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
// enqueue multiple ipms requests
|
||||||
|
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
mStore.retrieveNetworkAttributes(l2Key,
|
||||||
|
(status, key, attr) -> {
|
||||||
|
assertTrue("Retrieve network attributes not successful : "
|
||||||
|
+ status.resultCode, status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
|
||||||
|
});
|
||||||
|
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
|
||||||
|
(status, key, name, data) -> {
|
||||||
|
assertTrue("Retrieve blob status not successful : " + status.resultCode,
|
||||||
|
status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(name, TEST_DATA_NAME);
|
||||||
|
assertTrue(Arrays.equals(b.data, data.data));
|
||||||
|
});
|
||||||
|
|
||||||
|
// get ipms service ready
|
||||||
|
mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(mMockService);
|
||||||
|
|
||||||
|
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
|
||||||
|
inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
|
||||||
|
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
|
||||||
|
eq(b), any());
|
||||||
|
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
|
||||||
|
eq(TEST_OTHER_DATA_NAME), any());
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnqueuedIpMsRequestsWithException() throws Exception {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
|
||||||
|
|
||||||
|
final Blob b = new Blob();
|
||||||
|
b.data = TEST_BLOB_DATA;
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
// enqueue multiple ipms requests
|
||||||
|
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
mStore.retrieveNetworkAttributes(l2Key,
|
||||||
|
(status, key, attr) -> {
|
||||||
|
assertTrue("Retrieve network attributes not successful : "
|
||||||
|
+ status.resultCode, status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
|
||||||
|
});
|
||||||
|
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
|
||||||
|
(status, key, name, data) -> {
|
||||||
|
assertTrue("Retrieve blob status not successful : " + status.resultCode,
|
||||||
|
status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(name, TEST_DATA_NAME);
|
||||||
|
assertTrue(Arrays.equals(b.data, data.data));
|
||||||
|
});
|
||||||
|
|
||||||
|
// verify the rest of the queue is still processed in order even if the remote exception
|
||||||
|
// occurs when calling one or more requests
|
||||||
|
InOrder inOrder = inOrder(mMockService);
|
||||||
|
|
||||||
|
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
|
||||||
|
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
|
||||||
|
eq(b), any());
|
||||||
|
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
|
||||||
|
eq(TEST_OTHER_DATA_NAME), any());
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
|
||||||
|
final Blob b = new Blob();
|
||||||
|
b.data = TEST_BLOB_DATA;
|
||||||
|
final String l2Key = "fakeKey";
|
||||||
|
|
||||||
|
// enqueue multiple ipms requests
|
||||||
|
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
|
||||||
|
status -> assertTrue("Store not successful : " + status.resultCode,
|
||||||
|
status.isSuccess()));
|
||||||
|
mStore.retrieveNetworkAttributes(l2Key,
|
||||||
|
(status, key, attr) -> {
|
||||||
|
throw new RuntimeException("retrieveNetworkAttributes test");
|
||||||
|
});
|
||||||
|
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
||||||
|
status -> {
|
||||||
|
throw new RuntimeException("storeBlob test");
|
||||||
|
});
|
||||||
|
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
|
||||||
|
(status, key, name, data) -> {
|
||||||
|
assertTrue("Retrieve blob status not successful : " + status.resultCode,
|
||||||
|
status.isSuccess());
|
||||||
|
assertEquals(l2Key, key);
|
||||||
|
assertEquals(name, TEST_DATA_NAME);
|
||||||
|
assertTrue(Arrays.equals(b.data, data.data));
|
||||||
|
});
|
||||||
|
|
||||||
|
// verify the rest of the queue is still processed in order even if when one or more
|
||||||
|
// callback throw the remote exception
|
||||||
|
InOrder inOrder = inOrder(mMockService);
|
||||||
|
|
||||||
|
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
|
||||||
|
any());
|
||||||
|
inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
|
||||||
|
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
|
||||||
|
eq(b), any());
|
||||||
|
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
|
||||||
|
eq(TEST_OTHER_DATA_NAME), any());
|
||||||
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFactoryReset() throws RemoteException {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
mStore.factoryReset();
|
||||||
|
verify(mMockService, times(1)).factoryReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
226
tests/unit/java/android/net/IpSecAlgorithmTest.java
Normal file
226
tests/unit/java/android/net/IpSecAlgorithmTest.java
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.IpSecAlgorithm.ALGO_TO_REQUIRED_FIRST_SDK;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.util.CollectionUtils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecAlgorithm}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class IpSecAlgorithmTest {
|
||||||
|
private static final byte[] KEY_MATERIAL;
|
||||||
|
|
||||||
|
private final Resources mMockResources = mock(Resources.class);
|
||||||
|
|
||||||
|
static {
|
||||||
|
KEY_MATERIAL = new byte[128];
|
||||||
|
new Random().nextBytes(KEY_MATERIAL);
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] generateKey(int keyLenInBits) {
|
||||||
|
return Arrays.copyOf(KEY_MATERIAL, keyLenInBits / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoTruncLen() throws Exception {
|
||||||
|
Entry<String, Integer>[] authAndAeadList =
|
||||||
|
new Entry[] {
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
|
||||||
|
new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expect auth and aead algorithms to throw errors if trunclen is omitted.
|
||||||
|
for (Entry<String, Integer> algData : authAndAeadList) {
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
|
||||||
|
fail("Expected exception on unprovided auth trunclen");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure crypt works with no truncation length supplied.
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAuthKeyAndTruncLenValidation(String algoName, int keyLen, int truncLen)
|
||||||
|
throws Exception {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen);
|
||||||
|
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen));
|
||||||
|
fail("Expected exception on unprovided auth trunclen");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen + 8), truncLen);
|
||||||
|
fail("Invalid key length not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen + 1);
|
||||||
|
fail("Invalid truncation length not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCryptKeyLenValidation(String algoName, int keyLen) throws Exception {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen));
|
||||||
|
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(algoName, generateKey(keyLen + 8));
|
||||||
|
fail("Invalid key length not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationForAlgosAddedInS() throws Exception {
|
||||||
|
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.R) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int len : new int[] {160, 224, 288}) {
|
||||||
|
checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
|
||||||
|
}
|
||||||
|
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
|
||||||
|
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
|
||||||
|
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTruncLenValidation() throws Exception {
|
||||||
|
for (int truncLen : new int[] {256, 512}) {
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_SHA512,
|
||||||
|
Arrays.copyOf(KEY_MATERIAL, 512 / 8),
|
||||||
|
truncLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int truncLen : new int[] {255, 513}) {
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_SHA512,
|
||||||
|
Arrays.copyOf(KEY_MATERIAL, 512 / 8),
|
||||||
|
truncLen);
|
||||||
|
fail("Invalid truncation length not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLenValidation() throws Exception {
|
||||||
|
for (int len : new int[] {128, 192, 256}) {
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, len / 8));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 384 / 8));
|
||||||
|
fail("Invalid key length not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlgoNameValidation() throws Exception {
|
||||||
|
try {
|
||||||
|
new IpSecAlgorithm("rot13", Arrays.copyOf(KEY_MATERIAL, 128 / 8));
|
||||||
|
fail("Invalid algorithm name not validated");
|
||||||
|
} catch (IllegalArgumentException pass) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelUnparcel() throws Exception {
|
||||||
|
IpSecAlgorithm init =
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_SHA512, Arrays.copyOf(KEY_MATERIAL, 512 / 8), 256);
|
||||||
|
|
||||||
|
Parcel p = Parcel.obtain();
|
||||||
|
p.setDataPosition(0);
|
||||||
|
init.writeToParcel(p, 0);
|
||||||
|
|
||||||
|
p.setDataPosition(0);
|
||||||
|
IpSecAlgorithm fin = IpSecAlgorithm.CREATOR.createFromParcel(p);
|
||||||
|
assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
|
||||||
|
p.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> getMandatoryAlgos() {
|
||||||
|
return CollectionUtils.filter(
|
||||||
|
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
|
||||||
|
i -> Build.VERSION.FIRST_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> getOptionalAlgos() {
|
||||||
|
return CollectionUtils.filter(
|
||||||
|
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
|
||||||
|
i -> Build.VERSION.FIRST_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSupportedAlgorithms() throws Exception {
|
||||||
|
assertTrue(IpSecAlgorithm.getSupportedAlgorithms().containsAll(getMandatoryAlgos()));
|
||||||
|
assertTrue(ALGO_TO_REQUIRED_FIRST_SDK.keySet().containsAll(
|
||||||
|
IpSecAlgorithm.getSupportedAlgorithms()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadAlgos() throws Exception {
|
||||||
|
final Set<String> optionalAlgoSet = getOptionalAlgos();
|
||||||
|
final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]);
|
||||||
|
|
||||||
|
doReturn(optionalAlgos).when(mMockResources)
|
||||||
|
.getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms);
|
||||||
|
|
||||||
|
final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources));
|
||||||
|
final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet();
|
||||||
|
|
||||||
|
assertEquals(expectedAlgos, enabledAlgos);
|
||||||
|
}
|
||||||
|
}
|
||||||
103
tests/unit/java/android/net/IpSecConfigTest.java
Normal file
103
tests/unit/java/android/net/IpSecConfigTest.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecConfig}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class IpSecConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaults() throws Exception {
|
||||||
|
IpSecConfig c = new IpSecConfig();
|
||||||
|
assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
|
||||||
|
assertEquals("", c.getSourceAddress());
|
||||||
|
assertEquals("", c.getDestinationAddress());
|
||||||
|
assertNull(c.getNetwork());
|
||||||
|
assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
|
||||||
|
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
|
||||||
|
assertEquals(0, c.getEncapRemotePort());
|
||||||
|
assertEquals(0, c.getNattKeepaliveInterval());
|
||||||
|
assertNull(c.getEncryption());
|
||||||
|
assertNull(c.getAuthentication());
|
||||||
|
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
|
||||||
|
assertEquals(0, c.getXfrmInterfaceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IpSecConfig getSampleConfig() {
|
||||||
|
IpSecConfig c = new IpSecConfig();
|
||||||
|
c.setMode(IpSecTransform.MODE_TUNNEL);
|
||||||
|
c.setSourceAddress("0.0.0.0");
|
||||||
|
c.setDestinationAddress("1.2.3.4");
|
||||||
|
c.setSpiResourceId(1984);
|
||||||
|
c.setEncryption(
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.CRYPT_AES_CBC,
|
||||||
|
new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
|
||||||
|
c.setAuthentication(
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_MD5,
|
||||||
|
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
|
||||||
|
128));
|
||||||
|
c.setAuthenticatedEncryption(
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
|
||||||
|
new byte[] {
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
|
||||||
|
},
|
||||||
|
128));
|
||||||
|
c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
|
||||||
|
c.setEncapSocketResourceId(7);
|
||||||
|
c.setEncapRemotePort(22);
|
||||||
|
c.setNattKeepaliveInterval(42);
|
||||||
|
c.setMarkValue(12);
|
||||||
|
c.setMarkMask(23);
|
||||||
|
c.setXfrmInterfaceId(34);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCopyConstructor() {
|
||||||
|
IpSecConfig original = getSampleConfig();
|
||||||
|
IpSecConfig copy = new IpSecConfig(original);
|
||||||
|
|
||||||
|
assertEquals(original, copy);
|
||||||
|
assertNotSame(original, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelUnparcel() {
|
||||||
|
assertParcelingIsLossless(new IpSecConfig());
|
||||||
|
|
||||||
|
IpSecConfig c = getSampleConfig();
|
||||||
|
assertParcelSane(c, 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
305
tests/unit/java/android/net/IpSecManagerTest.java
Normal file
305
tests/unit/java/android/net/IpSecManagerTest.java
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.AF_INET;
|
||||||
|
import static android.system.OsConstants.IPPROTO_UDP;
|
||||||
|
import static android.system.OsConstants.SOCK_DGRAM;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.system.Os;
|
||||||
|
import android.test.mock.MockContext;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.server.IpSecService;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecManager}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class IpSecManagerTest {
|
||||||
|
|
||||||
|
private static final int TEST_UDP_ENCAP_PORT = 34567;
|
||||||
|
private static final int DROID_SPI = 0xD1201D;
|
||||||
|
private static final int DUMMY_RESOURCE_ID = 0x1234;
|
||||||
|
|
||||||
|
private static final InetAddress GOOGLE_DNS_4;
|
||||||
|
private static final String VTI_INTF_NAME = "ipsec_test";
|
||||||
|
private static final InetAddress VTI_LOCAL_ADDRESS;
|
||||||
|
private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
// Google Public DNS Addresses;
|
||||||
|
GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
|
||||||
|
VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException("Could not resolve DNS Addresses", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IpSecService mMockIpSecService;
|
||||||
|
private IpSecManager mIpSecManager;
|
||||||
|
private MockContext mMockContext = new MockContext() {
|
||||||
|
@Override
|
||||||
|
public String getOpPackageName() {
|
||||||
|
return "fooPackage";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mMockIpSecService = mock(IpSecService.class);
|
||||||
|
mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a specific SPI
|
||||||
|
* Close SPIs
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAllocSpi() throws Exception {
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
|
||||||
|
when(mMockIpSecService.allocateSecurityParameterIndex(
|
||||||
|
eq(GOOGLE_DNS_4.getHostAddress()),
|
||||||
|
eq(DROID_SPI),
|
||||||
|
anyObject()))
|
||||||
|
.thenReturn(spiResp);
|
||||||
|
|
||||||
|
IpSecManager.SecurityParameterIndex droidSpi =
|
||||||
|
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI);
|
||||||
|
assertEquals(DROID_SPI, droidSpi.getSpi());
|
||||||
|
|
||||||
|
droidSpi.close();
|
||||||
|
|
||||||
|
verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllocRandomSpi() throws Exception {
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
|
||||||
|
when(mMockIpSecService.allocateSecurityParameterIndex(
|
||||||
|
eq(GOOGLE_DNS_4.getHostAddress()),
|
||||||
|
eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
|
||||||
|
anyObject()))
|
||||||
|
.thenReturn(spiResp);
|
||||||
|
|
||||||
|
IpSecManager.SecurityParameterIndex randomSpi =
|
||||||
|
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
|
||||||
|
|
||||||
|
assertEquals(DROID_SPI, randomSpi.getSpi());
|
||||||
|
|
||||||
|
randomSpi.close();
|
||||||
|
|
||||||
|
verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Throws resource unavailable exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAllocSpiResUnavailableException() throws Exception {
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0);
|
||||||
|
when(mMockIpSecService.allocateSecurityParameterIndex(
|
||||||
|
anyString(), anyInt(), anyObject()))
|
||||||
|
.thenReturn(spiResp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
|
||||||
|
fail("ResourceUnavailableException was not thrown");
|
||||||
|
} catch (IpSecManager.ResourceUnavailableException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Throws spi unavailable exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAllocSpiSpiUnavailableException() throws Exception {
|
||||||
|
IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0);
|
||||||
|
when(mMockIpSecService.allocateSecurityParameterIndex(
|
||||||
|
anyString(), anyInt(), anyObject()))
|
||||||
|
.thenReturn(spiResp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
|
||||||
|
fail("ResourceUnavailableException was not thrown");
|
||||||
|
} catch (IpSecManager.ResourceUnavailableException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should throw exception when request spi 0 in IpSecManager
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRequestAllocInvalidSpi() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0);
|
||||||
|
fail("Able to allocate invalid spi");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenEncapsulationSocket() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
new IpSecUdpEncapResponse(
|
||||||
|
IpSecManager.Status.OK,
|
||||||
|
DUMMY_RESOURCE_ID,
|
||||||
|
TEST_UDP_ENCAP_PORT,
|
||||||
|
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
|
||||||
|
when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
|
||||||
|
.thenReturn(udpEncapResp);
|
||||||
|
|
||||||
|
IpSecManager.UdpEncapsulationSocket encapSocket =
|
||||||
|
mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
|
||||||
|
assertNotNull(encapSocket.getFileDescriptor());
|
||||||
|
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
|
||||||
|
|
||||||
|
encapSocket.close();
|
||||||
|
|
||||||
|
verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
IpSecConfig dummyConfig = new IpSecConfig();
|
||||||
|
IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig);
|
||||||
|
|
||||||
|
// Even if underlying SocketImpl is not initalized, this should force the init, and
|
||||||
|
// thereby succeed.
|
||||||
|
mIpSecManager.applyTransportModeTransform(
|
||||||
|
socket, IpSecManager.DIRECTION_IN, dummyTransform);
|
||||||
|
|
||||||
|
// Check to make sure the FileDescriptor is non-null
|
||||||
|
assertNotNull(socket.getFileDescriptor$());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
|
||||||
|
// Even if underlying SocketImpl is not initalized, this should force the init, and
|
||||||
|
// thereby succeed.
|
||||||
|
mIpSecManager.removeTransportModeTransforms(socket);
|
||||||
|
|
||||||
|
// Check to make sure the FileDescriptor is non-null
|
||||||
|
assertNotNull(socket.getFileDescriptor$());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
new IpSecUdpEncapResponse(
|
||||||
|
IpSecManager.Status.OK,
|
||||||
|
DUMMY_RESOURCE_ID,
|
||||||
|
TEST_UDP_ENCAP_PORT,
|
||||||
|
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
|
||||||
|
|
||||||
|
when(mMockIpSecService.openUdpEncapsulationSocket(eq(0), anyObject()))
|
||||||
|
.thenReturn(udpEncapResp);
|
||||||
|
|
||||||
|
IpSecManager.UdpEncapsulationSocket encapSocket =
|
||||||
|
mIpSecManager.openUdpEncapsulationSocket();
|
||||||
|
|
||||||
|
assertNotNull(encapSocket.getFileDescriptor());
|
||||||
|
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
|
||||||
|
|
||||||
|
encapSocket.close();
|
||||||
|
|
||||||
|
verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenEncapsulationSocketWithInvalidPort() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecManager.openUdpEncapsulationSocket(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
|
||||||
|
fail("IllegalArgumentException was not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add test when applicable transform builder interface is available
|
||||||
|
|
||||||
|
private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
|
||||||
|
throws Exception {
|
||||||
|
IpSecTunnelInterfaceResponse dummyResponse =
|
||||||
|
new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
|
||||||
|
when(mMockIpSecService.createTunnelInterface(
|
||||||
|
eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
|
||||||
|
anyObject(), anyObject(), anyString()))
|
||||||
|
.thenReturn(dummyResponse);
|
||||||
|
|
||||||
|
IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
|
||||||
|
VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
|
||||||
|
|
||||||
|
assertNotNull(tunnelIntf);
|
||||||
|
return tunnelIntf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateVti() throws Exception {
|
||||||
|
IpSecManager.IpSecTunnelInterface tunnelIntf =
|
||||||
|
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
|
||||||
|
|
||||||
|
assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
|
||||||
|
|
||||||
|
tunnelIntf.close();
|
||||||
|
verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddRemoveAddressesFromVti() throws Exception {
|
||||||
|
IpSecManager.IpSecTunnelInterface tunnelIntf =
|
||||||
|
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
|
||||||
|
|
||||||
|
tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
|
||||||
|
VTI_INNER_ADDRESS.getPrefixLength());
|
||||||
|
verify(mMockIpSecService)
|
||||||
|
.addAddressToTunnelInterface(
|
||||||
|
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
|
||||||
|
|
||||||
|
tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
|
||||||
|
VTI_INNER_ADDRESS.getPrefixLength());
|
||||||
|
verify(mMockIpSecService)
|
||||||
|
.addAddressToTunnelInterface(
|
||||||
|
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
|
||||||
|
}
|
||||||
|
}
|
||||||
62
tests/unit/java/android/net/IpSecTransformTest.java
Normal file
62
tests/unit/java/android/net/IpSecTransformTest.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecTransform}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class IpSecTransformTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTransformCopiesConfig() {
|
||||||
|
// Create a config with a few parameters to make sure it's not empty
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setSourceAddress("0.0.0.0");
|
||||||
|
config.setDestinationAddress("1.2.3.4");
|
||||||
|
config.setSpiResourceId(1984);
|
||||||
|
|
||||||
|
IpSecTransform preModification = new IpSecTransform(null, config);
|
||||||
|
|
||||||
|
config.setSpiResourceId(1985);
|
||||||
|
IpSecTransform postModification = new IpSecTransform(null, config);
|
||||||
|
|
||||||
|
assertNotEquals(preModification, postModification);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTransformsWithSameConfigEqual() {
|
||||||
|
// Create a config with a few parameters to make sure it's not empty
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setSourceAddress("0.0.0.0");
|
||||||
|
config.setDestinationAddress("1.2.3.4");
|
||||||
|
config.setSpiResourceId(1984);
|
||||||
|
|
||||||
|
IpSecTransform config1 = new IpSecTransform(null, config);
|
||||||
|
IpSecTransform config2 = new IpSecTransform(null, config);
|
||||||
|
|
||||||
|
assertEquals(config1, config2);
|
||||||
|
}
|
||||||
|
}
|
||||||
205
tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
Normal file
205
tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.net.util.KeepalivePacketDataUtil;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public final class KeepalivePacketDataUtilTest {
|
||||||
|
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
|
||||||
|
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromTcpKeepaliveStableParcelable() throws Exception {
|
||||||
|
final int srcPort = 1234;
|
||||||
|
final int dstPort = 4321;
|
||||||
|
final int seq = 0x11111111;
|
||||||
|
final int ack = 0x22222222;
|
||||||
|
final int wnd = 8000;
|
||||||
|
final int wndScale = 2;
|
||||||
|
final int tos = 4;
|
||||||
|
final int ttl = 64;
|
||||||
|
TcpKeepalivePacketData resultData = null;
|
||||||
|
final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
|
||||||
|
testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
|
||||||
|
testInfo.srcPort = srcPort;
|
||||||
|
testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
|
||||||
|
testInfo.dstPort = dstPort;
|
||||||
|
testInfo.seq = seq;
|
||||||
|
testInfo.ack = ack;
|
||||||
|
testInfo.rcvWnd = wnd;
|
||||||
|
testInfo.rcvWndScale = wndScale;
|
||||||
|
testInfo.tos = tos;
|
||||||
|
testInfo.ttl = ttl;
|
||||||
|
try {
|
||||||
|
resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
|
||||||
|
} catch (InvalidPacketException e) {
|
||||||
|
fail("InvalidPacketException: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
|
||||||
|
assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
|
||||||
|
assertEquals(testInfo.srcPort, resultData.getSrcPort());
|
||||||
|
assertEquals(testInfo.dstPort, resultData.getDstPort());
|
||||||
|
assertEquals(testInfo.seq, resultData.tcpSeq);
|
||||||
|
assertEquals(testInfo.ack, resultData.tcpAck);
|
||||||
|
assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
|
||||||
|
assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
|
||||||
|
assertEquals(testInfo.tos, resultData.ipTos);
|
||||||
|
assertEquals(testInfo.ttl, resultData.ipTtl);
|
||||||
|
|
||||||
|
assertParcelingIsLossless(resultData);
|
||||||
|
|
||||||
|
final byte[] packet = resultData.getPacket();
|
||||||
|
// IP version and IHL
|
||||||
|
assertEquals(packet[0], 0x45);
|
||||||
|
// TOS
|
||||||
|
assertEquals(packet[1], tos);
|
||||||
|
// TTL
|
||||||
|
assertEquals(packet[8], ttl);
|
||||||
|
// Source IP address.
|
||||||
|
byte[] ip = new byte[4];
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
|
||||||
|
buf.get(ip);
|
||||||
|
assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
|
||||||
|
// Destination IP address.
|
||||||
|
buf = ByteBuffer.wrap(packet, 16, 4);
|
||||||
|
buf.get(ip);
|
||||||
|
assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
|
||||||
|
|
||||||
|
buf = ByteBuffer.wrap(packet, 20, 12);
|
||||||
|
// Source port.
|
||||||
|
assertEquals(buf.getShort(), srcPort);
|
||||||
|
// Destination port.
|
||||||
|
assertEquals(buf.getShort(), dstPort);
|
||||||
|
// Sequence number.
|
||||||
|
assertEquals(buf.getInt(), seq);
|
||||||
|
// Ack.
|
||||||
|
assertEquals(buf.getInt(), ack);
|
||||||
|
// Window size.
|
||||||
|
buf = ByteBuffer.wrap(packet, 34, 2);
|
||||||
|
assertEquals(buf.getShort(), wnd >> wndScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: add ipv6 test when ipv6 supported
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToTcpKeepaliveStableParcelable() throws Exception {
|
||||||
|
final int srcPort = 1234;
|
||||||
|
final int dstPort = 4321;
|
||||||
|
final int sequence = 0x11111111;
|
||||||
|
final int ack = 0x22222222;
|
||||||
|
final int wnd = 48_000;
|
||||||
|
final int wndScale = 2;
|
||||||
|
final int tos = 4;
|
||||||
|
final int ttl = 64;
|
||||||
|
final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
|
||||||
|
testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
|
||||||
|
testInfo.srcPort = srcPort;
|
||||||
|
testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
|
||||||
|
testInfo.dstPort = dstPort;
|
||||||
|
testInfo.seq = sequence;
|
||||||
|
testInfo.ack = ack;
|
||||||
|
testInfo.rcvWnd = wnd;
|
||||||
|
testInfo.rcvWndScale = wndScale;
|
||||||
|
testInfo.tos = tos;
|
||||||
|
testInfo.ttl = ttl;
|
||||||
|
TcpKeepalivePacketData testData = null;
|
||||||
|
TcpKeepalivePacketDataParcelable resultData = null;
|
||||||
|
testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
|
||||||
|
resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
|
||||||
|
assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
|
||||||
|
assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
|
||||||
|
assertEquals(resultData.srcPort, srcPort);
|
||||||
|
assertEquals(resultData.dstPort, dstPort);
|
||||||
|
assertEquals(resultData.seq, sequence);
|
||||||
|
assertEquals(resultData.ack, ack);
|
||||||
|
assertEquals(resultData.rcvWnd, wnd);
|
||||||
|
assertEquals(resultData.rcvWndScale, wndScale);
|
||||||
|
assertEquals(resultData.tos, tos);
|
||||||
|
assertEquals(resultData.ttl, ttl);
|
||||||
|
|
||||||
|
final String expected = ""
|
||||||
|
+ "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
|
||||||
|
+ " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
|
||||||
|
+ " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
|
||||||
|
assertEquals(expected, resultData.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseTcpKeepalivePacketData() throws Exception {
|
||||||
|
final int srcPort = 1234;
|
||||||
|
final int dstPort = 4321;
|
||||||
|
final int sequence = 0x11111111;
|
||||||
|
final int ack = 0x22222222;
|
||||||
|
final int wnd = 4800;
|
||||||
|
final int wndScale = 2;
|
||||||
|
final int tos = 4;
|
||||||
|
final int ttl = 64;
|
||||||
|
final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
|
||||||
|
testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
|
||||||
|
testParcel.srcPort = srcPort;
|
||||||
|
testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
|
||||||
|
testParcel.dstPort = dstPort;
|
||||||
|
testParcel.seq = sequence;
|
||||||
|
testParcel.ack = ack;
|
||||||
|
testParcel.rcvWnd = wnd;
|
||||||
|
testParcel.rcvWndScale = wndScale;
|
||||||
|
testParcel.tos = tos;
|
||||||
|
testParcel.ttl = ttl;
|
||||||
|
|
||||||
|
final KeepalivePacketData testData =
|
||||||
|
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
|
||||||
|
final TcpKeepalivePacketDataParcelable parsedParcelable =
|
||||||
|
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
|
||||||
|
final TcpKeepalivePacketData roundTripData =
|
||||||
|
KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
|
||||||
|
|
||||||
|
// Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
|
||||||
|
assertTrue(testData.getPacket().length > 0);
|
||||||
|
assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
|
||||||
|
|
||||||
|
testParcel.rcvWndScale = 0;
|
||||||
|
final KeepalivePacketData noScaleTestData =
|
||||||
|
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
|
||||||
|
final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
|
||||||
|
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
|
||||||
|
final TcpKeepalivePacketData noScaleRoundTripData =
|
||||||
|
KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
|
||||||
|
assertEquals(noScaleTestData, noScaleRoundTripData);
|
||||||
|
assertTrue(noScaleTestData.getPacket().length > 0);
|
||||||
|
assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
|
||||||
|
}
|
||||||
|
}
|
||||||
312
tests/unit/java/android/net/MacAddressTest.java
Normal file
312
tests/unit/java/android/net/MacAddressTest.java
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.MacAddressUtils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class MacAddressTest {
|
||||||
|
|
||||||
|
static class AddrTypeTestCase {
|
||||||
|
byte[] addr;
|
||||||
|
int expectedType;
|
||||||
|
|
||||||
|
static AddrTypeTestCase of(int expectedType, int... addr) {
|
||||||
|
AddrTypeTestCase t = new AddrTypeTestCase();
|
||||||
|
t.expectedType = expectedType;
|
||||||
|
t.addr = toByteArray(addr);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacAddrTypes() {
|
||||||
|
AddrTypeTestCase[] testcases = {
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66),
|
||||||
|
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (AddrTypeTestCase t : testcases) {
|
||||||
|
int got = MacAddress.macAddressType(t.addr);
|
||||||
|
String msg = String.format("expected type of %s to be %s, but got %s",
|
||||||
|
Arrays.toString(t.addr), t.expectedType, got);
|
||||||
|
assertEquals(msg, t.expectedType, got);
|
||||||
|
|
||||||
|
if (got != MacAddress.TYPE_UNKNOWN) {
|
||||||
|
assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToOuiString() {
|
||||||
|
String[][] macs = {
|
||||||
|
{"07:00:d3:56:8a:c4", "07:00:d3"},
|
||||||
|
{"33:33:aa:bb:cc:dd", "33:33:aa"},
|
||||||
|
{"06:00:00:00:00:00", "06:00:00"},
|
||||||
|
{"07:00:d3:56:8a:c4", "07:00:d3"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String[] pair : macs) {
|
||||||
|
String mac = pair[0];
|
||||||
|
String expected = pair[1];
|
||||||
|
assertEquals(expected, MacAddress.fromString(mac).toOuiString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHexPaddingWhenPrinting() {
|
||||||
|
String[] macs = {
|
||||||
|
"07:00:d3:56:8a:c4",
|
||||||
|
"33:33:aa:bb:cc:dd",
|
||||||
|
"06:00:00:00:00:00",
|
||||||
|
"07:00:d3:56:8a:c4"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String mac : macs) {
|
||||||
|
assertEquals(mac, MacAddress.fromString(mac).toString());
|
||||||
|
assertEquals(mac,
|
||||||
|
MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsMulticastAddress() {
|
||||||
|
MacAddress[] multicastAddresses = {
|
||||||
|
MacAddress.BROADCAST_ADDRESS,
|
||||||
|
MacAddress.fromString("07:00:d3:56:8a:c4"),
|
||||||
|
MacAddress.fromString("33:33:aa:bb:cc:dd"),
|
||||||
|
};
|
||||||
|
MacAddress[] unicastAddresses = {
|
||||||
|
MacAddress.ALL_ZEROS_ADDRESS,
|
||||||
|
MacAddress.fromString("00:01:44:55:66:77"),
|
||||||
|
MacAddress.fromString("08:00:22:33:44:55"),
|
||||||
|
MacAddress.fromString("06:00:00:00:00:00"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (MacAddress mac : multicastAddresses) {
|
||||||
|
String msg = mac.toString() + " expected to be a multicast address";
|
||||||
|
assertTrue(msg, MacAddressUtils.isMulticastAddress(mac));
|
||||||
|
}
|
||||||
|
for (MacAddress mac : unicastAddresses) {
|
||||||
|
String msg = mac.toString() + " expected not to be a multicast address";
|
||||||
|
assertFalse(msg, MacAddressUtils.isMulticastAddress(mac));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsLocallyAssignedAddress() {
|
||||||
|
MacAddress[] localAddresses = {
|
||||||
|
MacAddress.fromString("06:00:00:00:00:00"),
|
||||||
|
MacAddress.fromString("07:00:d3:56:8a:c4"),
|
||||||
|
MacAddress.fromString("33:33:aa:bb:cc:dd"),
|
||||||
|
};
|
||||||
|
MacAddress[] universalAddresses = {
|
||||||
|
MacAddress.fromString("00:01:44:55:66:77"),
|
||||||
|
MacAddress.fromString("08:00:22:33:44:55"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (MacAddress mac : localAddresses) {
|
||||||
|
String msg = mac.toString() + " expected to be a locally assigned address";
|
||||||
|
assertTrue(msg, mac.isLocallyAssigned());
|
||||||
|
}
|
||||||
|
for (MacAddress mac : universalAddresses) {
|
||||||
|
String msg = mac.toString() + " expected not to be globally unique address";
|
||||||
|
assertFalse(msg, mac.isLocallyAssigned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacAddressConversions() {
|
||||||
|
final int iterations = 10000;
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
|
||||||
|
|
||||||
|
String stringRepr = mac.toString();
|
||||||
|
byte[] bytesRepr = mac.toByteArray();
|
||||||
|
|
||||||
|
assertEquals(mac, MacAddress.fromString(stringRepr));
|
||||||
|
assertEquals(mac, MacAddress.fromBytes(bytesRepr));
|
||||||
|
|
||||||
|
assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr)));
|
||||||
|
assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacAddressRandomGeneration() {
|
||||||
|
final int iterations = 1000;
|
||||||
|
final String expectedAndroidOui = "da:a1:19";
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase();
|
||||||
|
String stringRepr = mac.toString();
|
||||||
|
|
||||||
|
assertTrue(stringRepr + " expected to be a locally assigned address",
|
||||||
|
mac.isLocallyAssigned());
|
||||||
|
assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
|
||||||
|
stringRepr.startsWith(expectedAndroidOui));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Random r = new Random();
|
||||||
|
final String anotherOui = "24:5f:78";
|
||||||
|
final String expectedLocalOui = "26:5f:78";
|
||||||
|
final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0");
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r);
|
||||||
|
String stringRepr = mac.toString();
|
||||||
|
|
||||||
|
assertTrue(stringRepr + " expected to be a locally assigned address",
|
||||||
|
mac.isLocallyAssigned());
|
||||||
|
assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
|
||||||
|
assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
|
||||||
|
stringRepr.startsWith(expectedLocalOui));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
|
||||||
|
String stringRepr = mac.toString();
|
||||||
|
|
||||||
|
assertTrue(stringRepr + " expected to be a locally assigned address",
|
||||||
|
mac.isLocallyAssigned());
|
||||||
|
assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructorInputValidation() {
|
||||||
|
String[] invalidStringAddresses = {
|
||||||
|
"",
|
||||||
|
"abcd",
|
||||||
|
"1:2:3:4:5",
|
||||||
|
"1:2:3:4:5:6:7",
|
||||||
|
"10000:2:3:4:5:6",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String s : invalidStringAddresses) {
|
||||||
|
try {
|
||||||
|
MacAddress mac = MacAddress.fromString(s);
|
||||||
|
fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
|
||||||
|
} catch (IllegalArgumentException excepted) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
MacAddress mac = MacAddress.fromString(null);
|
||||||
|
fail("MacAddress.fromString(null) should have failed, but returned " + mac);
|
||||||
|
} catch (NullPointerException excepted) {
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[][] invalidBytesAddresses = {
|
||||||
|
{},
|
||||||
|
{1,2,3,4,5},
|
||||||
|
{1,2,3,4,5,6,7},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (byte[] b : invalidBytesAddresses) {
|
||||||
|
try {
|
||||||
|
MacAddress mac = MacAddress.fromBytes(b);
|
||||||
|
fail("MacAddress.fromBytes(" + Arrays.toString(b)
|
||||||
|
+ ") should have failed, but returned " + mac);
|
||||||
|
} catch (IllegalArgumentException excepted) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
MacAddress mac = MacAddress.fromBytes(null);
|
||||||
|
fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
|
||||||
|
} catch (NullPointerException excepted) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMatches() {
|
||||||
|
// match 4 bytes prefix
|
||||||
|
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("aa:bb:cc:dd:00:00"),
|
||||||
|
MacAddress.fromString("ff:ff:ff:ff:00:00")));
|
||||||
|
|
||||||
|
// match bytes 0,1,2 and 5
|
||||||
|
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("aa:bb:cc:00:00:11"),
|
||||||
|
MacAddress.fromString("ff:ff:ff:00:00:ff")));
|
||||||
|
|
||||||
|
// match 34 bit prefix
|
||||||
|
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("aa:bb:cc:dd:c0:00"),
|
||||||
|
MacAddress.fromString("ff:ff:ff:ff:c0:00")));
|
||||||
|
|
||||||
|
// fail to match 36 bit prefix
|
||||||
|
assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("aa:bb:cc:dd:40:00"),
|
||||||
|
MacAddress.fromString("ff:ff:ff:ff:f0:00")));
|
||||||
|
|
||||||
|
// match all 6 bytes
|
||||||
|
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("aa:bb:cc:dd:ee:11"),
|
||||||
|
MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
|
||||||
|
|
||||||
|
// match none of 6 bytes
|
||||||
|
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
|
||||||
|
MacAddress.fromString("00:00:00:00:00:00"),
|
||||||
|
MacAddress.fromString("00:00:00:00:00:00")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that link-local address generation from MAC is valid.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLinkLocalFromMacGeneration() {
|
||||||
|
MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
|
||||||
|
byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74,
|
||||||
|
(byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
|
||||||
|
Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
|
||||||
|
assertTrue(llv6.isLinkLocalAddress());
|
||||||
|
assertArrayEquals(inet6ll, llv6.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] toByteArray(int... in) {
|
||||||
|
byte[] out = new byte[in.length];
|
||||||
|
for (int i = 0; i < in.length; i++) {
|
||||||
|
out[i] = (byte) in[i];
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
tests/unit/java/android/net/NetworkIdentityTest.kt
Normal file
54
tests/unit/java/android/net/NetworkIdentityTest.kt
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net
|
||||||
|
|
||||||
|
import android.net.NetworkIdentity.OEM_NONE
|
||||||
|
import android.net.NetworkIdentity.OEM_PAID
|
||||||
|
import android.net.NetworkIdentity.OEM_PRIVATE
|
||||||
|
import android.net.NetworkIdentity.getOemBitfield
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class NetworkIdentityTest {
|
||||||
|
@Test
|
||||||
|
fun testGetOemBitfield() {
|
||||||
|
val oemNone = NetworkCapabilities().apply {
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
|
||||||
|
}
|
||||||
|
val oemPaid = NetworkCapabilities().apply {
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
|
||||||
|
}
|
||||||
|
val oemPrivate = NetworkCapabilities().apply {
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
|
||||||
|
}
|
||||||
|
val oemAll = NetworkCapabilities().apply {
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(getOemBitfield(oemNone), OEM_NONE)
|
||||||
|
assertEquals(getOemBitfield(oemPaid), OEM_PAID)
|
||||||
|
assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
|
||||||
|
assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
|
||||||
|
}
|
||||||
|
}
|
||||||
599
tests/unit/java/android/net/NetworkStatsHistoryTest.java
Normal file
599
tests/unit/java/android/net/NetworkStatsHistoryTest.java
Normal file
@@ -0,0 +1,599 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
|
||||||
|
import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
|
||||||
|
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
|
||||||
|
import static android.net.NetworkStatsHistory.FIELD_ALL;
|
||||||
|
import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
|
||||||
|
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
||||||
|
import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
|
||||||
|
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
||||||
|
import static android.net.TrafficStats.GB_IN_BYTES;
|
||||||
|
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||||
|
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.frameworks.tests.net.R;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NetworkStatsHistoryTest {
|
||||||
|
private static final String TAG = "NetworkStatsHistoryTest";
|
||||||
|
|
||||||
|
private static final long TEST_START = 1194220800000L;
|
||||||
|
|
||||||
|
private NetworkStatsHistory stats;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
if (stats != null) {
|
||||||
|
assertConsistent(stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadOriginalVersion() throws Exception {
|
||||||
|
final Context context = InstrumentationRegistry.getContext();
|
||||||
|
final DataInputStream in =
|
||||||
|
new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
|
||||||
|
|
||||||
|
NetworkStatsHistory.Entry entry = null;
|
||||||
|
try {
|
||||||
|
final NetworkStatsHistory history = new NetworkStatsHistory(in);
|
||||||
|
assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
|
||||||
|
|
||||||
|
entry = history.getValues(0, entry);
|
||||||
|
assertEquals(29143L, entry.rxBytes);
|
||||||
|
assertEquals(6223L, entry.txBytes);
|
||||||
|
|
||||||
|
entry = history.getValues(history.size() - 1, entry);
|
||||||
|
assertEquals(1476L, entry.rxBytes);
|
||||||
|
assertEquals(838L, entry.txBytes);
|
||||||
|
|
||||||
|
entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
|
||||||
|
assertEquals(332401L, entry.rxBytes);
|
||||||
|
assertEquals(64314L, entry.txBytes);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordSingleBucket() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
// record data into narrow window to get single bucket
|
||||||
|
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
|
||||||
|
assertEquals(1, stats.size());
|
||||||
|
assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordEqualBuckets() throws Exception {
|
||||||
|
final long bucketDuration = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(bucketDuration);
|
||||||
|
|
||||||
|
// split equally across two buckets
|
||||||
|
final long recordStart = TEST_START + (bucketDuration / 2);
|
||||||
|
stats.recordData(recordStart, recordStart + bucketDuration,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
|
||||||
|
|
||||||
|
assertEquals(2, stats.size());
|
||||||
|
assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
|
||||||
|
assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordTouchingBuckets() throws Exception {
|
||||||
|
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
// split almost completely into middle bucket, but with a few minutes
|
||||||
|
// overlap into neighboring buckets. total record is 20 minutes.
|
||||||
|
final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
|
||||||
|
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
|
||||||
|
stats.recordData(recordStart, recordEnd,
|
||||||
|
new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
|
||||||
|
|
||||||
|
assertEquals(3, stats.size());
|
||||||
|
// first bucket should have (1/20 of value)
|
||||||
|
assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
|
||||||
|
// second bucket should have (15/20 of value)
|
||||||
|
assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
|
||||||
|
// final bucket should have (4/20 of value)
|
||||||
|
assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordGapBuckets() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
// record some data today and next week with large gap
|
||||||
|
final long firstStart = TEST_START;
|
||||||
|
final long lastStart = TEST_START + WEEK_IN_MILLIS;
|
||||||
|
stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
|
||||||
|
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
|
||||||
|
|
||||||
|
// we should have two buckets, far apart from each other
|
||||||
|
assertEquals(2, stats.size());
|
||||||
|
assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
|
||||||
|
assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
|
||||||
|
|
||||||
|
// now record something in middle, spread across two buckets
|
||||||
|
final long middleStart = TEST_START + DAY_IN_MILLIS;
|
||||||
|
final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
|
||||||
|
stats.recordData(middleStart, middleEnd,
|
||||||
|
new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
|
||||||
|
|
||||||
|
// now should have four buckets, with new record in middle two buckets
|
||||||
|
assertEquals(4, stats.size());
|
||||||
|
assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
|
||||||
|
assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
|
||||||
|
assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
|
||||||
|
assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordOverlapBuckets() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
// record some data in one bucket, and another overlapping buckets
|
||||||
|
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
|
||||||
|
final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
|
||||||
|
stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
|
||||||
|
|
||||||
|
// should have two buckets, with some data mixed together
|
||||||
|
assertEquals(2, stats.size());
|
||||||
|
assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
|
||||||
|
assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordEntireGapIdentical() throws Exception {
|
||||||
|
// first, create two separate histories far apart
|
||||||
|
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
|
||||||
|
|
||||||
|
final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
|
||||||
|
final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
|
||||||
|
|
||||||
|
// combine together with identical bucket size
|
||||||
|
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
stats.recordEntireHistory(stats1);
|
||||||
|
stats.recordEntireHistory(stats2);
|
||||||
|
|
||||||
|
// first verify that totals match up
|
||||||
|
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
|
||||||
|
|
||||||
|
// now inspect internal buckets
|
||||||
|
assertValues(stats, 0, 1000L, 500L);
|
||||||
|
assertValues(stats, 1, 1000L, 500L);
|
||||||
|
assertValues(stats, 2, 500L, 250L);
|
||||||
|
assertValues(stats, 3, 500L, 250L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecordEntireOverlapVaryingBuckets() throws Exception {
|
||||||
|
// create history just over hour bucket boundary
|
||||||
|
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
|
||||||
|
|
||||||
|
final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
|
||||||
|
final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
|
||||||
|
stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
|
||||||
|
|
||||||
|
// combine together with minute bucket size
|
||||||
|
stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
|
||||||
|
stats.recordEntireHistory(stats1);
|
||||||
|
stats.recordEntireHistory(stats2);
|
||||||
|
|
||||||
|
// first verify that totals match up
|
||||||
|
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
|
||||||
|
|
||||||
|
// now inspect internal buckets
|
||||||
|
assertValues(stats, 0, 10L, 10L);
|
||||||
|
assertValues(stats, 1, 20L, 20L);
|
||||||
|
assertValues(stats, 2, 20L, 20L);
|
||||||
|
assertValues(stats, 3, 20L, 20L);
|
||||||
|
assertValues(stats, 4, 20L, 20L);
|
||||||
|
assertValues(stats, 5, 20L, 20L);
|
||||||
|
assertValues(stats, 6, 10L, 10L);
|
||||||
|
|
||||||
|
// now combine using 15min buckets
|
||||||
|
stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
|
||||||
|
stats.recordEntireHistory(stats1);
|
||||||
|
stats.recordEntireHistory(stats2);
|
||||||
|
|
||||||
|
// first verify that totals match up
|
||||||
|
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
|
||||||
|
|
||||||
|
// and inspect buckets
|
||||||
|
assertValues(stats, 0, 200L, 200L);
|
||||||
|
assertValues(stats, 1, 150L, 150L);
|
||||||
|
assertValues(stats, 2, 150L, 150L);
|
||||||
|
assertValues(stats, 3, 150L, 150L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemove() throws Exception {
|
||||||
|
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
|
||||||
|
// record some data across 24 buckets
|
||||||
|
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
|
||||||
|
assertEquals(24, stats.size());
|
||||||
|
|
||||||
|
// try removing invalid data; should be no change
|
||||||
|
stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
|
||||||
|
assertEquals(24, stats.size());
|
||||||
|
|
||||||
|
// try removing far before buckets; should be no change
|
||||||
|
stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
|
||||||
|
assertEquals(24, stats.size());
|
||||||
|
|
||||||
|
// try removing just moments into first bucket; should be no change
|
||||||
|
// since that bucket contains data beyond the cutoff
|
||||||
|
stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
|
||||||
|
assertEquals(24, stats.size());
|
||||||
|
|
||||||
|
// try removing single bucket
|
||||||
|
stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
|
||||||
|
assertEquals(23, stats.size());
|
||||||
|
|
||||||
|
// try removing multiple buckets
|
||||||
|
stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
|
||||||
|
assertEquals(20, stats.size());
|
||||||
|
|
||||||
|
// try removing all buckets
|
||||||
|
stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
|
||||||
|
assertEquals(0, stats.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTotalData() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
// record uniform data across day
|
||||||
|
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
|
||||||
|
|
||||||
|
// verify that total outside range is 0
|
||||||
|
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
|
||||||
|
|
||||||
|
// verify total in first hour
|
||||||
|
assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
|
||||||
|
|
||||||
|
// verify total across 1.5 hours
|
||||||
|
assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
|
||||||
|
|
||||||
|
// verify total beyond end
|
||||||
|
assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
|
||||||
|
|
||||||
|
// verify everything total
|
||||||
|
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFuzzing() throws Exception {
|
||||||
|
try {
|
||||||
|
// fuzzing with random events, looking for crashes
|
||||||
|
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
||||||
|
final Random r = new Random();
|
||||||
|
for (int i = 0; i < 500; i++) {
|
||||||
|
stats = new NetworkStatsHistory(r.nextLong());
|
||||||
|
for (int j = 0; j < 10000; j++) {
|
||||||
|
if (r.nextBoolean()) {
|
||||||
|
// add range
|
||||||
|
final long start = r.nextLong();
|
||||||
|
final long end = start + r.nextInt();
|
||||||
|
entry.rxBytes = nextPositiveLong(r);
|
||||||
|
entry.rxPackets = nextPositiveLong(r);
|
||||||
|
entry.txBytes = nextPositiveLong(r);
|
||||||
|
entry.txPackets = nextPositiveLong(r);
|
||||||
|
entry.operations = nextPositiveLong(r);
|
||||||
|
stats.recordData(start, end, entry);
|
||||||
|
} else {
|
||||||
|
// trim something
|
||||||
|
stats.removeBucketsBefore(r.nextLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertConsistent(stats);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.e(TAG, String.valueOf(stats));
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long nextPositiveLong(Random r) {
|
||||||
|
final long value = r.nextLong();
|
||||||
|
return value < 0 ? -value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoreFields() throws Exception {
|
||||||
|
final NetworkStatsHistory history = new NetworkStatsHistory(
|
||||||
|
MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
||||||
|
|
||||||
|
history.recordData(0, MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||||
|
history.recordData(0, 2 * MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
|
||||||
|
|
||||||
|
assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoreFieldsRecordIn() throws Exception {
|
||||||
|
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
|
||||||
|
final NetworkStatsHistory partial = new NetworkStatsHistory(
|
||||||
|
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
|
||||||
|
|
||||||
|
full.recordData(0, MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||||
|
partial.recordEntireHistory(full);
|
||||||
|
|
||||||
|
assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoreFieldsRecordOut() throws Exception {
|
||||||
|
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
|
||||||
|
final NetworkStatsHistory partial = new NetworkStatsHistory(
|
||||||
|
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
|
||||||
|
|
||||||
|
partial.recordData(0, MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||||
|
full.recordEntireHistory(partial);
|
||||||
|
|
||||||
|
assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerialize() throws Exception {
|
||||||
|
final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
|
||||||
|
before.recordData(0, 4 * MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||||
|
before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
|
||||||
|
new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
|
||||||
|
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
before.writeToStream(new DataOutputStream(out));
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
|
||||||
|
|
||||||
|
// must have identical totals before and after
|
||||||
|
assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
|
||||||
|
assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVarLong() throws Exception {
|
||||||
|
assertEquals(0L, performVarLong(0L));
|
||||||
|
assertEquals(-1L, performVarLong(-1L));
|
||||||
|
assertEquals(1024L, performVarLong(1024L));
|
||||||
|
assertEquals(-1024L, performVarLong(-1024L));
|
||||||
|
assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
|
||||||
|
assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
|
||||||
|
assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
|
||||||
|
assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
|
||||||
|
assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
|
||||||
|
assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIndexBeforeAfter() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
final long FIRST_START = TEST_START;
|
||||||
|
final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
|
||||||
|
final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
|
||||||
|
final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
|
||||||
|
final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
|
||||||
|
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
|
||||||
|
|
||||||
|
stats.recordData(FIRST_START, FIRST_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
stats.recordData(SECOND_START, SECOND_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
stats.recordData(THIRD_START, THIRD_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
|
||||||
|
// should have buckets: 2+1+2
|
||||||
|
assertEquals(5, stats.size());
|
||||||
|
|
||||||
|
assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
|
||||||
|
assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
|
||||||
|
assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
|
||||||
|
assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
|
||||||
|
assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
|
||||||
|
assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
|
||||||
|
assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
|
||||||
|
assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntersects() throws Exception {
|
||||||
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
|
final long FIRST_START = TEST_START;
|
||||||
|
final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
|
||||||
|
final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
|
||||||
|
final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
|
||||||
|
final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
|
||||||
|
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
|
||||||
|
|
||||||
|
stats.recordData(FIRST_START, FIRST_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
stats.recordData(SECOND_START, SECOND_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
stats.recordData(THIRD_START, THIRD_END,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
|
||||||
|
assertFalse(stats.intersects(10, 20));
|
||||||
|
assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
|
||||||
|
assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
|
||||||
|
|
||||||
|
assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
|
||||||
|
assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
|
||||||
|
assertTrue(stats.intersects(TEST_START, TEST_START));
|
||||||
|
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
|
||||||
|
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
|
||||||
|
assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
|
||||||
|
|
||||||
|
assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
|
||||||
|
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
|
||||||
|
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetValues() throws Exception {
|
||||||
|
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
|
||||||
|
stats.recordData(TEST_START, TEST_START + 1,
|
||||||
|
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||||
|
|
||||||
|
assertEquals(1024L + 2048L, stats.getTotalBytes());
|
||||||
|
|
||||||
|
final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
|
||||||
|
entry.rxBytes /= 2;
|
||||||
|
entry.txBytes *= 2;
|
||||||
|
stats.setValues(0, entry);
|
||||||
|
|
||||||
|
assertEquals(512L + 4096L, stats.getTotalBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertIndexBeforeAfter(
|
||||||
|
NetworkStatsHistory stats, int before, int after, long time) {
|
||||||
|
assertEquals("unexpected before", before, stats.getIndexBefore(time));
|
||||||
|
assertEquals("unexpected after", after, stats.getIndexAfter(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long performVarLong(long before) throws Exception {
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
writeVarLong(new DataOutputStream(out), before);
|
||||||
|
|
||||||
|
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
return readVarLong(new DataInputStream(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertConsistent(NetworkStatsHistory stats) {
|
||||||
|
// verify timestamps are monotonic
|
||||||
|
long lastStart = Long.MIN_VALUE;
|
||||||
|
NetworkStatsHistory.Entry entry = null;
|
||||||
|
for (int i = 0; i < stats.size(); i++) {
|
||||||
|
entry = stats.getValues(i, entry);
|
||||||
|
assertTrue(lastStart < entry.bucketStart);
|
||||||
|
lastStart = entry.bucketStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertValues(
|
||||||
|
NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
|
||||||
|
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
|
||||||
|
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||||
|
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertValues(
|
||||||
|
NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
|
||||||
|
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
|
||||||
|
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||||
|
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
|
||||||
|
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
|
||||||
|
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
|
||||||
|
assertEquals("unexpected activeTime", activeTime, entry.activeTime);
|
||||||
|
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||||
|
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
|
||||||
|
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||||
|
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
|
||||||
|
assertEquals("unexpected operations", operations, entry.operations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
|
||||||
|
long rxPackets, long txBytes, long txPackets, long operations) {
|
||||||
|
assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
|
||||||
|
txPackets, operations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertValues(NetworkStatsHistory stats, long start, long end,
|
||||||
|
long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
|
||||||
|
long operations) {
|
||||||
|
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
|
||||||
|
assertEquals("unexpected activeTime", activeTime, entry.activeTime);
|
||||||
|
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||||
|
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
|
||||||
|
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||||
|
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
|
||||||
|
assertEquals("unexpected operations", operations, entry.operations);
|
||||||
|
}
|
||||||
|
}
|
||||||
1024
tests/unit/java/android/net/NetworkStatsTest.java
Normal file
1024
tests/unit/java/android/net/NetworkStatsTest.java
Normal file
File diff suppressed because it is too large
Load Diff
351
tests/unit/java/android/net/NetworkTemplateTest.kt
Normal file
351
tests/unit/java/android/net/NetworkTemplateTest.kt
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIFI
|
||||||
|
import android.net.NetworkIdentity.SUBTYPE_COMBINED
|
||||||
|
import android.net.NetworkIdentity.OEM_NONE
|
||||||
|
import android.net.NetworkIdentity.OEM_PAID
|
||||||
|
import android.net.NetworkIdentity.OEM_PRIVATE
|
||||||
|
import android.net.NetworkIdentity.buildNetworkIdentity
|
||||||
|
import android.net.NetworkStats.DEFAULT_NETWORK_ALL
|
||||||
|
import android.net.NetworkStats.METERED_ALL
|
||||||
|
import android.net.NetworkStats.ROAMING_ALL
|
||||||
|
import android.net.NetworkTemplate.MATCH_MOBILE
|
||||||
|
import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
|
||||||
|
import android.net.NetworkTemplate.MATCH_WIFI
|
||||||
|
import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
|
||||||
|
import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
|
||||||
|
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
|
||||||
|
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
|
||||||
|
import android.net.NetworkTemplate.OEM_MANAGED_ALL
|
||||||
|
import android.net.NetworkTemplate.OEM_MANAGED_NO
|
||||||
|
import android.net.NetworkTemplate.OEM_MANAGED_YES
|
||||||
|
import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
|
||||||
|
import android.net.NetworkTemplate.buildTemplateWifi
|
||||||
|
import android.net.NetworkTemplate.buildTemplateWifiWildcard
|
||||||
|
import android.net.NetworkTemplate.buildTemplateCarrier
|
||||||
|
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import com.android.testutils.assertParcelSane
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
private const val TEST_IMSI1 = "imsi1"
|
||||||
|
private const val TEST_IMSI2 = "imsi2"
|
||||||
|
private const val TEST_SSID1 = "ssid1"
|
||||||
|
private const val TEST_SSID2 = "ssid2"
|
||||||
|
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class NetworkTemplateTest {
|
||||||
|
private val mockContext = mock(Context::class.java)
|
||||||
|
|
||||||
|
private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
|
||||||
|
buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
|
||||||
|
private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot =
|
||||||
|
buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid)
|
||||||
|
|
||||||
|
private fun buildNetworkState(
|
||||||
|
type: Int,
|
||||||
|
subscriberId: String? = null,
|
||||||
|
ssid: String? = null,
|
||||||
|
oemManaged: Int = OEM_NONE
|
||||||
|
): NetworkStateSnapshot {
|
||||||
|
val lp = LinkProperties()
|
||||||
|
val caps = NetworkCapabilities().apply {
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
|
||||||
|
setSSID(ssid)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
|
||||||
|
(oemManaged and OEM_PAID) == OEM_PAID)
|
||||||
|
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
|
||||||
|
(oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
|
||||||
|
}
|
||||||
|
return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
|
||||||
|
assertTrue(matches(ident), "$this does not match $ident")
|
||||||
|
|
||||||
|
private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
|
||||||
|
assertFalse(matches(ident), "$this should match $ident")
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWifiWildcardMatches() {
|
||||||
|
val templateWifiWildcard = buildTemplateWifiWildcard()
|
||||||
|
|
||||||
|
val identMobileImsi1 = buildNetworkIdentity(mockContext,
|
||||||
|
buildMobileNetworkState(TEST_IMSI1),
|
||||||
|
false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identWifiImsiNullSsid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
|
||||||
|
val identWifiImsi1Ssid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
|
||||||
|
|
||||||
|
templateWifiWildcard.assertDoesNotMatch(identMobileImsi1)
|
||||||
|
templateWifiWildcard.assertMatches(identWifiImsiNullSsid1)
|
||||||
|
templateWifiWildcard.assertMatches(identWifiImsi1Ssid1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWifiMatches() {
|
||||||
|
val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1)
|
||||||
|
val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null)
|
||||||
|
val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1)
|
||||||
|
val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1)
|
||||||
|
|
||||||
|
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
|
||||||
|
false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identWifiImsiNullSsid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
|
||||||
|
val identWifiImsi1Ssid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
|
||||||
|
val identWifiImsi2Ssid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
|
||||||
|
val identWifiImsi1Ssid2 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0)
|
||||||
|
|
||||||
|
// Verify that template with SSID only matches any subscriberId and specific SSID.
|
||||||
|
templateWifiSsid1.assertDoesNotMatch(identMobile1)
|
||||||
|
templateWifiSsid1.assertMatches(identWifiImsiNullSsid1)
|
||||||
|
templateWifiSsid1.assertMatches(identWifiImsi1Ssid1)
|
||||||
|
templateWifiSsid1.assertMatches(identWifiImsi2Ssid1)
|
||||||
|
templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2)
|
||||||
|
|
||||||
|
// Verify that template with SSID1 and null imsi matches any network with
|
||||||
|
// SSID1 and null imsi.
|
||||||
|
templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1)
|
||||||
|
templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1)
|
||||||
|
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1)
|
||||||
|
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1)
|
||||||
|
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2)
|
||||||
|
|
||||||
|
// Verify that template with SSID1 and imsi1 matches any network with
|
||||||
|
// SSID1 and imsi1.
|
||||||
|
templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1)
|
||||||
|
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
|
||||||
|
templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1)
|
||||||
|
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
|
||||||
|
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2)
|
||||||
|
|
||||||
|
// Verify that template with SSID all and imsi1 matches any network with
|
||||||
|
// any SSID and imsi1.
|
||||||
|
templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1)
|
||||||
|
templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
|
||||||
|
templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1)
|
||||||
|
templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
|
||||||
|
templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCarrierMatches() {
|
||||||
|
val templateCarrierImsi1 = buildTemplateCarrier(TEST_IMSI1)
|
||||||
|
|
||||||
|
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
|
||||||
|
false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identMobile2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
|
||||||
|
false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identWifiSsid1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
|
||||||
|
val identCarrierWifiImsi1 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
|
||||||
|
val identCarrierWifiImsi2 = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
|
||||||
|
|
||||||
|
templateCarrierImsi1.assertMatches(identCarrierWifiImsi1)
|
||||||
|
templateCarrierImsi1.assertDoesNotMatch(identCarrierWifiImsi2)
|
||||||
|
templateCarrierImsi1.assertDoesNotMatch(identWifiSsid1)
|
||||||
|
templateCarrierImsi1.assertMatches(identMobile1)
|
||||||
|
templateCarrierImsi1.assertDoesNotMatch(identMobile2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRatTypeGroupMatches() {
|
||||||
|
val stateMobile = buildMobileNetworkState(TEST_IMSI1)
|
||||||
|
// Build UMTS template that matches mobile identities with RAT in the same
|
||||||
|
// group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
|
||||||
|
val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
// Build normal template that matches mobile identities with any RAT and IMSI.
|
||||||
|
val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
|
||||||
|
// Build template with UNKNOWN RAT that matches mobile identities with RAT that
|
||||||
|
// cannot be determined.
|
||||||
|
val templateUnknown =
|
||||||
|
buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
|
||||||
|
|
||||||
|
val identUmts = buildNetworkIdentity(
|
||||||
|
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identHsdpa = buildNetworkIdentity(
|
||||||
|
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
|
||||||
|
val identLte = buildNetworkIdentity(
|
||||||
|
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
|
||||||
|
val identCombined = buildNetworkIdentity(
|
||||||
|
mockContext, stateMobile, false, SUBTYPE_COMBINED)
|
||||||
|
val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
|
||||||
|
false, TelephonyManager.NETWORK_TYPE_UMTS)
|
||||||
|
val identWifi = buildNetworkIdentity(
|
||||||
|
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
|
||||||
|
|
||||||
|
// Assert that identity with the same RAT matches.
|
||||||
|
templateUmts.assertMatches(identUmts)
|
||||||
|
templateAll.assertMatches(identUmts)
|
||||||
|
templateUnknown.assertDoesNotMatch(identUmts)
|
||||||
|
// Assert that identity with the RAT within the same group matches.
|
||||||
|
templateUmts.assertMatches(identHsdpa)
|
||||||
|
templateAll.assertMatches(identHsdpa)
|
||||||
|
templateUnknown.assertDoesNotMatch(identHsdpa)
|
||||||
|
// Assert that identity with the RAT out of the same group only matches template with
|
||||||
|
// NETWORK_TYPE_ALL.
|
||||||
|
templateUmts.assertDoesNotMatch(identLte)
|
||||||
|
templateAll.assertMatches(identLte)
|
||||||
|
templateUnknown.assertDoesNotMatch(identLte)
|
||||||
|
// Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
|
||||||
|
// and NETWORK_TYPE_UNKNOWN.
|
||||||
|
templateUmts.assertDoesNotMatch(identCombined)
|
||||||
|
templateAll.assertMatches(identCombined)
|
||||||
|
templateUnknown.assertMatches(identCombined)
|
||||||
|
// Assert that identity with different IMSI matches.
|
||||||
|
templateUmts.assertMatches(identImsi2)
|
||||||
|
templateAll.assertMatches(identImsi2)
|
||||||
|
templateUnknown.assertDoesNotMatch(identImsi2)
|
||||||
|
// Assert that wifi identity does not match.
|
||||||
|
templateUmts.assertDoesNotMatch(identWifi)
|
||||||
|
templateAll.assertDoesNotMatch(identWifi)
|
||||||
|
templateUnknown.assertDoesNotMatch(identWifi)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testParcelUnparcel() {
|
||||||
|
val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
|
||||||
|
ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
|
||||||
|
OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
|
||||||
|
ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL,
|
||||||
|
SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
|
||||||
|
ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES,
|
||||||
|
SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
assertParcelSane(templateMobile, 10)
|
||||||
|
assertParcelSane(templateWifi, 10)
|
||||||
|
assertParcelSane(templateOem, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
|
||||||
|
// TelephonyManager#NETWORK_TYPE_* constants.
|
||||||
|
@Test
|
||||||
|
fun testNetworkTypeConstants() {
|
||||||
|
for (ratType in TelephonyManager.getAllNetworkTypes()) {
|
||||||
|
assertNotEquals(NETWORK_TYPE_ALL, ratType)
|
||||||
|
assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOemNetworkConstants() {
|
||||||
|
val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
|
||||||
|
OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
|
||||||
|
|
||||||
|
// Verify that "not OEM managed network" constants are equal.
|
||||||
|
assertEquals(OEM_MANAGED_NO, OEM_NONE)
|
||||||
|
|
||||||
|
// Verify the constants don't conflict.
|
||||||
|
assertEquals(constantValues.size, constantValues.distinct().count())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
|
||||||
|
* their the appropriate OEM managed {@code NetworkIdentity}s.
|
||||||
|
*
|
||||||
|
* @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
|
||||||
|
* @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
|
||||||
|
* networkType.
|
||||||
|
* @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
|
||||||
|
* {@code TYPE_MOBILE}. May be left as null when matchType is
|
||||||
|
* {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
|
||||||
|
* @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
|
||||||
|
* {@code TYPE_WIFI}. May be left as null when matchType is
|
||||||
|
* {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
|
||||||
|
* @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
|
||||||
|
* one of {@code TEST_SSID*}.
|
||||||
|
*/
|
||||||
|
private fun matchOemManagedIdent(
|
||||||
|
networkType: Int,
|
||||||
|
matchType: Int,
|
||||||
|
subscriberId: String? = null,
|
||||||
|
templateSsid: String? = null,
|
||||||
|
identSsid: String? = null
|
||||||
|
) {
|
||||||
|
val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
|
||||||
|
val matchSubscriberIds = arrayOf(subscriberId)
|
||||||
|
|
||||||
|
val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
|
||||||
|
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
|
||||||
|
OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
|
||||||
|
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
|
||||||
|
OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
|
||||||
|
for (identityOemManagedState in oemManagedStates) {
|
||||||
|
val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
|
||||||
|
subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
|
||||||
|
/*subType=*/0)
|
||||||
|
|
||||||
|
// Create a template with each OEM managed type and match it against the NetworkIdentity
|
||||||
|
for (templateOemManagedState in oemManagedStates) {
|
||||||
|
val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
|
||||||
|
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
|
||||||
|
NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT)
|
||||||
|
if (identityOemManagedState == templateOemManagedState) {
|
||||||
|
template.assertMatches(ident)
|
||||||
|
} else {
|
||||||
|
template.assertDoesNotMatch(ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// OEM_MANAGED_ALL ignores OEM state.
|
||||||
|
templateOemAll.assertMatches(ident)
|
||||||
|
if (identityOemManagedState == OEM_NONE) {
|
||||||
|
// OEM_MANAGED_YES matches everything except OEM_NONE.
|
||||||
|
templateOemYes.assertDoesNotMatch(ident)
|
||||||
|
} else {
|
||||||
|
templateOemYes.assertMatches(ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOemManagedMatchesIdent() {
|
||||||
|
matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
|
||||||
|
matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
|
||||||
|
matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
|
||||||
|
identSsid = TEST_SSID1)
|
||||||
|
matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
|
||||||
|
}
|
||||||
|
}
|
||||||
128
tests/unit/java/android/net/NetworkUtilsTest.java
Normal file
128
tests/unit/java/android/net/NetworkUtilsTest.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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 android.net;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@androidx.test.filters.SmallTest
|
||||||
|
public class NetworkUtilsTest {
|
||||||
|
@Test
|
||||||
|
public void testRoutedIPv4AddressCount() {
|
||||||
|
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
|
||||||
|
// No routes routes to no addresses.
|
||||||
|
assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("0.0.0.0/0"));
|
||||||
|
assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("20.18.0.0/16"));
|
||||||
|
set.add(new IpPrefix("20.18.0.0/24"));
|
||||||
|
set.add(new IpPrefix("20.18.0.0/8"));
|
||||||
|
// There is a default route, still covers everything
|
||||||
|
assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.clear();
|
||||||
|
set.add(new IpPrefix("20.18.0.0/24"));
|
||||||
|
set.add(new IpPrefix("20.18.0.0/8"));
|
||||||
|
// The 8-length includes the 24-length prefix
|
||||||
|
assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("10.10.10.126/25"));
|
||||||
|
// The 8-length does not include this 25-length prefix
|
||||||
|
assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.clear();
|
||||||
|
set.add(new IpPrefix("1.2.3.4/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.4/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.4/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.4/32"));
|
||||||
|
assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("1.2.3.5/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.6/32"));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("1.2.3.7/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.8/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.9/32"));
|
||||||
|
set.add(new IpPrefix("1.2.3.0/32"));
|
||||||
|
assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
|
||||||
|
// 1.2.3.4/30 eats 1.2.3.{4-7}/32
|
||||||
|
set.add(new IpPrefix("1.2.3.4/30"));
|
||||||
|
set.add(new IpPrefix("6.2.3.4/28"));
|
||||||
|
set.add(new IpPrefix("120.2.3.4/16"));
|
||||||
|
assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRoutedIPv6AddressCount() {
|
||||||
|
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
|
||||||
|
// No routes routes to no addresses.
|
||||||
|
assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("::/0"));
|
||||||
|
assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("1234:622a::18/64"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
|
||||||
|
// There is a default route, still covers everything
|
||||||
|
assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.clear();
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
|
||||||
|
// The 8-length includes the 96-length prefix
|
||||||
|
assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("10::26/64"));
|
||||||
|
// The 8-length does not include this 64-length prefix
|
||||||
|
assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
|
||||||
|
NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.clear();
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
|
||||||
|
assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
|
||||||
|
assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
|
||||||
|
// add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
|
||||||
|
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
|
||||||
|
set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
|
||||||
|
set.add(new IpPrefix("f00b:a33::/112"));
|
||||||
|
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
|
||||||
|
NetworkUtils.routedIPv6AddressCount(set));
|
||||||
|
}
|
||||||
|
}
|
||||||
75
tests/unit/java/android/net/QosSocketFilterTest.java
Normal file
75
tests/unit/java/android/net/QosSocketFilterTest.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 android.net;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@androidx.test.filters.SmallTest
|
||||||
|
public class QosSocketFilterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPortExactMatch() {
|
||||||
|
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
assertTrue(QosSocketFilter.matchesLocalAddress(
|
||||||
|
new InetSocketAddress(addressA, 10), addressB, 10, 10));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPortLessThanStart() {
|
||||||
|
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
assertFalse(QosSocketFilter.matchesLocalAddress(
|
||||||
|
new InetSocketAddress(addressA, 8), addressB, 10, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPortGreaterThanEnd() {
|
||||||
|
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
assertFalse(QosSocketFilter.matchesLocalAddress(
|
||||||
|
new InetSocketAddress(addressA, 18), addressB, 10, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPortBetweenStartAndEnd() {
|
||||||
|
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
assertTrue(QosSocketFilter.matchesLocalAddress(
|
||||||
|
new InetSocketAddress(addressA, 10), addressB, 8, 18));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressesDontMatch() {
|
||||||
|
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
|
||||||
|
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
|
||||||
|
assertFalse(QosSocketFilter.matchesLocalAddress(
|
||||||
|
new InetSocketAddress(addressA, 10), addressB, 10, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
113
tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
Normal file
113
tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 android.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.net.wifi.WifiNetworkSpecifier;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for {@link android.net.TelephonyNetworkSpecifier}.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
public class TelephonyNetworkSpecifierTest {
|
||||||
|
private static final int TEST_SUBID = 5;
|
||||||
|
private static final String TEST_SSID = "Test123";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
|
||||||
|
* without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBuilderBuildWithDefault() {
|
||||||
|
try {
|
||||||
|
new TelephonyNetworkSpecifier.Builder().build();
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
// expected, test pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that no exception will be thrown even if pass invalid subscription id to
|
||||||
|
* {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBuilderBuildWithInvalidSubId() {
|
||||||
|
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
|
||||||
|
.setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
||||||
|
.build();
|
||||||
|
assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBuilderBuildWithValidSubId() {
|
||||||
|
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
|
||||||
|
.setSubscriptionId(TEST_SUBID)
|
||||||
|
.build();
|
||||||
|
assertEquals(TEST_SUBID, specifier.getSubscriptionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that parcel marshalling/unmarshalling works.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParcel() {
|
||||||
|
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
|
||||||
|
.setSubscriptionId(TEST_SUBID)
|
||||||
|
.build();
|
||||||
|
assertParcelSane(specifier, 1 /* fieldCount */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the behavior of method canBeSatisfiedBy().
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCanBeSatisfiedBy() {
|
||||||
|
final TelephonyNetworkSpecifier tns1 = new TelephonyNetworkSpecifier.Builder()
|
||||||
|
.setSubscriptionId(TEST_SUBID)
|
||||||
|
.build();
|
||||||
|
final TelephonyNetworkSpecifier tns2 = new TelephonyNetworkSpecifier.Builder()
|
||||||
|
.setSubscriptionId(TEST_SUBID)
|
||||||
|
.build();
|
||||||
|
final WifiNetworkSpecifier wns = new WifiNetworkSpecifier.Builder()
|
||||||
|
.setSsid(TEST_SSID)
|
||||||
|
.build();
|
||||||
|
final MatchAllNetworkSpecifier mans = new MatchAllNetworkSpecifier();
|
||||||
|
|
||||||
|
// Test equality
|
||||||
|
assertEquals(tns1, tns2);
|
||||||
|
assertTrue(tns1.canBeSatisfiedBy(tns1));
|
||||||
|
assertTrue(tns1.canBeSatisfiedBy(tns2));
|
||||||
|
|
||||||
|
// Test other edge cases.
|
||||||
|
assertFalse(tns1.canBeSatisfiedBy(null));
|
||||||
|
assertFalse(tns1.canBeSatisfiedBy(wns));
|
||||||
|
assertTrue(tns1.canBeSatisfiedBy(mans));
|
||||||
|
}
|
||||||
|
}
|
||||||
138
tests/unit/java/android/net/VpnManagerTest.java
Normal file
138
tests/unit/java/android/net/VpnManagerTest.java
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.test.mock.MockContext;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.net.VpnProfile;
|
||||||
|
import com.android.internal.util.MessageUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/** Unit tests for {@link VpnManager}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class VpnManagerTest {
|
||||||
|
private static final String PKG_NAME = "fooPackage";
|
||||||
|
|
||||||
|
private static final String SESSION_NAME_STRING = "testSession";
|
||||||
|
private static final String SERVER_ADDR_STRING = "1.2.3.4";
|
||||||
|
private static final String IDENTITY_STRING = "Identity";
|
||||||
|
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
|
||||||
|
|
||||||
|
private IVpnManager mMockService;
|
||||||
|
private VpnManager mVpnManager;
|
||||||
|
private final MockContext mMockContext =
|
||||||
|
new MockContext() {
|
||||||
|
@Override
|
||||||
|
public String getOpPackageName() {
|
||||||
|
return PKG_NAME;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mMockService = mock(IVpnManager.class);
|
||||||
|
mVpnManager = new VpnManager(mMockContext, mMockService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProvisionVpnProfilePreconsented() throws Exception {
|
||||||
|
final PlatformVpnProfile profile = getPlatformVpnProfile();
|
||||||
|
when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
|
// Expect there to be no intent returned, as consent has already been granted.
|
||||||
|
assertNull(mVpnManager.provisionVpnProfile(profile));
|
||||||
|
verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProvisionVpnProfileNeedsConsent() throws Exception {
|
||||||
|
final PlatformVpnProfile profile = getPlatformVpnProfile();
|
||||||
|
when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
|
// Expect intent to be returned, as consent has not already been granted.
|
||||||
|
final Intent intent = mVpnManager.provisionVpnProfile(profile);
|
||||||
|
assertNotNull(intent);
|
||||||
|
|
||||||
|
final ComponentName expectedComponentName =
|
||||||
|
ComponentName.unflattenFromString(
|
||||||
|
"com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
|
||||||
|
assertEquals(expectedComponentName, intent.getComponent());
|
||||||
|
verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteProvisionedVpnProfile() throws Exception {
|
||||||
|
mVpnManager.deleteProvisionedVpnProfile();
|
||||||
|
verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartProvisionedVpnProfile() throws Exception {
|
||||||
|
mVpnManager.startProvisionedVpnProfile();
|
||||||
|
verify(mMockService).startVpnProfile(eq(PKG_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopProvisionedVpnProfile() throws Exception {
|
||||||
|
mVpnManager.stopProvisionedVpnProfile();
|
||||||
|
verify(mMockService).stopVpnProfile(eq(PKG_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
|
||||||
|
return new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING)
|
||||||
|
.setBypassable(true)
|
||||||
|
.setMaxMtu(1300)
|
||||||
|
.setMetered(true)
|
||||||
|
.setAuthPsk(PSK_BYTES)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVpnTypesEqual() throws Exception {
|
||||||
|
SparseArray<String> vmVpnTypes = MessageUtils.findMessageNames(
|
||||||
|
new Class[] { VpnManager.class }, new String[]{ "TYPE_VPN_" });
|
||||||
|
SparseArray<String> nativeVpnType = MessageUtils.findMessageNames(
|
||||||
|
new Class[] { NativeVpnType.class }, new String[]{ "" });
|
||||||
|
|
||||||
|
// TYPE_VPN_NONE = -1 is only defined in VpnManager.
|
||||||
|
assertEquals(vmVpnTypes.size() - 1, nativeVpnType.size());
|
||||||
|
for (int i = VpnManager.TYPE_VPN_SERVICE; i < vmVpnTypes.size(); i++) {
|
||||||
|
assertEquals(vmVpnTypes.get(i), "TYPE_VPN_" + nativeVpnType.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
tests/unit/java/android/net/VpnTransportInfoTest.java
Normal file
68
tests/unit/java/android/net/VpnTransportInfoTest.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
|
||||||
|
import static android.net.NetworkCapabilities.REDACT_NONE;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class VpnTransportInfoTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParceling() {
|
||||||
|
VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
|
||||||
|
assertParcelSane(v, 2 /* fieldCount */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualsAndHashCode() {
|
||||||
|
String session1 = "12345";
|
||||||
|
String session2 = "6789";
|
||||||
|
VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
|
||||||
|
VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
|
||||||
|
VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
|
||||||
|
VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
|
||||||
|
VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
|
||||||
|
VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
|
||||||
|
|
||||||
|
VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
|
||||||
|
VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
|
||||||
|
|
||||||
|
assertNotEquals(v11, v12);
|
||||||
|
assertNotEquals(v13, v14);
|
||||||
|
assertNotEquals(v14, v15);
|
||||||
|
assertNotEquals(v14, v21);
|
||||||
|
|
||||||
|
assertEquals(v11, v13);
|
||||||
|
assertEquals(v31, v32);
|
||||||
|
assertEquals(v11.hashCode(), v13.hashCode());
|
||||||
|
assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
|
||||||
|
assertEquals(session1, v15.makeCopy(REDACT_NONE).getSessionId());
|
||||||
|
}
|
||||||
|
}
|
||||||
142
tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
Normal file
142
tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 android.net.ipmemorystore;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
|
||||||
|
import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirkParcelable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class ParcelableTests {
|
||||||
|
@Test
|
||||||
|
public void testNetworkAttributesParceling() throws Exception {
|
||||||
|
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
|
||||||
|
NetworkAttributes in = builder.build();
|
||||||
|
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
|
||||||
|
|
||||||
|
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
||||||
|
// lease will expire in two hours
|
||||||
|
builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
|
||||||
|
// cluster stays null this time around
|
||||||
|
builder.setDnsAddresses(Collections.emptyList());
|
||||||
|
builder.setMtu(18);
|
||||||
|
in = builder.build();
|
||||||
|
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
|
||||||
|
|
||||||
|
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
|
||||||
|
builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
|
||||||
|
builder.setCluster("groupHint");
|
||||||
|
builder.setDnsAddresses(Arrays.asList(
|
||||||
|
InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
|
||||||
|
InetAddress.getByName("6.7.8.9")));
|
||||||
|
builder.setMtu(1_000_000);
|
||||||
|
in = builder.build();
|
||||||
|
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
|
||||||
|
|
||||||
|
builder.setMtu(null);
|
||||||
|
in = builder.build();
|
||||||
|
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
|
||||||
|
|
||||||
|
// Verify that this test does not miss any new field added later.
|
||||||
|
// If any field is added to NetworkAttributes it must be tested here for parceling
|
||||||
|
// roundtrip.
|
||||||
|
assertEquals(6, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
|
||||||
|
.filter(f -> !Modifier.isStatic(f.getModifiers())).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrivateDataParceling() throws Exception {
|
||||||
|
final Blob in = new Blob();
|
||||||
|
in.data = new byte[] {89, 111, 108, 111};
|
||||||
|
final Blob out = parcelingRoundTrip(in);
|
||||||
|
// Object.equals on byte[] tests the references
|
||||||
|
assertEquals(in.data.length, out.data.length);
|
||||||
|
assertTrue(Arrays.equals(in.data, out.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSameL3NetworkResponseParceling() throws Exception {
|
||||||
|
final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
|
||||||
|
parcelable.l2Key1 = "key 1";
|
||||||
|
parcelable.l2Key2 = "key 2";
|
||||||
|
parcelable.confidence = 0.43f;
|
||||||
|
|
||||||
|
final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
|
||||||
|
assertEquals("key 1", in.l2Key1);
|
||||||
|
assertEquals("key 2", in.l2Key2);
|
||||||
|
assertEquals(0.43f, in.confidence, 0.01f /* delta */);
|
||||||
|
|
||||||
|
final SameL3NetworkResponse out =
|
||||||
|
new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
|
||||||
|
|
||||||
|
assertEquals(in, out);
|
||||||
|
assertEquals(in.l2Key1, out.l2Key1);
|
||||||
|
assertEquals(in.l2Key2, out.l2Key2);
|
||||||
|
assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIPv6ProvisioningLossQuirkParceling() throws Exception {
|
||||||
|
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
|
||||||
|
final IPv6ProvisioningLossQuirkParcelable parcelable =
|
||||||
|
new IPv6ProvisioningLossQuirkParcelable();
|
||||||
|
final long expiry = System.currentTimeMillis() + 7_200_000;
|
||||||
|
|
||||||
|
parcelable.detectionCount = 3;
|
||||||
|
parcelable.quirkExpiry = expiry; // quirk info will expire in two hours
|
||||||
|
builder.setIpv6ProvLossQuirk(IPv6ProvisioningLossQuirk.fromStableParcelable(parcelable));
|
||||||
|
final NetworkAttributes in = builder.build();
|
||||||
|
|
||||||
|
final NetworkAttributes out = new NetworkAttributes(parcelingRoundTrip(in.toParcelable()));
|
||||||
|
assertEquals(out.ipv6ProvisioningLossQuirk, in.ipv6ProvisioningLossQuirk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
|
||||||
|
final Parcel p = Parcel.obtain();
|
||||||
|
in.writeToParcel(p, /* flags */ 0);
|
||||||
|
p.setDataPosition(0);
|
||||||
|
final byte[] marshalledData = p.marshall();
|
||||||
|
p.recycle();
|
||||||
|
|
||||||
|
final Parcel q = Parcel.obtain();
|
||||||
|
q.unmarshall(marshalledData, 0, marshalledData.length);
|
||||||
|
q.setDataPosition(0);
|
||||||
|
|
||||||
|
final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
|
||||||
|
in.getClass().getField("CREATOR").get(null); // static object, so null receiver
|
||||||
|
final T unmarshalled = (T) creator.createFromParcel(q);
|
||||||
|
q.recycle();
|
||||||
|
return unmarshalled;
|
||||||
|
}
|
||||||
|
}
|
||||||
388
tests/unit/java/android/net/nsd/NsdManagerTest.java
Normal file
388
tests/unit/java/android/net/nsd/NsdManagerTest.java
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.net.nsd;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.util.AsyncChannel;
|
||||||
|
import com.android.testutils.HandlerUtils;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NsdManagerTest {
|
||||||
|
|
||||||
|
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
|
||||||
|
|
||||||
|
@Mock Context mContext;
|
||||||
|
@Mock INsdManager mService;
|
||||||
|
MockServiceHandler mServiceHandler;
|
||||||
|
|
||||||
|
NsdManager mManager;
|
||||||
|
|
||||||
|
long mTimeoutMs = 200; // non-final so that tests can adjust the value.
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mServiceHandler = spy(MockServiceHandler.create(mContext));
|
||||||
|
when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
|
||||||
|
|
||||||
|
mManager = makeManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
|
||||||
|
mServiceHandler.chan.disconnect();
|
||||||
|
mServiceHandler.stop();
|
||||||
|
if (mManager != null) {
|
||||||
|
mManager.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResolveService() {
|
||||||
|
NsdManager manager = mManager;
|
||||||
|
|
||||||
|
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
|
||||||
|
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
|
||||||
|
NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
|
||||||
|
|
||||||
|
manager.resolveService(request, listener);
|
||||||
|
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||||
|
int err = 33;
|
||||||
|
sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
|
||||||
|
|
||||||
|
manager.resolveService(request, listener);
|
||||||
|
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||||
|
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParallelResolveService() {
|
||||||
|
NsdManager manager = mManager;
|
||||||
|
|
||||||
|
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
|
||||||
|
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
|
||||||
|
|
||||||
|
NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
|
||||||
|
NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
|
||||||
|
|
||||||
|
manager.resolveService(request, listener1);
|
||||||
|
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||||
|
|
||||||
|
manager.resolveService(request, listener2);
|
||||||
|
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
|
||||||
|
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
|
||||||
|
|
||||||
|
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||||
|
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterService() {
|
||||||
|
NsdManager manager = mManager;
|
||||||
|
|
||||||
|
NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
|
||||||
|
NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
|
||||||
|
request1.setPort(2201);
|
||||||
|
request2.setPort(2202);
|
||||||
|
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
|
||||||
|
NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
|
||||||
|
|
||||||
|
// Register two services
|
||||||
|
manager.registerService(request1, PROTOCOL, listener1);
|
||||||
|
int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||||
|
|
||||||
|
manager.registerService(request2, PROTOCOL, listener2);
|
||||||
|
int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||||
|
|
||||||
|
// First reques fails, second request succeeds
|
||||||
|
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
|
||||||
|
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
|
||||||
|
|
||||||
|
int err = 1;
|
||||||
|
sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
|
||||||
|
verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
|
||||||
|
|
||||||
|
// Client retries first request, it succeeds
|
||||||
|
manager.registerService(request1, PROTOCOL, listener1);
|
||||||
|
int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
|
||||||
|
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
|
||||||
|
|
||||||
|
// First request is unregistered, it succeeds
|
||||||
|
manager.unregisterService(listener1);
|
||||||
|
int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
|
||||||
|
assertEquals(key3, key3again);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
|
||||||
|
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
|
||||||
|
|
||||||
|
// Second request is unregistered, it fails
|
||||||
|
manager.unregisterService(listener2);
|
||||||
|
int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
|
||||||
|
assertEquals(key2, key2again);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
|
||||||
|
verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
|
||||||
|
|
||||||
|
// TODO: do not unregister listener until service is unregistered
|
||||||
|
// Client retries unregistration of second request, it succeeds
|
||||||
|
//manager.unregisterService(listener2);
|
||||||
|
//int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
|
||||||
|
//assertEquals(key2, key2yetAgain);
|
||||||
|
|
||||||
|
//sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
|
||||||
|
//verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDiscoverService() {
|
||||||
|
NsdManager manager = mManager;
|
||||||
|
|
||||||
|
NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
|
||||||
|
NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
|
||||||
|
NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
|
||||||
|
|
||||||
|
NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
|
||||||
|
|
||||||
|
// Client registers for discovery, request fails
|
||||||
|
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||||
|
int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||||
|
|
||||||
|
int err = 1;
|
||||||
|
sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
|
||||||
|
|
||||||
|
// Client retries, request succeeds
|
||||||
|
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||||
|
int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
|
||||||
|
|
||||||
|
|
||||||
|
// mdns notifies about services
|
||||||
|
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
|
||||||
|
|
||||||
|
|
||||||
|
// Client unregisters its listener
|
||||||
|
manager.stopServiceDiscovery(listener);
|
||||||
|
int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
|
||||||
|
assertEquals(key2, key2again);
|
||||||
|
|
||||||
|
// TODO: unregister listener immediately and stop notifying it about services
|
||||||
|
// Notifications are still passed to the client's listener
|
||||||
|
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
|
||||||
|
|
||||||
|
// Client is notified of complete unregistration
|
||||||
|
sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
|
||||||
|
|
||||||
|
// Notifications are not passed to the client anymore
|
||||||
|
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
|
||||||
|
|
||||||
|
|
||||||
|
// Client registers for service discovery
|
||||||
|
reset(listener);
|
||||||
|
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||||
|
int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||||
|
|
||||||
|
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
|
||||||
|
|
||||||
|
// Client unregisters immediately, it fails
|
||||||
|
manager.stopServiceDiscovery(listener);
|
||||||
|
int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
|
||||||
|
assertEquals(key3, key3again);
|
||||||
|
|
||||||
|
err = 2;
|
||||||
|
sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
|
||||||
|
|
||||||
|
// New notifications are not passed to the client anymore
|
||||||
|
sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
|
||||||
|
verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidCalls() {
|
||||||
|
NsdManager manager = mManager;
|
||||||
|
|
||||||
|
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
|
||||||
|
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
|
||||||
|
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
|
||||||
|
|
||||||
|
NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
|
||||||
|
NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
|
||||||
|
validService.setPort(2222);
|
||||||
|
|
||||||
|
// Service registration
|
||||||
|
// - invalid arguments
|
||||||
|
mustFail(() -> { manager.unregisterService(null); });
|
||||||
|
mustFail(() -> { manager.registerService(null, -1, null); });
|
||||||
|
mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
|
||||||
|
mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
|
||||||
|
mustFail(() -> { manager.registerService(validService, -1, listener1); });
|
||||||
|
mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
|
||||||
|
manager.registerService(validService, PROTOCOL, listener1);
|
||||||
|
// - listener already registered
|
||||||
|
mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
|
||||||
|
manager.unregisterService(listener1);
|
||||||
|
// TODO: make listener immediately reusable
|
||||||
|
//mustFail(() -> { manager.unregisterService(listener1); });
|
||||||
|
//manager.registerService(validService, PROTOCOL, listener1);
|
||||||
|
|
||||||
|
// Discover service
|
||||||
|
// - invalid arguments
|
||||||
|
mustFail(() -> { manager.stopServiceDiscovery(null); });
|
||||||
|
mustFail(() -> { manager.discoverServices(null, -1, null); });
|
||||||
|
mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
|
||||||
|
mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
|
||||||
|
mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
|
||||||
|
manager.discoverServices("a_service", PROTOCOL, listener2);
|
||||||
|
// - listener already registered
|
||||||
|
mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
|
||||||
|
manager.stopServiceDiscovery(listener2);
|
||||||
|
// TODO: make listener immediately reusable
|
||||||
|
//mustFail(() -> { manager.stopServiceDiscovery(listener2); });
|
||||||
|
//manager.discoverServices("another_service", PROTOCOL, listener2);
|
||||||
|
|
||||||
|
// Resolver service
|
||||||
|
// - invalid arguments
|
||||||
|
mustFail(() -> { manager.resolveService(null, null); });
|
||||||
|
mustFail(() -> { manager.resolveService(null, listener3); });
|
||||||
|
mustFail(() -> { manager.resolveService(invalidService, listener3); });
|
||||||
|
mustFail(() -> { manager.resolveService(validService, null); });
|
||||||
|
manager.resolveService(validService, listener3);
|
||||||
|
// - listener already registered:w
|
||||||
|
mustFail(() -> { manager.resolveService(validService, listener3); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mustFail(Runnable fn) {
|
||||||
|
try {
|
||||||
|
fn.run();
|
||||||
|
fail();
|
||||||
|
} catch (Exception expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NsdManager makeManager() {
|
||||||
|
NsdManager manager = new NsdManager(mContext, mService);
|
||||||
|
// Acknowledge first two messages connecting the AsyncChannel.
|
||||||
|
verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
|
||||||
|
reset(mServiceHandler);
|
||||||
|
assertNotNull(mServiceHandler.chan);
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verifyRequest(int expectedMessageType) {
|
||||||
|
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
|
||||||
|
verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
|
||||||
|
reset(mServiceHandler);
|
||||||
|
Message received = mServiceHandler.getLastMessage();
|
||||||
|
assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
|
||||||
|
return received.arg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendResponse(int replyType, int arg, int key, Object obj) {
|
||||||
|
mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the server side of AsyncChannel connection protocol
|
||||||
|
public static class MockServiceHandler extends Handler {
|
||||||
|
public final Context context;
|
||||||
|
public AsyncChannel chan;
|
||||||
|
public Message lastMessage;
|
||||||
|
|
||||||
|
MockServiceHandler(Looper l, Context c) {
|
||||||
|
super(l);
|
||||||
|
context = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized Message getLastMessage() {
|
||||||
|
return lastMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setLastMessage(Message msg) {
|
||||||
|
lastMessage = obtainMessage();
|
||||||
|
lastMessage.copyFrom(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
setLastMessage(msg);
|
||||||
|
if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
|
||||||
|
chan = new AsyncChannel();
|
||||||
|
chan.connect(context, this, msg.replyTo);
|
||||||
|
chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
getLooper().quitSafely();
|
||||||
|
}
|
||||||
|
|
||||||
|
static MockServiceHandler create(Context context) {
|
||||||
|
HandlerThread t = new HandlerThread("mock-service-handler");
|
||||||
|
t.start();
|
||||||
|
return new MockServiceHandler(t.getLooper(), context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
188
tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
Normal file
188
tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 android.net.nsd;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NsdServiceInfoTest {
|
||||||
|
|
||||||
|
public final static InetAddress LOCALHOST;
|
||||||
|
static {
|
||||||
|
// Because test.
|
||||||
|
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||||
|
StrictMode.setThreadPolicy(policy);
|
||||||
|
|
||||||
|
InetAddress _host = null;
|
||||||
|
try {
|
||||||
|
_host = InetAddress.getLocalHost();
|
||||||
|
} catch (UnknownHostException e) { }
|
||||||
|
LOCALHOST = _host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLimits() throws Exception {
|
||||||
|
NsdServiceInfo info = new NsdServiceInfo();
|
||||||
|
|
||||||
|
// Non-ASCII keys.
|
||||||
|
boolean exceptionThrown = false;
|
||||||
|
try {
|
||||||
|
info.setAttribute("猫", "meow");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
exceptionThrown = true;
|
||||||
|
}
|
||||||
|
assertTrue(exceptionThrown);
|
||||||
|
assertEmptyServiceInfo(info);
|
||||||
|
|
||||||
|
// ASCII keys with '=' character.
|
||||||
|
exceptionThrown = false;
|
||||||
|
try {
|
||||||
|
info.setAttribute("kitten=", "meow");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
exceptionThrown = true;
|
||||||
|
}
|
||||||
|
assertTrue(exceptionThrown);
|
||||||
|
assertEmptyServiceInfo(info);
|
||||||
|
|
||||||
|
// Single key + value length too long.
|
||||||
|
exceptionThrown = false;
|
||||||
|
try {
|
||||||
|
String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
|
||||||
|
"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
|
||||||
|
"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
|
||||||
|
"ooooooooooooooooooooooooooooong"; // 248 characters.
|
||||||
|
info.setAttribute("longcat", longValue); // Key + value == 255 characters.
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
exceptionThrown = true;
|
||||||
|
}
|
||||||
|
assertTrue(exceptionThrown);
|
||||||
|
assertEmptyServiceInfo(info);
|
||||||
|
|
||||||
|
// Total TXT record length too long.
|
||||||
|
exceptionThrown = false;
|
||||||
|
int recordsAdded = 0;
|
||||||
|
try {
|
||||||
|
for (int i = 100; i < 300; ++i) {
|
||||||
|
// 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
|
||||||
|
String key = String.format("key%d", i);
|
||||||
|
info.setAttribute(key, "12345");
|
||||||
|
recordsAdded++;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
exceptionThrown = true;
|
||||||
|
}
|
||||||
|
assertTrue(exceptionThrown);
|
||||||
|
assertTrue(100 == recordsAdded);
|
||||||
|
assertTrue(info.getTxtRecord().length == 1300);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcel() throws Exception {
|
||||||
|
NsdServiceInfo emptyInfo = new NsdServiceInfo();
|
||||||
|
checkParcelable(emptyInfo);
|
||||||
|
|
||||||
|
NsdServiceInfo fullInfo = new NsdServiceInfo();
|
||||||
|
fullInfo.setServiceName("kitten");
|
||||||
|
fullInfo.setServiceType("_kitten._tcp");
|
||||||
|
fullInfo.setPort(4242);
|
||||||
|
fullInfo.setHost(LOCALHOST);
|
||||||
|
checkParcelable(fullInfo);
|
||||||
|
|
||||||
|
NsdServiceInfo noHostInfo = new NsdServiceInfo();
|
||||||
|
noHostInfo.setServiceName("kitten");
|
||||||
|
noHostInfo.setServiceType("_kitten._tcp");
|
||||||
|
noHostInfo.setPort(4242);
|
||||||
|
checkParcelable(noHostInfo);
|
||||||
|
|
||||||
|
NsdServiceInfo attributedInfo = new NsdServiceInfo();
|
||||||
|
attributedInfo.setServiceName("kitten");
|
||||||
|
attributedInfo.setServiceType("_kitten._tcp");
|
||||||
|
attributedInfo.setPort(4242);
|
||||||
|
attributedInfo.setHost(LOCALHOST);
|
||||||
|
attributedInfo.setAttribute("color", "pink");
|
||||||
|
attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
|
||||||
|
attributedInfo.setAttribute("adorable", (String) null);
|
||||||
|
attributedInfo.setAttribute("sticky", "yes");
|
||||||
|
attributedInfo.setAttribute("siblings", new byte[] {});
|
||||||
|
attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
|
||||||
|
attributedInfo.removeAttribute("sticky");
|
||||||
|
checkParcelable(attributedInfo);
|
||||||
|
|
||||||
|
// Sanity check that we actually wrote attributes to attributedInfo.
|
||||||
|
assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
|
||||||
|
String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
|
||||||
|
assertTrue(sound.equals("にゃあ"));
|
||||||
|
byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
|
||||||
|
assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
|
||||||
|
assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkParcelable(NsdServiceInfo original) {
|
||||||
|
// Write to parcel.
|
||||||
|
Parcel p = Parcel.obtain();
|
||||||
|
Bundle writer = new Bundle();
|
||||||
|
writer.putParcelable("test_info", original);
|
||||||
|
writer.writeToParcel(p, 0);
|
||||||
|
|
||||||
|
// Extract from parcel.
|
||||||
|
p.setDataPosition(0);
|
||||||
|
Bundle reader = p.readBundle();
|
||||||
|
reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
|
||||||
|
NsdServiceInfo result = reader.getParcelable("test_info");
|
||||||
|
|
||||||
|
// Assert equality of base fields.
|
||||||
|
assertEquals(original.getServiceName(), result.getServiceName());
|
||||||
|
assertEquals(original.getServiceType(), result.getServiceType());
|
||||||
|
assertEquals(original.getHost(), result.getHost());
|
||||||
|
assertTrue(original.getPort() == result.getPort());
|
||||||
|
|
||||||
|
// Assert equality of attribute map.
|
||||||
|
Map<String, byte[]> originalMap = original.getAttributes();
|
||||||
|
Map<String, byte[]> resultMap = result.getAttributes();
|
||||||
|
assertEquals(originalMap.keySet(), resultMap.keySet());
|
||||||
|
for (String key : originalMap.keySet()) {
|
||||||
|
assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
|
||||||
|
byte[] txtRecord = shouldBeEmpty.getTxtRecord();
|
||||||
|
if (txtRecord == null || txtRecord.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord));
|
||||||
|
}
|
||||||
|
}
|
||||||
216
tests/unit/java/android/net/util/DnsUtilsTest.java
Normal file
216
tests/unit/java/android/net/util/DnsUtilsTest.java
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.util;
|
||||||
|
|
||||||
|
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL;
|
||||||
|
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL;
|
||||||
|
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.net.InetAddresses;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class DnsUtilsTest {
|
||||||
|
private InetAddress stringToAddress(@NonNull String addr) {
|
||||||
|
return InetAddresses.parseNumericAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) {
|
||||||
|
return makeSortableAddress(addr, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr,
|
||||||
|
@Nullable String srcAddr) {
|
||||||
|
return new DnsUtils.SortableAddress(stringToAddress(addr),
|
||||||
|
srcAddr != null ? stringToAddress(srcAddr) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRfc6724Comparator() {
|
||||||
|
final List<DnsUtils.SortableAddress> test = Arrays.asList(
|
||||||
|
// Ipv4
|
||||||
|
makeSortableAddress("216.58.200.36", "192.168.1.1"),
|
||||||
|
// global with different scope src
|
||||||
|
makeSortableAddress("2404:6800:4008:801::2004", "fe80::1111:2222"),
|
||||||
|
// global without src addr
|
||||||
|
makeSortableAddress("2404:6800:cafe:801::1"),
|
||||||
|
// loop back
|
||||||
|
makeSortableAddress("::1", "::1"),
|
||||||
|
// link local
|
||||||
|
makeSortableAddress("fe80::c46f:1cff:fe04:39b4", "fe80::1"),
|
||||||
|
// teredo tunneling
|
||||||
|
makeSortableAddress("2001::47c1", "2001::2"),
|
||||||
|
// 6bone without src addr
|
||||||
|
makeSortableAddress("3ffe::1234:5678"),
|
||||||
|
// IPv4-compatible
|
||||||
|
makeSortableAddress("::216.58.200.36", "::216.58.200.9"),
|
||||||
|
// 6bone
|
||||||
|
makeSortableAddress("3ffe::1234:5678", "3ffe::1234:1"),
|
||||||
|
// IPv4-mapped IPv6
|
||||||
|
makeSortableAddress("::ffff:192.168.95.7", "::ffff:192.168.95.1"));
|
||||||
|
|
||||||
|
final List<InetAddress> expected = Arrays.asList(
|
||||||
|
stringToAddress("::1"), // loop back
|
||||||
|
stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local
|
||||||
|
stringToAddress("216.58.200.36"), // Ipv4
|
||||||
|
stringToAddress("::ffff:192.168.95.7"), // IPv4-mapped IPv6
|
||||||
|
stringToAddress("2001::47c1"), // teredo tunneling
|
||||||
|
stringToAddress("::216.58.200.36"), // IPv4-compatible
|
||||||
|
stringToAddress("3ffe::1234:5678"), // 6bone
|
||||||
|
stringToAddress("2404:6800:4008:801::2004"), // global with different scope src
|
||||||
|
stringToAddress("2404:6800:cafe:801::1"), // global without src addr
|
||||||
|
stringToAddress("3ffe::1234:5678")); // 6bone without src addr
|
||||||
|
|
||||||
|
Collections.sort(test, new DnsUtils.Rfc6724Comparator());
|
||||||
|
|
||||||
|
for (int i = 0; i < test.size(); ++i) {
|
||||||
|
assertEquals(test.get(i).address, expected.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add more combinations
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testV4SortableAddress() {
|
||||||
|
// Test V4 address
|
||||||
|
DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36");
|
||||||
|
assertEquals(test.hasSrcAddr, 0);
|
||||||
|
assertEquals(test.prefixMatchLen, 0);
|
||||||
|
assertEquals(test.address, stringToAddress("216.58.200.36"));
|
||||||
|
assertEquals(test.labelMatch, 0);
|
||||||
|
assertEquals(test.scopeMatch, 0);
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 4);
|
||||||
|
assertEquals(test.precedence, 35);
|
||||||
|
|
||||||
|
// Test V4 loopback address with the same source address
|
||||||
|
test = makeSortableAddress("127.1.2.3", "127.1.2.3");
|
||||||
|
assertEquals(test.hasSrcAddr, 1);
|
||||||
|
assertEquals(test.prefixMatchLen, 0);
|
||||||
|
assertEquals(test.address, stringToAddress("127.1.2.3"));
|
||||||
|
assertEquals(test.labelMatch, 1);
|
||||||
|
assertEquals(test.scopeMatch, 1);
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
|
||||||
|
assertEquals(test.label, 4);
|
||||||
|
assertEquals(test.precedence, 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testV6SortableAddress() {
|
||||||
|
// Test global address
|
||||||
|
DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004");
|
||||||
|
assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 1);
|
||||||
|
assertEquals(test.precedence, 40);
|
||||||
|
|
||||||
|
// Test global address with global source address
|
||||||
|
test = makeSortableAddress("2404:6800:4008:801::2004",
|
||||||
|
"2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6");
|
||||||
|
assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
|
||||||
|
assertEquals(test.hasSrcAddr, 1);
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.labelMatch, 1);
|
||||||
|
assertEquals(test.scopeMatch, 1);
|
||||||
|
assertEquals(test.label, 1);
|
||||||
|
assertEquals(test.precedence, 40);
|
||||||
|
assertEquals(test.prefixMatchLen, 13);
|
||||||
|
|
||||||
|
// Test global address with linklocal source address
|
||||||
|
test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4");
|
||||||
|
assertEquals(test.hasSrcAddr, 1);
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.labelMatch, 1);
|
||||||
|
assertEquals(test.scopeMatch, 0);
|
||||||
|
assertEquals(test.label, 1);
|
||||||
|
assertEquals(test.precedence, 40);
|
||||||
|
assertEquals(test.prefixMatchLen, 0);
|
||||||
|
|
||||||
|
// Test loopback address with the same source address
|
||||||
|
test = makeSortableAddress("::1", "::1");
|
||||||
|
assertEquals(test.hasSrcAddr, 1);
|
||||||
|
assertEquals(test.prefixMatchLen, 16 * 8);
|
||||||
|
assertEquals(test.labelMatch, 1);
|
||||||
|
assertEquals(test.scopeMatch, 1);
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
|
||||||
|
assertEquals(test.label, 0);
|
||||||
|
assertEquals(test.precedence, 50);
|
||||||
|
|
||||||
|
// Test linklocal address
|
||||||
|
test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
|
||||||
|
assertEquals(test.label, 1);
|
||||||
|
assertEquals(test.precedence, 40);
|
||||||
|
|
||||||
|
// Test linklocal address
|
||||||
|
test = makeSortableAddress("fe80::");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
|
||||||
|
assertEquals(test.label, 1);
|
||||||
|
assertEquals(test.precedence, 40);
|
||||||
|
|
||||||
|
// Test 6to4 address
|
||||||
|
test = makeSortableAddress("2002:c000:0204::");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 2);
|
||||||
|
assertEquals(test.precedence, 30);
|
||||||
|
|
||||||
|
// Test unique local address
|
||||||
|
test = makeSortableAddress("fc00::c000:13ab");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 13);
|
||||||
|
assertEquals(test.precedence, 3);
|
||||||
|
|
||||||
|
// Test teredo tunneling address
|
||||||
|
test = makeSortableAddress("2001::47c1");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 5);
|
||||||
|
assertEquals(test.precedence, 5);
|
||||||
|
|
||||||
|
// Test IPv4-compatible addresses
|
||||||
|
test = makeSortableAddress("::216.58.200.36");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 3);
|
||||||
|
assertEquals(test.precedence, 1);
|
||||||
|
|
||||||
|
// Test site-local address
|
||||||
|
test = makeSortableAddress("fec0::cafe:3ab2");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL);
|
||||||
|
assertEquals(test.label, 11);
|
||||||
|
assertEquals(test.precedence, 1);
|
||||||
|
|
||||||
|
// Test 6bone address
|
||||||
|
test = makeSortableAddress("3ffe::1234:5678");
|
||||||
|
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
|
||||||
|
assertEquals(test.label, 12);
|
||||||
|
assertEquals(test.precedence, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
145
tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
Normal file
145
tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.net.ConnectivityResources
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkCapabilities.MAX_TRANSPORT
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_VPN
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.internal.R
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.mockito.ArgumentMatchers.eq
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for [KeepaliveUtils].
|
||||||
|
*
|
||||||
|
* Build, install and run with:
|
||||||
|
* atest android.net.util.KeepaliveUtilsTest
|
||||||
|
*/
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class KeepaliveUtilsTest {
|
||||||
|
|
||||||
|
// Prepare mocked context with given resource strings.
|
||||||
|
private fun getMockedContextWithStringArrayRes(
|
||||||
|
id: Int,
|
||||||
|
name: String,
|
||||||
|
res: Array<out String?>?
|
||||||
|
): Context {
|
||||||
|
val mockRes = mock(Resources::class.java)
|
||||||
|
doReturn(res).`when`(mockRes).getStringArray(eq(id))
|
||||||
|
doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
|
||||||
|
|
||||||
|
return mock(Context::class.java).apply {
|
||||||
|
doReturn(mockRes).`when`(this).getResources()
|
||||||
|
ConnectivityResources.setResourcesContextForTest(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
ConnectivityResources.setResourcesContextForTest(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetSupportedKeepalives() {
|
||||||
|
fun assertRunWithException(res: Array<out String?>?) {
|
||||||
|
try {
|
||||||
|
val mockContext = getMockedContextWithStringArrayRes(
|
||||||
|
R.array.config_networkSupportedKeepaliveCount,
|
||||||
|
"config_networkSupportedKeepaliveCount", res)
|
||||||
|
KeepaliveUtils.getSupportedKeepalives(mockContext)
|
||||||
|
fail("Expected KeepaliveDeviceConfigurationException")
|
||||||
|
} catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check resource with various invalid format.
|
||||||
|
assertRunWithException(null)
|
||||||
|
assertRunWithException(arrayOf<String?>(null))
|
||||||
|
assertRunWithException(arrayOfNulls<String?>(10))
|
||||||
|
assertRunWithException(arrayOf(""))
|
||||||
|
assertRunWithException(arrayOf("3,ABC"))
|
||||||
|
assertRunWithException(arrayOf("6,3,3"))
|
||||||
|
assertRunWithException(arrayOf("5"))
|
||||||
|
|
||||||
|
// Check resource with invalid slots value.
|
||||||
|
assertRunWithException(arrayOf("3,-1"))
|
||||||
|
|
||||||
|
// Check resource with invalid transport type.
|
||||||
|
assertRunWithException(arrayOf("-1,3"))
|
||||||
|
assertRunWithException(arrayOf("10,3"))
|
||||||
|
|
||||||
|
// Check valid customization generates expected array.
|
||||||
|
val validRes = arrayOf("0,3", "1,0", "4,4")
|
||||||
|
val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
|
||||||
|
|
||||||
|
val mockContext = getMockedContextWithStringArrayRes(
|
||||||
|
R.array.config_networkSupportedKeepaliveCount,
|
||||||
|
"config_networkSupportedKeepaliveCount", validRes)
|
||||||
|
val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
|
||||||
|
assertArrayEquals(expectedValidRes, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetSupportedKeepalivesForNetworkCapabilities() {
|
||||||
|
// Mock customized supported keepalives for each transport type, and assuming:
|
||||||
|
// 3 for cellular,
|
||||||
|
// 6 for wifi,
|
||||||
|
// 0 for others.
|
||||||
|
val cust = IntArray(MAX_TRANSPORT + 1).apply {
|
||||||
|
this[TRANSPORT_CELLULAR] = 3
|
||||||
|
this[TRANSPORT_WIFI] = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
val nc = NetworkCapabilities()
|
||||||
|
// Check supported keepalives with single transport type.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
|
||||||
|
assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with multiple transport types.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
|
||||||
|
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with non-customized transport type.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
|
||||||
|
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with undefined transport type.
|
||||||
|
nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
|
||||||
|
try {
|
||||||
|
KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
|
||||||
|
fail("Expected ArrayIndexOutOfBoundsException")
|
||||||
|
} catch (expected: ArrayIndexOutOfBoundsException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.net.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
|
||||||
|
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
|
||||||
|
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
|
||||||
|
import android.net.ConnectivityResources
|
||||||
|
import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
|
||||||
|
import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
|
||||||
|
import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.telephony.SubscriptionInfo
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import android.test.mock.MockContentResolver
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.connectivity.resources.R
|
||||||
|
import com.android.internal.util.test.FakeSettingsProvider
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.ArgumentMatchers.argThat
|
||||||
|
import org.mockito.ArgumentMatchers.eq
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.times
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for [MultinetworkPolicyTracker].
|
||||||
|
*
|
||||||
|
* Build, install and run with:
|
||||||
|
* atest android.net.util.MultinetworkPolicyTrackerTest
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class MultinetworkPolicyTrackerTest {
|
||||||
|
private val resources = mock(Resources::class.java).also {
|
||||||
|
doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
|
||||||
|
eq("config_networkAvoidBadWifi"), eq("integer"), any())
|
||||||
|
doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
|
||||||
|
}
|
||||||
|
private val telephonyManager = mock(TelephonyManager::class.java)
|
||||||
|
private val subscriptionManager = mock(SubscriptionManager::class.java).also {
|
||||||
|
doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
|
||||||
|
}
|
||||||
|
private val resolver = MockContentResolver().apply {
|
||||||
|
addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
|
||||||
|
private val context = mock(Context::class.java).also {
|
||||||
|
doReturn(Context.TELEPHONY_SERVICE).`when`(it)
|
||||||
|
.getSystemServiceName(TelephonyManager::class.java)
|
||||||
|
doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
|
||||||
|
doReturn(subscriptionManager).`when`(it)
|
||||||
|
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
|
||||||
|
doReturn(resolver).`when`(it).contentResolver
|
||||||
|
doReturn(resources).`when`(it).resources
|
||||||
|
doReturn(it).`when`(it).createConfigurationContext(any())
|
||||||
|
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
|
||||||
|
ConnectivityResources.setResourcesContextForTest(it)
|
||||||
|
}
|
||||||
|
private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
|
||||||
|
|
||||||
|
private fun assertMultipathPreference(preference: Int) {
|
||||||
|
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
|
||||||
|
preference.toString())
|
||||||
|
tracker.updateMeteredMultipathPreference()
|
||||||
|
assertEquals(preference, tracker.meteredMultipathPreference)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
ConnectivityResources.setResourcesContextForTest(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUpdateMeteredMultipathPreference() {
|
||||||
|
assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
|
||||||
|
assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
|
||||||
|
assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUpdateAvoidBadWifi() {
|
||||||
|
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
|
||||||
|
assertTrue(tracker.updateAvoidBadWifi())
|
||||||
|
assertFalse(tracker.avoidBadWifi)
|
||||||
|
|
||||||
|
doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
|
||||||
|
assertTrue(tracker.updateAvoidBadWifi())
|
||||||
|
assertTrue(tracker.avoidBadWifi)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnActiveDataSubscriptionIdChanged() {
|
||||||
|
val testSubId = 1000
|
||||||
|
val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
|
||||||
|
"TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
|
||||||
|
"123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
|
||||||
|
""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
|
||||||
|
"1"/* cardString */)
|
||||||
|
doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
|
||||||
|
|
||||||
|
// Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
|
||||||
|
// MultinetworkPolicyTracker should be also updated after subId changed.
|
||||||
|
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
|
||||||
|
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
|
||||||
|
MULTIPATH_PREFERENCE_PERFORMANCE.toString())
|
||||||
|
|
||||||
|
val listenerCaptor = ArgumentCaptor.forClass(
|
||||||
|
ActiveDataSubscriptionIdListener::class.java)
|
||||||
|
verify(telephonyManager, times(1))
|
||||||
|
.registerTelephonyCallback(any(), listenerCaptor.capture())
|
||||||
|
val listener = listenerCaptor.value
|
||||||
|
listener.onActiveDataSubscriptionIdChanged(testSubId)
|
||||||
|
|
||||||
|
// Check it get resource value with test sub id.
|
||||||
|
verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
|
||||||
|
verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
|
||||||
|
|
||||||
|
// Check if avoidBadWifi and meteredMultipathPreference values have been updated.
|
||||||
|
assertFalse(tracker.avoidBadWifi)
|
||||||
|
assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.internal.net;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.AF_INET;
|
||||||
|
import static android.system.OsConstants.AF_INET6;
|
||||||
|
import static android.system.OsConstants.AF_UNIX;
|
||||||
|
import static android.system.OsConstants.EPERM;
|
||||||
|
import static android.system.OsConstants.SOCK_DGRAM;
|
||||||
|
import static android.system.OsConstants.SOCK_STREAM;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@androidx.test.filters.SmallTest
|
||||||
|
public class NetworkUtilsInternalTest {
|
||||||
|
|
||||||
|
private static void expectSocketSuccess(String msg, int domain, int type) {
|
||||||
|
try {
|
||||||
|
IoUtils.closeQuietly(Os.socket(domain, type, 0));
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
fail(msg + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void expectSocketPemissionError(String msg, int domain, int type) {
|
||||||
|
try {
|
||||||
|
IoUtils.closeQuietly(Os.socket(domain, type, 0));
|
||||||
|
fail(msg);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
assertEquals(msg, e.errno, EPERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void expectHasNetworking() {
|
||||||
|
expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
|
||||||
|
AF_UNIX, SOCK_STREAM);
|
||||||
|
expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
|
||||||
|
AF_INET, SOCK_DGRAM);
|
||||||
|
expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
|
||||||
|
AF_INET6, SOCK_DGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void expectNoNetworking() {
|
||||||
|
expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
|
||||||
|
AF_UNIX, SOCK_STREAM);
|
||||||
|
expectSocketPemissionError(
|
||||||
|
"Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
|
||||||
|
AF_INET, SOCK_DGRAM);
|
||||||
|
expectSocketPemissionError(
|
||||||
|
"Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
|
||||||
|
AF_INET6, SOCK_DGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAllowNetworkingForProcess() {
|
||||||
|
expectHasNetworking();
|
||||||
|
NetworkUtilsInternal.setAllowNetworkingForProcess(false);
|
||||||
|
expectNoNetworking();
|
||||||
|
NetworkUtilsInternal.setAllowNetworkingForProcess(true);
|
||||||
|
expectHasNetworking();
|
||||||
|
}
|
||||||
|
}
|
||||||
218
tests/unit/java/com/android/internal/net/VpnProfileTest.java
Normal file
218
tests/unit/java/com/android/internal/net/VpnProfileTest.java
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.internal.net;
|
||||||
|
|
||||||
|
import static com.android.testutils.ParcelUtils.assertParcelSane;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.net.IpSecAlgorithm;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Unit tests for {@link VpnProfile}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class VpnProfileTest {
|
||||||
|
private static final String DUMMY_PROFILE_KEY = "Test";
|
||||||
|
|
||||||
|
private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
|
||||||
|
private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaults() throws Exception {
|
||||||
|
final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
|
||||||
|
|
||||||
|
assertEquals(DUMMY_PROFILE_KEY, p.key);
|
||||||
|
assertEquals("", p.name);
|
||||||
|
assertEquals(VpnProfile.TYPE_PPTP, p.type);
|
||||||
|
assertEquals("", p.server);
|
||||||
|
assertEquals("", p.username);
|
||||||
|
assertEquals("", p.password);
|
||||||
|
assertEquals("", p.dnsServers);
|
||||||
|
assertEquals("", p.searchDomains);
|
||||||
|
assertEquals("", p.routes);
|
||||||
|
assertTrue(p.mppe);
|
||||||
|
assertEquals("", p.l2tpSecret);
|
||||||
|
assertEquals("", p.ipsecIdentifier);
|
||||||
|
assertEquals("", p.ipsecSecret);
|
||||||
|
assertEquals("", p.ipsecUserCert);
|
||||||
|
assertEquals("", p.ipsecCaCert);
|
||||||
|
assertEquals("", p.ipsecServerCert);
|
||||||
|
assertEquals(null, p.proxy);
|
||||||
|
assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
|
||||||
|
assertFalse(p.isBypassable);
|
||||||
|
assertFalse(p.isMetered);
|
||||||
|
assertEquals(1360, p.maxMtu);
|
||||||
|
assertFalse(p.areAuthParamsInline);
|
||||||
|
assertFalse(p.isRestrictedToTestNetworks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VpnProfile getSampleIkev2Profile(String key) {
|
||||||
|
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
|
||||||
|
|
||||||
|
p.name = "foo";
|
||||||
|
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
|
||||||
|
p.server = "bar";
|
||||||
|
p.username = "baz";
|
||||||
|
p.password = "qux";
|
||||||
|
p.dnsServers = "8.8.8.8";
|
||||||
|
p.searchDomains = "";
|
||||||
|
p.routes = "0.0.0.0/0";
|
||||||
|
p.mppe = false;
|
||||||
|
p.l2tpSecret = "";
|
||||||
|
p.ipsecIdentifier = "quux";
|
||||||
|
p.ipsecSecret = "quuz";
|
||||||
|
p.ipsecUserCert = "corge";
|
||||||
|
p.ipsecCaCert = "grault";
|
||||||
|
p.ipsecServerCert = "garply";
|
||||||
|
p.proxy = null;
|
||||||
|
p.setAllowedAlgorithms(
|
||||||
|
Arrays.asList(
|
||||||
|
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_SHA512,
|
||||||
|
IpSecAlgorithm.CRYPT_AES_CBC));
|
||||||
|
p.isBypassable = true;
|
||||||
|
p.isMetered = true;
|
||||||
|
p.maxMtu = 1350;
|
||||||
|
p.areAuthParamsInline = true;
|
||||||
|
|
||||||
|
// Not saved, but also not compared.
|
||||||
|
p.saveLogin = true;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
assertEquals(
|
||||||
|
getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
|
||||||
|
|
||||||
|
final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
modified.maxMtu--;
|
||||||
|
assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelUnparcel() {
|
||||||
|
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetInvalidAlgorithmValueDelimiter() {
|
||||||
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
profile.setAllowedAlgorithms(
|
||||||
|
Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
|
||||||
|
fail("Expected failure due to value separator in algorithm name");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetInvalidAlgorithmListDelimiter() {
|
||||||
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
profile.setAllowedAlgorithms(
|
||||||
|
Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
|
||||||
|
fail("Expected failure due to value separator in algorithm name");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecode() {
|
||||||
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
|
||||||
|
assertEquals(profile, decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeTooManyValues() {
|
||||||
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
final byte[] tooManyValues =
|
||||||
|
(new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
|
||||||
|
|
||||||
|
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
|
||||||
|
// Sort to ensure when we remove, we can do it from greatest first.
|
||||||
|
Arrays.sort(missingIndices);
|
||||||
|
|
||||||
|
final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
|
||||||
|
final List<String> parts =
|
||||||
|
new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
|
||||||
|
|
||||||
|
// Remove from back first to ensure indexing is consistent.
|
||||||
|
for (int i = missingIndices.length - 1; i >= 0; i--) {
|
||||||
|
parts.remove(missingIndices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeInvalidNumberOfValues() {
|
||||||
|
final String tooFewValues =
|
||||||
|
getEncodedDecodedIkev2ProfileMissingValues(
|
||||||
|
ENCODED_INDEX_AUTH_PARAMS_INLINE,
|
||||||
|
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
|
||||||
|
|
||||||
|
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
|
||||||
|
final String tooFewValues =
|
||||||
|
getEncodedDecodedIkev2ProfileMissingValues(
|
||||||
|
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
|
||||||
|
|
||||||
|
// Verify decoding without isRestrictedToTestNetworks defaults to false
|
||||||
|
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
|
||||||
|
assertFalse(decoded.isRestrictedToTestNetworks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeLoginsNotSaved() {
|
||||||
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
profile.saveLogin = false;
|
||||||
|
|
||||||
|
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
|
||||||
|
assertNotEquals(profile, decoded);
|
||||||
|
|
||||||
|
// Add the username/password back, everything else must be equal.
|
||||||
|
decoded.username = profile.username;
|
||||||
|
decoded.password = profile.password;
|
||||||
|
assertEquals(profile, decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
201
tests/unit/java/com/android/internal/util/BitUtilsTest.java
Normal file
201
tests/unit/java/com/android/internal/util/BitUtilsTest.java
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.internal.util;
|
||||||
|
|
||||||
|
import static com.android.internal.util.BitUtils.bytesToBEInt;
|
||||||
|
import static com.android.internal.util.BitUtils.bytesToLEInt;
|
||||||
|
import static com.android.internal.util.BitUtils.getUint16;
|
||||||
|
import static com.android.internal.util.BitUtils.getUint32;
|
||||||
|
import static com.android.internal.util.BitUtils.getUint8;
|
||||||
|
import static com.android.internal.util.BitUtils.packBits;
|
||||||
|
import static com.android.internal.util.BitUtils.uint16;
|
||||||
|
import static com.android.internal.util.BitUtils.uint32;
|
||||||
|
import static com.android.internal.util.BitUtils.uint8;
|
||||||
|
import static com.android.internal.util.BitUtils.unpackBits;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class BitUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnsignedByteWideningConversions() {
|
||||||
|
byte b0 = 0;
|
||||||
|
byte b1 = 1;
|
||||||
|
byte bm1 = -1;
|
||||||
|
assertEquals(0, uint8(b0));
|
||||||
|
assertEquals(1, uint8(b1));
|
||||||
|
assertEquals(127, uint8(Byte.MAX_VALUE));
|
||||||
|
assertEquals(128, uint8(Byte.MIN_VALUE));
|
||||||
|
assertEquals(255, uint8(bm1));
|
||||||
|
assertEquals(255, uint8((byte)255));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnsignedShortWideningConversions() {
|
||||||
|
short s0 = 0;
|
||||||
|
short s1 = 1;
|
||||||
|
short sm1 = -1;
|
||||||
|
assertEquals(0, uint16(s0));
|
||||||
|
assertEquals(1, uint16(s1));
|
||||||
|
assertEquals(32767, uint16(Short.MAX_VALUE));
|
||||||
|
assertEquals(32768, uint16(Short.MIN_VALUE));
|
||||||
|
assertEquals(65535, uint16(sm1));
|
||||||
|
assertEquals(65535, uint16((short)65535));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnsignedShortComposition() {
|
||||||
|
byte b0 = 0;
|
||||||
|
byte b1 = 1;
|
||||||
|
byte b2 = 2;
|
||||||
|
byte b10 = 10;
|
||||||
|
byte b16 = 16;
|
||||||
|
byte b128 = -128;
|
||||||
|
byte b224 = -32;
|
||||||
|
byte b255 = -1;
|
||||||
|
assertEquals(0x0000, uint16(b0, b0));
|
||||||
|
assertEquals(0xffff, uint16(b255, b255));
|
||||||
|
assertEquals(0x0a01, uint16(b10, b1));
|
||||||
|
assertEquals(0x8002, uint16(b128, b2));
|
||||||
|
assertEquals(0x01ff, uint16(b1, b255));
|
||||||
|
assertEquals(0x80ff, uint16(b128, b255));
|
||||||
|
assertEquals(0xe010, uint16(b224, b16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnsignedIntWideningConversions() {
|
||||||
|
assertEquals(0, uint32(0));
|
||||||
|
assertEquals(1, uint32(1));
|
||||||
|
assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
|
||||||
|
assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
|
||||||
|
assertEquals(4294967295L, uint32(-1));
|
||||||
|
assertEquals(4294967295L, uint32((int)4294967295L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBytesToInt() {
|
||||||
|
assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
|
||||||
|
assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
|
||||||
|
assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
|
||||||
|
assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
|
||||||
|
assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
|
||||||
|
assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
|
||||||
|
|
||||||
|
assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
|
||||||
|
assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
|
||||||
|
assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnsignedGetters() {
|
||||||
|
ByteBuffer b = ByteBuffer.allocate(4);
|
||||||
|
b.putInt(0xffff);
|
||||||
|
|
||||||
|
assertEquals(0x0, getUint8(b, 0));
|
||||||
|
assertEquals(0x0, getUint8(b, 1));
|
||||||
|
assertEquals(0xff, getUint8(b, 2));
|
||||||
|
assertEquals(0xff, getUint8(b, 3));
|
||||||
|
|
||||||
|
assertEquals(0x0, getUint16(b, 0));
|
||||||
|
assertEquals(0xffff, getUint16(b, 2));
|
||||||
|
|
||||||
|
b.rewind();
|
||||||
|
b.putInt(0xffffffff);
|
||||||
|
assertEquals(0xffffffffL, getUint32(b, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBitsPacking() {
|
||||||
|
BitPackingTestCase[] testCases = {
|
||||||
|
new BitPackingTestCase(0, ints()),
|
||||||
|
new BitPackingTestCase(1, ints(0)),
|
||||||
|
new BitPackingTestCase(2, ints(1)),
|
||||||
|
new BitPackingTestCase(3, ints(0, 1)),
|
||||||
|
new BitPackingTestCase(4, ints(2)),
|
||||||
|
new BitPackingTestCase(6, ints(1, 2)),
|
||||||
|
new BitPackingTestCase(9, ints(0, 3)),
|
||||||
|
new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
|
||||||
|
new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
|
||||||
|
new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
|
||||||
|
};
|
||||||
|
for (BitPackingTestCase tc : testCases) {
|
||||||
|
int[] got = unpackBits(tc.packedBits);
|
||||||
|
assertTrue(
|
||||||
|
"unpackBits("
|
||||||
|
+ tc.packedBits
|
||||||
|
+ "): expected "
|
||||||
|
+ Arrays.toString(tc.bits)
|
||||||
|
+ " but got "
|
||||||
|
+ Arrays.toString(got),
|
||||||
|
Arrays.equals(tc.bits, got));
|
||||||
|
}
|
||||||
|
for (BitPackingTestCase tc : testCases) {
|
||||||
|
long got = packBits(tc.bits);
|
||||||
|
assertEquals(
|
||||||
|
"packBits("
|
||||||
|
+ Arrays.toString(tc.bits)
|
||||||
|
+ "): expected "
|
||||||
|
+ tc.packedBits
|
||||||
|
+ " but got "
|
||||||
|
+ got,
|
||||||
|
tc.packedBits,
|
||||||
|
got);
|
||||||
|
}
|
||||||
|
|
||||||
|
long[] moreTestCases = {
|
||||||
|
0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
|
||||||
|
};
|
||||||
|
for (long l : moreTestCases) {
|
||||||
|
assertEquals(l, packBits(unpackBits(l)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] bytes(int b1, int b2, int b3, int b4) {
|
||||||
|
return new byte[] {b(b1), b(b2), b(b3), b(b4)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte b(int i) {
|
||||||
|
return (byte) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int[] ints(int... array) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BitPackingTestCase {
|
||||||
|
final int[] bits;
|
||||||
|
final long packedBits;
|
||||||
|
|
||||||
|
BitPackingTestCase(long packedBits, int[] bits) {
|
||||||
|
this.bits = bits;
|
||||||
|
this.packedBits = packedBits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
tests/unit/java/com/android/internal/util/RingBufferTest.java
Normal file
178
tests/unit/java/com/android/internal/util/RingBufferTest.java
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.internal.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class RingBufferTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyRingBuffer() {
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
|
||||||
|
|
||||||
|
assertArrayEquals(new String[0], buffer.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIncorrectConstructorArguments() {
|
||||||
|
try {
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
|
||||||
|
fail("Should not be able to create a negative capacity RingBuffer");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
|
||||||
|
fail("Should not be able to create a 0 capacity RingBuffer");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRingBufferWithNoWrapping() {
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
|
||||||
|
|
||||||
|
buffer.append("a");
|
||||||
|
buffer.append("b");
|
||||||
|
buffer.append("c");
|
||||||
|
buffer.append("d");
|
||||||
|
buffer.append("e");
|
||||||
|
|
||||||
|
String[] expected = {"a", "b", "c", "d", "e"};
|
||||||
|
assertArrayEquals(expected, buffer.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRingBufferWithCapacity1() {
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
|
||||||
|
|
||||||
|
buffer.append("a");
|
||||||
|
assertArrayEquals(new String[]{"a"}, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("b");
|
||||||
|
assertArrayEquals(new String[]{"b"}, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("c");
|
||||||
|
assertArrayEquals(new String[]{"c"}, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("d");
|
||||||
|
assertArrayEquals(new String[]{"d"}, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("e");
|
||||||
|
assertArrayEquals(new String[]{"e"}, buffer.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRingBufferWithWrapping() {
|
||||||
|
int capacity = 100;
|
||||||
|
RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
|
||||||
|
|
||||||
|
buffer.append("a");
|
||||||
|
buffer.append("b");
|
||||||
|
buffer.append("c");
|
||||||
|
buffer.append("d");
|
||||||
|
buffer.append("e");
|
||||||
|
|
||||||
|
String[] expected1 = {"a", "b", "c", "d", "e"};
|
||||||
|
assertArrayEquals(expected1, buffer.toArray());
|
||||||
|
|
||||||
|
String[] expected2 = new String[capacity];
|
||||||
|
int firstIndex = 0;
|
||||||
|
int lastIndex = capacity - 1;
|
||||||
|
|
||||||
|
expected2[firstIndex] = "e";
|
||||||
|
for (int i = 1; i < capacity; i++) {
|
||||||
|
buffer.append("x");
|
||||||
|
expected2[i] = "x";
|
||||||
|
}
|
||||||
|
assertArrayEquals(expected2, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("x");
|
||||||
|
expected2[firstIndex] = "x";
|
||||||
|
assertArrayEquals(expected2, buffer.toArray());
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
for (String s : expected2) {
|
||||||
|
buffer.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertArrayEquals(expected2, buffer.toArray());
|
||||||
|
|
||||||
|
buffer.append("a");
|
||||||
|
expected2[lastIndex] = "a";
|
||||||
|
assertArrayEquals(expected2, buffer.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNextSlot() {
|
||||||
|
int capacity = 100;
|
||||||
|
RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
|
||||||
|
|
||||||
|
final DummyClass1[] actual = new DummyClass1[capacity];
|
||||||
|
final DummyClass1[] expected = new DummyClass1[capacity];
|
||||||
|
for (int i = 0; i < capacity; ++i) {
|
||||||
|
final DummyClass1 obj = buffer.getNextSlot();
|
||||||
|
obj.x = capacity * i;
|
||||||
|
actual[i] = obj;
|
||||||
|
expected[i] = new DummyClass1();
|
||||||
|
expected[i].x = capacity * i;
|
||||||
|
}
|
||||||
|
assertArrayEquals(expected, buffer.toArray());
|
||||||
|
|
||||||
|
for (int i = 0; i < capacity; ++i) {
|
||||||
|
if (actual[i] != buffer.getNextSlot()) {
|
||||||
|
fail("getNextSlot() should re-use objects if available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
|
||||||
|
assertNull("getNextSlot() should return null if the object can't be initiated "
|
||||||
|
+ "(No nullary constructor)", buffer2.getNextSlot());
|
||||||
|
|
||||||
|
RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
|
||||||
|
assertNull("getNextSlot() should return null if the object can't be initiated "
|
||||||
|
+ "(Inaccessible class)", buffer3.getNextSlot());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class DummyClass1 {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof DummyClass1) {
|
||||||
|
final DummyClass1 other = (DummyClass1) o;
|
||||||
|
return other.x == this.x;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class DummyClass2 {
|
||||||
|
public DummyClass2(int x) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DummyClass3 {}
|
||||||
|
}
|
||||||
12461
tests/unit/java/com/android/server/ConnectivityServiceTest.java
Normal file
12461
tests/unit/java/com/android/server/ConnectivityServiceTest.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.server.IpSecService.IResource;
|
||||||
|
import com.android.server.IpSecService.RefcountedResource;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecService.RefcountedResource}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class IpSecServiceRefcountedResourceTest {
|
||||||
|
Context mMockContext;
|
||||||
|
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
|
||||||
|
IpSecService mIpSecService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mMockContext = mock(Context.class);
|
||||||
|
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
|
||||||
|
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertResourceState(
|
||||||
|
RefcountedResource<IResource> resource,
|
||||||
|
int refCount,
|
||||||
|
int userReleaseCallCount,
|
||||||
|
int releaseReferenceCallCount,
|
||||||
|
int invalidateCallCount,
|
||||||
|
int freeUnderlyingResourcesCallCount)
|
||||||
|
throws RemoteException {
|
||||||
|
// Check refcount on RefcountedResource
|
||||||
|
assertEquals(refCount, resource.mRefCount);
|
||||||
|
|
||||||
|
// Check call count of RefcountedResource
|
||||||
|
verify(resource, times(userReleaseCallCount)).userRelease();
|
||||||
|
verify(resource, times(releaseReferenceCallCount)).releaseReference();
|
||||||
|
|
||||||
|
// Check call count of IResource
|
||||||
|
verify(resource.getResource(), times(invalidateCallCount)).invalidate();
|
||||||
|
verify(resource.getResource(), times(freeUnderlyingResourcesCallCount))
|
||||||
|
.freeUnderlyingResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds mockito instrumentation */
|
||||||
|
private RefcountedResource<IResource> getTestRefcountedResource(
|
||||||
|
RefcountedResource... children) {
|
||||||
|
return getTestRefcountedResource(new Binder(), children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds mockito instrumentation with provided binder */
|
||||||
|
private RefcountedResource<IResource> getTestRefcountedResource(
|
||||||
|
IBinder binder, RefcountedResource... children) {
|
||||||
|
return spy(
|
||||||
|
mIpSecService
|
||||||
|
.new RefcountedResource<IResource>(mock(IResource.class), binder, children));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() throws RemoteException {
|
||||||
|
IBinder binderMock = mock(IBinder.class);
|
||||||
|
RefcountedResource<IResource> resource = getTestRefcountedResource(binderMock);
|
||||||
|
|
||||||
|
// Verify resource's refcount starts at 1 (for user-reference)
|
||||||
|
assertResourceState(resource, 1, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Verify linking to binder death
|
||||||
|
verify(binderMock).linkToDeath(anyObject(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructorWithChildren() throws RemoteException {
|
||||||
|
IBinder binderMockChild = mock(IBinder.class);
|
||||||
|
IBinder binderMockParent = mock(IBinder.class);
|
||||||
|
RefcountedResource<IResource> childResource = getTestRefcountedResource(binderMockChild);
|
||||||
|
RefcountedResource<IResource> parentResource =
|
||||||
|
getTestRefcountedResource(binderMockParent, childResource);
|
||||||
|
|
||||||
|
// Verify parent's refcount starts at 1 (for user-reference)
|
||||||
|
assertResourceState(parentResource, 1, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Verify child's refcounts were incremented
|
||||||
|
assertResourceState(childResource, 2, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Verify linking to binder death
|
||||||
|
verify(binderMockChild).linkToDeath(anyObject(), anyInt());
|
||||||
|
verify(binderMockParent).linkToDeath(anyObject(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailLinkToDeath() throws RemoteException {
|
||||||
|
IBinder binderMock = mock(IBinder.class);
|
||||||
|
doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
|
||||||
|
|
||||||
|
try {
|
||||||
|
getTestRefcountedResource(binderMock);
|
||||||
|
fail("Expected exception to propogate when binder fails to link to death");
|
||||||
|
} catch (RuntimeException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCleanupAndRelease() throws RemoteException {
|
||||||
|
IBinder binderMock = mock(IBinder.class);
|
||||||
|
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
|
||||||
|
|
||||||
|
// Verify user-initiated cleanup path decrements refcount and calls full cleanup flow
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
// Verify user-initated cleanup path unlinks from binder
|
||||||
|
verify(binderMock).unlinkToDeath(eq(refcountedResource), eq(0));
|
||||||
|
assertNull(refcountedResource.mBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleCallsToCleanupAndRelease() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
|
||||||
|
|
||||||
|
// Verify calling userRelease multiple times does not trigger any other cleanup
|
||||||
|
// methods
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
assertResourceState(refcountedResource, -1, 3, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBinderDeathAfterCleanupAndReleaseDoesNothing() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
|
||||||
|
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
// Verify binder death call does not trigger any other cleanup methods if called after
|
||||||
|
// userRelease()
|
||||||
|
refcountedResource.binderDied();
|
||||||
|
assertResourceState(refcountedResource, -1, 2, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBinderDeath() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
|
||||||
|
|
||||||
|
// Verify binder death caused cleanup
|
||||||
|
refcountedResource.binderDied();
|
||||||
|
verify(refcountedResource, times(1)).binderDied();
|
||||||
|
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
|
||||||
|
assertNull(refcountedResource.mBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCleanupParentDecrementsChildRefcount() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> childResource = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
|
||||||
|
|
||||||
|
parentResource.userRelease();
|
||||||
|
|
||||||
|
// Verify parent gets cleaned up properly, and triggers releaseReference on
|
||||||
|
// child
|
||||||
|
assertResourceState(childResource, 1, 0, 1, 0, 0);
|
||||||
|
assertResourceState(parentResource, -1, 1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCleanupReferencedChildDoesNotTriggerRelease() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> childResource = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
|
||||||
|
|
||||||
|
childResource.userRelease();
|
||||||
|
|
||||||
|
// Verify that child does not clean up kernel resources and quota.
|
||||||
|
assertResourceState(childResource, 1, 1, 1, 1, 0);
|
||||||
|
assertResourceState(parentResource, 1, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoParents() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> childResource = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> parentResource1 = getTestRefcountedResource(childResource);
|
||||||
|
RefcountedResource<IResource> parentResource2 = getTestRefcountedResource(childResource);
|
||||||
|
|
||||||
|
// Verify that child does not cleanup kernel resources and quota until all references
|
||||||
|
// have been released. Assumption: parents release correctly based on
|
||||||
|
// testCleanupParentDecrementsChildRefcount()
|
||||||
|
childResource.userRelease();
|
||||||
|
assertResourceState(childResource, 2, 1, 1, 1, 0);
|
||||||
|
|
||||||
|
parentResource1.userRelease();
|
||||||
|
assertResourceState(childResource, 1, 1, 2, 1, 0);
|
||||||
|
|
||||||
|
parentResource2.userRelease();
|
||||||
|
assertResourceState(childResource, -1, 1, 3, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoChildren() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> childResource1 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> childResource2 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> parentResource =
|
||||||
|
getTestRefcountedResource(childResource1, childResource2);
|
||||||
|
|
||||||
|
childResource1.userRelease();
|
||||||
|
assertResourceState(childResource1, 1, 1, 1, 1, 0);
|
||||||
|
assertResourceState(childResource2, 2, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
parentResource.userRelease();
|
||||||
|
assertResourceState(childResource1, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(childResource2, 1, 0, 1, 0, 0);
|
||||||
|
|
||||||
|
childResource2.userRelease();
|
||||||
|
assertResourceState(childResource1, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(childResource2, -1, 1, 2, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSampleUdpEncapTranform() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> spi1 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> spi2 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> transform =
|
||||||
|
getTestRefcountedResource(spi1, spi2, udpEncapSocket);
|
||||||
|
|
||||||
|
// Pretend one SPI goes out of reference (releaseManagedResource -> userRelease)
|
||||||
|
spi1.userRelease();
|
||||||
|
|
||||||
|
// User called releaseManagedResource on udpEncap socket
|
||||||
|
udpEncapSocket.userRelease();
|
||||||
|
|
||||||
|
// User dies, and binder kills the rest
|
||||||
|
spi2.binderDied();
|
||||||
|
transform.binderDied();
|
||||||
|
|
||||||
|
// Check resource states
|
||||||
|
assertResourceState(spi1, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(spi2, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(udpEncapSocket, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(transform, -1, 1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSampleDualTransformEncapSocket() throws RemoteException {
|
||||||
|
RefcountedResource<IResource> spi1 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> spi2 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> spi3 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> spi4 = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
|
||||||
|
RefcountedResource<IResource> transform1 =
|
||||||
|
getTestRefcountedResource(spi1, spi2, udpEncapSocket);
|
||||||
|
RefcountedResource<IResource> transform2 =
|
||||||
|
getTestRefcountedResource(spi3, spi4, udpEncapSocket);
|
||||||
|
|
||||||
|
// Pretend one SPIs goes out of reference (releaseManagedResource -> userRelease)
|
||||||
|
spi1.userRelease();
|
||||||
|
|
||||||
|
// User called releaseManagedResource on udpEncap socket and spi4
|
||||||
|
udpEncapSocket.userRelease();
|
||||||
|
spi4.userRelease();
|
||||||
|
|
||||||
|
// User dies, and binder kills the rest
|
||||||
|
spi2.binderDied();
|
||||||
|
spi3.binderDied();
|
||||||
|
transform2.binderDied();
|
||||||
|
transform1.binderDied();
|
||||||
|
|
||||||
|
// Check resource states
|
||||||
|
assertResourceState(spi1, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(spi2, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(spi3, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(spi4, -1, 1, 2, 1, 1);
|
||||||
|
assertResourceState(udpEncapSocket, -1, 1, 3, 1, 1);
|
||||||
|
assertResourceState(transform1, -1, 1, 1, 1, 1);
|
||||||
|
assertResourceState(transform2, -1, 1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fuzzTest() throws RemoteException {
|
||||||
|
List<RefcountedResource<IResource>> resources = new ArrayList<>();
|
||||||
|
|
||||||
|
// Build a tree of resources
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
// Choose a random number of children from the existing list
|
||||||
|
int numChildren = ThreadLocalRandom.current().nextInt(0, resources.size() + 1);
|
||||||
|
|
||||||
|
// Build a (random) list of children
|
||||||
|
Set<RefcountedResource<IResource>> children = new HashSet<>();
|
||||||
|
for (int j = 0; j < numChildren; j++) {
|
||||||
|
int childIndex = ThreadLocalRandom.current().nextInt(0, resources.size());
|
||||||
|
children.add(resources.get(childIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
RefcountedResource<IResource> newRefcountedResource =
|
||||||
|
getTestRefcountedResource(
|
||||||
|
children.toArray(new RefcountedResource[children.size()]));
|
||||||
|
resources.add(newRefcountedResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup all resources in a random order
|
||||||
|
List<RefcountedResource<IResource>> clonedResources =
|
||||||
|
new ArrayList<>(resources); // shallow copy
|
||||||
|
while (!clonedResources.isEmpty()) {
|
||||||
|
int index = ThreadLocalRandom.current().nextInt(0, clonedResources.size());
|
||||||
|
RefcountedResource<IResource> refcountedResource = clonedResources.get(index);
|
||||||
|
refcountedResource.userRelease();
|
||||||
|
clonedResources.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all resources were cleaned up properly
|
||||||
|
for (RefcountedResource<IResource> refcountedResource : resources) {
|
||||||
|
assertEquals(-1, refcountedResource.mRefCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
670
tests/unit/java/com/android/server/IpSecServiceTest.java
Normal file
670
tests/unit/java/com/android/server/IpSecServiceTest.java
Normal file
@@ -0,0 +1,670 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.server;
|
||||||
|
|
||||||
|
import static android.system.OsConstants.AF_INET;
|
||||||
|
import static android.system.OsConstants.EADDRINUSE;
|
||||||
|
import static android.system.OsConstants.IPPROTO_UDP;
|
||||||
|
import static android.system.OsConstants.SOCK_DGRAM;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.argThat;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.IpSecAlgorithm;
|
||||||
|
import android.net.IpSecConfig;
|
||||||
|
import android.net.IpSecManager;
|
||||||
|
import android.net.IpSecSpiResponse;
|
||||||
|
import android.net.IpSecUdpEncapResponse;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.system.StructStat;
|
||||||
|
import android.util.Range;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import dalvik.system.SocketTagger;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentMatcher;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecService}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class IpSecServiceTest {
|
||||||
|
|
||||||
|
private static final int DROID_SPI = 0xD1201D;
|
||||||
|
private static final int MAX_NUM_ENCAP_SOCKETS = 100;
|
||||||
|
private static final int MAX_NUM_SPIS = 100;
|
||||||
|
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
|
||||||
|
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
|
||||||
|
|
||||||
|
private static final InetAddress INADDR_ANY;
|
||||||
|
|
||||||
|
private static final byte[] AEAD_KEY = {
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||||
|
0x73, 0x61, 0x6C, 0x74
|
||||||
|
};
|
||||||
|
private static final byte[] CRYPT_KEY = {
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
|
||||||
|
};
|
||||||
|
private static final byte[] AUTH_KEY = {
|
||||||
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
||||||
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final IpSecAlgorithm AUTH_ALGO =
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
|
||||||
|
private static final IpSecAlgorithm CRYPT_ALGO =
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
|
||||||
|
private static final IpSecAlgorithm AEAD_ALGO =
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context mMockContext;
|
||||||
|
INetd mMockNetd;
|
||||||
|
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
|
||||||
|
IpSecService mIpSecService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mMockContext = mock(Context.class);
|
||||||
|
mMockNetd = mock(INetd.class);
|
||||||
|
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
|
||||||
|
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
|
||||||
|
|
||||||
|
// Injecting mock netd
|
||||||
|
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIpSecServiceCreate() throws InterruptedException {
|
||||||
|
IpSecService ipSecSrv = IpSecService.create(mMockContext);
|
||||||
|
assertNotNull(ipSecSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReleaseInvalidSecurityParameterIndex() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecService.releaseSecurityParameterIndex(1);
|
||||||
|
fail("IllegalArgumentException not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This function finds an available port */
|
||||||
|
int findUnusedPort() throws Exception {
|
||||||
|
// Get an available port.
|
||||||
|
ServerSocket s = new ServerSocket(0);
|
||||||
|
int port = s.getLocalPort();
|
||||||
|
s.close();
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
|
||||||
|
int localport = -1;
|
||||||
|
IpSecUdpEncapResponse udpEncapResp = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
|
||||||
|
localport = findUnusedPort();
|
||||||
|
|
||||||
|
udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
if (udpEncapResp.status == IpSecManager.Status.OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else retry to reduce possibility for port-bind failures.
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
assertEquals(localport, udpEncapResp.port);
|
||||||
|
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
|
||||||
|
// Verify quota and RefcountedResource objects cleaned up
|
||||||
|
IpSecService.UserRecord userRecord =
|
||||||
|
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
|
||||||
|
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
|
||||||
|
try {
|
||||||
|
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
|
||||||
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUdpEncapsulationSocketBinderDeath() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
|
||||||
|
IpSecService.UserRecord userRecord =
|
||||||
|
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
|
||||||
|
IpSecService.RefcountedResource refcountedRecord =
|
||||||
|
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
|
||||||
|
udpEncapResp.resourceId);
|
||||||
|
|
||||||
|
refcountedRecord.binderDied();
|
||||||
|
|
||||||
|
// Verify quota and RefcountedResource objects cleaned up
|
||||||
|
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
|
||||||
|
try {
|
||||||
|
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
|
||||||
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
int localport = udpEncapResp.port;
|
||||||
|
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
|
||||||
|
/** Check if localport is available. */
|
||||||
|
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
Os.bind(newSocket, INADDR_ANY, localport);
|
||||||
|
Os.close(newSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function checks if the IpSecService holds the reserved port. If
|
||||||
|
* closeUdpEncapsulationSocket is not called, the socket cleanup should not be complete.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUdpEncapPortNotReleased() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
int localport = udpEncapResp.port;
|
||||||
|
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
|
||||||
|
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
try {
|
||||||
|
Os.bind(newSocket, INADDR_ANY, localport);
|
||||||
|
fail("ErrnoException not thrown");
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
assertEquals(EADDRINUSE, e.errno);
|
||||||
|
}
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapsulationSocketOnRandomPort() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
assertNotEquals(0, udpEncapResp.port);
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapsulationSocketPortRange() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_INVALID_PORT, new Binder());
|
||||||
|
fail("IllegalArgumentException not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT_OUT_RANGE, new Binder());
|
||||||
|
fail("IllegalArgumentException not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
int localport = udpEncapResp.port;
|
||||||
|
|
||||||
|
IpSecUdpEncapResponse testUdpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
|
||||||
|
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, testUdpEncapResp.status);
|
||||||
|
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloseInvalidUdpEncapsulationSocket() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(1);
|
||||||
|
fail("IllegalArgumentException not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAuth() {
|
||||||
|
// Validate that correct algorithm type succeeds
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthentication(AUTH_ALGO);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
|
||||||
|
// Validate that incorrect algorithm types fails
|
||||||
|
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
|
||||||
|
try {
|
||||||
|
config = new IpSecConfig();
|
||||||
|
config.setAuthentication(algo);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Did not throw exception on invalid algorithm type");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsCrypt() {
|
||||||
|
// Validate that correct algorithm type succeeds
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setEncryption(CRYPT_ALGO);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
|
||||||
|
// Validate that incorrect algorithm types fails
|
||||||
|
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
|
||||||
|
try {
|
||||||
|
config = new IpSecConfig();
|
||||||
|
config.setEncryption(algo);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Did not throw exception on invalid algorithm type");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAead() {
|
||||||
|
// Validate that correct algorithm type succeeds
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthenticatedEncryption(AEAD_ALGO);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
|
||||||
|
// Validate that incorrect algorithm types fails
|
||||||
|
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
|
||||||
|
try {
|
||||||
|
config = new IpSecConfig();
|
||||||
|
config.setAuthenticatedEncryption(algo);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Did not throw exception on invalid algorithm type");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAuthCrypt() {
|
||||||
|
// Validate that correct algorithm type succeeds
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthentication(AUTH_ALGO);
|
||||||
|
config.setEncryption(CRYPT_ALGO);
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsNoAlgorithms() {
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
try {
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Expected exception; no algorithms specified");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAeadWithAuth() {
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthenticatedEncryption(AEAD_ALGO);
|
||||||
|
config.setAuthentication(AUTH_ALGO);
|
||||||
|
try {
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Expected exception; both AEAD and auth algorithm specified");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAeadWithCrypt() {
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthenticatedEncryption(AEAD_ALGO);
|
||||||
|
config.setEncryption(CRYPT_ALGO);
|
||||||
|
try {
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Expected exception; both AEAD and crypt algorithm specified");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setAuthenticatedEncryption(AEAD_ALGO);
|
||||||
|
config.setAuthentication(AUTH_ALGO);
|
||||||
|
config.setEncryption(CRYPT_ALGO);
|
||||||
|
try {
|
||||||
|
mIpSecService.validateAlgorithms(config);
|
||||||
|
fail("Expected exception; AEAD, auth and crypt algorithm specified");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteInvalidTransform() throws Exception {
|
||||||
|
try {
|
||||||
|
mIpSecService.deleteTransform(1);
|
||||||
|
fail("IllegalArgumentException not thrown");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTransportModeTransform() throws Exception {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
socket.bind(null);
|
||||||
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
|
||||||
|
mIpSecService.removeTransportModeTransforms(pfd);
|
||||||
|
|
||||||
|
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIpAddresses() throws Exception {
|
||||||
|
String[] invalidAddresses =
|
||||||
|
new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
|
||||||
|
for (String address : invalidAddresses) {
|
||||||
|
try {
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
mIpSecService.allocateSecurityParameterIndex(
|
||||||
|
address, DROID_SPI, new Binder());
|
||||||
|
fail("Invalid address was passed through IpSecService validation: " + address);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(
|
||||||
|
"Invalid InetAddress was not caught in validation: "
|
||||||
|
+ address
|
||||||
|
+ ", Exception: "
|
||||||
|
+ e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function checks if the number of encap UDP socket that one UID can reserve has a
|
||||||
|
* reasonable limit.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSocketResourceTrackerLimitation() throws Exception {
|
||||||
|
List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
|
||||||
|
// Reserve sockets until it fails.
|
||||||
|
for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
|
||||||
|
IpSecUdpEncapResponse newUdpEncapSocket =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(newUdpEncapSocket);
|
||||||
|
if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
openUdpEncapSockets.add(newUdpEncapSocket);
|
||||||
|
}
|
||||||
|
// Assert that the total sockets quota has a reasonable limit.
|
||||||
|
assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
|
||||||
|
assertTrue(
|
||||||
|
"Number of open UDP encap sockets is out of bound",
|
||||||
|
openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
|
||||||
|
|
||||||
|
// Try to reserve one more UDP encapsulation socket, and should fail.
|
||||||
|
IpSecUdpEncapResponse extraUdpEncapSocket =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(extraUdpEncapSocket);
|
||||||
|
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
|
||||||
|
|
||||||
|
// Close one of the open UDP encapsulation sockets.
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
|
||||||
|
openUdpEncapSockets.get(0).fileDescriptor.close();
|
||||||
|
openUdpEncapSockets.remove(0);
|
||||||
|
|
||||||
|
// Try to reserve one more UDP encapsulation socket, and should be successful.
|
||||||
|
extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(extraUdpEncapSocket);
|
||||||
|
assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
|
||||||
|
openUdpEncapSockets.add(extraUdpEncapSocket);
|
||||||
|
|
||||||
|
// Close open UDP sockets.
|
||||||
|
for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
|
||||||
|
openSocket.fileDescriptor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function checks if the number of SPI that one UID can reserve has a reasonable limit.
|
||||||
|
* This test does not test for both address families or duplicate SPIs because resource tracking
|
||||||
|
* code does not depend on them.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSpiResourceTrackerLimitation() throws Exception {
|
||||||
|
List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
|
||||||
|
// Return the same SPI for all SPI allocation since IpSecService only
|
||||||
|
// tracks the resource ID.
|
||||||
|
when(mMockNetd.ipSecAllocateSpi(
|
||||||
|
anyInt(),
|
||||||
|
anyString(),
|
||||||
|
eq(InetAddress.getLoopbackAddress().getHostAddress()),
|
||||||
|
anyInt()))
|
||||||
|
.thenReturn(DROID_SPI);
|
||||||
|
// Reserve spis until it fails.
|
||||||
|
for (int i = 0; i < MAX_NUM_SPIS; i++) {
|
||||||
|
IpSecSpiResponse newSpi =
|
||||||
|
mIpSecService.allocateSecurityParameterIndex(
|
||||||
|
InetAddress.getLoopbackAddress().getHostAddress(),
|
||||||
|
DROID_SPI + i,
|
||||||
|
new Binder());
|
||||||
|
assertNotNull(newSpi);
|
||||||
|
if (IpSecManager.Status.OK != newSpi.status) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reservedSpis.add(newSpi);
|
||||||
|
}
|
||||||
|
// Assert that the SPI quota has a reasonable limit.
|
||||||
|
assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
|
||||||
|
|
||||||
|
// Try to reserve one more SPI, and should fail.
|
||||||
|
IpSecSpiResponse extraSpi =
|
||||||
|
mIpSecService.allocateSecurityParameterIndex(
|
||||||
|
InetAddress.getLoopbackAddress().getHostAddress(),
|
||||||
|
DROID_SPI + MAX_NUM_SPIS,
|
||||||
|
new Binder());
|
||||||
|
assertNotNull(extraSpi);
|
||||||
|
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
|
||||||
|
|
||||||
|
// Release one reserved spi.
|
||||||
|
mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
|
||||||
|
reservedSpis.remove(0);
|
||||||
|
|
||||||
|
// Should successfully reserve one more spi.
|
||||||
|
extraSpi =
|
||||||
|
mIpSecService.allocateSecurityParameterIndex(
|
||||||
|
InetAddress.getLoopbackAddress().getHostAddress(),
|
||||||
|
DROID_SPI + MAX_NUM_SPIS,
|
||||||
|
new Binder());
|
||||||
|
assertNotNull(extraSpi);
|
||||||
|
assertEquals(IpSecManager.Status.OK, extraSpi.status);
|
||||||
|
|
||||||
|
// Release reserved SPIs.
|
||||||
|
for (IpSecSpiResponse spiResp : reservedSpis) {
|
||||||
|
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUidFdtagger() throws Exception {
|
||||||
|
SocketTagger actualSocketTagger = SocketTagger.get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
|
||||||
|
// Has to be done after socket creation because BlockGuardOS calls tag on new sockets
|
||||||
|
SocketTagger mockSocketTagger = mock(SocketTagger.class);
|
||||||
|
SocketTagger.set(mockSocketTagger);
|
||||||
|
|
||||||
|
mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
|
||||||
|
verify(mockSocketTagger).tag(eq(sockFd));
|
||||||
|
} finally {
|
||||||
|
SocketTagger.set(actualSocketTagger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if two file descriptors point to the same file.
|
||||||
|
*
|
||||||
|
* <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
|
||||||
|
* file descriptors is to check their inode and device. These two entries uniquely identify any
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
|
||||||
|
try {
|
||||||
|
StructStat fd1Stat = Os.fstat(fd1);
|
||||||
|
StructStat fd2Stat = Os.fstat(fd2);
|
||||||
|
|
||||||
|
return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapSocketTagsSocket() throws Exception {
|
||||||
|
IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
|
||||||
|
IpSecService testIpSecService = new IpSecService(
|
||||||
|
mMockContext, mMockIpSecSrvConfig, mockTagger);
|
||||||
|
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
testIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
assertNotNull(udpEncapResp);
|
||||||
|
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
|
||||||
|
|
||||||
|
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
|
||||||
|
ArgumentMatcher<FileDescriptor> fdMatcher =
|
||||||
|
(argFd) -> {
|
||||||
|
return fileDescriptorsEqual(sockFd, argFd);
|
||||||
|
};
|
||||||
|
verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
|
||||||
|
|
||||||
|
testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
udpEncapResp.fileDescriptor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
|
||||||
|
IpSecUdpEncapResponse udpEncapResp =
|
||||||
|
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
||||||
|
|
||||||
|
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
|
||||||
|
ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
|
||||||
|
try {
|
||||||
|
StructStat sockStat = Os.fstat(sockFd);
|
||||||
|
StructStat argStat = Os.fstat(arg.getFileDescriptor());
|
||||||
|
|
||||||
|
return sockStat.st_ino == argStat.st_ino
|
||||||
|
&& sockStat.st_dev == argStat.st_dev;
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
|
||||||
|
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReserveNetId() {
|
||||||
|
final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
|
||||||
|
for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
|
||||||
|
assertEquals(netId, mIpSecService.reserveNetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that resource exhaustion triggers an exception
|
||||||
|
try {
|
||||||
|
mIpSecService.reserveNetId();
|
||||||
|
fail("Did not throw error for all netIds reserved");
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now release one and try again
|
||||||
|
int releasedNetId =
|
||||||
|
netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
|
||||||
|
mIpSecService.releaseNetId(releasedNetId);
|
||||||
|
assertEquals(releasedNetId, mIpSecService.reserveNetId());
|
||||||
|
}
|
||||||
|
}
|
||||||
197
tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
Normal file
197
tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Don't warn about deprecated types anywhere in this test, because LegacyTypeTracker's very reason
|
||||||
|
// for existence is to power deprecated APIs. The annotation has to apply to the whole file because
|
||||||
|
// otherwise warnings will be generated by the imports of deprecated constants like TYPE_xxx.
|
||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package com.android.server
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.FEATURE_WIFI
|
||||||
|
import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
|
||||||
|
import android.net.ConnectivityManager.TYPE_ETHERNET
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_CBS
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_DUN
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_IA
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_IMS
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_MMS
|
||||||
|
import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
|
||||||
|
import android.net.ConnectivityManager.TYPE_VPN
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIFI
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIFI_P2P
|
||||||
|
import android.net.ConnectivityManager.TYPE_WIMAX
|
||||||
|
import android.net.EthernetManager
|
||||||
|
import android.net.NetworkInfo.DetailedState.CONNECTED
|
||||||
|
import android.net.NetworkInfo.DetailedState.DISCONNECTED
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.server.ConnectivityService.LegacyTypeTracker
|
||||||
|
import com.android.server.connectivity.NetworkAgentInfo
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Assert.assertSame
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.reset
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
const val UNSUPPORTED_TYPE = TYPE_WIMAX
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class LegacyTypeTrackerTest {
|
||||||
|
private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
|
||||||
|
TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
|
||||||
|
TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
|
||||||
|
TYPE_MOBILE_EMERGENCY, TYPE_VPN)
|
||||||
|
|
||||||
|
private val mMockService = mock(ConnectivityService::class.java).apply {
|
||||||
|
doReturn(false).`when`(this).isDefaultNetwork(any())
|
||||||
|
}
|
||||||
|
private val mPm = mock(PackageManager::class.java)
|
||||||
|
private val mContext = mock(Context::class.java).apply {
|
||||||
|
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
|
||||||
|
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
|
||||||
|
doReturn(mPm).`when`(this).packageManager
|
||||||
|
doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
|
||||||
|
Context.ETHERNET_SERVICE)
|
||||||
|
}
|
||||||
|
private val mTm = mock(TelephonyManager::class.java).apply {
|
||||||
|
doReturn(true).`when`(this).isDataCapable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
|
||||||
|
loadSupportedTypes(mContext, mTm)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSupportedTypes() {
|
||||||
|
val tracker = makeTracker()
|
||||||
|
supportedTypes.forEach {
|
||||||
|
assertTrue(tracker.isTypeSupported(it))
|
||||||
|
}
|
||||||
|
assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSupportedTypes_NoEthernet() {
|
||||||
|
doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
|
||||||
|
assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSupportedTypes_NoTelephony() {
|
||||||
|
doReturn(false).`when`(mTm).isDataCapable
|
||||||
|
val tracker = makeTracker()
|
||||||
|
val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
|
||||||
|
nonMobileTypes.forEach {
|
||||||
|
assertTrue(tracker.isTypeSupported(it))
|
||||||
|
}
|
||||||
|
supportedTypes.toSet().minus(nonMobileTypes).forEach {
|
||||||
|
assertFalse(tracker.isTypeSupported(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSupportedTypes_NoWifiDirect() {
|
||||||
|
doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
|
||||||
|
val tracker = makeTracker()
|
||||||
|
assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
|
||||||
|
supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
|
||||||
|
assertTrue(tracker.isTypeSupported(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSupl() {
|
||||||
|
val tracker = makeTracker()
|
||||||
|
val mobileNai = mock(NetworkAgentInfo::class.java)
|
||||||
|
tracker.add(TYPE_MOBILE, mobileNai)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
|
||||||
|
reset(mMockService)
|
||||||
|
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
|
||||||
|
reset(mMockService)
|
||||||
|
tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
|
||||||
|
reset(mMockService)
|
||||||
|
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
|
||||||
|
reset(mMockService)
|
||||||
|
tracker.remove(mobileNai, false)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddNetwork() {
|
||||||
|
val tracker = makeTracker()
|
||||||
|
val mobileNai = mock(NetworkAgentInfo::class.java)
|
||||||
|
val wifiNai = mock(NetworkAgentInfo::class.java)
|
||||||
|
tracker.add(TYPE_MOBILE, mobileNai)
|
||||||
|
tracker.add(TYPE_WIFI, wifiNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
|
||||||
|
// Make sure adding a second NAI does not change the results.
|
||||||
|
val secondMobileNai = mock(NetworkAgentInfo::class.java)
|
||||||
|
tracker.add(TYPE_MOBILE, secondMobileNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
|
||||||
|
// Make sure removing a network that wasn't added for this type is a no-op.
|
||||||
|
tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
|
||||||
|
// Remove the top network for mobile and make sure the second one becomes the network
|
||||||
|
// of record for this type.
|
||||||
|
tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
|
||||||
|
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
|
||||||
|
// Make sure adding a network for an unsupported type does not register it.
|
||||||
|
tracker.add(UNSUPPORTED_TYPE, mobileNai)
|
||||||
|
assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBroadcastOnDisconnect() {
|
||||||
|
val tracker = makeTracker()
|
||||||
|
val mobileNai1 = mock(NetworkAgentInfo::class.java)
|
||||||
|
val mobileNai2 = mock(NetworkAgentInfo::class.java)
|
||||||
|
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
|
||||||
|
tracker.add(TYPE_MOBILE, mobileNai1)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
|
||||||
|
reset(mMockService)
|
||||||
|
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
|
||||||
|
tracker.add(TYPE_MOBILE, mobileNai2)
|
||||||
|
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
|
||||||
|
tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
|
||||||
|
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
|
||||||
|
}
|
||||||
|
}
|
||||||
53
tests/unit/java/com/android/server/NetIdManagerTest.kt
Normal file
53
tests/unit/java/com/android/server/NetIdManagerTest.kt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.server
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.server.NetIdManager.MIN_NET_ID
|
||||||
|
import com.android.testutils.assertThrows
|
||||||
|
import com.android.testutils.ExceptionUtils.ThrowingRunnable
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NetIdManagerTest {
|
||||||
|
@Test
|
||||||
|
fun testReserveReleaseNetId() {
|
||||||
|
val manager = NetIdManager(MIN_NET_ID + 4)
|
||||||
|
assertEquals(MIN_NET_ID, manager.reserveNetId())
|
||||||
|
assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
|
||||||
|
assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
|
||||||
|
assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
|
||||||
|
|
||||||
|
manager.releaseNetId(MIN_NET_ID + 1)
|
||||||
|
manager.releaseNetId(MIN_NET_ID + 3)
|
||||||
|
// IDs only loop once there is no higher ID available
|
||||||
|
assertEquals(MIN_NET_ID + 4, manager.reserveNetId())
|
||||||
|
assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
|
||||||
|
assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
|
||||||
|
assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
|
||||||
|
manager.releaseNetId(MIN_NET_ID + 5)
|
||||||
|
// Still no ID available: MIN_NET_ID + 5 was not reserved
|
||||||
|
assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
|
||||||
|
manager.releaseNetId(MIN_NET_ID + 2)
|
||||||
|
// Throwing an exception still leaves the manager in a working state
|
||||||
|
assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.server;
|
||||||
|
|
||||||
|
import static android.util.DebugUtils.valueToString;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.INetdUnsolicitedEventListener;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.NetworkPolicyManager;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.app.IBatteryStats;
|
||||||
|
import com.android.server.NetworkManagementService.Dependencies;
|
||||||
|
import com.android.server.net.BaseNetworkObserver;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link NetworkManagementService}.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class NetworkManagementServiceTest {
|
||||||
|
private NetworkManagementService mNMService;
|
||||||
|
@Mock private Context mContext;
|
||||||
|
@Mock private IBatteryStats.Stub mBatteryStatsService;
|
||||||
|
@Mock private INetd.Stub mNetdService;
|
||||||
|
|
||||||
|
private static final int TEST_UID = 111;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
|
||||||
|
|
||||||
|
private final MockDependencies mDeps = new MockDependencies();
|
||||||
|
|
||||||
|
private final class MockDependencies extends Dependencies {
|
||||||
|
@Override
|
||||||
|
public IBinder getService(String name) {
|
||||||
|
switch (name) {
|
||||||
|
case BatteryStats.SERVICE_NAME:
|
||||||
|
return mBatteryStatsService;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unknown service " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerLocalService(NetworkManagementInternal nmi) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public INetd getNetd() {
|
||||||
|
return mNetdService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCallingUid() {
|
||||||
|
return Process.SYSTEM_UID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
doNothing().when(mNetdService)
|
||||||
|
.registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
|
||||||
|
// Start the service and wait until it connects to our socket.
|
||||||
|
mNMService = NetworkManagementService.create(mContext, mDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
mNMService.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T expectSoon(T mock) {
|
||||||
|
return verify(mock, timeout(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that network observers work properly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNetworkObservers() throws Exception {
|
||||||
|
BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
|
||||||
|
doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver.
|
||||||
|
mNMService.registerObserver(observer);
|
||||||
|
|
||||||
|
// Forget everything that happened to the mock so far, so we can explicitly verify
|
||||||
|
// everything that happens and does not happen to it from now on.
|
||||||
|
|
||||||
|
INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
|
||||||
|
reset(observer);
|
||||||
|
// Now call unsolListener methods and ensure that the observer methods are
|
||||||
|
// called. After every method we expect a callback soon after; to ensure that
|
||||||
|
// invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface changes.
|
||||||
|
*/
|
||||||
|
unsolListener.onInterfaceAdded("rmnet12");
|
||||||
|
expectSoon(observer).interfaceAdded("rmnet12");
|
||||||
|
|
||||||
|
unsolListener.onInterfaceRemoved("eth1");
|
||||||
|
expectSoon(observer).interfaceRemoved("eth1");
|
||||||
|
|
||||||
|
unsolListener.onInterfaceChanged("clat4", true);
|
||||||
|
expectSoon(observer).interfaceStatusChanged("clat4", true);
|
||||||
|
|
||||||
|
unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
|
||||||
|
expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bandwidth control events.
|
||||||
|
*/
|
||||||
|
unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
|
||||||
|
expectSoon(observer).limitReached("data", "rmnet_usb0");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface class activity.
|
||||||
|
*/
|
||||||
|
unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
|
||||||
|
expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
|
||||||
|
|
||||||
|
unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
|
||||||
|
expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
|
||||||
|
|
||||||
|
unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
|
||||||
|
expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP address changes.
|
||||||
|
*/
|
||||||
|
unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
|
||||||
|
expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
|
||||||
|
|
||||||
|
unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
|
||||||
|
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
|
||||||
|
|
||||||
|
unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
|
||||||
|
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNS information broadcasts.
|
||||||
|
*/
|
||||||
|
unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
|
||||||
|
expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
|
||||||
|
new String[]{"2001:db8::1"});
|
||||||
|
|
||||||
|
unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
|
||||||
|
new String[]{"2001:db8::1", "2001:db8::2"});
|
||||||
|
expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
|
||||||
|
new String[]{"2001:db8::1", "2001:db8::2"});
|
||||||
|
|
||||||
|
// We don't check for negative lifetimes, only for parse errors.
|
||||||
|
unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
|
||||||
|
expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
|
||||||
|
new String[]{"::1"});
|
||||||
|
|
||||||
|
// No syntax checking on the addresses.
|
||||||
|
unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
|
||||||
|
new String[]{"", "::", "", "foo", "::1"});
|
||||||
|
expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
|
||||||
|
new String[]{"", "::", "", "foo", "::1"});
|
||||||
|
|
||||||
|
// Make sure nothing else was called.
|
||||||
|
verifyNoMoreInteractions(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirewallEnabled() {
|
||||||
|
mNMService.setFirewallEnabled(true);
|
||||||
|
assertTrue(mNMService.isFirewallEnabled());
|
||||||
|
|
||||||
|
mNMService.setFirewallEnabled(false);
|
||||||
|
assertFalse(mNMService.isFirewallEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkRestrictedDefault() {
|
||||||
|
assertFalse(mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMeteredNetworkRestrictions() throws RemoteException {
|
||||||
|
// Make sure the mocked netd method returns true.
|
||||||
|
doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
|
||||||
|
|
||||||
|
// Restrict usage of mobile data in background
|
||||||
|
mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
|
||||||
|
assertTrue("Should be true since mobile data usage is restricted",
|
||||||
|
mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
|
||||||
|
mNMService.setDataSaverModeEnabled(true);
|
||||||
|
verify(mNetdService).bandwidthEnableDataSaver(true);
|
||||||
|
|
||||||
|
mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
|
||||||
|
assertTrue("Should be true since data saver is on and the uid is not allowlisted",
|
||||||
|
mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
|
||||||
|
mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
|
||||||
|
assertFalse("Should be false since data saver is on and the uid is allowlisted",
|
||||||
|
mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
|
||||||
|
// remove uid from allowlist and turn datasaver off again
|
||||||
|
mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
|
||||||
|
mNMService.setDataSaverModeEnabled(false);
|
||||||
|
verify(mNetdService).bandwidthEnableDataSaver(false);
|
||||||
|
assertFalse("Network should not be restricted when data saver is off",
|
||||||
|
mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirewallChains() {
|
||||||
|
final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
|
||||||
|
// Dozable chain
|
||||||
|
final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
|
||||||
|
isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
|
||||||
|
isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
|
||||||
|
isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
|
||||||
|
expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
|
||||||
|
// Powersaver chain
|
||||||
|
final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
|
||||||
|
isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
|
||||||
|
isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
|
||||||
|
isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
|
||||||
|
expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
|
||||||
|
// Standby chain
|
||||||
|
final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
|
||||||
|
isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
|
||||||
|
isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
|
||||||
|
isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
|
||||||
|
expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
|
||||||
|
// Restricted mode chain
|
||||||
|
final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
|
||||||
|
isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
|
||||||
|
isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
|
||||||
|
isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
|
||||||
|
expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
|
||||||
|
|
||||||
|
final int[] chains = {
|
||||||
|
INetd.FIREWALL_CHAIN_STANDBY,
|
||||||
|
INetd.FIREWALL_CHAIN_POWERSAVE,
|
||||||
|
INetd.FIREWALL_CHAIN_DOZABLE,
|
||||||
|
INetd.FIREWALL_CHAIN_RESTRICTED
|
||||||
|
};
|
||||||
|
final int[] states = {
|
||||||
|
INetd.FIREWALL_RULE_ALLOW,
|
||||||
|
INetd.FIREWALL_RULE_DENY,
|
||||||
|
NetworkPolicyManager.FIREWALL_RULE_DEFAULT
|
||||||
|
};
|
||||||
|
BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
|
||||||
|
return String.format("Unexpected value for chain: %s and state: %s",
|
||||||
|
valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
|
||||||
|
valueToString(INetd.class, "FIREWALL_RULE_", state));
|
||||||
|
};
|
||||||
|
for (int chain : chains) {
|
||||||
|
final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
|
||||||
|
mNMService.setFirewallChainEnabled(chain, true);
|
||||||
|
for (int state : states) {
|
||||||
|
mNMService.setFirewallUidRule(chain, TEST_UID, state);
|
||||||
|
assertEquals(errorMsg.apply(chain, state),
|
||||||
|
expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
|
||||||
|
}
|
||||||
|
mNMService.setFirewallChainEnabled(chain, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user