jenkins-bot has submitted this change and it was merged.

Change subject: Hygiene: Add page load performance test
......................................................................


Hygiene: Add page load performance test

We can't improve what we don't measure.
I'm adding some performance tests to see how long loading a few pages
on testwiki takes. It's good to have those tests added before we significantly
change the page load code further.
For serious testing increase the NUM_RUNS to a higher value.
Also to compare apples to apples it's imperative to test on the same devices,
ideally with the same network condition.
(Ok, the latter is not really exactly controlled. But as long as we're talking
about a stable broadband connection it should be good enough.
The alternative would be mocking responses from a Mock MediaWiki server
and injecting code to use that instead of the real servers.)

Introduced a callback for page load completion which is currently only
used for this performance test but could be used for other things in the future.

Renamed another test to make it clearer that it's testing SectionFetchTask 
directly.

Bug: T109246
Change-Id: Ie5f8494da952cfdaa753a5e4e7a9f826599a1409
---
R app/src/androidTest/java/org/wikipedia/test/SectionsFetchTaskTests.java
A app/src/androidTest/java/org/wikipedia/test/perf/MeasurementController.java
A app/src/androidTest/java/org/wikipedia/test/perf/PageLoadPerformanceTests.java
M app/src/main/java/org/wikipedia/page/PageFragment.java
A app/src/main/java/org/wikipedia/page/PageLoadCallbacks.java
5 files changed, 203 insertions(+), 2 deletions(-)

Approvals:
  Sniedzielski: Looks good to me, approved
  Niedzielski: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git 
a/app/src/androidTest/java/org/wikipedia/test/PageFetchTaskTests.java 
b/app/src/androidTest/java/org/wikipedia/test/SectionsFetchTaskTests.java
similarity index 94%
rename from app/src/androidTest/java/org/wikipedia/test/PageFetchTaskTests.java
rename to 
app/src/androidTest/java/org/wikipedia/test/SectionsFetchTaskTests.java
index 717dfa0..504cbe8 100644
--- a/app/src/androidTest/java/org/wikipedia/test/PageFetchTaskTests.java
+++ b/app/src/androidTest/java/org/wikipedia/test/SectionsFetchTaskTests.java
@@ -13,10 +13,10 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public class PageFetchTaskTests extends 
ActivityUnitTestCase<TestDummyActivity> {
+public class SectionsFetchTaskTests extends 
ActivityUnitTestCase<TestDummyActivity> {
     private static final int TASK_COMPLETION_TIMEOUT = 20000;
 
-    public PageFetchTaskTests() {
+    public SectionsFetchTaskTests() {
         super(TestDummyActivity.class);
     }
 
diff --git 
a/app/src/androidTest/java/org/wikipedia/test/perf/MeasurementController.java 
b/app/src/androidTest/java/org/wikipedia/test/perf/MeasurementController.java
new file mode 100644
index 0000000..f8ccbaf
--- /dev/null
+++ 
b/app/src/androidTest/java/org/wikipedia/test/perf/MeasurementController.java
@@ -0,0 +1,94 @@
+package org.wikipedia.test.perf;
+
+import org.wikipedia.util.log.L;
+
+import android.os.SystemClock;
+import android.support.v4.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A simple performance test measurement collection mechanism for Android.
+ */
+public class MeasurementController {
+    private final Map<String, MeasurementSeries> seriesMap = new ArrayMap<>();
+
+    public void start(String key) {
+        MeasurementSeries measurementSeries = seriesMap.get(key);
+        if (measurementSeries == null) {
+            measurementSeries = new MeasurementSeries();
+            seriesMap.put(key, measurementSeries);
+        }
+        if (measurementSeries.currentStart > 0) {
+            L.w("Overwriting currentStart of " + 
measurementSeries.currentStart);
+        }
+        L.v("Start(" + key + ")");
+        measurementSeries.currentStart = SystemClock.elapsedRealtime();
+    }
+
+    public void stop(String key) {
+        MeasurementSeries measurementSeries = seriesMap.get(key);
+        if (measurementSeries == null) {
+            throw new IllegalStateException("Stop called without start");
+        }
+
+        long duration = SystemClock.elapsedRealtime() - 
measurementSeries.currentStart;
+        measurementSeries.currentStart = 0L;
+        measurementSeries.measurements.add(duration);
+
+        L.v("Duration(" + key + ") = " + 
MeasurementSeries.toMillisecondString(duration));
+    }
+
+    public void analyzeAll() {
+        L.i("---");
+        for (String key : seriesMap.keySet()) {
+            analyze(key);
+        }
+        L.i("---");
+    }
+
+    private void analyze(String key) {
+        L.i(key + ": " + seriesMap.get(key).analyze());
+    }
+
+    /**
+     * One series of similar tests which can be aggregated
+     */
+    public static class MeasurementSeries {
+        private List<Long> measurements = new ArrayList<>();
+        private long currentStart = 0L;
+
+        public String analyze() {
+            long min = Long.MAX_VALUE;
+            long max = Long.MIN_VALUE;
+            long sum = 0L;
+
+            if (measurements.isEmpty()) {
+                return "No measurements to analyze";
+            }
+
+            for (long current : measurements) {
+                if (current < min) {
+                    min = current;
+                }
+                if (current > max) {
+                    max = current;
+                }
+                sum += current;
+            }
+
+            String res = toMillisecondString(sum / measurements.size());
+            res += "(n: " + measurements.size()
+                    + "; min: " + toMillisecondString(min)
+                    + "; max: " + toMillisecondString(max)
+                    + ")";
+            return res;
+        }
+
+        static String toMillisecondString(long value) {
+            return value + "ms";
+        }
+    }
+}
diff --git 
a/app/src/androidTest/java/org/wikipedia/test/perf/PageLoadPerformanceTests.java
 
b/app/src/androidTest/java/org/wikipedia/test/perf/PageLoadPerformanceTests.java
new file mode 100644
index 0000000..591fc34
--- /dev/null
+++ 
b/app/src/androidTest/java/org/wikipedia/test/perf/PageLoadPerformanceTests.java
@@ -0,0 +1,85 @@
+package org.wikipedia.test.perf;
+
+import org.wikipedia.Site;
+import org.wikipedia.history.HistoryEntry;
+import org.wikipedia.page.PageActivity;
+import org.wikipedia.page.PageFragment;
+import org.wikipedia.page.PageLoadCallbacks;
+import org.wikipedia.page.PageTitle;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test performance of page loading. Update the NUM_RUNS for better 
statistical significance.
+ */
+@LargeTest
+public class PageLoadPerformanceTests extends 
ActivityInstrumentationTestCase2<PageActivity> {
+    private static final int TASK_COMPLETION_TIMEOUT = 30000;
+    private static final Site SITE = new Site("test.wikipedia.org");
+    private static final int NUM_RUNS = 1; //50;
+    private PageActivity activity;
+    private CountDownLatch completionLatch;
+    private PageFragment fragment;
+    private String title;
+    private MeasurementController measurement = new MeasurementController();
+
+    private PageLoadCallbacks callback = new PageLoadCallbacks() {
+        @Override
+        public void onLoadComplete() {
+            measurement.stop(title);
+            completionLatch.countDown();
+        }
+    };
+
+    public PageLoadPerformanceTests() {
+        super(PageActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        activity = getActivity();
+    }
+
+    public void testLoadPages() throws Throwable {
+        testLoadPage("Test_page_for_app_testing/Section1");
+        testLoadPage("A_long_page");
+        testLoadPage("Barack_Obama"); // much longer than previous pages, has 
a lead image
+
+        measurement.analyzeAll();
+    }
+
+    private void testLoadPage(String myTitle) throws Throwable {
+        title = myTitle;
+        for (int i = 0; i < NUM_RUNS; i++) {
+            loadPageUi();
+        }
+    }
+
+    private void loadPageUi() throws Throwable {
+        completionLatch = new CountDownLatch(1);
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragment = (PageFragment) activity.getTopFragment();
+                fragment.setPageLoadCallbacks(callback);
+
+                measurement.start(title);
+                loadPage();
+            }
+        });
+        assertTrue(completionLatch.await(TASK_COMPLETION_TIMEOUT, 
TimeUnit.MILLISECONDS));
+    }
+
+    private void loadPage() {
+        PageTitle pageTitle = new PageTitle(null, title, SITE);
+        fragment.displayNewPage(pageTitle,
+                new HistoryEntry(pageTitle, HistoryEntry.SOURCE_RANDOM),
+                false,
+                false);
+    }
+}
diff --git a/app/src/main/java/org/wikipedia/page/PageFragment.java 
b/app/src/main/java/org/wikipedia/page/PageFragment.java
index 1601878..fdbde74 100755
--- a/app/src/main/java/org/wikipedia/page/PageFragment.java
+++ b/app/src/main/java/org/wikipedia/page/PageFragment.java
@@ -48,6 +48,7 @@
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.design.widget.FloatingActionButton;
 import android.support.v4.app.Fragment;
 import android.support.v4.view.MenuItemCompat;
@@ -168,6 +169,9 @@
             toggleToC(TOC_ACTION_TOGGLE);
         }
     };
+
+    @Nullable
+    private PageLoadCallbacks pageLoadCallbacks;
 
     public ObservableWebView getWebView() {
         return webView;
@@ -826,6 +830,10 @@
         checkAndShowSelectTextOnboarding();
 
         updateNavDrawerSelection();
+
+        if (pageLoadCallbacks != null) {
+            pageLoadCallbacks.onLoadComplete();
+        }
     }
 
     public PageTitle adjustPageTitleFromMobileview(PageTitle title, JSONObject 
mobileView)
@@ -1064,6 +1072,11 @@
         return (PageActivity) getActivity();
     }
 
+    @VisibleForTesting
+    public void setPageLoadCallbacks(@Nullable PageLoadCallbacks 
pageLoadCallbacks) {
+        this.pageLoadCallbacks = pageLoadCallbacks;
+    }
+
     private class LongPressHandler extends PageActivityLongPressHandler
             implements PageLongPressHandler.WebViewContextMenuListener {
         public LongPressHandler(@NonNull PageActivity activity) {
diff --git a/app/src/main/java/org/wikipedia/page/PageLoadCallbacks.java 
b/app/src/main/java/org/wikipedia/page/PageLoadCallbacks.java
new file mode 100644
index 0000000..af440eb
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/page/PageLoadCallbacks.java
@@ -0,0 +1,9 @@
+package org.wikipedia.page;
+
+/**
+ * Callback methods for page load state feedback
+ */
+public interface PageLoadCallbacks {
+    /** Called when page has finished loading */
+    void onLoadComplete();
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/232681
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie5f8494da952cfdaa753a5e4e7a9f826599a1409
Gerrit-PatchSet: 7
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: BearND <bsitzm...@wikimedia.org>
Gerrit-Reviewer: BearND <bsitzm...@wikimedia.org>
Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org>
Gerrit-Reviewer: Dbrant <dbr...@wikimedia.org>
Gerrit-Reviewer: Mholloway <mhollo...@wikimedia.org>
Gerrit-Reviewer: Niedzielski <sniedziel...@wikimedia.org>
Gerrit-Reviewer: Ori.livneh <o...@wikimedia.org>
Gerrit-Reviewer: Sniedzielski <sniedziel...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to