diff options
author | Robert Quattlebaum <rquattle@google.com> | 2017-06-07 18:42:45 -0700 |
---|---|---|
committer | Robert Quattlebaum <rquattle@google.com> | 2017-07-10 11:08:29 -0700 |
commit | 03ffec0969af9e9d42a73f5da2660a45cd9f6a64 (patch) | |
tree | e7fcbdc000f7f4731a0dbff3bd18f9c1579b4732 | |
parent | ff09314508b3d24d34ebb8658735f9a19ed8005c (diff) |
android.net.lowpan: Added basic unit tests.
This change has all of the bits for supporting LoWPAN unit tests.
Additional tests are being written to improve code coverage, but this
seems like a good start.
Bug: b/33073713
Test: Successfully ran enclosed unit tests
Change-Id: Ib3750be5052bf1a90bf871756e9121b047d3871f
-rw-r--r-- | lowpan/Android.mk | 2 | ||||
-rw-r--r-- | lowpan/tests/Android.mk | 65 | ||||
-rw-r--r-- | lowpan/tests/AndroidManifest.xml | 38 | ||||
-rw-r--r-- | lowpan/tests/AndroidTest.xml | 27 | ||||
-rw-r--r-- | lowpan/tests/README.md | 50 | ||||
-rwxr-xr-x | lowpan/tests/runtests.sh | 24 | ||||
-rw-r--r-- | lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java | 97 | ||||
-rw-r--r-- | lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java | 176 |
8 files changed, 479 insertions, 0 deletions
diff --git a/lowpan/Android.mk b/lowpan/Android.mk index 9e9164f51513..0079958d5b83 100644 --- a/lowpan/Android.mk +++ b/lowpan/Android.mk @@ -28,4 +28,6 @@ LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java LOCAL_AIDL_INCLUDES += frameworks/base/core/java LOCAL_SRC_FILES += $(call all-Iaidl-files-under, java/android/net/lowpan) include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) endif diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk new file mode 100644 index 000000000000..bb0a944b5e7d --- /dev/null +++ b/lowpan/tests/Android.mk @@ -0,0 +1,65 @@ +# 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. + +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/lowpan/Test.java src/com/android/server/lowpan/AnotherTest.java +# Generated exclude list: com.android.server.lowpan.Test*,com.android.server.lowpan.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.lowpan.* + +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include) +LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + guava \ + mockito-target-minus-junit4 \ + frameworks-base-testutils \ + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + +LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests +LOCAL_COMPATIBILITY_SUITE := device-tests + +LOCAL_CERTIFICATE := platform +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +include $(BUILD_PACKAGE) diff --git a/lowpan/tests/AndroidManifest.xml b/lowpan/tests/AndroidManifest.xml new file mode 100644 index 000000000000..a21621423e41 --- /dev/null +++ b/lowpan/tests/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?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 + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.net.lowpan.test"> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="LowpanTestDummyLabel" + android:name="LowpanTestDummyName"> + <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.lowpan.test" + android:label="Frameworks LoWPAN API Tests"> + </instrumentation> + +</manifest> diff --git a/lowpan/tests/AndroidTest.xml b/lowpan/tests/AndroidTest.xml new file mode 100644 index 000000000000..72ad050efaeb --- /dev/null +++ b/lowpan/tests/AndroidTest.xml @@ -0,0 +1,27 @@ +<?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 LoWPAN API Tests."> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="FrameworksLowpanApiTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-tag" value="FrameworksLowpanApiTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.net.lowpan.test" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + </test> +</configuration> diff --git a/lowpan/tests/README.md b/lowpan/tests/README.md new file mode 100644 index 000000000000..d0eed95739a3 --- /dev/null +++ b/lowpan/tests/README.md @@ -0,0 +1,50 @@ +# LoWPAN Unit Tests +This package contains unit tests for the android LoWPAN framework System 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/lowpan/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.lowpan +runtests.sh -e class android.net.lowpan.LowpanManagerTest +``` + +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/lowpan/tests/runtests.sh b/lowpan/tests/runtests.sh new file mode 100755 index 000000000000..040f4f0492e9 --- /dev/null +++ b/lowpan/tests/runtests.sh @@ -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/lowpan/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-lowpan-tests + +set -x # print commands + +adb root +adb wait-for-device + +adb install -r -g "$OUT/data/app/FrameworksLowpanApiTests/FrameworksLowpanApiTests.apk" + +adb shell am instrument -w "$@" 'android.net.lowpan.test/android.support.test.runner.AndroidJUnitRunner' diff --git a/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java b/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java new file mode 100644 index 000000000000..455ee08547bf --- /dev/null +++ b/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java @@ -0,0 +1,97 @@ +/* + * 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.lowpan; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.*; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Handler; +import android.os.IBinder; +import android.os.test.TestLooper; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import java.util.Map; +import java.util.HashMap; + +/** Unit tests for android.net.lowpan.LowpanInterface. */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanInterfaceTest { + private static final String TEST_PACKAGE_NAME = "TestPackage"; + + @Mock Context mContext; + @Mock ILowpanInterface mLowpanInterfaceService; + @Mock IBinder mLowpanInterfaceBinder; + @Mock ApplicationInfo mApplicationInfo; + @Mock IBinder mAppBinder; + @Mock LowpanInterface.Callback mLowpanInterfaceCallback; + + private Handler mHandler; + private final TestLooper mTestLooper = new TestLooper(); + private ILowpanInterfaceListener mInterfaceListener; + private LowpanInterface mLowpanInterface; + private Map<String, Object> mPropertyMap; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); + when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(mLowpanInterfaceService.getName()).thenReturn("wpan0"); + when(mLowpanInterfaceService.asBinder()).thenReturn(mLowpanInterfaceBinder); + + mLowpanInterface = new LowpanInterface(mContext, mLowpanInterfaceService, mTestLooper.getLooper()); + } + + @Test + public void testStateChangedCallback() throws Exception { + // Register our callback + mLowpanInterface.registerCallback(mLowpanInterfaceCallback); + + // Verify a listener was added + verify(mLowpanInterfaceService) + .addListener( + argThat( + listener -> { + mInterfaceListener = listener; + return listener instanceof ILowpanInterfaceListener; + })); + + // Build a changed property map + Map<String, Object> changedProperties = new HashMap<>(); + LowpanProperties.KEY_INTERFACE_STATE.putInMap(changedProperties, LowpanInterface.STATE_OFFLINE); + + // Change some properties + mInterfaceListener.onPropertiesChanged(changedProperties); + mTestLooper.dispatchAll(); + + // Verify that the property was changed + verify(mLowpanInterfaceCallback) + .onStateChanged( + argThat(stateString -> stateString.equals(LowpanInterface.STATE_OFFLINE))); + } +} diff --git a/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java b/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java new file mode 100644 index 000000000000..481ad76e6790 --- /dev/null +++ b/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java @@ -0,0 +1,176 @@ +/* + * 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.lowpan; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.*; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Handler; +import android.os.IBinder; +import android.os.test.TestLooper; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** Unit tests for android.net.lowpan.LowpanManager. */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanManagerTest { + private static final String TEST_PACKAGE_NAME = "TestPackage"; + + @Mock Context mContext; + @Mock ILowpanManager mLowpanService; + @Mock ILowpanInterface mLowpanInterfaceService; + @Mock IBinder mLowpanInterfaceBinder; + @Mock ApplicationInfo mApplicationInfo; + @Mock IBinder mAppBinder; + @Mock LowpanManager.Callback mLowpanManagerCallback; + + private Handler mHandler; + private final TestLooper mTestLooper = new TestLooper(); + private LowpanManager mLowpanManager; + + private ILowpanManagerListener mManagerListener; + private LowpanInterface mLowpanInterface; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); + when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME); + + mLowpanManager = new LowpanManager(mContext, mLowpanService, mTestLooper.getLooper()); + } + + @Test + public void testGetEmptyInterfaceList() throws Exception { + when(mLowpanService.getInterfaceList()).thenReturn(new String[0]); + assertTrue(mLowpanManager.getInterfaceList().length == 0); + assertTrue(mLowpanManager.getInterface() == null); + } + + @Test + public void testGetInterfaceList() throws Exception { + when(mLowpanService.getInterfaceList()).thenReturn(new String[] {"wpan0"}); + when(mLowpanService.getInterface("wpan0")).thenReturn(mLowpanInterfaceService); + when(mLowpanInterfaceService.getName()).thenReturn("wpan0"); + when(mLowpanInterfaceService.asBinder()).thenReturn(mLowpanInterfaceBinder); + assertEquals(mLowpanManager.getInterfaceList().length, 1); + + LowpanInterface iface = mLowpanManager.getInterface(); + assertNotNull(iface); + assertEquals(iface.getName(), "wpan0"); + } + + @Test + public void testRegisterCallback() throws Exception { + when(mLowpanInterfaceService.getName()).thenReturn("wpan0"); + when(mLowpanInterfaceService.asBinder()).thenReturn(mLowpanInterfaceBinder); + + // Register our callback + mLowpanManager.registerCallback(mLowpanManagerCallback); + + // Verify a listener was added + verify(mLowpanService) + .addListener( + argThat( + listener -> { + mManagerListener = listener; + return listener instanceof ILowpanManagerListener; + })); + + // Add an interface + mManagerListener.onInterfaceAdded(mLowpanInterfaceService); + mTestLooper.dispatchAll(); + + // Verify that the interface was added + verify(mLowpanManagerCallback) + .onInterfaceAdded( + argThat( + iface -> { + mLowpanInterface = iface; + return iface instanceof LowpanInterface; + })); + verifyNoMoreInteractions(mLowpanManagerCallback); + + // This check causes the test to fail with a weird error, but I'm not sure why. + assertEquals(mLowpanInterface.getService(), mLowpanInterfaceService); + + // Verify that calling getInterface on the LowpanManager object will yield the same + // LowpanInterface object. + when(mLowpanService.getInterfaceList()).thenReturn(new String[] {"wpan0"}); + when(mLowpanService.getInterface("wpan0")).thenReturn(mLowpanInterfaceService); + assertEquals(mLowpanManager.getInterface(), mLowpanInterface); + + // Remove the service + mManagerListener.onInterfaceRemoved(mLowpanInterfaceService); + mTestLooper.dispatchAll(); + + // Verify that the interface was removed + verify(mLowpanManagerCallback).onInterfaceRemoved(mLowpanInterface); + } + + @Test + public void testUnregisterCallback() throws Exception { + when(mLowpanInterfaceService.getName()).thenReturn("wpan0"); + when(mLowpanInterfaceService.asBinder()).thenReturn(mLowpanInterfaceBinder); + + // Register our callback + mLowpanManager.registerCallback(mLowpanManagerCallback); + + // Verify a listener was added + verify(mLowpanService) + .addListener( + argThat( + listener -> { + mManagerListener = listener; + return listener instanceof ILowpanManagerListener; + })); + + // Add an interface + mManagerListener.onInterfaceAdded(mLowpanInterfaceService); + mTestLooper.dispatchAll(); + + // Verify that the interface was added + verify(mLowpanManagerCallback) + .onInterfaceAdded( + argThat( + iface -> { + mLowpanInterface = iface; + return iface instanceof LowpanInterface; + })); + verifyNoMoreInteractions(mLowpanManagerCallback); + + // Unregister our callback + mLowpanManager.unregisterCallback(mLowpanManagerCallback); + + // Verify the listener was removed + verify(mLowpanService).removeListener(mManagerListener); + + // Verify that the callback wasn't invoked. + verifyNoMoreInteractions(mLowpanManagerCallback); + } +} |