add validation for topology and post event for cli
* check that limit is a positive number in 'vitrage topology show' * check that time is an iso8601 timestamp in 'vitrage event post' * add tests to check this Change-Id: If5c4b26578f865c68709027b6e815376e4ee9e1e
This commit is contained in:
parent
17ea93b290
commit
471cc55dcd
@ -8,3 +8,4 @@ cliff>=2.6.0 # Apache-2.0
|
|||||||
osc-lib>=1.5.1 # Apache-2.0
|
osc-lib>=1.5.1 # Apache-2.0
|
||||||
oslo.utils>=3.20.0 # Apache-2.0
|
oslo.utils>=3.20.0 # Apache-2.0
|
||||||
keystoneauth1>=2.21.0 # Apache-2.0
|
keystoneauth1>=2.21.0 # Apache-2.0
|
||||||
|
iso8601>=0.1.11 # MIT
|
@ -13,3 +13,4 @@ testrepository>=0.0.18 # Apache-2.0/BSD
|
|||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
testtools>=1.4.0 # MIT
|
testtools>=1.4.0 # MIT
|
||||||
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
||||||
|
mock>=2.0 # BSD
|
||||||
|
2
tox.ini
2
tox.ini
@ -10,7 +10,7 @@ install_command =
|
|||||||
setenv = VIRTUAL_ENV={envdir}
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/test-requirements.txt
|
-r{toxinidir}/test-requirements.txt
|
||||||
commands = rm -f .testrepository/times.dbm
|
commands = /bin/rm -f .testrepository/times.dbm
|
||||||
python setup.py test --slowest --testr-args='{posargs}'
|
python setup.py test --slowest --testr-args='{posargs}'
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
|
@ -10,7 +10,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.
|
||||||
|
|
||||||
import exc
|
from vitrageclient import exc
|
||||||
|
|
||||||
from keystoneauth1 import adapter as keystoneauth
|
from keystoneauth1 import adapter as keystoneauth
|
||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
|
@ -28,15 +28,15 @@ from cliff import app
|
|||||||
from cliff import commandmanager
|
from cliff import commandmanager
|
||||||
from keystoneauth1 import loading
|
from keystoneauth1 import loading
|
||||||
|
|
||||||
import client
|
|
||||||
|
|
||||||
from v1.cli import alarm
|
|
||||||
from v1.cli import event
|
|
||||||
from v1.cli import rca
|
|
||||||
from v1.cli import resource
|
|
||||||
from v1.cli import template
|
|
||||||
from v1.cli import topology
|
|
||||||
from vitrageclient import __version__
|
from vitrageclient import __version__
|
||||||
|
from vitrageclient import client
|
||||||
|
|
||||||
|
from vitrageclient.v1.cli import alarm
|
||||||
|
from vitrageclient.v1.cli import event
|
||||||
|
from vitrageclient.v1.cli import rca
|
||||||
|
from vitrageclient.v1.cli import resource
|
||||||
|
from vitrageclient.v1.cli import template
|
||||||
|
from vitrageclient.v1.cli import topology
|
||||||
|
|
||||||
|
|
||||||
class VitrageCommandManager(commandmanager.CommandManager):
|
class VitrageCommandManager(commandmanager.CommandManager):
|
||||||
|
0
vitrageclient/tests/cli/__init__.py
Normal file
0
vitrageclient/tests/cli/__init__.py
Normal file
@ -11,10 +11,18 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
# noinspection PyPackageRequirements
|
import argparse
|
||||||
|
|
||||||
from oslotest import base
|
from oslotest import base
|
||||||
|
|
||||||
|
|
||||||
class TestCase(base.BaseTestCase):
|
class CliTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
"""Test case base class for all unit tests."""
|
"""Test case base class for all unit tests."""
|
||||||
|
|
||||||
|
# original error method of argparse uses exit
|
||||||
|
# I just want to raise an exception and get the error message
|
||||||
|
# that exit outputs
|
||||||
|
@staticmethod
|
||||||
|
def _my_parser_error_func(message):
|
||||||
|
raise argparse.ArgumentTypeError(message)
|
53
vitrageclient/tests/cli/test_event_post.py
Normal file
53
vitrageclient/tests/cli/test_event_post.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Copyright 2017 Nokia
|
||||||
|
#
|
||||||
|
# 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 argparse import ArgumentParser
|
||||||
|
from argparse import ArgumentTypeError
|
||||||
|
|
||||||
|
# noinspection PyPackageRequirements
|
||||||
|
import mock
|
||||||
|
from testtools import ExpectedException
|
||||||
|
|
||||||
|
from vitrageclient.tests.cli.base import CliTestCase
|
||||||
|
from vitrageclient.v1.cli.event import EventPost
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAttributeOutsideInit
|
||||||
|
class EventPostTest(CliTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(EventPostTest, self).setUp()
|
||||||
|
self.event_post = EventPost(mock.Mock(), mock.Mock())
|
||||||
|
|
||||||
|
def test_parsing_iso8601_with_not_a_date_string(self):
|
||||||
|
self.assertRaises(ArgumentTypeError, self.event_post.iso8601, 'bla')
|
||||||
|
|
||||||
|
def test_parsing_iso8601_in_a_good_format(self):
|
||||||
|
self.event_post.iso8601('2014-12-13T12:44:21.123456')
|
||||||
|
|
||||||
|
def test_iso8601_parsing_with_wrong_date_format(self):
|
||||||
|
self.assertRaises(ArgumentTypeError, self.event_post.iso8601,
|
||||||
|
'2014/12/13 12:44:21')
|
||||||
|
|
||||||
|
@mock.patch.object(ArgumentParser, "error")
|
||||||
|
def test_parser_event_post_with_not_a_date_string(self, mock_parser):
|
||||||
|
mock_parser.side_effect = self._my_parser_error_func
|
||||||
|
parser = self.event_post.get_parser('vitrage event post')
|
||||||
|
|
||||||
|
# noinspection PyCallByClass
|
||||||
|
with ExpectedException(ArgumentTypeError,
|
||||||
|
'argument --time: -5 must be an iso8601 date'):
|
||||||
|
parser.parse_args(args=['--type', 'bla',
|
||||||
|
'--time', '-5',
|
||||||
|
'--details', 'blabla'])
|
71
vitrageclient/tests/cli/test_topology_show.py
Normal file
71
vitrageclient/tests/cli/test_topology_show.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Copyright 2017 Nokia
|
||||||
|
#
|
||||||
|
# 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 argparse import ArgumentParser
|
||||||
|
from argparse import ArgumentTypeError
|
||||||
|
|
||||||
|
# noinspection PyPackageRequirements
|
||||||
|
import mock
|
||||||
|
# noinspection PyPackageRequirements
|
||||||
|
from testtools import ExpectedException
|
||||||
|
|
||||||
|
from vitrageclient.tests.cli.base import CliTestCase
|
||||||
|
from vitrageclient.v1.cli.topology import TopologyShow
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAttributeOutsideInit
|
||||||
|
class TopologyShowTest(CliTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TopologyShowTest, self).setUp()
|
||||||
|
self.topology_show = TopologyShow(mock.Mock(), mock.Mock())
|
||||||
|
|
||||||
|
def test_positive_integer_validation_with_negative(self):
|
||||||
|
self.assertRaises(ArgumentTypeError,
|
||||||
|
self.topology_show.positive_non_zero_int, -1)
|
||||||
|
|
||||||
|
def test_positive_integer_validation_with_zero(self):
|
||||||
|
self.assertRaises(ArgumentTypeError,
|
||||||
|
self.topology_show.positive_non_zero_int, 0)
|
||||||
|
|
||||||
|
def test_positive_integer_validation_with_string(self):
|
||||||
|
self.assertRaises(ArgumentTypeError,
|
||||||
|
self.topology_show.positive_non_zero_int, 'bla')
|
||||||
|
|
||||||
|
def test_positive_integer_validation_with_positive(self):
|
||||||
|
self.topology_show.positive_non_zero_int(1)
|
||||||
|
|
||||||
|
@mock.patch.object(ArgumentParser, "error")
|
||||||
|
def test_parser_topology_limit_with_a_negative_number(self, mock_parser):
|
||||||
|
mock_parser.side_effect = self._my_parser_error_func
|
||||||
|
parser = self.topology_show.get_parser('vitrage topology show')
|
||||||
|
|
||||||
|
with ExpectedException(ArgumentTypeError,
|
||||||
|
'argument --limit: -5 must be greater than 0'):
|
||||||
|
parser.parse_args(args=['--filter', 'bla',
|
||||||
|
'--limit', '-5',
|
||||||
|
'--root', 'blabla',
|
||||||
|
'--graph-type', 'tree'])
|
||||||
|
|
||||||
|
@mock.patch.object(ArgumentParser, "error")
|
||||||
|
def test_parser_topology_limit_with_a_string(self, mock_parser):
|
||||||
|
mock_parser.side_effect = self._my_parser_error_func
|
||||||
|
parser = self.topology_show.get_parser('vitrage topology show')
|
||||||
|
|
||||||
|
with ExpectedException(ArgumentTypeError,
|
||||||
|
'argument --limit: spam must be an integer'):
|
||||||
|
parser.parse_args(args=['--filter', 'bla',
|
||||||
|
'--limit', 'spam',
|
||||||
|
'--root', 'blabla',
|
||||||
|
'--graph-type', 'tree'])
|
@ -1,26 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
test_vitrageclient
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
Tests for `vitrageclient` module.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from vitrageclient.tests import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestVitrageclient(base.TestCase):
|
|
||||||
|
|
||||||
def test_something(self):
|
|
||||||
pass
|
|
@ -14,8 +14,11 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from cliff import argparse
|
||||||
from cliff import command
|
from cliff import command
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from iso8601 import iso8601
|
||||||
|
from iso8601 import ParseError
|
||||||
|
|
||||||
from vitrageclient.common import exc
|
from vitrageclient.common import exc
|
||||||
|
|
||||||
@ -24,6 +27,14 @@ from vitrageclient.common import exc
|
|||||||
class EventPost(command.Command):
|
class EventPost(command.Command):
|
||||||
"""Show the event of the system"""
|
"""Show the event of the system"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def iso8601(argument_value):
|
||||||
|
try:
|
||||||
|
iso8601.parse_date(argument_value)
|
||||||
|
except ParseError:
|
||||||
|
msg = "%s must be an iso8601 date" % argument_value
|
||||||
|
raise argparse.ArgumentTypeError(msg)
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(EventPost, self).get_parser(prog_name)
|
parser = super(EventPost, self).get_parser(prog_name)
|
||||||
|
|
||||||
@ -32,6 +43,7 @@ class EventPost(command.Command):
|
|||||||
|
|
||||||
parser.add_argument('--time',
|
parser.add_argument('--time',
|
||||||
default='',
|
default='',
|
||||||
|
type=self.iso8601,
|
||||||
help='The timestamp of the event in ISO 8601 '
|
help='The timestamp of the event in ISO 8601 '
|
||||||
'format: YYYY-MM-DDTHH:MM:SS.mmmmmm. '
|
'format: YYYY-MM-DDTHH:MM:SS.mmmmmm. '
|
||||||
'If not specified, the current time is used')
|
'If not specified, the current time is used')
|
||||||
|
@ -10,6 +10,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 cliff import argparse
|
||||||
from cliff import show
|
from cliff import show
|
||||||
from vitrageclient.common import exc
|
from vitrageclient.common import exc
|
||||||
from vitrageclient.common import utils
|
from vitrageclient.common import utils
|
||||||
@ -19,6 +20,20 @@ from vitrageclient.common import utils
|
|||||||
class TopologyShow(show.ShowOne):
|
class TopologyShow(show.ShowOne):
|
||||||
"""Show the topology of the system"""
|
"""Show the topology of the system"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def positive_non_zero_int(argument_value):
|
||||||
|
if argument_value is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
value = int(argument_value)
|
||||||
|
except ValueError:
|
||||||
|
msg = "%s must be an integer" % argument_value
|
||||||
|
raise argparse.ArgumentTypeError(msg)
|
||||||
|
if value <= 0:
|
||||||
|
msg = "%s must be greater than 0" % argument_value
|
||||||
|
raise argparse.ArgumentTypeError(msg)
|
||||||
|
return value
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(TopologyShow, self).get_parser(prog_name)
|
parser = super(TopologyShow, self).get_parser(prog_name)
|
||||||
parser.add_argument('--filter',
|
parser.add_argument('--filter',
|
||||||
@ -26,7 +41,7 @@ class TopologyShow(show.ShowOne):
|
|||||||
help='query for the graph)')
|
help='query for the graph)')
|
||||||
|
|
||||||
parser.add_argument('--limit',
|
parser.add_argument('--limit',
|
||||||
type=int,
|
type=self.positive_non_zero_int,
|
||||||
metavar='<depth>',
|
metavar='<depth>',
|
||||||
help='the depth of the topology graph')
|
help='the depth of the topology graph')
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user