locking: Implement priority in Ganeti lock manager
[ganeti-local] / test / docs_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2009 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 02110-1301, USA.
20
21
22 """Script for unittesting documentation"""
23
24 import unittest
25 import re
26
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
32
33 import testutils
34
35
36 class TestDocs(unittest.TestCase):
37   """Documentation tests"""
38
39   @staticmethod
40   def _ReadDocFile(filename):
41     return utils.ReadFile("%s/doc/%s" %
42                           (testutils.GetSourceDir(), filename))
43
44   def testHookDocs(self):
45     """Check whether all hooks are documented.
46
47     """
48     hooksdoc = self._ReadDocFile("hooks.rst")
49
50     for name in dir(cmdlib):
51       obj = getattr(cmdlib, name)
52
53       if (isinstance(obj, type) and
54           issubclass(obj, cmdlib.LogicalUnit) and
55           hasattr(obj, "HPATH")):
56         self._CheckHook(name, obj, hooksdoc)
57
58   def _CheckHook(self, name, lucls, hooksdoc):
59     if lucls.HTYPE is None:
60       return
61
62     # TODO: Improve this test (e.g. find hooks documented but no longer
63     # existing)
64
65     pattern = r"^:directory:\s*%s\s*$" % re.escape(lucls.HPATH)
66
67     self.assert_(re.findall(pattern, hooksdoc, re.M),
68                  msg=("Missing documentation for hook %s/%s" %
69                       (lucls.HTYPE, lucls.HPATH)))
70
71
72   def testRapiDocs(self):
73     """Check whether all RAPI resources are documented.
74
75     """
76     rapidoc = self._ReadDocFile("rapi.rst")
77
78     node_name = "[node_name]"
79     instance_name = "[instance_name]"
80     job_id = "[job_id]"
81
82     resources = connector.GetHandlers(re.escape(node_name),
83                                       re.escape(instance_name),
84                                       re.escape(job_id))
85
86     titles = []
87
88     prevline = None
89     for line in rapidoc.splitlines():
90       if re.match(r"^\++$", line):
91         titles.append(prevline)
92
93       prevline = line
94
95     prefix_exception = frozenset(["/", "/version", "/2"])
96
97     undocumented = []
98
99     for key, handler in resources.iteritems():
100       # Regex objects
101       if hasattr(key, "match"):
102         self.assert_(key.pattern.startswith("^/2/"),
103                      msg="Pattern %r does not start with '^/2/'" % key.pattern)
104
105         found = False
106         for title in titles:
107           if (title.startswith("``") and
108               title.endswith("``") and
109               key.match(title[2:-2])):
110             found = True
111             break
112
113         if not found:
114           # TODO: Find better way of identifying resource
115           undocumented.append(key.pattern)
116
117       else:
118         self.assert_(key.startswith("/2/") or key in prefix_exception,
119                      msg="Path %r does not start with '/2/'" % key)
120
121         if ("``%s``" % key) not in titles:
122           undocumented.append(key)
123
124     self.failIf(undocumented,
125                 msg=("Missing RAPI resource documentation for %s" %
126                      utils.CommaJoin(undocumented)))
127
128
129 class TestManpages(unittest.TestCase):
130   """Manpage tests"""
131
132   @staticmethod
133   def _ReadManFile(name):
134     return utils.ReadFile("%s/man/%s.sgml" %
135                           (testutils.GetSourceDir(), name))
136
137   @staticmethod
138   def _LoadScript(name):
139     return build.LoadModule("scripts/%s" % name)
140
141   def test(self):
142     for script in _autoconf.GNT_SCRIPTS:
143       self._CheckManpage(script,
144                          self._ReadManFile(script),
145                          self._LoadScript(script).commands.keys())
146
147   def _CheckManpage(self, script, mantext, commands):
148     missing = []
149
150     for cmd in commands:
151       pattern = "<cmdsynopsis>\s*<command>%s</command>" % re.escape(cmd)
152       if not re.findall(pattern, mantext, re.S):
153         missing.append(cmd)
154
155     self.failIf(missing,
156                 msg=("Manpage for '%s' missing documentation for %s" %
157                      (script, utils.CommaJoin(missing))))
158
159
160 if __name__ == "__main__":
161   testutils.GanetiTestProgram()