blob: 5a11387f1a1c95444d7b19ec7b2107018096a163 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2012 The ChromiumOS Authors
Chris Sosa90c78502012-10-05 17:07:42 -07002# 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
Alex Klein1699fab2022-09-08 08:46:06 -060019_COMMAND_NAME = "superAwesomeCommandOfFunness"
Chris Sosa90c78502012-10-05 17:07:42 -070020
21
Mike Frysinger61cf22d2021-12-15 00:37:54 -050022@command.command_decorator(_COMMAND_NAME)
David Pursellffb90042015-03-23 09:21:41 -070023class TestCommand(command.CliCommand):
Alex Klein1699fab2022-09-08 08:46:06 -060024 """A fake command."""
25
26 def Run(self):
27 print("Just testing")
Chris Sosa90c78502012-10-05 17:07:42 -070028
29
David Pursellf80b8c52015-04-03 12:46:45 -070030class TestCommandTest(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060031 """This test class tests that Commands method."""
Chris Sosa90c78502012-10-05 17:07:42 -070032
Alex Klein1699fab2022-09-08 08:46:06 -060033 def testParserSetsCommandClass(self):
34 """Tests that our parser sets command_class correctly."""
35 my_parser = argparse.ArgumentParser()
36 command.CliCommand.AddParser(my_parser)
37 ns = my_parser.parse_args([])
38 self.assertEqual(ns.command_class, command.CliCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070039
Alex Klein1699fab2022-09-08 08:46:06 -060040 def testCommandDecorator(self):
41 """Tests that our decorator correctly adds TestCommand to _commands."""
42 # Note this exposes an implementation detail of _commands.
43 self.assertEqual(command._commands[_COMMAND_NAME], TestCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070044
Alex Klein1699fab2022-09-08 08:46:06 -060045 def testBadUseOfCommandDecorator(self):
46 """Tests that our decorator correctly rejects bad test commands."""
47 try:
48 # pylint: disable=unused-variable
49 @command.command_decorator("bad")
50 class BadTestCommand(object):
51 """A command that wasn't implemented correctly."""
Chris Sosa90c78502012-10-05 17:07:42 -070052
Alex Klein1699fab2022-09-08 08:46:06 -060053 except command.InvalidCommandError:
54 pass
55 else:
56 self.fail("Invalid command was accepted by @command_decorator")
David Pursellf1c27c12015-03-18 09:51:38 -070057
Alex Klein1699fab2022-09-08 08:46:06 -060058 def testAddDeviceArgument(self):
59 """Tests CliCommand.AddDeviceArgument()."""
60 parser = argparse.ArgumentParser()
61 command.CliCommand.AddDeviceArgument(parser, positional=True)
62 # Device should be a positional argument.
63 parser.parse_args(["device"])
David Pursellf80b8c52015-04-03 12:46:45 -070064
Alex Klein1699fab2022-09-08 08:46:06 -060065 def testAddNamedDeviceArgument(self):
66 """Tests CliCommand.AddDeviceArgument()."""
67 parser = argparse.ArgumentParser()
68 command.CliCommand.AddDeviceArgument(parser, positional=False)
69 # Device should be a named argument.
70 parser.parse_args(["--device=device"])
71 parser.parse_args(["-d", "device"])
Alex Kleindf030342020-02-14 10:07:38 -070072
David Pursellf1c27c12015-03-18 09:51:38 -070073
74class MockCommand(partial_mock.PartialMock):
Alex Klein1699fab2022-09-08 08:46:06 -060075 """Mock class for a generic CLI command."""
David Pursellf1c27c12015-03-18 09:51:38 -070076
Alex Klein1699fab2022-09-08 08:46:06 -060077 ATTRS = ("Run",)
78 COMMAND = None
79 TARGET_CLASS = None
David Pursellf1c27c12015-03-18 09:51:38 -070080
Alex Klein1699fab2022-09-08 08:46:06 -060081 def __init__(self, args, base_args=None):
82 partial_mock.PartialMock.__init__(self)
83 self.args = args
84 self.rc_mock = cros_test_lib.RunCommandMock()
85 self.rc_mock.SetDefaultCmdResult()
86 self.parser = parser = commandline.ArgumentParser(caching=True)
87 subparsers = parser.add_subparsers()
Mike Frysinger57a8feb2023-02-02 08:48:38 -050088 subparser = subparsers.add_parser(
89 self.COMMAND,
90 caching=self.TARGET_CLASS.use_caching_options,
91 dryrun=self.TARGET_CLASS.use_dryrun_options,
92 )
Alex Klein1699fab2022-09-08 08:46:06 -060093 self.TARGET_CLASS.AddParser(subparser)
David Pursellf1c27c12015-03-18 09:51:38 -070094
Alex Klein1699fab2022-09-08 08:46:06 -060095 args = base_args if base_args else []
96 args += [self.COMMAND] + self.args
97 options = parser.parse_args(args)
98 self.inst = options.command_class(options)
99
100 def Run(self, inst):
101 with self.rc_mock:
102 return self.backup["Run"](inst)
David Pursellf1c27c12015-03-18 09:51:38 -0700103
104
105class CommandTest(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600106 """This test class tests that we can load modules correctly."""
David Pursellf1c27c12015-03-18 09:51:38 -0700107
Alex Klein1699fab2022-09-08 08:46:06 -0600108 def testFindModules(self):
109 """Tests that we can return modules correctly when mocking out glob."""
110 fake_command_file = "cros_command_test.py"
111 filtered_file = "cros_command_unittest.py"
David Pursellf1c27c12015-03-18 09:51:38 -0700112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 self.PatchObject(
114 os, "listdir", return_value=[fake_command_file, filtered_file]
115 )
David Pursellf1c27c12015-03-18 09:51:38 -0700116
Alex Klein1699fab2022-09-08 08:46:06 -0600117 self.assertEqual(command.ListCommands(), {"command-test"})
David Pursellf1c27c12015-03-18 09:51:38 -0700118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 def testLoadCommands(self):
120 """Tests import commands correctly."""
121 fake_module = "cros_command_test"
122 module_path = "chromite.cli.cros.%s" % fake_module
David Pursellf1c27c12015-03-18 09:51:38 -0700123
Alex Klein1699fab2022-09-08 08:46:06 -0600124 # The code doesn't use the return value, so stub it out lazy-like.
125 load_mock = self.PatchObject(
126 importlib, "import_module", return_value=None
127 )
David Pursellf1c27c12015-03-18 09:51:38 -0700128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 command._commands["command-test"] = 123
130 self.assertEqual(command.ImportCommand("command-test"), 123)
131 command._commands.pop("command-test")
David Pursellf1c27c12015-03-18 09:51:38 -0700132
Alex Klein1699fab2022-09-08 08:46:06 -0600133 load_mock.assert_called_with(module_path)
David Pursellf1c27c12015-03-18 09:51:38 -0700134
Alex Klein1699fab2022-09-08 08:46:06 -0600135 def testListCrosCommands(self):
136 """Tests we get a correct `cros` list back."""
137 cros_commands = command.ListCommands()
138 # Pick some commands that are likely to not go away.
139 self.assertIn("chrome-sdk", cros_commands)
140 self.assertIn("flash", cros_commands)