Merge "Add unit tests for activity client state changes" into qt-dev

This commit is contained in:
Andrii Kulian
2019-04-16 21:18:18 +00:00
committed by Android (Google) Code Review
7 changed files with 526 additions and 0 deletions

View File

@@ -27,5 +27,15 @@
}
]
}
],
"postsubmit": [
{
"file_patterns": ["(/|^)ActivityThreadClientTest.java"],
"name": "FrameworksMockingCoreTests"
},
{
"file_patterns": ["(/|^)ActivityThreadTest.java"],
"name": "FrameworksCoreTests"
}
]
}

View 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.
//
android_test {
name: "FrameworksMockingCoreTests",
srcs: [
"src/**/*.java",
],
static_libs: [
"frameworks-base-testutils",
"services.core",
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"truth-prebuilt",
"testables",
"ub-uiautomator",
],
libs: [
"android.test.base",
"android.test.mock",
"android.test.runner",
],
// These are not normally accessible from apps so they must be explicitly included.
jni_libs: [
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
}

View File

@@ -0,0 +1,35 @@
<?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"
android:installLocation="internalOnly"
package="com.android.frameworks.mockingcoretests"
android:sharedUserId="com.android.uid.test">
<application android:supportsRtl="true" android:debuggable="true">
<uses-library android:name="android.test.runner" />
<activity android:name="android.app.activity.ActivityThreadClientTest$TestActivity"
android:exported="true">
</activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.mockingcoretests"
android:label="Frameworks Mocking Core Tests" />
</manifest>

View File

@@ -0,0 +1,31 @@
<?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 Mocking Core Tests.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksMockingCoreTests.apk" />
</target_preparer>
<option name="test-tag" value="FrameworksMockingCoreTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.mockingcoretests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View 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.
INTRODUCTION
The Android platform core tests that require additional mocking capabilities and use Extended
Mockito, such as the ability to stub static methods. ExtendedMockito is not fully compatible with
regular Mockito library, so tests that use it have to be verified and adapted. For that reason a
separate module is used instead of adding to FrameworksCoreTests.
For more information about ExtendedMockito see documentation of
com.android.dx.mockito.inline.extended.ExtendedMockito class.
See ../coretests/README for more information on FrameworksCoreTests.
INSTRUCTIONS
To build, install and run:
atest FrameworksMockingCoreTests

View File

@@ -0,0 +1,362 @@
/*
* 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.app.activity;
import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.IActivityTaskManager;
import android.app.servertransaction.PendingTransactionActions;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.view.WindowManagerGlobal;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
/**
* Test for verifying {@link android.app.ActivityThread} class.
*
* <p>Build/Install/Run:
* atest FrameworksMockingCoreTests:android.app.activity.ActivityThreadClientTest
*
* <p>This test class is a part of Window Manager Service tests and specified in
* {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ActivityThreadClientTest {
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnCreate() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
clientSession.launchActivity(r);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_CREATE, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnCreate_Finished() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
Activity activity = clientSession.launchActivity(r);
activity.finish();
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_CREATE, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnStart() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
clientSession.launchActivity(r);
clientSession.startActivity(r);
assertEquals(ON_START, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_START, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnStart_Finished() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
Activity activity = clientSession.launchActivity(r);
clientSession.startActivity(r);
activity.finish();
assertEquals(ON_START, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_START, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnResume() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
clientSession.launchActivity(r);
clientSession.startActivity(r);
clientSession.resumeActivity(r);
assertEquals(ON_RESUME, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_START, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnPause() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
clientSession.launchActivity(r);
clientSession.startActivity(r);
clientSession.resumeActivity(r);
clientSession.pauseActivity(r);
assertEquals(ON_PAUSE, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_START, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testWindowVisibilityChange_OnStop() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
clientSession.launchActivity(r);
clientSession.startActivity(r);
clientSession.resumeActivity(r);
clientSession.pauseActivity(r);
clientSession.stopActivity(r);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.changeVisibility(r, true);
assertEquals(ON_START, r.getLifecycleState());
clientSession.changeVisibility(r, false);
assertEquals(ON_STOP, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testLifecycleAfterFinished_OnCreate() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
Activity activity = clientSession.launchActivity(r);
activity.finish();
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.startActivity(r);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.resumeActivity(r);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.pauseActivity(r);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.stopActivity(r);
assertEquals(ON_CREATE, r.getLifecycleState());
clientSession.destroyActivity(r);
assertEquals(ON_DESTROY, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testLifecycleAfterFinished_OnStart() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
Activity activity = clientSession.launchActivity(r);
clientSession.startActivity(r);
activity.finish();
assertEquals(ON_START, r.getLifecycleState());
clientSession.resumeActivity(r);
assertEquals(ON_START, r.getLifecycleState());
clientSession.pauseActivity(r);
assertEquals(ON_START, r.getLifecycleState());
clientSession.stopActivity(r);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.destroyActivity(r);
assertEquals(ON_DESTROY, r.getLifecycleState());
}
}
@Test
@UiThreadTest
public void testLifecycleAfterFinished_OnResume() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
Activity activity = clientSession.launchActivity(r);
clientSession.startActivity(r);
clientSession.resumeActivity(r);
activity.finish();
assertEquals(ON_RESUME, r.getLifecycleState());
clientSession.pauseActivity(r);
assertEquals(ON_PAUSE, r.getLifecycleState());
clientSession.stopActivity(r);
assertEquals(ON_STOP, r.getLifecycleState());
clientSession.destroyActivity(r);
assertEquals(ON_DESTROY, r.getLifecycleState());
}
}
private class ClientMockSession implements AutoCloseable {
private MockitoSession mMockSession;
private ActivityThread mThread;
private ClientMockSession() throws RemoteException {
mThread = ActivityThread.currentActivityThread();
mMockSession = mockitoSession()
.strictness(Strictness.LENIENT)
.spyStatic(ActivityTaskManager.class)
.spyStatic(WindowManagerGlobal.class)
.startMocking();
doReturn(Mockito.mock(WindowManagerGlobal.class))
.when(WindowManagerGlobal::getInstance);
IActivityTaskManager mockAtm = Mockito.mock(IActivityTaskManager.class);
doReturn(mockAtm).when(ActivityTaskManager::getService);
when(mockAtm.finishActivity(any(), anyInt(), any(), anyInt())).thenReturn(true);
}
private Activity launchActivity(ActivityClientRecord r) {
return mThread.handleLaunchActivity(r, null /* pendingActions */,
null /* customIntent */);
}
private void startActivity(ActivityClientRecord r) {
mThread.handleStartActivity(r, null /* pendingActions */);
}
private void resumeActivity(ActivityClientRecord r) {
mThread.handleResumeActivity(r.token, true /* finalStateRequest */,
true /* isForward */, "test");
}
private void pauseActivity(ActivityClientRecord r) {
mThread.handlePauseActivity(r.token, false /* finished */,
false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */,
"test");
}
private void stopActivity(ActivityClientRecord r) {
mThread.handleStopActivity(r.token, false /* show */, 0 /* configChanges */,
new PendingTransactionActions(), false /* finalStateRequest */, "test");
}
private void destroyActivity(ActivityClientRecord r) {
mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */,
false /* getNonConfigInstance */, "test");
}
private void changeVisibility(ActivityClientRecord r, boolean show) {
mThread.handleWindowVisibility(r.token, show);
}
private ActivityClientRecord stubActivityRecord() {
ComponentName component = new ComponentName(
InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class);
ActivityInfo info = new ActivityInfo();
info.packageName = component.getPackageName();
info.name = component.getClassName();
info.exported = true;
info.applicationInfo = new ApplicationInfo();
info.applicationInfo.packageName = info.packageName;
info.applicationInfo.uid = UserHandle.myUserId();
return new ActivityClientRecord(new Binder(), Intent.makeMainActivity(component),
0 /* ident */, info, new Configuration(),
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
null /* profilerInfo */, mThread /* client */);
}
@Override
public void close() {
mMockSession.finishMocking();
}
}
// Test activity
public static class TestActivity extends Activity {
}
}

View File

@@ -34,6 +34,8 @@ import com.android.test.filters.SelectTest;
public final class FrameworksTestsFilter extends SelectTest {
private static final String[] SELECTED_TESTS = {
// Test specifications for FrameworksMockingCoreTests.
"android.app.activity.ActivityThreadClientTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
"android.view.DisplayCutoutTest",