blob: 98890cadab9d9cc5a7bf9dd8c3870f2694a49df8 [file] [log] [blame]
Chris Sosa90c78502012-10-05 17:07:42 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
David Pursellf1c27c12015-03-18 09:51:38 -07005"""Tests for the command module."""
Chris Sosa90c78502012-10-05 17:07:42 -07006
7import argparse
Alex Klein665aa072019-12-12 15:13:53 -07008import importlib
Ralph Nathan74e864d2015-05-11 12:13:53 -07009import os
Chris Sosa90c78502012-10-05 17:07:42 -070010
David Pursellf1c27c12015-03-18 09:51:38 -070011from chromite.cli import command
12from chromite.lib import commandline
Chris Sosa90c78502012-10-05 17:07:42 -070013from chromite.lib import cros_test_lib
David Pursellf1c27c12015-03-18 09:51:38 -070014from chromite.lib import partial_mock
15
Chris Sosa90c78502012-10-05 17:07:42 -070016
Don Garrett5bcf1442015-03-13 15:55:02 -070017# pylint:disable=protected-access
18
Chris Sosa90c78502012-10-05 17:07:42 -070019_COMMAND_NAME = 'superAwesomeCommandOfFunness'
20
21
David Pursellf1c27c12015-03-18 09:51:38 -070022@command.CommandDecorator(_COMMAND_NAME)
David Pursellffb90042015-03-23 09:21:41 -070023class TestCommand(command.CliCommand):
Chris Sosa90c78502012-10-05 17:07:42 -070024 """A fake command."""
25 def Run(self):
Mike Frysinger383367e2014-09-16 15:06:17 -040026 print('Just testing')
Chris Sosa90c78502012-10-05 17:07:42 -070027
28
David Pursellf80b8c52015-04-03 12:46:45 -070029class TestCommandTest(cros_test_lib.MockTestCase):
Chris Sosa90c78502012-10-05 17:07:42 -070030 """This test class tests that Commands method."""
31
David Pursellffb90042015-03-23 09:21:41 -070032 def testParserSetsCommandClass(self):
33 """Tests that our parser sets command_class correctly."""
Chris Sosa90c78502012-10-05 17:07:42 -070034 my_parser = argparse.ArgumentParser()
David Pursellffb90042015-03-23 09:21:41 -070035 command.CliCommand.AddParser(my_parser)
Chris Sosa90c78502012-10-05 17:07:42 -070036 ns = my_parser.parse_args([])
David Pursellffb90042015-03-23 09:21:41 -070037 self.assertEqual(ns.command_class, command.CliCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070038
39 def testCommandDecorator(self):
40 """Tests that our decorator correctly adds TestCommand to _commands."""
41 # Note this exposes an implementation detail of _commands.
David Pursellf1c27c12015-03-18 09:51:38 -070042 self.assertEqual(command._commands[_COMMAND_NAME], TestCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070043
44 def testBadUseOfCommandDecorator(self):
45 """Tests that our decorator correctly rejects bad test commands."""
46 try:
Mike Frysinger27e21b72018-07-12 14:20:21 -040047 # pylint: disable=unused-variable
David Pursellf1c27c12015-03-18 09:51:38 -070048 @command.CommandDecorator('bad')
Chris Sosa90c78502012-10-05 17:07:42 -070049 class BadTestCommand(object):
Brian Harring984988f2012-10-10 22:53:30 -070050 """A command that wasn't implemented correctly."""
Chris Sosa90c78502012-10-05 17:07:42 -070051
David Pursellf1c27c12015-03-18 09:51:38 -070052 except command.InvalidCommandError:
Chris Sosa90c78502012-10-05 17:07:42 -070053 pass
54 else:
55 self.fail('Invalid command was accepted by the CommandDecorator')
David Pursellf1c27c12015-03-18 09:51:38 -070056
David Pursellc7ba7842015-07-08 10:48:41 -070057 def testAddDeviceArgument(self):
58 """Tests CliCommand.AddDeviceArgument()."""
David Pursellf80b8c52015-04-03 12:46:45 -070059 parser = argparse.ArgumentParser()
Alex Kleindf030342020-02-14 10:07:38 -070060 command.CliCommand.AddDeviceArgument(parser, positional=True)
David Pursellc7ba7842015-07-08 10:48:41 -070061 # Device should be a positional argument.
David Pursellf80b8c52015-04-03 12:46:45 -070062 parser.parse_args(['device'])
David Pursellf80b8c52015-04-03 12:46:45 -070063
Alex Kleindf030342020-02-14 10:07:38 -070064 def testAddNamedDeviceArgument(self):
65 """Tests CliCommand.AddDeviceArgument()."""
66 parser = argparse.ArgumentParser()
67 command.CliCommand.AddDeviceArgument(parser, positional=False)
68 # Device should be a named argument.
69 parser.parse_args(['--device=device'])
70 parser.parse_args(['-d', 'device'])
71
David Pursellf1c27c12015-03-18 09:51:38 -070072
73class MockCommand(partial_mock.PartialMock):
David Pursellffb90042015-03-23 09:21:41 -070074 """Mock class for a generic CLI command."""
David Pursellf1c27c12015-03-18 09:51:38 -070075 ATTRS = ('Run',)
76 COMMAND = None
77 TARGET_CLASS = None
78
79 def __init__(self, args, base_args=None):
80 partial_mock.PartialMock.__init__(self)
81 self.args = args
Benjamin Gordon121a2aa2018-05-04 16:24:45 -060082 self.rc_mock = cros_test_lib.RunCommandMock()
David Pursellf1c27c12015-03-18 09:51:38 -070083 self.rc_mock.SetDefaultCmdResult()
84 parser = commandline.ArgumentParser(caching=True)
85 subparsers = parser.add_subparsers()
86 subparser = subparsers.add_parser(self.COMMAND, caching=True)
87 self.TARGET_CLASS.AddParser(subparser)
88
89 args = base_args if base_args else []
90 args += [self.COMMAND] + self.args
91 options = parser.parse_args(args)
David Pursellffb90042015-03-23 09:21:41 -070092 self.inst = options.command_class(options)
David Pursellf1c27c12015-03-18 09:51:38 -070093
94 def Run(self, inst):
95 with self.rc_mock:
96 return self.backup['Run'](inst)
97
98
99class CommandTest(cros_test_lib.MockTestCase):
100 """This test class tests that we can load modules correctly."""
101
David Pursellf1c27c12015-03-18 09:51:38 -0700102 def testFindModules(self):
103 """Tests that we can return modules correctly when mocking out glob."""
104 fake_command_file = 'cros_command_test.py'
105 filtered_file = 'cros_command_unittest.py'
David Pursellf1c27c12015-03-18 09:51:38 -0700106
Mike Frysinger1a470812019-11-07 01:19:17 -0500107 self.PatchObject(os, 'listdir',
David Pursellf1c27c12015-03-18 09:51:38 -0700108 return_value=[fake_command_file, filtered_file])
109
Mike Frysinger1a470812019-11-07 01:19:17 -0500110 self.assertEqual(command.ListCommands(), {'command-test'})
David Pursellf1c27c12015-03-18 09:51:38 -0700111
112 def testLoadCommands(self):
113 """Tests import commands correctly."""
114 fake_module = 'cros_command_test'
Alex Klein665aa072019-12-12 15:13:53 -0700115 module_path = 'chromite.cli.cros.%s' % fake_module
David Pursellf1c27c12015-03-18 09:51:38 -0700116
David Pursellf1c27c12015-03-18 09:51:38 -0700117 # The code doesn't use the return value, so stub it out lazy-like.
Alex Klein665aa072019-12-12 15:13:53 -0700118 load_mock = self.PatchObject(importlib, 'import_module', return_value=None)
David Pursellf1c27c12015-03-18 09:51:38 -0700119
Mike Frysinger1a470812019-11-07 01:19:17 -0500120 command._commands['command-test'] = 123
121 self.assertEqual(command.ImportCommand('command-test'), 123)
122 command._commands.pop('command-test')
David Pursellf1c27c12015-03-18 09:51:38 -0700123
124 load_mock.assert_called_with(module_path)
125
David Pursellffb90042015-03-23 09:21:41 -0700126 def testListCrosCommands(self):
127 """Tests we get a sane `cros` list back."""
David Pursellc7ba7842015-07-08 10:48:41 -0700128 cros_commands = command.ListCommands()
David Pursellf1c27c12015-03-18 09:51:38 -0700129 # Pick some commands that are likely to not go away.
130 self.assertIn('chrome-sdk', cros_commands)
131 self.assertIn('flash', cros_commands)