blob: 33c072567a1e24836f2519e8e527ff7cb86c4a74 [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
Mike Frysinger383367e2014-09-16 15:06:17 -04007from __future__ import print_function
8
Chris Sosa90c78502012-10-05 17:07:42 -07009import argparse
David Pursellf1c27c12015-03-18 09:51:38 -070010import glob
Ralph Nathan74e864d2015-05-11 12:13:53 -070011import os
Chris Sosa90c78502012-10-05 17:07:42 -070012
David Pursellc7ba7842015-07-08 10:48:41 -070013from chromite.cbuildbot import constants
David Pursellf1c27c12015-03-18 09:51:38 -070014from chromite.cli import command
15from chromite.lib import commandline
16from chromite.lib import cros_build_lib_unittest
17from chromite.lib import cros_import
Ralph Nathan74e864d2015-05-11 12:13:53 -070018from chromite.lib import cros_logging as logging
Chris Sosa90c78502012-10-05 17:07:42 -070019from chromite.lib import cros_test_lib
David Pursellf1c27c12015-03-18 09:51:38 -070020from chromite.lib import partial_mock
Ralph Nathan7a0bae22015-05-13 10:49:54 -070021from chromite.lib import workspace_lib
David Pursellf1c27c12015-03-18 09:51:38 -070022
Chris Sosa90c78502012-10-05 17:07:42 -070023
Don Garrett5bcf1442015-03-13 15:55:02 -070024# pylint:disable=protected-access
25
Chris Sosa90c78502012-10-05 17:07:42 -070026_COMMAND_NAME = 'superAwesomeCommandOfFunness'
27
28
David Pursellf1c27c12015-03-18 09:51:38 -070029@command.CommandDecorator(_COMMAND_NAME)
David Pursellffb90042015-03-23 09:21:41 -070030class TestCommand(command.CliCommand):
Chris Sosa90c78502012-10-05 17:07:42 -070031 """A fake command."""
32 def Run(self):
Mike Frysinger383367e2014-09-16 15:06:17 -040033 print('Just testing')
Chris Sosa90c78502012-10-05 17:07:42 -070034
35
David Pursellf80b8c52015-04-03 12:46:45 -070036class TestCommandTest(cros_test_lib.MockTestCase):
Chris Sosa90c78502012-10-05 17:07:42 -070037 """This test class tests that Commands method."""
38
David Pursellffb90042015-03-23 09:21:41 -070039 def testParserSetsCommandClass(self):
40 """Tests that our parser sets command_class correctly."""
Chris Sosa90c78502012-10-05 17:07:42 -070041 my_parser = argparse.ArgumentParser()
David Pursellffb90042015-03-23 09:21:41 -070042 command.CliCommand.AddParser(my_parser)
Chris Sosa90c78502012-10-05 17:07:42 -070043 ns = my_parser.parse_args([])
David Pursellffb90042015-03-23 09:21:41 -070044 self.assertEqual(ns.command_class, command.CliCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070045
46 def testCommandDecorator(self):
47 """Tests that our decorator correctly adds TestCommand to _commands."""
48 # Note this exposes an implementation detail of _commands.
David Pursellf1c27c12015-03-18 09:51:38 -070049 self.assertEqual(command._commands[_COMMAND_NAME], TestCommand)
Chris Sosa90c78502012-10-05 17:07:42 -070050
51 def testBadUseOfCommandDecorator(self):
52 """Tests that our decorator correctly rejects bad test commands."""
53 try:
Brian Harring984988f2012-10-10 22:53:30 -070054 # pylint: disable=W0612
David Pursellf1c27c12015-03-18 09:51:38 -070055 @command.CommandDecorator('bad')
Chris Sosa90c78502012-10-05 17:07:42 -070056 class BadTestCommand(object):
Brian Harring984988f2012-10-10 22:53:30 -070057 """A command that wasn't implemented correctly."""
Chris Sosa90c78502012-10-05 17:07:42 -070058 pass
59
David Pursellf1c27c12015-03-18 09:51:38 -070060 except command.InvalidCommandError:
Chris Sosa90c78502012-10-05 17:07:42 -070061 pass
62 else:
63 self.fail('Invalid command was accepted by the CommandDecorator')
David Pursellf1c27c12015-03-18 09:51:38 -070064
David Pursellc7ba7842015-07-08 10:48:41 -070065 def testAddDeviceArgument(self):
66 """Tests CliCommand.AddDeviceArgument()."""
David Pursellf80b8c52015-04-03 12:46:45 -070067 parser = argparse.ArgumentParser()
68 command.CliCommand.AddDeviceArgument(parser)
David Pursellc7ba7842015-07-08 10:48:41 -070069 # Device should be a positional argument.
David Pursellf80b8c52015-04-03 12:46:45 -070070 parser.parse_args(['device'])
David Pursellf80b8c52015-04-03 12:46:45 -070071
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
82 self.rc_mock = cros_build_lib_unittest.RunCommandMock()
83 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
102 # pylint: disable=W0212
103
104 def testFindModules(self):
105 """Tests that we can return modules correctly when mocking out glob."""
106 fake_command_file = 'cros_command_test.py'
107 filtered_file = 'cros_command_unittest.py'
108 mydir = 'mydir'
109
110 self.PatchObject(glob, 'glob',
111 return_value=[fake_command_file, filtered_file])
112
David Pursellc7ba7842015-07-08 10:48:41 -0700113 self.assertEqual(command._FindModules(mydir), [fake_command_file])
David Pursellf1c27c12015-03-18 09:51:38 -0700114
115 def testLoadCommands(self):
116 """Tests import commands correctly."""
117 fake_module = 'cros_command_test'
David Pursellc7ba7842015-07-08 10:48:41 -0700118 fake_command_file = os.path.join(constants.CHROMITE_DIR, 'foo', fake_module)
119 module_path = ['chromite', 'foo', fake_module]
David Pursellf1c27c12015-03-18 09:51:38 -0700120
121 self.PatchObject(command, '_FindModules', return_value=[fake_command_file])
122 # The code doesn't use the return value, so stub it out lazy-like.
123 load_mock = self.PatchObject(cros_import, 'ImportModule', return_value=None)
124
David Pursellc7ba7842015-07-08 10:48:41 -0700125 command._ImportCommands()
David Pursellf1c27c12015-03-18 09:51:38 -0700126
127 load_mock.assert_called_with(module_path)
128
David Pursellffb90042015-03-23 09:21:41 -0700129 def testListCrosCommands(self):
130 """Tests we get a sane `cros` list back."""
David Pursellc7ba7842015-07-08 10:48:41 -0700131 cros_commands = command.ListCommands()
David Pursellf1c27c12015-03-18 09:51:38 -0700132 # Pick some commands that are likely to not go away.
133 self.assertIn('chrome-sdk', cros_commands)
134 self.assertIn('flash', cros_commands)
David Pursellffb90042015-03-23 09:21:41 -0700135
Ralph Nathan74e864d2015-05-11 12:13:53 -0700136
137class FileLoggerSetupTest(cros_test_lib.WorkspaceTestCase):
138 """Test that logging to file works correctly."""
139
140 def setUp(self):
141 self.CreateWorkspace()
142
143 def testSetupFileLoggerFilename(self):
144 """Test that the filename and path are correct."""
145 patch_handler = self.PatchObject(logging, 'FileHandler',
146 return_value=logging.StreamHandler())
147 command.SetupFileLogger(filename='foo.log')
148
149 # Test that the filename is correct.
150 patch_handler.assert_called_with(
Ralph Nathan7a0bae22015-05-13 10:49:54 -0700151 os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR,
152 'foo.log'), mode='w')
Ralph Nathan74e864d2015-05-11 12:13:53 -0700153
154 def testSetupFileLoggerNoFilename(self):
155 """Test that the filename and path are correct with no arguments."""
156 patch_handler = self.PatchObject(logging, 'FileHandler',
157 return_value=logging.StreamHandler())
158 command.SetupFileLogger()
159
160 # Test that the filename is correct.
161 patch_handler.assert_called_with(
Ralph Nathan7a0bae22015-05-13 10:49:54 -0700162 os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR,
163 'brillo.log'), mode='w')
Ralph Nathan74e864d2015-05-11 12:13:53 -0700164
165 def testSetupFileLoggerLogLevels(self):
166 """Test that the logger operates at the right level."""
167 command.SetupFileLogger('foo.log', log_level=logging.INFO)
168 logging.getLogger().setLevel(logging.DEBUG)
169 logging.debug('debug')
170 logging.info('info')
171 logging.notice('notice')
172
173 # Test that the logs are correct.
174 logs = open(
Ralph Nathan7a0bae22015-05-13 10:49:54 -0700175 os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR,
176 'foo.log'), 'r').read()
Ralph Nathan74e864d2015-05-11 12:13:53 -0700177 self.assertNotIn('debug', logs)
178 self.assertIn('info', logs)
179 self.assertIn('notice', logs)