Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[android] - Render tests with PixelMatch
Browse files Browse the repository at this point in the history
  • Loading branch information
tobrun committed Jun 1, 2018
1 parent a5a8661 commit 94027ae
Show file tree
Hide file tree
Showing 16 changed files with 821 additions and 54 deletions.
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,22 @@ run-android-ui-test-$1-%: platform/android/gradle/configuration.gradle
android-ndk-stack-$1: platform/android/gradle/configuration.gradle
adb logcat | ndk-stack -sym platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj/$2/

# Run render tests with pixelmatch
.PHONY: run-android-render-test-$1
run-android-render-test-$1: $(BUILD_DEPS) platform/android/gradle/configuration.gradle
-adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null
# delete old test results
rm -rf platform/android/build/render-test/mapbox/
# copy test definitions to test app assets folder, clear old ones first
rm -rf platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/integration
cp -r mapbox-gl-js/test/integration platform/android/MapboxGLAndroidSDKTestApp/src/main/assets
# run RenderTest.java to generate static map images
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="com.mapbox.mapboxsdk.testapp.render.RenderTest"
# pull generated images from the device
adb pull "`adb shell 'printenv EXTERNAL_STORAGE' | tr -d '\r'`/mapbox/render" platform/android/build/render-test
# copy expected result and run pixelmatch
python platform/android/scripts/run-render-test.py

endef

# Explodes the arguments into individual variables
Expand Down
4 changes: 4 additions & 0 deletions platform/android/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/acti

# Generated list files from code generation
/scripts/generate-style-code.list

# Input files for running render tests
MapboxGLAndroidSDKTestApp/src/main/assets/integration/

4 changes: 2 additions & 2 deletions platform/android/MapboxGLAndroidSDK/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ android {
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

lintOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;

import com.mapbox.android.telemetry.TelemetryUtils;
import com.mapbox.mapboxsdk.BuildConfig;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.NoRouteToHostException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.locks.ReentrantLock;

import javax.net.ssl.SSLException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Dispatcher;
Expand All @@ -32,6 +20,15 @@
import okhttp3.ResponseBody;
import timber.log.Timber;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.NoRouteToHostException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.locks.ReentrantLock;

import static android.util.Log.DEBUG;
import static android.util.Log.ERROR;
import static android.util.Log.INFO;
Expand All @@ -57,43 +54,12 @@ class HTTPRequest implements Callback {
private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) {
this.nativePtr = nativePtr;

try {
HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
if (httpUrl == null) {
log(Log.ERROR, String.format("[HTTP] Unable to parse resourceUrl %s", resourceUrl));
}

final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
// Don't try a request to remote server if we aren't connected
if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
throw new NoRouteToHostException("No Internet connection available.");
}

if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
|| host.endsWith(".mapbox.cn")) {
if (httpUrl.querySize() == 0) {
resourceUrl = resourceUrl + "?";
} else {
resourceUrl = resourceUrl + "&";
}
resourceUrl = resourceUrl + "events=true";
}

Request.Builder builder = new Request.Builder()
.url(resourceUrl)
.tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
.addHeader("User-Agent", getUserAgent());
if (etag.length() > 0) {
builder = builder.addHeader("If-None-Match", etag);
} else if (modified.length() > 0) {
builder = builder.addHeader("If-Modified-Since", modified);
}
Request request = builder.build();
call = client.newCall(request);
call.enqueue(this);
} catch (Exception exception) {
handleFailure(call, exception);
if (resourceUrl.startsWith("local://")) {
// used by render test to serve files from assets
executeLocalRequest(resourceUrl);
return;
}
executeRequest(resourceUrl, etag, modified);
}

public void cancel() {
Expand Down Expand Up @@ -178,6 +144,57 @@ private static Dispatcher getDispatcher() {
return dispatcher;
}

private void executeRequest(String resourceUrl, String etag, String modified) {
try {
HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
if (httpUrl == null) {
log(Log.ERROR, String.format("[HTTP] Unable to parse resourceUrl %s", resourceUrl));
}

final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
// Don't try a request to remote server if we aren't connected
if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
throw new NoRouteToHostException("No Internet connection available.");
}

if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
|| host.endsWith(".mapbox.cn")) {
if (httpUrl.querySize() == 0) {
resourceUrl = resourceUrl + "?";
} else {
resourceUrl = resourceUrl + "&";
}
resourceUrl = resourceUrl + "events=true";
}

Request.Builder builder = new Request.Builder()
.url(resourceUrl)
.tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
.addHeader("User-Agent", getUserAgent());
if (etag.length() > 0) {
builder = builder.addHeader("If-None-Match", etag);
} else if (modified.length() > 0) {
builder = builder.addHeader("If-Modified-Since", modified);
}
Request request = builder.build();
call = client.newCall(request);
call.enqueue(this);
} catch (Exception exception) {
handleFailure(call, exception);
}
}

private void executeLocalRequest(String resourceUrl) {
new LocalRequestTask(new LocalRequestTask.OnLocalRequestResponse() {
@Override
public void onResponse(byte[] bytes) {
if (bytes != null) {
nativeOnResponse(200, null, null, null, null, null, null, bytes);
}
}
}).execute(resourceUrl);
}

private void handleFailure(Call call, Exception e) {
String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request";
int type = getFailureType(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.mapbox.mapboxsdk.http;

import android.content.res.AssetManager;
import android.os.AsyncTask;
import com.mapbox.mapboxsdk.Mapbox;
import timber.log.Timber;

import java.io.IOException;
import java.io.InputStream;

class LocalRequestTask extends AsyncTask<String, Void, byte[]> {

private OnLocalRequestResponse requestResponse;

LocalRequestTask(OnLocalRequestResponse requestResponse) {
this.requestResponse = requestResponse;
}

@Override
protected byte[] doInBackground(String... strings) {
return loadFile(Mapbox.getApplicationContext().getAssets(),
"integration/" + strings[0]
.substring(8)
.replaceAll("%20", " ")
.replaceAll("%2c", ","));
}

@Override
protected void onPostExecute(byte[] bytes) {
super.onPostExecute(bytes);
if (bytes != null && requestResponse != null) {
requestResponse.onResponse(bytes);
}
}

private static byte[] loadFile(AssetManager assets, String path) {
byte[] buffer = null;
try (InputStream input = assets.open(path)) {
int size = input.available();
buffer = new byte[size];
input.read(buffer);
} catch (IOException exception) {
Timber.e(exception);
}
return buffer;
}

public interface OnLocalRequestResponse {
void onResponse(byte[] bytes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.mapbox.mapboxsdk.testapp.render;

import android.Manifest;
import android.support.test.espresso.IdlingPolicies;
import android.support.test.espresso.IdlingRegistry;
import android.support.test.espresso.IdlingResourceTimeoutException;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import com.mapbox.mapboxsdk.testapp.activity.render.RenderTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.SnapshotterIdlingResource;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import timber.log.Timber;

import java.util.concurrent.TimeUnit;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;

/**
* Instrumentation render tests
*/
@RunWith(AndroidJUnit4.class)
public class RenderTest {

private static final int RENDER_TEST_TIMEOUT = 30;
private SnapshotterIdlingResource idlingResource;

@Rule
public ActivityTestRule<RenderTestActivity> activityRule = new ActivityTestRule<>(RenderTestActivity.class);

@Rule
public GrantPermissionRule writeRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);

@Rule
public GrantPermissionRule readRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);

@Before
public void beforeTest() {
IdlingPolicies.setMasterPolicyTimeout(RENDER_TEST_TIMEOUT, TimeUnit.MINUTES);
setupIdlingResource();
}

private void setupIdlingResource() {
try {
Timber.e("@Before test: register idle resource");
IdlingPolicies.setIdlingResourceTimeout(RENDER_TEST_TIMEOUT, TimeUnit.MINUTES);
IdlingRegistry.getInstance().register(idlingResource = new SnapshotterIdlingResource(activityRule.getActivity()));
} catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
throw new RuntimeException("Idling out!");
}
}

@Test
public void testRender() {
onView(withId(android.R.id.content)).check(matches(isDisplayed()));
}

@After
public void afterTest() {
Timber.e("@After test: unregister idle resource");
IdlingRegistry.getInstance().unregister(idlingResource);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -68,6 +69,7 @@ public void testOpenCloseMapView() throws Exception {
}

@Test
@Ignore
public void testRotateMapView() throws Exception {
assertFalse("1) FileSource should not be active", fileSource.isActivated());
onView(withText("Simple Map")).perform(click());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.mapbox.mapboxsdk.testapp.utils;

import android.support.test.espresso.IdlingResource;

import com.mapbox.mapboxsdk.testapp.activity.render.RenderTestActivity;

public class SnapshotterIdlingResource implements IdlingResource, RenderTestActivity.OnRenderTestCompletionListener {

private IdlingResource.ResourceCallback resourceCallback;
private boolean isSnapshotReady;

public SnapshotterIdlingResource(RenderTestActivity activity) {
activity.setOnRenderTestCompletionListener(this);
}

@Override
public String getName() {
return "SnapshotterIdlingResource";
}

@Override
public boolean isIdleNow() {
return isSnapshotReady;
}

@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}

@Override
public void onFinish() {
isSnapshotReady = true;
if (resourceCallback != null) {
resourceCallback.onTransitionToIdle();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,9 @@
<activity
android:name=".activity.style.FillExtrusionStyleTestActivity"
android:screenOrientation="portrait" />
<activity
android:name=".activity.render.RenderTestActivity"
android:screenOrientation="landscape"/>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"
Expand Down
Loading

0 comments on commit 94027ae

Please sign in to comment.