diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md
index af9889619f..4b78b06649 100644
--- a/recipes/README.recipes.md
+++ b/recipes/README.recipes.md
@@ -780,7 +780,7 @@ Returns:
#### **class [TryserverApi](/recipes/recipe_modules/tryserver/api.py#11)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
-— **def [add\_failure\_reason](/recipes/recipe_modules/tryserver/api.py#221)(self, reason):**
+— **def [add\_failure\_reason](/recipes/recipe_modules/tryserver/api.py#237)(self, reason):**
Records a more detailed reason why build is failing.
@@ -820,11 +820,11 @@ Argument:
Returned paths will be relative to to patch_root.
-— **def [get\_footer](/recipes/recipe_modules/tryserver/api.py#279)(self, tag, patch_text=None):**
+— **def [get\_footer](/recipes/recipe_modules/tryserver/api.py#295)(self, tag, patch_text=None):**
Gets a specific tag from a CL description
-— **def [get\_footers](/recipes/recipe_modules/tryserver/api.py#259)(self, patch_text=None):**
+— **def [get\_footers](/recipes/recipe_modules/tryserver/api.py#275)(self, patch_text=None):**
Retrieves footers from the patch description.
@@ -843,7 +843,7 @@ Returns true iff the properties exist to match a Gerrit issue.
Returns true iff we have a change to check out.
-— **def [normalize\_footer\_name](/recipes/recipe_modules/tryserver/api.py#283)(self, footer):**
+— **def [normalize\_footer\_name](/recipes/recipe_modules/tryserver/api.py#299)(self, footer):**
— **def [set\_compile\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#200)(self):**
@@ -856,7 +856,7 @@ A flag to indicate the build should not be retried by the CQ.
This mechanism is used to reduce CQ duration when retrying will likely
return an identical result.
- **@contextlib.contextmanager**
— **def [set\_failure\_hash](/recipes/recipe_modules/tryserver/api.py#230)(self):**
+ **@contextlib.contextmanager**
— **def [set\_failure\_hash](/recipes/recipe_modules/tryserver/api.py#246)(self):**
Context manager that sets a failure_hash build property on StepFailure.
@@ -884,12 +884,26 @@ Adds a subproject tag to the build.
This can be used to distinguish between builds that execute different steps
depending on what was patched, e.g. blink vs. pure chromium patches.
+— **def [set\_test\_expired\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#229)(self):**
+
+Mark the tryjob result as a test expiration.
+
+This means a test task expired and was never scheduled, most likely due to
+lack of capacity.
+
— **def [set\_test\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#204)(self):**
Mark the tryjob result as a test failure.
This means we started running actual tests (not prerequisite steps
like checkout or compile), and some of these tests have failed.
+
+— **def [set\_test\_timeout\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#221)(self):**
+
+Mark the tryjob result as a test timeout.
+
+This means tests were scheduled but didn't finish executing within the
+timeout.
### *recipe_modules* / [windows\_sdk](/recipes/recipe_modules/windows_sdk)
[DEPS](/recipes/recipe_modules/windows_sdk/__init__.py#5): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/step][recipe_engine/recipe_modules/step]
diff --git a/recipes/recipe_modules/tryserver/api.py b/recipes/recipe_modules/tryserver/api.py
index 42ff0d9604..16bffc200d 100644
--- a/recipes/recipe_modules/tryserver/api.py
+++ b/recipes/recipe_modules/tryserver/api.py
@@ -218,6 +218,22 @@ class TryserverApi(recipe_api.RecipeApi):
"""
self._set_failure_type('INVALID_TEST_RESULTS')
+ def set_test_timeout_tryjob_result(self):
+ """Mark the tryjob result as a test timeout.
+
+ This means tests were scheduled but didn't finish executing within the
+ timeout.
+ """
+ self._set_failure_type('TEST_TIMEOUT')
+
+ def set_test_expired_tryjob_result(self):
+ """Mark the tryjob result as a test expiration.
+
+ This means a test task expired and was never scheduled, most likely due to
+ lack of capacity.
+ """
+ self._set_failure_type('TEST_EXPIRED')
+
def add_failure_reason(self, reason):
"""
Records a more detailed reason why build is failing.
diff --git a/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json b/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json
index 682e26081d..d3adadfb40 100644
--- a/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json
+++ b/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json
@@ -170,6 +170,24 @@
"@@@STEP_FAILURE@@@"
]
},
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (5)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_TIMEOUT@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_TIMEOUT\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (6)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_EXPIRED@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_EXPIRED\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
{
"cmd": [
"python",
diff --git a/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json b/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json
index 60217faf04..0a7368bbc7 100644
--- a/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json
+++ b/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json
@@ -170,6 +170,24 @@
"@@@STEP_FAILURE@@@"
]
},
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (5)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_TIMEOUT@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_TIMEOUT\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (6)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_EXPIRED@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_EXPIRED\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
{
"cmd": [
"python",
diff --git a/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch.json b/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch.json
index d09899d7bd..1591255979 100644
--- a/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch.json
+++ b/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch.json
@@ -67,6 +67,24 @@
"@@@STEP_FAILURE@@@"
]
},
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (5)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_TIMEOUT@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_TIMEOUT\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (6)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_EXPIRED@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_EXPIRED\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
{
"cmd": [
"python",
diff --git a/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch_luci.json b/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch_luci.json
index d09899d7bd..1591255979 100644
--- a/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch_luci.json
+++ b/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch_luci.json
@@ -67,6 +67,24 @@
"@@@STEP_FAILURE@@@"
]
},
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (5)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_TIMEOUT@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_TIMEOUT\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "TRYJOB FAILURE (6)",
+ "~followup_annotations": [
+ "@@@STEP_TEXT@TEST_EXPIRED@@@",
+ "@@@SET_BUILD_PROPERTY@failure_type@\"TEST_EXPIRED\"@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
{
"cmd": [
"python",
diff --git a/recipes/recipe_modules/tryserver/examples/full.py b/recipes/recipe_modules/tryserver/examples/full.py
index 4d4c342bc8..27e7e70240 100644
--- a/recipes/recipe_modules/tryserver/examples/full.py
+++ b/recipes/recipe_modules/tryserver/examples/full.py
@@ -50,6 +50,8 @@ def RunSteps(api):
api.tryserver.set_compile_failure_tryjob_result()
api.tryserver.set_test_failure_tryjob_result()
api.tryserver.set_invalid_test_results_tryjob_result()
+ api.tryserver.set_test_timeout_tryjob_result()
+ api.tryserver.set_test_expired_tryjob_result()
api.tryserver.normalize_footer_name('Cr-Commit-Position')