Commit a0c3e726 authored by Michael Hanselmann's avatar Michael Hanselmann

QA: Enable use of OR conditions in test checks

Until now “TestRunIf” and “TestEnabled” could only handle AND. With this
patch a new class named “Either” is added to “qa_config” and allows OR.
The name “Either” was chosen instead of “Or” as the latter is very close
to the reserved keyword “or”.

Examples:
  ["rapi", Either(["instance-rename", "instance-reboot"])]

  Either(["node-list", "instance-list", "job-list"])
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 79ac58fa
......@@ -498,6 +498,7 @@ PYTHON_BOOTSTRAP = \
tools/ensure-dirs
qa_scripts = \
qa/__init__.py \
qa/ganeti-qa.py \
qa/qa_cluster.py \
qa/qa_config.py \
......@@ -847,6 +848,7 @@ python_tests = \
test/ganeti.utils.x509_unittest.py \
test/ganeti.utils_unittest.py \
test/ganeti.workerpool_unittest.py \
test/qa.qa_config_unittest.py \
test/cfgupgrade_unittest.py \
test/docs_unittest.py \
test/pycurl_reset_unittest.py \
......
......@@ -10,7 +10,7 @@ trap "rm -rf $tmpdir" EXIT
mkdir $tmpdir/doc
cp -r autotools daemons scripts lib tools test $tmpdir
cp -r autotools daemons scripts lib tools test qa $tmpdir
cp -r doc/examples $tmpdir/doc
mv $tmpdir/lib $tmpdir/ganeti
......
......@@ -60,22 +60,79 @@ def get(name, default=None):
return cfg.get(name, default)
def TestEnabled(tests):
class Either:
def __init__(self, tests):
"""Initializes this class.
@type tests: list or string
@param tests: List of test names
@see: L{TestEnabled} for details
"""
self.tests = tests
def _MakeSequence(value):
"""Make sequence of single argument.
If the single argument is not already a list or tuple, a list with the
argument as a single item is returned.
"""
if isinstance(value, (list, tuple)):
return value
else:
return [value]
def _TestEnabledInner(check_fn, names, fn):
"""Evaluate test conditions.
@type check_fn: callable
@param check_fn: Callback to check whether a test is enabled
@type names: sequence or string
@param names: Test name(s)
@type fn: callable
@param fn: Aggregation function
@rtype: bool
@return: Whether test is enabled
"""
names = _MakeSequence(names)
result = []
for name in names:
if isinstance(name, Either):
value = _TestEnabledInner(check_fn, name.tests, compat.any)
elif isinstance(name, (list, tuple)):
value = _TestEnabledInner(check_fn, name, compat.all)
else:
value = check_fn(name)
result.append(value)
return fn(result)
def TestEnabled(tests, _cfg=None):
"""Returns True if the given tests are enabled.
@param tests: a single test, or a list of tests to check
@param tests: A single test as a string, or a list of tests to check; can
contain L{Either} for OR conditions, AND is default
"""
if isinstance(tests, basestring):
tests = [tests]
if _cfg is None:
_cfg = cfg
# Get settings for all tests
all_tests = cfg.get("tests", {})
cfg_tests = _cfg.get("tests", {})
# Get default setting
default = all_tests.get("default", True)
default = cfg_tests.get("default", True)
return compat.all(all_tests.get(name, default) for name in tests)
return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
tests, compat.all)
def GetMasterNode():
......
#!/usr/bin/python
#
# Copyright (C) 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Script for testing qa.qa_config"""
import unittest
from qa import qa_config
import testutils
class TestTestEnabled(unittest.TestCase):
def testSimple(self):
for name in ["test", ["foobar"], ["a", "b"]]:
self.assertTrue(qa_config.TestEnabled(name, _cfg={}))
for default in [False, True]:
self.assertFalse(qa_config.TestEnabled("foo", _cfg={
"tests": {
"default": default,
"foo": False,
},
}))
self.assertTrue(qa_config.TestEnabled("bar", _cfg={
"tests": {
"default": default,
"bar": True,
},
}))
def testEitherWithDefault(self):
names = qa_config.Either("one")
self.assertTrue(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
},
}))
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": False,
},
}))
def testEither(self):
names = [qa_config.Either(["one", "two"]),
qa_config.Either("foo"),
"hello",
["bar", "baz"]]
self.assertTrue(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
},
}))
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": False,
},
}))
for name in ["foo", "bar", "baz", "hello"]:
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
name: False,
},
}))
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
"one": False,
"two": False,
},
}))
self.assertTrue(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
"one": False,
"two": True,
},
}))
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
"one": True,
"two": True,
"foo": False,
},
}))
def testEitherNestedWithAnd(self):
names = qa_config.Either([["one", "two"], "foo"])
self.assertTrue(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
},
}))
for name in ["one", "two"]:
self.assertFalse(qa_config.TestEnabled(names, _cfg={
"tests": {
"default": True,
"foo": False,
name: False,
},
}))
if __name__ == "__main__":
testutils.GanetiTestProgram()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment