diff --git a/apple/testing/default_runner/ios_xctestrun_runner.bzl b/apple/testing/default_runner/ios_xctestrun_runner.bzl
index 00043a0f15..591e0d2c2e 100644
--- a/apple/testing/default_runner/ios_xctestrun_runner.bzl
+++ b/apple/testing/default_runner/ios_xctestrun_runner.bzl
@@ -163,6 +163,7 @@ When executed, the binary will have the following environment variables availabl
- `SIMULATOR_UDID`: The UDID of the simulator to clean up. This will be the same UDID produced by the `create_simulator_action` and used to run the tests.
- `SIMULATOR_REUSE_SIMULATOR`: Whether to an existing simulator was reused or if a new one was created. The value will be set to "1" if the `reuse_simulator` attribute is true, and unset otherwise. Whether or not this variable is respected should be treated as an implementation detail of the simulator cleanup tool.
+- `TEST_TIMEOUT_DETECTED`: Whether the test timed out. The value will be set to "1" if the test timed out (i.e., if the test runner received SIGTERM or SIGINT), and unset otherwise.
""",
),
diff --git a/apple/testing/default_runner/ios_xctestrun_runner.template.sh b/apple/testing/default_runner/ios_xctestrun_runner.template.sh
index 2c1fcadf62..c3d7024ae7 100755
--- a/apple/testing/default_runner/ios_xctestrun_runner.template.sh
+++ b/apple/testing/default_runner/ios_xctestrun_runner.template.sh
@@ -53,10 +53,33 @@ basename_without_extension() {
echo "${filename%.*}"
}
+test_timeout_detected=""
+
+cleanup() {
+ local exit_status=$?
+
+ # Clean up simulator if one was created.
+ if [[ -n "${simulator_id:-}" && "$simulator_id" != "unused" ]]; then
+ SIMULATOR_UDID="$simulator_id" \
+ SIMULATOR_REUSE_SIMULATOR="${reuse_simulator:-}" \
+ XCTESTRUN_RUNNER_PID="${BASHPID:-$$}" \
+ TEST_TIMEOUT_DETECTED="${test_timeout_detected:-}" \
+ "%(clean_up_simulator_action_binary)s"
+ fi
+
+ # Clean up temporary directory if appropriate.
+ if [[ -n "${test_tmp_dir:-}" && -z "${NO_CLEAN:-}" ]]; then
+ rm -rf "${test_tmp_dir}"
+ fi
+
+ exit $exit_status
+}
+
+trap 'cleanup' EXIT
+trap 'test_timeout_detected=1; exit 143' INT TERM
+
test_tmp_dir="$(mktemp -d "${TEST_TMPDIR:-${TMPDIR:-/tmp}}/test_tmp_dir.XXXXXX")"
-if [[ -z "${NO_CLEAN:-}" ]]; then
- trap 'rm -rf "${test_tmp_dir}"' EXIT
-else
+if [[ -n "${NO_CLEAN:-}" ]]; then
test_tmp_dir="${TMPDIR:-/tmp}/test_tmp_dir"
rm -rf "$test_tmp_dir"
mkdir -p "$test_tmp_dir"
@@ -647,8 +670,6 @@ if [[
rm -r "$result_bundle_path"
fi
-SIMULATOR_UDID="$simulator_id" SIMULATOR_REUSE_SIMULATOR="${reuse_simulator:-}" XCTESTRUN_RUNNER_PID="${BASHPID:-$$}" "%(clean_up_simulator_action_binary)s"
-
if [[ "$post_action_determines_exit_code" == true ]]; then
if [[ "$post_action_exit_code" -ne 0 ]]; then
echo "error: post_action exited with '$post_action_exit_code'" >&2
diff --git a/apple/testing/default_runner/simulator_cleanup.sh b/apple/testing/default_runner/simulator_cleanup.sh
index ff63d935b5..c5acfee518 100755
--- a/apple/testing/default_runner/simulator_cleanup.sh
+++ b/apple/testing/default_runner/simulator_cleanup.sh
@@ -7,7 +7,7 @@ if [ -z "${SIMULATOR_UDID:-}" ]; then
exit 1
fi
-if [ -z "${SIMULATOR_REUSE_SIMULATOR:-}" ]; then
+if [ -z "${SIMULATOR_REUSE_SIMULATOR:-}" ] || [ -n "${TEST_TIMEOUT_DETECTED:-}" ]; then
# Delete will shutdown down the simulator if it's still currently running.
xcrun simctl delete "$SIMULATOR_UDID"
fi
diff --git a/doc/rules-ios.md b/doc/rules-ios.md
index 391159fb08..f1a8ce78ce 100644
--- a/doc/rules-ios.md
+++ b/doc/rules-ios.md
@@ -691,7 +691,7 @@ in Xcode.
| :------------- | :------------- | :------------- | :------------- | :------------- |
| name | A unique name for this target. | Name | required | |
| attachment_lifetime | Attachment lifetime to set in the xctestrun file when running the test bundle - `"keepNever"` (default), `"keepAlways"` or `"deleteOnSuccess"`. This affects presence of attachments in the XCResult output. This does not force using `xcodebuild` or an XCTestRun file but the value will be used in that case. | String | optional | `"keepNever"` |
-| clean_up_simulator_action | A binary that cleans up any simulators created by the `create_simulator_action`. Runs after the `post_action`, regardless of test success or failure.
When executed, the binary will have the following environment variables available to it:
- `SIMULATOR_UDID`: The UDID of the simulator to clean up. This will be the same UDID produced by the `create_simulator_action` and used to run the tests.
- `SIMULATOR_REUSE_SIMULATOR`: Whether to an existing simulator was reused or if a new one was created. The value will be set to "1" if the `reuse_simulator` attribute is true, and unset otherwise. Whether or not this variable is respected should be treated as an implementation detail of the simulator cleanup tool.
| Label | optional | `"@rules_apple//apple/testing/default_runner:simulator_cleanup"` |
+| clean_up_simulator_action | A binary that cleans up any simulators created by the `create_simulator_action`. Runs after the `post_action`, regardless of test success or failure.
When executed, the binary will have the following environment variables available to it:
- `SIMULATOR_UDID`: The UDID of the simulator to clean up. This will be the same UDID produced by the `create_simulator_action` and used to run the tests.
- `SIMULATOR_REUSE_SIMULATOR`: Whether to an existing simulator was reused or if a new one was created. The value will be set to "1" if the `reuse_simulator` attribute is true, and unset otherwise. Whether or not this variable is respected should be treated as an implementation detail of the simulator cleanup tool.
- `TEST_TIMEOUT_DETECTED`: Whether the test timed out. The value will be set to "1" if the test timed out (i.e., if the test runner received SIGTERM or SIGINT), and unset otherwise.
| Label | optional | `"@rules_apple//apple/testing/default_runner:simulator_cleanup"` |
| command_line_args | CommandLineArguments to pass to xctestrun file when running the test bundle. This means it will always use `xcodebuild test-without-building` to run the test bundle. | List of strings | optional | `[]` |
| create_simulator_action | A binary that produces a UDID for a simulator that matches the given device type and OS version. Runs before the `pre_action`. The UDID will be used to run the tests on the correct simulator. The binary must print only the UDID to stdout.
When executed, the binary will have the following environment variables available to it:
- `SIMULATOR_DEVICE_TYPE`: The device type of the simulator to create. The supported types correspond to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air. The value will either be the value of the `device_type` attribute, or the `ios_simulator_device` build setting.
- `SIMULATOR_OS_VERSION`: The OS version of the simulator to create. The supported OS versions correspond to the output of `xcrun simctl list runtimes`. E.g., 11.2, 9.3. The value will either be the value of the `os_version` attribute, or the `ios_simulator_version` build setting.
- `SIMULATOR_REUSE_SIMULATOR`: Whether to reuse an existing simulator or create a new one. The value will be set to "1" if the `reuse_simulator` attribute is true, and unset otherwise. Whether or not this variable is respected should be treated as an implementation detail of the simulator creator tool.
- `SIMULATOR_SDK_VERSION`: The SDK version of the simulator to create. The supported SDK builds correspond to the output of `xcrun simctl runtime match list`. E.g., 11.2, 9.3. The value will be derived from the `default_ios_sdk_version` for the current Xcode version.
| Label | optional | `"@rules_apple//apple/testing/default_runner:simulator_creator"` |
| create_xcresult_bundle | Force the test runner to always create an XCResult bundle. This means it will always use `xcodebuild test-without-building` to run the test bundle. | Boolean | optional | `False` |