Leverage on Rally task tags 19/68619/2
authorCédric Ollivier <cedric.ollivier@orange.com>
Fri, 11 Oct 2019 08:44:25 +0000 (10:44 +0200)
committerCédric Ollivier <cedric.ollivier@orange.com>
Fri, 11 Oct 2019 16:57:23 +0000 (18:57 +0200)
It avoids parsing rally task outputs which may hang (subprocess
communicate) as seen in rally_full and rally_jobs.

It simply selects test names as tags.

Change-Id: I88b54a8f155e557f8a606fdbd7d86c1f4d5dae3b
Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
(cherry picked from commit 74df72ec294998787a8f0af5e2084db91ba0778b)

functest/opnfv_tests/openstack/rally/rally.py
functest/tests/unit/openstack/rally/test_rally.py

index 5d94eaf..6a162de 100644 (file)
@@ -22,10 +22,10 @@ import shutil
 import subprocess
 import time
 
-from threading import Timer
 import pkg_resources
 import prettytable
 from ruamel.yaml import YAML
+import six
 from six.moves import configparser
 from xtesting.core import testcase
 import yaml
@@ -102,7 +102,6 @@ class RallyBase(singlevm.VmReady2):
         self.run_cmd = ''
         self.network_extensions = []
         self.services = []
-        self.task_aborted = False
 
     def _build_task_args(self, test_file_name):
         """Build arguments for the Rally task."""
@@ -235,20 +234,17 @@ class RallyBase(singlevm.VmReady2):
                 rconfig.write(config_file)
 
     @staticmethod
-    def get_task_id(cmd_raw):
+    def get_task_id(tag):
         """
         Get task id from command rally result.
 
-        :param cmd_raw:
+        :param tag:
         :return: task_id as string
         """
-        taskid_re = re.compile('^Task +(.*): started$')
-        for line in cmd_raw.splitlines(True):
-            line = line.strip()
-            match = taskid_re.match(line.decode("utf-8"))
-            if match:
-                return match.group(1)
-        return None
+        cmd = ["rally", "task", "list", "--tag", tag, "--uuids-only"]
+        output = subprocess.check_output(cmd).decode("utf-8").rstrip()
+        LOGGER.info("%s: %s", " ".join(cmd), output)
+        return output
 
     @staticmethod
     def task_succeed(json_raw):
@@ -426,30 +422,22 @@ class RallyBase(singlevm.VmReady2):
         else:
             LOGGER.info('Test scenario: "%s" Failed.', test_name)
 
-    def kill_task(self, proc):
-        """ Kill a task."""
-        proc.kill()
-        self.task_aborted = True
-
     def run_task(self, test_name):
         """Run a task."""
         LOGGER.info('Starting test scenario "%s" ...', test_name)
         LOGGER.debug('running command: %s', self.run_cmd)
-        proc = subprocess.Popen(self.run_cmd, stdout=subprocess.PIPE,
-                                stderr=subprocess.STDOUT)
-        self.task_aborted = False
-        timer = Timer(self.task_timeout, self.kill_task, [proc])
-        timer.start()
-        output = proc.communicate()[0]
-        if self.task_aborted:
-            LOGGER.error("Failed to complete task")
-            raise Exception("Failed to complete task")
-        timer.cancel()
-        task_id = self.get_task_id(output)
+        if six.PY3:
+            # pylint: disable=no-member
+            subprocess.call(
+                self.run_cmd, timeout=self.task_timeout,
+                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+        else:
+            with open(os.devnull, 'wb') as devnull:
+                subprocess.call(self.run_cmd, stdout=devnull, stderr=devnull)
+        task_id = self.get_task_id(test_name)
         LOGGER.debug('task_id : %s', task_id)
-        if task_id is None:
+        if not task_id:
             LOGGER.error("Failed to retrieve task_id")
-            LOGGER.error("Result:\n%s", output.decode("utf-8"))
             raise Exception("Failed to retrieve task id")
         self._save_results(test_name, task_id)
 
@@ -539,7 +527,8 @@ class RallyBase(singlevm.VmReady2):
         if self.file_is_empty(file_name):
             LOGGER.info('No tests for scenario "%s"', test_name)
             return False
-        self.run_cmd = (["rally", "task", "start", "--abort-on-sla-failure",
+        self.run_cmd = (["rally", "task", "start", "--tag", test_name,
+                         "--abort-on-sla-failure",
                          "--task", self.task_file, "--task-args",
                          str(self._build_task_args(test_name))])
         return True
@@ -841,7 +830,8 @@ class RallyJobs(RallyBase):
             os.makedirs(self.temp_dir)
         task_file_name = os.path.join(self.temp_dir, task_name)
         self.apply_blacklist(task, task_file_name)
-        self.run_cmd = (["rally", "task", "start", "--task", task_file_name])
+        self.run_cmd = (["rally", "task", "start", "--tag", test_name,
+                         "--task", task_file_name])
         return True
 
     def clean(self):
index c867990..5ab82ec 100644 (file)
@@ -103,15 +103,19 @@ class OSRallyTesting(unittest.TestCase):
         mock_method.assert_called()
         mock_os_makedirs.assert_called()
 
-    def test_get_task_id_default(self):
-        cmd_raw = b'Task 1: started'
-        self.assertEqual(self.rally_base.get_task_id(cmd_raw),
-                         '1')
-
-    def test_get_task_id_missing_id(self):
-        cmd_raw = b''
-        self.assertEqual(self.rally_base.get_task_id(cmd_raw),
-                         None)
+    @mock.patch('subprocess.check_output', return_value=b'1\n')
+    def test_get_task_id_default(self, *args):
+        tag = 'nova'
+        self.assertEqual(self.rally_base.get_task_id(tag), '1')
+        args[0].assert_called_with(
+            ['rally', 'task', 'list', '--tag', tag, '--uuids-only'])
+
+    @mock.patch('subprocess.check_output', return_value=b'\n')
+    def test_get_task_id_missing_id(self, *args):
+        tag = 'nova'
+        self.assertEqual(self.rally_base.get_task_id(tag), '')
+        args[0].assert_called_with(
+            ['rally', 'task', 'list', '--tag', tag, '--uuids-only'])
 
     def test_task_succeed_fail(self):
         json_raw = json.dumps({})