Git Product home page Git Product logo

marathonlabs / marathon Goto Github PK

View Code? Open in Web Editor NEW
566.0 17.0 121.0 55.67 MB

Cross-platform test runner

Home Page: https://docs.marathonlabs.io

License: GNU General Public License v2.0

Kotlin 89.46% Shell 0.28% CSS 0.23% JavaScript 5.76% HTML 0.42% SCSS 3.85%
android testing testing-tool test-runner espresso uitest uitesting uitests ios marathon xcrun instrumentation instrumentation-tests gradle parallel performance orchestrator hacktoberfest

marathon's Introduction

Marathon Logo

GitHub release Slack Telegram PRs Welcome

Releases   |   Documentation   

Marathon is a project that helps execute tests in the shortest time possible. Specifically it helps with stability of test execution adjusting for flakiness in the environment and in the tests and also achieves best performance using high parallelization

TL;DR

Marathon is a fast, platform-independent test runner focused on performance and stability. It offers easy to use platform implementations for Android and iOS as well as an API for use with custom hardware farms and more techstacks.

Marathon implements multiple key concepts of test execution such as test batching, device pools, test sharding, test sorting, preventive retries as well as post-factum retries. By default, most of these are set to conservative defaults but custom configurations are encouraged for those who want to optimize performance and/or stability.

Marathon's primary focus is on full control over the balance between stability of test execution, testing performance and cost.

For more information see the documentation

Overview

Performance

Marathon takes into account two key aspects of test execution:

  • The duration of the test
  • The probability of the test passing

Test run can only finish as quickly as possible if we plan the execution of tests with regard to the expected duration of the test. On the other hand, we need to address the flakiness of the environment and of the test itself. One key indicator of flakiness is the probability of the test passing.

Marathon takes a number of steps to ensure that each test run is as balanced as possible:

  • The flakiness strategy queues up preventive retries for tests which are expected to fail during the test run according to the current real-time statistical data
  • The sorting strategy forces long tests to be executed first so that if an unexpected retry attempt occurs it doesn't affect the test run significantly (e.g. at the end of execution)
  • If all else fail we revert back to post-factum retries, but we try to limit their impact on the run with retry quotas

Configuration

Create a basic Marathonfile in the root of your project with the following content:

Android:

name: "My application"
outputDir: "build/reports/marathon"
vendorConfiguration:
  type: "Android"
  applicationApk: "dist/app-debug.apk"
  testApplicationApk: "dist/app-debug-androidTest.apk"

iOS:

name: "My application"
outputDir: "derived-data/Marathon"
vendorConfiguration:
  type: "iOS"
  bundle:
    application: "sample.app"
    testApplication: "sampleUITests.xctest"
    testType: xcuitest

Vendor section describes platform specific details.

Since iOS doesn't have any way to discover remote execution devices you have to provide your simulators using the Marathondevices file:

workers:
  - transport:
      type: local
    devices:
      - type: simulator
        udid: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
      - type: simulatorProfile
        deviceType: com.apple.CoreSimulator.SimDeviceType.iPhone-13-mini

This Marathondevices file specifies a list of macOS instances and simulators for use. Marathon can use pre-provisioned simulators, but it can also provision new ones if needed.

Example above uses the local instance where marathon is executed, but you can connect many more instance via SSH.

ℹ️ The instance where you run marathon is not limited to macOS: if you're using remote macOS instances then you can easily start your marathon run from Linux for example.

You can find more information on providing devices in the workers documentation

The file structure for testing should look something like this:

Android:

foo@bar $ tree .  
.
├── Marathonfile
├── dist
│   ├── app-debug.apk
│   ├── app-debug-androidTest.apk

iOS:

foo@bar $ tree .  
.
├── Marathondevices
├── Marathonfile
├── build
│   ├── my.app
│   ├── my.xctest

Execution

Start the test runner in the root of your project

$ marathon 
XXX [main] INFO com.malinskiy.marathon.cli.ApplicationView - Starting marathon
XXX [main] INFO com.malinskiy.marathon.cli.config.ConfigFactory - Checking Marathonfile config
...

Requirements

Marathon requires Java Runtime Environment 8 or higher.

Move even faster with Marathon Cloud

Marathon Logo

Marathon Cloud is a scalable testing-as-a-service product designed and developed by us, the creators of Marathon. It's got all the cloud testing infrastructure you need to run any number of tests in less than 15 minutes, whether you're a startup or a large enterprise.

Learn more

Contributing

See contributing docs

License

Marathon codebase is GPL 2.0 LICENSE with following optional components under specific licenses:

marathon's People

Contributors

austyh avatar bartek-wesolowski avatar borisosipov avatar cdsap avatar dependabot[bot] avatar j-vegas avatar kavabunga6 avatar kerem356 avatar litemn avatar lukaville avatar lukyanovanatoliy avatar mabae avatar malinskiy avatar matzuk avatar memega avatar mikepenz avatar plastiv avatar raikerian avatar rupinr avatar sergkhram avatar snpefk avatar tagantroy avatar tieru avatar timoptr avatar trevjonez avatar tseperi avatar vacxe avatar vfadc avatar victorireri avatar zoey-juan 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

marathon's Issues

Batching Strategies

We still don't have implementation of batching strategy, except default strategy 1 test = 1 batch.

  • Fixed size batches #29
  • Batches based on data from analytics for example batch size up to 5 minutes #32

SummaryReport Empty

Due some infrastructure problems(adb/ddms) sometimes we are getting TestResults like:
'{"testName":"Test])","status":"INCOMPLETE","startDate":0,"endDate":0,"expectedValue":0.0,"variance":0}'
Causing problems in the distribution report:
screen shot 2561-11-09 at 16 09 26

CI

We need ci to validate changes (develop is broken atm >.>)

I can help with circle ci setup if you want.

DeviceActor refactoring

  • Remove mutable job field from DeviceActor.
  • Extract StateMachine. Add tests
  private val context = newSingleThreadContext(device.toString())

    private var job by Delegates.observable<Job?>(null) { _, _, newValue ->
        newValue?.invokeOnCompletion {
            if (it == null) {
                state.transition(DeviceEvent.Complete)
            } else {
                it.printStackTrace()
                logger.error(it) { "Error ${it.message}" }
                state.transition(DeviceEvent.Terminate)
                terminate()
            }
        }
    }

Pooling Strategies

We need define more pooling strategies. Right now we have only one strategy - common pool.
Probably we need strategy which will separate tablets and phones, run all tests on each device.
@dsvoronin @Malinskiy what do you think?

Exception for "Unknown" model

marathon 0.1.1
seems like a valid case (it's always Unknown for emulator?)

Exception in thread "AndroidDevice(model=Unknown, serial=openstf-emulator.dev:1001)" java.lang.NumberFormatException: For input string: "unknown"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.lang.Integer.parseInt(Integer.java:580)
        at java.lang.Integer.parseInt(Integer.java:615)
        at com.malinskiy.marathon.android.AndroidDevice.getDeviceFeatures(AndroidDevice.kt:43)
        at com.malinskiy.marathon.device.DeviceInfoKt.toDeviceInfo(DeviceInfo.kt:17)
        at com.malinskiy.marathon.android.executor.listeners.AnalyticsListenerKt.toTestResult(AnalyticsListener.kt:26)
        at com.malinskiy.marathon.android.executor.listeners.AnalyticsListener.handleTestRunResults(AnalyticsListener.kt:19)
        at com.malinskiy.marathon.android.executor.listeners.AbstractTestRunResultListener.testRunEnded(AbstractTestRunResultListener.kt:44)
        at com.malinskiy.marathon.android.executor.listeners.CompositeTestRunListener.testRunEnded(CompositeTestRunListener.kt:44)
        at com.android.ddmlib.testrunner.InstrumentationResultParser.handleTestRunFailed(InstrumentationResultParser.java:618)
        at com.android.ddmlib.testrunner.InstrumentationResultParser.submitCurrentKeyValue(InstrumentationResultParser.java:339)
        at com.android.ddmlib.testrunner.InstrumentationResultParser.parse(InstrumentationResultParser.java:310)
        at com.android.ddmlib.testrunner.InstrumentationResultParser.processNewLines(InstrumentationResultParser.java:267)
        at com.android.ddmlib.MultiLineReceiver.addOutput(MultiLineReceiver.java:103)
        at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:572)
        at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:383)
        at com.android.ddmlib.Device.executeShellCommand(Device.java:635)
        at com.android.ddmlib.testrunner.RemoteAndroidTestRunner.run(RemoteAndroidTestRunner.java:270)
        at com.android.ddmlib.testrunner.RemoteAndroidTestRunner.run(RemoteAndroidTestRunner.java:255)
        at com.malinskiy.marathon.android.executor.AndroidDeviceTestRunner.execute(AndroidDeviceTestRunner.kt:47)
        at com.malinskiy.marathon.android.AndroidDevice$execute$2.doResume(AndroidDevice.kt:89)
        at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
        at kotlinx.coroutines.experimental.DispatchTask.run(CoroutineDispatcher.kt:123)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

Sorting Strategies

We already implemented analytics integration(with influxdb) and we can start implementing custom sorting strategies based on this analytics.

Analytics module

Some extra metrics required for "smart" batching and sorting.

  • Save execution results to InfluxDb
  • Query test success rate
  • Query test execution time(percentile)

Launching single class UI test

It's feature request: consider to add the possibility to launch single UI test class (with several tests) from terminal/console

It's important for development/debugging

P.S. IDE plugin also could be good option in the future.

Parse annotation values

2.0.0 dex parser lib support annotation values.
We should add support for values too, because it can be useful for some cases.

Usage analytics

We want to have anonymised usage data from users of marathon test runner to better understand most relevant use-cases for the runner. For example we want to understand how long is the average queue during the test run, how many execution units are available and so on

This should be enable only by user accepting to send this data. So either a configuration option in Marathonfile/CLI/gradle-plugin or some interactive question during the run, but we need to think about CI use-cases where interactive questions are not an option and we shouldn't hang the build because of this.

Support test running for library projects

Currently testApplicationOutput param is required and marathon-gradle-plugin throws an exception if you try to apply it to a library project:

A problem occurred configuring project ':components:SomeUiPart'.
> com.android.build.gradle.internal.api.LibraryVariantOutputImpl_Decorated cannot be cast to com.android.build.gradle.api.ApkVariantOutput

Fix JUnit report

Time always 0.0
Example
<?xml version="1.0" encoding="UTF-8"?><testsuite name="MainActivityFlakyTest.testTextFlaky2" tests="1" failures="0" errors="0" skipped="0" time="0.0" timestamp="2018-07-24T10:36:58"><properties></properties><testcase classname="com.example.MainActivityFlakyTest" name="testTextFlaky2" time="0.0"></testcase></testsuite>

Test state machines

Implement unit tests for:

  • DeviceActor
  • PoolProgressTracker
  • TestResultReporter

Filtering of executed tests

Whitelist + blacklist of tests by

  • test class simple or FQN name
  • test package
  • FQN test annotation

The logic should get all the available tests first, then it should apply all the whitelists from different groups (if available), then apply all blacklists to everything that is still left (if available)

include ':sample-app' ?

Why it is separated and not included in multiproject build? It would be handy(if possible) to check integration in single gradle run

missing dependencies in configuration

missing dependencies when apply plugin: 'marathon'
Caused by: java.lang.NoClassDefFoundError: com/malinskiy/marathon/execution/Configuration
unless add dependencies by adding "com.malinskiy.marathon:core"

CLI/YML configuration

We need CLI/YML configuration, because with current implementation we cannot use marathon w/o gradle

Cannot round NaN value

Disconnected device error hidden under unhelpful Cannot round NaN value in ProgressReporter:27
val percent = (float * 100.0).roundToInt()

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.