# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Tests for the command module.""" from __future__ import print_function import argparse import glob import os from chromite.cbuildbot import constants from chromite.cli import command from chromite.lib import commandline from chromite.lib import cros_build_lib_unittest from chromite.lib import cros_import from chromite.lib import cros_logging as logging from chromite.lib import cros_test_lib from chromite.lib import partial_mock from chromite.lib import workspace_lib # pylint:disable=protected-access _COMMAND_NAME = 'superAwesomeCommandOfFunness' @command.CommandDecorator(_COMMAND_NAME) class TestCommand(command.CliCommand): """A fake command.""" def Run(self): print('Just testing') class TestCommandTest(cros_test_lib.MockTestCase): """This test class tests that Commands method.""" def testParserSetsCommandClass(self): """Tests that our parser sets command_class correctly.""" my_parser = argparse.ArgumentParser() command.CliCommand.AddParser(my_parser) ns = my_parser.parse_args([]) self.assertEqual(ns.command_class, command.CliCommand) def testCommandDecorator(self): """Tests that our decorator correctly adds TestCommand to _commands.""" # Note this exposes an implementation detail of _commands. self.assertEqual(command._commands[_COMMAND_NAME], TestCommand) def testBadUseOfCommandDecorator(self): """Tests that our decorator correctly rejects bad test commands.""" try: # pylint: disable=W0612 @command.CommandDecorator('bad') class BadTestCommand(object): """A command that wasn't implemented correctly.""" pass except command.InvalidCommandError: pass else: self.fail('Invalid command was accepted by the CommandDecorator') def testAddDeviceArgument(self): """Tests CliCommand.AddDeviceArgument().""" parser = argparse.ArgumentParser() command.CliCommand.AddDeviceArgument(parser) # Device should be a positional argument. parser.parse_args(['device']) class MockCommand(partial_mock.PartialMock): """Mock class for a generic CLI command.""" ATTRS = ('Run',) COMMAND = None TARGET_CLASS = None def __init__(self, args, base_args=None): partial_mock.PartialMock.__init__(self) self.args = args self.rc_mock = cros_build_lib_unittest.RunCommandMock() self.rc_mock.SetDefaultCmdResult() parser = commandline.ArgumentParser(caching=True) subparsers = parser.add_subparsers() subparser = subparsers.add_parser(self.COMMAND, caching=True) self.TARGET_CLASS.AddParser(subparser) args = base_args if base_args else [] args += [self.COMMAND] + self.args options = parser.parse_args(args) self.inst = options.command_class(options) def Run(self, inst): with self.rc_mock: return self.backup['Run'](inst) class CommandTest(cros_test_lib.MockTestCase): """This test class tests that we can load modules correctly.""" # pylint: disable=W0212 def testFindModules(self): """Tests that we can return modules correctly when mocking out glob.""" fake_command_file = 'cros_command_test.py' filtered_file = 'cros_command_unittest.py' mydir = 'mydir' self.PatchObject(glob, 'glob', return_value=[fake_command_file, filtered_file]) self.assertEqual(command._FindModules(mydir), [fake_command_file]) def testLoadCommands(self): """Tests import commands correctly.""" fake_module = 'cros_command_test' fake_command_file = os.path.join(constants.CHROMITE_DIR, 'foo', fake_module) module_path = ['chromite', 'foo', fake_module] self.PatchObject(command, '_FindModules', return_value=[fake_command_file]) # The code doesn't use the return value, so stub it out lazy-like. load_mock = self.PatchObject(cros_import, 'ImportModule', return_value=None) command._ImportCommands() load_mock.assert_called_with(module_path) def testListCrosCommands(self): """Tests we get a sane `cros` list back.""" cros_commands = command.ListCommands() # Pick some commands that are likely to not go away. self.assertIn('chrome-sdk', cros_commands) self.assertIn('flash', cros_commands) class FileLoggerSetupTest(cros_test_lib.WorkspaceTestCase): """Test that logging to file works correctly.""" def setUp(self): self.CreateWorkspace() def testSetupFileLoggerFilename(self): """Test that the filename and path are correct.""" patch_handler = self.PatchObject(logging, 'FileHandler', return_value=logging.StreamHandler()) command.SetupFileLogger(filename='foo.log') # Test that the filename is correct. patch_handler.assert_called_with( os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR, 'foo.log'), mode='w') def testSetupFileLoggerNoFilename(self): """Test that the filename and path are correct with no arguments.""" patch_handler = self.PatchObject(logging, 'FileHandler', return_value=logging.StreamHandler()) command.SetupFileLogger() # Test that the filename is correct. patch_handler.assert_called_with( os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR, 'brillo.log'), mode='w') def testSetupFileLoggerLogLevels(self): """Test that the logger operates at the right level.""" command.SetupFileLogger('foo.log', log_level=logging.INFO) logging.getLogger().setLevel(logging.DEBUG) logging.debug('debug') logging.info('info') logging.notice('notice') # Test that the logs are correct. logs = open( os.path.join(self.workspace_path, workspace_lib.WORKSPACE_LOGS_DIR, 'foo.log'), 'r').read() self.assertNotIn('debug', logs) self.assertIn('info', logs) self.assertIn('notice', logs)