Exemplo n.º 1
0
 def shell_is_bash(clazz):
     'Return True if the current shell is bash.'
     v = os_env_var('SHELL')
     if v.is_set:
         return 'bash' in v.value
     v = os_env_var('BASH')
     if v.is_set:
         return 'bash' in v.value
     return False
Exemplo n.º 2
0
 def resolve_env_vars(clazz, value):
   if not check.is_string(value):
     return value
   variables = variable.find_variables(value)
   substitutions = {}
   for var in variables:
     os_var = os_env_var(var)
     if not os_var.is_set:
       raise ValueError('not set in the current environment: {}'.format(var))
     substitutions[var] = os_var.value
   return variable.substitute(value, substitutions)
Exemplo n.º 3
0
  def test_extract_alpine_linux_with_docker(self):
    tmp_tar_exe_dir = self.make_temp_dir()
    fail_flag_file = self.make_temp_file(content = 'foo', suffix = '.flag')
    
    fake_tar_content = '''\
#!/bin/bash
${_BES_TAR_EXE} ${1+"$@"}
if [[ -f ${_BES_TAR_FAIL_FLAG} ]]; then
  rm -f ${_BES_TAR_FAIL_FLAG}
  exit 2
fi
rv=$?
exit ${rv}
'''
    tar_exe = file_util.save(path.join(tmp_tar_exe_dir, 'tar'), content = fake_tar_content, mode = 0o0755)
    
    tmp_dir = self.make_temp_dir()
    
    old_path = os_env_var
    with env_override(env = { '_BES_TAR_EXE': tar_util.tar_exe(), '_BES_TAR_FAIL_FLAG': fail_flag_file }) as over:
      os_env_var('PATH').prepend(tmp_tar_exe_dir)
      tar_util.extract(self.data_path('test.tar'), tmp_dir)
      
    expected_files = [
      self.native_filename('1'),
      self.native_filename('1/2'),
      self.native_filename('1/2/3'),
      self.native_filename('1/2/3/4'),
      self.native_filename('1/2/3/4/5'),
      self.native_filename('1/2/3/4/5/apple.txt'),
      self.native_filename('1/2/3/4/5/kiwi.txt'),
      self.native_filename('bar.txt'),
      self.native_filename('empty'),
      self.native_filename('foo.txt'),
      self.native_filename('kiwi_link.txt'),
    ]
    actual_files = file_find.find(tmp_dir, file_type = file_find.ANY)
    self.assertEqual( expected_files, actual_files )
Exemplo n.º 4
0
    def page(clazz, filename):
        'Page a file with ${PAGER}'
        check.check_string(filename)

        if not path.exists(filename):
            raise RuntimeError('Not found: "{}"'.format(filename))
        v = os_env_var('PAGER')
        if v.is_set:
            pager = which.which(v.value)
        else:
            pager = which.which('less') or which.which('more')
        if not pager:
            raise RuntimeError('Pager not found')
        subprocess.call([pager, filename])
Exemplo n.º 5
0
 def _find_egoist(clazz):
     v = os_env_var('EGOIST')
     if v.is_set:
         if not path.exists(v.value):
             raise RuntimeError('${EGOIST} not found: {}'.format(v.value))
         if not file_path.is_executable(v.value):
             raise RuntimeError('${EGOIST} not an executable: {}'.format(
                 v.value))
         return v.value
     for possible_egoist in ['egoist', 'egoist2.py', 'egoist3.py']:
         egoist = which.which(possible_egoist, raise_error=False)
         if egoist:
             return egoist
     raise RuntimeError(
         'egoist not found in either the environment or PATH.')
Exemplo n.º 6
0
 def _substitutions_for_value(self, v, variables, origin):
   result = {}
   for var in variables:
     os_var = os_env_var(var)
     found = False
     if os_var.is_set:
       value = os_var.value
       found = True
     else:
       if var in self.variables_:
         value = self.variables_[var]
         found = True
       elif var in self.parent_variables_:
         value = self.parent_variables_[var]
         found = True
     if not found:  
       raise simple_config_error('Not set in the current environment: "{}"'.format(v), origin)
     result[var] = value
   return result
Exemplo n.º 7
0
 def test_set_path(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.path = [ 'FOO', 'BAR' ]
   self.assertEqual( 'FOO%sBAR' % (os.pathsep), os.environ[test_name] )
Exemplo n.º 8
0
 def auth(self):
   username = self.username or os_env_var('BES_VMWARE_USERNAME').value_if_set
   password = self.password or os_env_var('BES_VMWARE_PASSWORD').value_if_set
   return credentials('<cli>', username = username, password = password)
Exemplo n.º 9
0
 def find_tar_in_env_path(clazz, flavor):
     # Always include the DEFAULT_SYSTEM_PATH to guarantee checking the usual dirs.
     env_path = os_env.DEFAULT_SYSTEM_PATH.split(
         os.pathsep) + os_env_var('PATH').path
     return clazz.find_tar(env_path, flavor)
Exemplo n.º 10
0
 def test_prepend_duplicate(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.path = [ 'FOO', 'BAR', 'BAZ' ]
   v.prepend('BAR')
   self.assertEqual( [ 'BAR', 'FOO', 'BAZ' ], os_env_var(test_name).path )
Exemplo n.º 11
0
 def test_get_unknown(self):
   test_name = self.__test_name()
   self.assertEqual( None, os_env_var(test_name).value )
Exemplo n.º 12
0
 def test_set_path_with_cleanup(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.path = [ 'FOO', 'BAR', 'FOO' ]
   self.assertEqual( [ 'FOO', 'BAR' ], os_env_var(test_name).path )
Exemplo n.º 13
0
 def test_append(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.path = [ 'FOO', 'BAR' ]
   v.append('BAZ')
   self.assertEqual( [ 'FOO', 'BAR', 'BAZ' ], os_env_var(test_name).path )
Exemplo n.º 14
0
 def test_get_path(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.path = [ 'FOO', 'BAR' ]
   self.assertEqual( [ 'FOO', 'BAR' ], v.path )
Exemplo n.º 15
0
 def test_get_environ_path(self):
   test_name = self.__test_name()
   os.environ[test_name] = self.native_path('FOO:BAR')
   self.assertEqual( [ 'FOO', 'BAR' ], os_env_var(test_name).path )
Exemplo n.º 16
0
def main():
    DEBUG = os.environ.get('DEBUG', False)

    import bes
    vcli = version_cli(bes)
    parser = argparse.ArgumentParser()
    parser.add_argument('files',
                        action='store',
                        nargs='*',
                        help='Files or directories to rename')
    vcli.version_add_arguments(parser)
    parser.add_argument('--dry-run',
                        '-n',
                        action='store_true',
                        default=False,
                        help='Only print what files will get tests [ False ]')
    parser.add_argument(
        '--timing',
        '-t',
        action='store_true',
        default=False,
        help='Show the amount of time it takes to run tests [ False ]')
    parser.add_argument('--verbose',
                        '-v',
                        action='store_true',
                        default=False,
                        help='Verbose debug output [ False ]')
    parser.add_argument('--stop',
                        '-s',
                        action='store_true',
                        default=False,
                        help='Stop right after the first failure. [ False ]')
    parser.add_argument(
        '--randomize',
        action='store_true',
        default=False,
        help='Randomize the order in which unit tests run. [ False ]')
    parser.add_argument(
        '--python',
        action='append',
        default=[],
        help=
        'Python executable) to use.  Multiple flags can be used for running with mutiple times with different python versions [ python ]'
    )
    parser.add_argument('--page',
                        '-p',
                        action='store_true',
                        default=False,
                        help='Page output with $PAGER [ False ]')
    parser.add_argument(
        '--profile',
        action='store',
        default=None,
        help=
        'Profile the code with cProfile and store the output in the given argument [ None ]'
    )
    parser.add_argument(
        '--coverage',
        action='store',
        default=None,
        help=
        'Run coverage on the code and store the output in the given argument [ None ]'
    )
    parser.add_argument('--pager',
                        action='store',
                        default=os.environ.get('PAGER', 'more'),
                        help='Pager to use when paging [ %s ]' %
                        (os.environ.get('PAGER', 'more')))
    parser.add_argument('--iterations',
                        '-i',
                        action='store',
                        default=1,
                        type=int,
                        help='Python executable to use [ python ]')
    parser.add_argument(
        '--git',
        '-g',
        action='store_true',
        default=False,
        help='Use git status to figure out what has changed to test [ False ]')
    parser.add_argument(
        '--commit',
        '-c',
        action='store',
        type=str,
        default=None,
        help='Test only the files affected by the given git commit [ None ]')
    parser.add_argument('--pre-commit',
                        action='store_true',
                        default=False,
                        help='Run pre commit checks [ False ]')
    parser.add_argument('--print-tests',
                        action='store_true',
                        default=False,
                        help='Print the list of unit tests [ False ]')
    parser.add_argument('--print-python',
                        action='store_true',
                        default=False,
                        help='Print the detected python executable [ False ]')
    parser.add_argument('--print-files',
                        action='store_true',
                        default=False,
                        help='Print the list of unit files [ False ]')
    parser.add_argument(
        '--egg',
        action='store_true',
        default=False,
        help=
        'Make an egg of the package and run the tests against that instead the live files. [ False ]'
    )
    parser.add_argument(
        '--save-egg',
        action='store_true',
        default=False,
        help='Save the egg in the current directory. [ False ]')
    parser.add_argument('--ignore',
                        action='append',
                        default=[],
                        help='Patterns of filenames to ignore []')
    parser.add_argument(
        '--root-dir',
        action='store',
        default=None,
        help=
        'The root directory for all your projets.  By default its computed from your git struture.  [ None ]'
    )
    parser.add_argument('--dont-hack-env',
                        action='store_true',
                        default=False,
                        help='Dont hack PATH and PYTHONPATH. [ False ]')
    parser.add_argument(
        '--compile-only',
        action='store_true',
        default=False,
        help='Just compile the files to verify syntax [ False ]')
    parser.add_argument(
        '--print-deps',
        action='store_true',
        default=False,
        help='Print python dependencies for test files [ False ]')
    parser.add_argument('--print-configs',
                        action='store_true',
                        default=False,
                        help='Print testing configs found [ False ]')
    parser.add_argument('--print-root-dir',
                        action='store_true',
                        default=False,
                        help='Print the root dir [ False ]')
    parser.add_argument('--print-path',
                        action='store_true',
                        default=False,
                        help='Print sys.path [ False ]')
    parser.add_argument(
        '--file-ignore-file',
        action='append',
        default=[],
        help=
        'List of file ignore files. [ .bes_test_ignore .bes_test_internal_ignore ]'
    )
    parser.add_argument('--env',
                        action='append',
                        default=[],
                        help='Environment variables to set [ None ]')
    parser.add_argument('--no-env-deps',
                        action='store_true',
                        default=False,
                        help='Dont use env deps. [ False ]')
    parser.add_argument(
        '--temp-dir',
        action='store',
        default=None,
        help=
        'The directory to use for tmp files overriding the system default.  [ None ]'
    )
    parser.add_argument(
        '--keep-side-effects',
        action='store_true',
        default=DEBUG,
        help='Dont delete side effects - for debugging. [ False ]')
    parser.add_argument(
        '--ignore-side-effects',
        action='store_true',
        default=DEBUG,
        help='Dont delete side effects - for debugging. [ False ]')

    found_git_exe = git_exe.find_git_exe()
    if not found_git_exe:
        printer.writeln_name(
            'ERROR: No git found.  Git is needed to run bes_test.')
        return 1

    for g in parser._action_groups:
        g._group_actions.sort(key=lambda x: x.dest)

    args = parser.parse_args()

    args.python = _resolve_python_exe_list(args.python)

    if not args.python:
        python_exe = python.find_python_exe()
        if python_exe:
            args.python = [python_exe]

    if not args.python:
        printer.writeln_name(
            'ERROR: No python found.  Python is needed to run bes_test.')
        return 1

    _LOG.log_d('using python={}'.format(args.python))

    if args.git and args.commit:
        printer.writeln_name(
            'ERROR: Only one of --git or --commit can be given.')
        return 1

    if args.temp_dir:
        file_util.mkdir(args.temp_dir)
        tempfile.tempdir = args.temp_dir

    if DEBUG:
        args.verbose = True

    cwd = os.getcwd()

    if args.version:
        vcli.version_print_version()
        return 0

    args.env = _parse_args_env(args.env)

    if not args.files:
        args.files = [cwd]

    if not args.file_ignore_file:
        args.file_ignore_file = [
            '.bes_test_ignore', '.bes_test_internal_ignore'
        ]

    if args.commit:
        if args.commit in ['HEAD', 'last']:
            args.commit = git.last_commit_hash('.')

    ar = argument_resolver(cwd,
                           args.files,
                           root_dir=args.root_dir,
                           file_ignore_filename=args.file_ignore_file,
                           check_git=args.git,
                           git_commit=args.commit,
                           use_env_deps=not args.no_env_deps)
    ar.num_iterations = args.iterations
    ar.randomize = args.randomize

    ar.ignore_with_patterns(args.ignore)

    if args.compile_only:
        total_files = len(ar.all_files)
        for i, f in enumerate(ar.all_files):
            tmp = temp_file.make_temp_file()
            filename_count_blurb = ' ' + _make_count_blurb(i + 1, total_files)
            short_filename = file_util.remove_head(f, cwd)
            blurb = '%7s:%s %s ' % ('compile', filename_count_blurb,
                                    short_filename)
            printer.writeln_name(blurb)
            py_compile.compile(f, cfile=tmp, doraise=True)
        return 0

    if not ar.test_descriptions:
        return 1

    if args.print_python:
        for python_exe in args.python:
            print(python_exe)
        return 0

    if args.print_path:
        for p in sys.path:
            print(p)
        return 0

    if args.print_configs:
        ar.print_configs()
        return 0

    if args.print_root_dir:
        print(ar.root_dir)
        return 0

    if args.print_files:
        ar.print_files()
        return 0

    if args.print_tests:
        ar.print_tests()
        return 0

    if args.print_deps or args.pre_commit and not ar.supports_test_dependency_files(
    ):
        printer.writeln_name(
            'ERROR: Cannot figure out dependencies.  snakefood missing.')
        return 1

    if args.print_deps:
        dep_files = ar.test_dependency_files()
        for filename in sorted(dep_files.keys()):
            print(filename)
            for dep_file in dep_files[filename]:
                print('  %s' % (dep_file.filename))
        return 0

    # Read ~/.bes_test/bes_test.config (or use a default config)
    bes_test_config = _read_config_file()
    keep_patterns = bes_test_config.get_value_string_list(
        'environment', 'keep_patterns')

    # Start with a clean environment so unit testing can be deterministic and not subject
    # to whatever the user happened to have exported.  PYTHONPATH and PATH for dependencies
    # are set below by iterating the configs
    keep_keys = bes_test_config.get_value_string_list('environment',
                                                      'keep_keys')
    if args.dont_hack_env:
        keep_keys.extend(['PATH', 'PYTHONPATH'])

    keep_keys.extend(['TMPDIR', 'TEMP', 'TMP'])
    env = os_env.make_clean_env(
        keep_keys=keep_keys,
        keep_func=lambda key: _env_var_should_keep(key, keep_patterns))
    env_var(env, 'PATH').prepend(path.dirname(found_git_exe))
    for python_exe in args.python:
        env_var(env, 'PATH').prepend(path.dirname(python_exe))
    env['PYTHONDONTWRITEBYTECODE'] = 'x'

    variables = {
        'rebuild_dir': path.expanduser('~/.rebuild'),
        'system': host.SYSTEM,
    }

    if not args.dont_hack_env:
        for var in ar.env_dependencies_variables():
            ov = os_env_var(var)
            if ov.is_set:
                value = ov.value
            else:
                value = ''
            variables[var] = value
        ar.update_environment(env, variables)

    # Update env with whatever was given in --env
    env.update(args.env)

    # Use a custom TMP dir so that we can catch temporary side effects and flag them
    tmp_tmp = temp_file.make_temp_dir(prefix='bes_test_',
                                      suffix='.tmp.tmp.dir',
                                      delete=False)
    env.update({
        'TMPDIR': tmp_tmp,
        'TEMP': tmp_tmp,
        'TMP': tmp_tmp,
    })
    side_effects = {}

    num_passed = 0
    num_failed = 0
    num_executed = 0
    num_tests = len(ar.test_descriptions)
    failed_tests = []

    # Remove current dir from sys.path to avoid side effects
    if cwd in sys.path:
        sys.path.remove(cwd)

    if args.egg:
        pythonpath = env_var(env, 'PYTHONPATH')
        pythonpath.remove(cwd)
        for config in ar.env_dependencies_configs:
            setup_dot_py = path.join(config.root_dir, 'setup.py')
            if not path.isfile(setup_dot_py):
                raise RuntimeError('No setup.py found in %s to make the egg.' %
                                   (cwd))
            egg_zip = egg.make(config.root_dir,
                               'master',
                               setup_dot_py,
                               untracked=False)
            pythonpath.prepend(egg_zip)
            printer.writeln_name('using tmp egg: %s' % (egg_zip))
            if args.save_egg:
                file_util.copy(egg_zip, path.join(cwd, path.basename(egg_zip)))

    if args.pre_commit:
        missing_from_git = []
        for filename, dep_files in ar.test_dependency_files().items():
            for dep_file in dep_files:
                if dep_file.config and not dep_file.git_tracked:
                    missing_from_git.append(dep_file.filename)
        if missing_from_git:
            for f in missing_from_git:
                printer.writeln_name('PRE_COMMIT: missing from git: %s' %
                                     (path.relpath(f)))
            return 1
        return 0

    ar.cleanup_python_compiled_files()

    # Do all our work with a temporary working directory to be able to check for side effects
    tmp_cwd = temp_file.make_temp_dir(prefix='bes_test_',
                                      suffix='.tmp.cwd.dir',
                                      delete=False)
    tmp_home = temp_file.make_temp_dir(prefix='bes_test_',
                                       suffix='.tmp.home.dir',
                                       delete=False)
    os.environ['HOME'] = tmp_home
    os.chdir(tmp_cwd)

    # Use what the OS thinks the path is (to deal with symlinks and virtual tmpfs things)
    tmp_cwd = os.getcwd()

    if not args.dry_run and args.page:
        printer.OUTPUT = tempfile.NamedTemporaryFile(prefix='bes_test',
                                                     delete=True,
                                                     mode='w')

    total_tests = _count_tests(ar.inspect_map, ar.test_descriptions)
    total_files = len(ar.test_descriptions)

    total_num_tests = 0

    if args.profile:
        args.profile = path.abspath(args.profile)
        if not _check_program('cprofilev'):
            return 1

    if args.coverage:
        args.coverage = path.abspath(args.coverage)
        coverage_exe = _check_program('coverage')
        if not coverage_exe:
            return 1
        args.python = [coverage_exe]

    if args.profile and args.coverage:
        printer.writeln_name(
            'ERROR: --profile and --coverage are mutually exclusive.')
        return 1

    options = test_options(args.dry_run, args.verbose, args.stop, args.timing,
                           args.profile, args.coverage, args.python,
                           args.temp_dir, tmp_home)

    timings = {}

    total_time_start = time.time()

    stopped = False
    for i, test_desc in enumerate(ar.test_descriptions):
        file_info = test_desc.file_info
        filename = file_info.filename
        if not filename in timings:
            timings[filename] = []
        for python_exe in args.python:
            result = _test_execute(python_exe, ar.inspect_map, filename,
                                   test_desc.tests, options, i + 1,
                                   total_files, cwd, env)
            _collect_side_effects(side_effects, filename, tmp_home, 'home',
                                  args.keep_side_effects)
            _collect_side_effects(side_effects, filename, tmp_tmp, 'tmp',
                                  args.keep_side_effects)
            _collect_side_effects(side_effects, filename, os.getcwd(), 'cwd',
                                  args.keep_side_effects)
            timings[filename].append(result.elapsed_time)
            total_num_tests += result.num_tests_run
            num_executed += 1
            if result.success:
                num_passed += 1
            else:
                num_failed += 1
                failed_tests.append((python_exe, filename, result))
            if args.stop and not result.success:
                stopped = True
        if stopped:
            break
    total_elapsed_time = 1000 * (time.time() - total_time_start)

    if args.dry_run:
        return 0
    num_skipped = num_tests - num_executed
    summary_parts = []

    if total_num_tests == total_tests:
        function_summary = '(%d %s)' % (total_tests,
                                        _make_test_string(total_tests))
    else:
        function_summary = '(%d of %d %s)' % (total_num_tests, total_tests,
                                              _make_test_string(total_tests))

    if num_failed > 0:
        summary_parts.append('%d of %d fixtures FAILED' %
                             (num_failed, num_tests))
    summary_parts.append('%d of %d passed %s' %
                         (num_passed, num_tests, function_summary))
    if num_skipped > 0:
        summary_parts.append('%d of %d skipped' % (num_skipped, num_tests))

    summary = '; '.join(summary_parts)
    printer.writeln_name('%s' % (summary))
    if failed_tests:
        longest_python_exe = max(
            [len(path.basename(p)) for p in options.interpreters])
        for python_exe, filename, result in failed_tests:
            if len(options.interpreters) > 1:
                python_exe_blurb = path.basename(python_exe).rjust(
                    longest_python_exe)
            else:
                python_exe_blurb = ''
            error_status = unit_test_output.error_status(result.output)
            for error in error_status.errors:
                printer.writeln_name('%5s: %s %s :%s.%s' %
                                     (error.error_type, python_exe_blurb,
                                      file_util.remove_head(filename, cwd),
                                      error.fixture, error.function))

    if num_failed > 0:
        rv = 1
    else:
        rv = 0

    if args.timing:
        filenames = sorted(timings.keys())
        num_filenames = len(filenames)
        for i, filename in zip(range(0, num_filenames), filenames):
            short_filename = file_util.remove_head(filename, cwd)
            all_timings = timings[filename]
            num_timings = len(all_timings)
            avg_ms = _timing_average(all_timings) * 1000.0
            if num_timings > 1:
                run_blurb = '(average of %d runs)' % (num_timings)
            else:
                run_blurb = ''
            if num_filenames > 1:
                count_blurb = '[%s of %s] ' % (i + 1, num_filenames)
            else:
                count_blurb = ''

            printer.writeln_name(
                'timing: %s%s - %2.2f ms %s' %
                (count_blurb, short_filename, avg_ms, run_blurb))
        if total_elapsed_time >= 1000.0:
            printer.writeln_name('total time: %2.2f s' %
                                 (total_elapsed_time / 1000.0))
        else:
            printer.writeln_name('total time: %2.2f ms' % (total_elapsed_time))

    if args.page:
        subprocess.call([args.pager, printer.OUTPUT.name])

    current_cwd = os.getcwd()
    if current_cwd != tmp_cwd:
        rv = 1
        printer.writeln_name(
            'SIDE EFFECT: working directory was changed from %s to %s' %
            (tmp_cwd, current_cwd))

    if not args.ignore_side_effects:
        for test, items in sorted(side_effects.items()):
            for item in items:
                rv = 1
                filename = item.filename
                print('SIDE EFFECT [{}] {} {}'.format(
                    item.label, test.replace(cwd + os.sep, ''), filename))

    os.chdir('/tmp')

    if not args.keep_side_effects:
        file_util.remove(tmp_cwd)
        file_util.remove(tmp_home)
        file_util.remove(tmp_tmp)

    return rv
Exemplo n.º 17
0
 def test_get_unknown_path(self):
   test_name = self.__test_name()
   self.assertEqual( [], os_env_var(test_name).path )
Exemplo n.º 18
0
 def test_get_environ(self):
   test_name = self.__test_name()
   os.environ[test_name] = 'FOO'
   self.assertEqual( 'FOO', os_env_var(test_name).value )
Exemplo n.º 19
0
 def test_get(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.value = 'FOO'
   self.assertEqual( 'FOO', v.value )
Exemplo n.º 20
0
 def test_set(self):
   test_name = self.__test_name()
   v = os_env_var(test_name)
   v.value = 'FOO'
   self.assertEqual( 'FOO', os.environ[test_name] )