Merge "Add Python 3.4 as supported interpreters"

This commit is contained in:
Jenkins 2015-03-10 19:57:05 +00:00 committed by Gerrit Code Review
commit ec14f4ef08
10 changed files with 82 additions and 18 deletions

View File

@ -7,7 +7,7 @@
# #
# NOTE: The script assumes that you have the following # NOTE: The script assumes that you have the following
# programs already installed: # programs already installed:
# -> Python 2.6 or Python 2.7 # -> Python 2.6, Python 2.7 or Python 3.4
set -e set -e

View File

@ -19,6 +19,7 @@ import itertools
import random import random
import time import time
from rally.common import costilius
from rally.common import log as logging from rally.common import log as logging
from rally.common import utils from rally.common import utils
from rally import consts from rally import consts
@ -58,7 +59,7 @@ class Scenario(object):
self._admin_clients = admin_clients self._admin_clients = admin_clients
self._clients = clients self._clients = clients
self._idle_duration = 0 self._idle_duration = 0
self._atomic_actions = {} self._atomic_actions = costilius.OrderedDict()
# TODO(amaretskiy): consider about prefix part of benchmark uuid # TODO(amaretskiy): consider about prefix part of benchmark uuid
@classmethod @classmethod

View File

@ -323,12 +323,12 @@ def _add_command_parsers(categories, subparsers):
def validate_deprecated_args(argv, fn): def validate_deprecated_args(argv, fn):
if (len(argv) > 3 if (len(argv) > 3
and (argv[2] == fn.func_name) and (argv[2] == fn.__name__)
and getattr(fn, "deprecated_args", None)): and getattr(fn, "deprecated_args", None)):
for item in fn.deprecated_args: for item in fn.deprecated_args:
if item in argv[3:]: if item in argv[3:]:
LOG.warning("Deprecated argument %s for %s." % (item, LOG.warning("Deprecated argument %s for %s." % (item,
fn.func_name)) fn.__name__))
def run(argv, categories): def run(argv, categories):
@ -379,14 +379,15 @@ def run(argv, categories):
return(0) return(0)
fn = CONF.category.action_fn fn = CONF.category.action_fn
fn_args = [arg.decode("utf-8") for arg in CONF.category.action_args] fn_args = [encodeutils.safe_decode(arg)
for arg in CONF.category.action_args]
fn_kwargs = {} fn_kwargs = {}
for k in CONF.category.action_kwargs: for k in CONF.category.action_kwargs:
v = getattr(CONF.category, "action_kwarg_" + k) v = getattr(CONF.category, "action_kwarg_" + k)
if v is None: if v is None:
continue continue
if isinstance(v, six.string_types): if isinstance(v, six.string_types):
v = v.decode("utf-8") v = encodeutils.safe_decode(v)
fn_kwargs[k] = v fn_kwargs[k] = v
# call the action with the remaining arguments # call the action with the remaining arguments

View File

@ -608,7 +608,8 @@ class TaskCommands(object):
STATUS_FAIL = "FAIL" STATUS_FAIL = "FAIL"
for result in results: for result in results:
key = result["key"] key = result["key"]
for sla in result["data"]["sla"]: for sla in sorted(result["data"]["sla"],
key=lambda x: x["criterion"]):
success = sla.pop("success") success = sla.pop("success")
sla["status"] = success and STATUS_PASS or STATUS_FAIL sla["status"] = success and STATUS_PASS or STATUS_FAIL
sla["benchmark"] = key["name"] sla["benchmark"] = key["name"]
@ -616,7 +617,7 @@ class TaskCommands(object):
failed_criteria += int(not success) failed_criteria += int(not success)
data.append(sla if tojson else rutils.Struct(**sla)) data.append(sla if tojson else rutils.Struct(**sla))
if tojson: if tojson:
print(json.dumps(data)) print(json.dumps(data, sort_keys=False))
else: else:
cliutils.print_list(data, ("benchmark", "pos", "criterion", cliutils.print_list(data, ("benchmark", "pos", "criterion",
"status", "detail")) "status", "detail"))

51
rally/common/costilius.py Normal file
View File

@ -0,0 +1,51 @@
#
# All Rights Reserved.
#
# 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.
#
"""
This module is a storage for different types of workarounds.
"""
import sys
try:
from collections import OrderedDict # noqa
except ImportError:
# NOTE(andreykurilin): Python 2.6 issue. OrderedDict is not
# present in `collections` library.
from ordereddict import OrderedDict # noqa
def is_py26():
return sys.version_info[:2] == (2, 6)
if is_py26():
import simplejson as json
else:
import json
def json_loads(*args, **kwargs):
"""Deserialize a str or unicode instance to a Python object.
'simplejson' is used in Python 2.6 environment, because standard 'json'
library not include several important features(for example
'object_pairs_hook', which allows to deserialize input object to
OrderedDict)
"""
return json.loads(*args, **kwargs)

View File

@ -19,6 +19,8 @@ from sqlalchemy.dialects import mysql as mysql_types
from sqlalchemy.ext import mutable from sqlalchemy.ext import mutable
from sqlalchemy import types as sa_types from sqlalchemy import types as sa_types
from rally.common import costilius
class JSONEncodedDict(sa_types.TypeDecorator): class JSONEncodedDict(sa_types.TypeDecorator):
"""Represents an immutable structure as a json-encoded string.""" """Represents an immutable structure as a json-encoded string."""
@ -27,12 +29,13 @@ class JSONEncodedDict(sa_types.TypeDecorator):
def process_bind_param(self, value, dialect): def process_bind_param(self, value, dialect):
if value is not None: if value is not None:
value = json.dumps(value) value = json.dumps(value, sort_keys=False)
return value return value
def process_result_value(self, value, dialect): def process_result_value(self, value, dialect):
if value is not None: if value is not None:
value = json.loads(value) value = costilius.json_loads(
value, object_pairs_hook=costilius.OrderedDict)
return value return value

View File

@ -37,3 +37,7 @@ requests>=2.2.0,!=2.4.0
SQLAlchemy>=0.9.7,<=0.9.99 SQLAlchemy>=0.9.7,<=0.9.99
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
six>=1.9.0 six>=1.9.0
# Python 2.6 related packages(see rally.common.costilius for more details)
ordereddict
simplejson>=2.2.0

View File

@ -17,6 +17,8 @@ classifier =
Programming Language :: Python :: 2 Programming Language :: Python :: 2
Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
[files] [files]
packages = packages =

View File

@ -535,11 +535,11 @@ class SLATestCase(unittest.TestCase):
rally("task sla_check") rally("task sla_check")
expected = [ expected = [
{"benchmark": "KeystoneBasic.create_and_list_users", {"benchmark": "KeystoneBasic.create_and_list_users",
"criterion": "max_seconds_per_iteration", "criterion": "failure_rate",
"detail": mock.ANY, "detail": mock.ANY,
"pos": 0, "status": "PASS"}, "pos": 0, "status": "PASS"},
{"benchmark": "KeystoneBasic.create_and_list_users", {"benchmark": "KeystoneBasic.create_and_list_users",
"criterion": "failure_rate", "criterion": "max_seconds_per_iteration",
"detail": mock.ANY, "detail": mock.ANY,
"pos": 0, "status": "PASS"} "pos": 0, "status": "PASS"}
] ]

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_utils import encodeutils
from six.moves import configparser from six.moves import configparser
import inspect import inspect
@ -37,7 +38,7 @@ class RallyCmdError(Exception):
def __init__(self, code, output): def __init__(self, code, output):
self.code = code self.code = code
self.output = output self.output = encodeutils.safe_decode(output)
def __str__(self): def __str__(self):
return "Code: %d Output: %s\n" % (self.code, self.output) return "Code: %d Output: %s\n" % (self.code, self.output)
@ -50,7 +51,7 @@ class TaskConfig(object):
def __init__(self, config): def __init__(self, config):
config_file = tempfile.NamedTemporaryFile(delete=False) config_file = tempfile.NamedTemporaryFile(delete=False)
config_file.write(json.dumps(config).encode("utf-8")) config_file.write(encodeutils.safe_encode(json.dumps(config)))
config_file.close() config_file.close()
self.filename = config_file.name self.filename = config_file.name
@ -159,7 +160,7 @@ class Rally(object):
:param getjson: in cases, when rally prints JSON, you can catch output :param getjson: in cases, when rally prints JSON, you can catch output
deserialized deserialized
:param report_path: if present, rally command and its output will be :param report_path: if present, rally command and its output will be
wretten to file with passed file name written to file with passed file name
:param raw: don't write command itself to report file. Only output :param raw: don't write command itself to report file. Only output
will be written will be written
""" """
@ -167,8 +168,8 @@ class Rally(object):
if not isinstance(cmd, list): if not isinstance(cmd, list):
cmd = cmd.split(" ") cmd = cmd.split(" ")
try: try:
output = subprocess.check_output(self.args + cmd, output = encodeutils.safe_decode(subprocess.check_output(
stderr=subprocess.STDOUT) self.args + cmd, stderr=subprocess.STDOUT))
if write_report: if write_report:
if not report_path: if not report_path:
@ -181,6 +182,6 @@ class Rally(object):
if getjson: if getjson:
return json.loads(output) return json.loads(output)
return output.decode("utf-8") return output
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
raise RallyCmdError(e.returncode, e.output) raise RallyCmdError(e.returncode, e.output)