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:
Eyal 2017-06-27 12:34:02 +03:00
parent 17ea93b290
commit 471cc55dcd
12 changed files with 174 additions and 39 deletions

View File

@ -8,3 +8,4 @@ cliff>=2.6.0 # Apache-2.0
osc-lib>=1.5.1 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
keystoneauth1>=2.21.0 # Apache-2.0
iso8601>=0.1.11 # MIT

View File

@ -13,3 +13,4 @@ testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
reno!=2.3.1,>=1.8.0 # Apache-2.0
mock>=2.0 # BSD

View File

@ -10,7 +10,7 @@ install_command =
setenv = VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/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}'
[testenv:pep8]

View File

@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import exc
from vitrageclient import exc
from keystoneauth1 import adapter as keystoneauth
from oslo_utils import importutils

View File

@ -28,15 +28,15 @@ from cliff import app
from cliff import commandmanager
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 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):

View File

View File

@ -11,10 +11,18 @@
# License for the specific language governing permissions and limitations
# under the License.
# noinspection PyPackageRequirements
import argparse
from oslotest import base
class TestCase(base.BaseTestCase):
class CliTestCase(base.BaseTestCase):
"""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)

View 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'])

View 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'])

View File

@ -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

View File

@ -14,8 +14,11 @@
import json
from cliff import argparse
from cliff import command
from datetime import datetime
from iso8601 import iso8601
from iso8601 import ParseError
from vitrageclient.common import exc
@ -24,6 +27,14 @@ from vitrageclient.common import exc
class EventPost(command.Command):
"""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):
parser = super(EventPost, self).get_parser(prog_name)
@ -32,6 +43,7 @@ class EventPost(command.Command):
parser.add_argument('--time',
default='',
type=self.iso8601,
help='The timestamp of the event in ISO 8601 '
'format: YYYY-MM-DDTHH:MM:SS.mmmmmm. '
'If not specified, the current time is used')

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from cliff import argparse
from cliff import show
from vitrageclient.common import exc
from vitrageclient.common import utils
@ -19,6 +20,20 @@ from vitrageclient.common import utils
class TopologyShow(show.ShowOne):
"""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):
parser = super(TopologyShow, self).get_parser(prog_name)
parser.add_argument('--filter',
@ -26,7 +41,7 @@ class TopologyShow(show.ShowOne):
help='query for the graph)')
parser.add_argument('--limit',
type=int,
type=self.positive_non_zero_int,
metavar='<depth>',
help='the depth of the topology graph')