Skip to content

Commit d7c9189

Browse files
committed
Fix regression tests for TubStatistics field_aggregations requirement
- Add FIELD_AGGREGATIONS to test configs that use TubDataset with config - Add LAP_SORTING_CRITERIA to test configs that expect gyro_z_agg rankings - Add FULL_SORTING_STRATEGY constant to tests that need gyro_z_agg in rankings - Update tests to pass explicit sorting_strategy when testing gyro_z_agg These tests previously relied on silent defaults that have been removed. https://claude.ai/code/session_01BkSETqkmCyc5PavsvyAidf
1 parent 4581556 commit d7c9189

File tree

5 files changed

+103
-21
lines changed

5 files changed

+103
-21
lines changed

donkeycar/tests/test_course_segmentation_integration.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,19 @@ def _create_test_config(self):
5959
cfg = Config()
6060
cfg.USE_LAP_0 = False
6161
cfg.TRAIN_TEST_SPLIT = 0.8
62-
cfg.GYRO_Z_INDEX = 1
62+
cfg.FIELD_AGGREGATIONS = [
63+
{
64+
'field': 'car/gyro',
65+
'output_key': 'gyro_z_agg',
66+
'index': 1,
67+
'aggregation': 'avg'
68+
}
69+
]
70+
cfg.LAP_SORTING_CRITERIA = [
71+
{'key': 'time'},
72+
{'key': 'distance'},
73+
{'key': 'gyro_z_agg'},
74+
]
6375
return cfg
6476

6577
def _create_test_tub(self):

donkeycar/tests/test_lap_pct_regression.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from donkeycar.parts.tub_v2 import Tub
1919
from donkeycar.parts.tub_statistics import TubStatistics, FieldAggregationSpec
2020
from donkeycar.pipeline.types import TubDataset, PctMode
21+
from donkeycar.pipeline.transformations import SortingStrategy
2122

2223

2324
# Standard field aggregation for gyro_z at index 1 (simulator convention)
@@ -31,6 +32,13 @@
3132
)
3233
]
3334

35+
# Sorting strategy that includes time, distance, and gyro_z_agg
36+
FULL_SORTING_STRATEGY = SortingStrategy([
37+
{'key': 'time'},
38+
{'key': 'distance'},
39+
{'key': 'gyro_z_agg'},
40+
])
41+
3442

3543
class TestLapPerformanceRegression(unittest.TestCase):
3644
"""Regression tests for lap-based training"""
@@ -58,7 +66,14 @@ def _create_test_config(self):
5866
cfg = Config()
5967
cfg.USE_LAP_0 = False
6068
cfg.TRAIN_TEST_SPLIT = 0.8
61-
cfg.GYRO_Z_INDEX = 1
69+
cfg.FIELD_AGGREGATIONS = [
70+
{
71+
'field': 'car/gyro',
72+
'output_key': 'gyro_z_agg',
73+
'index': 1,
74+
'aggregation': 'avg'
75+
}
76+
]
6277
return cfg
6378

6479
def test_lap_mode_unchanged(self):
@@ -127,7 +142,8 @@ def test_lap_performance_calculation_unchanged(self):
127142

128143
tub = Tub(self.tub_path, read_only=True)
129144
self.open_tubs.append(tub)
130-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
145+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
146+
sorting_strategy=FULL_SORTING_STRATEGY)
131147

132148
# Calculate lap performance (original method)
133149
session_lap_rank = stats.calculate_lap_performance()

donkeycar/tests/test_pipeline.py

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
)
3232
]
3333

34+
# Sorting strategy that includes time, distance, and gyro_z_agg
35+
FULL_SORTING_STRATEGY = SortingStrategy([
36+
{'key': 'time'},
37+
{'key': 'distance'},
38+
{'key': 'gyro_z_agg'},
39+
])
40+
3441

3542
def random_records(size: int = 100) -> List[TubRecord]:
3643
return [random_record() for _ in range(size)]
@@ -241,7 +248,8 @@ def test_current_lap_pct_extension(self):
241248
tub = self._create_tub_with_data(records)
242249

243250
# Generate lap times
244-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
251+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
252+
sorting_strategy=FULL_SORTING_STRATEGY)
245253
stats.generate_laptimes_from_records()
246254

247255
# Close and reopen as read-only
@@ -251,7 +259,8 @@ def test_current_lap_pct_extension(self):
251259
tub = Tub(self.test_path, inputs, types, read_only=True)
252260

253261
# Calculate lap performance
254-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
262+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
263+
sorting_strategy=FULL_SORTING_STRATEGY)
255264
session_lap_rank = stats.calculate_lap_performance(use_lap_0=True)
256265

257266
# Test that records can be extended
@@ -275,17 +284,18 @@ def test_current_lap_pct_extension(self):
275284

276285
def test_current_sorting_criteria(self):
277286
"""
278-
Test current hardcoded sorting by 'time', 'distance', 'gyro_z_agg'.
287+
Test sorting by 'time', 'distance', 'gyro_z_agg' with explicit config.
279288
280289
Validates that:
281-
- Laps are sorted by these three criteria
290+
- Laps are sorted by these three criteria when configured
282291
- Sorting is done using itemgetter
283292
- Rankings are assigned correctly
284293
"""
285294
records = self._create_oval_track_data(num_laps=5, varying_performance=True)
286295
tub = self._create_tub_with_data(records)
287296

288-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
297+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
298+
sorting_strategy=FULL_SORTING_STRATEGY)
289299
stats.generate_laptimes_from_records()
290300

291301
# Close and reopen
@@ -294,7 +304,8 @@ def test_current_sorting_criteria(self):
294304
tub.close()
295305
tub = Tub(self.test_path, inputs, types, read_only=True)
296306

297-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
307+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
308+
sorting_strategy=FULL_SORTING_STRATEGY)
298309
performance = stats.calculate_lap_performance(use_lap_0=True)
299310

300311
session_id = list(performance.keys())[0]
@@ -366,10 +377,22 @@ def test_tub_dataset_with_lap_pct(self):
366377

367378
# Create TubDataset with lap_pct enabled
368379
config = Config()
369-
config.GYRO_Z_INDEX = 1
370380
config.USE_LAP_0 = True
371381
config.COMPRESS_SESSIONS_FOR_LAP_STATS = False
372382
config.NUM_BINS_FOR_LAP_STATS = None
383+
config.FIELD_AGGREGATIONS = [
384+
{
385+
'field': 'car/gyro',
386+
'output_key': 'gyro_z_agg',
387+
'index': 1,
388+
'aggregation': 'avg'
389+
}
390+
]
391+
config.LAP_SORTING_CRITERIA = [
392+
{'key': 'time'},
393+
{'key': 'distance'},
394+
{'key': 'gyro_z_agg'},
395+
]
373396

374397
dataset = TubDataset(config, [self.test_path], add_lap_pct=True)
375398
records_loaded = dataset.get_records()
@@ -449,12 +472,15 @@ class TestSortingStrategy(unittest.TestCase):
449472
"""Test suite for the new SortingStrategy classes."""
450473

451474
def test_default_sorting_strategy(self):
452-
"""Test default sorting strategy (time, distance, gyro_z_agg)."""
475+
"""Test default sorting strategy (time, distance only).
476+
477+
Note: gyro_z_agg was removed from defaults because it requires
478+
explicit field_aggregations configuration.
479+
"""
453480
strategy = default_lap_sorting_strategy()
454-
self.assertEqual(len(strategy.criteria), 3)
481+
self.assertEqual(len(strategy.criteria), 2)
455482
self.assertEqual(strategy.criteria[0]['key'], 'time')
456483
self.assertEqual(strategy.criteria[1]['key'], 'distance')
457-
self.assertEqual(strategy.criteria[2]['key'], 'gyro_z_agg')
458484

459485
def test_sorting_with_transformation(self):
460486
"""Test sorting with transformation using plain functions."""
@@ -671,10 +697,17 @@ def test_tub_dataset_with_custom_ranking_keys(self):
671697
tub_path = self._create_test_tub()
672698

673699
config = Config()
674-
config.GYRO_Z_INDEX = 1
675700
config.USE_LAP_0 = True
676701
config.COMPRESS_SESSIONS_FOR_LAP_STATS = False
677702
config.NUM_BINS_FOR_LAP_STATS = None
703+
config.FIELD_AGGREGATIONS = [
704+
{
705+
'field': 'car/gyro',
706+
'output_key': 'gyro_z_agg',
707+
'index': 1,
708+
'aggregation': 'avg'
709+
}
710+
]
678711

679712
# Use only time and distance for ranking
680713
custom_keys = ['time', 'distance']

donkeycar/tests/test_segment_performance.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from donkeycar.parts.tub_v2 import Tub
2020
from donkeycar.parts.tub_statistics import TubStatistics, FieldAggregationSpec
2121
from donkeycar.pipeline.types import TubRecord
22+
from donkeycar.pipeline.transformations import SortingStrategy
2223

2324

2425
# Standard field aggregation for gyro_z at index 1 (simulator convention)
@@ -32,6 +33,13 @@
3233
)
3334
]
3435

36+
# Sorting strategy that includes time, distance, and gyro_z_agg
37+
FULL_SORTING_STRATEGY = SortingStrategy([
38+
{'key': 'time'},
39+
{'key': 'distance'},
40+
{'key': 'gyro_z_agg'},
41+
])
42+
3543

3644
class TestSegmentPerformanceCalculation(unittest.TestCase):
3745
"""Test segment performance ranking across laps"""
@@ -160,7 +168,8 @@ def test_segment_performance_structure(self):
160168
"""Test that calculate_segment_performance returns correct structure"""
161169
tub = Tub(self.tub_path, read_only=True)
162170
self.open_tubs.append(tub)
163-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
171+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
172+
sorting_strategy=FULL_SORTING_STRATEGY)
164173

165174
session_rank = stats.calculate_segment_performance()
166175

@@ -198,7 +207,8 @@ def test_segment_ranking_across_laps(self):
198207
"""Test that same segment in different laps gets different rankings"""
199208
tub = Tub(self.tub_path, read_only=True)
200209
self.open_tubs.append(tub)
201-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
210+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
211+
sorting_strategy=FULL_SORTING_STRATEGY)
202212

203213
session_rank = stats.calculate_segment_performance()
204214
session_id = list(session_rank.keys())[0]
@@ -223,7 +233,8 @@ def test_segment_0_fastest_in_lap_1(self):
223233
"""Test that segment 0 is ranked fastest in lap 1"""
224234
tub = Tub(self.tub_path, read_only=True)
225235
self.open_tubs.append(tub)
226-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
236+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
237+
sorting_strategy=FULL_SORTING_STRATEGY)
227238

228239
session_rank = stats.calculate_segment_performance()
229240
session_id = list(session_rank.keys())[0]
@@ -245,7 +256,8 @@ def test_segment_1_fastest_in_lap_1(self):
245256
"""Test that segment 1 is ranked fastest in lap 1"""
246257
tub = Tub(self.tub_path, read_only=True)
247258
self.open_tubs.append(tub)
248-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
259+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
260+
sorting_strategy=FULL_SORTING_STRATEGY)
249261

250262
session_rank = stats.calculate_segment_performance()
251263
session_id = list(session_rank.keys())[0]
@@ -266,7 +278,8 @@ def test_ranking_percentiles(self):
266278
"""Test that rankings are proper percentiles (0.33, 0.67, 1.0)"""
267279
tub = Tub(self.tub_path, read_only=True)
268280
self.open_tubs.append(tub)
269-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
281+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
282+
sorting_strategy=FULL_SORTING_STRATEGY)
270283

271284
session_rank = stats.calculate_segment_performance()
272285
session_id = list(session_rank.keys())[0]
@@ -292,7 +305,8 @@ def test_synthetic_best_lap_creation(self):
292305
"""Test that we can create synthetic best lap from best segments"""
293306
tub = Tub(self.tub_path, read_only=True)
294307
self.open_tubs.append(tub)
295-
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1)
308+
stats = TubStatistics(tub, field_aggregations=GYRO_Z_INDEX_1,
309+
sorting_strategy=FULL_SORTING_STRATEGY)
296310

297311
session_rank = stats.calculate_segment_performance()
298312
session_id = list(session_rank.keys())[0]

donkeycar/tests/test_segment_training_integration.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,15 @@ def _create_test_config(self):
6060
cfg = Config()
6161
cfg.USE_LAP_0 = False
6262
cfg.TRAIN_TEST_SPLIT = 0.8
63-
cfg.GYRO_Z_INDEX = 1
6463
cfg.SEGMENT_PCT_MODE = True
64+
cfg.FIELD_AGGREGATIONS = [
65+
{
66+
'field': 'car/gyro',
67+
'output_key': 'gyro_z_agg',
68+
'index': 1,
69+
'aggregation': 'avg'
70+
}
71+
]
6572
return cfg
6673

6774
def test_end_to_end_segment_training_workflow(self):

0 commit comments

Comments
 (0)