Compare commits

..

18 Commits

Author SHA1 Message Date
Zuul
673905fead Merge "Update links in README" 2018-04-02 08:09:51 +00:00
Zuul
d886672fb5 Merge "add lower-constraints job" 2018-03-29 10:01:43 +00:00
Alexander Chadin
83ccfbb177 [WiP] functional jobs fix
Change-Id: If92660ad48b19fce47dd7a88ed33796427f70a80
2018-03-28 09:11:18 +00:00
Zuul
4c47c7364c Merge "ZuulV3 support for watcherclient" 2018-03-27 16:48:01 +00:00
Alexander Chadin
8acf01859c ZuulV3 support for watcherclient
Change-Id: I0efc302dae72d18f86dbdae1d22a6ea798cfb8f5
2018-03-27 18:38:55 +03:00
Zuul
d4af8d8834 Merge "Delete the unnecessary '-'" 2018-03-26 09:30:30 +00:00
Doug Hellmann
40d8df21c8 add lower-constraints job
Create a tox environment for running the unit tests against the lower
bounds of the dependencies.

Create a lower-constraints.txt to be used to enforce the lower bounds
in those tests.

Add openstack-tox-lower-constraints job to the zuul configuration.

See http://lists.openstack.org/pipermail/openstack-dev/2018-March/128352.html
for more details.

Change-Id: I11c8526b413e6dfc6e2457026ccc2f35e38d1699
Depends-On: https://review.openstack.org/555034
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2018-03-25 11:32:15 -04:00
Zuul
b87399cb2c Merge "Add tempest plugin" 2018-03-23 12:56:05 +00:00
Alexander Chadin
9bfefbf9ab Add tempest plugin
This patch set adds tempest plugin to register existing tempest
tests of watcherclient. It is also required to let devstack-tempest
job to launch watcherclient functional tests.

Change-Id: I4d906fd597048bb37803a2bb42f8357502cf1b76
2018-03-23 14:36:38 +03:00
huang.zhiping
b84039d7d4 Delete the unnecessary '-'
Change-Id: I6f36a4114026368d854fac37dcd003d3f4236455
2018-03-23 11:29:03 +08:00
OpenStack Proposal Bot
f8ead12481 Updated from global requirements
Change-Id: I35f49cea5915272e21ac1351dfb190c2b55be335
2018-03-15 08:06:52 +00:00
OpenStack Proposal Bot
85e4e364b7 Updated from global requirements
Change-Id: I46b763854d736e74523106240e1faf06150a3139
2018-03-13 07:30:46 +00:00
melissaml
ed9ce5b952 Update links in README
Change the outdated links to the latest links in README

Change-Id: I0a0781d4a86bb860bb8c85923e7be8b803f91ae2
2018-03-11 03:01:04 +08:00
Zuul
731e019bc1 Merge "Fix global efficacy format" 2018-02-23 09:09:47 +00:00
OpenStack Proposal Bot
a22dab5f88 Updated from global requirements
Change-Id: Ib45b0cc6fefd94b3c3a8181bd10b0d85f8044800
2018-02-17 10:20:48 +00:00
Alexander Chadin
0d7233055d Fix global efficacy format
Closes-Bug: #1749463
Change-Id: I0496f0d82bbf72dbbc8b808feb3a529ad6d49402
2018-02-14 17:06:15 +03:00
Zuul
2777a9bba8 Merge "Zuul: Remove project name" 2018-02-07 08:23:00 +00:00
James E. Blair
e359488cde Zuul: Remove project name
Zuul no longer requires the project-name for in-repo configuration.
Omitting it makes forking or renaming projects easier.

Change-Id: I884a00879ac30b504833951303578de42174ba09
2018-02-02 10:11:34 -08:00
17 changed files with 290 additions and 115 deletions

3
.stestr.conf Normal file
View File

@@ -0,0 +1,3 @@
[DEFAULT]
test_path=${OS_TEST_PATH:-./watcherclient/tests/functional}
top_dir=./

View File

@@ -1,8 +1,9 @@
- project:
name: openstack/python-watcherclient
check:
jobs:
- watcherclient-tempest-functional
- openstack-tox-lower-constraints
gate:
jobs:
- watcherclient-tempest-functional
- openstack-tox-lower-constraints

View File

@@ -2,8 +2,8 @@
Team and repository tags
========================
.. image:: https://governance.openstack.org/badges/python-watcherclient.svg
:target: https://governance.openstack.org/reference/tags/index.html
.. image:: https://governance.openstack.org/tc/badges/python-watcherclient.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
.. Change things from this point on
@@ -20,7 +20,7 @@ metrics receiver, complex event processor and profiler, optimization processor
and an action plan applier. This provides a robust framework to realize a wide
range of cloud optimization goals, including the reduction of data center
operating costs, increased system performance via intelligent virtual machine
migration, increased energy efficiency-and more!
migration, increased energy efficiency and more!
* Free software: Apache license
* Wiki: https://wiki.openstack.org/wiki/Watcher

92
lower-constraints.txt Normal file
View File

@@ -0,0 +1,92 @@
alabaster==0.7.10
appdirs==1.4.3
asn1crypto==0.23.0
Babel==2.5.3
certifi==2018.1.18
cffi==1.7.0
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.2
coverage==4.0
cryptography==2.1
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
docutils==0.11
dogpile.cache==0.6.5
dulwich==0.15.0
extras==1.0.0
fasteners==0.7.0
fixtures==3.0.0
flake8==2.5.5
future==0.16.0
hacking==0.12.0
idna==2.6
imagesize==0.7.1
iso8601==0.1.12
Jinja2==2.10
jmespath==0.9.3
jsonpatch==1.21
jsonpointer==2.0
jsonschema==2.6.0
keystoneauth1==3.4.0
linecache2==1.0.0
MarkupSafe==1.0
mccabe==0.2.1
mock==2.0.0
monotonic==1.4
mox3==0.20.0
msgpack-python==0.4.0
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
openstackdocstheme==1.18.1
openstacksdk==0.12.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
osc-lib==1.10.0
oslo.concurrency==3.25.0
oslo.config==5.2.0
oslo.context==2.19.2
oslo.i18n==3.20.0
oslo.log==3.36.0
oslo.serialization==2.18.0
oslo.utils==3.36.0
oslotest==3.2.0
packaging==17.1
paramiko==2.0.0
pbr==3.1.1
pep8==1.5.7
prettytable==0.7.2
pyasn1==0.1.8
pycparser==2.18
pyflakes==0.8.1
Pygments==2.2.0
pyinotify==0.9.6
pyparsing==2.2.0
pyperclip==1.6.0
python-dateutil==2.5.3
python-mimeparse==1.6.0
python-subunit==1.0.0
-e git://git.openstack.org/openstack/python-watcherclient@104894958882a4877dad6f469361d2adb41d0b59#egg=python_watcherclient
pytz==2018.3
PyYAML==3.12
requests==2.18.4
requestsexceptions==1.4.0
rfc3986==0.3.1
simplejson==3.13.2
six==1.11.0
snowballstemmer==1.2.1
Sphinx==1.6.5
sphinxcontrib-websupport==1.0.1
stestr==1.0.0
stevedore==1.28.0
tempest==17.1.0
testrepository==0.0.18
testscenarios==0.4
testtools==2.2.0
traceback2==1.4.0
unittest2==1.1.0
urllib3==1.22
wrapt==1.10.11

View File

@@ -9,6 +9,6 @@ oslo.i18n>=3.15.3 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
pbr!=2.1.0,>=2.0.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
keystoneauth1>=3.3.0 # Apache-2.0
keystoneauth1>=3.4.0 # Apache-2.0
six>=1.10.0 # MIT
PyYAML>=3.10 # MIT
PyYAML>=3.12 # MIT

View File

@@ -25,6 +25,8 @@ packages =
[entry_points]
console_scripts =
watcher = watcherclient.shell:main
tempest.test_plugins =
watcherclient_tests = watcherclient.plugin:WatcherClientTempestPlugin
openstack.cli.extension =
infra_optim = watcherclient.osc.plugin

View File

@@ -9,7 +9,7 @@ mock>=2.0.0 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
sphinx!=1.6.6,>=1.6.2 # BSD
sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=2.2.0 # MIT

View File

@@ -60,3 +60,11 @@ commands = python setup.py bdist_wheel
[hacking]
import_exceptions = watcherclient._i18n
[testenv:lower-constraints]
basepython = python3
install_command = pip install -U {opts} {packages}
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt

23
watcherclient/config.py Normal file
View File

@@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2018 Servionica
#
# 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.
from oslo_config import cfg
service_option = cfg.BoolOpt("watcher_client",
default=True,
help="Whether or not watcher_client is expected"
"to be available")

34
watcherclient/plugin.py Normal file
View File

@@ -0,0 +1,34 @@
# 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
from tempest.test_discover import plugins
from watcherclient import config as watcher_config
class WatcherClientTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "watcherclient/tests/functional/v1"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
conf.register_opt(watcher_config.service_option,
group='service_available')
def get_opt_lists(self):
return [('service_available', [watcher_config.service_option])]

View File

@@ -1,53 +0,0 @@
#!/bin/bash -xe
# 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 script is executed inside post_test_hook function in devstack gate.
# Default gate uses /opt/stack/new... but some of us may install differently
STACK_DIR=$BASE/new/devstack
function generate_testr_results {
if [ -f .testrepository/0 ]; then
sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
sudo gzip -9 $BASE/logs/testrepository.subunit
sudo gzip -9 $BASE/logs/testr_results.html
sudo chown $USER:$USER $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
fi
}
export WATCHERCLIENT_DIR="$BASE/new/python-watcherclient"
sudo chown -R $USER:stack $WATCHERCLIENT_DIR
# Get admin credentials
cd $STACK_DIR
source openrc admin admin
# Go to the watcherclient dir
cd $WATCHERCLIENT_DIR
# Run tests
echo "Running watcherclient functional test suite"
set +e
# Preserve env for OS_ credentials
sudo -E -H -u $USER tox -efunctional
EXIT_CODE=$?
set -e
# Collect and parse result
generate_testr_results
exit $EXIT_CODE

View File

@@ -18,22 +18,31 @@ import subprocess
import testtools
import six
from tempest import clients
from tempest.common import credentials_factory as creds_factory
from tempest.lib.cli import output_parser
from tempest.lib import exceptions
def credentials():
creds = {
'--os-username': os.environ.get('OS_USERNAME', 'admin'),
'--os-password': os.environ.get('OS_PASSWORD', 'secretadmin'),
'--os-project-name': os.environ.get('OS_PROJECT_NAME', 'admin'),
# You can get credentials either from tempest.conf file or
# from OS environment.
tempest_creds = clients.get_auth_provider(
creds_factory.get_configured_admin_credentials())
creds = tempest_creds.credentials
creds_dict = {
'--os-username': os.environ.get('OS_USERNAME', creds.username),
'--os-password': os.environ.get('OS_PASSWORD', creds.password),
'--os-project-name': os.environ.get('OS_PROJECT_NAME',
creds.project_name),
'--os-auth-url': os.environ.get('OS_AUTH_URL',
'http://10.0.1.94/identity'),
'--os-project-domain-id': os.environ.get('OS_PROJECT_DOMAIN_ID',
'default'),
'--os-user-domain-id': os.environ.get('OS_USER_DOMAIN_ID', 'default'),
tempest_creds.auth_url),
'--os-project-domain-name': os.environ.get('OS_PROJECT_DOMAIN_ID',
creds.project_domain_name),
'--os-user-domain-name': os.environ.get('OS_USER_DOMAIN_ID',
creds.user_domain_name),
}
return [x for sub in creds.items() for x in sub]
return [x for sub in creds_dict.items() for x in sub]
def execute(cmd, fail_ok=False, merge_stderr=False):
@@ -123,3 +132,13 @@ class TestCase(testtools.TestCase):
def parse_listing(self, raw_output):
"""Return list of dicts with basic item parsed from cli output."""
return output_parser.listing(raw_output)
def has_actionplan_succeeded(self, ap_uuid):
return self.parse_show_as_object(
self.watcher('actionplan show %s' % ap_uuid)
)['State'] == 'SUCCEEDED'
@classmethod
def has_audit_created(cls, audit_uuid):
return cls.parse_show_as_object(
cls.watcher('audit show %s' % audit_uuid))['State'] == 'SUCCEEDED'

View File

@@ -15,6 +15,10 @@
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -33,17 +37,22 @@ class ActionTests(base.TestCase):
template_raw_output = cls.watcher(
'audittemplate create %s dummy -s dummy' % cls.audit_template_name)
template_output = cls.parse_show_as_object(template_raw_output)
audit_raw_output = cls.watcher(
'audit create -a %s' % template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
audit_output = cls.parse_show_as_object(cls.watcher(
'audit create -a %s' % template_output['Name']))
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
# Delete Action Plan and all related actions.
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = output[0].keys()[0]
action_plan_uuid = list(output[0])[0]
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.assertOutput('', raw_output)
# Delete audit
@@ -63,9 +72,10 @@ class ActionTests(base.TestCase):
self.assert_table_structure([raw_output], self.detailed_list_fields)
def test_action_show(self):
action_list = self.parse_show(self.watcher('action list'))
action_uuid = action_list[0].keys()[0]
action = self.watcher('action show ' + action_uuid)
action_list = self.parse_show(self.watcher('action list --audit %s'
% self.audit_uuid))
action_uuid = list(action_list[0])[0]
action = self.watcher('action show %s' % action_uuid)
self.assertIn(action_uuid, action)
self.assert_table_structure([action],
self.detailed_list_fields)

View File

@@ -13,10 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -39,22 +41,19 @@ class ActionPlanTests(base.TestCase):
% template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
# Delete action plan
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = output[0].keys()[0]
retry = 10
while retry > 0:
output = cls.parse_show(
cls.watcher('actionplan show %s' % action_plan_uuid))
state = [x for x in output if x.keys()[0] == 'State'][0]['State']
if state == 'SUCCEEDED':
break
time.sleep(1)
retry -= 1
action_plan_uuid = list(output[0])[0]
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.assertOutput('', raw_output)
# Delete audit
@@ -75,7 +74,7 @@ class ActionPlanTests(base.TestCase):
def test_action_plan_show(self):
action_plan_list = self.parse_show(self.watcher('actionplan list'))
action_plan_uuid = action_plan_list[0].keys()[0]
action_plan_uuid = list(action_plan_list[0])[0]
actionplan = self.watcher('actionplan show %s' % action_plan_uuid)
self.assertIn(action_plan_uuid, actionplan)
self.assert_table_structure([actionplan],
@@ -84,11 +83,18 @@ class ActionPlanTests(base.TestCase):
def test_action_plan_start(self):
output = self.parse_show(self.watcher('actionplan list --audit %s'
% self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
action_plan_uuid = list(output[0])[0]
self.watcher('actionplan start %s' % action_plan_uuid)
raw_output = self.watcher('actionplan show %s' % action_plan_uuid)
self.assert_table_structure([raw_output], self.detailed_list_fields)
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_actionplan_succeeded, action_plan_uuid),
duration=600,
sleep_for=2
))
class ActionPlanActiveTests(base.TestCase):
@@ -100,9 +106,15 @@ class ActionPlanActiveTests(base.TestCase):
'Strategy', 'Efficacy indicators']
def _delete_action_plan(self):
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_audit_created, self.audit_uuid),
duration=600,
sleep_for=2
))
output = self.parse_show(
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
action_plan_uuid = list(output[0])[0]
raw_output = self.watcher('actionplan delete %s' % action_plan_uuid)
self.assertOutput('', raw_output)

View File

@@ -15,6 +15,10 @@
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -39,12 +43,18 @@ class AuditTests(base.TestCase):
'audit create -a %s' % template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = output[0].keys()[0]
action_plan_uuid = list(output[0])[0]
cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.watcher('audit delete %s' % cls.audit_uuid)
cls.watcher('audittemplate delete %s' % cls.audit_template_name)
@@ -76,39 +86,51 @@ class AuditActiveTests(base.TestCase):
'Deleted At', 'Parameters',
'Interval', 'Audit Scope']
audit_template_name = 'a' + uuidutils.generate_uuid()
audit_uuid = None
@classmethod
def setUpClass(cls):
cls.watcher('audittemplate create %s dummy -s dummy'
% cls.audit_template_name)
@classmethod
def tearDownClass(cls):
cls.watcher('audittemplate delete %s' % cls.audit_template_name)
def _create_audit(self):
raw_output = self.watcher('audittemplate create %s dummy -s dummy'
% self.audit_template_name)
template_output = self.parse_show_as_object(raw_output)
self.audit_uuid = self.parse_show_as_object(
return self.parse_show_as_object(
self.watcher('audit create -a %s'
% template_output['Name']))['UUID']
% self.audit_template_name))['UUID']
def _delete_audit(self):
def _delete_audit(self, audit_uuid):
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_audit_created, audit_uuid),
duration=600,
sleep_for=2
))
output = self.parse_show(
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
self.watcher('actionplan list --audit %s' % audit_uuid))
action_plan_uuid = list(output[0])[0]
self.watcher('actionplan delete %s' % action_plan_uuid)
self.watcher('audit delete %s' % self.audit_uuid)
self.watcher('audittemplate delete %s' % self.audit_template_name)
self.watcher('audit delete %s' % audit_uuid)
def test_create_audit(self):
raw_output = self.watcher('audittemplate create %s dummy -s dummy'
% self.audit_template_name)
template_output = self.parse_show_as_object(raw_output)
audit = self.watcher('audit create -a %s' % template_output['Name'])
self.audit_uuid = self.parse_show_as_object(audit)['UUID']
audit = self.watcher('audit create -a %s' % self.audit_template_name)
audit_uuid = self.parse_show_as_object(audit)['UUID']
self.assert_table_structure([audit], self.detailed_list_fields)
self._delete_audit()
self._delete_audit(audit_uuid)
def test_delete_audit(self):
self._create_audit()
raw_output = self.watcher('audit delete %s' % self.audit_uuid)
audit_uuid = self._create_audit()
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_audit_created, audit_uuid),
duration=600,
sleep_for=2
))
raw_output = self.watcher('audit delete %s' % audit_uuid)
self.assertOutput('', raw_output)
output = self.parse_show(
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
self.watcher('actionplan list --audit %s' % audit_uuid))
action_plan_uuid = list(output[0])[0]
self.watcher('actionplan delete %s' % action_plan_uuid)
self.watcher('audittemplate delete %s' % self.audit_template_name)

View File

@@ -37,6 +37,8 @@ class ServiceTests(base.TestCase):
self.list_fields + ['Last seen up'])
def test_service_show(self):
# TODO(alexchadin): this method should be refactored since Watcher will
# get HA support soon.
raw_output = self.watcher('service show %s'
% self.decision_engine_name)
self.assertIn(self.decision_engine_name, raw_output)

View File

@@ -28,8 +28,8 @@ from watcherclient.v1 import resource_fields as res_fields
def format_global_efficacy(global_efficacy):
formatted_global_eff = {}
for eff in global_efficacy:
eff_name = eff.get('name')
if (eff.get('value') is not None and eff.get('unit')):
eff_name = eff.get('name')
formatted_global_eff[eff_name] = "%(value).2f %(unit)s" % dict(
unit=eff.get('unit'),
value=eff.get('value'))