OSDN Git Service

wifi: add test target/directory for unit testing WiFi framework APIs
authorPeter Qiu <zqiu@google.com>
Mon, 26 Sep 2016 20:14:13 +0000 (13:14 -0700)
committerPeter Qiu <zqiu@google.com>
Tue, 27 Sep 2016 22:13:20 +0000 (15:13 -0700)
The existing tests for the WiFi frameworks API android.net.wifi are
copied from frameworks/opt/wifi/tests, and will be removed in
frameworks/opt/wifi/tests.

Bug: 31745421
Change-Id: I789e983bc7dd02b6c3fa6a982ca671347912be0f
Test: frameworks/base/wifi/runtests.sh

wifi/tests/Android.mk [new file with mode: 0644]
wifi/tests/AndroidManifest.xml [new file with mode: 0644]
wifi/tests/README.md [new file with mode: 0644]
wifi/tests/runtests.sh [new file with mode: 0755]
wifi/tests/src/android/net/wifi/FakeKeys.java [new file with mode: 0644]
wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java [new file with mode: 0644]
wifi/tests/src/android/net/wifi/WifiScannerTest.java [new file with mode: 0644]

diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
new file mode 100644 (file)
index 0000000..5850fee
--- /dev/null
@@ -0,0 +1,61 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Make test APK
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+# This list is generated from the java source files in this module
+# The list is a comma separated list of class names with * matching zero or more characters.
+# Example:
+#   Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
+#   Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
+
+# Filter all src files to just java files
+local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
+# Transform java file names into full class names.
+# This only works if the class name matches the file name and the directory structure
+# matches the package.
+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
+# Utility variables to allow replacing a space with a comma
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+# These patterns will match all classes in this module and their inner classes.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+jacoco_include := android.net.wifi.*
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+       android-support-test \
+       mockito-target-minus-junit4 \
+       frameworks-base-testutils \
+
+LOCAL_JAVA_LIBRARIES := \
+       android.test.runner \
+
+LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+
+include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..4eaca2b
--- /dev/null
@@ -0,0 +1,38 @@
+<?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="android.net.wifi.test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:label="WifiTestDummyLabel"
+                  android:name="WifiTestDummyName">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.net.wifi.test"
+        android:label="Frameworks Wifi API Tests">
+    </instrumentation>
+
+</manifest>
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
new file mode 100644 (file)
index 0000000..b418abd
--- /dev/null
@@ -0,0 +1,50 @@
+# Wifi Unit Tests
+This package contains unit tests for the android wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+frameworks/base/wifi/tests/runtests.sh
+```
+
+`runtests.sh` will build the test project and all of its dependencies and push the APK to the
+connected device. It will then run the tests on the device.
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+See below for a few example of options to limit which tests are run.
+See the
+[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
+for more details on the supported options.
+
+```
+runtests.sh -e package android.net.wifi
+runtests.sh -e class android.net.wifi.WifiScannerTest
+```
+
+If you manually build and push the test APK to the device you can run tests using
+
+```
+adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+```
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
new file mode 100755 (executable)
index 0000000..ebcc2a2
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+echo "Running tests"
+
+set -e # fail early
+
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
+# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
+#      caller.
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
+
+set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
+
+adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java
new file mode 100644 (file)
index 0000000..0c73070
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.wifi;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+/**
+ * A class containing test certificates.
+ */
+public class FakeKeys {
+    private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" +
+            "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" +
+            "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" +
+            "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" +
+            "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" +
+            "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" +
+            "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" +
+            "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" +
+            "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" +
+            "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" +
+            "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" +
+            "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING);
+
+    private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" +
+            "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" +
+            "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" +
+            "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" +
+            "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" +
+            "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" +
+            "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" +
+            "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" +
+            "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" +
+            "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" +
+            "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" +
+            "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+
+
+    private static X509Certificate loadCertificate(String blob) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8));
+
+            return (X509Certificate) certFactory.generateCertificate(stream);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
new file mode 100644 (file)
index 0000000..0d964b7
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiEnterpriseConfig.Eap;
+import android.net.wifi.WifiEnterpriseConfig.Phase2;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.cert.X509Certificate;
+
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
+ */
+@SmallTest
+public class WifiEnterpriseConfigTest {
+    // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant.
+    public static final String KEYSTORE_URI = "keystore://";
+    public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+    public static final String KEYSTORES_URI = "keystores://";
+
+    private WifiEnterpriseConfig mEnterpriseConfig;
+
+    @Before
+    public void setUp() throws Exception {
+        mEnterpriseConfig = new WifiEnterpriseConfig();
+    }
+
+    @Test
+    public void testGetEmptyCaCertificate() {
+        // A newly-constructed WifiEnterpriseConfig object should have no CA certificate.
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to null explicitly.
+        mEnterpriseConfig.setCaCertificate(null);
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        // Setting CA certificate to null using setCaCertificates().
+        mEnterpriseConfig.setCaCertificates(null);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to zero-length array.
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[0]);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+    }
+
+    @Test
+    public void testSetGetSingleCaCertificate() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        mEnterpriseConfig.setCaCertificate(cert0);
+        assertEquals(mEnterpriseConfig.getCaCertificate(), cert0);
+    }
+
+    @Test
+    public void testSetGetMultipleCaCertificates() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        X509Certificate cert1 = FakeKeys.CA_CERT1;
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1});
+        X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+        assertEquals(result.length, 2);
+        assertTrue(result[0] == cert0 && result[1] == cert1);
+    }
+
+    @Test
+    public void testSaveSingleCaCertificateAlias() {
+        final String alias = "single_alias 0";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
+        assertEquals(getCaCertField(), CA_CERT_PREFIX + alias);
+    }
+
+    @Test
+    public void testLoadSingleCaCertificateAlias() {
+        final String alias = "single_alias 1";
+        setCaCertField(CA_CERT_PREFIX + alias);
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 1);
+        assertEquals(aliases[0], alias);
+    }
+
+    @Test
+    public void testSaveMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1});
+        assertEquals(getCaCertField(), String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+    }
+
+    @Test
+    public void testLoadMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        setCaCertField(String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 2);
+        assertEquals(aliases[0], alias0);
+        assertEquals(aliases[1], alias1);
+    }
+
+    private String getCaCertField() {
+        return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY);
+    }
+
+    private void setCaCertField(String value) {
+        mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value);
+    }
+
+    // Retrieves the value for a specific key supplied to wpa_supplicant.
+    private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver {
+        private String mValue = null;
+        private String mKey;
+
+        SupplicantConfigExtractor(String key) {
+            mKey = key;
+        }
+
+        @Override
+        public boolean saveValue(String key, String value) {
+            if (key.equals(mKey)) {
+                mValue = value;
+            }
+            return true;
+        }
+
+        public String getValue() {
+            return mValue;
+        }
+    }
+
+    private String getSupplicantEapMethod() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.EAP_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    private String getSupplicantPhase2Method() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.PHASE2_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    /** Verifies the default value for EAP outer and inner methods */
+    @Test
+    public void eapInnerDefault() {
+        assertEquals(null, getSupplicantEapMethod());
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verifies that the EAP inner method is reset when we switch to TLS */
+    @Test
+    public void eapPhase2MethodForTls() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to another type which supports a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to TLS which does not support a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TLS);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */
+    @Test
+    public void eapPhase2None() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the phase2 method to NONE and ensure the value is cleared.
+        mEnterpriseConfig.setPhase2Method(Phase2.NONE);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */
+    @Test
+    public void peapGtcToTtls() {
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */
+    @Test
+    public void ttlsGtcToPeap() {
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the copy constructor preseves the inner method information. */
+    @Test
+    public void copyConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
+    @Test
+    public void parcelConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        Parcel parcel = Parcel.obtain();
+        enterpriseConfig.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
+        mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verifies proper operation of the getKeyId() method. */
+    @Test
+    public void getKeyId() {
+        assertEquals("NULL", mEnterpriseConfig.getKeyId(null));
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig));
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig));
+    }
+
+    /** Verifies that passwords are not displayed in toString. */
+    @Test
+    public void passwordNotInToString() {
+        String password = "supersecret";
+        mEnterpriseConfig.setPassword(password);
+        assertFalse(mEnterpriseConfig.toString().contains(password));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
new file mode 100644 (file)
index 0000000..a829eb9
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.validateMockitoUsage;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiScanner.BssidInfo;
+import android.net.wifi.WifiScanner.BssidListener;
+import android.os.Handler;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.util.test.BidirectionalAsyncChannelServer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiScanner}.
+ */
+@SmallTest
+public class WifiScannerTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private IWifiScanner mService;
+    @Mock
+    private BssidListener mBssidListener;
+
+    private WifiScanner mWifiScanner;
+    private TestLooper mLooper;
+    private Handler mHandler;
+
+    /**
+     * Setup before tests.
+     */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLooper = new TestLooper();
+        mHandler = mock(Handler.class);
+        BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
+                mContext, mLooper.getLooper(), mHandler);
+        when(mService.getMessenger()).thenReturn(server.getMessenger());
+        mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
+        mLooper.dispatchAll();
+    }
+
+    /**
+     * Clean up after tests.
+     */
+    @After
+    public void cleanup() {
+        validateMockitoUsage();
+    }
+
+    private void verifySetHotlistMessage(Handler handler) {
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture());
+        assertEquals("message.what is not CMD_SET_HOTLIST",
+                WifiScanner.CMD_SET_HOTLIST,
+                messageCaptor.getValue().what);
+    }
+
+    /**
+     * Test duplicate listeners for bssid tracking.
+     */
+    @Test
+    public void testStartTrackingBssidsDuplicateListeners() throws Exception {
+        BssidInfo[] bssids = new BssidInfo[] {
+                new BssidInfo()
+        };
+
+        // First start tracking succeeds.
+        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+        mLooper.dispatchAll();
+        verifySetHotlistMessage(mHandler);
+
+        // Second start tracking should fail.
+        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+        mLooper.dispatchAll();
+        verify(mBssidListener).onFailure(eq(WifiScanner.REASON_DUPLICATE_REQEUST), anyString());
+    }
+}