Fork subbuild recipe module.

This is required to update the led runs to use -real-build. Updating
upstream is not possible becuase it will require several changes in
fuchsia infra.

Bug: https://github.com/flutter/flutter/issues/122891
Change-Id: Ie5d5b85c0e4ae82dafd4db0587523d70ec80f91c
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/41240
Reviewed-by: Keyong Han <keyonghan@google.com>
Commit-Queue: Godofredo Contreras <godofredoc@google.com>
diff --git a/recipe_modules/recipe_testing/__init__.py b/recipe_modules/recipe_testing/__init__.py
index 7fe54ac..7441f25 100644
--- a/recipe_modules/recipe_testing/__init__.py
+++ b/recipe_modules/recipe_testing/__init__.py
@@ -9,7 +9,7 @@
     "fuchsia/gerrit",
     "fuchsia/git",
     "fuchsia/gitiles",
-    "fuchsia/subbuild",
+    "flutter/subbuild",
     "fuchsia/swarming_retry",
     "recipe_engine/buildbucket",
     "recipe_engine/context",
diff --git a/recipe_modules/subbuild/__init__.py b/recipe_modules/subbuild/__init__.py
new file mode 100644
index 0000000..de39588
--- /dev/null
+++ b/recipe_modules/subbuild/__init__.py
@@ -0,0 +1,15 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+DEPS = [
+    "fuchsia/utils",
+    "recipe_engine/buildbucket",
+    "recipe_engine/file",
+    "recipe_engine/json",
+    "recipe_engine/led",
+    "recipe_engine/path",
+    "recipe_engine/properties",
+    "recipe_engine/step",
+    "recipe_engine/swarming",
+]
diff --git a/recipe_modules/subbuild/api.py b/recipe_modules/subbuild/api.py
new file mode 100644
index 0000000..44873c5
--- /dev/null
+++ b/recipe_modules/subbuild/api.py
@@ -0,0 +1,331 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import attr
+
+import collections
+import datetime
+
+from recipe_engine import recipe_api
+from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
+from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
+
+from RECIPE_MODULES.fuchsia.utils import pluralize
+
+# As of 2021-10-19, the `api.buildbucket.collect()` timeout defaults to
+# something too short. We never want subbuild collection to timeout; we'd rather
+# the whole build time out.
+COLLECT_TIMEOUT = datetime.timedelta(hours=24)
+
+# We implicitly rely on a select few properties being passed through
+# from the parent build to the subbuild.
+# NOTE: Only dynamically computed properties should be passed through
+# automatically. Any static properties (i.e. properties that don't change
+# between builds) should be configured explicitly on the subbuild's builder
+# rather than implicitly passing them through.
+PASS_THROUGH_PROPERTIES = {
+    # Used by toolchain recipes to pass custom toolchain info.
+    "$fuchsia/build",
+    # Used by toolchain recipes to pass commit info.
+    "$fuchsia/checkout",
+    # recipe_bootstrap may pass some properties to subbuilds via this field.
+    "$fuchsia/recipe_bootstrap",
+    # If a parent build is running under recipe testing, then the
+    # subbuild is as well, and it should be made aware of that.
+    "$fuchsia/recipe_testing",
+    # Needed for subbuilds to determine how the parent was invoked in CQ
+    # (e.g. whether it's a dry run or full run).
+    "$recipe_engine/cq",
+    # Set by recipe_bootstrap. A subbuild should inherit the same
+    # integration base revision as its parent so the two builds use the same
+    # version of recipes and properties.
+    "integration_base_revision",
+    # Set by `led edit-recipe-bundle -property-only` to point to the uploaded
+    # recipe bundle. It's then up to recipe_bootstrap to download the recipe
+    # bundle and execute it. A led subbuild should use the same recipe bundle
+    # version as its parent.
+    "led_cas_recipe_bundle",
+}
+
+
+@attr.s
+class SubbuildResult:
+    """Subbuild result metadata."""
+
+    builder = attr.ib(type=str)
+    build_id = attr.ib(type=str, converter=str)
+    url = attr.ib(type=str, default=None)
+    build_proto = attr.ib(type=build_pb2.Build, default=None)
+
+
+@attr.s
+class _SplitBuilder:
+    """Project/bucket/name triplet."""
+
+    project = attr.ib(type=str)
+    bucket = attr.ib(type=str)
+    name = attr.ib(type=str)
+
+
+class SubbuildApi(recipe_api.RecipeApi):
+    """API for launching subbuilds and collecting the results."""
+
+    def launch(
+        self,
+        builder_names,
+        presentation,
+        extra_properties=None,
+        set_swarming_parent_run_id=True,
+        hide_in_gerrit=True,
+        include_sub_invs=True,
+    ):
+        """Launches builds with buildbucket or led.
+
+        If the current task was launched with led, then subbuilds will also be
+        launched with led.
+
+        Args:
+          builder_names (list(str)): The names of the builders to launch.
+          presentation (StepPresentation): The presentation to add logs to.
+          extra_properties (dict): The extra set of properties to launch the
+            builders with. These will override the parent properties that will be
+            passed to the children by default.
+          set_swarming_parent_run_id (bool): Whether to set swarming parent run
+            ID on buildbucket builds.
+          hide_in_gerrit (bool): Hide buildbucket subbuilds in the Gerrit UI.
+          include_sub_invs (bool): Whether the parent should inherit ResultDB
+            test results from the child builds.
+
+        Returns:
+          launched_builds (dict): The launched_builds is a map from builder name
+          to the corresponding SubbuildResult.
+        """
+        parent_properties = self.m.properties.thaw()
+        properties = {
+            key: val
+            for key, val in parent_properties.items()
+            if key and key in PASS_THROUGH_PROPERTIES
+        }
+        if extra_properties:
+            properties.update(extra_properties)
+
+        # If this task was launched by led, we launch the child with led as well.
+        # This lets us ensure that the parent and child use the same version of
+        # the recipes code. That is a requirement for testing, as well as for
+        # avoiding the need to do soft transitions when updating the interface
+        # between the parent and child recipes.
+        if self.m.led.launched_by_led:
+            builds = self._launch_with_led(builder_names, properties)
+        else:
+            builds = self._launch_with_buildbucket(
+                builder_names,
+                properties,
+                set_swarming_parent_run_id=set_swarming_parent_run_id,
+                hide_in_gerrit=hide_in_gerrit,
+                include_sub_invs=include_sub_invs,
+            )
+        for builder, build in builds.items():
+            presentation.links[builder] = build.url
+        return builds
+
+    def split_builder(self, builder_name):
+        """Split a builder name into parts, filling in from current build."""
+        parent = self.m.buildbucket.build.builder
+
+        *prefixes, name = builder_name.split("/")
+        assert len(prefixes) <= 2, f"bad builder_name {builder_name}"
+        if len(prefixes) == 2:
+            project, bucket = prefixes
+        elif len(prefixes) == 1:
+            project = parent.project
+            bucket = prefixes[0]
+        else:
+            project = parent.project
+            bucket = parent.bucket
+
+        return _SplitBuilder(project, bucket, name)
+
+    def _launch_with_led(self, builder_names, properties):
+        edit_args = []
+        for k, v in sorted(properties.items()):
+            edit_args.extend(["-p", f"{k}={self.m.json.dumps(v)}"])
+        edit_cr_cl_arg = None
+        bb_input = self.m.buildbucket.build_input
+        if bb_input.gerrit_changes:
+            gerrit_change = bb_input.gerrit_changes[0]
+            edit_cr_cl_arg = f"https://{gerrit_change.host}/c/{gerrit_change.project}/+/{int(gerrit_change.change)}"
+
+        builds = {}
+        for builder_name in builder_names:
+            builder = self.split_builder(builder_name)
+            led_data = self.m.led(
+                "get-builder",
+                # By default, led reduces the priority of tasks from their
+                # values in buildbucket which we do not want.
+                "-adjust-priority",
+                "0",
+                f"{builder.project}/{builder.bucket}/{builder.name}",
+            )
+            led_data = led_data.then("edit", *edit_args)
+            if edit_cr_cl_arg:
+                led_data = led_data.then("edit-cr-cl", edit_cr_cl_arg)
+            led_data = self.m.led.inject_input_recipes(led_data)
+            launch_res = led_data.then("launch", "-modernize")
+            task_id = launch_res.launch_result.task_id
+            build_url = f"https://ci.chromium.org/swarming/task/{task_id}?server={launch_res.launch_result.swarming_hostname}"
+            builds[builder_name] = SubbuildResult(
+                builder=builder_name, build_id=task_id, url=build_url
+            )
+        return builds
+
+    def _launch_with_buildbucket(
+        self,
+        builder_names,
+        properties,
+        set_swarming_parent_run_id,
+        hide_in_gerrit,
+        include_sub_invs,
+    ):
+        reqs = []
+        swarming_parent_run_id = (
+            self.m.swarming.task_id if set_swarming_parent_run_id else None
+        )
+        bb_tags = {"skip-retry-in-gerrit": "subbuild"}
+        if hide_in_gerrit:
+            bb_tags["hide-in-gerrit"] = "subbuild"
+        for builder_name in builder_names:
+            builder = self.split_builder(builder_name)
+            reqs.append(
+                self.m.buildbucket.schedule_request(
+                    project=builder.project,
+                    bucket=builder.bucket,
+                    builder=builder.name,
+                    properties=properties,
+                    swarming_parent_run_id=swarming_parent_run_id,
+                    priority=None,  # Leave unset to avoid overriding priority from configs.
+                    tags=self.m.buildbucket.tags(**bb_tags),
+                )
+            )
+
+        scheduled_builds = self.m.buildbucket.schedule(
+            reqs, step_name="schedule", include_sub_invs=include_sub_invs
+        )
+
+        builds = {}
+        for build in scheduled_builds:
+            build_url = f"https://ci.chromium.org/b/{build.id}"
+            builds[build.builder.builder] = SubbuildResult(
+                builder=build.builder.builder, build_id=build.id, url=build_url
+            )
+        return builds
+
+    def collect(self, build_ids, launched_by_led=None, extra_fields=frozenset()):
+        """Collects builds with the provided build_ids.
+
+        Args:
+          build_ids (list(str)): The list of build ids to collect results for.
+          presentation (StepPresentation): The presentation to add logs to.
+          launched_by_led (bool|None): Whether the builds to collect were
+              launched by led. If None, then this value will be determined by
+              whether the current task was launched by led.
+          extra_fields (set): Extra fields to include in the buildbucket
+            response.
+
+        Returns:
+          A map from build IDs to the corresponding SubbuildResult.
+        """
+        if launched_by_led is None:
+            launched_by_led = self.m.led.launched_by_led
+        if launched_by_led:
+            builds = self._collect_from_led(build_ids)
+        else:
+            builds = self._collect_from_buildbucket(build_ids, extra_fields)
+        return collections.OrderedDict(
+            sorted(builds.items(), key=lambda item: (item[1].builder, item[0]))
+        )
+
+    def get_property(self, build_proto, property_name):
+        """Retrieve an output property from a subbuild's Build proto.
+
+        Ensures a clear and unified missing property error message across all
+        builders that use this recipe module.
+        """
+        try:
+            return build_proto.output.properties[property_name]
+        except ValueError:
+            raise self.m.step.InfraFailure(
+                f"Subbuild did not set the {property_name!r} output property"
+            )
+
+    def _collect_from_led(self, task_ids):
+        swarming_results = self.m.swarming.collect(
+            "collect", task_ids, output_dir=self.m.path["cleanup"]
+        )
+        builds = {}
+        for result in swarming_results:
+            task_id = result.id
+            # Led launch ensures this file is present in the task root dir.
+            build_proto_path = result.output_dir.join("build.proto.json")
+            build_proto = self.m.file.read_proto(
+                "read build.proto.json", build_proto_path, build_pb2.Build, "JSONPB"
+            )
+            builds[task_id] = SubbuildResult(
+                builder=build_proto.builder.builder,
+                build_id=task_id,
+                build_proto=build_proto,
+            )
+        return builds
+
+    def _collect_from_buildbucket(self, build_ids, extra_fields):
+        bb_fields = self.m.buildbucket.DEFAULT_FIELDS.union(
+            {"infra.swarming.task_id", "summary_markdown"}
+        ).union(extra_fields)
+
+        builds = self.m.buildbucket.collect_builds(
+            [int(build_id) for build_id in build_ids],
+            interval=20,  # Lower from default of 60 b/c we're impatient.
+            timeout=COLLECT_TIMEOUT,
+            step_name="collect",
+            fields=bb_fields,
+        )
+
+        failed_builds = [b for b in builds.values() if b.status != common_pb2.SUCCESS]
+        if failed_builds:
+            task_ids = [b.infra.swarming.task_id for b in failed_builds]
+            # Make sure task IDs are non-empty.
+            assert all(task_ids), task_ids
+
+            # Wait for the underlying Swarming tasks to complete. The Swarming
+            # task for a Buildbucket build can take significantly longer to
+            # complete than the build itself due to post-processing outside the
+            # scope of the build's recipe (e.g. cache pruning). If the parent
+            # build and its Swarming task both complete before the subbuild's
+            # Swarming task finishes post-processing, then the subbuild's
+            # Swarming task will be killed by Swarming due to the parent being
+            # complete.
+            #
+            # That is actually working as intended. However, it's confusing for
+            # a subbuild to be marked as killed when the recipe actually exited
+            # normally; "killed" usually only happens for CQ builds, when a
+            # build is canceled by CQ because a new patchset of the triggering
+            # CL is uploaded. So it's convenient to have dashboards and queries
+            # ignore "killed" tasks. We use this workaround to ensure that
+            # failed subbuilds with long post-processing steps have time to
+            # complete and exit cleanly with a plain old "COMPLETED (FAILURE)"
+            # status.
+            #
+            # We only do this if the subbuild failed as a latency optimization.
+            # If all subbuilds passed, the parent will go on to do some more
+            # steps using the results of the subbuilds, leaving time for the
+            # subbuilds' tasks to complete asynchronously, so we don't want to
+            # block here while the tasks complete.
+            self.m.swarming.collect(
+                f"wait for {pluralize('task', task_ids)} to complete", task_ids
+            )
+        return {
+            str(build.id): SubbuildResult(
+                builder=build.builder.builder, build_id=build.id, build_proto=build
+            )
+            for build in builds.values()
+        }
diff --git a/recipe_modules/subbuild/test_api.py b/recipe_modules/subbuild/test_api.py
new file mode 100644
index 0000000..e228165
--- /dev/null
+++ b/recipe_modules/subbuild/test_api.py
@@ -0,0 +1,126 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from recipe_engine import recipe_test_api
+from PB.go.chromium.org.luci.buildbucket.proto import (
+    builds_service as builds_service_pb2,
+)
+from PB.go.chromium.org.luci.led.job import job as job_pb2
+
+
+class SubbuildTestApi(recipe_test_api.RecipeTestApi):
+    def ci_build_message(self, builder, input_props=None, output_props=None, **kwargs):
+        """Generates a CI Buildbucket Build message.
+
+        Args:
+          builder (str): The builder name.
+          input_props (Dict): Input properties to set on the build.
+          output_props (Dict): Output properties to set on the build.
+          kwargs: Forwarded to BuildbucketApi.ci_build_message.
+
+        See BuildBucketTestApi.ci_build_message for full parameter documentation.
+        """
+        project = kwargs.pop("project", "fuchsia")
+        msg = self.m.buildbucket.ci_build_message(
+            builder=builder, project=project, **kwargs
+        )
+        msg.infra.swarming.task_id = "abc123"
+        msg.input.properties.update(input_props if input_props else {})
+        msg.output.properties.update(output_props if output_props else {})
+        return msg
+
+    def try_build_message(self, builder, input_props=None, output_props=None, **kwargs):
+        """Generates a try Buildbucket Build message.
+
+        Args:
+          builder (str): The builder name.
+          input_props (Dict): Input properties to set on the build.
+          output_props (Dict): Output properties to set on the build.
+          kwargs: Forwarded to BuildbucketApi.try_build_message.
+
+        See BuildBucketTestApi.try_build_message for full parameter documentation.
+        """
+        project = kwargs.pop("project", "fuchsia")
+        msg = self.m.buildbucket.try_build_message(
+            builder=builder, project=project, **kwargs
+        )
+        msg.infra.swarming.task_id = "abc123"
+        msg.input.properties.update(input_props if input_props else {})
+        msg.output.properties.update(output_props if output_props else {})
+        return msg
+
+    def child_build_steps(
+        self, builds, launch_step="build", collect_step="build", collect_attempt=1
+    ):
+        """Generates step data to schedule and collect from child builds.
+
+        Args:
+          builds (list(build_pb2.Build)): The builds to schedule and collect from.
+        """
+        responses = []
+        for build in builds:
+            responses.append(
+                dict(schedule_build=dict(id=build.id, builder=build.builder))
+            )
+        mock_schedule_data = self.m.buildbucket.simulated_schedule_output(
+            step_name=f"{launch_step}.schedule",
+            batch_response=builds_service_pb2.BatchResponse(responses=responses),
+        )
+
+        index = "" if collect_attempt <= 1 else (f" ({collect_attempt})")
+        mock_collect_data = self.m.buildbucket.simulated_collect_output(
+            step_name=f"{collect_step}.collect{index}",
+            builds=builds,
+        )
+        return mock_schedule_data + mock_collect_data
+
+    def child_led_steps(
+        self,
+        builds,
+        collect_step="build",
+    ):
+        """Generates step data to schedule and collect from child builds.
+
+        Args:
+          builds (list(build_pb2.Build)): The builds to schedule and collect from.
+        """
+        step_data = []
+        task_results = []
+        i = 0
+        for build in builds:
+            i += 1
+            suffix = ""
+            if i > 1:
+                suffix = f" ({int(i)})"
+
+            task_id = f"fake-task-id-{int(i)}"
+
+            # led launch mock will take ....infra.swarming.task_id as this
+            # build's launched swarming ID.
+            jd = job_pb2.Definition()
+            jd.buildbucket.bbagent_args.build.CopyFrom(build)
+            jd.buildbucket.bbagent_args.build.infra.swarming.task_id = task_id
+            step_data.append(
+                self.m.led.mock_get_builder(
+                    jd,
+                    build.builder.project,
+                    build.builder.bucket,
+                    build.builder.builder,
+                )
+            )
+            task_results.append(
+                self.m.swarming.task_result(id=task_id, name=build.builder.builder)
+            )
+            step_data.append(
+                self.step_data(
+                    f"{collect_step}.read build.proto.json{suffix}",
+                    self.m.file.read_proto(build),
+                )
+            )
+        ret = self.step_data(
+            f"{collect_step}.collect", self.m.swarming.collect(task_results)
+        )
+        for s in step_data:
+            ret += s
+        return ret
diff --git a/recipe_modules/subbuild/tests/full.expected/failed_subbuild.json b/recipe_modules/subbuild/tests/full.expected/failed_subbuild.json
new file mode 100644
index 0000000..70e1d27
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.expected/failed_subbuild.json
@@ -0,0 +1,434 @@
+[
+  {
+    "cmd": [],
+    "name": "launch builds",
+    "~followup_annotations": [
+      "@@@STEP_LINK@builder-subbuild2@https://ci.chromium.org/b/8945511751514863187@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.schedule",
+    "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"try\", \"builder\": \"builder-subbuild1\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gerritChanges\": [{\"change\": \"123456\", \"host\": \"fuchsia-review.googlesource.com\", \"patchset\": \"7\", \"project\": \"fuchsia\"}], \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"cq_experimental\", \"value\": \"false\"}, {\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}, {\"scheduleBuild\": {\"builder\": {\"bucket\": \"try\", \"builder\": \"builder-subbuild2\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gerritChanges\": [{\"change\": \"123456\", \"host\": \"fuchsia-review.googlesource.com\", \"patchset\": \"7\", \"project\": \"fuchsia\"}], \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"cq_experimental\", \"value\": \"false\"}, {\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gerritChanges\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"change\": \"123456\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"host\": \"fuchsia-review.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"patchset\": \"7\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ], @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"cq_experimental\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }, @@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gerritChanges\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"change\": \"123456\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"host\": \"fuchsia-review.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"patchset\": \"7\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ], @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"cq_experimental\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863187@https://cr-buildbucket.appspot.com/build/8945511751514863187@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds",
+    "~followup_annotations": [
+      "@@@STEP_FAILURE@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.collect",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "collect",
+      "-host",
+      "cr-buildbucket.appspot.com",
+      "-interval",
+      "20s",
+      "8945511751514863187"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.wait",
+    "timeout": 86400.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.get",
+    "stdin": "{\"requests\": [{\"getBuild\": {\"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", \"id\": \"8945511751514863187\"}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createTime\": \"2018-05-25T23:50:17Z\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createdBy\": \"project:fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863187\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }, @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"priority\": 30, @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"taskId\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"gerritChanges\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@            {@@@",
+      "@@@STEP_LOG_LINE@json.output@              \"change\": \"123456\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"host\": \"chromium-review.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"patchset\": \"7\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@            }@@@",
+      "@@@STEP_LOG_LINE@json.output@          ]@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"status\": \"FAILURE\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@          {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"key\": \"cq_experimental\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        ]@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"id\": \"8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863187@https://cr-buildbucket.appspot.com/build/8945511751514863187@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.install infra/tools/luci/swarming",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin",
+      "-ensure-file",
+      "infra/tools/luci/swarming/${platform} swarming_module_pin",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-swarming_module_\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/swarming/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin/swarming",
+      "collect",
+      "-server",
+      "https://example.swarmingserver.appspot.com",
+      "-task-summary-json",
+      "/path/to/tmp/json",
+      "-task-output-stdout",
+      "json",
+      "abc123"
+    ],
+    "cost": {
+      "cpu": 100,
+      "disk": 0,
+      "memory": 50,
+      "net": 0
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.wait for 1 task to complete",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"abc123\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"output\": \"hello world!\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"outputs\": [], @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"results\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"bot_id\": \"vm-123\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"cas_output_root\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"cas_instance\": \"projects/example-project/instances/default_instance\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"digest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"hash\": \"24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"size_bytes\": \"73\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"duration\": 62.35, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"exit_code\": \"0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"my_task_0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"resultdb_info\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"invocation\": \"invocations/some-inv-name\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"state\": \"COMPLETED\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"task_id\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@task stdout+stderr: my_task_0@hello world!@@@",
+      "@@@STEP_LOG_END@task stdout+stderr: my_task_0@@@",
+      "@@@STEP_LINK@task cas outputs: my_task_0@https://cas-viewer.appspot.com/projects/example-project/instances/default_instance/blobs/24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73/tree@@@"
+    ]
+  },
+  {
+    "failure": {
+      "failure": {},
+      "humanReason": "build 8945511751514863187 failed"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/subbuild/tests/full.expected/launch_builds_ci.json b/recipe_modules/subbuild/tests/full.expected/launch_builds_ci.json
new file mode 100644
index 0000000..2a347b6
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.expected/launch_builds_ci.json
@@ -0,0 +1,324 @@
+[
+  {
+    "cmd": [],
+    "name": "launch builds",
+    "~followup_annotations": [
+      "@@@STEP_LINK@builder-subbuild1@https://ci.chromium.org/b/8945511751514863184@@@",
+      "@@@STEP_LINK@builder-subbuild2@https://ci.chromium.org/b/8945511751514863185@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.schedule",
+    "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"builder-subbuild1\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"fuchsia.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"fuchsia\", \"ref\": \"refs/heads/main\"}, \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}, {\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"builder-subbuild2\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"fuchsia.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"fuchsia\", \"ref\": \"refs/heads/main\"}, \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"host\": \"fuchsia.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }, @@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"host\": \"fuchsia.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863184@https://cr-buildbucket.appspot.com/build/8945511751514863184@@@",
+      "@@@STEP_LINK@8945511751514863185@https://cr-buildbucket.appspot.com/build/8945511751514863185@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds"
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.collect",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "collect",
+      "-host",
+      "cr-buildbucket.appspot.com",
+      "-interval",
+      "20s",
+      "8945511751514863184",
+      "8945511751514863185"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.wait",
+    "timeout": 86400.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.get",
+    "stdin": "{\"requests\": [{\"getBuild\": {\"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", \"id\": \"8945511751514863184\"}}, {\"getBuild\": {\"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", \"id\": \"8945511751514863185\"}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createTime\": \"2018-05-25T23:50:17Z\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createdBy\": \"user:luci-scheduler@appspot.gserviceaccount.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863184\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"invocation\": \"invocations/build:8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }, @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"priority\": 30, @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"taskId\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"host\": \"chromium.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }, @@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createTime\": \"2018-05-25T23:50:17Z\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createdBy\": \"user:luci-scheduler@appspot.gserviceaccount.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863185\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"invocation\": \"invocations/build:8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }, @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"priority\": 30, @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"taskId\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"host\": \"chromium.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"id\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }, @@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"id\": \"8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863184@https://cr-buildbucket.appspot.com/build/8945511751514863184@@@",
+      "@@@STEP_LINK@8945511751514863185@https://cr-buildbucket.appspot.com/build/8945511751514863185@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_ci.json b/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_ci.json
new file mode 100644
index 0000000..0f2ca90
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_ci.json
@@ -0,0 +1,650 @@
+[
+  {
+    "cmd": [],
+    "name": "launch builds",
+    "~followup_annotations": [
+      "@@@STEP_LINK@fuchsia/ci/builder-subbuild1@https://ci.chromium.org/swarming/task/fake-task-id-1?server=example.swarmingserver.appspot.com@@@",
+      "@@@STEP_LINK@builder-subbuild2@https://ci.chromium.org/swarming/task/fake-task-id-2?server=example.swarmingserver.appspot.com@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "get-builder",
+      "-adjust-priority",
+      "0",
+      "fuchsia/ci/builder-subbuild1"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led get-builder",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863184\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit",
+      "-p",
+      "integration_base_revision=\"abc123\"",
+      "-p",
+      "parent_id=\"parentid\""
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"ci\",\n          \"builder\": \"builder-subbuild1\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",\n        \"id\": \"8945511751514863184\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863184\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-1\"\n          }\n        },\n        \"input\": {\n          \"gitiles_commit\": {\n            \"host\": \"chromium.googlesource.com\",\n            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",\n            \"project\": \"fuchsia\",\n            \"ref\": \"refs/heads/main\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\"\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863184\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "launch",
+      "-modernize"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led launch",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"ci\",\n          \"builder\": \"builder-subbuild1\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",\n        \"id\": \"8945511751514863184\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863184\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-1\"\n          }\n        },\n        \"input\": {\n          \"gitiles_commit\": {\n            \"host\": \"chromium.googlesource.com\",\n            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",\n            \"project\": \"fuchsia\",\n            \"ref\": \"refs/heads/main\"\n          },\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\"\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"host_name\": \"example.swarmingserver.appspot.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@Swarming task@https://example.swarmingserver.appspot.com/task?id=fake-task-id-1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "get-builder",
+      "-adjust-priority",
+      "0",
+      "fuchsia/ci/builder-subbuild2"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led get-builder (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863185\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit",
+      "-p",
+      "integration_base_revision=\"abc123\"",
+      "-p",
+      "parent_id=\"parentid\""
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit (2)",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"ci\",\n          \"builder\": \"builder-subbuild2\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",\n        \"id\": \"8945511751514863185\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863185\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-2\"\n          }\n        },\n        \"input\": {\n          \"gitiles_commit\": {\n            \"host\": \"chromium.googlesource.com\",\n            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",\n            \"project\": \"fuchsia\",\n            \"ref\": \"refs/heads/main\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\"\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863185\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "launch",
+      "-modernize"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led launch (2)",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"ci\",\n          \"builder\": \"builder-subbuild2\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",\n        \"id\": \"8945511751514863185\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863185\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-2\"\n          }\n        },\n        \"input\": {\n          \"gitiles_commit\": {\n            \"host\": \"chromium.googlesource.com\",\n            \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",\n            \"project\": \"fuchsia\",\n            \"ref\": \"refs/heads/main\"\n          },\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\"\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"host_name\": \"example.swarmingserver.appspot.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@Swarming task@https://example.swarmingserver.appspot.com/task?id=fake-task-id-2@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds"
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.install infra/tools/luci/swarming",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin",
+      "-ensure-file",
+      "infra/tools/luci/swarming/${platform} swarming_module_pin",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-swarming_module_\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/swarming/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin/swarming",
+      "collect",
+      "-server",
+      "https://example.swarmingserver.appspot.com",
+      "-task-summary-json",
+      "/path/to/tmp/json",
+      "-task-output-stdout",
+      "json",
+      "-output-dir",
+      "[CLEANUP]",
+      "fake-task-id-1",
+      "fake-task-id-2"
+    ],
+    "cost": {
+      "cpu": 100,
+      "disk": 0,
+      "memory": 50,
+      "net": 0
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fake-task-id-1\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"output\": \"hello world!\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"outputs\": [], @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"results\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"bot_id\": \"vm-123\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"cas_output_root\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"cas_instance\": \"projects/example-project/instances/default_instance\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"digest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"hash\": \"24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"size_bytes\": \"73\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"duration\": 62.35, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"exit_code\": \"0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"resultdb_info\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"invocation\": \"invocations/some-inv-name\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"state\": \"COMPLETED\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fake-task-id-2\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"output\": \"hello world!\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"outputs\": [], @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"results\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"bot_id\": \"vm-123\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"cas_output_root\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"cas_instance\": \"projects/example-project/instances/default_instance\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"digest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"hash\": \"24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"size_bytes\": \"73\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"duration\": 62.35, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"exit_code\": \"0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"resultdb_info\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"invocation\": \"invocations/some-inv-name\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"state\": \"COMPLETED\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@task stdout+stderr: builder-subbuild1@hello world!@@@",
+      "@@@STEP_LOG_END@task stdout+stderr: builder-subbuild1@@@",
+      "@@@STEP_LOG_LINE@task stdout+stderr: builder-subbuild2@hello world!@@@",
+      "@@@STEP_LOG_END@task stdout+stderr: builder-subbuild2@@@",
+      "@@@STEP_LINK@task cas outputs: builder-subbuild1@https://cas-viewer.appspot.com/projects/example-project/instances/default_instance/blobs/24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73/tree@@@",
+      "@@@STEP_LINK@task cas outputs: builder-subbuild2@https://cas-viewer.appspot.com/projects/example-project/instances/default_instance/blobs/24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73/tree@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CLEANUP]/fake-task-id-1/build.proto.json",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.read build.proto.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@{@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"id\": \"8945511751514863184\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"invocation\": \"invocations/build:8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"task_id\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"input\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"output\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@}@@@",
+      "@@@STEP_LOG_END@build.proto.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CLEANUP]/fake-task-id-2/build.proto.json",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.read build.proto.json (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@{@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"bucket\": \"ci\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"created_by\": \"user:luci-scheduler@appspot.gserviceaccount.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"id\": \"8945511751514863185\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"invocation\": \"invocations/build:8945511751514863185\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"task_id\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"input\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"gitiles_commit\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"host\": \"chromium.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"project\": \"fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"output\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@}@@@",
+      "@@@STEP_LOG_END@build.proto.json@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_cq.json b/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_cq.json
new file mode 100644
index 0000000..7aedf8d
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.expected/launch_builds_with_led_cq.json
@@ -0,0 +1,850 @@
+[
+  {
+    "cmd": [],
+    "name": "launch builds",
+    "~followup_annotations": [
+      "@@@STEP_LINK@try/builder-subbuild1@https://ci.chromium.org/swarming/task/fake-task-id-1?server=example.swarmingserver.appspot.com@@@",
+      "@@@STEP_LINK@builder-subbuild2@https://ci.chromium.org/swarming/task/fake-task-id-2?server=example.swarmingserver.appspot.com@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "get-builder",
+      "-adjust-priority",
+      "0",
+      "fuchsia/try/builder-subbuild1"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led get-builder",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863186\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863186\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit",
+      "-p",
+      "integration_base_revision=\"abc123\"",
+      "-p",
+      "parent_id=\"parentid\""
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild1\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863186\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863186\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-1\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"chromium-review.googlesource.com\",\n              \"patchset\": \"7\",\n              \"project\": \"fuchsia\"\n            }\n          ]\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863186\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863186\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ],@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit-cr-cl",
+      "https://fuchsia-review.googlesource.com/c/fuchsia/+/123456"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit-cr-cl",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild1\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863186\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863186\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-1\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"chromium-review.googlesource.com\",\n              \"patchset\": \"7\",\n              \"project\": \"fuchsia\"\n            }\n          ],\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863186\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863186\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"fuchsia-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"1337\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ],@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "launch",
+      "-modernize"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led launch",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild1\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863186\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863186\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-1\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"fuchsia-review.googlesource.com\",\n              \"patchset\": \"1337\",\n              \"project\": \"fuchsia\"\n            }\n          ],\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"host_name\": \"example.swarmingserver.appspot.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@Swarming task@https://example.swarmingserver.appspot.com/task?id=fake-task-id-1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "get-builder",
+      "-adjust-priority",
+      "0",
+      "fuchsia/try/builder-subbuild2"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led get-builder (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863187\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit",
+      "-p",
+      "integration_base_revision=\"abc123\"",
+      "-p",
+      "parent_id=\"parentid\""
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit (2)",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild2\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863187\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863187\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-2\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"chromium-review.googlesource.com\",\n              \"patchset\": \"7\",\n              \"project\": \"fuchsia\"\n            }\n          ]\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863187\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ],@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "edit-cr-cl",
+      "https://fuchsia-review.googlesource.com/c/fuchsia/+/123456"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led edit-cr-cl (2)",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild2\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863187\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863187\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-2\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"chromium-review.googlesource.com\",\n              \"patchset\": \"7\",\n              \"project\": \"fuchsia\"\n            }\n          ],\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@proto.output@{@@@",
+      "@@@STEP_LOG_LINE@proto.output@  \"buildbucket\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@    \"bbagent_args\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@      \"build\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"id\": \"8945511751514863187\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          },@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@            {@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"host\": \"fuchsia-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"patchset\": \"1337\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@            }@@@",
+      "@@@STEP_LOG_LINE@proto.output@          ],@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"integration_base_revision\": \"abc123\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"output\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@          \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        },@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@proto.output@          {@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@proto.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@proto.output@          }@@@",
+      "@@@STEP_LOG_LINE@proto.output@        ]@@@",
+      "@@@STEP_LOG_LINE@proto.output@      }@@@",
+      "@@@STEP_LOG_LINE@proto.output@    }@@@",
+      "@@@STEP_LOG_LINE@proto.output@  }@@@",
+      "@@@STEP_LOG_LINE@proto.output@}@@@",
+      "@@@STEP_LOG_END@proto.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "led",
+      "launch",
+      "-modernize"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.led launch (2)",
+    "stdin": "{\n  \"buildbucket\": {\n    \"bbagent_args\": {\n      \"build\": {\n        \"builder\": {\n          \"bucket\": \"try\",\n          \"builder\": \"builder-subbuild2\",\n          \"project\": \"fuchsia\"\n        },\n        \"create_time\": \"2018-05-25T23:50:17Z\",\n        \"created_by\": \"project:fuchsia\",\n        \"id\": \"8945511751514863187\",\n        \"infra\": {\n          \"resultdb\": {\n            \"invocation\": \"invocations/build:8945511751514863187\"\n          },\n          \"swarming\": {\n            \"priority\": 30,\n            \"task_id\": \"fake-task-id-2\"\n          }\n        },\n        \"input\": {\n          \"gerrit_changes\": [\n            {\n              \"change\": \"123456\",\n              \"host\": \"fuchsia-review.googlesource.com\",\n              \"patchset\": \"1337\",\n              \"project\": \"fuchsia\"\n            }\n          ],\n          \"properties\": {\n            \"integration_base_revision\": \"abc123\",\n            \"parent_id\": \"parentid\"\n          }\n        },\n        \"output\": {\n          \"properties\": {\n            \"test_orchestration_inputs_hash\": \"abc\"\n          }\n        },\n        \"status\": \"SUCCESS\",\n        \"tags\": [\n          {\n            \"key\": \"cq_experimental\",\n            \"value\": \"false\"\n          }\n        ]\n      }\n    }\n  }\n}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"host_name\": \"example.swarmingserver.appspot.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@Swarming task@https://example.swarmingserver.appspot.com/task?id=fake-task-id-2@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds"
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.install infra/tools/luci/swarming",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin",
+      "-ensure-file",
+      "infra/tools/luci/swarming/${platform} swarming_module_pin",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.install infra/tools/luci/swarming.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-swarming_module_\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/swarming/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/swarming/swarming_module_pin/swarming",
+      "collect",
+      "-server",
+      "https://example.swarmingserver.appspot.com",
+      "-task-summary-json",
+      "/path/to/tmp/json",
+      "-task-output-stdout",
+      "json",
+      "-output-dir",
+      "[CLEANUP]",
+      "fake-task-id-1",
+      "fake-task-id-2"
+    ],
+    "cost": {
+      "cpu": 100,
+      "disk": 0,
+      "memory": 50,
+      "net": 0
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fake-task-id-1\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"output\": \"hello world!\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"outputs\": [], @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"results\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"bot_id\": \"vm-123\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"cas_output_root\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"cas_instance\": \"projects/example-project/instances/default_instance\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"digest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"hash\": \"24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"size_bytes\": \"73\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"duration\": 62.35, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"exit_code\": \"0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"resultdb_info\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"invocation\": \"invocations/some-inv-name\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"state\": \"COMPLETED\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"task_id\": \"fake-task-id-1\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }, @@@",
+      "@@@STEP_LOG_LINE@json.output@  \"fake-task-id-2\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"output\": \"hello world!\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"outputs\": [], @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"results\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"bot_id\": \"vm-123\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"cas_output_root\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"cas_instance\": \"projects/example-project/instances/default_instance\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"digest\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"hash\": \"24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"size_bytes\": \"73\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"duration\": 62.35, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"exit_code\": \"0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"resultdb_info\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"invocation\": \"invocations/some-inv-name\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }, @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"state\": \"COMPLETED\", @@@",
+      "@@@STEP_LOG_LINE@json.output@      \"task_id\": \"fake-task-id-2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@task stdout+stderr: builder-subbuild1@hello world!@@@",
+      "@@@STEP_LOG_END@task stdout+stderr: builder-subbuild1@@@",
+      "@@@STEP_LOG_LINE@task stdout+stderr: builder-subbuild2@hello world!@@@",
+      "@@@STEP_LOG_END@task stdout+stderr: builder-subbuild2@@@",
+      "@@@STEP_LINK@task cas outputs: builder-subbuild1@https://cas-viewer.appspot.com/projects/example-project/instances/default_instance/blobs/24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73/tree@@@",
+      "@@@STEP_LINK@task cas outputs: builder-subbuild2@https://cas-viewer.appspot.com/projects/example-project/instances/default_instance/blobs/24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73/tree@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CLEANUP]/fake-task-id-1/build.proto.json",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.read build.proto.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@{@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"builder\": \"builder-subbuild1\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"id\": \"8945511751514863186\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"invocation\": \"invocations/build:8945511751514863186\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"task_id\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"input\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    ]@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"output\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  ]@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@}@@@",
+      "@@@STEP_LOG_END@build.proto.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CLEANUP]/fake-task-id-2/build.proto.json",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.read build.proto.json (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@{@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"bucket\": \"try\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"builder\": \"builder-subbuild2\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"create_time\": \"2018-05-25T23:50:17Z\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"created_by\": \"project:fuchsia\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"id\": \"8945511751514863187\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"priority\": 30,@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"task_id\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"input\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"gerrit_changes\": [@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"change\": \"123456\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"host\": \"chromium-review.googlesource.com\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"patchset\": \"7\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@        \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    ]@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"output\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"test_orchestration_inputs_hash\": \"abc\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  },@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"status\": \"SUCCESS\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    {@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"key\": \"cq_experimental\",@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@      \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@    }@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@  ]@@@",
+      "@@@STEP_LOG_LINE@build.proto.json@}@@@",
+      "@@@STEP_LOG_END@build.proto.json@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/subbuild/tests/full.expected/missing_property.json b/recipe_modules/subbuild/tests/full.expected/missing_property.json
new file mode 100644
index 0000000..06754cf
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.expected/missing_property.json
@@ -0,0 +1,278 @@
+[
+  {
+    "cmd": [],
+    "name": "launch builds",
+    "~followup_annotations": [
+      "@@@STEP_LINK@builder-subbuild2@https://ci.chromium.org/b/8945511751514863187@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "launch builds.schedule",
+    "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"builder-subbuild1\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"fuchsia.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"fuchsia\", \"ref\": \"refs/heads/main\"}, \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}, {\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"builder-subbuild2\", \"project\": \"fuchsia\"}, \"experimental\": \"NO\", \"experiments\": {\"luci.buildbucket.parent_tracking\": false}, \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"fuchsia.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"fuchsia\", \"ref\": \"refs/heads/main\"}, \"properties\": {\"integration_base_revision\": \"abc123\", \"parent_id\": \"parentid\"}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", \"swarming\": {\"parentRunId\": \"fake-task-id\"}, \"tags\": [{\"key\": \"hide-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"parent_buildbucket_id\", \"value\": \"8945511751514863184\"}, {\"key\": \"skip-retry-in-gerrit\", \"value\": \"subbuild\"}, {\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild1\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"host\": \"fuchsia.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }, @@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"bucket\": \"ci\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"experiments\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"luci.buildbucket.parent_tracking\": false@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,input,number,output,startTime,status,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"gitilesCommit\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"host\": \"fuchsia.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"project\": \"fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"ref\": \"refs/heads/main\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"properties\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"integration_base_revision\": \"abc123\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"parent_id\": \"parentid\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-00000000133a\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@request@          \"parentRunId\": \"fake-task-id\"@@@",
+      "@@@STEP_LOG_LINE@request@        }, @@@",
+      "@@@STEP_LOG_LINE@request@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"hide-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"parent_buildbucket_id\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"8945511751514863184\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"skip-retry-in-gerrit\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"subbuild\"@@@",
+      "@@@STEP_LOG_LINE@request@          }, @@@",
+      "@@@STEP_LOG_LINE@request@          {@@@",
+      "@@@STEP_LOG_LINE@request@            \"key\": \"user_agent\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"value\": \"recipe\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
+      "@@@STEP_LOG_LINE@request@        ]@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863187@https://cr-buildbucket.appspot.com/build/8945511751514863187@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds",
+    "~followup_annotations": [
+      "@@@STEP_EXCEPTION@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "collect builds.collect",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "collect",
+      "-host",
+      "cr-buildbucket.appspot.com",
+      "-interval",
+      "20s",
+      "8945511751514863187"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.wait",
+    "timeout": 86400.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bb",
+      "batch",
+      "-host",
+      "cr-buildbucket.appspot.com"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "collect builds.collect.get",
+    "stdin": "{\"requests\": [{\"getBuild\": {\"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", \"id\": \"8945511751514863187\"}}]}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@    {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"try\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"builder-subbuild2\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createTime\": \"2018-05-25T23:50:17Z\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"createdBy\": \"project:fuchsia\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"id\": \"8945511751514863187\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"infra\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"resultdb\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"invocation\": \"invocations/build:8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }, @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"swarming\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"priority\": 30, @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"taskId\": \"abc123\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"input\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@          \"gerritChanges\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@            {@@@",
+      "@@@STEP_LOG_LINE@json.output@              \"change\": \"123456\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"host\": \"chromium-review.googlesource.com\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"patchset\": \"7\", @@@",
+      "@@@STEP_LOG_LINE@json.output@              \"project\": \"fuchsia\"@@@",
+      "@@@STEP_LOG_LINE@json.output@            }@@@",
+      "@@@STEP_LOG_LINE@json.output@          ]@@@",
+      "@@@STEP_LOG_LINE@json.output@        }, @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"status\": \"SUCCESS\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"tags\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@          {@@@",
+      "@@@STEP_LOG_LINE@json.output@            \"key\": \"cq_experimental\", @@@",
+      "@@@STEP_LOG_LINE@json.output@            \"value\": \"false\"@@@",
+      "@@@STEP_LOG_LINE@json.output@          }@@@",
+      "@@@STEP_LOG_LINE@json.output@        ]@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    }@@@",
+      "@@@STEP_LOG_LINE@json.output@  ]@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@request@{@@@",
+      "@@@STEP_LOG_LINE@request@  \"requests\": [@@@",
+      "@@@STEP_LOG_LINE@request@    {@@@",
+      "@@@STEP_LOG_LINE@request@      \"getBuild\": {@@@",
+      "@@@STEP_LOG_LINE@request@        \"fields\": \"builder,createTime,createdBy,critical,endTime,id,infra,infra.swarming.taskId,input,number,output,startTime,status,summaryMarkdown,updateTime\", @@@",
+      "@@@STEP_LOG_LINE@request@        \"id\": \"8945511751514863187\"@@@",
+      "@@@STEP_LOG_LINE@request@      }@@@",
+      "@@@STEP_LOG_LINE@request@    }@@@",
+      "@@@STEP_LOG_LINE@request@  ]@@@",
+      "@@@STEP_LOG_LINE@request@}@@@",
+      "@@@STEP_LOG_END@request@@@",
+      "@@@STEP_LINK@8945511751514863187@https://cr-buildbucket.appspot.com/build/8945511751514863187@@@"
+    ]
+  },
+  {
+    "failure": {
+      "humanReason": "Subbuild did not set the 'test_orchestration_inputs_hash' output property"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/subbuild/tests/full.py b/recipe_modules/subbuild/tests/full.py
new file mode 100644
index 0000000..d69166c
--- /dev/null
+++ b/recipe_modules/subbuild/tests/full.py
@@ -0,0 +1,169 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from recipe_engine.recipe_api import Property
+from recipe_engine.config import List
+from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
+from PB.recipe_modules.recipe_engine.led.properties import (
+    InputProperties as LedInputProperties,
+)
+
+DEPS = [
+    "fuchsia/buildbucket_util",
+    "flutter/subbuild",
+    "recipe_engine/properties",
+    "recipe_engine/step",
+]
+
+PROPERTIES = {
+    "builder_names": Property(
+        kind=List(str), help="The names of the builders to launch"
+    ),
+    "extra_properties": Property(
+        kind=dict,
+        help="The extra properties to launch the subbuilds with",
+        default=None,
+    ),
+}
+
+
+def RunSteps(api, builder_names, extra_properties):
+    with api.step.nest("launch builds") as presentation:
+        builds = api.subbuild.launch(
+            builder_names, presentation, extra_properties=extra_properties
+        )
+    with api.step.nest("collect builds", status="last"):
+        builds = api.subbuild.collect([build.build_id for build in builds.values()])
+        for build in builds.values():
+            if build.build_proto.status != common_pb2.SUCCESS:
+                raise api.step.StepFailure(f"build {build.build_id} failed")
+            assert api.subbuild.get_property(
+                build.build_proto, "test_orchestration_inputs_hash"
+            )
+
+
+def GenTests(api):
+    ci_subbuild1 = api.subbuild.ci_build_message(
+        build_id=8945511751514863184,
+        builder="builder-subbuild1",
+        output_props={"test_orchestration_inputs_hash": "abc"},
+        status="SUCCESS",
+    )
+    ci_subbuild2 = api.subbuild.ci_build_message(
+        build_id=8945511751514863185,
+        builder="builder-subbuild2",
+        output_props={"test_orchestration_inputs_hash": "abc"},
+        status="SUCCESS",
+    )
+    try_subbuild1 = api.subbuild.try_build_message(
+        build_id=8945511751514863186,
+        builder="builder-subbuild1",
+        output_props={"test_orchestration_inputs_hash": "abc"},
+        status="SUCCESS",
+    )
+    try_subbuild2 = api.subbuild.try_build_message(
+        build_id=8945511751514863187,
+        builder="builder-subbuild2",
+        output_props={"test_orchestration_inputs_hash": "abc"},
+        status="SUCCESS",
+    )
+    subbuild_missing_property = api.subbuild.try_build_message(
+        build_id=8945511751514863187,
+        builder="builder-subbuild2",
+        output_props={},
+        status="SUCCESS",
+    )
+    failed_subbuild = api.subbuild.try_build_message(
+        build_id=8945511751514863187,
+        builder="builder-subbuild2",
+        status="FAILURE",
+    )
+
+    def properties(project=None, bucket=None, **kwargs):
+        if project:
+            assert bucket
+        project = f"{project}/" if project else ""
+        bucket = f"{bucket}/" if bucket else ""
+        props = dict(
+            builder_names=[
+                f"{project}{bucket}builder-subbuild1",
+                "builder-subbuild2",
+            ],
+            extra_properties={
+                "parent_id": "parentid",
+                # This should be passed through from the parent to the subbuild.
+                "integration_base_revision": "abc123",
+            },
+        )
+        props.update(**kwargs)
+        return api.properties(**props)
+
+    # Use different sets of options for different cases so we get coverage of
+    # the logic to split the builder name without adding more tests.
+
+    def ci_properties(**kwargs):
+        return properties(project="fuchsia", bucket="ci", **kwargs)
+
+    def try_properties(**kwargs):
+        return properties(bucket="try", **kwargs)
+
+    yield (
+        api.buildbucket_util.test("launch_builds_ci")
+        + ci_properties()
+        + api.subbuild.child_build_steps(
+            builds=[ci_subbuild1, ci_subbuild2],
+            launch_step="launch builds",
+            collect_step="collect builds",
+        )
+    )
+
+    yield (
+        api.buildbucket_util.test("missing_property", status="infra_failure")
+        + properties()
+        + api.subbuild.child_build_steps(
+            builds=[subbuild_missing_property],
+            launch_step="launch builds",
+            collect_step="collect builds",
+        )
+    )
+
+    yield (
+        api.buildbucket_util.test("launch_builds_with_led_ci")
+        + ci_properties(
+            **{
+                "$recipe_engine/led": LedInputProperties(
+                    led_run_id="led/user_example.com/abc123",
+                ),
+            }
+        )
+        + api.subbuild.child_led_steps(
+            builds=[ci_subbuild1, ci_subbuild2],
+            collect_step="collect builds",
+        )
+    )
+
+    yield (
+        api.buildbucket_util.test("launch_builds_with_led_cq", tryjob=True)
+        + try_properties(
+            **{
+                "$recipe_engine/led": LedInputProperties(
+                    led_run_id="led/user_example.com/abc123",
+                ),
+            }
+        )
+        + api.subbuild.child_led_steps(
+            builds=[try_subbuild1, try_subbuild2],
+            collect_step="collect builds",
+        )
+    )
+
+    yield (
+        api.buildbucket_util.test("failed_subbuild", tryjob=True, status="failure")
+        + properties()
+        + api.subbuild.child_build_steps(
+            builds=[failed_subbuild],
+            launch_step="launch builds",
+            collect_step="collect builds",
+        )
+    )