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
This commit is contained in:
Robert Quattlebaum
2017-06-07 18:42:45 -07:00
parent ff09314508
commit 03ffec0969
8 changed files with 479 additions and 0 deletions

View File

@@ -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

65
lowpan/tests/Android.mk Normal file
View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

50
lowpan/tests/README.md Normal file
View File

@@ -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`.

24
lowpan/tests/runtests.sh Executable file
View File

@@ -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'

View File

@@ -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)));
}
}

View File

@@ -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);
}
}