Add `--show-traffic` feature to aid Redfish diagnostics

Added `--show-traffic` command-line option that makes `sushycli`
pretty-printing full HTTP exchange with the Redfish agent.

This feature can be handy for troubleshooting fishy matters.

Change-Id: I0d427f13d509d59b742be32ef3aeee061a7de662
This commit is contained in:
Ilya Etingof 2020-03-17 12:32:27 +01:00
parent 87261f9790
commit 9463bec49e
7 changed files with 360 additions and 63 deletions

View File

@ -16,6 +16,6 @@ Sphinx==1.6.2
sphinxcontrib-websupport==1.0.1
stevedore==1.29.0
stestr==2.0.0
sushy==3.1.0
sushy==3.2.0
testtools==2.2.0
urllib3==1.22

View File

@ -0,0 +1,6 @@
---
features:
- |
Adds ``--show-traffic`` command-line option that makes ``sushycli``
pretty-printing full HTTP exchange with Redfish agent. This feature
can be handy for Redfish issues troubleshooting.

View File

@ -2,6 +2,6 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
sushy>=3.1.0 # Apache-2.0
sushy>=3.2.0 # Apache-2.0
cliff>=2.17.0 # Apache-2.0
urllib3>=1.22 # MIT

View File

@ -15,12 +15,16 @@
# under the License.
import argparse
import json
import sys
from urllib.parse import urlsplit
from urllib.parse import urlunsplit
from cliff import command
from cliff import lister
import sushy
from sushy import connector
import urllib3
@ -56,8 +60,57 @@ class BaseParserMixIn(object):
help='Path to a CA bundle or a directory containing trusted '
'TLS certificates.')
parser.add_argument(
'--show-traffic',
action='store_true',
help='Show Redfish HTTP message exchange.')
return parser
def _to_json(self, data):
"""Turn input object into JSON when possible.
:param data: object to jsonize
:type data: dict or str or None
"""
if not data:
data = {}
elif isinstance(data, (str, bytes)):
try:
data = json.loads(data)
except json.JSONDecodeError as exc:
self.app.LOG.error(
'Malformed JSON document %(doc)s: %(error)s',
{'doc': data, 'error': exc})
data = {}
else:
data = dict(data)
return json.dumps(data, indent=2)
def observer(self, response):
"""Pretty print HTTP request and response details.
:param response: HTTP response object
:type response: requests.Response
"""
sys.stdout.write(
'%s %s\n%s\n%s\n' % (
response.request.method, response.request.url,
self._to_json(response.request.headers),
self._to_json(response.request.body)))
sys.stdout.write(
'%s %s\n%s\n%s\n' % (
response.reason, response.status_code,
self._to_json(response.headers),
self._to_json(response.text)))
sys.stdout.flush()
def take_action(self, args):
"""Common base for all command actions
@ -78,8 +131,10 @@ class BaseParserMixIn(object):
address.append('')
path.append(component)
base_url = urlunsplit(address)
kwargs = {
'base_url': urlunsplit(address),
'base_url': base_url,
'username': args.username,
'password': args.password,
}
@ -96,6 +151,12 @@ class BaseParserMixIn(object):
urllib3.disable_warnings(
urllib3.exceptions.InsecureRequestWarning)
conn = connector.Connector(
base_url, verify=verify,
response_callback=args.show_traffic and self.observer)
kwargs.update(connector=conn)
return sushy.Sushy(**kwargs)

View File

@ -24,53 +24,95 @@ from sushycli.tests.unit import base
@mock.patch.object(sushy, 'Sushy', autospec=True)
@mock.patch.object(sushy.connector, 'Connector', autospec=True)
class SuchyCliTestCase(base.TestCase):
@mock.patch('sys.stdout.write', autospec=True)
def test_insecure(self, mock_write, mock_sushy):
def test_show_traffic(self, mock_write, mock_connector, mock_sushy):
main(['version', 'show',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me', '--show-traffic'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=mock.ANY, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
@mock.patch('sys.stdout.write', autospec=True)
def test_insecure(self, mock_write, mock_connector, mock_sushy):
main(['version', 'show',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me', '--insecure'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=False)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly', verify=False)
'http://fish.me', connector=mock_connection,
password='fish', username='jelly', verify=False)
@mock.patch('sys.stdout.write', autospec=True)
def test_tls_certificate(self, mock_write, mock_sushy):
def test_tls_certificate(self, mock_write, mock_connector, mock_sushy):
main(['version', 'show',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me',
'--tls-certificate', '/dev/null'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify='/dev/null')
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly',
verify='/dev/null')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly', verify='/dev/null')
@mock.patch('sys.stdout.write', autospec=True)
def test_service_endpoint_default(self, mock_write, mock_sushy):
def test_service_endpoint_default(
self, mock_write, mock_connector, mock_sushy):
main(['version', 'show',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
@mock.patch('sys.stdout.write', autospec=True)
def test_service_endpoint_mounted(self, mock_write, mock_sushy):
def test_service_endpoint_mounted(
self, mock_write, mock_connector, mock_sushy):
main(['version', 'show',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me:1234/out'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me:1234', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me:1234', password='fish', username='jelly',
'http://fish.me:1234', connector=mock_connection,
password='fish', username='jelly',
root_prefix='/out')
@mock.patch('sys.stdout.write', autospec=True)
def test_version(self, mock_write, mock_sushy):
def test_version(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -80,8 +122,14 @@ class SuchyCliTestCase(base.TestCase):
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+---------+\n'
@ -95,7 +143,8 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_manager_vmedia_list(self, mock_write, mock_sushy):
def test_manager_vmedia_list(
self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -114,8 +163,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--manager-id', '/redfish/v1/Managers/BMC'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+-----------------------------------------'
@ -135,7 +190,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
def test_manager_vmedia_insert(self, mock_sushy):
def test_manager_vmedia_insert(self, mock_connector, mock_sushy):
main(['manager', 'vmedia', 'insert',
'--username', 'jelly', '--password', 'fish',
@ -144,8 +199,14 @@ class SuchyCliTestCase(base.TestCase):
'--device-id', '/redfish/v1/Managers/BMC/VirtualMedia/Cd',
'--image', 'http://fish.me/fishiso.iso'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -159,7 +220,7 @@ class SuchyCliTestCase(base.TestCase):
mock_vmedia.insert_media.\
assert_called_once_with('http://fish.me/fishiso.iso')
def test_manager_vmedia_eject(self, mock_sushy):
def test_manager_vmedia_eject(self, mock_connector, mock_sushy):
main(['manager', 'vmedia', 'eject',
'--username', 'jelly', '--password', 'fish',
@ -167,8 +228,14 @@ class SuchyCliTestCase(base.TestCase):
'--manager-id', '/redfish/v1/Managers/BMC',
'--device-id', '/redfish/v1/Managers/BMC/VirtualMedia/Cd'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -182,7 +249,7 @@ class SuchyCliTestCase(base.TestCase):
mock_vmedia.eject_media.assert_called_once()
@mock.patch('sys.stdout.write', autospec=True)
def test_system_boot_show(self, mock_write, mock_sushy):
def test_system_boot_show(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -199,8 +266,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+-----------+----------------------+-------------+----'
@ -217,7 +290,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_system_bios_show(self, mock_write, mock_sushy):
def test_system_bios_show(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
mock_system = mock_root.get_system.return_value
@ -232,8 +305,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+----------------+-------------+\n'
@ -249,14 +328,21 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
def test_system_bios_reset(self, mock_sushy):
def test_system_bios_reset(self, mock_connector, mock_sushy):
main(['system', 'bios', 'reset',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -267,7 +353,7 @@ class SuchyCliTestCase(base.TestCase):
mock_system.bios.reset_bios.assert_called_once()
def test_system_bios_set(self, mock_sushy):
def test_system_bios_set(self, mock_connector, mock_sushy):
main(['system', 'bios', 'set',
'--username', 'jelly', '--password', 'fish',
@ -275,8 +361,15 @@ class SuchyCliTestCase(base.TestCase):
'--system-id', '/redfish/v1/Systems/1',
'BootMode=Uefi', 'EmbeddedSata=Raid',
'NicBoot1=NetworkBoot', 'ProcTurboMode=Enabled'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -294,15 +387,23 @@ class SuchyCliTestCase(base.TestCase):
}
)
def test_system_bios_set_with_keys_blanks(self, mock_sushy):
def test_system_bios_set_with_keys_blanks(
self, mock_connector, mock_sushy):
main(['system', 'bios', 'set',
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1',
'BootMode =Uefi', ' EmbeddedSata=Raid'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -318,7 +419,7 @@ class SuchyCliTestCase(base.TestCase):
}
)
def test_system_boot_set(self, mock_sushy):
def test_system_boot_set(self, mock_connector, mock_sushy):
main(['system', 'boot', 'set',
'--username', 'jelly', '--password', 'fish',
@ -328,8 +429,14 @@ class SuchyCliTestCase(base.TestCase):
'--enabled', 'once',
'--mode', 'uefi'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
@ -344,7 +451,8 @@ class SuchyCliTestCase(base.TestCase):
mode=sushy.BOOT_SOURCE_MODE_UEFI)
@mock.patch('sys.stdout.write', autospec=True)
def test_chassis_inventory_show(self, mock_write, mock_sushy):
def test_chassis_inventory_show(
self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -365,8 +473,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--chassis-id', '/redfish/v1/Chassis/1U'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+----------+------+-------------+--------------+-----'
@ -386,7 +500,8 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_manager_inventory_show(self, mock_write, mock_sushy):
def test_manager_inventory_show(
self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -407,8 +522,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--manager-id', '/redfish/v1/Mnagers/BMC'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
@ -423,7 +544,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_system_list(self, mock_write, mock_sushy):
def test_system_list(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -442,8 +563,14 @@ class SuchyCliTestCase(base.TestCase):
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+------+--------------------------------------+------'
@ -460,7 +587,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_manager_list(self, mock_write, mock_sushy):
def test_manager_list(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -479,8 +606,14 @@ class SuchyCliTestCase(base.TestCase):
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+------+--------------------------------------+------'
@ -497,7 +630,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_chassis_list(self, mock_write, mock_sushy):
def test_chassis_list(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -516,8 +649,14 @@ class SuchyCliTestCase(base.TestCase):
'--username', 'jelly', '--password', 'fish',
'--service-endpoint', 'http://fish.me'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+------+--------------------------------------+------'
@ -533,7 +672,8 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_system_inventory_show(self, mock_write, mock_sushy):
def test_system_inventory_show(
self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -554,8 +694,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+----------+------+-------------+--------------+-----'
@ -575,7 +721,7 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
@mock.patch('sys.stdout.write', autospec=True)
def test_system_power_show(self, mock_write, mock_sushy):
def test_system_power_show(self, mock_write, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
@ -588,8 +734,14 @@ class SuchyCliTestCase(base.TestCase):
'--service-endpoint', 'http://fish.me',
'--system-id', '/redfish/v1/Systems/1'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
expected_calls = [
mock.call('+-------------+\n'
@ -602,7 +754,13 @@ class SuchyCliTestCase(base.TestCase):
mock_write.assert_has_calls(expected_calls)
def test_system_power_on(self, mock_sushy):
def test_system_power_on(self, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
mock_system = mock_root.get_system.return_value
mock_system.power_state = 'off'
main(['system', 'power',
'--username', 'jelly', '--password', 'fish',
@ -610,19 +768,28 @@ class SuchyCliTestCase(base.TestCase):
'--system-id', '/redfish/v1/Systems/1',
'on'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
mock_root.get_system.assert_called_once_with(
'/redfish/v1/Systems/1')
mock_root.get_system.assert_called_once_with('/redfish/v1/Systems/1')
mock_system = mock_root.get_system.return_value
mock_system.reset_system.assert_called_once_with('on')
def test_system_power_off(self, mock_sushy):
def test_system_power_off(self, mock_connector, mock_sushy):
mock_root = mock_sushy.return_value
mock_system = mock_root.get_system.return_value
mock_system.power_state = 'on'
main(['system', 'power',
'--username', 'jelly', '--password', 'fish',
@ -630,13 +797,16 @@ class SuchyCliTestCase(base.TestCase):
'--system-id', '/redfish/v1/Systems/1',
'Off'])
mock_connection = mock_connector.return_value
mock_connector.assert_called_once_with(
'http://fish.me', response_callback=False, verify=True)
mock_sushy.assert_called_once_with(
'http://fish.me', password='fish', username='jelly')
'http://fish.me', connector=mock_connection,
password='fish', username='jelly')
mock_root = mock_sushy.return_value
mock_root.get_system.assert_called_once_with(
'/redfish/v1/Systems/1')
mock_root.get_system.assert_called_once_with('/redfish/v1/Systems/1')
mock_system = mock_root.get_system.return_value

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# Copyright 2020 OpenStack Foundation
# 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.
import mock
from sushycli.base import BaseParserMixIn
from sushycli.tests.unit import base
class BaseParserMixInTestCase(base.TestCase):
def setUp(self):
super(BaseParserMixInTestCase, self).setUp()
self.obj = BaseParserMixIn()
def test__to_json_from_none(self):
output = self.obj._to_json(None)
expected = '{}'
self.assertEqual(expected, output)
def test__to_json_from_dict(self):
output = self.obj._to_json({'test': 1})
expected = '{\n "test": 1\n}'
self.assertEqual(expected, output)
def test__to_json_from_json(self):
output = self.obj._to_json('{"test": 1}')
expected = '{\n "test": 1\n}'
self.assertEqual(expected, output)
def test__to_json_malformed(self):
self.obj.app = mock.MagicMock()
output = self.obj._to_json('not json')
expected = '{}'
self.assertEqual(expected, output)
self.assertEqual(1, self.obj.app.LOG.error.call_count)

View File

@ -14,16 +14,16 @@
# License for the specific language governing permissions and limitations
# under the License.
from sushycli.base import BaseLister
from sushycli import base
class VersionShow(BaseLister):
"""Read supported Redfish protocol version of remote agent.
class VersionShow(base.BaseLister):
"""Show Redfish protocol version implemented by the BMC
Implements `sushycli version` command.
Implements `sushycli version show` command.
"""
def get_parser(self, prog_name):
"""Redfish versioin command parser.
"""Redfish version command parser.
:param prog_name: name of the cliff command being executed
:returns: an `argparse.ArgumentParser` instance