File size: 3,269 Bytes
2129c29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""
NLProxy SDK test runner CLI.

This command runs the SDK test suite using pytest and supports class-level
and flow/marker-based filtering so tests can be executed in a scalable,
reproducible way.

Examples:
  python -m nlproxy tests
  python -m nlproxy tests --class TestPromptShield
  python -m nlproxy tests --flow unit
  python -m nlproxy tests --flow integration --pytest-args="-v --maxfail=1"

The runner defaults to `tests.py` in the project root and delegates to the
Python interpreter environment that executes the CLI.
"""

from __future__ import annotations

import argparse
import shlex
import subprocess
import sys
from typing import List, Optional


def create_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="nlproxy tests",
        description="Run NLProxy SDK tests with optional class or flow filtering.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python -m nlproxy tests
  python -m nlproxy tests --class TestPromptShield
  python -m nlproxy tests --flow unit
  python -m nlproxy tests --flow integration --pytest-args='-v --maxfail=1'
        """,
    )

    parser.add_argument(
        "-c",
        "--class",
        dest="test_class",
        help="Run only a single test class or filter expression from tests.py",
    )
    parser.add_argument(
        "-f",
        "--flow",
        dest="flow",
        help="Run tests by pytest marker/flow name (e.g. unit, integration, performance, asyncio)",
    )
    parser.add_argument(
        "--path",
        type=str,
        default="tests.py",
        help="Path to the test module or directory to execute",
    )
    parser.add_argument(
        "--pytest-args",
        type=str,
        default="",
        help="Additional pytest arguments to pass through",
    )
    parser.add_argument(
        "-q",
        "--quiet",
        action="store_true",
        help="Suppress output from the test runner when possible",
    )

    return parser


def build_pytest_args(args: argparse.Namespace) -> List[str]:
    pytest_args: List[str] = [sys.executable, "-m", "pytest", args.path]

    if args.test_class:
        pytest_args.extend(["-k", args.test_class])

    if args.flow:
        pytest_args.extend(["-m", args.flow])

    if args.pytest_args:
        pytest_args.extend(shlex.split(args.pytest_args))

    if args.quiet:
        pytest_args.append("-q")

    return pytest_args


def cmd_tests(args: argparse.Namespace) -> int:
    pytest_args = build_pytest_args(args)
    print(f"Running tests: {' '.join(pytest_args)}")

    result = subprocess.run(pytest_args, env=sys.environ.copy())
    return result.returncode


def main(argv: Optional[List[str]] = None) -> int:
    parser = create_parser()
    args = parser.parse_args(argv)
    try:
        return cmd_tests(args)
    except KeyboardInterrupt:
        print("Test execution interrupted by user.", file=sys.stderr)
        return 130
    except FileNotFoundError as exc:
        print(f"Test runner failed: {exc}", file=sys.stderr)
        return 1
    except Exception as exc:
        print(f"Unexpected error while running tests: {exc}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    raise SystemExit(main())