初始提交
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
import subprocess
|
||||
from collections.abc import Callable
|
||||
|
||||
from cli.exit_codes import DEPENDENCY_ERROR, SUCCESS
|
||||
|
||||
|
||||
def test_app_config_json_output_is_pure_json(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
) -> None:
|
||||
completed = run_cli_command('app', 'config', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode == 0
|
||||
assert completed.stderr == ''
|
||||
assert payload['ok'] is True
|
||||
assert payload['env'] == 'dev'
|
||||
assert isinstance(payload['config'], dict)
|
||||
assert '\u001b[' not in completed.stdout
|
||||
assert '✅' not in completed.stdout
|
||||
assert '❌' not in completed.stdout
|
||||
|
||||
|
||||
def test_app_config_text_output_has_stable_section_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('app', 'config', '--env=dev', '--output=text')
|
||||
|
||||
assert completed.returncode == SUCCESS
|
||||
assert '\x1b[' not in completed.stdout
|
||||
assert '✅' not in completed.stdout
|
||||
assert completed.stdout.startswith('OK SUCCESS\n')
|
||||
assert 'env: dev\n' in completed.stdout
|
||||
assert 'application:\n' in completed.stdout
|
||||
assert 'database:\n' in completed.stdout
|
||||
assert 'redis:\n' in completed.stdout
|
||||
assert 'logging:\n' in completed.stdout
|
||||
assert 'transport_crypto:\n' in completed.stdout
|
||||
|
||||
|
||||
def test_app_env_text_output_has_stable_section_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('app', 'env', '--env=dev', '--output=text')
|
||||
|
||||
assert completed.returncode == SUCCESS
|
||||
assert completed.stdout.startswith('OK SUCCESS\n')
|
||||
assert 'env: dev\n' in completed.stdout
|
||||
assert 'runtime:\n' in completed.stdout
|
||||
assert 'cli_env: dev\n' in completed.stdout
|
||||
assert 'config_env:' in completed.stdout
|
||||
assert 'app_env: dev\n' in completed.stdout
|
||||
assert 'env_file: .env.dev\n' in completed.stdout
|
||||
assert 'env_file_exists:' in completed.stdout
|
||||
assert 'backend_dir:' in completed.stdout
|
||||
assert 'python_executable:' in completed.stdout
|
||||
|
||||
|
||||
def test_app_doctor_text_output_has_stable_check_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('app', 'doctor', '--env=dev', '--output=text')
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert '\x1b[' not in completed.stdout
|
||||
assert '✅' not in completed.stdout
|
||||
assert completed.stdout.startswith(('OK SUCCESS\n', 'FAIL FAILED\n'))
|
||||
assert 'env: dev\n' in completed.stdout
|
||||
assert 'checks:\n' in completed.stdout
|
||||
assert 'database:' in completed.stdout
|
||||
assert 'redis:' in completed.stdout
|
||||
assert 'crypto:' in completed.stdout
|
||||
|
||||
|
||||
def test_app_doctor_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
assert_check_payload_contract: Callable[[dict, bool], None],
|
||||
) -> None:
|
||||
completed = run_cli_command('app', 'doctor', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert completed.stderr == ''
|
||||
assert payload['env'] == 'dev'
|
||||
assert isinstance(payload['ok'], bool)
|
||||
assert set(payload) == {'env', 'database', 'redis', 'crypto', 'ok'}
|
||||
assert_check_payload_contract(payload['database'], True)
|
||||
assert_check_payload_contract(payload['redis'], True)
|
||||
assert_check_payload_contract(payload['crypto'], False)
|
||||
|
||||
|
||||
def test_app_env_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
) -> None:
|
||||
completed = run_cli_command('app', 'env', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode == SUCCESS
|
||||
assert payload['ok'] is True
|
||||
assert payload['env'] == 'dev'
|
||||
assert set(payload) == {'ok', 'env', 'runtime'}
|
||||
assert isinstance(payload['runtime'], dict)
|
||||
assert set(payload['runtime']) == {
|
||||
'cliEnv',
|
||||
'configEnv',
|
||||
'appEnv',
|
||||
'envFile',
|
||||
'envFilePath',
|
||||
'envFileExists',
|
||||
'backendDir',
|
||||
'pythonExecutable',
|
||||
}
|
||||
assert payload['runtime']['cliEnv'] == 'dev'
|
||||
assert payload['runtime']['appEnv'] == 'dev'
|
||||
assert payload['runtime']['envFile'] == '.env.dev'
|
||||
assert isinstance(payload['runtime']['envFileExists'], bool)
|
||||
|
||||
|
||||
def test_app_routes_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
) -> None:
|
||||
completed = run_cli_command('app', 'routes', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode == 0
|
||||
assert payload['ok'] is True
|
||||
assert payload['env'] == 'dev'
|
||||
assert isinstance(payload['count'], int)
|
||||
assert payload['count'] > 0
|
||||
assert payload['groupedRoutes'] is None
|
||||
assert payload['filters'] == {
|
||||
'pathPrefix': '',
|
||||
'method': '',
|
||||
'groupBy': 'none',
|
||||
'includeHidden': False,
|
||||
}
|
||||
assert isinstance(payload['routes'], list)
|
||||
assert payload['routes']
|
||||
|
||||
first_route = payload['routes'][0]
|
||||
assert set(first_route) == {
|
||||
'path',
|
||||
'methods',
|
||||
'name',
|
||||
'summary',
|
||||
'operationId',
|
||||
'tags',
|
||||
'includeInSchema',
|
||||
}
|
||||
assert isinstance(first_route['path'], str)
|
||||
assert isinstance(first_route['methods'], list)
|
||||
assert first_route['methods']
|
||||
assert all(isinstance(method, str) for method in first_route['methods'])
|
||||
assert isinstance(first_route['name'], str | None)
|
||||
assert isinstance(first_route['summary'], str | None)
|
||||
assert isinstance(first_route['operationId'], str | None)
|
||||
assert isinstance(first_route['tags'], list)
|
||||
assert all(isinstance(tag, str) for tag in first_route['tags'])
|
||||
assert isinstance(first_route['includeInSchema'], bool)
|
||||
|
||||
|
||||
def test_server_info_text_output_has_stable_section_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('ops', 'server-info', '--env=dev')
|
||||
|
||||
assert completed.returncode == 0
|
||||
assert '\x1b[' not in completed.stdout
|
||||
assert '✅' not in completed.stdout
|
||||
assert completed.stdout.startswith('OK SUCCESS\n')
|
||||
assert 'host:\n' in completed.stdout
|
||||
assert 'cpu:\n' in completed.stdout
|
||||
assert 'memory:\n' in completed.stdout
|
||||
assert 'python:\n' in completed.stdout
|
||||
assert 'disks:' in completed.stdout
|
||||
|
||||
|
||||
def test_ops_health_text_output_has_stable_check_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('ops', 'health', '--env=dev', '--output=text')
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert '\x1b[' not in completed.stdout
|
||||
assert '✅' not in completed.stdout
|
||||
assert completed.stdout.startswith(('OK SUCCESS\n', 'FAIL FAILED\n'))
|
||||
assert 'env: dev\n' in completed.stdout
|
||||
assert 'checks:\n' in completed.stdout
|
||||
assert 'database:' in completed.stdout
|
||||
assert 'redis:' in completed.stdout
|
||||
|
||||
|
||||
def test_ops_deps_text_output_has_stable_structure(
|
||||
run_text_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
) -> None:
|
||||
completed = run_text_cli_command('ops', 'deps', '--env=dev', '--output=text')
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert completed.stdout.startswith(('OK SUCCESS\n', 'FAIL FAILED\n'))
|
||||
assert 'message:' in completed.stdout
|
||||
assert 'include_dev: false\n' in completed.stdout
|
||||
assert 'missing_required:' in completed.stdout
|
||||
assert 'packages:\n' in completed.stdout
|
||||
assert 'python:' in completed.stdout
|
||||
assert 'fastapi:' in completed.stdout
|
||||
assert 'typer:' in completed.stdout
|
||||
|
||||
|
||||
def test_ops_health_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
assert_check_payload_contract: Callable[[dict, bool], None],
|
||||
) -> None:
|
||||
completed = run_cli_command('ops', 'health', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert completed.stderr == ''
|
||||
assert payload['env'] == 'dev'
|
||||
assert isinstance(payload['ok'], bool)
|
||||
assert set(payload) == {'env', 'database', 'redis', 'ok'}
|
||||
assert_check_payload_contract(payload['database'], True)
|
||||
assert_check_payload_contract(payload['redis'], True)
|
||||
|
||||
|
||||
def test_ops_deps_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
) -> None:
|
||||
completed = run_cli_command('ops', 'deps', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode in {SUCCESS, DEPENDENCY_ERROR}
|
||||
assert set(payload) == {'ok', 'message', 'missingRequired', 'includeDev', 'packages'}
|
||||
assert isinstance(payload['ok'], bool)
|
||||
assert isinstance(payload['message'], str)
|
||||
assert isinstance(payload['missingRequired'], list)
|
||||
assert payload['includeDev'] is False
|
||||
assert isinstance(payload['packages'], dict)
|
||||
assert 'python' in payload['packages']
|
||||
assert 'fastapi' in payload['packages']
|
||||
assert 'typer' in payload['packages']
|
||||
for package_payload in payload['packages'].values():
|
||||
assert isinstance(package_payload, dict)
|
||||
assert isinstance(package_payload.get('installed'), bool)
|
||||
assert isinstance(package_payload.get('version'), str)
|
||||
assert isinstance(package_payload.get('required'), bool)
|
||||
|
||||
|
||||
def test_ops_server_info_json_output_has_stable_contract(
|
||||
run_cli_command: Callable[..., subprocess.CompletedProcess[str]],
|
||||
parse_json_stdout: Callable[[subprocess.CompletedProcess[str]], dict],
|
||||
) -> None:
|
||||
completed = run_cli_command('ops', 'server-info', '--env=dev', '--output=json')
|
||||
payload = parse_json_stdout(completed)
|
||||
|
||||
assert completed.returncode == 0
|
||||
assert payload['ok'] is True
|
||||
assert isinstance(payload['server'], dict)
|
||||
|
||||
server = payload['server']
|
||||
assert set(server) == {'cpu', 'mem', 'sys', 'py', 'sysFiles'}
|
||||
|
||||
cpu = server['cpu']
|
||||
assert set(cpu) == {'cpuNum', 'used', 'sys', 'free'}
|
||||
assert isinstance(cpu['cpuNum'], int)
|
||||
assert isinstance(cpu['used'], float | int | str)
|
||||
assert isinstance(cpu['sys'], float | int | str)
|
||||
assert isinstance(cpu['free'], float | int | str)
|
||||
|
||||
memory = server['mem']
|
||||
assert set(memory) == {'total', 'used', 'free', 'usage'}
|
||||
assert isinstance(memory['total'], str)
|
||||
assert isinstance(memory['used'], str)
|
||||
assert isinstance(memory['free'], str)
|
||||
assert isinstance(memory['usage'], float | int)
|
||||
|
||||
sys_info = server['sys']
|
||||
assert set(sys_info) == {'computerIp', 'computerName', 'osArch', 'osName', 'userDir'}
|
||||
assert all(isinstance(value, str) for value in sys_info.values())
|
||||
|
||||
py_info = server['py']
|
||||
assert set(py_info) == {
|
||||
'name',
|
||||
'version',
|
||||
'startTime',
|
||||
'runTime',
|
||||
'home',
|
||||
'total',
|
||||
'used',
|
||||
'free',
|
||||
'usage',
|
||||
}
|
||||
assert isinstance(py_info['name'], str)
|
||||
assert isinstance(py_info['version'], str)
|
||||
assert isinstance(py_info['startTime'], str)
|
||||
assert isinstance(py_info['runTime'], str)
|
||||
assert isinstance(py_info['home'], str)
|
||||
assert isinstance(py_info['total'], str)
|
||||
assert isinstance(py_info['used'], str)
|
||||
assert isinstance(py_info['free'], str)
|
||||
assert isinstance(py_info['usage'], float | int)
|
||||
|
||||
assert isinstance(server['sysFiles'], list)
|
||||
assert server['sysFiles']
|
||||
first_disk = server['sysFiles'][0]
|
||||
assert set(first_disk) == {'dirName', 'sysTypeName', 'typeName', 'total', 'used', 'free', 'usage'}
|
||||
assert all(isinstance(value, str) for value in first_disk.values())
|
||||
Reference in New Issue
Block a user