Bug 1471227 - adjust taskcluster backfill with path to use test-verify instead of original job. r=gbrown
authorJoel Maher <jmaher@mozilla.com>
Wed, 04 Jul 2018 20:01:36 +0000
changeset 425141 22764fd6ae904f0fe9146ba38e02ded560918170
parent 425128 f839685ceb8eebc50fa69c9273141a4bdc8ce1e2
child 425142 01837d6c41b63b21cf7b8ccfe8f8366f08dc7512
push id104984
push useraciure@mozilla.com
push dateThu, 05 Jul 2018 09:55:01 +0000
treeherdermozilla-inbound@35ae03d7cf2d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgbrown
bugs1471227
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1471227 - adjust taskcluster backfill with path to use test-verify instead of original job. r=gbrown Differential Revision: https://phabricator.services.mozilla.com/D1961
taskcluster/taskgraph/actions/backfill.py
testing/mozharness/scripts/android_emulator_unittest.py
--- a/taskcluster/taskgraph/actions/backfill.py
+++ b/taskcluster/taskgraph/actions/backfill.py
@@ -60,17 +60,17 @@ logger = logging.getLogger(__name__)
             },
             'testPath': {
                 'type': 'string',
                 'title': 'Test Path',
             }
         },
         'additionalProperties': False
     },
-    available=lambda parameters: parameters.get('project', None) != 'try'
+    available=lambda parameters: True
 )
 def backfill_action(parameters, graph_config, input, task_group_id, task_id, task):
     label = task['metadata']['name']
     pushes = []
     inclusive_tweak = 1 if input.get('inclusive') else 0
     depth = input.get('depth', 5) + inclusive_tweak
     end_id = int(parameters['pushlog_id']) - (1 - inclusive_tweak)
 
@@ -107,23 +107,152 @@ def backfill_action(parameters, graph_co
             logger.info('Skipping {} due to missing index artifacts! Error: {}'.format(push, e))
             continue
 
         if label in full_task_graph.tasks.keys():
             def modifier(task):
                 if task.label != label:
                     return task
                 if input.get('addGeckoProfile'):
-                    mh = task.task['payload'].setdefault('env', {}) \
-                                                    .get('MOZHARNESS_OPTIONS', '')
-                    task.task['payload']['env']['MOZHARNESS_OPTIONS'] = mh + ' --geckoProfile'
+                    cmd = task.task['payload']['command']
+                    task.task['payload']['command'] = add_args_to_command(cmd, ['--geckoProfile'])
                     task.task['extra']['treeherder']['symbol'] += '-p'
 
-                if input.get('testPath'):
-                    env = task.task['payload'].setdefault('env', {})
-                    env['MOZHARNESS_TEST_PATHS'] = input.get('testPath')
-                    task.task['extra']['treeherder']['symbol'] += '-b'
+                if input.get('testPath', ''):
+                    tp = input.get('testPath', '')
+                    gpu_required = False
+                    # TODO: this has a high chance of getting out of date
+                    if 'gpu' in task.task['metadata']['name'] or \
+                       'webgl' in task.task['metadata']['name'] or \
+                       'canvas' in tp or \
+                       'gfx/tests' in tp or \
+                       ('reftest' in tp and 'jsreftest' not in tp):
+                        gpu_required = True
+                    is_wpttest = 'web-platform' in task.task['metadata']['name']
+                    is_android = 'android' in task.task['metadata']['name']
+
+                    # Create new cmd that runs a test-verify type job
+                    preamble_length = 3
+                    verify_args = ['--e10s',
+                                   '--verify',
+                                   '--total-chunk=1',
+                                   '--this-chunk=1']
+                    if is_android:
+                        # no --e10s; todo, what about future geckoView?
+                        verify_args.remove('--e10s')
+
+                    if gpu_required:
+                        verify_args.append('--gpu-required')
+
+                    task.task['payload']['env']['MOZHARNESS_TEST_PATHS'] = input.get('testPath')
+
+                    cmd_parts = task.task['payload']['command']
+                    keep_args = ['--installer-url', '--download-symbols', '--test-packages-url']
+                    cmd_parts = remove_args_from_command(cmd_parts, preamble_length, keep_args)
+                    cmd_parts = add_args_to_command(cmd_parts, verify_args)
+                    task.task['payload']['command'] = cmd_parts
+
+                    # morph the task label to a test-verify job
+                    pc = task.task['metadata']['name'].split('/')
+                    config = pc[-1].split('-')
+                    subtype = ''
+                    symbol = 'TV-bf'
+                    if gpu_required:
+                        subtype = '-gpu'
+                        symbol = 'TVg-bf'
+                    if is_wpttest:
+                        subtype = '-wpt'
+                        symbol = 'TVw-bf'
+                    if not is_android:
+                        subtype = "%s-e10s" % subtype
+                    newlabel = "%s/%s-test-verify%s" % (pc[0], config[0], subtype)
+                    task.task['metadata']['name'] = newlabel
+                    task.task['tags']['label'] = newlabel
+
+                    task.task['extra']['index']['rank'] = 0
+                    task.task['extra']['chunks']['current'] = 1
+                    task.task['extra']['chunks']['total'] = 1
+
+                    task.task['extra']['suite']['name'] = 'test-verify'
+                    task.task['extra']['suite']['flavor'] = 'test-verify'
+
+                    task.task['extra']['treeherder']['symbol'] = symbol
+                    del task.task['extra']['treeherder']['groupSymbol']
                 return task
 
             create_tasks([label], full_task_graph, label_to_taskid,
                          push_params, push_decision_task_id, push, modifier=modifier)
         else:
             logging.info('Could not find {} on {}. Skipping.'.format(label, push))
+
+
+def remove_args_from_command(cmd_parts, preamble_length=0, args_to_ignore=[]):
+    """
+       We need to remove all extra instances of command line arguments
+       that are suite/job specific, like suite=jsreftest, subsuite=devtools
+       and other ones like --total-chunk=X.
+       args:
+         cmd_parts: the raw command as seen by taskcluster
+         preamble_length: the number of args to skip (usually python -u <name>)
+         args_to_ignore: ignore specific args and their related values
+    """
+    cmd_type = 'default'
+    if len(cmd_parts) == 1 and isinstance(cmd_parts[0], dict):
+        # windows has single cmd part as dict: 'task-reference', with long string
+        preamble_length += 2
+        cmd_parts = cmd_parts[0]['task-reference'].split(' ')
+        cmd_type = 'dict'
+    elif len(cmd_parts) == 1 and isinstance(cmd_parts[0], list):
+        # osx has an single value array with an array inside
+        preamble_length += 2
+        cmd_parts = cmd_parts[0]
+        cmd_type = 'subarray'
+
+    idx = preamble_length - 1
+    while idx+1 < len(cmd_parts):
+        idx += 1
+        part = cmd_parts[idx]
+
+        # task-reference values need a transform to s/<build>/{taskID}/
+        if isinstance(part, dict):
+            part = cmd_parts[idx]['task-reference']
+
+        if filter(lambda x: x in part, args_to_ignore):
+            # some args are |--arg=val| vs |--arg val|
+            if '=' not in part:
+                idx += 1
+            continue
+
+        # remove job specific arg, and reduce array index as size changes
+        cmd_parts.remove(cmd_parts[idx])
+        idx -= 1
+
+    if cmd_type == 'dict':
+        cmd_parts = [{'task-reference': ' '.join(cmd_parts)}]
+    elif cmd_type == 'subarray':
+        cmd_parts = [cmd_parts]
+    return cmd_parts
+
+
+def add_args_to_command(cmd_parts, extra_args=[]):
+    """
+        Add custom command line args to a given command.
+        args:
+          cmd_parts: the raw command as seen by taskcluster
+          extra_args: array of args we want to add
+    """
+    cmd_type = 'default'
+    if len(cmd_parts) == 1 and isinstance(cmd_parts[0], dict):
+        # windows has single cmd part as dict: 'task-reference', with long string
+        cmd_parts = cmd_parts[0]['task-reference'].split(' ')
+        cmd_type = 'dict'
+    elif len(cmd_parts) == 1 and isinstance(cmd_parts[0], list):
+        # osx has an single value array with an array inside
+        cmd_parts = cmd_parts[0]
+        cmd_type = 'subarray'
+
+    cmd_parts.extend(extra_args)
+
+    if cmd_type == 'dict':
+        cmd_parts = [{'task-reference': ' '.join(cmd_parts)}]
+    elif cmd_type == 'subarray':
+        cmd_parts = [cmd_parts]
+    return cmd_parts
--- a/testing/mozharness/scripts/android_emulator_unittest.py
+++ b/testing/mozharness/scripts/android_emulator_unittest.py
@@ -52,16 +52,23 @@ class AndroidEmulatorTest(TestingMixin, 
     ], [
         ["--this-chunk"],
         {"action": "store",
          "dest": "this_chunk",
          "default": None,
          "help": "Number of this chunk",
          }
     ], [
+        ["--gpu-required"],
+        {"action": "store_true",
+         "dest": "gpu_required",
+         "default": False,
+         "help": "Run additional verification on modified tests using gpu instances.",
+         }
+    ], [
         ["--log-raw-level"],
         {"action": "store",
          "dest": "log_raw_level",
          "default": "info",
          "help": "Set log level (debug|info|warning|error|critical|fatal)",
          }
     ], [
         ["--log-tbpl-level"],