test_setup.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. # Copyright (c) 2011 OpenStack Foundation
  2. # Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
  3. # All Rights Reserved.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  6. # not use this file except in compliance with the License. You may obtain
  7. # a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. # License for the specific language governing permissions and limitations
  15. # under the License.
  16. from __future__ import print_function
  17. import os
  18. try:
  19. import cStringIO as io
  20. BytesIO = io.StringIO
  21. except ImportError:
  22. import io
  23. BytesIO = io.BytesIO
  24. import fixtures
  25. from pbr import git
  26. from pbr import options
  27. from pbr import packaging
  28. from pbr.tests import base
  29. class SkipFileWrites(base.BaseTestCase):
  30. scenarios = [
  31. ('changelog_option_true',
  32. dict(option_key='skip_changelog', option_value='True',
  33. env_key='SKIP_WRITE_GIT_CHANGELOG', env_value=None,
  34. pkg_func=git.write_git_changelog, filename='ChangeLog')),
  35. ('changelog_option_false',
  36. dict(option_key='skip_changelog', option_value='False',
  37. env_key='SKIP_WRITE_GIT_CHANGELOG', env_value=None,
  38. pkg_func=git.write_git_changelog, filename='ChangeLog')),
  39. ('changelog_env_true',
  40. dict(option_key='skip_changelog', option_value='False',
  41. env_key='SKIP_WRITE_GIT_CHANGELOG', env_value='True',
  42. pkg_func=git.write_git_changelog, filename='ChangeLog')),
  43. ('changelog_both_true',
  44. dict(option_key='skip_changelog', option_value='True',
  45. env_key='SKIP_WRITE_GIT_CHANGELOG', env_value='True',
  46. pkg_func=git.write_git_changelog, filename='ChangeLog')),
  47. ('authors_option_true',
  48. dict(option_key='skip_authors', option_value='True',
  49. env_key='SKIP_GENERATE_AUTHORS', env_value=None,
  50. pkg_func=git.generate_authors, filename='AUTHORS')),
  51. ('authors_option_false',
  52. dict(option_key='skip_authors', option_value='False',
  53. env_key='SKIP_GENERATE_AUTHORS', env_value=None,
  54. pkg_func=git.generate_authors, filename='AUTHORS')),
  55. ('authors_env_true',
  56. dict(option_key='skip_authors', option_value='False',
  57. env_key='SKIP_GENERATE_AUTHORS', env_value='True',
  58. pkg_func=git.generate_authors, filename='AUTHORS')),
  59. ('authors_both_true',
  60. dict(option_key='skip_authors', option_value='True',
  61. env_key='SKIP_GENERATE_AUTHORS', env_value='True',
  62. pkg_func=git.generate_authors, filename='AUTHORS')),
  63. ]
  64. def setUp(self):
  65. super(SkipFileWrites, self).setUp()
  66. self.temp_path = self.useFixture(fixtures.TempDir()).path
  67. self.root_dir = os.path.abspath(os.path.curdir)
  68. self.git_dir = os.path.join(self.root_dir, ".git")
  69. if not os.path.exists(self.git_dir):
  70. self.skipTest("%s is missing; skipping git-related checks"
  71. % self.git_dir)
  72. return
  73. self.filename = os.path.join(self.temp_path, self.filename)
  74. self.option_dict = dict()
  75. if self.option_key is not None:
  76. self.option_dict[self.option_key] = ('setup.cfg',
  77. self.option_value)
  78. self.useFixture(
  79. fixtures.EnvironmentVariable(self.env_key, self.env_value))
  80. def test_skip(self):
  81. self.pkg_func(git_dir=self.git_dir,
  82. dest_dir=self.temp_path,
  83. option_dict=self.option_dict)
  84. self.assertEqual(
  85. not os.path.exists(self.filename),
  86. (self.option_value.lower() in options.TRUE_VALUES
  87. or self.env_value is not None))
  88. _changelog_content = """7780758\x00Break parser\x00 (tag: refs/tags/1_foo.1)
  89. 04316fe\x00Make python\x00 (refs/heads/review/monty_taylor/27519)
  90. 378261a\x00Add an integration test script.\x00
  91. 3c373ac\x00Merge "Lib\x00 (HEAD, tag: refs/tags/2013.2.rc2, tag: refs/tags/2013.2, refs/heads/mile-proposed)
  92. 182feb3\x00Fix pip invocation for old versions of pip.\x00 (tag: refs/tags/0.5.17)
  93. fa4f46e\x00Remove explicit depend on distribute.\x00 (tag: refs/tags/0.5.16)
  94. d1c53dd\x00Use pip instead of easy_install for installation.\x00
  95. a793ea1\x00Merge "Skip git-checkout related tests when .git is missing"\x00
  96. 6c27ce7\x00Skip git-checkout related tests when .git is missing\x00
  97. 451e513\x00Bug fix: create_stack() fails when waiting\x00
  98. 4c8cfe4\x00Improve test coverage: network delete API\x00 (tag: refs/tags/(evil))
  99. d7e6167\x00Bug fix: Fix pass thru filtering in list_networks\x00 (tag: refs/tags/ev()il)
  100. c47ec15\x00Consider 'in-use' a non-pending volume for caching\x00 (tag: refs/tags/ev)il)
  101. 8696fbd\x00Improve test coverage: private extension API\x00 (tag: refs/tags/ev(il)
  102. f0440f8\x00Improve test coverage: hypervisor list\x00 (tag: refs/tags/e(vi)l)
  103. 04984a5\x00Refactor hooks file.\x00 (HEAD, tag: 0.6.7,b, tag: refs/tags/(12), refs/heads/master)
  104. a65e8ee\x00Remove jinja pin.\x00 (tag: refs/tags/0.5.14, tag: refs/tags/0.5.13)
  105. """ # noqa
  106. def _make_old_git_changelog_format(line):
  107. """Convert post-1.8.1 git log format to pre-1.8.1 git log format"""
  108. if not line.strip():
  109. return line
  110. sha, msg, refname = line.split('\x00')
  111. refname = refname.replace('tag: ', '')
  112. return '\x00'.join((sha, msg, refname))
  113. _old_git_changelog_content = '\n'.join(
  114. _make_old_git_changelog_format(line)
  115. for line in _changelog_content.split('\n'))
  116. class GitLogsTest(base.BaseTestCase):
  117. scenarios = [
  118. ('pre1.8.3', {'changelog': _old_git_changelog_content}),
  119. ('post1.8.3', {'changelog': _changelog_content}),
  120. ]
  121. def setUp(self):
  122. super(GitLogsTest, self).setUp()
  123. self.temp_path = self.useFixture(fixtures.TempDir()).path
  124. self.root_dir = os.path.abspath(os.path.curdir)
  125. self.git_dir = os.path.join(self.root_dir, ".git")
  126. self.useFixture(
  127. fixtures.EnvironmentVariable('SKIP_GENERATE_AUTHORS'))
  128. self.useFixture(
  129. fixtures.EnvironmentVariable('SKIP_WRITE_GIT_CHANGELOG'))
  130. def test_write_git_changelog(self):
  131. self.useFixture(fixtures.FakePopen(lambda _: {
  132. "stdout": BytesIO(self.changelog.encode('utf-8'))
  133. }))
  134. git.write_git_changelog(git_dir=self.git_dir,
  135. dest_dir=self.temp_path)
  136. with open(os.path.join(self.temp_path, "ChangeLog"), "r") as ch_fh:
  137. changelog_contents = ch_fh.read()
  138. self.assertIn("2013.2", changelog_contents)
  139. self.assertIn("0.5.17", changelog_contents)
  140. self.assertIn("------", changelog_contents)
  141. self.assertIn("Refactor hooks file", changelog_contents)
  142. self.assertIn(
  143. "Bug fix: create\_stack() fails when waiting",
  144. changelog_contents)
  145. self.assertNotIn("Refactor hooks file.", changelog_contents)
  146. self.assertNotIn("182feb3", changelog_contents)
  147. self.assertNotIn("review/monty_taylor/27519", changelog_contents)
  148. self.assertNotIn("0.5.13", changelog_contents)
  149. self.assertNotIn("0.6.7", changelog_contents)
  150. self.assertNotIn("12", changelog_contents)
  151. self.assertNotIn("(evil)", changelog_contents)
  152. self.assertNotIn("ev()il", changelog_contents)
  153. self.assertNotIn("ev(il", changelog_contents)
  154. self.assertNotIn("ev)il", changelog_contents)
  155. self.assertNotIn("e(vi)l", changelog_contents)
  156. self.assertNotIn('Merge "', changelog_contents)
  157. self.assertNotIn('1\_foo.1', changelog_contents)
  158. def test_generate_authors(self):
  159. author_old = u"Foo Foo <email@foo.com>"
  160. author_new = u"Bar Bar <email@bar.com>"
  161. co_author = u"Foo Bar <foo@bar.com>"
  162. co_author_by = u"Co-authored-by: " + co_author
  163. git_log_cmd = (
  164. "git --git-dir=%s log --format=%%aN <%%aE>"
  165. % self.git_dir)
  166. git_co_log_cmd = ("git --git-dir=%s log" % self.git_dir)
  167. git_top_level = "git rev-parse --show-toplevel"
  168. cmd_map = {
  169. git_log_cmd: author_new,
  170. git_co_log_cmd: co_author_by,
  171. git_top_level: self.root_dir,
  172. }
  173. exist_files = [self.git_dir,
  174. os.path.join(self.temp_path, "AUTHORS.in")]
  175. self.useFixture(fixtures.MonkeyPatch(
  176. "os.path.exists",
  177. lambda path: os.path.abspath(path) in exist_files))
  178. def _fake_run_shell_command(cmd, **kwargs):
  179. return cmd_map[" ".join(cmd)]
  180. self.useFixture(fixtures.MonkeyPatch(
  181. "pbr.git._run_shell_command",
  182. _fake_run_shell_command))
  183. with open(os.path.join(self.temp_path, "AUTHORS.in"), "w") as auth_fh:
  184. auth_fh.write("%s\n" % author_old)
  185. git.generate_authors(git_dir=self.git_dir,
  186. dest_dir=self.temp_path)
  187. with open(os.path.join(self.temp_path, "AUTHORS"), "r") as auth_fh:
  188. authors = auth_fh.read()
  189. self.assertTrue(author_old in authors)
  190. self.assertTrue(author_new in authors)
  191. self.assertTrue(co_author in authors)
  192. class _SphinxConfig(object):
  193. man_pages = ['foo']
  194. class BaseSphinxTest(base.BaseTestCase):
  195. def setUp(self):
  196. super(BaseSphinxTest, self).setUp()
  197. # setup_command requires the Sphinx instance to have some
  198. # attributes that aren't set normally with the way we use the
  199. # class (because we replace the constructor). Add default
  200. # values directly to the class definition.
  201. import sphinx.application
  202. sphinx.application.Sphinx.messagelog = []
  203. sphinx.application.Sphinx.statuscode = 0
  204. self.useFixture(fixtures.MonkeyPatch(
  205. "sphinx.application.Sphinx.__init__", lambda *a, **kw: None))
  206. self.useFixture(fixtures.MonkeyPatch(
  207. "sphinx.application.Sphinx.build", lambda *a, **kw: None))
  208. self.useFixture(fixtures.MonkeyPatch(
  209. "sphinx.application.Sphinx.config", _SphinxConfig))
  210. self.useFixture(fixtures.MonkeyPatch(
  211. "sphinx.config.Config.init_values", lambda *a: None))
  212. self.useFixture(fixtures.MonkeyPatch(
  213. "sphinx.config.Config.__init__", lambda *a: None))
  214. from distutils import dist
  215. self.distr = dist.Distribution()
  216. self.distr.packages = ("fake_package",)
  217. self.distr.command_options["build_sphinx"] = {
  218. "source_dir": ["a", "."]}
  219. pkg_fixture = fixtures.PythonPackage(
  220. "fake_package", [("fake_module.py", b""),
  221. ("another_fake_module_for_testing.py", b""),
  222. ("fake_private_module.py", b"")])
  223. self.useFixture(pkg_fixture)
  224. self.useFixture(base.DiveDir(pkg_fixture.base))
  225. self.distr.command_options["pbr"] = {}
  226. if hasattr(self, "excludes"):
  227. self.distr.command_options["pbr"]["autodoc_exclude_modules"] = (
  228. 'setup.cfg',
  229. "fake_package.fake_private_module\n"
  230. "fake_package.another_fake_*\n"
  231. "fake_package.unknown_module")
  232. if hasattr(self, 'has_opt') and self.has_opt:
  233. options = self.distr.command_options["pbr"]
  234. options["autodoc_index_modules"] = ('setup.cfg', self.autodoc)
  235. class BuildSphinxTest(BaseSphinxTest):
  236. scenarios = [
  237. ('true_autodoc_caps',
  238. dict(has_opt=True, autodoc='True', has_autodoc=True)),
  239. ('true_autodoc_caps_with_excludes',
  240. dict(has_opt=True, autodoc='True', has_autodoc=True,
  241. excludes="fake_package.fake_private_module\n"
  242. "fake_package.another_fake_*\n"
  243. "fake_package.unknown_module")),
  244. ('true_autodoc_lower',
  245. dict(has_opt=True, autodoc='true', has_autodoc=True)),
  246. ('false_autodoc',
  247. dict(has_opt=True, autodoc='False', has_autodoc=False)),
  248. ('no_autodoc',
  249. dict(has_opt=False, autodoc='False', has_autodoc=False)),
  250. ]
  251. def test_build_doc(self):
  252. build_doc = packaging.LocalBuildDoc(self.distr)
  253. build_doc.run()
  254. self.assertTrue(
  255. os.path.exists("api/autoindex.rst") == self.has_autodoc)
  256. self.assertTrue(
  257. os.path.exists(
  258. "api/fake_package.fake_module.rst") == self.has_autodoc)
  259. if not self.has_autodoc or hasattr(self, "excludes"):
  260. assertion = self.assertFalse
  261. else:
  262. assertion = self.assertTrue
  263. assertion(
  264. os.path.exists(
  265. "api/fake_package.fake_private_module.rst"))
  266. assertion(
  267. os.path.exists(
  268. "api/fake_package.another_fake_module_for_testing.rst"))
  269. def test_builders_config(self):
  270. build_doc = packaging.LocalBuildDoc(self.distr)
  271. build_doc.finalize_options()
  272. self.assertEqual(1, len(build_doc.builders))
  273. self.assertIn('html', build_doc.builders)
  274. build_doc = packaging.LocalBuildDoc(self.distr)
  275. build_doc.builders = ''
  276. build_doc.finalize_options()
  277. self.assertEqual('', build_doc.builders)
  278. build_doc = packaging.LocalBuildDoc(self.distr)
  279. build_doc.builders = 'man'
  280. build_doc.finalize_options()
  281. self.assertEqual(1, len(build_doc.builders))
  282. self.assertIn('man', build_doc.builders)
  283. build_doc = packaging.LocalBuildDoc(self.distr)
  284. build_doc.builders = 'html,man,doctest'
  285. build_doc.finalize_options()
  286. self.assertIn('html', build_doc.builders)
  287. self.assertIn('man', build_doc.builders)
  288. self.assertIn('doctest', build_doc.builders)
  289. def test_cmd_builder_override(self):
  290. if self.has_opt:
  291. self.distr.command_options["pbr"] = {
  292. "autodoc_index_modules": ('setup.cfg', self.autodoc)
  293. }
  294. self.distr.command_options["build_sphinx"]["builder"] = (
  295. "command line", "non-existing-builder")
  296. build_doc = packaging.LocalBuildDoc(self.distr)
  297. self.assertNotIn('non-existing-builder', build_doc.builders)
  298. self.assertIn('html', build_doc.builders)
  299. # process command line options which should override config
  300. build_doc.finalize_options()
  301. self.assertIn('non-existing-builder', build_doc.builders)
  302. self.assertNotIn('html', build_doc.builders)
  303. def test_cmd_builder_override_multiple_builders(self):
  304. if self.has_opt:
  305. self.distr.command_options["pbr"] = {
  306. "autodoc_index_modules": ('setup.cfg', self.autodoc)
  307. }
  308. self.distr.command_options["build_sphinx"]["builder"] = (
  309. "command line", "builder1,builder2")
  310. build_doc = packaging.LocalBuildDoc(self.distr)
  311. build_doc.finalize_options()
  312. self.assertEqual(["builder1", "builder2"], build_doc.builders)
  313. class APIAutoDocTest(base.BaseTestCase):
  314. def setUp(self):
  315. super(APIAutoDocTest, self).setUp()
  316. # setup_command requires the Sphinx instance to have some
  317. # attributes that aren't set normally with the way we use the
  318. # class (because we replace the constructor). Add default
  319. # values directly to the class definition.
  320. import sphinx.application
  321. sphinx.application.Sphinx.messagelog = []
  322. sphinx.application.Sphinx.statuscode = 0
  323. self.useFixture(fixtures.MonkeyPatch(
  324. "sphinx.application.Sphinx.__init__", lambda *a, **kw: None))
  325. self.useFixture(fixtures.MonkeyPatch(
  326. "sphinx.application.Sphinx.build", lambda *a, **kw: None))
  327. self.useFixture(fixtures.MonkeyPatch(
  328. "sphinx.application.Sphinx.config", _SphinxConfig))
  329. self.useFixture(fixtures.MonkeyPatch(
  330. "sphinx.config.Config.init_values", lambda *a: None))
  331. self.useFixture(fixtures.MonkeyPatch(
  332. "sphinx.config.Config.__init__", lambda *a: None))
  333. from distutils import dist
  334. self.distr = dist.Distribution()
  335. self.distr.packages = ("fake_package",)
  336. self.distr.command_options["build_sphinx"] = {
  337. "source_dir": ["a", "."]}
  338. self.sphinx_options = self.distr.command_options["build_sphinx"]
  339. pkg_fixture = fixtures.PythonPackage(
  340. "fake_package", [("fake_module.py", b""),
  341. ("another_fake_module_for_testing.py", b""),
  342. ("fake_private_module.py", b"")])
  343. self.useFixture(pkg_fixture)
  344. self.useFixture(base.DiveDir(pkg_fixture.base))
  345. self.pbr_options = self.distr.command_options.setdefault('pbr', {})
  346. self.pbr_options["autodoc_index_modules"] = ('setup.cfg', 'True')
  347. def test_default_api_build_dir(self):
  348. build_doc = packaging.LocalBuildDoc(self.distr)
  349. build_doc.run()
  350. print('PBR OPTIONS:', self.pbr_options)
  351. print('DISTR OPTIONS:', self.distr.command_options)
  352. self.assertTrue(os.path.exists("api/autoindex.rst"))
  353. self.assertTrue(os.path.exists("api/fake_package.fake_module.rst"))
  354. self.assertTrue(
  355. os.path.exists(
  356. "api/fake_package.fake_private_module.rst"))
  357. self.assertTrue(
  358. os.path.exists(
  359. "api/fake_package.another_fake_module_for_testing.rst"))
  360. def test_different_api_build_dir(self):
  361. # Options have to come out of the settings dict as a tuple
  362. # showing the source and the value.
  363. self.pbr_options['api_doc_dir'] = (None, 'contributor/api')
  364. build_doc = packaging.LocalBuildDoc(self.distr)
  365. build_doc.run()
  366. print('PBR OPTIONS:', self.pbr_options)
  367. print('DISTR OPTIONS:', self.distr.command_options)
  368. self.assertTrue(os.path.exists("contributor/api/autoindex.rst"))
  369. self.assertTrue(
  370. os.path.exists("contributor/api/fake_package.fake_module.rst"))
  371. self.assertTrue(
  372. os.path.exists(
  373. "contributor/api/fake_package.fake_private_module.rst"))