def setUp(self): """Install a resource instance sufficient for testing common things with subcommands. """ class BasicResource(models.Resource): endpoint = '/basic/' name = models.Field(unique=True) self.resource = BasicResource() self.command = ResSubcommand(self.resource)
def test_basic_launch_with_echo(self): """Establish that we are able to run an ad hoc command and also print that to the command line without errors. """ with client.test_mode as t: t.register_json('/ad_hoc_commands/42/', {'id': 42}, method='GET') t.register_json('/', {'ad_hoc_commands': '/api/v1/ad_hoc_commands/'}, method='GET') t.register_json('/ad_hoc_commands/', { 'changed': True, 'id': 42, 'inventory': 'foobar', 'credential': 2, 'name': 'ping', 'created': 1234, 'elapsed': 2352, 'status': 'successful', 'module_name': 'command', 'limit': '', }, method='POST') result = self.res.launch(inventory="foobar", machine_credential=2) self.assertEqual(result['changed'], True) self.assertEqual(result['id'], 42) f = ResSubcommand(self.res)._echo_method(self.res.launch) with mock.patch.object(click, 'secho'): with settings.runtime_values(format='human'): f(inventory="foobar", machine_credential=2)
def lookup_stdout(self, pk=None, start_line=None, end_line=None, full=True): """ Internal method that lies to our `monitor` method by returning a scorecard for the workflow job where the standard out would have been expected. """ uj_res = get_resource('unified_job') # Filters # - limit search to jobs spawned as part of this workflow job # - order in the order in which they should add to the list # - only include final job states query_params = (('unified_job_node__workflow_job', pk), ('order_by', 'finished'), ('status__in', 'successful,failed,error')) jobs_list = uj_res.list(all_pages=True, query=query_params) if jobs_list['count'] == 0: return '' return_content = ResSubcommand(uj_res)._format_human(jobs_list) lines = return_content.split('\n') if not full: lines = lines[:-1] N = len(lines) start_range = start_line if start_line is None: start_range = 0 elif start_line > N: start_range = N end_range = end_line if end_line is None or end_line > N: end_range = N lines = lines[start_range:end_range] return_content = '\n'.join(lines) if len(lines) > 0: return_content += '\n' return return_content
def test_docstring_replacement_an(self): """Establish that for resources with names beginning with vowels, that the automatic docstring replacement is gramatically correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'Oreo cookie' # COOOOOOKIES!!!! endpoint = '/oreo/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'create') self.assertIn('Create an Oreo cookie', create.help)
def test_docstring_replacement_y(self): """Establish that for resources with names ending in y, that plural replacement is correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'telephony' endpoint = '/telephonies/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'list') self.assertIn('list of telephonies', create.help)
def test_basic_launch_with_echo(self): """Establish that we are able to create a job and echo the output to the command line without it breaking. """ with client.test_mode as t: standard_registration(t) result = self.res.launch(1) self.assertDictContainsSubset({'changed': True, 'id': 42}, result) f = ResSubcommand(self.res)._echo_method(self.res.launch) with mock.patch.object(click, 'secho'): with settings.runtime_values(format='human'): f(job_template=1)
def test_field_help_text_has_prefix(self): """Establish that resource field help text is properly prefixed. """ class FieldHelpTextResource(models.Resource): endpoint = '/foobar/' option_name = models.Field('internal_name', help_text='foobar', required=False) cmd = ResSubcommand(FieldHelpTextResource()).get_command(None, 'get') opt = cmd.params[0] self.assertEqual(opt.help, '[FIELD]foobar')
def test_field_help_text_has_suffix_for_structured_input(self): """Establish that resource field help text is properly suffixed if field type is StructuredInput. """ class FieldHelpTextResource(models.Resource): endpoint = '/foobar/' option_name = models.Field('internal_name', type=StructuredInput(), help_text='foobar', required=False) cmd = ResSubcommand(FieldHelpTextResource()).get_command(None, 'get') opt = cmd.params[0] self.assertEqual( opt.help.endswith(' Use @ to get JSON or YAML from a file.'), True)
def test_command_with_pk(self): """Establish that the `get_command` method appropriately adds a primary key argument if the method has a "pk" positional argument. """ # Create a resource with an appropriate command. class PKResource(models.BaseResource): endpoint = '/pkr/' @resources.command def my_method(self, pk): pass # Get the command version of my_method. my_method = ResSubcommand(PKResource()).get_command(None, 'my_method') # Establish that the `my_method` command does, in fact, have a PK # click argument attached. self.assertEqual(my_method.params[-1].name, 'pk')
def test_fields_not_options(self): """Establish that a field which is not an option is not made into an option for commands. """ # Create a resource with a field that is an option and another # field that isn't. class NoOptionResource(models.Resource): endpoint = '/nor/' yes = models.Field() no = models.Field(is_option=False) # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(NoOptionResource()).get_command(None, 'list') # Establish that "yes" is an option on the command and "no" is not. self.assertTrue(any([o.name == 'yes' for o in cmd.params])) self.assertFalse(any([o.name == 'no' for o in cmd.params]))
def test_field_explicit_key(self): """Establish that if a field is given an explicit key, that they key is used for the field name instead of the implicit name. """ # Create a resource with a field that has an explicit key. class ExplicitKeyResource(models.Resource): endpoint = '/ekr/' option_name = models.Field('internal_name') # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(ExplicitKeyResource()).get_command(None, 'get') # Establish that the field has an option of --option-name, and # a name of internal_name. opt = cmd.params[0] self.assertEqual(opt.name, 'internal_name') self.assertEqual(opt.opts, ['--option-name'])
def get_command(self, ctx, name): """Given a command identified by its name, import the appropriate module and return the decorated command. Resources are automatically commands, but if both a resource and a command are defined, the command takes precedence. """ # First, attempt to get a basic command from `tower_cli.api.misc`. if name in misc.__all__: return getattr(misc, name) # No command was found; try to get a resource. try: resource = tower_cli.get_resource(name) return ResSubcommand(resource) except ImportError: pass # Okay, we weren't able to find a command. secho('No such command: %s.' % name, fg='red', bold=True) sys.exit(2)
def test_job_template_create_with_echo(self): """Establish that a job template can be created """ with client.test_mode as t: endpoint = '/job_templates/' t.register_json(endpoint, { 'count': 0, 'results': [], 'next': None, 'previous': None }, method='GET') t.register_json(endpoint, { 'changed': True, 'id': 42, 'name': 'bar', 'inventory': 1, 'project': 1, 'playbook': 'foobar.yml', 'credential': 1 }, method='POST') self.res.create(name='bar', job_type='run', inventory=1, project=1, playbook='foobar.yml', credential=1) f = ResSubcommand(self.res)._echo_method(self.res.create) with mock.patch.object(click, 'secho'): with settings.runtime_values(format='human'): f(name='bar', job_type='run', inventory=1, project=1, playbook='foobar.yml', credential=1)
def test_use_fields_as_options_false(self): """Establish that the `use_fields_as_options` attribute is honored if set to False. """ # Create a resource with a command that doesn't expect its # fields to become options. class NoOptResource(models.BaseResource): endpoint = '/nor/' f1 = models.Field() f2 = models.Field() @resources.command(use_fields_as_options=False) def noopt(self): pass # Make the resource into a command, and get the noopt subcommand. noopt = ResSubcommand(NoOptResource()).get_command(None, 'noopt') # Establish that the noopt command does NOT have fields as options. self.assertFalse(any([o.name == 'f1' for o in noopt.params])) self.assertFalse(any([o.name == 'f2' for o in noopt.params]))
def test_delete_method_is_disabled(self): """The create method is properly disabled.""" self.assertEqual(ResSubcommand(self.res).get_command(None, 'delete'), None)
def test_removed_methods(self): """Test that None is returned from removed methods.""" self.assertEqual( ResSubcommand(self.res).get_command(None, 'delete'), None)
def test_delete_method_is_disabled(self): """Establish that delete method of a label is properly disabled. """ self.assertEqual( ResSubcommand(self.res).get_command(None, 'delete'), None)
class SubcommandTests(unittest.TestCase): """A set of tests for establishing that the Subcommand class created on the basis of a Reosurce class works in the way we expect. """ def setUp(self): """Install a resource instance sufficient for testing common things with subcommands. """ class BasicResource(models.Resource): endpoint = '/basic/' name = models.Field(unique=True) self.resource = BasicResource() self.command = ResSubcommand(self.resource) def test_command_instance(self): """Establish that the command based on a resource is, in fact, a click MultiCommand. """ # Assert that it is a click command, and that it has the commands # available on the resource. self.assertIsInstance(self.command, click.MultiCommand) def test_list_commands(self): """Establish that the `list_commands` method for the command corresponds to the commands available on the resource. """ self.assertEqual(set(self.resource.commands), set(self.command.list_commands(None))) def test_get_command(self): """Establish that the `get_command` method returns the appropriate resource method wrapped as a click command. """ list_command = self.command.get_command(None, 'list') # Ensure that this is a click command. self.assertIsInstance(list_command, click.core.Command) # Ensure that this command has an option corresponding to the # "name" unique field. self.assertEqual(list_command.params[0].name, 'name') self.assertIn('--name', list_command.params[0].opts) def test_get_command_error(self): """Establish that if `get_command` is called against a command that does not actually exist on the resource, that null value is returned. """ self.assertEqual(self.command.get_command(None, 'bogus'), None) def test_command_with_pk(self): """Establish that the `get_command` method appropriately adds a primary key argument if the method has a "pk" positional argument. """ # Create a resource with an appropriate command. class PKResource(models.BaseResource): endpoint = '/pkr/' @resources.command def my_method(self, pk): pass # Get the command version of my_method. my_method = ResSubcommand(PKResource()).get_command(None, 'my_method') # Establish that the `my_method` command does, in fact, have a PK # click argument attached. self.assertEqual(my_method.params[-1].name, 'pk') def test_use_fields_as_options_false(self): """Establish that the `use_fields_as_options` attribute is honored if set to False. """ # Create a resource with a command that doesn't expect its # fields to become options. class NoOptResource(models.BaseResource): endpoint = '/nor/' f1 = models.Field() f2 = models.Field() @resources.command(use_fields_as_options=False) def noopt(self): pass # Make the resource into a command, and get the noopt subcommand. noopt = ResSubcommand(NoOptResource()).get_command(None, 'noopt') # Establish that the noopt command does NOT have fields as options. self.assertFalse(any([o.name == 'f1' for o in noopt.params])) self.assertFalse(any([o.name == 'f2' for o in noopt.params])) def test_use_fields_as_options_enumerated(self): """Establish that the `use_fields_as_options` attribute is honored if set to a tuple containing a subset of fields. """ # Create a resource with a command that doesn't expect its # fields to become options. class NoOptResource(models.BaseResource): endpoint = '/nor/' f1 = models.Field() f2 = models.Field() @resources.command(use_fields_as_options=('f2', )) def noopt(self): pass # Make the resource into a command, and get the noopt subcommand. noopt = ResSubcommand(NoOptResource()).get_command(None, 'noopt') # Establish that the noopt command does NOT have fields as options. self.assertFalse(any([o.name == 'f1' for o in noopt.params])) self.assertTrue(any([o.name == 'f2' for o in noopt.params])) def test_fields_not_options(self): """Establish that a field which is not an option is not made into an option for commands. """ # Create a resource with a field that is an option and another # field that isn't. class NoOptionResource(models.Resource): endpoint = '/nor/' yes = models.Field() no = models.Field(is_option=False) # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(NoOptionResource()).get_command(None, 'list') # Establish that "yes" is an option on the command and "no" is not. self.assertTrue(any([o.name == 'yes' for o in cmd.params])) self.assertFalse(any([o.name == 'no' for o in cmd.params])) def test_field_explicit_key(self): """Establish that if a field is given an explicit key, that they key is used for the field name instead of the implicit name. """ # Create a resource with a field that has an explicit key. class ExplicitKeyResource(models.Resource): endpoint = '/ekr/' option_name = models.Field('internal_name') # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(ExplicitKeyResource()).get_command(None, 'get') # Establish that the field has an option of --option-name, and # a name of internal_name. opt = cmd.params[0] self.assertEqual(opt.name, 'internal_name') self.assertEqual(opt.opts, ['--option-name']) def test_field_help_text_has_prefix(self): """Establish that resource field help text is properly prefixed. """ class FieldHelpTextResource(models.Resource): endpoint = '/foobar/' option_name = models.Field('internal_name', help_text='foobar', required=False) cmd = ResSubcommand(FieldHelpTextResource()).get_command(None, 'get') opt = cmd.params[0] self.assertEqual(opt.help, '[FIELD]foobar') def test_docstring_replacement_an(self): """Establish that for resources with names beginning with vowels, that the automatic docstring replacement is gramatically correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'Oreo cookie' # COOOOOOKIES!!!! endpoint = '/oreo/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'create') self.assertIn('Create an Oreo cookie', create.help) def test_docstring_replacement_y(self): """Establish that for resources with names ending in y, that plural replacement is correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'telephony' endpoint = '/telephonies/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'list') self.assertIn('list of telephonies', create.help) def test_echo_method(self): """Establish that the _echo_method subcommand class works in the way we expect. """ func = self.command._echo_method(lambda: {'foo': 'bar'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json'): func() secho.assert_called_once_with(json.dumps({'foo': 'bar'}, indent=2)) def test_echo_method_changed_false(self): """Establish that the _echo_method subcommand decorator works in the way we expect if we get an unchanged designation. """ func = self.command._echo_method(lambda: {'changed': False}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json', color=True): func() answer = json.dumps({'changed': False}, indent=2) secho.assert_called_once_with(answer, fg='green') def test_echo_method_changed_true(self): """Establish that the _echo_method subcommand decorator works in the way we expect if we get an changed designation. """ func = self.command._echo_method(lambda: {'changed': True}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json', color=True): func() answer = json.dumps({'changed': True}, indent=2) secho.assert_called_once_with(answer, fg='yellow') def test_echo_method_yaml_formatted(self): """Establish that the `_echo_method` properly returns YAML formatting when it gets back a list of objects. """ func = self.command._echo_method(lambda: {'foo': 'bar'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='yaml'): func() secho.assert_called_once_with( yaml.safe_dump({'foo': 'bar'}, indent=2, allow_unicode=True, default_flow_style=False)) def test_echo_method_human_formatted(self): """Establish that the `_echo_method` properly returns human formatting when it gets back a list of objects. """ func = self.command._echo_method( lambda: { 'results': [ { 'id': 1, 'name': 'Durham, NC' }, { 'id': 2, 'name': 'Austin, TX' }, ] }) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) self.assertIn('2 Austin, TX', output) def test_echo_method_human_formatted_changed(self): """Establish that if there is a change and no id is returned, we print a generic OK message. """ func = self.command._echo_method(lambda: {'changed': False}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertEqual(output, 'OK. (changed: false)') def test_echo_method_human_formatted_no_records(self): """Establish that if there are no records sent to the human formatter, that it prints a terse message to that effect. """ func = self.command._echo_method(lambda: {'results': []}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertEqual(output, 'No records found.') def test_echo_method_human_formatted_single_result(self): """Establish that a single result sent to the human formatter shows a table with a single row as expected. """ f = self.command._echo_method(lambda: {'id': 1, 'name': 'Durham, NC'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): f() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) def test_echo_method_human_boolean_formatting(self): """Establish that booleans are formatted right-aligned, lower-cased in human output. """ func = self.command._echo_method( lambda: { 'results': [ { 'id': 1, 'name': 'Durham, NC' }, { 'id': 2, 'name': True }, ] }) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) self.assertIn('2 true', output) def test_echo_method_human_pagination(self): """Establish that pagination works in human formatting, and it prints the way we expect. """ func = self.command._echo_method( lambda: { 'results': [ { 'id': 1, 'name': 'Durham, NC' }, { 'id': 2, 'name': True }, ], 'next': 3, 'count': 10, 'previous': 1 }) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('(Page 2 of 5.)', output) def test_echo_method_human_pagination_last_page(self): """Establish that pagination works in human formatting, and it prints the way we expect on the final page.. """ func = self.command._echo_method( lambda: { 'results': [ { 'id': 1, 'name': 'Durham, NC' }, ], 'next': None, 'count': 3, 'previous': 1 }) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('(Page 2 of 2.)', output) def test_echo_method_human_custom_output(self): """Establish that a custom dictionary with no ID is made into a table and printed as expected. """ func = self.command._echo_method(lambda: { 'foo': 'bar', 'spam': 'eggs' }) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('foo', output) self.assertIn('spam', output) self.assertIn('bar', output) self.assertIn('eggs', output) def test_echo_id(self): func = self.command._echo_method(lambda: {'id': 5}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='id'): func() output = secho.mock_calls[-1][1][0] self.assertEqual('5', output)
class SubcommandTests(unittest.TestCase): """A set of tests for establishing that the Subcommand class created on the basis of a Reosurce class works in the way we expect. """ def setUp(self): """Install a resource instance sufficient for testing common things with subcommands. """ class BasicResource(models.Resource): endpoint = '/basic/' name = models.Field(unique=True) self.resource = BasicResource() self.command = ResSubcommand(self.resource) def test_command_instance(self): """Establish that the command based on a resource is, in fact, a click MultiCommand. """ # Assert that it is a click command, and that it has the commands # available on the resource. self.assertIsInstance(self.command, click.MultiCommand) def test_list_commands(self): """Establish that the `list_commands` method for the command corresponds to the commands available on the resource. """ self.assertEqual(set(self.resource.commands), set(self.command.list_commands(None))) def test_get_command(self): """Establish that the `get_command` method returns the appropriate resource method wrapped as a click command. """ list_command = self.command.get_command(None, 'list') # Ensure that this is a click command. self.assertIsInstance(list_command, click.core.Command) # Ensure that this command has an option corresponding to the # "name" unique field. self.assertEqual(list_command.params[0].name, 'name') self.assertIn('--name', list_command.params[0].opts) def test_get_command_error(self): """Establish that if `get_command` is called against a command that does not actually exist on the resource, that null value is returned. """ self.assertEqual(self.command.get_command(None, 'bogus'), None) def test_command_with_pk(self): """Establish that the `get_command` method appropriately adds a primary key argument if the method has a "pk" positional argument. """ # Create a resource with an appropriate command. class PKResource(models.BaseResource): endpoint = '/pkr/' @resources.command def my_method(self, pk): pass # Get the command version of my_method. my_method = ResSubcommand(PKResource()).get_command(None, 'my_method') # Establish that the `my_method` command does, in fact, have a PK # click argument attached. self.assertEqual(my_method.params[-1].name, 'pk') def test_use_fields_as_options_false(self): """Establish that the `use_fields_as_options` attribute is honored if set to False. """ # Create a resource with a command that doesn't expect its # fields to become options. class NoOptResource(models.BaseResource): endpoint = '/nor/' f1 = models.Field() f2 = models.Field() @resources.command(use_fields_as_options=False) def noopt(self): pass # Make the resource into a command, and get the noopt subcommand. noopt = ResSubcommand(NoOptResource()).get_command(None, 'noopt') # Establish that the noopt command does NOT have fields as options. self.assertFalse(any([o.name == 'f1' for o in noopt.params])) self.assertFalse(any([o.name == 'f2' for o in noopt.params])) def test_use_fields_as_options_enumerated(self): """Establish that the `use_fields_as_options` attribute is honored if set to a tuple containing a subset of fields. """ # Create a resource with a command that doesn't expect its # fields to become options. class NoOptResource(models.BaseResource): endpoint = '/nor/' f1 = models.Field() f2 = models.Field() @resources.command(use_fields_as_options=('f2',)) def noopt(self): pass # Make the resource into a command, and get the noopt subcommand. noopt = ResSubcommand(NoOptResource()).get_command(None, 'noopt') # Establish that the noopt command does NOT have fields as options. self.assertFalse(any([o.name == 'f1' for o in noopt.params])) self.assertTrue(any([o.name == 'f2' for o in noopt.params])) def test_fields_not_options(self): """Establish that a field which is not an option is not made into an option for commands. """ # Create a resource with a field that is an option and another # field that isn't. class NoOptionResource(models.Resource): endpoint = '/nor/' yes = models.Field() no = models.Field(is_option=False) # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(NoOptionResource()).get_command(None, 'list') # Establish that "yes" is an option on the command and "no" is not. self.assertTrue(any([o.name == 'yes' for o in cmd.params])) self.assertFalse(any([o.name == 'no' for o in cmd.params])) def test_field_explicit_key(self): """Establish that if a field is given an explicit key, that they key is used for the field name instead of the implicit name. """ # Create a resource with a field that has an explicit key. class ExplicitKeyResource(models.Resource): endpoint = '/ekr/' option_name = models.Field('internal_name') # Make the resource into a command, and get a reasonably-arbitrary # subcommand. cmd = ResSubcommand(ExplicitKeyResource()).get_command(None, 'get') # Establish that the field has an option of --option-name, and # a name of internal_name. opt = cmd.params[0] self.assertEqual(opt.name, 'internal_name') self.assertEqual(opt.opts, ['--option-name']) def test_field_help_text_has_prefix(self): """Establish that resource field help text is properly prefixed. """ class FieldHelpTextResource(models.Resource): endpoint = '/foobar/' option_name = models.Field('internal_name', help_text='foobar', required=False) cmd = ResSubcommand(FieldHelpTextResource()).get_command(None, 'get') opt = cmd.params[0] self.assertEqual(opt.help, '[FIELD]foobar') def test_field_help_text_has_suffix_for_structured_input(self): """Establish that resource field help text is properly suffixed if field type is StructuredInput. """ class FieldHelpTextResource(models.Resource): endpoint = '/foobar/' option_name = models.Field('internal_name', type=StructuredInput(), help_text='foobar', required=False) cmd = ResSubcommand(FieldHelpTextResource()).get_command(None, 'get') opt = cmd.params[0] self.assertEqual(opt.help.endswith(' Use @ to get JSON or YAML from a file.'), True) def test_docstring_replacement_an(self): """Establish that for resources with names beginning with vowels, that the automatic docstring replacement is grammatically correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'Oreo cookie' # COOOOOOKIES!!!! endpoint = '/oreo/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'create') self.assertIn('Create an Oreo cookie', create.help) def test_docstring_replacement_y(self): """Establish that for resources with names ending in y, that plural replacement is correct. """ # Create a resource with an approriate name. class Oreo(models.Resource): resource_name = 'telephony' endpoint = '/telephonies/' # Get the Oreo resource's create method. create = ResSubcommand(Oreo()).get_command(None, 'list') self.assertIn('list of telephonies', create.help) def test_echo_method(self): """Establish that the _echo_method subcommand class works in the way we expect. """ func = self.command._echo_method(lambda: {'foo': 'bar'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json'): func() secho.assert_called_once_with(json.dumps({'foo': 'bar'}, indent=2)) def test_echo_method_format_freezer(self): """Establish that the _echo_method subcommand class respects format_freezer attribute of inner method. """ def inner_func(): return {'foo': 'bar'} inner_func.format_freezer = 'json' func = self.command._echo_method(inner_func) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() secho.assert_called_once_with(json.dumps({'foo': 'bar'}, indent=2)) def test_echo_method_changed_false(self): """Establish that the _echo_method subcommand decorator works in the way we expect if we get an unchanged designation. """ func = self.command._echo_method(lambda: {'changed': False}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json', color=True): func() answer = json.dumps({'changed': False}, indent=2) secho.assert_called_once_with(answer, fg='green') def test_echo_method_changed_true(self): """Establish that the _echo_method subcommand decorator works in the way we expect if we get an changed designation. """ func = self.command._echo_method(lambda: {'changed': True}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='json', color=True): func() answer = json.dumps({'changed': True}, indent=2) secho.assert_called_once_with(answer, fg='yellow') def test_echo_method_yaml_formatted(self): """Establish that the `_echo_method` properly returns YAML formatting when it gets back a list of objects. """ func = self.command._echo_method(lambda: {'foo': 'bar'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='yaml'): func() secho.assert_called_once_with(yaml.safe_dump({'foo': 'bar'}, indent=2, allow_unicode=True, default_flow_style=False)) def test_echo_method_human_formatted(self): """Establish that the `_echo_method` properly returns human formatting when it gets back a list of objects. """ func = self.command._echo_method(lambda: {'results': [ {'id': 1, 'name': 'Durham, NC'}, {'id': 2, 'name': 'Austin, TX'}, ]}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) self.assertIn('2 Austin, TX', output) def test_unicode_human_formatting(self): value = u'unicode ❤ ☀ ☆ ☂' data = { 'count': 1, 'results': [ {'id': 1, 'name': 'ascii'}, { 'id': 42, 'name': '' } ] } data['results'][1]['name'] = value output = self.command._format_human(data) assert value in output def test_echo_method_human_formatted_changed(self): """Establish that if there is a change and no id is returned, we print a generic OK message. """ func = self.command._echo_method(lambda: {'changed': False}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertEqual(output, 'OK. (changed: false)') def test_echo_method_human_formatted_no_records(self): """Establish that if there are no records sent to the human formatter, that it prints a terse message to that effect. """ func = self.command._echo_method(lambda: {'results': []}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertEqual(output, 'No records found.') def test_echo_method_human_formatted_single_result(self): """Establish that a single result sent to the human formatter shows a table with a single row as expected. """ f = self.command._echo_method(lambda: {'id': 1, 'name': 'Durham, NC'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): f() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) def test_echo_method_human_boolean_formatting(self): """Establish that booleans are formatted right-aligned, lower-cased in human output. """ func = self.command._echo_method(lambda: {'results': [ {'id': 1, 'name': 'Durham, NC'}, {'id': 2, 'name': True}, ]}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('1 Durham, NC', output) self.assertIn('2 true', output) def test_echo_method_human_pagination(self): """Establish that pagination works in human formatting, and it prints the way we expect. """ func = self.command._echo_method(lambda: {'results': [ {'id': 1, 'name': 'Durham, NC'}, {'id': 2, 'name': True}, ], 'next': 3, 'count': 10, 'previous': 1}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('(Page 2 of 5.)', output) def test_echo_method_human_pagination_last_page(self): """Establish that pagination works in human formatting, and it prints the way we expect on the final page.. """ func = self.command._echo_method(lambda: {'results': [ {'id': 1, 'name': 'Durham, NC'}, ], 'next': None, 'count': 3, 'previous': 1}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('(Page 2 of 2.)', output) def test_echo_method_human_custom_output(self): """Establish that a custom dictionary with no ID is made into a table and printed as expected. """ func = self.command._echo_method(lambda: {'foo': 'bar', 'spam': 'eggs'}) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='human'): func() output = secho.mock_calls[-1][1][0] self.assertIn('foo', output) self.assertIn('spam', output) self.assertIn('bar', output) self.assertIn('eggs', output) def test_echo_id(self): for input_format in [{'id': 5}, {'count': 1, 'results': [{'id': 5}]}]: func = self.command._echo_method(lambda: input_format) with mock.patch.object(click, 'secho') as secho: with settings.runtime_values(format='id'): func() output = secho.mock_calls[-1][1][0] self.assertEqual('5', output)