mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-30 12:25:29 +08:00
89 lines
4.0 KiB
Python
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()
|