Skip to content

Commit

Permalink
Add test_timeout fields to go_package (#13707)
Browse files Browse the repository at this point in the history
Closes #13530.

Unlike Python, we use Go's native timeout support instead of the engine's. Users could have already set the timeout globally via `[go-test].args`, so we have to special-case that the global args should override the field.

[ci skip-rust]
  • Loading branch information
Eric-Arellano authored Dec 2, 2021
1 parent eb7ff2f commit 54f72e8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
31 changes: 25 additions & 6 deletions src/python/pants/backend/go/goals/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
from __future__ import annotations

import os
from dataclasses import dataclass
from typing import Sequence

from pants.backend.go.subsystems.gotest import GoTestSubsystem
from pants.backend.go.target_types import GoPackageSourcesField, SkipGoTestsField
from pants.backend.go.target_types import (
GoPackageSourcesField,
GoTestTimeoutField,
SkipGoTestsField,
)
from pants.backend.go.util_rules.build_pkg import (
BuildGoPackageRequest,
FallibleBuildGoPackageRequest,
Expand Down Expand Up @@ -61,26 +66,29 @@
}


@dataclass(frozen=True)
class GoTestFieldSet(TestFieldSet):
required_fields = (GoPackageSourcesField,)

sources: GoPackageSourcesField
timeout: GoTestTimeoutField

@classmethod
def opt_out(cls, tgt: Target) -> bool:
return tgt.get(SkipGoTestsField).value


def transform_test_args(args: Sequence[str]) -> tuple[str, ...]:
def transform_test_args(args: Sequence[str], timeout_field_value: int | None) -> tuple[str, ...]:
result = []

i = 0
next_arg_is_option_value = False
timeout_is_set = False
while i < len(args):
arg = args[i]
i += 1

# If this argument is an option value, then append it to the result and continue to next argument.
# If this argument is an option value, then append it to the result and continue to next
# argument.
if next_arg_is_option_value:
result.append(arg)
next_arg_is_option_value = False
Expand All @@ -106,13 +114,21 @@ def transform_test_args(args: Sequence[str]) -> tuple[str, ...]:
option_value = ""

if arg_name in TEST_FLAGS:
if arg_name == "timeout":
timeout_is_set = True

rewritten_arg = f"{arg[0:start_index]}test.{arg_name}{option_value}"
result.append(rewritten_arg)
if TEST_FLAGS[arg_name] and option_value == "":

no_opt_provided = TEST_FLAGS[arg_name] and option_value == ""
if no_opt_provided:
next_arg_is_option_value = True
else:
result.append(arg)

if not timeout_is_set and timeout_field_value is not None:
result.append(f"-test.timeout={timeout_field_value}s")

result.extend(args[i:])
return tuple(result)

Expand Down Expand Up @@ -249,7 +265,10 @@ def compilation_failure(exit_code: int, stderr: str) -> TestResult:
result = await Get(
FallibleProcessResult,
Process(
["./test_runner", *transform_test_args(go_test_subsystem.args)],
[
"./test_runner",
*transform_test_args(go_test_subsystem.args, field_set.timeout.value),
],
input_digest=binary.digest,
description=f"Run Go tests: {field_set.address}",
cache_scope=cache_scope,
Expand Down
33 changes: 30 additions & 3 deletions src/python/pants/backend/go/goals/test_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,42 @@ def rule_runner() -> RuleRunner:


def test_transform_test_args() -> None:
assert transform_test_args(["-v", "--", "-v"]) == ("-test.v", "--", "-v")
assert transform_test_args(["-run=TestFoo", "-v"]) == ("-test.run=TestFoo", "-test.v")
assert transform_test_args(["-run", "TestFoo", "-foo", "-v"]) == (
assert transform_test_args(["-v", "--", "-v"], timeout_field_value=None) == (
"-test.v",
"--",
"-v",
)
assert transform_test_args(["-run=TestFoo", "-v"], timeout_field_value=None) == (
"-test.run=TestFoo",
"-test.v",
)
assert transform_test_args(["-run", "TestFoo", "-foo", "-v"], timeout_field_value=None) == (
"-test.run",
"TestFoo",
"-foo",
"-test.v",
)

assert transform_test_args(["-timeout=1m", "-v"], timeout_field_value=None) == (
"-test.timeout=1m",
"-test.v",
)
assert transform_test_args(["-timeout", "1m", "-v"], timeout_field_value=None) == (
"-test.timeout",
"1m",
"-test.v",
)
assert transform_test_args(["-v"], timeout_field_value=100) == ("-test.v", "-test.timeout=100s")
assert transform_test_args(["-timeout=1m", "-v"], timeout_field_value=100) == (
"-test.timeout=1m",
"-test.v",
)
assert transform_test_args(["-timeout", "1m", "-v"], timeout_field_value=100) == (
"-test.timeout",
"1m",
"-test.v",
)


def test_internal_test_success(rule_runner: RuleRunner) -> None:
rule_runner.write_files(
Expand Down
9 changes: 5 additions & 4 deletions src/python/pants/backend/go/subsystems/gotest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ def register_options(cls, register):
member_type=shell_str,
passthrough=True,
help=(
'Arguments to pass directly to the Go test binary, e.g. `--go-test-args="-run TestFoo -v"` '
"Known Go test options will be transformed into the form expected by the test binary, "
"e.g. `-v` becomes `-test.v`. Run `go help testflag` from the Go SDK to learn more about "
"the options supported by Go test binaries."
"Arguments to pass directly to the Go test binary, e.g. "
'`--go-test-args="-run TestFoo -v"`.\n\n'
"Known Go test options will be transformed into the form expected by the test "
"binary, e.g. `-v` becomes `-test.v`. Run `go help testflag` from the Go SDK to "
"learn more about the options supported by Go test binaries."
),
)

Expand Down
12 changes: 12 additions & 0 deletions src/python/pants/backend/go/target_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
AsyncFieldMixin,
BoolField,
Dependencies,
IntField,
InvalidFieldException,
InvalidTargetException,
MultipleSourcesField,
StringField,
Target,
ValidNumbers,
)

# -----------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -127,12 +129,22 @@ class SkipGoTestsField(BoolField):
help = "If true, don't run this package's tests."


class GoTestTimeoutField(IntField):
alias = "test_timeout"
help = (
"A timeout (in seconds) when running this package's tests.\n\n"
"If this field is not set, the test will never time out."
)
valid_numbers = ValidNumbers.positive_and_zero


class GoPackageTarget(Target):
alias = "go_package"
core_fields = (
*COMMON_TARGET_FIELDS,
GoPackageDependenciesField,
GoPackageSourcesField,
GoTestTimeoutField,
SkipGoTestsField,
)
help = (
Expand Down

0 comments on commit 54f72e8

Please sign in to comment.