Files
LangBot/tools/test_regression_cli_cases.py

89 lines
4.0 KiB
Python

"""Keep CLI presentation flexible while rejecting wrong identity and false success."""
from pathlib import Path
from types import SimpleNamespace
import tempfile
import json
import unittest
from unittest.mock import Mock, patch
from regression_cli_cases import identity, invalid_credential, pipeline_roundtrip
from regression_ci import suite_profile
from regression_suite import Suite, validate
class CLICompatibilityTests(unittest.TestCase):
def test_wrong_workspace_fails_even_when_cli_exits_successfully(self):
suite = SimpleNamespace(
call=Mock(side_effect=[{'version': 'future', 'new_field': True}, {'workspace_uuid': 'wrong'}]),
variables={'workspace_uuid': 'expected'},
)
row = {}
with self.assertRaisesRegex(ValueError, 'different Workspace'):
identity(suite, row)
self.assertEqual(row['assertions']['workspace_identity'], 'failed')
def test_invalid_credential_must_have_nonzero_exit(self):
suite = SimpleNamespace(
connection={'credential_source': 'env:QA_KEY'},
cli=['lbctl', '-o', 'json'],
env={'QA_KEY': 'secret'},
timeout=lambda value: value,
)
with patch(
'regression_cli_cases.subprocess.run', return_value=SimpleNamespace(returncode=0, stdout='{}', stderr='')
):
with self.assertRaisesRegex(ValueError, 'success with an invalid credential'):
invalid_credential(suite, {})
def test_successful_cli_create_without_backend_state_fails(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory)
suite = Suite(
{'cli': {'config': 'unused'}, 'cases': [], 'vars': {'workspace_uuid': 'test'}}, path / 'p.json', path
)
suite.call = Mock(return_value={'uuid': 'reported-but-not-created'})
row = {}
with (
patch('regression_cli_cases.request', return_value={'pipelines': []}),
patch('regression_api_checks.api', return_value=(200, {'code': 0, 'data': {'pipelines': []}})),
):
with self.assertRaisesRegex(ValueError, 'exactly one owned Pipeline'):
pipeline_roundtrip(suite, row)
self.assertEqual(row['owned_resources'][0]['state'], 'absent')
def test_zero_exit_does_not_hide_an_explicit_failure_envelope(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory)
suite = Suite({'cli': {'config': 'unused'}, 'cases': []}, path / 'p.json', path, env={})
for response in (
{'ok': False, 'data': {'requested_uuid': 'owned'}},
{'error': {'type': 'failed'}, 'data': {'uuid': 'owned'}},
):
process = SimpleNamespace(returncode=0, stdout=json.dumps(response), stderr='')
with self.subTest(response=response), patch('regression_suite.subprocess.run', return_value=process):
with self.assertRaisesRegex(RuntimeError, 'failure response'):
suite.call(['pipeline', 'get', 'owned'])
process = SimpleNamespace(
returncode=0,
stdout=json.dumps(
{'ok': True, 'new_field': 'allowed', 'data': {'pipeline': {'uuid': 'owned', 'extra': 1}}}
),
stderr='',
)
with patch('regression_suite.subprocess.run', return_value=process):
self.assertEqual(suite.call(['pipeline', 'get', 'owned'])['pipeline']['uuid'], 'owned')
def test_profile_is_finite_and_uses_no_shared_resources(self):
profile, _ = suite_profile('cli', 'unit-test')
validate(profile)
self.assertEqual(profile['resources'], [])
self.assertEqual(len(profile['cases']), 3)
self.assertNotIn('execution', profile)
smoke, _ = suite_profile('smoke', 'unit-test')
self.assertFalse(any(case.get('scenario', '').startswith('cli.') for case in smoke['cases']))
if __name__ == '__main__':
unittest.main()