aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/benchmark/core/report.py
diff options
context:
space:
mode:
authorPatrice Buriez <patrice.buriez@intel.com>2018-11-15 12:30:30 +0100
committerPatrice Buriez <patrice.buriez@intel.com>2018-12-21 19:07:59 +0100
commitf85bca25fd5a681215c210c51b703e0e957a91e5 (patch)
treeeca867f2731ba0b2da2c3d6a5c02c48cbb2fb1ef /yardstick/benchmark/core/report.py
parent285a0026d13173fb3bca4c74562874cb10641384 (diff)
Fix conversion to JS for HTML reports
Some new fields in InfluxDB have plain text contents that AST cannot parse as valid expressions, resulting in exceptions being raised by yardstick CLI commands "report generate" and "report generate-nsb". Reworked _generate_common() to properly handle and convert: - unicode, str and missing keys - None, unicode, str, float, long and int values - float, long and int stored as unicode or str values Added test__generate_common() unit test, to verify all possible conversion flavors. Also renamed incorrect "tasks" to "metrics". Also fixed warning in Python3 for some unit tests, caused by deprecation of unittest.TestCase.assertRaisesRegexp(). JIRA: YARDSTICK-1367 Topic: report/html_table (10 of 12) Change-Id: Iff75bfd2c1dcaf3806f67f52f0ea594f10aceb5b Signed-off-by: Patrice Buriez <patrice.buriez@intel.com>
Diffstat (limited to 'yardstick/benchmark/core/report.py')
-rw-r--r--yardstick/benchmark/core/report.py93
1 files changed, 63 insertions, 30 deletions
diff --git a/yardstick/benchmark/core/report.py b/yardstick/benchmark/core/report.py
index 0bc392fe5..17a9fe40c 100644
--- a/yardstick/benchmark/core/report.py
+++ b/yardstick/benchmark/core/report.py
@@ -10,13 +10,12 @@
""" Handler for yardstick command 'report' """
-import ast
import re
+import six
import uuid
import jinja2
from api.utils import influx
-from oslo_utils import encodeutils
from oslo_utils import uuidutils
from yardstick.common import constants as consts
from yardstick.common.utils import cliargs
@@ -115,10 +114,10 @@ class Report(object):
else:
raise KeyError("Test case not found.")
- def _get_tasks(self):
- task_cmd = "select * from \"%s\" where task_id= '%s'"
- task_query = task_cmd % (self.yaml_name, self.task_id)
- query_exec = influx.query(task_query)
+ def _get_metrics(self):
+ metrics_cmd = "select * from \"%s\" where task_id = '%s'"
+ metrics_query = metrics_cmd % (self.yaml_name, self.task_id)
+ query_exec = influx.query(metrics_query)
if query_exec:
return query_exec
else:
@@ -132,38 +131,72 @@ class Report(object):
"""
self._validate(args.yaml_name[0], args.task_id[0])
- self.db_fieldkeys = self._get_fieldkeys()
+ db_fieldkeys = self._get_fieldkeys()
+ # list of dicts of:
+ # - PY2: unicode key and unicode value
+ # - PY3: str key and str value
- self.db_task = self._get_tasks()
+ db_metrics = self._get_metrics()
+ # list of dicts of:
+ # - PY2: unicode key and { None | unicode | float | long | int } value
+ # - PY3: str key and { None | str | float | int } value
- field_keys = []
- datasets = []
- table_vals = {}
+ # extract fieldKey entries, and convert them to str where needed
+ field_keys = [key if isinstance(key, str) # PY3: already str
+ else key.encode('utf8') # PY2: unicode to str
+ for key in
+ [field['fieldKey']
+ for field in db_fieldkeys]]
- field_keys = [encodeutils.to_utf8(field['fieldKey'])
- for field in self.db_fieldkeys]
+ # extract timestamps
+ self.Timestamp = []
+ for metric in db_metrics:
+ metric_time = metric['time'] # in RFC3339 format
+ if not isinstance(metric_time, str):
+ metric_time = metric_time.encode('utf8') # PY2: unicode to str
+ metric_time = metric_time[11:] # skip date, keep time
+ head, _, tail = metric_time.partition('.') # split HH:MM:SS and nsZ
+ metric_time = head + '.' + tail[:6] # join HH:MM:SS and .us
+ self.Timestamp.append(metric_time) # HH:MM:SS.micros
+
+ # prepare return values
+ datasets = []
+ table_vals = {'Timestamp': self.Timestamp}
+ # extract and convert field values
for key in field_keys:
- self.Timestamp = []
values = []
- for task in self.db_task:
- task_time = encodeutils.to_utf8(task['time'])
- if not isinstance(task_time, str):
- task_time = str(task_time, 'utf8')
- if not isinstance(key, str):
- key = str(key, 'utf8')
- task_time = task_time[11:]
- head, _, tail = task_time.partition('.')
- task_time = head + "." + tail[:6]
- self.Timestamp.append(task_time)
- if task[key] is None:
- values.append(None)
- elif isinstance(task[key], (int, float)):
- values.append(task[key])
+ for metric in db_metrics:
+ val = metric.get(key, None)
+ if val is None:
+ # keep explicit None or missing entry as is
+ pass
+ elif isinstance(val, (int, float)):
+ # keep plain int or float as is
+ pass
+ elif six.PY2 and isinstance(val,
+ long): # pylint: disable=undefined-variable
+ # PY2: long value would be rendered with trailing L,
+ # which JS does not support, so convert it to float
+ val = float(val)
+ elif isinstance(val, six.string_types):
+ s = val
+ if not isinstance(s, str):
+ s = s.encode('utf8') # PY2: unicode to str
+ try:
+ # convert until failure
+ val = s
+ val = float(s)
+ val = int(s)
+ if six.PY2 and isinstance(val,
+ long): # pylint: disable=undefined-variable
+ val = float(val) # PY2: long to float
+ except ValueError:
+ pass
else:
- values.append(ast.literal_eval(task[key]))
+ raise ValueError("Cannot convert %r" % val)
+ values.append(val)
datasets.append({'label': key, 'data': values})
- table_vals['Timestamp'] = self.Timestamp
table_vals[key] = values
return datasets, table_vals