def __init__(self): """Initialise the helper plugin.""" # Nose has attrib plugin which works as expected but isn't passed the # tests generated from features. Create a local copy which will be used # to veto the tests. super().__init__() self.attrib_plugin = AttributeSelector()
def test_basic_attr(self): def f(): pass f.a = 1 def g(): pass plug = AttributeSelector() plug.attribs = [[('a', True)]] assert plug.wantFunction(f) is not False assert not plug.wantFunction(g)
def test_class_attr(self): class TestP: foo = True def h(): pass def i(): pass plug = AttributeSelector() plug.attribs = [[('foo', True)]] assert plug.wantMethod(unbound_method(TestP, TestP.h)) is not False assert plug.wantFunction(i) is False
def configure(self, options, noseconfig): super(ITE, self).configure(options, noseconfig) if not self.enabled: return self.curdir = os.getcwd() noseconfig.testMatch = re.compile('$^') self.attr_plugin = AttributeSelector() self.attr_plugin.configure(noseconfig.options, noseconfig) if os.getuid() == 0: os.setegid(self.options.gid) os.seteuid(self.options.uid)
def run_test(): nose.main(addplugins=[ AutotestClientTestRunner(), AttributeSelector(), Xunit(), Coverage() ])
def test_eval_attr(self): if not compat_24: warn("No support for eval attributes in python versions older" " than 2.4") return def f(): pass f.monkey = 2 def g(): pass g.monkey = 6 def h(): pass h.monkey = 5 cnf = Config() opt = Bucket() opt.eval_attr = "monkey > 5" plug = AttributeSelector() plug.configure(opt, cnf) assert not plug.wantFunction(f) assert plug.wantFunction(g) is not False assert not plug.wantFunction(h)
class AttributePluginTester(PluginTester, unittest.TestCase): plugins = [AttributeSelector()] suitepath = os.path.join(support, 'att') # Some cases need -a to activate and others need -A, so # let's treat -v as the activate argument and let individual # cases specify their -a arguments as part of args activate = '-v' def runTest(self): print('*' * 70) print(str(self.output)) print('*' * 70) self.verify() def verify(self): raise NotImplementedError()
class TestAttributeArrayAnd(PluginTester, unittest.TestCase): activate = "-a d=1,d=2" args = ['-v'] plugins = [AttributeSelector()] suitepath = os.path.join(support, 'att') def runTest(self): print '*' * 70 print str(self.output) print '*' * 70 assert 'test_attr.test_one ... ok' in self.output assert 'test_attr.test_two ... ok' not in self.output assert 'test_attr.test_three ... ok' not in self.output assert 'TestClass.test_class_one ... ok' not in self.output assert 'TestClass.test_class_two ... ok' not in self.output assert 'TestClass.test_class_three ... ok' not in self.output assert 'test_case_two' not in self.output assert 'test_case_one' not in self.output assert 'test_case_three' not in self.output
def test_class_and_method_str_attr(self): class TestP(object): foo = 'a' def h(self): pass h.foo = 'b' def i(): pass i.foo = 'a' plug = AttributeSelector() plug.attribs = [[('foo', 'a'), ('foo', 'b')]] assert plug.wantMethod(unbound_method(TestP, TestP.h)) is not False assert plug.wantFunction(i) is False plug.attribs = [[('foo', 'b')]] assert plug.wantMethod(unbound_method(TestP, TestP.h)) is not False assert plug.wantFunction(i) is False
def test_attr_a_b(self): def f1(): pass f1.tags = ['a', 'b'] def f2(): pass f2.tags = ['a', 'c'] def f3(): pass f3.tags = ['b', 'c'] def f4(): pass f4.tags = ['c', 'd'] cnf = Config() parser = OptionParser() plug = AttributeSelector() plug.add_options(parser) # OR opt, args = parser.parse_args(['test', '-a', 'tags=a', '-a', 'tags=b']) print opt plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert plug.wantFunction(f2) is None assert plug.wantFunction(f3) is None assert not plug.wantFunction(f4) # AND opt, args = parser.parse_args(['test', '-a', 'tags=a,tags=b']) print opt plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert not plug.wantFunction(f2) assert not plug.wantFunction(f3) assert not plug.wantFunction(f4)
def selector(self): if self._selector is None: self._selector = AttributeSelector() return self._selector
class ITE(ExtendedPlugin): """ Log when the session has started (after all plugins are configured). """ score = 1000 def options(self, parser, env): """Register command line options.""" parser.add_option('--with-ite', action='store_true', dest='with_ite', default=False, help="Enable ITE mockup. (default: no)") def configure(self, options, noseconfig): super(ITE, self).configure(options, noseconfig) if not self.enabled: return self.curdir = os.getcwd() noseconfig.testMatch = re.compile('$^') self.attr_plugin = AttributeSelector() self.attr_plugin.configure(noseconfig.options, noseconfig) if os.getuid() == 0: os.setegid(self.options.gid) os.seteuid(self.options.uid) def begin(self): STDOUT.info('ITE emulation plugin starting...') for path in self.options.paths: if path.startswith('/'): p = path else: p = os.path.join(os.path.dirname(__file__), path) # Pull any existing paths to make sure our mocks come first. if p in sys.path: sys.path.remove(p) sys.path.append(p) def mdparse(self, source): metadata_regex = re.compile( r""" ^\#\s?@ # Metadata marker (\w+): # Name of metadata key \s*?(.*?)\n # The value of the metadata """, re.VERBOSE | re.MULTILINE) tokens = [(key.strip(), val.strip()) for key, val in metadata_regex.findall(source)] return tokens def beforeTest(self, test): if hasattr(test.test.descriptor, ITE_METADATA): os.chdir(os.path.dirname(test.test.descriptor.__file__)) def loadTestsFromModule(self, module, path=None): if not os.path.isfile(path): return with open(path) as f: source = f.read() tokens = dict(self.mdparse(source)) if tokens: def test_eval(): g = globals() g['__name__'] = '__main__' g['__file__'] = path g['__path__'] = [path] need_root = to_bool(tokens.get('Sudo', False)) try: #exec(source, g) if need_root and os.getuid() == 0: os.setegid(0) os.seteuid(0) else: STDOUT.warning('This test requires root privileges.') exec(compile(source, path, 'exec'), g) except SystemExit as e: from tcutils.base import PASS assert e.code in (None, PASS), e.code finally: if need_root and os.getuid() == 0: os.setegid(self.options.gid) os.seteuid(self.options.uid) module.__module__ = module.__name__ module.compat_func_name = 'main' f = FunctionTestCase(test_eval, descriptor=module) dummy = Dummy() for k, v in tokens.items(): setattr(dummy, k, v) setattr(module, ITE_METADATA, dummy) if not self.attr_plugin.enabled: return [f] if self.attr_plugin.validateAttrib(dummy) is None: return [f]
def test_add_options(self): plug = AttributeSelector() parser = MockOptParser() plug.add_options(parser) expect = [(('-a', '--attr'), {'dest': 'attr', 'action': 'append', 'default': None, 'metavar': 'ATTR', 'help': 'Run only tests that have attributes ' 'specified by ATTR [NOSE_ATTR]'})] if compat_24: expect.append( (('-A', '--eval-attr'), {'dest': 'eval_attr', 'action': 'append', 'default': None, 'metavar': 'EXPR', 'help': 'Run only tests for whose attributes the ' 'Python expression EXPR evaluates to True ' '[NOSE_EVAL_ATTR]'})) self.assertEqual(parser.opts, expect) opt = Bucket() opt.attr = ['!slow'] plug.configure(opt, Config()) assert plug.enabled self.assertEqual(plug.attribs, [[('slow', False)]]) opt.attr = ['fast,quick', 'weird=66'] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[('fast', True), ('quick', True)], [('weird', '66')]]) # don't die on trailing , opt.attr = [ 'something,' ] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[('something', True)]] ) if compat_24: opt.attr = None opt.eval_attr = [ 'weird >= 66' ] plug.configure(opt, Config()) self.assertEqual(plug.attribs[0][0][0], 'weird >= 66') assert callable(plug.attribs[0][0][1])
def test_attr_a_b(self): def f1(): pass f1.tags = ["a", "b"] def f2(): pass f2.tags = ["a", "c"] def f3(): pass f3.tags = ["b", "c"] def f4(): pass f4.tags = ["c", "d"] cnf = Config() parser = OptionParser() plug = AttributeSelector() plug.add_options(parser) # OR opt, args = parser.parse_args(["test", "-a", "tags=a", "-a", "tags=b"]) print opt plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert plug.wantFunction(f2) is None assert plug.wantFunction(f3) is None assert not plug.wantFunction(f4) # AND opt, args = parser.parse_args(["test", "-a", "tags=a,tags=b"]) print opt plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert not plug.wantFunction(f2) assert not plug.wantFunction(f3) assert not plug.wantFunction(f4)
def test_add_options(self): plug = AttributeSelector() parser = MockOptParser() plug.add_options(parser) expect = [ ( ("-a", "--attr"), { "dest": "attr", "action": "append", "default": None, "metavar": "ATTR", "help": "Run only tests that have attributes " "specified by ATTR [NOSE_ATTR]", }, ) ] if compat_24: expect.append( ( ("-A", "--eval-attr"), { "dest": "eval_attr", "action": "append", "default": None, "metavar": "EXPR", "help": "Run only tests for whose attributes the " "Python expression EXPR evaluates to True " "[NOSE_EVAL_ATTR]", }, ) ) self.assertEqual(parser.opts, expect) opt = Bucket() opt.attr = ["!slow"] plug.configure(opt, Config()) assert plug.enabled self.assertEqual(plug.attribs, [[("slow", False)]]) opt.attr = ["fast,quick", "weird=66"] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[("fast", True), ("quick", True)], [("weird", "66")]]) # don't die on trailing , opt.attr = ["something,"] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[("something", True)]]) if compat_24: opt.attr = None opt.eval_attr = ["weird >= 66"] plug.configure(opt, Config()) self.assertEqual(plug.attribs[0][0][0], "weird >= 66") assert callable(plug.attribs[0][0][1])
def test_attr_a_b(self): def f1(): pass f1.tags = ['a', 'b'] def f2(): pass f2.tags = ['a', 'c'] def f3(): pass f3.tags = ['b', 'c'] def f4(): pass f4.tags = ['c', 'd'] cnf = Config() parser = OptionParser() plug = AttributeSelector() plug.add_options(parser) # OR opt, args = parser.parse_args(['test', '-a', 'tags=a', '-a', 'tags=b']) print(opt) plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert plug.wantFunction(f2) is None assert plug.wantFunction(f3) is None assert not plug.wantFunction(f4) # AND opt, args = parser.parse_args(['test', '-a', 'tags=a,tags=b']) print(opt) plug.configure(opt, cnf) assert plug.wantFunction(f1) is None assert not plug.wantFunction(f2) assert not plug.wantFunction(f3) assert not plug.wantFunction(f4)
class GherkinPlugin(Plugin): """ Collect Gherkin tests. """ # Nose interface has non-Pythonic names # pylint:disable=invalid-name,unused-argument name = 'gherkin' enableOpt = 'gherkin' TEST_CLASS = TestCase def __init__(self): """Initialise the helper plugin.""" # Nose has attrib plugin which works as expected but isn't passed the # tests generated from features. Create a local copy which will be used # to veto the tests. super().__init__() self.attrib_plugin = AttributeSelector() def begin(self): """ Start the test suite, loading all the step definitions. """ if self.conf.options.version or self.conf.options.showPlugins: # Don't try to load anything if only called for information return self.feature_dirs = [ dir_ for dir_ in FeatureLoader.find_feature_directories('.') ] for feature_dir in self.feature_dirs: FeatureLoader.find_and_load_step_definitions(feature_dir) def options(self, parser, env=None): """ Register the plugin options. """ if env is None: env = os.environ super().options(parser, env) test_class_name = \ '{c.__module__}.{c.__name__}'.format(c=self.TEST_CLASS) parser.add_option( '--test-class', action='store', dest='test_class_name', default=env.get('NOSE_GHERKIN_CLASS', test_class_name), metavar='TEST_CLASS', help='Base class to use for the generated tests', ) parser.add_option( '--no-ignore-python', action='store_false', dest='ignore_python', default=True, help='Run Python and Gherkin tests together', ) parser.add_option( '-n', '--scenario-indices', action='store', dest='scenario_indices', default='', help='Only run scenarios with these indices (comma-separated)', ) parser.add_option( '--color', action='store_true', dest='force_color', default=False, help='Force colored output', ) # Options for attribute plugin will be registered by its main instance def configure(self, options, conf): """ Configure the plugin. """ super().configure(options, conf) module_name, class_name = options.test_class_name.rsplit('.', 1) module = import_module(module_name) self.test_class = getattr(module, class_name) self.ignore_python = options.ignore_python conf.force_color = options.force_color if options.scenario_indices: self.scenario_indices = tuple( int(index) for index in options.scenario_indices.split(',')) else: self.scenario_indices = None self.attrib_plugin.configure(options, conf) def wantDirectory(self, directory): """ Collect features from 'features' directories. """ directory = os.path.abspath(directory) for feature_dir in self.feature_dirs: feature_dir = os.path.abspath(feature_dir) if feature_dir.startswith(directory) or \ directory.startswith(feature_dir): return True def wantFile(self, file_): """ Load features from feature files. """ if os.path.basename(file_).endswith('.feature'): return True def wantPython(self, _): """ Ignore Python tests if required. """ if self.ignore_python: return False wantClass = wantFunction = wantMethod = wantModule = wantPython def scenario_matches(self, feature, scenario_index, scenario_name): """ Whether a given scenario is selected by the command-line options. @feature The feature class @scenario_index The scenario index @scenario_name The scenario name """ if self.scenario_indices: if scenario_index not in self.scenario_indices: return False if self.attrib_plugin.enabled: scenario = getattr(feature, scenario_name) # False means "no", None means "don't care" for Nose plugins if self.attrib_plugin.validateAttrib(scenario, feature) is False: return False return True def loadTestsFromFile(self, file_): """ Load a feature from the feature file. """ test = self.test_class.from_file(file_) # About to run a feature - ensure "before all" callbacks have run self.ensure_before_callbacks() has_tests = False # Filter the scenarios, if asked for idx, scenario_name in test.scenarios(): if self.scenario_matches(test, idx, scenario_name): has_tests = True yield test(scenario_name) # Feature OK but no tests filtered if not has_tests: yield False def ensure_before_callbacks(self): """ Before the first test, run the "before all" callbacks. """ if not hasattr(self, 'after_hook'): before_all, after_all = CALLBACK_REGISTRY.before_after('all') before_all() self.after_hook = after_all def finalize(self, result): """ After the last test, run the "after all" callbacks. """ # TODO: Is there a better method to do something _after_ all the tests # have been run? if hasattr(self, 'after_hook'): self.after_hook() delattr(self, 'after_hook') def prepareTestRunner(self, runner): """ Monkeypatch in our TestResult class. In unittest we could just set runner.resultclass, but Nose doesn't use this. """ def _makeResult(): """Build our result""" return AloeTestResult(runner.stream, runner.descriptions, runner.verbosity, runner.config) runner._makeResult = _makeResult # pylint:disable=protected-access return runner
def test_add_options(self): plug = AttributeSelector() parser = MockOptParser() plug.add_options(parser) expect = [(('-a', '--attr'), { 'dest': 'attr', 'action': 'append', 'default': None, 'metavar': 'ATTR', 'help': 'Run only tests that have attributes ' 'specified by ATTR [NOSE_ATTR]' })] if compat_24: expect.append((('-A', '--eval-attr'), { 'dest': 'eval_attr', 'action': 'append', 'default': None, 'metavar': 'EXPR', 'help': 'Run only tests for whose attributes the ' 'Python expression EXPR evaluates to True ' '[NOSE_EVAL_ATTR]' })) self.assertEqual(parser.opts, expect) opt = Bucket() opt.attr = ['!slow'] plug.configure(opt, Config()) assert plug.enabled self.assertEqual(plug.attribs, [[('slow', False)]]) opt.attr = ['fast,quick', 'weird=66'] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[('fast', True), ('quick', True)], [('weird', '66')]]) # don't die on trailing , opt.attr = ['something,'] plug.configure(opt, Config()) self.assertEqual(plug.attribs, [[('something', True)]]) if compat_24: opt.attr = None opt.eval_attr = ['weird >= 66'] plug.configure(opt, Config()) self.assertEqual(plug.attribs[0][0][0], 'weird >= 66') assert isinstance(plug.attribs[0][0][1], collections.Callable)
class GherkinPlugin(Plugin): """ Collect Gherkin tests. """ # Nose interface has non-Pythonic names # pylint:disable=invalid-name,unused-argument name = 'gherkin' enableOpt = 'gherkin' TEST_CLASS = TestCase def __init__(self): """Initialise the helper plugin.""" # Nose has attrib plugin which works as expected but isn't passed the # tests generated from features. Create a local copy which will be used # to veto the tests. super().__init__() self.attrib_plugin = AttributeSelector() def begin(self): """ Start the test suite, loading all the step definitions. """ if self.conf.options.version or self.conf.options.showPlugins: # Don't try to load anything if only called for information return self.feature_dirs = [ dir_ for dir_ in FeatureLoader.find_feature_directories('.') ] for feature_dir in self.feature_dirs: FeatureLoader.find_and_load_step_definitions(feature_dir) def options(self, parser, env=None): """ Register the plugin options. """ if env is None: env = os.environ super().options(parser, env) test_class_name = \ '{c.__module__}.{c.__name__}'.format(c=self.TEST_CLASS) parser.add_option( '--test-class', action='store', dest='test_class_name', default=env.get('NOSE_GHERKIN_CLASS', test_class_name), metavar='TEST_CLASS', help='Base class to use for the generated tests', ) parser.add_option( '--no-ignore-python', action='store_false', dest='ignore_python', default=True, help='Run Python and Gherkin tests together', ) parser.add_option( '-n', '--scenario-indices', action='store', dest='scenario_indices', default='', help='Only run scenarios with these indices (comma-separated)', ) parser.add_option( '--color', action='store_true', dest='force_color', default=False, help='Force colored output', ) # Options for attribute plugin will be registered by its main instance def configure(self, options, conf): """ Configure the plugin. """ super().configure(options, conf) module_name, class_name = options.test_class_name.rsplit('.', 1) module = import_module(module_name) self.test_class = getattr(module, class_name) self.ignore_python = options.ignore_python conf.force_color = options.force_color if options.scenario_indices: self.scenario_indices = tuple( int(index) for index in options.scenario_indices.split(',') ) else: self.scenario_indices = None self.attrib_plugin.configure(options, conf) def wantDirectory(self, directory): """ Collect features from 'features' directories. This returns true for any directory either _above_ or _below_ any of the features directories; above to ensure the search continues inside, below to collect features from all the subdirectories. """ directory = os.path.abspath(directory) for feature_dir in self.feature_dirs: feature_dir = os.path.abspath(feature_dir) if feature_dir.startswith(directory) or \ directory.startswith(feature_dir): return True def wantFile(self, file_): """ Load features from feature files. """ # Check that the feature is in one of the features directories file_dir = os.path.abspath(os.path.dirname(file_)) if any( file_dir.startswith(os.path.abspath(feature_dir)) for feature_dir in self.feature_dirs ): # Check the file extension # Convert to str (not bytes) since Nose passes in both depending on # whether the feature is in a Python module dir or not if isinstance(file_, bytes): file_ = file_.decode(sys.getfilesystemencoding()) if os.path.basename(file_).endswith('.feature'): return True def wantPython(self, _): """ Ignore Python tests if required. """ if self.ignore_python: return False wantClass = wantFunction = wantMethod = wantModule = wantPython def scenario_matches(self, feature, scenario_index, scenario_name): """ Whether a given scenario is selected by the command-line options. @feature The feature class @scenario_index The scenario index @scenario_name The scenario name """ if self.scenario_indices: if scenario_index not in self.scenario_indices: return False if self.attrib_plugin.enabled: scenario = getattr(feature, scenario_name) # False means "no", None means "don't care" for Nose plugins if self.attrib_plugin.validateAttrib(scenario, feature) is False: return False return True def loadTestsFromFile(self, file_): """ Load a feature from the feature file. """ test = self.test_class.from_file(file_) # About to run a feature - ensure "before all" callbacks have run self.ensure_before_callbacks() has_tests = False # Filter the scenarios, if asked for idx, scenario_name in test.scenarios(): if self.scenario_matches(test, idx, scenario_name): has_tests = True yield test(scenario_name) # Feature OK but no tests filtered if not has_tests: yield False def ensure_before_callbacks(self): """ Before the first test, run the "before all" callbacks. """ if not hasattr(self, 'after_hook'): before_all, after_all = CALLBACK_REGISTRY.before_after('all') before_all() self.after_hook = after_all def finalize(self, result): """ After the last test, run the "after all" callbacks. """ # TODO: Is there a better method to do something _after_ all the tests # have been run? if hasattr(self, 'after_hook'): self.after_hook() delattr(self, 'after_hook') def prepareTestRunner(self, runner): """ Monkeypatch in our TestResult class. In unittest we could just set runner.resultclass, but Nose doesn't use this. """ def _makeResult(): """Build our result""" return AloeTestResult(runner.stream, runner.descriptions, runner.verbosity, runner.config) runner._makeResult = _makeResult # pylint:disable=protected-access return runner