Keep K3 suite selection and report-schema scoring in bash, merge K3/vision dataset_args into dpv4 yamls, and pin EvalScope at 735d920ee911 with local patches. Co-authored-by: Cursor <cursoragent@cursor.com>
139 lines
5.9 KiB
Python
139 lines
5.9 KiB
Python
"""Tests for the unified ``--dataset-args`` framework.
|
|
|
|
Covers:
|
|
- Per-dataset ``args_schema`` selection via the dataset registry.
|
|
- ``extra='forbid'`` fail-fast rejection of unknown keys (at the plugin/schema
|
|
layer, which owns the schema).
|
|
- Backward-compatible folding of the deprecated ``--multi-turn-args`` into
|
|
the raw ``--dataset-args`` dict on ``Arguments`` (config layer, no plugin dep).
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from evalscope.perf.arguments import Arguments
|
|
from evalscope.perf.multi_turn_args import MultiTurnArgs
|
|
from evalscope.perf.plugin.datasets.dataset_args import BaseDatasetArgs, MultiTurnDatasetArgs, TextDatasetArgs
|
|
from evalscope.perf.plugin.datasets.openqa import OpenqaDatasetPlugin
|
|
from evalscope.perf.plugin.registry import DatasetRegistry
|
|
|
|
|
|
def _args(**kwargs) -> Arguments:
|
|
return Arguments(model='test-model', url='http://localhost:8080/v1/chat/completions', **kwargs)
|
|
|
|
|
|
def _resolve(args: Arguments):
|
|
"""Resolve raw ``dataset_args`` against the selected plugin's schema.
|
|
|
|
Mirrors the plugin-layer resolution (``self.args_schema(**raw)``) so tests
|
|
can validate the mapping without constructing a full plugin.
|
|
"""
|
|
schema = DatasetRegistry.get_class(args.dataset).args_schema
|
|
return schema(**(args.dataset_args or {}))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Schema selection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSchemaSelection:
|
|
|
|
def test_text_datasets_use_text_schema(self):
|
|
for name in ('openqa', 'longalpaca', 'line_by_line', 'share_gpt_zh', 'share_gpt_en'):
|
|
assert DatasetRegistry.get_class(name).args_schema is TextDatasetArgs
|
|
|
|
def test_multi_turn_datasets_use_multi_turn_schema(self):
|
|
for name in ('swe_smith', 'random_multi_turn', 'share_gpt_zh_multi_turn', 'share_gpt_en_multi_turn'):
|
|
assert DatasetRegistry.get_class(name).args_schema is MultiTurnDatasetArgs
|
|
|
|
def test_default_schema_is_base(self):
|
|
assert DatasetRegistry.get_class('random').args_schema is BaseDatasetArgs
|
|
|
|
def test_multi_turn_schema_subclasses_multi_turn_args(self):
|
|
assert issubclass(MultiTurnDatasetArgs, MultiTurnArgs)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Schema resolution + fail-fast validation (plugin/schema layer)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestResolveDatasetArgs:
|
|
|
|
def test_none_resolves_to_empty_schema(self):
|
|
resolved = _resolve(_args(dataset='openqa'))
|
|
assert isinstance(resolved, TextDatasetArgs)
|
|
assert resolved.target_input_len is None
|
|
assert resolved.input_len_mode == 'cap'
|
|
|
|
def test_valid_keys_parsed(self):
|
|
args = _args(dataset='openqa', dataset_args={'target_input_len': 256, 'input_len_mode': 'drop'})
|
|
resolved = _resolve(args)
|
|
assert resolved.target_input_len == 256
|
|
assert resolved.input_len_mode == 'drop'
|
|
|
|
def test_unknown_key_fails_fast(self):
|
|
with pytest.raises(Exception):
|
|
_resolve(_args(dataset='openqa', dataset_args={'not_a_real_key': 1}))
|
|
|
|
def test_json_string_is_parsed(self):
|
|
args = _args(dataset='openqa', dataset_args='{"target_input_len": 64}')
|
|
assert _resolve(args).target_input_len == 64
|
|
|
|
def test_invalid_input_len_mode_rejected(self):
|
|
with pytest.raises(Exception):
|
|
_resolve(_args(dataset='openqa', dataset_args={'target_input_len': 8, 'input_len_mode': 'nope'}))
|
|
|
|
def test_non_positive_target_input_len_rejected(self):
|
|
with pytest.raises(Exception):
|
|
_resolve(_args(dataset='openqa', dataset_args={'target_input_len': 0}))
|
|
|
|
def test_target_input_len_requires_tokenizer(self):
|
|
# The tokenizer requirement is enforced at plugin construction (base layer).
|
|
args = _args(dataset='openqa', dataset_args={'target_input_len': 128})
|
|
with pytest.raises(ValueError, match='requires a tokenizer'):
|
|
OpenqaDatasetPlugin(args)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Backward-compat: --multi-turn-args folding (config layer, raw dict only)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestMultiTurnArgsFolding:
|
|
|
|
def test_folds_into_dataset_args(self):
|
|
args = _args(dataset='swe_smith', multi_turn_args='{"first_turn_length": 100}')
|
|
assert args.dataset_args['first_turn_length'] == 100
|
|
assert _resolve(args).first_turn_length == 100
|
|
|
|
def test_only_user_set_keys_are_folded(self):
|
|
args = _args(dataset='swe_smith', multi_turn_args='{"first_turn_length": 100}')
|
|
# subsequent_turn_length was not set by the user -> not injected
|
|
assert 'subsequent_turn_length' not in args.dataset_args
|
|
|
|
def test_dataset_args_wins_on_conflict(self):
|
|
args = _args(
|
|
dataset='swe_smith',
|
|
dataset_args={'first_turn_length': 999},
|
|
multi_turn_args='{"first_turn_length": 100}',
|
|
)
|
|
assert _resolve(args).first_turn_length == 999
|
|
|
|
def test_num_workers_promoted_to_top_level(self):
|
|
args = _args(dataset='swe_smith', multi_turn_args='{"num_workers": 3}')
|
|
assert args.num_workers == 3
|
|
|
|
def test_num_workers_in_dataset_args_promoted_and_popped(self):
|
|
# num_workers passed directly in --dataset-args must be promoted to top-level
|
|
# and removed, so non-multi-turn schemas (extra='forbid') do not reject it.
|
|
args = _args(dataset='openqa', dataset_args='{"num_workers": 4, "target_input_len": 100}')
|
|
assert args.num_workers == 4
|
|
assert 'num_workers' not in args.dataset_args
|
|
# remaining keys still validate against the dataset schema
|
|
assert _resolve(args).target_input_len == 100
|
|
|
|
def test_no_multi_turn_args_leaves_dataset_args_none(self):
|
|
args = _args(dataset='swe_smith')
|
|
assert args.dataset_args is None
|