Skip to content

Instantly share code, notes, and snippets.

@sleekweasel
Created January 30, 2017 10:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sleekweasel/e8fb0317ed35fa1eab9b2c0ac7806509 to your computer and use it in GitHub Desktop.
Save sleekweasel/e8fb0317ed35fa1eab9b2c0ac7806509 to your computer and use it in GitHub Desktop.
~/git/calabash-android (master)$ git show 0acc0d1d98e485336c3a37b599a8b052063e85a4 > patch
commit 0acc0d1d98e485336c3a37b599a8b052063e85a4
Author: Tim Baverstock <tim.baverstock@corp.badoo.com>
Date: Fri May 29 18:18:36 2015 +0100
Retrieve Jacoco coverage
diff --git a/ruby-gem/lib/calabash-android/helpers.rb b/ruby-gem/lib/calabash-android/helpers.rb
index c94c768..485aa31 100755
--- a/ruby-gem/lib/calabash-android/helpers.rb
+++ b/ruby-gem/lib/calabash-android/helpers.rb
@@ -3,7 +3,7 @@ require 'zip'
require 'tempfile'
require 'escape'
require 'rbconfig'
-require 'calabash-android/java_keystore'
+require_relative 'java_keystore'
def package_name(app)
unless File.exist?(app)
diff --git a/ruby-gem/lib/calabash-android/operations.rb b/ruby-gem/lib/calabash-android/operations.rb
index 753b613..c92bc26 100644
--- a/ruby-gem/lib/calabash-android/operations.rb
+++ b/ruby-gem/lib/calabash-android/operations.rb
@@ -121,6 +121,10 @@ module Calabash module Android
default_device.clear_app_data
end
+ def collect_coverage_data
+ default_device.collect_coverage_data
+ end
+
def pull(remote, local)
default_device.pull(remote, local)
end
@@ -569,6 +573,7 @@ module Calabash module Android
end
def clear_app_data
+ collect_coverage_data
cmd = "#{adb_command} shell am instrument #{package_name(@test_server_path)}/sh.calaba.instrumentationbackend.ClearAppData"
raise "Could not clear data" unless system(cmd)
end
@@ -666,8 +671,30 @@ module Calabash module Android
log("Client and server versions match (client: #{client_version}, server: #{server_version}). Proceeding...")
end
+ def collect_coverage_data
+ coverage_dir = ENV['COVERAGE_DIR']
+ return unless coverage_dir && !coverage_dir.empty?
+ begin
+ res = http('/coverage')
+ if res && !res.empty?
+ i = 0
+ i += 1 while File.exist?((path = coverage_filename(coverage_dir, i)))
+ File.open(path, 'wb') { |f| f.write res }
+ end
+ rescue StandardError => e
+ # Not sure how important failure is here: some folks collect coverage routinely,
+ # but only check it periodically.
+ log("Failed to retrieve coverage: #{e}")
+ end
+ end
+
+ def coverage_filename(coverage_dir, i)
+ File.join(coverage_dir, "coverage.#{serial}.#{i}.ec".gsub(/[^\w.-]/, '_'))
+ end
+
def shutdown_test_server
begin
+ collect_coverage_data
http("/kill")
Timeout::timeout(3) do
sleep 0.3 while app_running?
diff --git a/ruby-gem/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java b/ruby-gem/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java
index 3c76cbb..574729f 100644
--- a/ruby-gem/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java
+++ b/ruby-gem/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java
@@ -9,6 +9,8 @@ import java.io.StringWriter;
import java.lang.InterruptedException;
import java.lang.Override;
import java.lang.Runnable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -53,11 +55,11 @@ public class HttpServer extends NanoHTTPD {
private final Condition shutdownCondition = lock.newCondition();
private static HttpServer instance;
-
+
/**
* Creates and returns the singleton instance for HttpServer.
- *
+ *
* Can only be called once. Otherwise, you'll get an IllegalStateException.
*/
public synchronized static HttpServer instantiate(int testServerPort) {
@@ -96,39 +98,39 @@ public class HttpServer extends NanoHTTPD {
else if (uri.endsWith("/dump")) {
FranklyResult errorResult = null;
try {
-
-
+
+
String json = params.getProperty("json");
-
-
+
+
if (json == null)
- {
+ {
Map<?,?> dumpTree = new ViewDump().dumpWithoutElements();
return new NanoHTTPD.Response(HTTP_OK, "application/json;charset=utf-8", JSONUtils.asJson(dumpTree));
}
- else
+ else
{
ObjectMapper mapper = new ObjectMapper();
Map dumpSpec = mapper.readValue(json, Map.class);
-
+
List<Integer> path = (List<Integer>) dumpSpec.get("path");
if (path == null)
{
Map<?,?> dumpTree = new ViewDump().dumpWithoutElements();
- return new NanoHTTPD.Response(HTTP_OK, "application/json;charset=utf-8", JSONUtils.asJson(dumpTree));
+ return new NanoHTTPD.Response(HTTP_OK, "application/json;charset=utf-8", JSONUtils.asJson(dumpTree));
}
Map<?,?> dumpTree = new ViewDump().dumpPathWithoutElements(path);
if (dumpTree == null) {
- return new NanoHTTPD.Response(HTTP_NOTFOUND, "application/json;charset=utf-8", "{}");
+ return new NanoHTTPD.Response(HTTP_NOTFOUND, "application/json;charset=utf-8", "{}");
}
else {
- return new NanoHTTPD.Response(HTTP_OK, "application/json;charset=utf-8", JSONUtils.asJson(dumpTree));
+ return new NanoHTTPD.Response(HTTP_OK, "application/json;charset=utf-8", JSONUtils.asJson(dumpTree));
}
-
-
+
+
}
-
+
} catch (Exception e ) {
e.printStackTrace();
errorResult = FranklyResult.fromThrowable(e);
@@ -212,7 +214,7 @@ public class HttpServer extends NanoHTTPD {
String commandString = params.getProperty("json");
ObjectMapper mapper = new ObjectMapper();
Map command = mapper.readValue(commandString, Map.class);
-
+
String uiQuery = (String) command.get("query");
uiQuery = uiQuery.trim();
Map op = (Map) command.get("operation");
@@ -348,8 +350,29 @@ public class HttpServer extends NanoHTTPD {
} else if (uri.endsWith("/ready")) {
return new Response(HTTP_OK, MIME_HTML, Boolean.toString(ready));
-
- } else if (uri.endsWith("/screenshot")) {
+ } else if (uri.endsWith("/coverage")) {
+ try {
+ // Use reflection like Android InstrumentationTestRunner for now.
+ ClassLoader classLoader = InstrumentationBackend.instrumentation.getTargetContext().getClassLoader();
+ Class<?> RTClass = classLoader.loadClass("org.jacoco.agent.rt.RT");
+ Method getAgentMethod = RTClass.getMethod("getAgent");
+ Object agent = getAgentMethod.invoke(null);
+ Class<?> IAgentClass = classLoader.loadClass("org.jacoco.agent.rt.IAgent");
+ Method dumpCoverageMethod = IAgentClass.getMethod("getExecutionData", boolean.class);
+ byte[] executionData = (byte[])dumpCoverageMethod.invoke(agent, true);
+ return new NanoHTTPD.Response(HTTP_OK, "application/data",
+ new ByteArrayInputStream(executionData));
+ }
+ catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ System.out.println(sw.toString());
+ return new NanoHTTPD.Response(HTTP_INTERNALERROR, null,
+ sw.toString());
+ }
+ }
+ else if (uri.endsWith("/screenshot")) {
try {
Bitmap bitmap;
View rootView = getRootView();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment