Permalink
Browse files

Retrieve Jacoco coverage

  • Loading branch information...
Tim Baverstock
Tim Baverstock committed May 29, 2015
1 parent d547353 commit 0acc0d1d98e485336c3a37b599a8b052063e85a4
@@ -3,7 +3,7 @@
require 'tempfile'
require 'escape'
require 'rbconfig'
-require 'calabash-android/java_keystore'
+require_relative 'java_keystore'
def package_name(app)
unless File.exist?(app)
@@ -121,6 +121,10 @@ def clear_app_data
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 @@ def wake_up
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 @@ def start_test_server_in_background(options={})
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?
@@ -9,6 +9,8 @@
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 @@
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 Response serve(String uri, String method, Properties header,
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 @@ else if (uri.endsWith("/map")) {
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 @@ else if (methodName.equals("execute-javascript")) {
} 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();

0 comments on commit 0acc0d1

Please sign in to comment.