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
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)
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 )
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])
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.')
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
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] )
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)
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)
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 )
def test_get_unknown(self): test_name = self.__test_name() self.assertEqual( None, os_env_var(test_name).value )
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 )
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 )
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 )
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 )
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
def test_get_unknown_path(self): test_name = self.__test_name() self.assertEqual( [], os_env_var(test_name).path )
def test_get_environ(self): test_name = self.__test_name() os.environ[test_name] = 'FOO' self.assertEqual( 'FOO', os_env_var(test_name).value )
def test_get(self): test_name = self.__test_name() v = os_env_var(test_name) v.value = 'FOO' self.assertEqual( 'FOO', v.value )
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] )