Bug 1302192: combine the android-test and desktop-test kinds into the test kind; r=wcosta r?jmaher draft
authorDustin J. Mitchell <dustin@mozilla.com>
Fri, 23 Dec 2016 22:12:17 +0000
changeset 454196 c3c701a614972c125b814b9272310d487433c7d5
parent 454195 9e530a2503e671f65e94de8dc53bf0720484de04
child 454197 131d8c0639a36c75dbddb4c0ef1443c0b8890a90
push id39862
push userdmitchell@mozilla.com
push dateWed, 28 Dec 2016 14:40:33 +0000
reviewerswcosta, jmaher
bugs1302192
milestone53.0a1
Bug 1302192: combine the android-test and desktop-test kinds into the test kind; r=wcosta r?jmaher This makes heavy use of by-test-platform to distinguish the various platforms, since Android mozharness invocations differ substantially from desktop. MozReview-Commit-ID: GsZFij6VPTf
taskcluster/ci/android-test/kind.yml
taskcluster/ci/android-test/test-platforms.yml
taskcluster/ci/android-test/test-sets.yml
taskcluster/ci/android-test/tests.yml
taskcluster/ci/desktop-test/kind.yml
taskcluster/ci/desktop-test/test-platforms.yml
taskcluster/ci/desktop-test/test-sets.yml
taskcluster/ci/desktop-test/tests.yml
taskcluster/ci/test/kind.yml
taskcluster/ci/test/test-platforms.yml
taskcluster/ci/test/test-sets.yml
taskcluster/ci/test/tests.yml
taskcluster/docs/kinds.rst
taskcluster/docs/transforms.rst
taskcluster/taskgraph/transforms/tests.py
deleted file mode 100644
--- a/taskcluster/ci/android-test/kind.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-implementation: taskgraph.task.test:TestTask
-
-kind-dependencies:
-    - build
-
-transforms:
-   - taskgraph.transforms.tests:transforms
-   - taskgraph.transforms.task:transforms
deleted file mode 100644
--- a/taskcluster/ci/android-test/test-platforms.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file maps build platforms to test platforms.  In some cases, a
-# single build may be tested on multiple test platforms, but a single test
-# platform can only link to one build platform.  Both build and test platforms
-# are represented as <platform>/<type>, where <type> is what Treeherder calls a
-# collection.
-#
-# Each test platform further specifies the set of tests that will be scheduled
-# for the platform, referring to tests defined in test-sets.yml.
-#
-# Note that set does not depend on the tree; tree-dependent job selection
-# should be performed in the target task selection phase of task-graph
-# generation.
-
-android-4.3-arm7-api-15/debug:
-    build-platform: android-api-15/debug
-    test-sets:
-        - debug-tests
-android-4.3-arm7-api-15/opt:
-    build-platform: android-api-15/opt
-    test-sets:
-        - opt-tests
-android-4.2-x86/opt:
-    build-platform: android-x86/opt
-    test-sets:
-        - x86-tests
-android-4.3-arm7-api-15-gradle/opt:
-    build-platform: android-api-15-gradle/opt
-    test-sets:
-        - gradle-tests
deleted file mode 100644
--- a/taskcluster/ci/android-test/test-sets.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-# Each key in this file specifies a set of tests to run.  Different test sets
-# may, for example, be bound to different test platforms.
-#
-# Note that set does not depend on the tree; tree-dependent job selection
-# should be performed in the target task selection phase of task-graph
-# generation.
-#
-# A test set has a name, and a list of tests that it contains.
-#
-# Test names given here reference tests.yml.
-
-debug-tests:
-    - cppunit
-    - crashtest
-    - jsreftest
-    # Marionette only available on Fennec debug builds as a security precaution
-    - marionette
-    - mochitest
-    - mochitest-chrome
-    - mochitest-clipboard
-    - mochitest-gpu
-    - mochitest-media
-    - mochitest-webgl
-    - reftest
-    - xpcshell
-
-opt-tests:
-    - cppunit
-    - crashtest
-    - jsreftest
-    - mochitest
-    - mochitest-chrome
-    - mochitest-clipboard
-    - mochitest-gpu
-    - mochitest-media
-    - mochitest-webgl
-    - reftest
-    - robocop
-    - xpcshell
-
-gradle-tests:
-    - robocop
-    - mochitest-chrome
-
-x86-tests:
-    - xpcshell
-    - mochitest-chrome
deleted file mode 100644
--- a/taskcluster/ci/android-test/tests.yml
+++ /dev/null
@@ -1,281 +0,0 @@
-# Each stanza here describes a particular test suite or sub-suite.  These are
-# processed through the transformations described in kind.yml to produce a
-# bunch of tasks.  See the schema in `test-descriptions.py` for a description
-# of the fields used here.
-
-# The Android tests have separate test definitions from desktop because,
-# despite sharing test names, the invocation of these test suites differ
-# substantially from desktop.
-
-# Note that these are in lexical order
-
-cppunit:
-    description: "CPP Unit Tests"
-    suite: cppunittest
-    treeherder-symbol: tc(Cpp)
-    e10s: false
-    loopback-video: true
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=cppunittest
-
-crashtest:
-    description: "Crashtest run"
-    suite: reftest/crashtest
-    treeherder-symbol: tc-R(C)
-    instance-size: xlarge
-    chunks:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 10
-            default: 4
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=crashtest
-
-jsreftest:
-    description: "JS Reftest run"
-    suite: reftest/jsreftest
-    treeherder-symbol: tc-R(J)
-    instance-size: xlarge
-    chunks:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 20
-            default: 6
-    loopback-video: true
-    max-run-time: 7200
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=jsreftest
-
-marionette:
-    description: "Marionette unittest run"
-    suite: marionette
-    treeherder-symbol: tc(Mn)
-    chunks: 10
-    instance-size: xlarge
-    loopback-video: true
-    e10s: false
-    tier: 3
-    max-run-time: 3600
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=marionette
-
-mochitest:
-    description: "Mochitest plain run"
-    suite: mochitest/plain-chunked
-    treeherder-symbol: tc-M()
-    instance-size: xlarge
-    chunks:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 32
-            default: 20
-    loopback-video: true
-    e10s: false
-    max-run-time:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 10800
-            default: 5400
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=mochitest
-
-mochitest-chrome:
-    description: "Mochitest chrome run"
-    suite: mochitest/chrome
-    treeherder-symbol: tc-M(c)
-    instance-size: xlarge
-    chunks:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 2
-            default: 1
-    loopback-video: true
-    e10s: false
-    max-run-time: 5400
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                default:
-                    - android/androidarm_4_3.py
-                    - remove_executables.py
-                    - android/androidarm_4_3-tc.py
-                android-4.2-x86/opt:
-                    - android/androidx86-tc.py
-        extra-options:
-            - --test-suite=mochitest-chrome
-
-mochitest-clipboard:
-    description: "Mochitest clipboard run"
-    suite: mochitest/clipboard
-    treeherder-symbol: tc-M(cl)
-    instance-size: xlarge
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=mochitest-plain-clipboard
-
-mochitest-gpu:
-    description: "Mochitest gpu run"
-    suite: mochitest/gpu
-    treeherder-symbol: tc-M(gpu)
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=mochitest-plain-gpu
-
-mochitest-media:
-    description: "Mochitest media run"
-    suite: mochitest/mochitest-media
-    treeherder-symbol: tc-M(mda)
-    instance-size: xlarge
-    chunks: 3
-    loopback-video: true
-    e10s: false
-    max-run-time: 5400
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=mochitest-media
-
-mochitest-webgl:
-    description: "Mochitest webgl run"
-    suite: mochitest/mochitest-gl
-    treeherder-symbol: tc-M(gl)
-    chunks: 10
-    loopback-video: true
-    e10s: false
-    max-run-time: 7200
-    instance-size: xlarge
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=mochitest-gl
-
-reftest:
-    description: "Reftest run"
-    suite: reftest/reftest
-    treeherder-symbol: tc-R(R)
-    chunks:
-        by-test-platform:
-            android-4.3-arm7-api-15/debug: 48
-            default: 16
-    instance-size: xlarge
-    max-run-time: 10800
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=reftest
-
-robocop:
-    description: "Robocop run"
-    suite: robocop
-    treeherder-symbol: tc-M(rc)
-    instance-size: xlarge
-    chunks:
-        by-test-platform:
-            # android-4.3-arm7-api-15/debug -- not run
-            android-4.3-arm7-api-15/opt: 4
-            android-4.3-arm7-api-15-gradle/opt: 4
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        config:
-            - android/androidarm_4_3.py
-            - remove_executables.py
-            - android/androidarm_4_3-tc.py
-        extra-options:
-            - --test-suite=robocop
-
-xpcshell:
-    description: "xpcshell test run"
-    suite: xpcshell
-    treeherder-symbol: tc-X()
-    chunks:
-        by-test-platform:
-            default: 6
-            android-4.2-x86/opt: 4
-    instance-size: xlarge
-    max-run-time: 7200
-    loopback-video: true
-    e10s: false
-    mozharness:
-        script: android_emulator_unittest.py
-        no-read-buildbot-config: true
-        extra-options:
-            - --test-suite=xpcshell
-        config:
-            by-test-platform:
-                default:
-                    - android/androidarm_4_3.py
-                    - remove_executables.py
-                    - android/androidarm_4_3-tc.py
-                android-4.2-x86/opt:
-                    - android/androidx86-tc.py
deleted file mode 100644
--- a/taskcluster/ci/desktop-test/kind.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-implementation: taskgraph.task.test:TestTask
-
-kind-dependencies:
-    - build
-
-transforms:
-   - taskgraph.transforms.tests:transforms
-   - taskgraph.transforms.task:transforms
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/test/kind.yml
@@ -0,0 +1,8 @@
+implementation: taskgraph.task.test:TestTask
+
+kind-dependencies:
+    - build
+
+transforms:
+   - taskgraph.transforms.tests:transforms
+   - taskgraph.transforms.task:transforms
rename from taskcluster/ci/desktop-test/test-platforms.yml
rename to taskcluster/ci/test/test-platforms.yml
--- a/taskcluster/ci/desktop-test/test-platforms.yml
+++ b/taskcluster/ci/test/test-platforms.yml
@@ -6,16 +6,20 @@
 #
 # Each test platform further specifies the set of tests that will be scheduled
 # for the platform, referring to tests defined in test-sets.yml.
 #
 # Note that set does not depend on the tree; tree-dependent job selection
 # should be performed in the target task selection phase of task-graph
 # generation.
 
+
+##
+# Linux platforms (matching /linux.*/)
+
 linux64/debug:
     build-platform: linux64/debug
     test-sets:
         - common-tests
         - external-media-tests
         - web-platform-tests
 linux64/opt:
     build-platform: linux64/opt
@@ -54,16 +58,19 @@ linux64-ccov/opt:
     build-platform: linux64-ccov/opt
     test-sets:
         - ccov-code-coverage-tests
 linux64-jsdcov/opt:
     build-platform: linux64-jsdcov/opt
     test-sets:
         - jsdcov-code-coverage-tests
 
+##
+# Windows platforms (matching /windows.*/)
+
 # win32 vm
 windows7-32-vm/debug:
     build-platform: win32/debug
     test-sets:
         - windows-vm-tests
 windows7-32-vm/opt:
     build-platform: win32/opt
     test-sets:
@@ -94,16 +101,44 @@ windows10-64-vm/opt:
 #    build-platform: win64/debug
 #    test-sets:
 #        - windows-gpu-tests
 #windows10-64/opt:
 #    build-platform: win64/opt
 #    test-sets:
 #        - windows-gpu-tests
 
+##
+# MacOS X platforms (matching /macosx.*/)
+
 macosx64/debug:
     build-platform: macosx64/debug
     test-sets:
         - macosx64-tests-debug
 macosx64/opt:
     build-platform: macosx64/opt
     test-sets:
         - macosx64-tests-talos
+
+##
+# Android platforms (matching /android.*/)
+
+android-4.3-arm7-api-15/debug:
+    build-platform: android-api-15/debug
+    test-sets:
+        - android-common-tests
+        - android-debug-tests
+
+android-4.3-arm7-api-15/opt:
+    build-platform: android-api-15/opt
+    test-sets:
+        - android-common-tests
+        - android-opt-tests
+
+android-4.2-x86/opt:
+    build-platform: android-x86/opt
+    test-sets:
+        - android-x86-tests
+
+android-4.3-arm7-api-15-gradle/opt:
+    build-platform: android-api-15-gradle/opt
+    test-sets:
+        - android-gradle-tests
rename from taskcluster/ci/desktop-test/test-sets.yml
rename to taskcluster/ci/test/test-sets.yml
--- a/taskcluster/ci/desktop-test/test-sets.yml
+++ b/taskcluster/ci/test/test-sets.yml
@@ -146,8 +146,36 @@ macosx64-tests-talos:
     - talos-dromaeojs
     - talos-g1
     - talos-g2
     - talos-g3
     - talos-g4
     - talos-other
     - talos-svgr
     - talos-tp5o
+
+android-common-tests:
+    - cppunit
+    - crashtest
+    - jsreftest
+    - mochitest
+    - mochitest-chrome
+    - mochitest-clipboard
+    - mochitest-gpu
+    - mochitest-media
+    - mochitest-webgl
+    - reftest
+    - xpcshell
+
+android-debug-tests:
+    # Marionette only available on Fennec debug builds as a security precaution
+    - marionette
+
+android-opt-tests:
+    - robocop
+
+android-gradle-tests:
+    - mochitest-chrome
+    - robocop
+
+android-x86-tests:
+    - mochitest-chrome
+    - xpcshell
rename from taskcluster/ci/desktop-test/tests.yml
rename to taskcluster/ci/test/tests.yml
--- a/taskcluster/ci/desktop-test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -6,70 +6,103 @@
 # Note that these are in lexical order
 
 cppunit:
     description: "CPP Unit Tests"
     suite: cppunittest
     treeherder-symbol: tc(Cpp)
     e10s: false
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --cppunittest-suite=cppunittest
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=cppunittest
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --cppunittest-suite=cppunittest
 
 crashtest:
     description: "Crashtest run"
     suite: reftest/crashtest
     treeherder-symbol: tc-R(C)
-    docker-image: {"in-tree": "desktop1604-test"}
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
+    docker-image:
+        by-test-platform:
+            android.*: {'in-tree': 'desktop-test'}
+            default: {"in-tree": 'desktop1604-test'}
+    chunks:
+        by-test-platform:
+            android-4.3-arm7-api-15/debug: 10
+            android.*: 4
+            default: 1
     e10s:
         by-test-platform:
-            # Bug 1304435
-            win.*: false
+            windows.*: false # Bug 1304435
             default: both
     mozharness:
-        script: desktop_unittest.py
-        chunked: true
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --reftest-suite=crashtest
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=crashtest
+            default:
+                script: desktop_unittest.py
+                chunked: true
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --reftest-suite=crashtest
 
 external-media-tests:
     description: "External Media Test run"
     suite: external-media-tests
     treeherder-symbol: tc-VP(b-m)
     e10s: false
     tier: 2
     max-run-time: 5400
     mozharness:
         script: firefox_media_tests_taskcluster.py
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - mediatests/taskcluster_windows_config.py
                 default:
                     - mediatests/taskcluster_posix_config.py
                     - remove_executables.py
 
 firefox-ui-functional-local:
     description: "Firefox-ui-tests functional run"
     suite: "firefox-ui/functional local"
@@ -108,160 +141,230 @@ gtest:
     treeherder-symbol: tc(GTest)
     e10s: false
     instance-size: xlarge
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --gtest-suite=gtest
 
 jittest:
     description: "JIT Test run"
     suite: jittest/jittest-chunked
     treeherder-symbol: tc(Jit)
     e10s: false
     chunks:
         by-test-platform:
-            win.*: 1
+            windows.*: 1
             default: 6
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --jittest-suite=jittest-chunked
 
 jsreftest:
     description: "JS Reftest run"
     suite: reftest/jsreftest
     treeherder-symbol: tc-R(J)
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
     chunks:
         by-test-platform:
-            win.*: 1
+            android-4.3-arm7-api-15/debug: 20
+            android.*: 6
+            windows.*: 1
             default: 2
     e10s:
         by-test-platform:
             # Bug 1321782
-            win.*: false
+            windows.*: false
+            android.*: false
             default: both
+    max-run-time:
+        by-test-platform:
+            android.*: 7200
+            default: 3600
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --reftest-suite=jsreftest
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=jsreftest
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --reftest-suite=jsreftest
 
 marionette:
     description: "Marionette unittest run"
     suite: marionette
     treeherder-symbol: tc(Mn)
-    max-run-time: 5400
-    docker-image: {"in-tree": "desktop1604-test"}
+    max-run-time:
+        by-test-platform:
+            android.*: 3600
+            default: 5400
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
+    docker-image:
+        by-test-platform:
+            android.*: {'in-tree': 'desktop-test'}
+            default: {"in-tree": 'desktop1604-test'}
+    tier:
+        by-test-platform:
+            android.*: 3
+            default: default
+    chunks:
+        by-test-platform:
+            android.*: 10
+            default: 1
     mozharness:
-        script: marionette.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - marionette/windows_taskcluster_config.py
-                default:
-                    - marionette/prod_config.py
+        by-test-platform:
+            android:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=marionette
+            default:
+                script: marionette.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - marionette/windows_taskcluster_config.py
+                        default:
+                            - marionette/prod_config.py
+                            - remove_executables.py
 
 mochitest:
     description: "Mochitest plain run"
     suite: mochitest/plain-chunked
     treeherder-symbol: tc-M()
     loopback-video: true
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: legacy # Bug 1281241: migrating to m3.large instances
     run-on-projects:
         by-test-platform:
             linux64-ccov/opt: []
             default: ['all']
     chunks:
         by-test-platform:
+            android-4.3-arm7-api-15/debug: 32
+            android.*: 20
             macosx.*: 5
-            win.*: 5
-            default: 10
+            windows.*: 5
+            linux.*: 10
     e10s:
         by-test-platform:
             linux64-ccov/opt: false
+            android.*: false
             default: both
-    max-run-time: 5400
+    max-run-time:
+        by-test-platform:
+            android-4.3-arm7-api-15/debug: 10800
+            default: 5400
+    allow-software-gl-layers: false
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        chunked: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            by-test-platform:
-                linux64-ccov/opt:
-                    - --mochitest-suite=plain-chunked
-                    - --code-coverage
-                default:
-                    - --mochitest-suite=plain-chunked
-    # Bug 1281241: migrating to m3.large instances
-    instance-size: legacy
-    allow-software-gl-layers: false
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=mochitest
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                chunked: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    by-test-platform:
+                        linux64-ccov/opt:
+                            - --mochitest-suite=plain-chunked
+                            - --code-coverage
+                        default:
+                            - --mochitest-suite=plain-chunked
 
 mochitest-a11y:
     description: "Mochitest a11y run"
     suite: mochitest/a11y
     treeherder-symbol: tc-M(a11y)
     loopback-video: true
     e10s: false
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         chunked: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --mochitest-suite=a11y
 
 mochitest-browser-chrome:
     description: "Mochitest browser-chrome run"
     suite:
@@ -291,22 +394,22 @@ mochitest-browser-chrome:
             linux64-ccov/opt: 7200
             linux64/debug: 5400
             default: 3600
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             by-test-platform:
                 linux64-jsdcov/opt:
                     - --mochitest-suite=browser-chrome-coverage
                 linux64-ccov/opt:
                     - --mochitest-suite=browser-chrome-chunked
@@ -321,98 +424,135 @@ mochitest-browser-chrome:
             default: legacy
     allow-software-gl-layers: false
 
 mochitest-chrome:
     description: "Mochitest chrome run"
     suite: mochitest/chrome
     treeherder-symbol: tc-M(c)
     loopback-video: true
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
     chunks:
-      by-test-platform:
-        macosx.*: 1
-        default: 3
+        by-test-platform:
+            android-4.3-arm7-api-15/debug: 2
+            android.*: 1
+            macosx.*: 1
+            default: 3
+    max-run-time:
+        by-test-platform:
+            android.*: 5400
+            default: 3600
     e10s: false
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
-                    - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --mochitest-suite=chrome
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        android-4.2-x86/opt:
+                            - android/androidx86-tc.py
+                        default:
+                            - android/androidarm_4_3.py
+                            - remove_executables.py
+                            - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=mochitest-chrome
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --mochitest-suite=chrome
 
 mochitest-clipboard:
     description: "Mochitest clipboard run"
     suite: mochitest/clipboard
     treeherder-symbol: tc-M(cl)
     loopback-video: true
     instance-size: xlarge
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        chunked: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --mochitest-suite=plain-clipboard,chrome-clipboard,browser-chrome-clipboard,jetpack-package-clipboard
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    # note that Android runs fewer suites than other platforms
+                    - --test-suite=mochitest-plain-clipboard
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                chunked: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --mochitest-suite=plain-clipboard,chrome-clipboard,browser-chrome-clipboard,jetpack-package-clipboard
 
 mochitest-devtools-chrome:
     description: "Mochitest devtools-chrome run"
     suite:
         by-test-platform:
             linux64-jsdcov/opt: mochitest/mochitest-devtools-chrome-coverage
             default: mochitest/mochitest-devtools-chrome-chunked
     treeherder-symbol: tc-M(dt)
     loopback-video: true
     max-run-time: 5400
     chunks:
         by-test-platform:
-            win.*: 8
+            windows.*: 8
             default: 10
     run-on-projects:
         by-test-platform:
             linux64-ccov/opt: []
             linux64-jsdcov/opt: []
             default: ['all']
     e10s:
         by-test-platform:
             # Bug 1242986: linux64/debug mochitest-devtools-chrome e10s is not greened up yet
             linux64/debug: false
             linux64-ccov/opt: false
             linux64-jsdcov/opt: false
             # Bug 1304433: mochitest-devtools-chrome (e10s) not greened on windows
-            win.*: false
+            windows.*: false
             default: both
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             by-test-platform:
                 linux64-ccov/opt:
                     - --mochitest-suite=mochitest-devtools-chrome-chunked
                     - --code-coverage
                 linux64-jsdcov:
@@ -429,84 +569,118 @@ mochitest-devtools-chrome:
 
 mochitest-gpu:
     description: "Mochitest GPU run"
     suite: mochitest/gpu
     treeherder-symbol: tc-M(gpu)
     loopback-video: true
     e10s:
         by-test-platform:
-            win.*: both
+            windows.*: both
+            android.*: false
             default: true
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        chunked: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --mochitest-suite=plain-gpu,chrome-gpu,browser-chrome-gpu
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    # note that Android runs fewer suites than other platforms
+                    - --test-suite=mochitest-plain-gpu
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                chunked: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --mochitest-suite=plain-gpu,chrome-gpu,browser-chrome-gpu
 
 mochitest-jetpack:
     description: "Mochitest jetpack run"
     suite: mochitest/jetpack-package
     treeherder-symbol: tc-M(JP)
     loopback-video: true
     e10s: false
     max-run-time: 5400
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         chunked: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --mochitest-suite=jetpack-package
             - --mochitest-suite=jetpack-addon
 
 mochitest-media:
     description: "Mochitest media run"
     suite: mochitest/mochitest-media
     treeherder-symbol: tc-M(mda)
     max-run-time: 5400
     loopback-video: true
-    instance-size: large
-    docker-image: {"in-tree": "desktop1604-test"}
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: large
+    chunks:
+        by-test-platform:
+            android.*: 3
+            default: 1
+    docker-image:
+        by-test-platform:
+            android.*: {'in-tree': 'desktop-test'}
+            default: {"in-tree": 'desktop1604-test'}
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        chunked: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --mochitest-suite=mochitest-media
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=mochitest-media
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                chunked: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --mochitest-suite=mochitest-media
 
 mochitest-other:
     description: "Mochitest other"
     suite: mochitest/other
     treeherder-symbol: tc-M(oth)
     e10s: false
     max-run-time: 5400
     mozharness:
@@ -514,72 +688,94 @@ mochitest-other:
         no-read-buildbot-config: true
         include-blob-upload-branch: true
         chunked: true
         config:
           by-test-platform:
             macosx.*:
               - remove_executables.py
               - unittests/mac_unittest.py
-            default:
+            linux.*:
               - unittests/linux_unittest.py
               - remove_executables.py
         extra-options:
             - --mochitest-suite=chrome,a11y
 
 mochitest-valgrind:
     description: "Mochitest plain Valgrind run"
     suite: mochitest/valgrind-plain
     treeherder-symbol: tc-M-V()
     run-on-projects: []
     loopback-video: true
     chunks: 40
     max-run-time: 14400
     # We could re-enable e10s later.
     # There's no intrinsic reason not to use it.
     e10s: false
+    allow-software-gl-layers: false
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         chunked: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --mochitest-suite=valgrind-plain
-    allow-software-gl-layers: false
 
 mochitest-webgl:
     description: "Mochitest webgl run"
     suite: mochitest/mochitest-gl
     treeherder-symbol: tc-M(gl)
-    chunks: 3
+    chunks:
+        by-test-platform:
+            android.*: 10
+            default: 3
     loopback-video: true
-    mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        chunked: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
-                    - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --mochitest-suite=mochitest-gl
+    max-run-time:
+        by-test-platform:
+            android.*: 7200
+            default: 3600
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
     # Bug 1296733: llvmpipe with mesa 9.2.1 lacks thread safety
     allow-software-gl-layers: false
+    mozharness:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
+                    - remove_executables.py
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=mochitest-gl
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                chunked: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --mochitest-suite=mochitest-gl
 
 mochitest-stylo:
     description: "Mochitest run for Stylo"
     suite: mochitest/mochitest-stylo
     treeherder-symbol: tc-M(s)
     loopback-video: true
     e10s: false
     mozharness:
@@ -592,78 +788,122 @@ mochitest-stylo:
                     - remove_executables.py
         extra-options:
             - --mochitest-suite=mochitest-stylo
 
 reftest:
     description: "Reftest run"
     suite: reftest/reftest
     treeherder-symbol: tc-R(R)
-    docker-image: {"in-tree": "desktop1604-test"}
+    docker-image:
+        by-test-platform:
+            android.*: {'in-tree': 'desktop-test'}
+            default: {"in-tree": 'desktop1604-test'}
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: default
     chunks:
-      by-test-platform:
-        macosx.*: 1
-        default: 8
+        by-test-platform:
+            android-4.3-arm7-api-15/debug: 48
+            android.*: 16
+            macosx.*: 1
+            default: 8
+    max-run-time:
+        by-test-platform:
+            android.*: 10800
+            default: 3600
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    - android/androidarm_4_3.py
                     - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            - --reftest-suite=reftest
+                    - android/androidarm_4_3-tc.py
+                extra-options:
+                    - --test-suite=reftest
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    - --reftest-suite=reftest
 
 reftest-no-accel:
     description: "Reftest not accelerated run"
     suite: reftest/reftest-no-accel
     treeherder-symbol: tc-R(Ru)
     docker-image: {"in-tree": "desktop1604-test"}
     chunks:
       by-test-platform:
         macosx.*: 1
         default: 8
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
                     - remove_executables.py
                     - unittests/mac_unittest.py
-                default:
+                linux.*:
                     - unittests/linux_unittest.py
                     - remove_executables.py
         extra-options:
             - --reftest-suite=reftest-no-accel
 
 reftest-stylo:
     description: "Reftest run for Stylo"
     suite: reftest/reftest-stylo
     treeherder-symbol: tc-R(Rs)
     chunks: 16
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
-            by-test-platform:
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
+            - unittests/linux_unittest.py
+            - remove_executables.py
         extra-options:
             - --reftest-suite=reftest-stylo
 
+robocop:
+    description: "Robocop run"
+    suite: robocop
+    treeherder-symbol: tc-M(rc)
+    instance-size: xlarge
+    chunks:
+        by-test-platform:
+            # android-4.3-arm7-api-15/debug -- not run
+            android-4.3-arm7-api-15/opt: 4
+            android-4.3-arm7-api-15-gradle/opt: 4
+    loopback-video: true
+    e10s: false
+    mozharness:
+        script: android_emulator_unittest.py
+        no-read-buildbot-config: true
+        config:
+            - android/androidarm_4_3.py
+            - remove_executables.py
+            - android/androidarm_4_3-tc.py
+        extra-options:
+            - --test-suite=robocop
+
 talos-chrome:
     description: "Talos chrome"
     suite: talos
     talos-try-name: chromez
     treeherder-symbol: tc-T(c)
     run-on-projects: []
     max-run-time: 3600
     mozharness:
@@ -833,43 +1073,43 @@ web-platform-tests:
     instance-size: xlarge
     docker-image: {"in-tree": "desktop1604-test"}
     checkout: true
     mozharness:
         script: web_platform_tests.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - web_platform_tests/prod_config_windows_taskcluster.py
                 default:
                     - web_platform_tests/prod_config.py
                     - remove_executables.py
         extra-options:
             - --test-type=testharness
 
 web-platform-tests-reftests:
     description: "Web platform reftest run"
     suite: web-platform-tests-reftests
     treeherder-symbol: tc-W(Wr)
     max-run-time: 5400
     instance-size: xlarge
     e10s:
         by-test-platform:
             # Bug 1304438
-            win.*: false
+            windows.*: false
             default: both
     docker-image: {"in-tree": "desktop1604-test"}
     checkout: true
     mozharness:
         script: web_platform_tests.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - web_platform_tests/prod_config_windows_taskcluster.py
                 default:
                     - web_platform_tests/prod_config.py
                     - remove_executables.py
         extra-options:
             - --test-type=reftest
 
 web-platform-tests-wdspec:
@@ -880,17 +1120,17 @@ web-platform-tests-wdspec:
     instance-size: xlarge
     docker-image: {"in-tree": "desktop1604-test"}
     checkout: true
     mozharness:
         script: web_platform_tests.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
-                win.*:
+                windows.*:
                     - web_platform_tests/prod_config_windows_taskcluster.py
                 default:
                     - web_platform_tests/prod_config.py
                     - remove_executables.py
         extra-options:
             - --test-type=wdspec
 
 xpcshell:
@@ -898,37 +1138,59 @@ xpcshell:
     suite: xpcshell
     treeherder-symbol: tc-X()
     run-on-projects:
         by-test-platform:
             linux64-ccov/opt: []
             default: ['all']
     chunks:
         by-test-platform:
-            # win.*: 1
+            linux64/debug: 10
+            android-4.2-x86/opt: 4
+            android.*: 6
+            # windows.*: 1
             macosx.*: 1
-            linux64/debug: 10
             default: 8
-    max-run-time: 5400
+    instance-size:
+        by-test-platform:
+            android.*: xlarge
+            default: legacy # Bug 1281241: migrating to m3.large instances
+    max-run-time:
+        by-test-platform:
+            android.*: 7200
+            default: 5400
     e10s: false
+    allow-software-gl-layers: false
     mozharness:
-        script: desktop_unittest.py
-        no-read-buildbot-config: true
-        config:
-            by-test-platform:
-                win.*:
-                    - unittests/win_taskcluster_unittest.py
-                macosx.*:
-                    - remove_executables.py
-                    - unittests/mac_unittest.py
-                default:
-                    - unittests/linux_unittest.py
-                    - remove_executables.py
-        extra-options:
-            by-test-platform:
-                linux64-ccov/opt:
-                    - --xpcshell-suite=xpcshell
-                    - --code-coverage
-                default:
-                    - --xpcshell-suite=xpcshell
-    # Bug 1281241: migrating to m3.large instances
-    instance-size: legacy
-    allow-software-gl-layers: false
+        by-test-platform:
+            android.*:
+                script: android_emulator_unittest.py
+                no-read-buildbot-config: true
+                extra-options:
+                    - --test-suite=xpcshell
+                config:
+                    by-test-platform:
+                        android-4.2-x86/opt:
+                            - android/androidx86-tc.py
+                        default:
+                            - android/androidarm_4_3.py
+                            - remove_executables.py
+                            - android/androidarm_4_3-tc.py
+            default:
+                script: desktop_unittest.py
+                no-read-buildbot-config: true
+                config:
+                    by-test-platform:
+                        windows.*:
+                            - unittests/win_taskcluster_unittest.py
+                        macosx.*:
+                            - remove_executables.py
+                            - unittests/mac_unittest.py
+                        linux.*:
+                            - unittests/linux_unittest.py
+                            - remove_executables.py
+                extra-options:
+                    by-test-platform:
+                        linux64-ccov/opt:
+                            - --xpcshell-suite=xpcshell
+                            - --code-coverage
+                        default:
+                            - --xpcshell-suite=xpcshell
--- a/taskcluster/docs/kinds.rst
+++ b/taskcluster/docs/kinds.rst
@@ -109,31 +109,24 @@ files named in ``kind.yml``:
  * The resulting tasks become a part of the task graph.
 
 .. important::
 
     This process generates *all* test jobs, regardless of tree or try syntax.
     It is up to a later stage of the task-graph generation (the target set) to
     select the tests that will actually be performed.
 
-desktop-test
-............
-
-The ``desktop-test`` kind defines tests for Desktop builds.  Its ``tests.yml``
-defines the full suite of desktop tests and their particulars, leaving it to
-the transforms to determine how those particulars apply to Linux, OS X, and
-Windows.
+test
+....
 
-android-test
-............
+The ``desktop-test`` kind defines tests for builds.  Its ``tests.yml`` defines
+the full suite of desktop tests and their particulars, leaving it to the
+transforms to determine how those particulars apply to the various platforms.
 
-The ``android-test`` kind defines tests for Android builds.
-
-It is very similar to ``desktop-test``, but the details of running the tests
-differ substantially, so they are defined separately.
+This kind includes both unit tests and talos.
 
 docker-image
 ------------
 
 Tasks of the ``docker-image`` kind build the Docker images in which other
 Docker tasks run.
 
 The tasks to generate each docker image have predictable labels:
--- a/taskcluster/docs/transforms.rst
+++ b/taskcluster/docs/transforms.rst
@@ -88,50 +88,27 @@ variations of the same task.
 
 In any case, shared transforms then convert this into a "task description",
 which the task-generation transforms then convert into a task definition
 suitable for ``queue.createTask``.
 
 Test Descriptions
 -----------------
 
-The transforms configured for test kinds proceed as follows, based on
-configuration in ``kind.yml``:
-
- * The test description is validated to conform to the schema in
-   ``taskcluster/taskgraph/transforms/tests/test_description.py``.  This schema
-   is extensively documented and is a the primary reference for anyone
-   modifying tests.
-
- * Kind-specific transformations are applied.  These may apply default
-   settings, split tests (e.g., one to run with feature X enabled, one with it
-   disabled), or apply across-the-board business rules such as "all desktop
-   debug test platforms should have a max-run-time of 5400s".
+Test descriptions specify how to run a unittest or talos run.  They aim to
+describe this abstractly, although in many cases the unique nature of
+invocation on different platforms leaves a lot of specific behavior in the test
+description, divided by ``by-test-platform``.
 
- * Transformations generic to all tests are applied.  These apply policies
-   which apply to multiple kinds, e.g., for treeherder tiers.  This is also the
-   place where most values which differ based on platform are resolved, and
-   where chunked tests are split out into a test per chunk.
-
- * The test is again validated against the same schema.  At this point it is
-   still a test description, just with defaults and policies applied, and
-   per-platform options resolved.  So transforms up to this point do not modify
-   the "shape" of the test description, and are still governed by the schema in
-   ``test_description.py``.
+Test descriptions are validated to conform to the schema in
+``taskcluster/taskgraph/transforms/tests.py``.  This schema is extensively
+documented and is a the primary reference for anyone modifying tests.
 
- * The ``taskgraph.transforms.tests.make_task_description:transforms`` then
-   take the test description and create a *task* description.  This transform
-   embodies the specifics of how test runs work: invoking mozharness, various
-   worker options, and so on.
-
- * Finally, the ``taskgraph.transforms.task:transforms``, described above
-   under "Task-Generation Transforms", are applied.
-
-Test dependencies are produced in the form of a dictionary mapping dependency
-name to task label.
+The output of ``tests.py`` is a task description.  Test dependencies are
+produced in the form of a dictionary mapping dependency name to task label.
 
 Job Descriptions
 ----------------
 
 A job description says what to run in the task.  It is a combination of a
 ``run`` section and all of the fields from a task description.  The run section
 has a ``using`` property that defines how this task should be run; for example,
 ``mozharness`` to run a mozharness script, or ``mach`` to run a mach command.
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -82,20 +82,19 @@ transforms = TransformSequence()
 # See the warnings in taskcluster/docs/how-tos.rst
 #
 # *****WARNING*****
 test_description_schema = Schema({
     # description of the suite, for the task metadata
     'description': basestring,
 
     # test suite name, or <suite>/<flavor>
-    Required('suite'): Any(
-        basestring,
-        {'by-test-platform': {basestring: basestring}},
-    ),
+    Required('suite'): optionally_keyed_by(
+        'test-platform',
+        basestring),
 
     # the name by which this test suite is addressed in try syntax; defaults to
     # the test-name
     Optional('unittest-try-name'): basestring,
 
     # the name by which this talos test is addressed in try syntax
     Optional('talos-try-name'): basestring,
 
@@ -110,53 +109,48 @@ test_description_schema = Schema({
 
     # attributes to appear in the resulting task (later transforms will add the
     # common attributes)
     Optional('attributes'): {basestring: object},
 
     # The `run_on_projects` attribute, defaulting to "all".  This dictates the
     # projects on which this task should be included in the target task set.
     # See the attributes documentation for details.
-    Optional('run-on-projects', default=['all']): Any(
-        [basestring],
-        {'by-test-platform': {basestring: [basestring]}},
-    ),
+    Optional('run-on-projects', default=['all']): optionally_keyed_by(
+        'test-platform',
+        [basestring]),
 
     # the sheriffing tier for this task (default: set based on test platform)
-    Optional('tier'): Any(
-        int,
-        {'by-test-platform': {basestring: int}},
-    ),
+    Optional('tier'): optionally_keyed_by(
+        'test-platform',
+        Any(int, 'default')),
 
     # number of chunks to create for this task.  This can be keyed by test
     # platform by passing a dictionary in the `by-test-platform` key.  If the
     # test platform is not found, the key 'default' will be tried.
-    Required('chunks', default=1): Any(
-        int,
-        {'by-test-platform': {basestring: int}},
-    ),
+    Required('chunks', default=1): optionally_keyed_by(
+        'test-platform',
+        int),
 
     # the time (with unit) after which this task is deleted; default depends on
     # the branch (see below)
     Optional('expires-after'): basestring,
 
     # Whether to run this task with e10s (desktop-test only).  If false, run
     # without e10s; if true, run with e10s; if 'both', run one task with and
     # one task without e10s.  E10s tasks have "-e10s" appended to the test name
     # and treeherder group.
-    Required('e10s', default='both'): Any(
-        bool, 'both',
-        {'by-test-platform': {basestring: Any(bool, 'both')}},
-    ),
+    Required('e10s', default='both'): optionally_keyed_by(
+        'test-platform',
+        Any(bool, 'both')),
 
     # The EC2 instance size to run these tests on.
-    Required('instance-size', default='default'): Any(
-        Any('default', 'large', 'xlarge', 'legacy'),
-        {'by-test-platform': {basestring: Any('default', 'large', 'xlarge', 'legacy')}},
-    ),
+    Required('instance-size', default='default'): optionally_keyed_by(
+        'test-platform',
+        Any('default', 'large', 'xlarge', 'legacy')),
 
     # Whether the task requires loopback audio or video (whatever that may mean
     # on the platform)
     Required('loopback-audio', default=False): bool,
     Required('loopback-video', default=False): bool,
 
     # Whether the test can run using a software GL implementation on Linux
     # using the GL compositor. May not be used with "legacy" sized instances
@@ -174,56 +168,57 @@ test_description_schema = Schema({
         'docker-engine',
         'buildbot-bridge',
     ),
 
     # For tasks that will run in docker-worker or docker-engine, this is the
     # name of the docker image or in-tree docker image to run the task in.  If
     # in-tree, then a dependency will be created automatically.  This is
     # generally `desktop-test`, or an image that acts an awful lot like it.
-    Required('docker-image', default={'in-tree': 'desktop-test'}): Any(
-        # a raw Docker image path (repo/image:tag)
-        basestring,
-        # an in-tree generated docker image (from `taskcluster/docker/<name>`)
-        {'in-tree': basestring}
+    Required('docker-image', default={'in-tree': 'desktop-test'}): optionally_keyed_by(
+        'test-platform', 'test-platform-phylum',
+        Any(
+            # a raw Docker image path (repo/image:tag)
+            basestring,
+            # an in-tree generated docker image (from `taskcluster/docker/<name>`)
+            {'in-tree': basestring}
+        )
     ),
 
     # seconds of runtime after which the task will be killed.  Like 'chunks',
     # this can be keyed by test pltaform.
-    Required('max-run-time', default=3600): Any(
-        int,
-        {'by-test-platform': {basestring: int}},
-    ),
+    Required('max-run-time', default=3600): optionally_keyed_by(
+        'test-platform',
+        int),
 
     # the exit status code that indicates the task should be retried
     Optional('retry-exit-status'): int,
 
     # Whether to perform a gecko checkout.
     Required('checkout', default=False): bool,
 
     # What to run
-    Required('mozharness'): Any({
+    Required('mozharness'): optionally_keyed_by(
+        'test-platform', 'test-platform-phylum', {
         # the mozharness script used to run this task
         Required('script'): basestring,
 
         # the config files required for the task
-        Required('config'): Any(
-            [basestring],
-            {'by-test-platform': {basestring: [basestring]}},
-        ),
+        Required('config'): optionally_keyed_by(
+            'test-platform',
+            [basestring]),
 
         # any additional actions to pass to the mozharness command
         Optional('actions'): [basestring],
 
         # additional command-line options for mozharness, beyond those
         # automatically added
-        Required('extra-options', default=[]): Any(
-            [basestring],
-            {'by-test-platform': {basestring: [basestring]}},
-        ),
+        Required('extra-options', default=[]): optionally_keyed_by(
+            'test-platform',
+            [basestring]),
 
         # the artifact name (including path) to test on the build task; this is
         # generally set in a per-kind transformation
         Optional('build-artifact-name'): basestring,
 
         # If true, tooltool downloads will be enabled via relengAPIProxy.
         Required('tooltool-downloads', default=False): bool,
 
@@ -262,21 +257,19 @@ test_description_schema = Schema({
         Optional('chunk-suffix'): basestring,
     }),
 
     # The current chunk; this is filled in by `all_kinds.py`
     Optional('this-chunk'): int,
 
     # os user groups for test task workers; required scopes, will be
     # added automatically
-    Optional('os-groups', default=[]): Any(
-        [basestring],
-        # todo: create a dedicated elevated worker group and name here
-        {'by-test-platform': {basestring: [basestring]}},
-    ),
+    Optional('os-groups', default=[]): optionally_keyed_by(
+        'test-platform',
+        [basestring]),
 
     # -- values supplied by the task-generation infrastructure
 
     # the platform of the build this task is testing
     'build-platform': basestring,
 
     # the label of the build task generating the materials to test
     'build-label': basestring,
@@ -296,36 +289,47 @@ test_description_schema = Schema({
 @transforms.add
 def validate(config, tests):
     for test in tests:
         yield validate_schema(test_description_schema, test,
                               "In test {!r}:".format(test['test-name']))
 
 
 @transforms.add
+def resolve_keyed_by_mozharness(config, tests):
+    """Resolve a mozharness field if it is keyed by something"""
+    for test in tests:
+        test['mozharness'] = get_keyed_by(item=test, field='mozharness', item_name=test['test-name'])
+        yield test
+
+
+@transforms.add
 def set_defaults(config, tests):
     for test in tests:
         build_platform = test['build-platform']
         if build_platform.startswith('android'):
             # all Android test tasks download internal objects from tooltool
             test['mozharness']['tooltool-downloads'] = True
             test['mozharness']['actions'] = ['get-secrets']
             # Android doesn't do e10s
             test['e10s'] = False
+            # loopback-video is always true for Android, but false for other
+            # platform phyla
+            test['loopback-video'] = True
         else:
             # all non-android tests want to run the bits that require node
             test['mozharness']['set-moz-node-path'] = True
+            test.setdefault('e10s', 'both')
 
         # software-gl-layers is only meaningful on linux, where it defaults to True
         if test['test-platform'].startswith('linux'):
             test.setdefault('allow-software-gl-layers', True)
         else:
             test['allow-software-gl-layers'] = False
 
-        test.setdefault('e10s', 'both')
         test.setdefault('os-groups', [])
         test.setdefault('chunks', 1)
         test.setdefault('run-on-projects', ['all'])
         test.setdefault('instance-size', 'default')
         test.setdefault('max-run-time', 3600)
         test['mozharness'].setdefault('extra-options', [])
         yield test
 
@@ -393,18 +397,21 @@ def set_worker_implementation(config, te
         yield test
 
 
 @transforms.add
 def set_tier(config, tests):
     """Set the tier based on policy for all test descriptions that do not
     specify a tier otherwise."""
     for test in tests:
+        if 'tier' in test:
+            test['tier'] = get_keyed_by(item=test, field='tier', item_name=test['test-name'])
+
         # only override if not set for the test
-        if 'tier' not in test:
+        if 'tier' not in test or test['tier'] == 'default':
             if test['test-platform'] in ['linux64/debug',
                                          'linux64-asan/opt',
                                          'android-4.3-arm7-api-15/debug',
                                          'android-x86/opt']:
                 test['tier'] = 1
             elif test['test-platform'].startswith('windows'):
                 test['tier'] = 3
             else:
@@ -441,23 +448,23 @@ def set_download_symbols(config, tests):
         yield test
 
 
 @transforms.add
 def resolve_keyed_by(config, tests):
     """Resolve fields that can be keyed by platform, etc."""
     fields = [
         'instance-size',
+        'docker-image',
         'max-run-time',
         'chunks',
         'e10s',
         'suite',
         'run-on-projects',
         'os-groups',
-        'tier',
     ]
     mozharness_fields = [
         'config',
         'extra-options',
     ]
     for test in tests:
         for field in fields:
             test[field] = get_keyed_by(item=test, field=field, item_name=test['test-name'])