Coder Social home page Coder Social logo

fork's Introduction

Build Status Codacy Badge

Fork tools

The Fork project consists of these tools:

  • Fork offers the fastest way to execute Android instrumentation test suites.
  • Flakiness Reporter produces readable reports about test flakiness on tests suites previously executed by Fork.
  • Chimprunner runs performance tests and keeps stats and standard reports (Systrace, memory, CPU, etc).

Fork

When running instrumentation tests, there is a significant time overhead for developers, especially on larger test suites. Existing solutions were not satisfactory for quick feedback before pushing code to VCS and for CI purposes.

We are big fans of Spoon and were using it for our plans, so we used it as our starting point. However, Spoon had similar issues to the Gradle and Maven test execution plugins, in the sense that it executes all tests on all of the connected devices (and emulators). We decided to tweak that naive scheduling to achieve much faster test execution.

How it works

We introduced the notion of pools of devices. These are now responsible for running a test suite instead of each device running the suite separately. That has two side effects:

  • infinite scaling: your tests can speed up by as many devices and emulators as you can dedicate to your CI box.
  • because test suites now get scheduled to run on a pool, not all tests will run on all devices. For that reason, we also introduced a way to create a pool per device, which offers full coverage (a.k.a. Spoon-mode) but typically takes longer, so we run it on a nightly basis. Fork works out-of-the-box, without any code changes.

Running Fork

There are two ways to run Fork with your builds.

Gradle plugin (recommended)

First, you need to add a build-script dependency. You can have access to snapshot builds, but stable versions are recommended.

Stable

buildscript {
  dependencies {
    classpath 'com.shazam.fork:fork-gradle-plugin:3.16.0'
  }
}

Snapshot

buildscript {
  repositories {
    // other repos ...
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
  }
  dependencies {
    classpath 'com.shazam.fork:fork-gradle-plugin:3.17.0-SNAPSHOT
  }
}

Apply the Fork plugin

apply plugin: 'com.shazam.fork'

You're now done. If you had any instrumentation test tasks before, the plugin has added Fork tasks. You can verify by running:

gradlew tasks | grep fork

You can use Fork's DSL to configure its execution parameters. For a full list of the properties, have a look at: Configuring pools and runtime and related Examples. It should be as easy as adding a block to your build.gradle:

fork {
    title = "My acceptance tests"
    testPackage = "com.example.tests"
    poolingStrategy {
        computed {
            characteristic = "sw"
            groups {
                allDevices = 0
            }
        }
    }
}

Note: The testPackage property refers to the base package name which your tests reside in. If you have tests in multiple packages, provide the most common ancestor.

Standalone

Check out the Fork project and execute:

> gradlew fork-runner:run -Pargs='ARGUMENTS LIST'

Available options (* mandatory).         
    --sdk                       Path to Android SDK. Defaults to the ANDROID_HOME environment variable.
    --apk (*)                   Path to application.
    --test-apk (*)              Path to test application.
    --config (*)                Location of the configuration file. 

The properties of the configuration file are described in: Configuring pools and runtime and related Examples.

Configuring pools and runtime

One of the most useful characteristics of the library is the way it creates the device pools. There are different options, to automatically create pools by API level, shortest width dimension and whether devices are self-described as tablets. On top of that, users can also manually create pools based on serial numbers, for maximum flexibility.

With either way of executing Fork (Gradle / Standalone) you can specify how the pools are created by setting a combination of the properties below. You can also find examples:

Property Name Property Type Default value
baseOutputDir File "fork"
ignoreFailures boolean false
isCoverageEnabled boolean false
testClassRegex String "^((?!Abstract).)*Test$"
testPackage String (Your instrumentation APK package)
title String -
subtitle String -
testOutputTimeout int 60000
testSize String -
excludedSerials Collection<String> -
totalAllowedRetryQuota int 0
retryPerTestCaseQuota int 1
autoGrantPermissions boolean true
poolingStrategy PoolingStrategy -
excludedAnnotation String (tests with this annotation are excluded)
applicationApkName String -
instrumentationApkName String -

Poolingstrategy is an object that describes how the device pools are created. You can choose only one strategy from below:

Property Name Property Type Description
splitTablets boolean configure pools depending on their manufacturer's 'tablet' flag (ro.build.characteristics)
eachDevice boolean create a pool per device (a.k.a. Spoon-mode). This is the default behaviour.
manual ManualPooling configure pools manually, per serial number
computed ComputedPooling configure pools automatically, by setting device criteria (API level, shortest width dimension)

ManualPooling's properties are:

Property Name Property Type Description
groupings Map<String, Collection<String>> map pool names to collection of device serials to be assigned to that pool

ComputedPooling's properties are:

Property Name Property Type Description
characteristic Characteristic Possible values: "sw"|"api" (shortest width or API level)
groups Map<String, Integer> map the name of a pool to their lowest dimension for a characteristic

Runtime Permissions

By default Fork auto-grants all runtime permissions on Android Marshmallow +. It is possible anyway to selectively revoke one or more permissions per single test case. To do so, you have to add an annotation called RevokePermission. Here is an example:

  @Test
  @RevokePermission({Manifest.permission.RECORD_AUDIO,
                        Manifest.permission.ACCESS_FINE_LOCATION})
  public void aTestRevokingRecordAudioAndFineLocation() {
    //in here RECORD_AUDIO and ACCESS_FINE_LOCATION are *not* granted.
  }

Remember to add the fork client-side library to your project to have access to the annotation. To do so, in your app's dependencies add:

    androidTestImplementation "com.shazam.fork:fork-client:3.16.0"

After every test case, all the runtime permissions will be automatically re-granted even if the test fails. This feature will impact only Marshmallow and subsequent devices.

Arbitrary metadata

Using Fork you can set metadata on tests and get them back in its JUnit xml reports. The metadata are added as additional property tags on the suite level of the report, as each test produces its own report.

@Test
@TestProperties(keys = {"k1", "k2"}, values = {"v1", "v2"})
public void testWithProperties() {
    // Test normally here
}

Note that Fork will stop adding pairs after it encounters an unpaired key or value, so make sure you have the same number of keys and values.

Examples

Gradle plugin examples

Automatic pooling

A common case can be that you want to create two pools, one for phones & small tablets (7" and below) and one for large tablets. You could add to your build.gradle file:

fork {
    title "Fork report"
    subtitle "automatically split phones to large tablets"
    poolingStrategy {
	    computed {
		    characteristic = "sw"
		    groups {
			    phablets = 0
			    tablets = 720
			}
	    }
    }
}

The above will run tests on 2 pools, one named "phablets" and another called "tablets". The smallest width for the first pool will be 0 and for the latter 720 dpi.

Manual pooling

fork {
    title "Fork report"
    subtitle "manually allocated devices"
    poolingStrategy {
	    manual {
		    groupings {
			    phablets = ["ABCDE", "FGHIJ"]
			    tablets = ["12345"]
			    emulators = [".*:5555"]
			}
	    }
    }
}

That will create three pools named "phablets", "tablets" & "emulators" with devices that have the respective serial numbers. Emulators will be selected automatically by a regexp.

Standalone examples

Automatic pooling

Execute the following:

> gradlew fork-runner:run -Pargs='--apk /path/to/production.APK --test-apk /path/to/test.APK --config /path/to/fork-config.json'

Where the contents of fork-config.json are:

{
	"title" : "Fork Report",
	"subtitle" : "automatically split phones to tablets",
	"poolingStrategy" : {
		"computed" : {
			"characteristic" : "sw",
			"groups" : {
				"phablets" : 0,
				"tablets" : 720
			}
		}
	}
}

Manual pooling

Execute the following:

> gradlew fork-runner:run -Pargs='--apk /path/to/production.APK --test-apk /path/to/test.APK --config /path/to/fork-config.json'

Where the contents of fork-config.json are:

{
    "title" : "Fork Report",
    "subtitle" : "manually allocated devices",
    "poolingStrategy" : {
        "manual" : {
            "phablets" : ["ABCDE", "FGHIJ"],
            "tablets" : ["12345"]
        }
    }
}

Limitations

  • The scheduling still works on a single build box with ADB, so there still is a limit by how many devices & emulators can be simultaneously connected to ADB. Eventually, Fork could be tweaked to talk over HTTP with other build agents, that would then be connected to devices over ADB. That model would tie in nicely with multi-agent CI systems, like Jenkins.

Flakiness Reporter

One common problem with UI tests is the test flakiness from either the environment they run on or badly written tests. To help track down tests that are misbehaving, we introduced the Flakiness reporter.

The reports produced by the Flakiness Reporter eventually make it trivial to find flaky tests and link to them and their diagnostics. Currently Jenkins is supported and it should be really easy to extend it to other types of CI servers.

How it works

The Flakiness Reporter collects Fork output files, matches test runs over previous builds and sorts them according to their flakiness. Links are also created to each test of each test run, for easy navigation to diagnostics.

Sample output

The output after a successful run of the Flakiness Reporter looks like the following: Fork Flakiness Reporter

Running the Flakiness Reporter (Jenkins)

The Gradle plugin that allows the Reporter to run can be applied to a standalone project, since it doesn't directly depend on your Android project. For convenience, however, that is a good compromise.

Currently, the Reporter supports Jenkins but plugins can be written to be used with other CI servers.

To be able to use the Flakiness Reporter add these dependencies:

buildscript {
    dependencies {
        classpath "com.shazam.fork:fork-reporter-jenkins-gradle-plugin:3.16.0"
    }
    repositories {
        maven { url "https://repo.jenkins-ci.org/public/" }
    }
}

Apply the Jenkins Flakiness Reporter plugin

apply plugin: 'com.shazam.fork.reporter.jenkins'

You can easily execute the Reporter with the following command.

gradlew forkJenkinsReport

Gradle plugin configuration

To allow the Reporter communicate with your Jenkins server, you need to configure it with some basic details about your Jenkins Plan

Property Name Property Type Description
reportTitle String The title you want your report to have
jenkinsUrl String The base URL of your Jenkins Server
jenkinsJobName String The name of the job you want to be tracked
jenkinsReportTitle String Optional, used to link to Fork diagnostics. The report title you use to archive Fork's report folder
escapeUnderscores boolean Optional, should have the same value as HTML Publisher (default: true)

An example of a configuration:

forkJenkins {
    reportTitle = "My project's awesome flakiness report"
    jenkinsUrl = "http://my-jenkins.server.net:8080/"
    jenkinsJobName = "Master"
    jenkinsReportTitle = "Fork Report"
 }

Jenkins configuration

In your post-build action section in Jenkins, do the following two actions.

Archive Fork's summary file as an artifact

The Reporter works with summary files from Fork runs. For them to be accessible, they need to be archived like below: Fork summary archiving

Publish Fork's HTML report

This requires Jenkins's HTML Publisher Plugin. To be able to link to the right test runs, use a clear title. Fork HTML reports archiving

Note: The forkJenkins.jenkinsReportTitle parameter of the gradle configuration has to match the Report Title added here.

Chimprunner

At the time of writing, not much is available around automated performance testing. Chimprunner is a very simple test runner that allows recording of somewhat accurate timings on test execution, from process creation to test finish. It all works on the Android instrumentation tests system that developers are familiar with.

How to setup

buildscript {
    dependencies {
        classpath 'com.shazam.chimprunner:chimprunner-gradle-plugin:3.16.0'
    }
}

Apply the Chimprunner plugin

apply plugin: 'com.shazam.chimprunner'

New tasks will have been added that allow you to run familiar instrumentation tests as performance tests. Verify the tasks exist with:

gradlew tasks | grep chimprunner

Configuring Chimprunner

Configuring Chimprunner is simple. Add the following to your build.gradle file:

chimprunner {
	serial "0123456"
	testPackage "com.example.performancetests"
}

The full list of configurable properties (* are mandatory):

Property Name Property Type Default value Description
baseOutputDir File "chimprunner" the output folder
* serial String - the serial of the device where the performance tests will be executed
ignoreFailures boolean false whether failures of the performance tests should fail the build
testClassRegex String "^((?!Abstract).)*Test$" classes that will be searched for tests
* testPackage String (Your instrumentation APK package) the package where the performance tests are located

Current reports

Currently, Chimprunner produces a timings.csv file in the output folder with all the timings of tests that were executed as part of the performance tests and the average time they took after running a number of iterations. That CSV file can be then used for plotting by other tools. Using the Jenkins Plot plugin we can now produce historic diagrams of our startup time like the following diagram: Chimprunner timing plot

Future work

We would like to add ways of automatically launching Android performance tools & reports developers know and use already, with no or minimal code changes. We will investigate around how to provide systrace, CPU, GPU & memory usage reports. The library will probably provide some annotations that will enable various performance tools. An example could be:

@Test
@Systrace
@Gpu
public void trackListScroll() {
	//...
}

@Test
@Timings(iterations=10)
public void startUpSpeed() {
    //...
}

The system could then provide a systrace & GPU profiling reports for the duration of the trackListScroll() test.

License

Copyright 2019 Apple Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

fork's People

Contributors

alexstyl avatar andreizaitcev avatar asos-veskoiliev avatar badya avatar bersh avatar fpezzato avatar iordanis avatar jbaginski avatar kittsville avatar martynhaigh avatar mihaibolboceanu avatar qautomatron avatar rkochhar avatar silviul avatar tmelz avatar traviswestbrook avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fork's Issues

Some device names cause problems with relative paths

For instance my genymotion device name comes up as:

$ adb devices
List of devices attached
192.168.56.101:5555 device

So inside the pool the generated relative path causes a totally expected issue.

<a href="192.168.56.101:5555/com.foo.test.Test__test.html" data-original-title="" title="">
    LXSearchParamsTest : Required Params Filled
</a>

On the main page it works fine because the generated href is:

<a href="pools/192.168.56.101:5555/com.foo.test.Test__test.html" id="testMethod" data-original-title="Test" data-content="Test (Google_Nexus_5_-_5.0.0_-_API_21_-_1080x1920) [192.168.56.101:5555]">
    &nbsp;
</a>

com/github/mustachejava/MustacheFactory : Unsupported major.minor version 52.0

Recently I started getting this error:

* What went wrong:
Execution failed for task ':app:forkDebug'.
> com/github/mustachejava/MustacheFactory : Unsupported major.minor version 52.0

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Does fork now require Java 8?

1.0.0 gradle plugin: Some warning output after applying fork plugin

I also have the crashlytics plugin applied and it appears as if fork and crashlytics are stomping each other.

log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "com.crashlytics.reloc.org.apache.log4j.Appender" variable.
log4j:ERROR The class "com.crashlytics.reloc.org.apache.log4j.Appender" was loaded by
log4j:ERROR [java.net.URLClassLoader@67e1ff2c] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [org.gradle.internal.classloader.MutableURLClassLoader@34c45dca].
log4j:ERROR Could not instantiate appender named "stdout".

ignore devices that are offline or unauthorized

Fork should ignore devices that are offline or unauthorized, not fail the build.

Or have an option for "only use 'online' devices"

This is what you get with 0.10.0 for offline devices.

com.android.ddmlib.AdbCommandRejectedException: device offline
    at com.android.ddmlib.AdbHelper.setDevice(AdbHelper.java:857)
    at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:460)
    at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:390)
    at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:359)
    at com.android.ddmlib.Device.executeShellCommand(Device.java:557)
    at com.shazam.fork.geometry.RegexDisplayGeometryRetrievalStrategy.getDisplayGeometry(RegexDisplayGeometryRetrievalStrategy.java:54)
    at com.shazam.fork.geometry.RegexDisplayGeometryRetrievalStrategy.retrieveGeometry(RegexDisplayGeometryRetrievalStrategy.java:45)
    at com.shazam.fork.geometry.DeviceGeometryRetriever.detectGeometry(DeviceGeometryRetriever.java:41)
    at com.shazam.fork.system.DeviceLoader.loadDeviceCharacteristics(DeviceLoader.java:83)
    at com.shazam.fork.system.DeviceLoader.loadDevices(DeviceLoader.java:53)
    at com.shazam.fork.ForkRunner.run(ForkRunner.java:70)
    at com.shazam.fork.Fork.run(Fork.java:46)
    at com.shazam.fork.Fork$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:585)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:568)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:306)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
    at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:169)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.Main.doAction(Main.java:33)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:30)
    at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:127)
    at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:56)

Problem with missing ddmlib method

Getting this error after updating gradle to 2.9 and gradle plugin to 1.5.0

Exception in thread "DeviceExecutor-0" java.lang.NoSuchMethodError: com.android.ddmlib.IDevice.installPackage(Ljava/lang/String;Z[Ljava/lang/String;)Ljava/lang/String;
at com.shazam.fork.system.adb.Installer$1.run(Installer.java:53)
at com.shazam.fork.system.adb.Installer.tryThrice(Installer.java:77)
at com.shazam.fork.system.adb.Installer.reinstall(Installer.java:47)
at com.shazam.fork.system.adb.Installer.prepareInstallation(Installer.java:41)
at com.shazam.fork.runner.DeviceTestRunner.run(DeviceTestRunner.java:59)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)

gradle plugin update may have brought a newer version of ddmlib that is not compatible with one used by fork?

Device pool fails to run all the tests

I had this problem (INSTALL_FAILED_UID_CHANGED):
https://code.google.com/p/android/issues/detail?id=79716

Which caused the app to not be installed.

So Fork gave this error:
"Test run failed: Unable to find instrumentation target package:"

Because of the above error forked failed to run most of the tests in that pool, but still reported SUCCESS as the build status.

Fork should fail the overall build status in this case and really any time there is an issue that prevents a test case from being run, the build should fail. ( this could be an optional setting that is configurable )

NoSuchMethodError: org.apache.commons.io.FileUtils.getFile(Ljava/io/File;[Ljava/lang/String;)Ljava/io/File;

When trying to run forkDebug from com.shazam.fork:fork-gradle-plugin:1.0.0-RC1-SNAPSHOT, I get the following NoSuchMethodError: org.apache.commons.io.FileUtils.getFile not found.

:express:forkDebug FAILED
:express:forkDebug (Thread[main,5,main]) completed. Took 0.048 secs.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':express:forkDebug'.
> org.apache.commons.io.FileUtils.getFile(Ljava/io/File;[Ljava/lang/String;)Ljava/io/File;

* Try:
Run with --debug option to get more log output.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':express:forkDebug'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
    at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.Main.doAction(Main.java:33)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
    at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:33)
    at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:130)
    at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:48)
Caused by: java.lang.NoSuchMethodError: org.apache.commons.io.FileUtils.getFile(Ljava/io/File;[Ljava/lang/String;)Ljava/io/File;
    at com.shazam.fork.system.adb.SpoonUtils.initAdb(SpoonUtils.java:35)
    at com.shazam.fork.injector.system.AndroidDebugBridgeInjector.<clinit>(AndroidDebugBridgeInjector.java:21)
    at com.shazam.fork.injector.pooling.DeviceLoaderInjector.deviceLoader(DeviceLoaderInjector.java:24)
    at com.shazam.fork.injector.pooling.PoolLoaderInjector.poolLoader(PoolLoaderInjector.java:21)
    at com.shazam.fork.injector.ForkRunnerInjector.forkRunner(ForkRunnerInjector.java:39)
    at com.shazam.fork.Fork.<init>(Fork.java:41)
    at com.shazam.fork.ForkBuilder.build(ForkBuilder.java:153)
    at com.shazam.fork.ForkBuilder$build$6.call(Unknown Source)
    at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:70)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 47 more

Fork fails to run on Gradle v1.0.0

Fork was working fine with Gradle v0.12. After updating to Gradle v1.0.0 (as part of updating to Android Studio v1.0), my builds now fail with the error below.

* What went wrong:
A problem occurred configuring project ':CookBrite'.
> Could not find property 'outputFile' on com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated@50434e01.

I was trying to run:

./gradlew forkDevDebugTest -Dandroid.test.classes=com.cookbrite.step1_unit.MySingleTestClass

This bug does not affect Spoon, so you may be able to check their code for a solution? I wasn't able to spot it by checking their most recent commits.

Create -alpha releases

It would be helpful to create -alpha1, -alpha2 releases and git tags.

1.1.0-SNAPSHOT might be different in the morning than in the evening which can make troubleshooting harder, it would be nice to be able to control when we jump to the next version.

Also, by having git tags tied to specific alpha releases, it helps us debug if we want to look at the source code of fork.

Sort test order in the HTML report

Sort test order in the HTML report, so that each device pool shows the tests in the same order.

This will help identify patterns of broken tests ( vertical red lines across device pools ).

Test cases are ignored when method name contains characters like Chinese

Hi, since upgrade fork to the new release 1.3.0, My test cases are ignored to execute, i've notice that only the method name in Chinese is not executed, any ideas about this?
I'm using 2.10 and AS plugin 2.1.0-beta1, any suggestions will be appreciated:)

I feel it is because of these file changes, Do we changed a way to get the test method ?

  • TestCaseEvent.java
  • TestRun.java
  • TestRunFactory.java
  • TestRunParameters.java

Allow changing the order of tests that are run

It appears as if fork runs tests alphabetically based on package+class name.

My thinking is similar to how TeamCity will run failing tests from the last build as the first tests of the current build to speedup feedback.

Perhaps tests that match a provided regular expression (eg failingTest1,failingTest2) will be prioritized before the other tests. Coupled with the "fail fast" feature requested elsewhere this could help decrease the load on environments with shared device resources.

Simplify package configuration: test package should be the same as app package

By default Android Studio creates tests in the same package as the package of the main application, e.g. com.example.

Even if the eventual package of the test application has the test suffix (com.example.test), the test classes are still in com.example.

Fork should be modified to follow the default AS behaviour.

Fork marks build as failed, even when all tests have passed.

Fork often fails the build even when all the tests pass.

This is using 0.10.0. ( we can't use 0.11.0, because the screenshot stuff is causing problems and it can't be disabled. )

This happens frequently with 20+ devices attached.

Pools remaining: 0
  0 E    0 F   123 P: older=api0-17
  0 E    0 F   123 P: Newer=api18-up
No suppressed tests.
Device  pending after 120 seconds of inactivity
Apparently, no devices pending. Aborting in 15sec

Related to this code:
https://github.com/shazam/fork/blob/d0e1dce11d2214c7c1e91fca6c928b9df44723e5/src/main/java/com/shazam/fork/runtime/TimeoutAlert.java

Allow "android.test.classes" per pool

I would like to be able to have a different android.test.classes for each pool.

For example, I might want to run a separate set of tests on my API 18+ devices.

Maybe android.test.classes.$pool_name$

Allow configuration in a Gradle file

It would be nice to be able to configure via the gradle file, something like:

fork {
    testClassRegex = "*.Important" 
    apiPools = { 
                  "old": 0,
                "new": 15
        }
}

Enable code coverage.

As far as I can tell Fork does not support code coverage. I think there should be an optional configuration for enabling code coverage and specifying the directory to which the coverage files should be output to. I can submit a pull request to do so, just wanted to be sure I wasn't missing something or if there was a reason for not supporting the generation of the coverage files.

Support for latest ddmlib

Fork has an issue with the ddmlib version used by the Android gradle plugin v0.14.x
In practice, this makes it look like all the tests pass ( failures don't get reported ).

Fork needs a similar fix:

square/spoon#210

Exception in thread "DeviceExecutor-1" java.lang.AbstractMethodError: com.shazam.fork.TestRunActivityWatchdog.testFailed(Lcom/android/ddmlib/testrunner/TestIdentifier;Ljava/lang/String;)V
    at com.android.ddmlib.testrunner.InstrumentationResultParser.reportResult(InstrumentationResultParser.java:461)
    at com.android.ddmlib.testrunner.InstrumentationResultParser.parseStatusCode(InstrumentationResultParser.java:415)
    at com.android.ddmlib.testrunner.InstrumentationResultParser.parse(InstrumentationResultParser.java:276)
    at com.android.ddmlib.testrunner.InstrumentationResultParser.processNewLines(InstrumentationResultParser.java:247)
    at com.android.ddmlib.MultiLineReceiver.addOutput(MultiLineReceiver.java:94)
    at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:521)
    at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:387)
    at com.android.ddmlib.Device.executeShellCommand(Device.java:565)
    at com.android.ddmlib.testrunner.RemoteAndroidTestRunner.run(RemoteAndroidTestRunner.java:263)
    at com.android.ddmlib.testrunner.RemoteAndroidTestRunner.run(RemoteAndroidTestRunner.java:248)
    at com.shazam.fork.TestRun.execute(TestRun.java:54)
    at com.shazam.fork.TestSuiteRunnerTask.runIndividualTestClass(TestSuiteRunnerTask.java:90)
    at com.shazam.fork.TestSuiteRunnerTask.run(TestSuiteRunnerTask.java:59)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

java.lang.IllegalArgumentException: Array is empty

I'm using 'com.shazam.fork:fork-gradle-plugin:1.0.0-RC1-SNAPSHOT', and running

./gradlew forkDebug -Dfork.test.size=medium -Dfork.pool.a=192.168.56.102:5555,192.168.56.101:5555 -Dfork.eachdevice=false

results in:

Error while Fork runner was executing
java.lang.IllegalArgumentException: Array is empty
    at org.apache.commons.lang3.BooleanUtils.and(BooleanUtils.java:944)
    at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:58)
    at com.shazam.fork.summary.OutcomeAggregator.access$100(OutcomeAggregator.java:27)
    at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:42)
    at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:36)
    at com.google.common.collect.Iterators$8.transform(Iterators.java:794)
    at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:48)
    at java.util.AbstractCollection.toArray(AbstractCollection.java:195)
    at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:58)
    at com.shazam.fork.summary.OutcomeAggregator.aggregate(OutcomeAggregator.java:32)
    at com.shazam.fork.summary.HtmlConverters.toHtmlSummary(HtmlConverters.java:36)
    at com.shazam.fork.summary.HtmlSummaryPrinter.print(HtmlSummaryPrinter.java:74)
    at com.shazam.fork.summary.CompositeSummaryPrinter.print(CompositeSummaryPrinter.java:14)
    at com.shazam.fork.summary.ReportGeneratorHook.generateReportOnlyOnce(ReportGeneratorHook.java:72)
    at com.shazam.fork.ForkRunner.run(ForkRunner.java:87)
    at com.shazam.fork.Fork.run(Fork.java:50)
    at com.shazam.fork.Fork$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
    at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.Main.doAction(Main.java:33)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:33)
    at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:130)
    at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:48)

Also, Sonatype seems to be out of sync with development here. Would you guys mind updating it?

Build Failed (with gradle plugin)

build failed (with fork plugin) using the command:

./gradlew fork

Also the test report output was useless (see screenies) I got this stacktrace from the command line.
(geny motion emu)

Build passes with:

./gradlew connectedAndroidTest

:app:preBuild                                                                                            
:app:compileDebugNdk UP-TO-DATE     
:app:preDebugBuild                
:app:checkDebugManifest                
:app:prepareDebugDependencies                
:app:compileDebugAidl UP-TO-DATE     
:app:compileDebugRenderscript UP-TO-DATE      
:app:generateDebugBuildConfig UP-TO-DATE      
:app:generateDebugAssets UP-TO-DATE      
:app:mergeDebugAssets UP-TO-DATE      
:app:generateDebugResValues UP-TO-DATE      
:app:generateDebugResources UP-TO-DATE      
:app:mergeDebugResources UP-TO-DATE      
:app:processDebugManifest UP-TO-DATE      
:app:processDebugResources UP-TO-DATE      
:app:generateDebugSources UP-TO-DATE      
:core:compileJava UP-TO-DATE                                               
:core:processResources UP-TO-DATE      
:core:classes UP-TO-DATE      
:core:jar UP-TO-DATE      
:app:compileDebugJava UP-TO-DATE      
:app:unzipJacocoAgent UP-TO-DATE      
:app:instrumentDebug UP-TO-DATE                                                       
:app:preDexDebug UP-TO-DATE      
:app:dexDebug UP-TO-DATE      
:app:processDebugJavaRes UP-TO-DATE      
:app:validateDebugSigning                 
:app:packageDebug UP-TO-DATE      
:app:zipalignDebug UP-TO-DATE      
:app:assembleDebug UP-TO-DATE      
:app:compileDebugTestNdk UP-TO-DATE      
:app:preDebugTestBuild                 
:app:prepareDebugTestDependencies                 
:app:compileDebugTestAidl UP-TO-DATE      
:app:processDebugTestManifest UP-TO-DATE      
:app:compileDebugTestRenderscript UP-TO-DATE      
:app:generateDebugTestBuildConfig UP-TO-DATE      
:app:generateDebugTestAssets UP-TO-DATE      
:app:mergeDebugTestAssets UP-TO-DATE      
:app:generateDebugTestResValues UP-TO-DATE      
:app:generateDebugTestResources UP-TO-DATE      
:app:mergeDebugTestResources UP-TO-DATE      
:app:processDebugTestResources UP-TO-DATE      
:app:generateDebugTestSources UP-TO-DATE      
:app:compileDebugTestJava UP-TO-DATE      
:app:preDexDebugTest UP-TO-DATE      
:app:dexDebugTest UP-TO-DATE      
:app:processDebugTestJavaRes UP-TO-DATE      
:app:packageDebugTest UP-TO-DATE      
:app:assembleDebugTest UP-TO-DATE      
:app:forkDebug                 
Use -Dandroid.test.classes=REGEX to specify a pattern for the classes/packages to run
Use -Dfork.tablet=(true|false) to configure pools depending on their manufacturer's 'tablet' flag (ro.build.characteristics)
Use -Dfork.pool.POOL_NAME=(Serial','?)* to add devices with a given serial to a pool with given name,e.g. hdpi=01234567,abcdefgh
Use -Dfork.computed.STRATEGY=(PoolName=LowerBound','?)* to automatically create pools based on device characteristics
STRATEGY:=sw - by smallest width, e.g.phablet=0,tablet=720
STRATEGY:=api - by api, e.g. gingerbread_and_earlier=0,honeycomb_and_later=11)
Use -Dfork.eachdevice=(true|false) to create a pool per device (a.k.a. Spoon mode). This is the default behaviour.
Use -Dfork.excluded.serial=(Serial','?)* to exclude specific devices from running any tests
Use -Dfork.report.title=Title to specify a title for the generated report
Use -Dfork.report.subtitle=Subitle to specify a subtitle for the generated report
Error while Fork runner was executing
java.lang.IllegalArgumentException: Array is empty
        at org.apache.commons.lang3.BooleanUtils.and(BooleanUtils.java:929)
        at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:59)
        at com.shazam.fork.summary.OutcomeAggregator.access$100(OutcomeAggregator.java:27)
        at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:42)
        at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:36)
        at com.google.common.collect.Iterators$8.transform(Iterators.java:794)
        at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:48)
        at java.util.AbstractCollection.toArray(AbstractCollection.java:195)
        at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:59)
        at com.shazam.fork.summary.OutcomeAggregator.aggregate(OutcomeAggregator.java:32)
        at com.shazam.fork.ForkRunner.run(ForkRunner.java:115)
        at com.shazam.fork.Fork.run(Fork.java:46)
        at com.shazam.fork.Fork$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
        at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:62)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
        at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
        at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:47)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:35)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:24)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.StartStopIfBuildAndStop.execute(StartStopIfBuildAndStop.java:33)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:71)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:69)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:69)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:70)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.DaemonHygieneAction.execute(DaemonHygieneAction.java:39)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:46)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
        at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
:app:forkDebug FAILED          

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:forkDebug'.
> Tests failed! See /Users/Blundell/MyApp/app/build/fork/debug/html/index.html

* Try:        
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED  

Total time: 20.536 secs

screen shot 2015-02-03 at 21 42 02
screen shot 2015-02-03 at 21 42 06

I would have expected it to work with all default params. It saying array is empty makes me think it might need a argument? or looking at the source https://github.com/shazam/fork/blob/master/src/main/java/com/shazam/fork/summary/OutcomeAggregator.java#L58 it's looking for test outcomes, so has it failed to pull the results from the device?

IllegalArgumentException while creating html report

Version : 1.1.1-SNAPSHOT

java.lang.IllegalArgumentException: Array is empty    
        at org.apache.commons.lang3.BooleanUtils.and(BooleanUtils.java:944)
        at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:62)
        at com.shazam.fork.summary.OutcomeAggregator.access$100(OutcomeAggregator.java:27)
        at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:46)
        at com.shazam.fork.summary.OutcomeAggregator$1.apply(OutcomeAggregator.java:40)
        at com.google.common.collect.Iterators$8.transform(Iterators.java:794)
        at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:48)
        at java.util.AbstractCollection.toArray(AbstractCollection.java:195)
        at com.shazam.fork.summary.OutcomeAggregator.and(OutcomeAggregator.java:62)
        at com.shazam.fork.summary.OutcomeAggregator.aggregate(OutcomeAggregator.java:36)
        at com.shazam.fork.summary.HtmlConverters.toHtmlSummary(HtmlConverters.java:36)
        at com.shazam.fork.summary.HtmlSummaryPrinter.print(HtmlSummaryPrinter.java:68)
        at com.shazam.fork.summary.CompositeSummaryPrinter.print(CompositeSummaryPrinter.java:14)
        at com.shazam.fork.summary.Summarizer.summarize(Summarizer.java:33)
        at com.shazam.fork.summary.SummaryGeneratorHook.defineOutcome(SummaryGeneratorHook.java:63)
        at com.shazam.fork.ForkRunner.run(ForkRunner.java:75)
        at com.shazam.fork.Fork.run(Fork.java:50)     
        at com.shazam.fork.Fork$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
        at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:74)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:226)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:219)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:208)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:589)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:572)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:310)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:90)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:49)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:66)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:71)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745) 

This might be related to #55

Implement screenshot capture

Our current solution of screenshots depends on a third party library. It would be better to avoid it and use the system commands for taking screenshots, probably once at the end of the test.

Linked to video capture: #1

Maven central update requested

Having snapshots is really nice, but to use fork for CI we need to be locked down on a stable version. Would you guys mind publishing the current state as a minor version?

Unable to include fork plugin in my project

Hi,

I modified my build.gradle file to include following two changes and then ran "./gradlew clean" command.
buildscript {
dependencies {
...
classpath 'com.shazam.fork:fork-gradle-plugin:1.1.1-SNAPSHOT'
}
repositories() {
mavenLocal();
maven {
...
}
mavenCentral();
flatDir {
dirs 'libs'
}
jcenter()
}
}
...
apply plugin: 'fork'
....
}
Am seeing the following error:
FAILURE: Build failed with an exception.

  • What went wrong:
    A problem occurred configuring project ':App'.

    Could not resolve all dependencies for configuration ':App:classpath'.
    Could not find com.shazam.fork:fork-gradle-plugin:1.1.1-SNAPSHOT.

Can you please let us know what am i doing wrong here?

Thanks,
Pavan

Fork reports no devices are found after multiple runs

Even if adb devices reports one or more devices are found, when executing Fork consecutively, it reports that no devices are found.

This only happens when someone is using the Gradle daemon and can temporarily work around it by stopping it (./gradlew --stop).

Cannot run Fork

I followed the instructions in the README.md file, and when running

./gradlew forkDebug

I get:

Configuring devices and pools failed
com.shazam.fork.pooling.NoDevicesForPoolException: No devices found.

Is there any extra configuration needed to make fork run? I am just trying to run UATs on two different emulators to save time.

NumberFormatException: For input string: "Unspecified API Level"

This is an intermittent error ( it worked when I just re-ran it ).
It might have been an ADB hiccup.

Use -Dfork.report.subtitle=Subitle to specify a subtitle for the generated report
Error while Fork runner was executing
java.lang.NumberFormatException: For input string: "Unspecified API Level"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at com.shazam.fork.pooling.PoolByApi.getParameter(PoolByApi.java:29)
    at com.shazam.fork.pooling.SmallestComputedPoolsSelector.poolForDevice(SmallestComputedPoolsSelector.java:37)
    at com.shazam.fork.pooling.ComputedDevicePoolLoader.createComputedPools(ComputedDevicePoolLoader.java:53)
    at com.shazam.fork.pooling.ComputedDevicePoolLoader.loadPools(ComputedDevicePoolLoader.java:45)
    at com.shazam.fork.pooling.CompositeDevicePoolLoader.loadPools(CompositeDevicePoolLoader.java:38)
    at com.shazam.fork.ForkRunner.run(ForkRunner.java:76)
    at com.shazam.fork.Fork.run(Fork.java:46)
    at com.shazam.fork.Fork$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at com.shazam.fork.gradle.ForkRunTask.runFork(ForkRunTask.groovy:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)

Add fast fail option

It would be nice to have an option to fast fail a build.

i.e. if anything goes wrong or any test fails, just stop immediately and fail the build, don't bother running the rest of the tests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.