diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 4440ce71d786..48662d565e4e 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -394,7 +394,9 @@ jobs: timeout-minutes: 10 run: | cd test/ - python3 run_suite.py + python3 run_suite.py --hw cuda --suite stage-a-test-1 + # temporarily put backend-independent cpu tests here + python3 run_suite.py --hw cpu --suite default unit-test-backend-1-gpu: needs: [check-changes, stage-a-test-1, sgl-kernel-build-wheels] diff --git a/python/sglang/test/ci/ci_register.py b/python/sglang/test/ci/ci_register.py index 6beea6a5e110..a272bdd4794d 100644 --- a/python/sglang/test/ci/ci_register.py +++ b/python/sglang/test/ci/ci_register.py @@ -6,6 +6,7 @@ class HWBackend(Enum): + CPU = auto() CUDA = auto() AMD = auto() @@ -14,19 +15,24 @@ class HWBackend(Enum): class CIRegistry: backend: HWBackend filename: str - estimation_time: float - stage: str + est_time: float + suite: str -def register_cuda_ci(estimation_time: float, ci_stage: str): +def register_cpu_ci(est_time: float, suite: str): pass -def register_amd_ci(estimation_time: float, ci_stage: str): +def register_cuda_ci(est_time: float, suite: str): + pass + + +def register_amd_ci(est_time: float, suite: str): pass REGISTER_MAPPING = { + "register_cpu_ci": HWBackend.CPU, "register_cuda_ci": HWBackend.CUDA, "register_amd_ci": HWBackend.AMD, } @@ -45,28 +51,27 @@ def _collect_ci_registry(self, func_call: ast.Call): return None hw = REGISTER_MAPPING[func_call.func.id] - est_time = None - ci_stage = None + est_time, suite = None, None for kw in func_call.keywords: - if kw.arg == "estimation_time": + if kw.arg == "est_time": if isinstance(kw.value, ast.Constant): est_time = kw.value.value - elif kw.arg == "ci_stage": + elif kw.arg == "suite": if isinstance(kw.value, ast.Constant): - ci_stage = kw.value.value + suite = kw.value.value for i, arg in enumerate(func_call.args): if isinstance(arg, ast.Constant): if i == 0: est_time = arg.value elif i == 1: - ci_stage = arg.value + suite = arg.value assert ( est_time is not None ), "esimation_time is required and should be a constant" - assert ci_stage is not None, "ci_stage is required and should be a constant" + assert suite is not None, "suite is required and should be a constant" return CIRegistry( - backend=hw, filename=self.filename, estimation_time=est_time, stage=ci_stage + backend=hw, filename=self.filename, est_time=est_time, suite=suite ) def visit_Module(self, node): diff --git a/test/srt/test_function_call_parser.py b/test/per_commit/function_call/test_function_call_parser.py similarity index 99% rename from test/srt/test_function_call_parser.py rename to test/per_commit/function_call/test_function_call_parser.py index 12f26982ae1d..c8aeba746a1a 100644 --- a/test/srt/test_function_call_parser.py +++ b/test/per_commit/function_call/test_function_call_parser.py @@ -12,6 +12,9 @@ from sglang.srt.function_call.mistral_detector import MistralDetector from sglang.srt.function_call.pythonic_detector import PythonicDetector from sglang.srt.function_call.qwen3_coder_detector import Qwen3CoderDetector +from sglang.test.ci.ci_register import register_cpu_ci + +register_cpu_ci(1.0, "default") class TestPythonicDetector(unittest.TestCase): diff --git a/test/srt/function_call/test_json_schema_constraint.py b/test/per_commit/function_call/test_json_schema_constraint.py similarity index 99% rename from test/srt/function_call/test_json_schema_constraint.py rename to test/per_commit/function_call/test_json_schema_constraint.py index b1e6195e7bae..6a7131cacd8c 100644 --- a/test/srt/function_call/test_json_schema_constraint.py +++ b/test/per_commit/function_call/test_json_schema_constraint.py @@ -16,6 +16,9 @@ _get_tool_schema_defs, get_json_schema_constraint, ) +from sglang.test.ci.ci_register import register_cpu_ci + +register_cpu_ci(1.0, "default") class TestJsonSchemaConstraint(unittest.TestCase): diff --git a/test/srt/function_call/test_unknown_tool_name.py b/test/per_commit/function_call/test_unknown_tool_name.py similarity index 92% rename from test/srt/function_call/test_unknown_tool_name.py rename to test/per_commit/function_call/test_unknown_tool_name.py index 94860104b0d9..e8baf55b05c6 100644 --- a/test/srt/function_call/test_unknown_tool_name.py +++ b/test/per_commit/function_call/test_unknown_tool_name.py @@ -1,10 +1,15 @@ import json import logging +import pytest + from sglang.srt.entrypoints.openai.protocol import Function, Tool from sglang.srt.environ import envs from sglang.srt.function_call.base_format_detector import BaseFormatDetector from sglang.srt.function_call.core_types import StreamingParseResult +from sglang.test.ci.ci_register import register_cpu_ci + +register_cpu_ci(1.0, "default") class DummyDetector(BaseFormatDetector): @@ -17,6 +22,9 @@ def detect_and_parse(self, text: str, tools): normal_text="", calls=self.parse_base_json(action, tools) ) + def structure_info(self): + pass + def test_unknown_tool_name_dropped_default(caplog): """Test that unknown tools are dropped by default (legacy behavior).""" @@ -67,3 +75,7 @@ def test_unknown_tool_name_forwarded(caplog): assert result.calls[0].name == "unknown_tool" assert result.calls[0].tool_index == -1 assert json.loads(result.calls[0].parameters)["city"] == "Paris" + + +if __name__ == "__main__": + pytest.main([__file__]) diff --git a/test/per_commit/test_srt_backend.py b/test/per_commit/test_srt_backend.py index e7f75fa6caa2..5b44eac60fc9 100644 --- a/test/per_commit/test_srt_backend.py +++ b/test/per_commit/test_srt_backend.py @@ -19,7 +19,7 @@ ) from sglang.test.test_utils import DEFAULT_MODEL_NAME_FOR_TEST, CustomTestCase -register_cuda_ci(estimation_time=80, ci_stage="stage-a-test-1") +register_cuda_ci(est_time=80, suite="stage-a-test-1") class TestSRTBackend(CustomTestCase): diff --git a/test/run_suite.py b/test/run_suite.py index 356c207952c7..000fee970a26 100644 --- a/test/run_suite.py +++ b/test/run_suite.py @@ -1,10 +1,19 @@ +import argparse import glob from typing import List from sglang.test.ci.ci_register import CIRegistry, HWBackend, collect_tests from sglang.test.ci.ci_utils import TestFile, run_unittest_files -LABEL_MAPPING = {HWBackend.CUDA: ["stage-a-test-1"]} +HW_MAPPING = { + "cpu": HWBackend.CPU, + "cuda": HWBackend.CUDA, +} + +LABEL_MAPPING = { + HWBackend.CUDA: ["stage-a-test-1"], + HWBackend.CPU: ["default"], +} def _filter_tests( @@ -13,8 +22,8 @@ def _filter_tests( ci_tests = [t for t in ci_tests if t.backend == hw] ret = [] for t in ci_tests: - assert t.stage in LABEL_MAPPING[hw], f"Unknown stage {t.stage} for backend {hw}" - if t.stage == suite: + assert t.suite in LABEL_MAPPING[hw], f"Unknown stage {t.suite} for backend {hw}" + if t.suite == suite: ret.append(t) return ret @@ -22,7 +31,7 @@ def _filter_tests( def run_per_commit(hw: HWBackend, suite: str): files = glob.glob("per_commit/**/*.py", recursive=True) ci_tests = _filter_tests(collect_tests(files), hw, suite) - test_files = [TestFile(t.filename, t.estimation_time) for t in ci_tests] + test_files = [TestFile(t.filename, t.est_time) for t in ci_tests] run_unittest_files( test_files, @@ -32,7 +41,23 @@ def run_per_commit(hw: HWBackend, suite: str): def main(): - run_per_commit(HWBackend.CUDA, "stage-a-test-1") + parser = argparse.ArgumentParser() + parser.add_argument( + "--hw", + type=str, + choices=["cpu", "cuda"], + required=True, + help="Hardware backend to run tests on.", + ) + parser.add_argument( + "--suite", + type=str, + required=True, + help="Test suite to run.", + ) + args = parser.parse_args() + hw = HW_MAPPING[args.hw] + run_per_commit(hw, args.suite) if __name__ == "__main__": diff --git a/test/srt/run_suite.py b/test/srt/run_suite.py index 664dba7828c7..2c09b5d3d1a3 100644 --- a/test/srt/run_suite.py +++ b/test/srt/run_suite.py @@ -8,7 +8,6 @@ suites = { "per-commit-1-gpu": [ TestFile("debug_utils/test_tensor_dump_forward_hook.py", 15), - TestFile("function_call/test_json_schema_constraint.py", 1), TestFile("hicache/test_hicache_storage.py", 127), TestFile("hicache/test_hicache_variants.py", 393), TestFile("layers/attention/mamba/test_causal_conv1d.py", 25), @@ -70,7 +69,6 @@ TestFile("test_flashmla.py", 230), TestFile("test_fp8_utils.py", 5), TestFile("rotary_embedding/test_mrope.py", 10), - TestFile("test_function_call_parser.py", 10), TestFile("test_fused_moe.py", 80), TestFile("test_gpt_oss_1gpu.py", 750), TestFile("test_harmony_parser.py", 20), @@ -239,7 +237,6 @@ TestFile("ep/test_hybrid_dp_ep_tp_mtp.py"), TestFile("ep/test_moe_deepep.py"), TestFile("ep/test_moe_deepep_eval_accuracy_large.py"), - TestFile("function_call/test_unknown_tool_name.py"), TestFile("hicache/test_disaggregation_hicache.py"), TestFile("hicache/test_hicache_storage_benchmark.py"), TestFile("hicache/test_hicache_storage_e2e.py"), @@ -381,7 +378,6 @@ # NOTE: please sort the test cases alphabetically by the test file name suite_amd = { "per-commit-amd": [ - TestFile("function_call/test_json_schema_constraint.py", 1), # TestFile("hicache/test_hicache.py", 116), # Disabled temporarily, see https://github.com/sgl-project/sglang/issues/12575 # TestFile("hicache/test_hicache_mla.py", 127), # Disabled temporarily, # Temporarily disabled, see https://github.com/sgl-project/sglang/issues/12574 # TestFile("hicache/test_hicache_storage.py", 127), # Disabled temporarily, see https://github.com/sgl-project/sglang/issues/12575 @@ -421,7 +417,6 @@ TestFile("test_chunked_prefill.py", 410), TestFile("test_create_kvindices.py", 2), TestFile("test_eval_fp8_accuracy.py", 303), - TestFile("test_function_call_parser.py", 10), TestFile("test_fused_moe.py", 30), TestFile("test_harmony_parser.py", 20), TestFile("test_input_embeddings.py", 38),