Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
17ea834
Squash merge avah/rename_to_gameplay_tests into avah/combine_simulate…
nycrat Jun 14, 2026
fd08dcd
Move pytest_main definition to util.py file
nycrat Jun 14, 2026
0d473c5
Rename simulated_test_fixture to just fixture
nycrat Jun 14, 2026
0421022
Separate simulated test runner into separate file, remove aggregate t…
nycrat Jun 15, 2026
c352218
Move field_test_fixture to fixture, and separate out field_test_runner
nycrat Jun 15, 2026
33a39dd
Fix field test imports
nycrat Jun 15, 2026
85b71bf
Fix interface of tbots test runner and field test runner
nycrat Jun 15, 2026
bfa7db4
Use get_runtime_dir actually
nycrat Jun 16, 2026
a49d254
Update tests with new interface of test runners
nycrat Jun 16, 2026
cc9c782
Fix offense play test
nycrat Jun 16, 2026
ad36c0e
Merge branch 'master' into avah/combine_simulated_and_field_tests
nycrat Jun 16, 2026
7090e6f
Delete unused sim test fixture
nycrat Jun 17, 2026
69428d8
Unify test fixture as gameplay_test_runner
nycrat Jun 17, 2026
6c3c3f1
Pull out helper function
nycrat Jun 17, 2026
f9f32d7
Minor fix and doc comment updates
nycrat Jun 17, 2026
73562f3
Move enable_thunderscope to sim only args
nycrat Jun 17, 2026
8e8856a
Fix capitalization
nycrat Jun 17, 2026
fa901ea
Merge branch 'master' into avah/combine_simulated_and_field_tests
nycrat Jun 17, 2026
46021c3
Port field test runner updates from #3783
nycrat Jun 17, 2026
71553d9
Clean up field and simulated test runner classes
nycrat Jun 17, 2026
3edd9ed
Rewrite field test in sim test style
nycrat Jun 17, 2026
f98a792
Remove unused imports
nycrat Jun 17, 2026
c1fe6c1
WIP: WORKING ON FIELD TEST STUFF KINDA WORKS RN
Thunderbots Jun 17, 2026
61576ef
Get rid of run_till_end and tick_duration_s arguments
nycrat Jun 17, 2026
168aad3
Fix test params
nycrat Jun 18, 2026
d32d3a1
Combine some common code from field and sim test runners
nycrat Jun 18, 2026
33dca21
Reimplement run till end but better
nycrat Jun 18, 2026
3406178
Small refactors
nycrat Jun 18, 2026
a2f379a
Refactor out common code in run_test
nycrat Jun 18, 2026
70df4a1
Minor moving around code
nycrat Jun 18, 2026
45e9547
Tag TODO for delay and duration validations
nycrat Jun 18, 2026
1f737c9
Fix up the 3 field tests
nycrat Jun 18, 2026
2ee7d38
Make setup mandatory and fix misuse of test runner
nycrat Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/software/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ py_library(
name = "conftest",
srcs = ["conftest.py"],
deps = [
"//software/gameplay_tests:field_test_fixture",
"//software/gameplay_tests:simulated_test_fixture",
"//software/gameplay_tests:fixture",
"//software/gameplay_tests:util",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
from software.gameplay_tests.validation.robot_enters_region import (
RobotEventuallyExitsRegion,
)
from software.gameplay_tests.simulated_test_fixture import (
pytest_main,
)
from software.gameplay_tests.util import pytest_main


@pytest.mark.parametrize(
Expand All @@ -33,10 +31,10 @@
],
)
def test_two_ai_ball_placement(
simulated_test_runner, ball_start_point, ball_placement_point
gameplay_test_runner, ball_start_point, ball_placement_point
):
run_ball_placement_scenario(
simulated_test_runner, ball_start_point, ball_placement_point
gameplay_test_runner, ball_start_point, ball_placement_point
)


Expand Down Expand Up @@ -64,21 +62,21 @@ def test_two_ai_ball_placement(
],
)
def test_robocup_technical_challenge_placement(
simulated_test_runner, ball_start_point, ball_placement_point
gameplay_test_runner, ball_start_point, ball_placement_point
):
run_ball_placement_scenario(
simulated_test_runner, ball_start_point, ball_placement_point, blue_only=True
gameplay_test_runner, ball_start_point, ball_placement_point, blue_only=True
)


def ball_placement_play_setup(
ball_start_point, ball_placement_point, simulated_test_runner, blue_only
ball_start_point, ball_placement_point, gameplay_test_runner, blue_only
):
"""Set up ball placement test by initializing bot positions, ball placement targets, and test settings

:param ball_start_point: Initial point of the ball
:param ball_placement_point: Target point of the ball
:param simulated_test_runner: Simulated test runner
:param gameplay_test_runner: Simulated test runner
:param blue_only: If True, only the blue team is active; the yellow team is ignored.
"""
# Setup blue robots
Expand Down Expand Up @@ -113,7 +111,7 @@ def ball_placement_play_setup(
]

# Create world state
simulated_test_runner.set_world_state(
gameplay_test_runner.set_world_state(
create_world_state(
yellow_robot_locations=yellow_bots,
blue_robot_locations=blue_bots,
Expand All @@ -123,28 +121,28 @@ def ball_placement_play_setup(
)

# Game Controller Setup
simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.STOP, team=Team.UNKNOWN
)
# Pass in placement point here - not required for all play tests
simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.BALL_PLACEMENT,
team=Team.BLUE,
final_ball_placement_point=ball_placement_point,
)

# Force play override here
simulated_test_runner.set_plays(
gameplay_test_runner.set_plays(
blue_play=PlayName.BallPlacementPlay, yellow_play=PlayName.HaltPlay
)


def run_ball_placement_scenario(
simulated_test_runner, ball_start_point, ball_placement_point, blue_only=False
gameplay_test_runner, ball_start_point, ball_placement_point, blue_only=False
):
"""Runs a ball placement test scenario with the specified parameters.

:param simulated_test_runner: The test runner used to simulate robot and ball behavior.
:param gameplay_test_runner: The test runner used to simulate robot and ball behavior.
:param ball_start_point: The initial position of the ball.
:param ball_placement_point: The target position where the ball should be placed.
:param blue_only: If True, only the blue team is active; the yellow team is ignored.
Expand All @@ -156,23 +154,9 @@ def run_ball_placement_scenario(
BallEventuallyEntersRegion(
regions=[tbots_cpp.Circle(ball_placement_point, 0.15)]
),
]
]

# Drop Ball Always Validation
drop_ball_always_validation_sequence_set = [
[
BallAlwaysStaysInRegion(
regions=[tbots_cpp.Circle(ball_placement_point, 0.15)]
),
]
]

# Drop Ball Eventually Validation
# Non free kick after ball placement, the robot must be 0.5 away from the ball after the placement
# See detailed rules here: https://robocup-ssl.github.io/ssl-rules/sslrules.html#_ball_placement
drop_ball_eventually_validation_sequence_set = [
[
# Drop Ball Eventually Validation
# Non free kick after ball placement, the robot must be 0.5 away from the ball after the placement
# See detailed rules here: https://robocup-ssl.github.io/ssl-rules/sslrules.html#_ball_placement
RobotEventuallyExitsRegion(
regions=[
tbots_cpp.Circle(
Expand All @@ -183,33 +167,25 @@ def run_ball_placement_scenario(
]
]

simulated_test_runner.run_test(
setup=lambda test_setup_arg: ball_placement_play_setup(
test_setup_arg["ball_start_point"],
test_setup_arg["ball_placement_point"],
simulated_test_runner,
# Make sure ball never moves after robot moves away
# TODO (#3503): Enable this with an OrValidation checking robot is moving back
# drop_ball_always_validation_sequence_set = [
# [
# BallAlwaysStaysInRegion(
# regions=[tbots_cpp.Circle(ball_placement_point, 0.15)]
# ),
# ]
# ]

gameplay_test_runner.run_test(
setup=lambda: ball_placement_play_setup(
ball_start_point,
ball_placement_point,
gameplay_test_runner,
blue_only,
),
params=[
{
"ball_start_point": ball_start_point,
"ball_placement_point": ball_placement_point,
}
],
inv_always_validation_sequence_set=[[]],
inv_eventually_validation_sequence_set=placement_eventually_validation_sequence_set,
ag_always_validation_sequence_set=[[]],
ag_eventually_validation_sequence_set=placement_eventually_validation_sequence_set,
test_timeout_s=[30],
)

simulated_test_runner.run_test(
# setup argument isn't passed to preserve world state from previous test run
inv_always_validation_sequence_set=drop_ball_always_validation_sequence_set,
inv_eventually_validation_sequence_set=drop_ball_eventually_validation_sequence_set,
ag_always_validation_sequence_set=drop_ball_always_validation_sequence_set,
ag_eventually_validation_sequence_set=drop_ball_eventually_validation_sequence_set,
test_timeout_s=[10],
eventually_validation_sequence_set=placement_eventually_validation_sequence_set,
test_timeout_s=30,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
from proto.import_all_protos import *
from proto.message_translation.tbots_protobuf import create_world_state
from proto.ssl_gc_common_pb2 import Team
from software.gameplay_tests.simulated_test_fixture import (
pytest_main,
)
from software.gameplay_tests.util import pytest_main
from software.gameplay_tests.validation.robot_speed_threshold import (
RobotSpeedEventuallyBelowThreshold,
)
Expand All @@ -15,12 +13,12 @@
from software.gameplay_tests.validation.delay_validation import DelayValidation


def test_crease_defense_play(simulated_test_runner):
def test_crease_defense_play(gameplay_test_runner):
field = tbots_cpp.Field.createSSLDivisionBField()
goalie_position = tbots_cpp.Point(-4.5, 0)

def setup(*args):
simulated_test_runner.set_world_state(
def setup():
gameplay_test_runner.set_world_state(
create_world_state(
blue_robot_locations=[
goalie_position,
Expand All @@ -43,11 +41,11 @@ def setup(*args):
),
)

simulated_test_runner.set_plays(
gameplay_test_runner.set_plays(
blue_play=PlayName.CreaseDefensePlay, yellow_play=PlayName.HaltPlay
)

simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.STOP, team=Team.UNKNOWN
)

Expand All @@ -70,10 +68,9 @@ def setup(*args):
]
]

simulated_test_runner.run_test(
gameplay_test_runner.run_test(
setup=setup,
inv_eventually_validation_sequence_set=eventually_validations,
ag_eventually_validation_sequence_set=eventually_validations,
eventually_validation_sequence_set=eventually_validations,
test_timeout_s=10,
)

Expand Down
46 changes: 19 additions & 27 deletions src/software/ai/hl/stp/play/defense/defense_play_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
)
from proto.message_translation.tbots_protobuf import create_world_state
from proto.ssl_gc_common_pb2 import Team
from software.gameplay_tests.simulated_test_fixture import (
pytest_main,
)
from software.gameplay_tests.util import pytest_main


@pytest.mark.parametrize(
Expand All @@ -35,11 +33,11 @@
)
],
)
def test_defense_play_ball_steal(simulated_test_runner, blue_bots, yellow_bots):
def setup(*args):
def test_defense_play_ball_steal(gameplay_test_runner, blue_bots, yellow_bots):
def setup():
ball_initial_pos = tbots_cpp.Point(0.93, 0)

simulated_test_runner.set_world_state(
gameplay_test_runner.set_world_state(
create_world_state(
yellow_robot_locations=yellow_bots,
blue_robot_locations=blue_bots,
Expand All @@ -48,32 +46,29 @@ def setup(*args):
),
)

simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.STOP, team=Team.UNKNOWN
)
simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.FORCE_START, team=Team.BLUE
)

simulated_test_runner.set_plays(
gameplay_test_runner.set_plays(
blue_play=PlayName.DefensePlay, yellow_play=PlayName.HaltPlay
)

simulated_test_runner.run_test(
gameplay_test_runner.run_test(
setup=setup,
params=[0, 1, 2, 3, 4], # The aggregate test runs 5 times
inv_always_validation_sequence_set=[
always_validation_sequence_set=[
[
BallNeverEntersRegion(
regions=[tbots_cpp.Field.createSSLDivisionBField().friendlyGoal()]
)
]
],
inv_eventually_validation_sequence_set=[
eventually_validation_sequence_set=[
[FriendlyEventuallyHasBallPossession(tolerance=0.2)]
],
ag_always_validation_sequence_set=[[]],
ag_eventually_validation_sequence_set=[[]],
test_timeout_s=20,
)

Expand All @@ -100,11 +95,11 @@ def setup(*args):
)
],
)
def test_defense_play(simulated_test_runner, blue_bots, yellow_bots):
def setup(*args):
def test_defense_play(gameplay_test_runner, blue_bots, yellow_bots):
def setup():
ball_initial_pos = tbots_cpp.Point(0.9, 2.85)

simulated_test_runner.set_world_state(
gameplay_test_runner.set_world_state(
create_world_state(
yellow_robot_locations=yellow_bots,
blue_robot_locations=blue_bots,
Expand All @@ -113,32 +108,29 @@ def setup(*args):
),
)

simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.STOP, team=Team.UNKNOWN
)
simulated_test_runner.send_gamecontroller_command(
gameplay_test_runner.send_gamecontroller_command(
gc_command=Command.Type.FORCE_START, team=Team.BLUE
)

simulated_test_runner.set_plays(
gameplay_test_runner.set_plays(
blue_play=PlayName.DefensePlay, yellow_play=PlayName.ShootOrPassPlay
)

simulated_test_runner.run_test(
gameplay_test_runner.run_test(
setup=setup,
params=[0, 1, 2, 3, 4], # The aggregate test runs 5 times
inv_always_validation_sequence_set=[
always_validation_sequence_set=[
[
BallNeverEntersRegion(
regions=[tbots_cpp.Field.createSSLDivisionBField().friendlyGoal()]
)
]
],
inv_eventually_validation_sequence_set=[
eventually_validation_sequence_set=[
[FriendlyEventuallyHasBallPossession(tolerance=0.1)]
],
ag_always_validation_sequence_set=[[]],
ag_eventually_validation_sequence_set=[[]],
test_timeout_s=30,
)

Expand Down
Loading
Loading