Statistics
| Branch: | Tag: | Revision:

root / test / docs_unittest.py @ e23881ed

History | View | Annotate | Download (4.6 kB)

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
    group_name = "[group_name]"
81
    job_id = "[job_id]"
82
    disk_index = "[disk_index]"
83

    
84
    resources = connector.GetHandlers(re.escape(node_name),
85
                                      re.escape(instance_name),
86
                                      re.escape(group_name),
87
                                      re.escape(job_id),
88
                                      re.escape(disk_index))
89

    
90
    titles = []
91

    
92
    prevline = None
93
    for line in rapidoc.splitlines():
94
      if re.match(r"^\++$", line):
95
        titles.append(prevline)
96

    
97
      prevline = line
98

    
99
    prefix_exception = frozenset(["/", "/version", "/2"])
100

    
101
    undocumented = []
102

    
103
    for key, handler in resources.iteritems():
104
      # Regex objects
105
      if hasattr(key, "match"):
106
        self.assert_(key.pattern.startswith("^/2/"),
107
                     msg="Pattern %r does not start with '^/2/'" % key.pattern)
108

    
109
        found = False
110
        for title in titles:
111
          if (title.startswith("``") and
112
              title.endswith("``") and
113
              key.match(title[2:-2])):
114
            found = True
115
            break
116

    
117
        if not found:
118
          # TODO: Find better way of identifying resource
119
          undocumented.append(key.pattern)
120

    
121
      else:
122
        self.assert_(key.startswith("/2/") or key in prefix_exception,
123
                     msg="Path %r does not start with '/2/'" % key)
124

    
125
        if ("``%s``" % key) not in titles:
126
          undocumented.append(key)
127

    
128
    self.failIf(undocumented,
129
                msg=("Missing RAPI resource documentation for %s" %
130
                     utils.CommaJoin(undocumented)))
131

    
132

    
133
class TestManpages(unittest.TestCase):
134
  """Manpage tests"""
135

    
136
  @staticmethod
137
  def _ReadManFile(name):
138
    return utils.ReadFile("%s/man/%s.rst" %
139
                          (testutils.GetSourceDir(), name))
140

    
141
  @staticmethod
142
  def _LoadScript(name):
143
    return build.LoadModule("scripts/%s" % name)
144

    
145
  def test(self):
146
    for script in _autoconf.GNT_SCRIPTS:
147
      self._CheckManpage(script,
148
                         self._ReadManFile(script),
149
                         self._LoadScript(script).commands.keys())
150

    
151
  def _CheckManpage(self, script, mantext, commands):
152
    missing = []
153

    
154
    for cmd in commands:
155
      pattern = r"^(\| )?\*\*%s\*\*" % re.escape(cmd)
156
      if not re.findall(pattern, mantext, re.DOTALL | re.MULTILINE):
157
        missing.append(cmd)
158

    
159
    self.failIf(missing,
160
                msg=("Manpage for '%s' missing documentation for %s" %
161
                     (script, utils.CommaJoin(missing))))
162

    
163

    
164
if __name__ == "__main__":
165
  testutils.GanetiTestProgram()