4 # Copyright (C) 2009 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting documentation"""
27 from ganeti import _autoconf
28 from ganeti import utils
29 from ganeti import cmdlib
30 from ganeti import build
31 from ganeti.rapi import connector
36 class TestDocs(unittest.TestCase):
37 """Documentation tests"""
40 def _ReadDocFile(filename):
41 return utils.ReadFile("%s/doc/%s" %
42 (testutils.GetSourceDir(), filename))
44 def testHookDocs(self):
45 """Check whether all hooks are documented.
48 hooksdoc = self._ReadDocFile("hooks.rst")
50 for name in dir(cmdlib):
51 obj = getattr(cmdlib, name)
53 if (isinstance(obj, type) and
54 issubclass(obj, cmdlib.LogicalUnit) and
55 hasattr(obj, "HPATH")):
56 self._CheckHook(name, obj, hooksdoc)
58 def _CheckHook(self, name, lucls, hooksdoc):
59 if lucls.HTYPE is None:
62 # TODO: Improve this test (e.g. find hooks documented but no longer
65 pattern = r"^:directory:\s*%s\s*$" % re.escape(lucls.HPATH)
67 self.assert_(re.findall(pattern, hooksdoc, re.M),
68 msg=("Missing documentation for hook %s/%s" %
69 (lucls.HTYPE, lucls.HPATH)))
72 def testRapiDocs(self):
73 """Check whether all RAPI resources are documented.
76 rapidoc = self._ReadDocFile("rapi.rst")
78 node_name = "[node_name]"
79 instance_name = "[instance_name]"
82 resources = connector.GetHandlers(re.escape(node_name),
83 re.escape(instance_name),
89 for line in rapidoc.splitlines():
90 if re.match(r"^\++$", line):
91 titles.append(prevline)
95 prefix_exception = frozenset(["/", "/version", "/2"])
99 for key, handler in resources.iteritems():
101 if hasattr(key, "match"):
102 self.assert_(key.pattern.startswith("^/2/"),
103 msg="Pattern %r does not start with '^/2/'" % key.pattern)
107 if (title.startswith("``") and
108 title.endswith("``") and
109 key.match(title[2:-2])):
114 # TODO: Find better way of identifying resource
115 undocumented.append(key.pattern)
118 self.assert_(key.startswith("/2/") or key in prefix_exception,
119 msg="Path %r does not start with '/2/'" % key)
121 if ("``%s``" % key) not in titles:
122 undocumented.append(key)
124 self.failIf(undocumented,
125 msg=("Missing RAPI resource documentation for %s" %
126 utils.CommaJoin(undocumented)))
129 class TestManpages(unittest.TestCase):
133 def _ReadManFile(name):
134 return utils.ReadFile("%s/man/%s.sgml" %
135 (testutils.GetSourceDir(), name))
138 def _LoadScript(name):
139 return build.LoadModule("scripts/%s" % name)
142 for script in _autoconf.GNT_SCRIPTS:
143 self._CheckManpage(script,
144 self._ReadManFile(script),
145 self._LoadScript(script).commands.keys())
147 def _CheckManpage(self, script, mantext, commands):
151 pattern = "<cmdsynopsis>\s*<command>%s</command>" % re.escape(cmd)
152 if not re.findall(pattern, mantext, re.S):
156 msg=("Manpage for '%s' missing documentation for %s" %
157 (script, utils.CommaJoin(missing))))
160 if __name__ == "__main__":
161 testutils.GanetiTestProgram()