mirror of
https://github.com/ansible/awx.git
synced 2026-03-07 11:41:08 -03:30
275 lines
9.2 KiB
Python
275 lines
9.2 KiB
Python
import argparse
|
|
import unittest
|
|
from io import StringIO
|
|
|
|
from awxkit.api.pages import Page
|
|
from awxkit.cli.options import ResourceOptionsParser
|
|
|
|
|
|
class ResourceOptionsParser(ResourceOptionsParser):
|
|
def get_allowed_options(self):
|
|
self.allowed_options = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
|
|
|
|
|
|
class NoPostResourceOptionsParser(ResourceOptionsParser):
|
|
"""Simulates a user with object-level PUT but no list-level POST."""
|
|
|
|
detail_put_actions = {}
|
|
|
|
def get_allowed_options(self):
|
|
self.allowed_options = ['GET', 'PUT', 'PATCH', 'DELETE']
|
|
# Simulate the logic from the real get_allowed_options that
|
|
# falls back to the detail endpoint's PUT schema when POST
|
|
# is not available on the list endpoint.
|
|
if 'POST' not in self.options and 'PUT' in self.allowed_options:
|
|
if self.detail_put_actions:
|
|
self.options['PUT'] = self.detail_put_actions
|
|
|
|
def handle_custom_actions(self):
|
|
pass
|
|
|
|
|
|
class OptionsPage(Page):
|
|
def options(self):
|
|
return self
|
|
|
|
def endswith(self, v):
|
|
return self.endpoint.endswith(v)
|
|
|
|
def __getitem__(self, k):
|
|
return {
|
|
'GET': {},
|
|
'POST': {},
|
|
'PUT': {},
|
|
}
|
|
|
|
|
|
class TestOptions(unittest.TestCase):
|
|
def setUp(self):
|
|
_parser = argparse.ArgumentParser()
|
|
self.parser = _parser.add_subparsers(help='action')
|
|
|
|
def test_list(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'GET': {},
|
|
'POST': {},
|
|
}
|
|
}
|
|
)
|
|
ResourceOptionsParser(None, page, 'users', self.parser)
|
|
assert 'list' in self.parser.choices
|
|
|
|
def test_list_filtering(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'GET': {},
|
|
'POST': {'first_name': {'type': 'string'}},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('list', 'POST')
|
|
assert 'list' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['list'].print_help(out)
|
|
assert '--first_name TEXT' in out.getvalue()
|
|
|
|
def test_list_not_filterable(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'GET': {},
|
|
'POST': {'middle_name': {'type': 'string', 'filterable': False}},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('list', 'POST')
|
|
assert 'list' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['list'].print_help(out)
|
|
assert '--middle_name' not in out.getvalue()
|
|
|
|
def test_creation_optional_argument(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'POST': {
|
|
'first_name': {
|
|
'type': 'string',
|
|
'help_text': 'Please specify your first name',
|
|
}
|
|
},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('create', 'POST')
|
|
assert 'create' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['create'].print_help(out)
|
|
assert '--first_name TEXT Please specify your first name' in out.getvalue()
|
|
|
|
def test_creation_required_argument(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'POST': {'username': {'type': 'string', 'help_text': 'Please specify a username', 'required': True}},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('create', 'POST')
|
|
assert 'create' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['create'].print_help(out)
|
|
assert '--username TEXT Please specify a username'
|
|
|
|
def test_integer_argument(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'POST': {'max_hosts': {'type': 'integer'}},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'organizations', self.parser)
|
|
options.build_query_arguments('create', 'POST')
|
|
assert 'create' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['create'].print_help(out)
|
|
assert '--max_hosts INTEGER' in out.getvalue()
|
|
|
|
def test_boolean_argument(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'POST': {'diff_mode': {'type': 'boolean'}},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('create', 'POST')
|
|
assert 'create' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['create'].print_help(out)
|
|
assert '--diff_mode BOOLEAN' in out.getvalue()
|
|
|
|
def test_choices(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'POST': {
|
|
'verbosity': {
|
|
'type': 'integer',
|
|
'choices': [
|
|
(0, '0 (Normal)'),
|
|
(1, '1 (Verbose)'),
|
|
(2, '2 (More Verbose)'),
|
|
(3, '3 (Debug)'),
|
|
(4, '4 (Connection Debug)'),
|
|
(5, '5 (WinRM Debug)'),
|
|
],
|
|
}
|
|
},
|
|
}
|
|
}
|
|
)
|
|
options = ResourceOptionsParser(None, page, 'users', self.parser)
|
|
options.build_query_arguments('create', 'POST')
|
|
assert 'create' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['create'].print_help(out)
|
|
assert '--verbosity {0,1,2,3,4,5}' in out.getvalue()
|
|
|
|
def test_actions_with_primary_key(self):
|
|
page = OptionsPage.from_json({'actions': {'GET': {}, 'POST': {}}})
|
|
ResourceOptionsParser(None, page, 'jobs', self.parser)
|
|
|
|
for method in ('get', 'modify', 'delete'):
|
|
assert method in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices[method].print_help(out)
|
|
assert 'positional arguments:\n id' in out.getvalue()
|
|
|
|
def test_modify_without_list_post(self):
|
|
"""User with object-level PUT but no list-level POST can still modify."""
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'GET': {},
|
|
}
|
|
}
|
|
)
|
|
NoPostResourceOptionsParser.detail_put_actions = {
|
|
'scm_branch': {'type': 'string', 'help_text': 'SCM branch'},
|
|
'description': {'type': 'string', 'help_text': 'Description'},
|
|
}
|
|
options = NoPostResourceOptionsParser(None, page, 'projects', self.parser)
|
|
|
|
assert 'modify' in self.parser.choices
|
|
assert 'create' not in self.parser.choices
|
|
|
|
options.build_query_arguments('modify', 'PUT')
|
|
out = StringIO()
|
|
self.parser.choices['modify'].print_help(out)
|
|
assert '--scm_branch TEXT' in out.getvalue()
|
|
assert '--description TEXT' in out.getvalue()
|
|
|
|
|
|
class TestSettingsOptions(unittest.TestCase):
|
|
def setUp(self):
|
|
_parser = argparse.ArgumentParser()
|
|
self.parser = _parser.add_subparsers(help='action')
|
|
|
|
def test_list(self):
|
|
page = OptionsPage.from_json(
|
|
{
|
|
'actions': {
|
|
'GET': {},
|
|
'POST': {},
|
|
'PUT': {},
|
|
}
|
|
}
|
|
)
|
|
page.endpoint = '/settings/all/'
|
|
ResourceOptionsParser(None, page, 'settings', self.parser)
|
|
assert 'list' in self.parser.choices
|
|
assert 'modify' in self.parser.choices
|
|
|
|
out = StringIO()
|
|
self.parser.choices['modify'].print_help(out)
|
|
assert 'modify [-h] key value' in out.getvalue()
|
|
|
|
|
|
class TestHelpParameterChanges(unittest.TestCase):
|
|
"""Test that add_help parameter changes work correctly"""
|
|
|
|
def test_add_help_parameter_handling(self):
|
|
"""Test that add_help=True and add_help=False work as expected"""
|
|
# Test add_help=True (for action parsers like list, create)
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers(dest='action')
|
|
|
|
list_parser = subparsers.add_parser('list', help='', add_help=True)
|
|
out = StringIO()
|
|
list_parser.print_help(out)
|
|
help_text = out.getvalue()
|
|
assert 'show this help message and exit' in help_text
|
|
|
|
# Test add_help=False (for resource parsers like users, jobs)
|
|
resource_parser = subparsers.add_parser('users', help='', add_help=False)
|
|
help_actions = [action for action in resource_parser._actions if '--help' in action.option_strings]
|
|
assert len(help_actions) == 0 # Should be 0 because add_help=False
|