From 29e22e45c565469258635cf65b6229dd13cf493f Mon Sep 17 00:00:00 2001 From: Sirushti Murugesan Date: Tue, 21 Apr 2015 12:33:12 +0530 Subject: [PATCH] Add some tests to validate specs Tests were added to - Compare titles with the skeleton template.rst. - Detect trailing whitespaces - Check lines are limited to a maximum of 79 characters. - Detect literal carriage returns Note: Taken from nova-specs/tests/test_titles.py and modified for Heat. Change-Id: Ib8bc85c086cbf37ec79b787c07657b9ffd7d17ac --- .gitignore | 2 + .testr.conf | 4 + .../support-to-generate-hot-templates.rst | 10 +- specs/liberty/type-in-attributes-schema.rst | 6 +- test-requirements.txt | 2 + tests/__init__.py | 0 tests/test_titles.py | 111 ++++++++++++++++++ tox.ini | 6 +- 8 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 .testr.conf create mode 100644 tests/__init__.py create mode 100644 tests/test_titles.py diff --git a/.gitignore b/.gitignore index 0f898542..7d28021c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ heat_specs.egg-info/ doc/build/ .tox/ +*.pyc +.testrepository diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 00000000..1641f86e --- /dev/null +++ b/.testr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/specs/liberty/support-to-generate-hot-templates.rst b/specs/liberty/support-to-generate-hot-templates.rst index 82012727..3f6d476b 100644 --- a/specs/liberty/support-to-generate-hot-templates.rst +++ b/specs/liberty/support-to-generate-hot-templates.rst @@ -11,14 +11,16 @@ https://blueprints.launchpad.net/heat/+spec/support-to-generate-hot-templates -This Blueprint will support to generate hot templates based on the specified type. +This Blueprint will support to generate hot templates based on the specified +type. Problem description =================== -Currently Heat only supports to generate the 'HeatTemplateFormatVersion' template -based on the specified resource type, this is the functionality exposed via the -'heat resource-type-template' command. And the link of the API: +Currently Heat only supports to generate the 'HeatTemplateFormatVersion' +template based on the specified resource type, this is the functionality +exposed via the 'heat resource-type-template' command. And the link of the +API: http://developer.openstack.org/api-ref-orchestration-v1.html diff --git a/specs/liberty/type-in-attributes-schema.rst b/specs/liberty/type-in-attributes-schema.rst index 78fbafb1..5b3d75c3 100644 --- a/specs/liberty/type-in-attributes-schema.rst +++ b/specs/liberty/type-in-attributes-schema.rst @@ -24,9 +24,9 @@ attributes also becomes a issue without the knowledge of the attribute type. Proposed change =============== -The changes will be made in each resource plugin to add type field in the attribute -schema. Type can be a String, Map or List. This will also generate the docs telling -the users what type of value to expect from get_attr. +The changes will be made in each resource plugin to add type field in the +attribute schema. Type can be a String, Map or List. This will also generate +the docs telling the users what type of value to expect from get_attr. Alternatives ------------ diff --git a/test-requirements.txt b/test-requirements.txt index e69de29b..b23d4c7e 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +testrepository>=0.0.18 +testtools>=0.9.34 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_titles.py b/tests/test_titles.py new file mode 100644 index 00000000..f235ed53 --- /dev/null +++ b/tests/test_titles.py @@ -0,0 +1,111 @@ +# 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 glob +import re + +import docutils.core +import testtools + + +class TestTitles(testtools.TestCase): + def _get_title(self, section_tree): + section = { + 'subtitles': [], + } + for node in section_tree: + if node.tagname == 'title': + section['name'] = node.rawsource + elif node.tagname == 'section': + subsection = self._get_title(node) + section['subtitles'].append(subsection['name']) + return section + + def _get_titles(self, spec): + titles = {} + for node in spec: + if node.tagname == 'section': + # Note subsection subtitles are thrown away + section = self._get_title(node) + titles[section['name']] = section['subtitles'] + return titles + + def _check_titles(self, filename, expect, actual): + missing_sections = [x for x in expect.keys() if ( + x not in actual.keys())] + extra_sections = [x for x in actual.keys() if x not in expect.keys()] + + msgs = [] + if len(missing_sections) > 0: + msgs.append("Missing sections: %s" % missing_sections) + if len(extra_sections) > 0: + msgs.append("Extra sections: %s" % extra_sections) + + for section in expect.keys(): + missing_subsections = [x for x in expect[section] + if x not in actual[section]] + # extra subsections are allowed + if len(missing_subsections) > 0: + msgs.append("Section '%s' is missing subsections: %s" + % (section, missing_subsections)) + + if len(msgs) > 0: + self.fail("While checking '%s':\n %s" + % (filename, "\n ".join(msgs))) + + def _check_lines_wrapping(self, tpl, raw): + for i, line in enumerate(raw.split("\n")): + if "http://" in line or "https://" in line: + continue + self.assertTrue( + len(line) < 80, + msg="%s:%d: Line limited to a maximum of 79 characters." % + (tpl, i+1)) + + def _check_no_cr(self, tpl, raw): + matches = re.findall('\r', raw) + self.assertEqual( + 0, len(matches), + "Found %s literal carriage returns in file %s" % + (len(matches), tpl)) + + def _check_trailing_spaces(self, tpl, raw): + for i, line in enumerate(raw.split("\n")): + trailing_spaces = re.findall(" +$", line) + self.assertEqual( + 0, len(trailing_spaces), + "Found trailing spaces on line %s of %s" % (i+1, tpl)) + + def test_template(self): + releases = [x.split('/')[1] for x in glob.glob('specs/*/')] + # Ignore juno and kilo. + releases.remove('juno') + releases.remove('kilo') + for release in releases: + with open("specs/%s/template.rst" % release) as f: + template = f.read() + spec = docutils.core.publish_doctree(template) + template_titles = self._get_titles(spec) + + files = glob.glob("specs/%s/*" % release) + for filename in files: + self.assertTrue(filename.endswith(".rst"), + "spec's file must uses 'rst' extension.") + with open(filename) as f: + data = f.read() + + spec = docutils.core.publish_doctree(data) + titles = self._get_titles(spec) + self._check_titles(filename, template_titles, titles) + self._check_lines_wrapping(filename, data) + self._check_no_cr(filename, data) + self._check_trailing_spaces(filename, data) diff --git a/tox.ini b/tox.ini index c354f609..33f83a57 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.6 -envlist = docs +envlist = docs,py27 skipsdist = True [testenv] @@ -10,6 +10,10 @@ setenv = VIRTUAL_ENV={envdir} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt +whitelist_externals = find +commands = + find . -type f -name "*.pyc" -delete + python setup.py testr --slowest --testr-args='{posargs}' [testenv:venv] commands = {posargs}