[engine_v2] Use some of the implementation of flutter_drone in engine_v2/tester

Existing support for installing test dependencies and setting up
the Flutter environment is used by the flutter/flutter_drone recipe
to run tests.

Use this support in the engine_v2/tester recipe.

Bug: b/241224027
Change-Id: I822e381c9030e6e9330abffd433b11bc886b4ed7
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/37200
Commit-Queue: William Hesse <whesse@google.com>
Reviewed-by: Godofredo Contreras <godofredoc@google.com>
diff --git a/recipes/engine_v2/tester.expected/engine.json b/recipes/engine_v2/tester.expected/engine.json
index 743eb85..a97e17a 100644
--- a/recipes/engine_v2/tester.expected/engine.json
+++ b/recipes/engine_v2/tester.expected/engine.json
@@ -226,12 +226,12 @@
   },
   {
     "cmd": [
-      "[CACHE]/builder/flutter/bin/flutter",
-      "update-packages"
+      "git",
+      "rev-parse",
+      "HEAD"
     ],
-    "env": {
-      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2"
-    },
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
     "luci_context": {
       "realm": {
         "name": "flutter:prod"
@@ -244,16 +244,74 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "Update packages"
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "flutter",
+      "update-packages"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2",
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_coverage",
+      "SUBSHARD": null
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "flutter:prod"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "download dependencies"
   },
   {
     "cmd": [
       "[CACHE]/builder/flutter/bin/dart",
       "[CACHE]/builder/flutter/dev/bots/test.dart"
     ],
+    "cwd": "[CACHE]/builder/flutter",
     "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
       "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2",
-      "SHARD": "framework_coverage"
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_coverage",
+      "SUBSHARD": null
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
     },
     "luci_context": {
       "realm": {
@@ -267,7 +325,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "Run tests"
+    "name": "Run framework_coverage tests"
   },
   {
     "name": "$result"
diff --git a/recipes/engine_v2/tester.expected/monorepo.json b/recipes/engine_v2/tester.expected/monorepo.json
index 6b6c5f7..34fcc9f 100644
--- a/recipes/engine_v2/tester.expected/monorepo.json
+++ b/recipes/engine_v2/tester.expected/monorepo.json
@@ -453,12 +453,12 @@
   },
   {
     "cmd": [
-      "[CACHE]/builder/flutter/bin/flutter",
-      "update-packages"
+      "git",
+      "rev-parse",
+      "HEAD"
     ],
-    "env": {
-      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo"
-    },
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
     "luci_context": {
       "realm": {
         "name": "dart:ci.sandbox"
@@ -471,16 +471,74 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "Update packages"
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "flutter",
+      "update-packages"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_coverage",
+      "SUBSHARD": null
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "download dependencies"
   },
   {
     "cmd": [
       "[CACHE]/builder/flutter/bin/dart",
       "[CACHE]/builder/flutter/dev/bots/test.dart"
     ],
+    "cwd": "[CACHE]/builder/flutter",
     "env": {
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
       "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
-      "SHARD": "framework_coverage"
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_coverage",
+      "SUBSHARD": null
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
     },
     "luci_context": {
       "realm": {
@@ -494,7 +552,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "Run tests"
+    "name": "Run framework_coverage tests"
   },
   {
     "name": "$result"
diff --git a/recipes/engine_v2/tester.expected/monorepo_framework_tests.json b/recipes/engine_v2/tester.expected/monorepo_framework_tests.json
new file mode 100644
index 0000000..fc5eddf
--- /dev/null
+++ b/recipes/engine_v2/tester.expected/monorepo_framework_tests.json
@@ -0,0 +1,610 @@
+[
+  {
+    "cmd": [],
+    "name": "Checkout flutter/monorepo"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[CACHE]/builder/monorepo",
+      "--url",
+      "https://dart.googlesource.com/monorepo"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CACHE]/builder/monorepo/commits.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "get commits from monorepo",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@commits.json@{@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"engine/src/flutter\": \"57ac2d3d67bde512ed071d0250bfdcb986142ea4\",@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"engine/src/third_party/dart\": \"355295789e4dee435d6ae2dff3d38dc1d5a9ab9a\",@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"flutter\": \"523b600efeb7d60b743c1b952201aa969a744791\"@@@",
+      "@@@STEP_LOG_LINE@commits.json@}@@@",
+      "@@@STEP_LOG_END@commits.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/flutter"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[CACHE]/builder/flutter",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/flutter"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "523b600efeb7d60b743c1b952201aa969a744791"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
+      "[CACHE]/builder/flutter/bin/internal/engine.version"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "update engine version",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@engine.version@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@",
+      "@@@STEP_LOG_END@engine.version@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/android",
+      "-ensure-file",
+      "flutter/android/sdk/all/${platform} version:33v6",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure_installed",
+    "~followup_annotations": [
+      "@@@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-version:33v6----\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter/android/sdk/all/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": [
+      "flutter",
+      "update-packages"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/android/sdk",
+      "ANDROID_NDK_PATH": "[CACHE]/android/ndk",
+      "ANDROID_SDK_ROOT": "[CACHE]/android/sdk",
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
+      "GIT_BRANCH": "",
+      "GRADLE_OPTS": "-Dorg.gradle.daemon=false",
+      "GRADLE_USER_HOME": "[CACHE]/gradle",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_tests",
+      "SUBSHARD": "slow"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "download dependencies"
+  },
+  {
+    "cmd": [
+      "[CACHE]/builder/flutter/bin/dart",
+      "[CACHE]/builder/flutter/dev/bots/test.dart"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "ANDROID_HOME": "[CACHE]/android/sdk",
+      "ANDROID_NDK_PATH": "[CACHE]/android/ndk",
+      "ANDROID_SDK_ROOT": "[CACHE]/android/sdk",
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
+      "GIT_BRANCH": "",
+      "GRADLE_OPTS": "-Dorg.gradle.daemon=false",
+      "GRADLE_USER_HOME": "[CACHE]/gradle",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "framework_tests",
+      "SUBSHARD": "slow"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin"
+      ]
+    },
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Run framework_tests slow tests"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/engine_v2/tester.expected/monorepo_web_tests.json b/recipes/engine_v2/tester.expected/monorepo_web_tests.json
new file mode 100644
index 0000000..f648bd4
--- /dev/null
+++ b/recipes/engine_v2/tester.expected/monorepo_web_tests.json
@@ -0,0 +1,654 @@
+[
+  {
+    "cmd": [],
+    "name": "Checkout flutter/monorepo"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[CACHE]/builder/monorepo",
+      "--url",
+      "https://dart.googlesource.com/monorepo"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[CACHE]/builder/monorepo",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/monorepo.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[CACHE]/builder/monorepo/commits.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "get commits from monorepo",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@commits.json@{@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"engine/src/flutter\": \"57ac2d3d67bde512ed071d0250bfdcb986142ea4\",@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"engine/src/third_party/dart\": \"355295789e4dee435d6ae2dff3d38dc1d5a9ab9a\",@@@",
+      "@@@STEP_LOG_LINE@commits.json@  \"flutter\": \"523b600efeb7d60b743c1b952201aa969a744791\"@@@",
+      "@@@STEP_LOG_LINE@commits.json@}@@@",
+      "@@@STEP_LOG_END@commits.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "Checkout flutter/flutter"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[CACHE]/builder/flutter",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/flutter"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "523b600efeb7d60b743c1b952201aa969a744791"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Checkout flutter/flutter.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
+      "[CACHE]/builder/flutter/bin/internal/engine.version"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "update engine version",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@engine.version@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@",
+      "@@@STEP_LOG_END@engine.version@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [],
+    "name": "Chrome and driver dependency"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/chrome/chrome",
+      "-ensure-file",
+      "flutter_internal/browsers/chrome/${platform} version:96.2",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Chrome and driver dependency.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-version:96.2----\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter_internal/browsers/chrome/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": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CACHE]/chrome/drivers",
+      "-ensure-file",
+      "flutter_internal/browser-drivers/chrome/${platform} version:96.2",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Chrome and driver dependency.ensure_installed (2)",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@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-version:96.2----\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"flutter_internal/browser-drivers/chrome/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": [
+      "flutter",
+      "update-packages"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
+      "CHROME_NO_SANDBOX": "true",
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "web_tests",
+      "SUBSHARD": "3"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin",
+        "[CACHE]/chrome/chrome",
+        "[CACHE]/chrome/drivers"
+      ]
+    },
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "download dependencies"
+  },
+  {
+    "cmd": [
+      "[CACHE]/builder/flutter/bin/dart",
+      "[CACHE]/builder/flutter/dev/bots/test.dart"
+    ],
+    "cwd": "[CACHE]/builder/flutter",
+    "env": {
+      "CHROME_EXECUTABLE": "[CACHE]/chrome/chrome/chrome",
+      "CHROME_NO_SANDBOX": "true",
+      "DEPOT_TOOLS": "RECIPE_REPO[depot_tools]",
+      "FLUTTER_STORAGE_BASE_URL": "https://storage.googleapis.com/flutter_archives_v2/monorepo",
+      "GIT_BRANCH": "",
+      "LUCI_BRANCH": "",
+      "LUCI_CI": "True",
+      "LUCI_PR": "",
+      "OS": "linux",
+      "PUB_CACHE": "[START_DIR]/.pub-cache",
+      "REVISION": "12345abcde12345abcde12345abcde12345abcde",
+      "SDK_CHECKOUT_PATH": "[CACHE]/builder/flutter",
+      "SHARD": "web_tests",
+      "SUBSHARD": "3"
+    },
+    "env_prefixes": {
+      "PATH": [
+        "[CACHE]/builder/flutter/bin",
+        "[CACHE]/builder/flutter/bin/cache/dart-sdk/bin",
+        "[CACHE]/chrome/chrome",
+        "[CACHE]/chrome/drivers"
+      ]
+    },
+    "luci_context": {
+      "realm": {
+        "name": "dart:ci.sandbox"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "Run web_tests 3 tests"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/engine_v2/tester.py b/recipes/engine_v2/tester.py
index c57305e..d86bd6d 100644
--- a/recipes/engine_v2/tester.py
+++ b/recipes/engine_v2/tester.py
@@ -11,8 +11,10 @@
 from PB.recipes.flutter.engine.engine import EnvProperties
 
 DEPS = [
+    'flutter/flutter_deps',
     'flutter/monorepo',
     'flutter/repo_util',
+    'flutter/retry',
     'recipe_engine/buildbucket',
     'recipe_engine/context',
     'recipe_engine/file',
@@ -44,20 +46,6 @@
   return commits['flutter']
 
 
-def test(api, builder, flutter, artifact_url):
-  """Runs an independent test task."""
-  test_config = api.properties.get('build')
-  environment = {
-      'FLUTTER_STORAGE_BASE_URL': artifact_url, 'SHARD': test_config['shard']
-  }
-  with api.context(env=environment):
-    api.step(
-        'Run tests',
-        [flutter.join('bin', 'dart'),
-         flutter.join('dev', 'bots', 'test.dart')]
-    )
-
-
 def RunSteps(api, properties, env_properties):
   builder = api.path['cache'].join('builder')
   flutter = builder.join('flutter')
@@ -75,13 +63,34 @@
       'update engine version',
       flutter.join('bin', 'internal', 'engine.version'), engine_version + '\n'
   )
-  environment = {'FLUTTER_STORAGE_BASE_URL': artifact_url}
-  with api.context(env=environment):
-    api.step(
-        'Update packages', [flutter.join('bin', 'flutter'), 'update-packages']
-    )
-  test(api, builder, flutter, artifact_url)
 
+  # TODO(https://github.com/flutter/flutter/issues/116906): Combine this
+  # recipe with the flutter/flutter_drone recipe if possible, to avoid
+  # duplication.
+  env, env_prefixes = api.repo_util.flutter_environment(flutter)
+  test_config = api.properties.get('build')
+  deps = test_config.get('dependencies', [])
+  api.flutter_deps.required_deps(env, env_prefixes, deps)
+  shard = test_config.get('shard')
+  subshard = test_config.get('subshard')
+  env['SHARD'] = shard
+  env['SUBSHARD'] = subshard
+  if subshard:
+    shard_name = '%s %s' % (shard, subshard)
+  else:
+    shard_name = shard
+  env['FLUTTER_STORAGE_BASE_URL'] = artifact_url
+  with api.context(env=env, env_prefixes=env_prefixes, cwd=flutter):
+    api.retry.step(
+        'download dependencies', ['flutter', 'update-packages'],
+        max_attempts=2,
+        infra_step=True
+    )
+    api.step(
+        'Run %s tests' % shard_name,
+        [flutter.join('bin', 'dart'),
+         flutter.join('dev', 'bots', 'test.dart')]
+    )
 
 def GenTests(api):
   build = {'shard': 'framework_coverage'}
@@ -114,3 +123,42 @@
           build_number=123,
       ),
   )
+
+  web_tests_subshard_build = {
+      'shard':
+          'web_tests',
+      'subshard':
+          '3',
+      'dependencies': [{
+          "dependency": "chrome_and_driver", "version": "version:96.2"
+      }],
+  }
+
+  yield api.test(
+      'monorepo_web_tests',
+      api.properties(build=web_tests_subshard_build, no_goma=True),
+      api.monorepo.ci_build(),
+      api.step_data(
+          'get commits from monorepo',
+          api.file.read_json(SAMPLE_MONOREPO_COMMITS)
+      ),
+  )
+
+  framework_tests_subshard_build = {
+      'shard':
+          'framework_tests',
+      'subshard':
+          'slow',
+      'dependencies': [{"dependency": "android_sdk",
+                        "version": "version:33v6"}],
+  }
+
+  yield api.test(
+      'monorepo_framework_tests',
+      api.properties(build=framework_tests_subshard_build, no_goma=True),
+      api.monorepo.ci_build(),
+      api.step_data(
+          'get commits from monorepo',
+          api.file.read_json(SAMPLE_MONOREPO_COMMITS)
+      ),
+  )