# Copyright 2011 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import os.path import re from gslib.command import Command from gslib.command import COMMAND_NAME from gslib.command import COMMAND_NAME_ALIASES from gslib.command import CONFIG_REQUIRED from gslib.command import FILE_URIS_OK from gslib.command import MAX_ARGS from gslib.command import MIN_ARGS from gslib.command import PROVIDER_URIS_OK from gslib.command import SUPPORTED_SUB_ARGS from gslib.command import URIS_START_ARG from gslib.exception import CommandException from gslib.help_provider import HELP_NAME from gslib.help_provider import HELP_NAME_ALIASES from gslib.help_provider import HELP_ONE_LINE_SUMMARY from gslib.help_provider import HELP_TEXT from gslib.help_provider import HELP_TYPE from gslib.help_provider import HelpType import gslib.tests as tests from gslib.util import NO_MAX # For Python 2.6, unittest2 is required to run the tests. If it's not available, # display an error if the test command is run instead of breaking the whole # program. try: from gslib.tests.util import unittest except ImportError as e: if 'unittest2' in str(e): unittest = None else: raise COMMANDS_DIR = os.path.abspath(os.path.dirname(__file__)) GSLIB_DIR = os.path.split(COMMANDS_DIR)[0] TESTS_DIR = os.path.join(GSLIB_DIR, 'tests') _detailed_help_text = (""" SYNOPSIS gsutil test [command command...] DESCRIPTION The gsutil test command runs the gsutil unit tests and integration tests. The unit tests use an in-memory mock storage service implementation, while the integration tests send requests to the production service. To run both the unit tests and integration tests, run the command with no arguments: gsutil test To run the unit tests only (which run quickly): gsutil test -u To see additional details for test failures: gsutil -d test To have the tests stop running immediately when an error occurs: gsutil test -f To run tests for one or more individual commands add those commands as arguments. For example, the following command will run the cp and mv command tests: gsutil test cp mv To list available tests, run the test command with the -l argument: gsutil test -l Note: the tests are defined in the code under the gslib/tests module. Each test file is of the format test_[name].py where [name] is the test name you can pass to this command. For example, running "gsutil test ls" would run the tests in "gslib/tests/test_ls.py". """) def MakeCustomTestResultClass(total_tests): """Creates a closure of CustomTestResult. Args: total_tests: The total number of tests being run. Returns: An instance of CustomTestResult. """ class CustomTestResult(unittest.TextTestResult): """A subclass of unittest.TextTestResult that prints a progress report.""" def startTest(self, test): super(CustomTestResult, self).startTest(test) if self.dots: id = '.'.join(test.id().split('.')[-2:]) message = ('\r%d/%d finished - E[%d] F[%d] s[%d] - %s' % ( self.testsRun, total_tests, len(self.errors), len(self.failures), len(self.skipped), id)) message = message[:73] message = message.ljust(73) self.stream.write('%s - ' % message) return CustomTestResult class TestCommand(Command): """Implementation of gsutil test command.""" # Command specification (processed by parent class). command_spec = { # Name of command. COMMAND_NAME: 'test', # List of command name aliases. COMMAND_NAME_ALIASES: [], # Min number of args required by this command. MIN_ARGS: 0, # Max number of args required by this command, or NO_MAX. MAX_ARGS: NO_MAX, # Getopt-style string specifying acceptable sub args. SUPPORTED_SUB_ARGS: 'ufl', # True if file URIs acceptable for this command. FILE_URIS_OK: True, # True if provider-only URIs acceptable for this command. PROVIDER_URIS_OK: False, # Index in args of first URI arg. URIS_START_ARG: 0, # True if must configure gsutil before running command. CONFIG_REQUIRED: True, } help_spec = { # Name of command or auxiliary help info for which this help applies. HELP_NAME: 'test', # List of help name aliases. HELP_NAME_ALIASES: [], # Type of help: HELP_TYPE: HelpType.COMMAND_HELP, # One line summary of this help. HELP_ONE_LINE_SUMMARY: 'Run gsutil tests', # The full help text. HELP_TEXT: _detailed_help_text, } # Command entry point. def RunCommand(self): if not unittest: raise CommandException('On Python 2.6, the unittest2 module is required ' 'to run the gsutil tests.') failfast = False list_tests = False if self.sub_opts: for o, _ in self.sub_opts: if o == '-u': tests.util.RUN_INTEGRATION_TESTS = False elif o == '-f': failfast = True elif o == '-l': list_tests = True if list_tests: test_files = os.listdir(TESTS_DIR) matcher = re.compile(r'^test_(?P.*).py$') test_names = [] for fname in test_files: m = matcher.match(fname) if m: test_names.append(m.group('name')) print 'Found %d test names:' % len(test_names) print ' ', '\n '.join(sorted(test_names)) return 0 # Set list of commands to test if supplied. commands_to_test = [] if self.args: for name in self.args: test_file = os.path.join(TESTS_DIR, 'test_%s.py' % name) if not os.path.exists(test_file): raise CommandException('The requested test, "%s", was not found at ' '"%s".' % (name, test_file)) commands_to_test.append('gslib.tests.test_%s' % name) # Installs a ctrl-c handler that tries to cleanly tear down tests. unittest.installHandler() loader = unittest.TestLoader() if commands_to_test: suite = loader.loadTestsFromNames(commands_to_test) else: suite = loader.discover(TESTS_DIR) if logging.getLogger().getEffectiveLevel() <= logging.INFO: verbosity = 2 else: verbosity = 1 logging.disable(logging.ERROR) total_tests = suite.countTestCases() resultclass = MakeCustomTestResultClass(total_tests) runner = unittest.TextTestRunner(verbosity=verbosity, resultclass=resultclass, failfast=failfast) ret = runner.run(suite) if ret.wasSuccessful(): return 0 return 1