Files
rally/tests/unit/plugins/common/verification/test_testr.py
Andrey Kurilin 86cd7dfa5c [verifiers] Fix identification of testr/stestr
With Ibcb949ad98323f770bf20f144ad66b4a47c00e22 the support of stestr was
added.
Unfortunately, this commit included a wrong check for testr config file
which is an identifier what interface should be used (testr or stestr)
to launch tests, so stestr was used for all cases.

Also, this patch temporary turns off verification gates, since it
contains a bug related to openstack roles configuration which make
tempest verifier fail. Since we are planning to remove openstack related
code from the main repository, this issue should be solved in
rally-openstack repository.

Change-Id: I691503901c6d1c6ceed79035b0df8bd752d912bd
Closes-Bug: #1777757
2018-06-20 16:09:30 +03:00

330 lines
13 KiB
Python

#
# 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 os
import subprocess
import mock
from rally import exceptions
from rally.plugins.common.verification import testr
from tests.unit import test
PATH = "rally.plugins.common.verification.testr"
class TestrContextTestCase(test.TestCase):
def setUp(self):
super(TestrContextTestCase, self).setUp()
self.verifier = mock.Mock()
self.prepare_run_args = self.verifier.manager.prepare_run_args
self.prepare_run_args.side_effect = lambda x: x
def assertEqualCmd(self, expected, actual, msg="", stestr=False):
cmd = ["stestr" if stestr else "testr", "run", "--subunit"]
cmd.extend(expected)
self.assertEqual(cmd, actual, message=msg)
def test_setup_with_concurrency(self):
# default behaviour
cfg = {"verifier": self.verifier}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--parallel"], cfg["testr_cmd"])
cfg = {"verifier": self.verifier, "run_args": {"concurrency": 0}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--parallel"], cfg["testr_cmd"])
# serial mode
cfg = {"verifier": self.verifier,
"run_args": {"concurrency": 1}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--concurrency", "1"], cfg["testr_cmd"])
# parallel mode
cfg = {"verifier": self.verifier,
"run_args": {"concurrency": 2}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--parallel", "--concurrency", "2"],
cfg["testr_cmd"])
def test_setup_with_concurrency_stestr(self):
self.verifier.manager._use_testr = False
# default behaviour
cfg = {"verifier": self.verifier}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd([], cfg["testr_cmd"], stestr=True)
cfg = {"verifier": self.verifier, "run_args": {"concurrency": 0}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd([], cfg["testr_cmd"], stestr=True)
# serial mode
cfg = {"verifier": self.verifier,
"run_args": {"concurrency": 1}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--serial"], cfg["testr_cmd"], stestr=True)
# parallel mode
cfg = {"verifier": self.verifier,
"run_args": {"concurrency": 2}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--concurrency", "2"], cfg["testr_cmd"],
stestr=True)
@mock.patch("%s.common_utils.generate_random_path" % PATH)
def test_setup_with_skip_and_load_lists(self, mock_generate_random_path):
# with load_list, but without skip_list
load_list = ["tests.foo", "tests.bar"]
cfg = {"verifier": self.verifier,
"run_args": {"load_list": load_list}}
ctx = testr.TestrContext(cfg)
mock_open = mock.mock_open()
with mock.patch("%s.open" % PATH, mock_open):
ctx.setup()
mock_open.assert_called_once_with(
mock_generate_random_path.return_value, "w")
handle = mock_open.return_value
handle.write.assert_called_once_with("\n".join(load_list))
self.assertEqualCmd(["--parallel", "--load-list",
mock_generate_random_path.return_value],
cfg["testr_cmd"])
self.assertFalse(self.verifier.manager.list_tests.called)
# with load_list and skip_list
load_list = ["tests.foo", "tests.bar"]
skip_list = ["tests.foo"]
cfg = {"verifier": self.verifier,
"run_args": {"load_list": load_list,
"skip_list": skip_list}}
ctx = testr.TestrContext(cfg)
mock_open = mock.mock_open()
with mock.patch("%s.open" % PATH, mock_open):
ctx.setup()
mock_open.assert_called_once_with(
mock_generate_random_path.return_value, "w")
handle = mock_open.return_value
handle.write.assert_called_once_with(load_list[1])
self.assertEqualCmd(["--parallel", "--load-list",
mock_generate_random_path.return_value],
cfg["testr_cmd"])
self.assertFalse(self.verifier.manager.list_tests.called)
# with skip_list, but without load_list
load_list = ["tests.foo", "tests.bar"]
self.verifier.manager.list_tests.return_value = load_list
skip_list = ["tests.foo"]
cfg = {"verifier": self.verifier,
"run_args": {"skip_list": skip_list}}
ctx = testr.TestrContext(cfg)
mock_open = mock.mock_open()
with mock.patch("%s.open" % PATH, mock_open):
ctx.setup()
mock_open.assert_called_once_with(
mock_generate_random_path.return_value, "w")
handle = mock_open.return_value
handle.write.assert_called_once_with(load_list[1])
self.assertEqualCmd(["--parallel", "--load-list",
mock_generate_random_path.return_value],
cfg["testr_cmd"])
self.verifier.manager.list_tests.assert_called_once_with()
def test_setup_with_failing(self):
cfg = {"verifier": self.verifier, "run_args": {"failed": True}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--parallel", "--failing"], cfg["testr_cmd"])
def test_setup_with_pattern(self):
cfg = {"verifier": self.verifier, "run_args": {"pattern": "foo"}}
ctx = testr.TestrContext(cfg)
ctx.setup()
self.assertEqualCmd(["--parallel", "foo"], cfg["testr_cmd"])
@mock.patch("%s.os.remove" % PATH)
@mock.patch("%s.os.path.exists" % PATH)
def test_cleanup(self, mock_exists, mock_remove):
files = {"/path/foo_1": True,
"/path/bar_1": False,
"/path/foo_2": False,
"/path/bar_2": True}
def fake_exists(path):
return files.get(path, False)
mock_exists.side_effect = fake_exists
ctx = testr.TestrContext({"verifier": self.verifier})
ctx._tmp_files = files.keys()
ctx.cleanup()
self.assertEqual([mock.call(f) for f in files.keys()],
mock_exists.call_args_list)
self.assertEqual([mock.call(f) for f in files.keys() if files[f]],
mock_remove.call_args_list)
class TestrLauncherTestCase(test.TestCase):
def test_run_environ_property(self):
env = mock.Mock()
class FakeLauncher(testr.TestrLauncher):
@property
def environ(self):
return env
self.assertEqual(env, FakeLauncher(mock.Mock()).run_environ)
@mock.patch("%s.utils.check_output" % PATH)
def test_list_tests_via_stestr(self, mock_check_output):
mock_check_output.return_value = (
"logging message\n" # should be ignored
"one more useless data\n" # should be ignored
"tests.FooTestCase.test_something\n" # valid
"tests.FooTestCase.test_another[\n" # invalid
"tests.BarTestCase.test_another[id=123]\n" # valid
"tests.FooTestCase.test_another[id=a2-213,smoke]\n" # valid
)
verifier = mock.Mock()
launcher = testr.TestrLauncher(verifier)
launcher._use_testr = False
self.assertEqual(["tests.FooTestCase.test_something",
"tests.BarTestCase.test_another[id=123]",
"tests.FooTestCase.test_another[id=a2-213,smoke]"],
launcher.list_tests())
mock_check_output.assert_called_once_with(
["stestr", "list", ""],
cwd=launcher.repo_dir, env=launcher.environ, debug_output=False)
@mock.patch("%s.utils.check_output" % PATH)
def test_list_tests_via_testr(self, mock_check_output):
mock_check_output.return_value = (
"logging message\n" # should be ignored
"one more useless data\n" # should be ignored
"tests.FooTestCase.test_something\n" # valid
"tests.FooTestCase.test_another[\n" # invalid
"tests.BarTestCase.test_another[id=123]\n" # valid
"tests.FooTestCase.test_another[id=a2-213,smoke]\n" # valid
)
verifier = mock.Mock()
launcher = testr.TestrLauncher(verifier)
launcher._use_testr = True
self.assertEqual(["tests.FooTestCase.test_something",
"tests.BarTestCase.test_another[id=123]",
"tests.FooTestCase.test_another[id=a2-213,smoke]"],
launcher.list_tests())
mock_check_output.assert_called_once_with(
["testr", "list-tests", ""],
cwd=launcher.repo_dir, env=launcher.environ, debug_output=False)
@mock.patch("%s.shutil.rmtree" % PATH)
@mock.patch("%s.utils.check_output" % PATH)
@mock.patch("%s.os.path.exists" % PATH)
@mock.patch("%s.os.path.isdir" % PATH)
def test__init_testr(self, mock_isdir, mock_exists, mock_check_output,
mock_rmtree):
launcher = testr.TestrLauncher(mock.Mock())
mock_exists.assert_called_once_with(
os.path.join(launcher.repo_dir, ".testr.conf"))
mock_exists.reset_mock()
# case #1: testr already initialized
mock_isdir.return_value = True
launcher._init_testr()
self.assertFalse(mock_check_output.called)
self.assertFalse(mock_exists.called)
self.assertFalse(mock_rmtree.called)
# case #2: initializing testr without errors
mock_isdir.return_value = False
launcher._init_testr()
mock_check_output.assert_called_once_with(
["testr", "init"], cwd=launcher.repo_dir, env=launcher.environ)
self.assertFalse(mock_exists.called)
self.assertFalse(mock_rmtree.called)
mock_check_output.reset_mock()
# case #3: initializing stestr without errors
launcher._use_testr = False
launcher._init_testr()
mock_check_output.assert_called_once_with(
["stestr", "init"], cwd=launcher.repo_dir, env=launcher.environ)
self.assertFalse(mock_exists.called)
self.assertFalse(mock_rmtree.called)
mock_check_output.reset_mock()
# case #4: initializing testr with error
mock_check_output.side_effect = OSError
test_repository_dir = os.path.join(launcher.base_dir,
".testrepository")
self.assertRaises(exceptions.RallyException, launcher._init_testr)
mock_check_output.assert_called_once_with(
["stestr", "init"], cwd=launcher.repo_dir, env=launcher.environ)
mock_exists.assert_called_once_with(test_repository_dir)
mock_rmtree.assert_called_once_with(test_repository_dir)
@mock.patch("%s.subunit_v2.parse" % PATH)
@mock.patch("%s.subprocess.Popen" % PATH)
def test_run(self, mock_popen, mock_parse):
launcher = testr.TestrLauncher(mock.Mock())
ctx = {"testr_cmd": ["ls", "-la"],
"run_args": {"xfail_list": mock.Mock(),
"skip_list": mock.Mock()}}
self.assertEqual(mock_parse.return_value, launcher.run(ctx))
mock_popen.assert_called_once_with(ctx["testr_cmd"],
env=launcher.run_environ,
cwd=launcher.repo_dir,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
mock_popen.return_value.wait.assert_called_once_with()
mock_parse.assert_called_once_with(
mock_popen.return_value.stdout, live=True,
expected_failures=ctx["run_args"]["xfail_list"],
skipped_tests=ctx["run_args"]["skip_list"],
logger_name=launcher.verifier.name)
@mock.patch("%s.manager.VerifierManager.install" % PATH)
def test_install(self, mock_verifier_manager_install):
launcher = testr.TestrLauncher(mock.Mock())
launcher._init_testr = mock.Mock()
launcher.install()
mock_verifier_manager_install.assert_called_once_with()
launcher._init_testr.assert_called_once_with()