aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Danno <vincent.danno@orange.com>2021-06-07 20:53:10 +0200
committerVincent Danno <vincent.danno@orange.com>2021-06-08 14:06:41 +0200
commit5389151567d189fb65fcded344929dcc319f2db3 (patch)
treecf7311a582061125b0378b73ad0cb4016c0ef625
parentec6921039af3b016eecc6e609f2554aea0f81e2c (diff)
MTS inherits BashFeature
Signed-off-by: Vincent Danno <vincent.danno@orange.com> Change-Id: Ifa3a5d5946c29863905490de5f875e17026744a5
-rw-r--r--xtesting/core/feature.py12
-rw-r--r--xtesting/core/mts.py68
-rw-r--r--xtesting/tests/unit/core/test_feature.py35
3 files changed, 52 insertions, 63 deletions
diff --git a/xtesting/core/feature.py b/xtesting/core/feature.py
index f92858bd..946233d6 100644
--- a/xtesting/core/feature.py
+++ b/xtesting/core/feature.py
@@ -96,11 +96,13 @@ class BashFeature(Feature):
Returns:
0 if cmd returns 0,
- -1 otherwise.
+ non-zero in all other cases.
"""
try:
cmd = kwargs["cmd"]
console = kwargs["console"] if "console" in kwargs else False
+ # For some tests, we may need to force stop after N sec
+ max_duration = kwargs.get("max_duration")
if not os.path.isdir(self.res_dir):
os.makedirs(self.res_dir)
with open(self.result_file, 'w') as f_stdout:
@@ -112,7 +114,13 @@ class BashFeature(Feature):
if console:
sys.stdout.write(line.decode("utf-8"))
f_stdout.write(line.decode("utf-8"))
- process.wait()
+ try:
+ process.wait(timeout=max_duration)
+ except subprocess.TimeoutExpired:
+ process.kill()
+ self.__logger.info(
+ "Killing process after %d second(s).", max_duration)
+ return -2
with open(self.result_file, 'r') as f_stdin:
self.__logger.debug("$ %s\n%s", cmd, f_stdin.read().rstrip())
return process.returncode
diff --git a/xtesting/core/mts.py b/xtesting/core/mts.py
index f1cf80ac..b9f605b8 100644
--- a/xtesting/core/mts.py
+++ b/xtesting/core/mts.py
@@ -15,13 +15,12 @@ import csv
import logging
import os
import shutil
-import subprocess
-import sys
import time
from lxml import etree
import prettytable
+from xtesting.core import feature
from xtesting.core import testcase
@@ -29,7 +28,7 @@ __author__ = ("Vincent Mahe <v.mahe@orange.com>, "
"Cedric Ollivier <cedric.ollivier@orange.com>")
-class MTSLauncher(testcase.TestCase):
+class MTSLauncher(feature.BashFeature):
"""Class designed to run MTS tests."""
__logger = logging.getLogger(__name__)
@@ -45,7 +44,6 @@ class MTSLauncher(testcase.TestCase):
def __init__(self, **kwargs):
super(MTSLauncher, self).__init__(**kwargs)
- self.result_file = "{}/{}.log".format(self.res_dir, self.case_name)
# Location of the HTML report generated by MTS
self.mts_stats_dir = os.path.join(self.res_dir, 'mts_stats_report')
# Location of the log files generated by MTS for each test.
@@ -164,25 +162,11 @@ class MTSLauncher(testcase.TestCase):
return True
def execute(self, **kwargs): # pylint: disable=too-many-locals
- """Execute the cmd passed as arg
-
- Args:
- kwargs: Arbitrary keyword arguments.
-
- Returns:
- 0 if cmd returns 0,
- -1 otherwise.
- """
try:
- console = kwargs["console"] if "console" in kwargs else False
# Read specific parameters for MTS
test_file = kwargs["test_file"]
log_level = kwargs[
"log_level"] if "log_level" in kwargs else "INFO"
-
- # For some MTS tests, we need to force stop after N sec
- max_duration = kwargs[
- "max_duration"] if "max_duration" in kwargs else None
store_method = kwargs[
"store_method"] if "store_method" in kwargs else "FILE"
# Must use the $HOME_MTS/bin as current working dir
@@ -196,7 +180,7 @@ class MTSLauncher(testcase.TestCase):
enabled_testcases_str = ' '.join(enabled_testcases)
check_ok = self.check_enabled_mts_test_cases(enabled_testcases)
if not check_ok:
- return -2
+ return -3
# Build command line to launch for MTS
cmd = ("cd {} && ./startCmd.sh {} {} -sequential -levelLog:{}"
@@ -229,54 +213,16 @@ class MTSLauncher(testcase.TestCase):
"MTS statistics output dir: %s ", self.mts_stats_dir)
self.__logger.info("MTS logs output dir: %s ", self.mts_logs_dir)
- # Launch MTS as a sub-process
- # and save its standard output to a file
- with open(self.result_file, 'w') as f_stdout:
- self.__logger.info("Calling %s", cmd)
- process = subprocess.Popen(
- cmd, shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- for line in iter(process.stdout.readline, b''):
- if console:
- sys.stdout.write(line.decode("utf-8"))
- f_stdout.write(line.decode("utf-8"))
- try:
- process.wait(timeout=max_duration)
- except subprocess.TimeoutExpired:
- process.kill()
- self.__logger.info(
- "Killing MTS process after %d second(s).",
- max_duration)
- return 3
- with open(self.result_file, 'r') as f_stdin:
- self.__logger.debug("$ %s\n%s", cmd, f_stdin.read().rstrip())
- return process.returncode
+ kwargs.pop("cmd", None)
+ return super(MTSLauncher, self).execute(cmd=cmd, **kwargs)
+
except KeyError:
self.__logger.error("Missing mandatory arg for MTS. kwargs: %s",
kwargs)
return -1
def run(self, **kwargs):
- """Run the feature.
-
- It allows executing any Python method by calling execute().
-
- It sets the following attributes required to push the results
- to DB:
-
- * result,
- * start_time,
- * stop_time.
-
- It doesn't fulfill details when pushing the results to the DB.
-
- Args:
- kwargs: Arbitrary keyword arguments.
-
- Returns:
- TestCase.EX_OK if execute() returns 0,
- TestCase.EX_RUN_ERROR otherwise.
- """
+ """Runs the MTS suite"""
self.start_time = time.time()
exit_code = testcase.TestCase.EX_RUN_ERROR
self.result = 0
diff --git a/xtesting/tests/unit/core/test_feature.py b/xtesting/tests/unit/core/test_feature.py
index b36fa367..76f5d85a 100644
--- a/xtesting/tests/unit/core/test_feature.py
+++ b/xtesting/tests/unit/core/test_feature.py
@@ -44,6 +44,7 @@ class FeatureTestingBase(unittest.TestCase):
_repo = "dir_repo_bar"
_cmd = "run_bar_tests.py"
_output_file = os.path.join(constants.RESULTS_DIR, 'foo/foo.log')
+ _max_duration = 1
feature = None
@mock.patch('time.time', side_effect=[1, 2])
@@ -66,6 +67,15 @@ class FeatureTestingBase(unittest.TestCase):
self.assertEqual(self.feature.start_time, 1)
self.assertEqual(self.feature.stop_time, 2)
+ @mock.patch('time.time', side_effect=[1, 2])
+ def _test_run_max_duration(self, status, mock_method=None):
+ self.assertEqual(
+ self.feature.run(cmd=self._cmd, max_duration=self._max_duration),
+ status)
+ mock_method.assert_has_calls([mock.call(), mock.call()])
+ self.assertEqual(self.feature.start_time, 1)
+ self.assertEqual(self.feature.stop_time, 2)
+
class FeatureTesting(FeatureTestingBase):
@@ -132,6 +142,31 @@ class BashFeatureTesting(FeatureTestingBase):
self._cmd, shell=True, stderr=mock.ANY, stdout=mock.ANY)
args[1].assert_called_once_with(self.feature.res_dir)
+ @mock.patch('subprocess.Popen')
+ @mock.patch('os.path.isdir', return_value=True)
+ def test_run_ko3(self, *args):
+ stream = BytesIO()
+ stream.write(b"foo")
+ stream.seek(0)
+ wait = mock.MagicMock(side_effect=subprocess.TimeoutExpired(
+ cmd=FeatureTestingBase._cmd,
+ timeout=FeatureTestingBase._max_duration))
+ kill = mock.MagicMock()
+ attrs = {'return_value.wait': wait,
+ 'return_value.kill': kill,
+ 'return_value.stdout': stream,
+ 'return_value.returncode': 0}
+ args[1].configure_mock(**attrs)
+ with mock.patch('builtins.open', mock.mock_open()) as mopen:
+ self._test_run_max_duration(testcase.TestCase.EX_RUN_ERROR)
+ self.assertIn(mock.call(self._output_file, 'w'), mopen.mock_calls)
+ self.assertNotIn(mock.call(self._output_file, 'r'), mopen.mock_calls)
+ args[1].assert_called_once_with(
+ self._cmd, shell=True, stderr=mock.ANY, stdout=mock.ANY)
+ wait.assert_called_once_with(timeout=FeatureTestingBase._max_duration)
+ kill.assert_called_once()
+ args[0].assert_called_once_with(self.feature.res_dir)
+
@mock.patch('os.path.isdir', return_value=True)
@mock.patch('subprocess.Popen')
def test_run1(self, *args):