Skip to content

Commit 42ec220

Browse files
leotianlizhanpull[bot]
authored andcommitted
Perf e2e test app fragments (#3210)
* new template activity * copyright * fix appcompat theme * WIP FTL instrumeumented tests * rv in all fragments * automated scroll of all 3 fragments * remove debug code * gJF * copyright * rename to slow/fast fragments * copyright
1 parent 942cbc8 commit 42ec220

25 files changed

+715
-54
lines changed

firebase-perf/e2e-app/e2e-app.gradle

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ firebaseTestLab {
2828
}
2929

3030
android {
31-
compileSdkVersion 28
31+
compileSdkVersion 31
3232

3333
// Specifies the build type that the Android plugin should use to run the instrumentation tests.
3434
// TL;DR Configure what build types should Firebase Test Lab (FTL) runs your tests on.
@@ -52,7 +52,7 @@ android {
5252
// https://developer.android.com/studio/build/application-id.html
5353
applicationId "com.google.firebase.testing.fireperf"
5454

55-
minSdkVersion 16
55+
minSdkVersion 18
5656
targetSdkVersion 28
5757
versionCode 3
5858
versionName "3.0"
@@ -87,9 +87,16 @@ dependencies {
8787
implementation "com.google.android.gms:play-services-tasks:17.2.0"
8888
implementation "com.google.guava:guava:29.0-android"
8989
implementation 'androidx.annotation:annotation:1.1.0'
90-
implementation "androidx.appcompat:appcompat:1.2.0"
9190
implementation 'androidx.multidex:multidex:2.0.1'
9291
implementation "androidx.recyclerview:recyclerview:1.1.0"
92+
implementation 'androidx.appcompat:appcompat:1.4.0'
93+
implementation 'com.google.android.material:material:1.4.0'
94+
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
95+
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
96+
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
97+
implementation 'androidx.navigation:navigation-fragment:2.3.5'
98+
implementation 'androidx.navigation:navigation-ui:2.3.5'
99+
implementation 'com.google.android.material:material:1.4.0'
93100

94101
// 3rd party Deps
95102
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
@@ -102,6 +109,8 @@ dependencies {
102109
androidTestImplementation 'androidx.test:runner:1.3.0'
103110
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
104111
androidTestImplementation "androidx.test.espresso:espresso-contrib:3.3.0"
112+
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
113+
androidTestImplementation "com.google.truth:truth:$googleTruthVersion"
105114
}
106115

107116
// This allows the app to connect to Firebase on the CI.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
//
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.testing.fireperf;
16+
17+
import static androidx.test.espresso.Espresso.onView;
18+
import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
19+
import static androidx.test.espresso.matcher.ViewMatchers.withId;
20+
import static com.google.common.truth.Truth.assertThat;
21+
22+
import android.app.Activity;
23+
import androidx.annotation.NonNull;
24+
import androidx.appcompat.app.AppCompatActivity;
25+
import androidx.fragment.app.Fragment;
26+
import androidx.fragment.app.FragmentManager;
27+
import androidx.lifecycle.Lifecycle.State;
28+
import androidx.navigation.NavController;
29+
import androidx.navigation.Navigation;
30+
import androidx.test.core.app.ActivityScenario;
31+
import androidx.test.ext.junit.rules.ActivityScenarioRule;
32+
import androidx.test.filters.MediumTest;
33+
import androidx.test.runner.AndroidJUnit4;
34+
import com.google.firebase.testing.fireperf.ui.fast.FastFragment;
35+
import com.google.firebase.testing.fireperf.ui.home.HomeFragment;
36+
import com.google.firebase.testing.fireperf.ui.slow.SlowFragment;
37+
import java.util.Arrays;
38+
import org.junit.Rule;
39+
import org.junit.Test;
40+
import org.junit.runner.RunWith;
41+
42+
/**
43+
* Scrolls a slow RecyclerView all the way to the end, which should generate slow and frozen frame
44+
* data.
45+
*/
46+
@RunWith(AndroidJUnit4.class)
47+
@MediumTest
48+
public class FirebasePerformanceFragmentScreenTracesTest {
49+
50+
@Rule
51+
public ActivityScenarioRule<FragmentActivity> activityRule =
52+
new ActivityScenarioRule<>(FragmentActivity.class);
53+
54+
@Test
55+
public void scrollAndCycleThroughAllFragments() throws InterruptedException {
56+
activityRule
57+
.getScenario()
58+
.onActivity(
59+
activity -> {
60+
((AppCompatActivity) activity)
61+
.getSupportFragmentManager()
62+
.registerFragmentLifecycleCallbacks(
63+
new FragmentManager.FragmentLifecycleCallbacks() {
64+
@Override
65+
public void onFragmentResumed(
66+
@NonNull FragmentManager fm, @NonNull Fragment f) {
67+
super.onFragmentResumed(fm, f);
68+
notifyNavigationLock();
69+
}
70+
},
71+
true);
72+
});
73+
scrollRecyclerViewToEnd(HomeFragment.NUM_LIST_ITEMS, R.id.rv_numbers_home);
74+
activityRule.getScenario().onActivity(new NavigateAction(R.id.navigation_fast));
75+
blockUntilNavigationDone();
76+
scrollRecyclerViewToEnd(FastFragment.NUM_LIST_ITEMS, R.id.rv_numbers_fast);
77+
activityRule.getScenario().onActivity(new NavigateAction(R.id.navigation_slow));
78+
blockUntilNavigationDone();
79+
scrollRecyclerViewToEnd(SlowFragment.NUM_LIST_ITEMS, R.id.rv_numbers_slow);
80+
assertThat(activityRule.getScenario().getState())
81+
.isIn(Arrays.asList(State.CREATED, State.RESUMED));
82+
activityRule.getScenario().moveToState(State.CREATED);
83+
}
84+
85+
private void scrollRecyclerViewToEnd(int itemCount, int viewId) {
86+
int currItemCount = 0;
87+
88+
while (currItemCount < itemCount) {
89+
onView(withId(viewId)).perform(scrollToPosition(currItemCount));
90+
currItemCount += 5;
91+
}
92+
}
93+
94+
private synchronized void blockUntilNavigationDone() throws InterruptedException {
95+
wait();
96+
}
97+
98+
private synchronized void notifyNavigationLock() {
99+
notify();
100+
}
101+
102+
static class NavigateAction implements ActivityScenario.ActivityAction {
103+
private final int destinationId;
104+
105+
public NavigateAction(int destinationId) {
106+
this.destinationId = destinationId;
107+
}
108+
109+
@Override
110+
public void perform(Activity activity) {
111+
NavController navController =
112+
Navigation.findNavController(activity, R.id.nav_host_fragment_activity_fragment);
113+
navController.navigate(destinationId);
114+
}
115+
}
116+
}

firebase-perf/e2e-app/src/androidTest/java/com/google/firebase/testing/fireperf/FirebasePerformanceScreenTracesTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@
1717
import static androidx.test.espresso.Espresso.onView;
1818
import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
1919
import static androidx.test.espresso.matcher.ViewMatchers.withId;
20+
import static com.google.common.truth.Truth.assertThat;
2021

2122
import androidx.recyclerview.widget.RecyclerView;
2223
import androidx.test.filters.MediumTest;
24+
import androidx.test.platform.app.InstrumentationRegistry;
2325
import androidx.test.rule.ActivityTestRule;
2426
import androidx.test.runner.AndroidJUnit4;
27+
import androidx.test.uiautomator.By;
28+
import androidx.test.uiautomator.UiDevice;
29+
import androidx.test.uiautomator.Until;
30+
import org.junit.After;
2531
import org.junit.Rule;
2632
import org.junit.Test;
2733
import org.junit.runner.RunWith;
@@ -33,6 +39,7 @@
3339
@RunWith(AndroidJUnit4.class)
3440
@MediumTest
3541
public class FirebasePerformanceScreenTracesTest {
42+
private static final int LAUNCH_TIMEOUT = 5000;
3643

3744
@Rule
3845
public ActivityTestRule<FirebasePerfScreenTracesActivity> activityRule =
@@ -41,6 +48,16 @@ public class FirebasePerformanceScreenTracesTest {
4148
/* initialTouchMode= */ false,
4249
/* launchActivity= */ true);
4350

51+
@After
52+
public void pressHome_toTriggerSendScreenTrace() {
53+
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
54+
boolean success = device.pressHome();
55+
// Wait for launcher
56+
final String launcherPackage = device.getLauncherPackageName();
57+
assertThat(launcherPackage).isNotNull();
58+
device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);
59+
}
60+
4461
@Test
4562
public void scrollRecyclerViewToEnd() {
4663
RecyclerView recyclerView = activityRule.getActivity().findViewById(R.id.rv_numbers);
Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,38 @@
11
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2020 Google Inc. All Rights Reserved. -->
2-
32
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
4-
xmlns:tools="http://schemas.android.com/tools"
5-
package="com.google.firebase.testing.fireperf">
6-
7-
<uses-permission android:name="android.permission.INTERNET" />
8-
9-
<application
10-
android:allowBackup="true"
11-
android:debuggable="true"
12-
android:label="FirePerf E2E Test App"
13-
android:usesCleartextTraffic="true"
14-
tools:ignore="HardcodedDebugMode,UnusedAttribute">
15-
16-
<activity
17-
android:label="FirebasePerfActivity"
18-
android:name=".FirebasePerfActivity">
19-
<intent-filter>
20-
<action android:name="android.intent.action.MAIN" />
21-
<category android:name="android.intent.category.LAUNCHER" />
22-
</intent-filter>
23-
</activity>
24-
25-
<activity
26-
android:label="FirebasePerfScreenTracesActivity"
27-
android:name=".FirebasePerfScreenTracesActivity" />
28-
29-
<meta-data
30-
android:name="firebase_performance_logcat_enabled"
31-
android:value="true" />
32-
33-
<meta-data
34-
android:name="sessions_sampling_percentage"
35-
android:value="100.0" />
36-
37-
</application>
38-
39-
</manifest>
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.google.firebase.testing.fireperf">
5+
6+
<uses-permission android:name="android.permission.INTERNET" />
7+
8+
<application
9+
android:allowBackup="true"
10+
android:debuggable="true"
11+
android:label="FirePerf E2E Test App"
12+
android:usesCleartextTraffic="true"
13+
tools:ignore="HardcodedDebugMode,UnusedAttribute">
14+
<activity
15+
android:name=".FragmentActivity"
16+
android:label="@string/title_activity_fragment"
17+
android:theme="@style/Theme.MaterialComponents.DayNight.DarkActionBar" />
18+
<activity
19+
android:name=".FirebasePerfActivity"
20+
android:label="FirebasePerfActivity">
21+
<intent-filter>
22+
<action android:name="android.intent.action.MAIN" />
23+
<category android:name="android.intent.category.LAUNCHER" />
24+
</intent-filter>
25+
</activity>
26+
<activity
27+
android:name=".FirebasePerfScreenTracesActivity"
28+
android:label="FirebasePerfScreenTracesActivity" />
29+
30+
<meta-data
31+
android:name="firebase_performance_logcat_enabled"
32+
android:value="true" />
33+
<meta-data
34+
android:name="sessions_sampling_percentage"
35+
android:value="100.0" />
36+
</application>
37+
38+
</manifest>

firebase-perf/e2e-app/src/main/java/com/google/firebase/testing/fireperf/FirebasePerfScreenTracesActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) {
3939

4040
RecyclerView numbersList = findViewById(R.id.rv_numbers);
4141
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
42-
ListAdapter listAdapter = new ListAdapter(NUM_LIST_ITEMS);
42+
ListAdapter listAdapter = new SlowListAdapter(NUM_LIST_ITEMS);
4343

4444
numbersList.setLayoutManager(layoutManager);
4545
numbersList.setHasFixedSize(true);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
//
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package com.google.firebase.testing.fireperf;
15+
16+
import android.os.Bundle;
17+
import androidx.appcompat.app.AppCompatActivity;
18+
import androidx.navigation.NavController;
19+
import androidx.navigation.Navigation;
20+
import androidx.navigation.ui.AppBarConfiguration;
21+
import androidx.navigation.ui.NavigationUI;
22+
import com.google.android.material.bottomnavigation.BottomNavigationView;
23+
24+
public class FragmentActivity extends AppCompatActivity {
25+
@Override
26+
protected void onCreate(Bundle savedInstanceState) {
27+
super.onCreate(savedInstanceState);
28+
setContentView(R.layout.activity_fragment);
29+
BottomNavigationView navView = findViewById(R.id.nav_view);
30+
// Passing each menu ID as a set of Ids because each
31+
// menu should be considered as top level destinations.
32+
AppBarConfiguration appBarConfiguration =
33+
new AppBarConfiguration.Builder(
34+
R.id.navigation_home, R.id.navigation_fast, R.id.navigation_slow)
35+
.build();
36+
NavController navController =
37+
Navigation.findNavController(this, R.id.nav_host_fragment_activity_fragment);
38+
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
39+
NavigationUI.setupWithNavController(navView, navController);
40+
}
41+
}

firebase-perf/e2e-app/src/main/java/com/google/firebase/testing/fireperf/ListAdapter.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
package com.google.firebase.testing.fireperf;
1616

17-
import android.util.Log;
1817
import android.view.LayoutInflater;
1918
import android.view.View;
2019
import android.view.ViewGroup;
@@ -25,15 +24,14 @@
2524
/** The Adapter for the ScreenTraces test ListView. */
2625
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.NumberViewHolder> {
2726

28-
private static final String LOG_TAG = ListAdapter.class.getSimpleName();
2927
private final int numberOfItems;
3028

3129
/**
3230
* Constructor for ListAdapter that accepts a number of items to display.
3331
*
3432
* @param numberOfItems Number of items to display in list
3533
*/
36-
ListAdapter(int numberOfItems) {
34+
public ListAdapter(int numberOfItems) {
3735
this.numberOfItems = numberOfItems;
3836
}
3937

@@ -47,16 +45,6 @@ public NumberViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
4745

4846
@Override
4947
public void onBindViewHolder(@NotNull NumberViewHolder holder, int position) {
50-
try {
51-
if (position % 15 == 0) {
52-
Thread.sleep(900);
53-
} else if (position % 5 == 0) {
54-
Thread.sleep(50);
55-
}
56-
} catch (InterruptedException e) {
57-
Log.e(LOG_TAG, e.getMessage(), e);
58-
}
59-
6048
holder.bind(position);
6149
}
6250

0 commit comments

Comments
 (0)