20_test_rpm.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. # vim: set fileencoding=utf-8 :
  2. #
  3. # (C) 2012 Intel Corporation <markus.lehtonen@linux.intel.com>
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, please see
  16. # <http://www.gnu.org/licenses/>
  17. """Test the classes under L{gbp.rpm}"""
  18. import filecmp
  19. import os
  20. import shutil
  21. import tempfile
  22. from nose.tools import assert_raises, eq_, ok_ # pylint: disable=E0611
  23. import six
  24. from gbp.errors import GbpError
  25. from gbp.rpm import (SpecFile, SrcRpmFile, NoSpecError, guess_spec,
  26. guess_spec_repo, spec_from_repo)
  27. from gbp.git.repository import GitRepository
  28. # Disable "Method could be a function"
  29. # pylint: disable=R0201
  30. DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data',
  31. 'rpm')
  32. SRPM_DIR = os.path.join(DATA_DIR, 'srpms')
  33. SPEC_DIR = os.path.join(DATA_DIR, 'specs')
  34. class SpecFileTester(SpecFile):
  35. """Helper class for testing"""
  36. def protected(self, name):
  37. """Get a protected member"""
  38. return super(SpecFileTester, self).__getattribute__(name)
  39. class RpmTestBase(object):
  40. """Test base class"""
  41. def __init__(self):
  42. self.tmpdir = None
  43. def setup(self):
  44. """Test case setup"""
  45. self.tmpdir = tempfile.mkdtemp(prefix='gbp_%s_' % __name__, dir='.')
  46. def teardown(self):
  47. """Test case teardown"""
  48. shutil.rmtree(self.tmpdir)
  49. class TestSrcRpmFile(RpmTestBase):
  50. """Test L{gbp.rpm.SrcRpmFile}"""
  51. def test_srpm(self):
  52. """Test parsing of a source rpm"""
  53. srpm = SrcRpmFile(os.path.join(SRPM_DIR, 'gbp-test-1.0-1.src.rpm'))
  54. eq_(srpm.version, {'release': '1', 'upstreamversion': '1.0'})
  55. eq_(srpm.name, 'gbp-test')
  56. eq_(srpm.upstreamversion, '1.0')
  57. eq_(srpm.packager, None)
  58. def test_srpm_2(self):
  59. """Test parsing of another source rpm"""
  60. srpm = SrcRpmFile(os.path.join(SRPM_DIR, 'gbp-test2-3.0-0.src.rpm'))
  61. eq_(srpm.version, {'release': '0', 'upstreamversion': '3.0',
  62. 'epoch': '2'})
  63. eq_(srpm.packager, 'Markus Lehtonen <markus.lehtonen@linux.intel.com>')
  64. def test_unpack_srpm(self):
  65. """Test unpacking of a source rpm"""
  66. srpm = SrcRpmFile(os.path.join(SRPM_DIR, 'gbp-test-1.0-1.src.rpm'))
  67. srpm.unpack(self.tmpdir)
  68. for fn in ['gbp-test-1.0.tar.bz2', 'foo.txt', 'bar.tar.gz', 'my.patch',
  69. 'my2.patch', 'my3.patch']:
  70. ok_(os.path.exists(os.path.join(self.tmpdir, fn)),
  71. "%s not found" % fn)
  72. class TestSpecFile(RpmTestBase):
  73. """Test L{gbp.rpm.SpecFile}"""
  74. def test_spec(self):
  75. """Test parsing of a valid spec file"""
  76. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test.spec')
  77. spec = SpecFileTester(spec_filepath)
  78. # Test basic properties
  79. eq_(spec.specfile, os.path.basename(spec_filepath))
  80. eq_(spec.specdir, os.path.dirname(spec_filepath))
  81. eq_(spec.specpath, spec_filepath)
  82. eq_(spec.name, 'gbp-test')
  83. eq_(spec.packager, None)
  84. eq_(spec.upstreamversion, '1.0')
  85. eq_(spec.release, '1')
  86. eq_(spec.epoch, None)
  87. eq_(spec.version, {'release': '1', 'upstreamversion': '1.0'})
  88. orig = spec.orig_src
  89. eq_(orig['filename'], 'gbp-test-1.0.tar.bz2')
  90. eq_(orig['uri'], 'gbp-test-1.0.tar.bz2')
  91. eq_(orig['filename_base'], 'gbp-test-1.0')
  92. eq_(orig['archive_fmt'], 'tar')
  93. eq_(orig['compression'], 'bzip2')
  94. eq_(orig['prefix'], 'gbp-test/')
  95. def test_spec_2(self):
  96. """Test parsing of another valid spec file"""
  97. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test2.spec')
  98. spec = SpecFile(spec_filepath)
  99. # Test basic properties
  100. eq_(spec.name, 'gbp-test2')
  101. eq_(spec.packager, 'Markus Lehtonen <markus.lehtonen@linux.intel.com>')
  102. eq_(spec.epoch, '2')
  103. eq_(spec.version, {'release': '0', 'upstreamversion': '3.0',
  104. 'epoch': '2'})
  105. orig = spec.orig_src
  106. eq_(orig['filename'], 'gbp-test2-3.0.tar.gz')
  107. eq_(orig['uri'], 'ftp://ftp.host.com/gbp-test2-3.0.tar.gz')
  108. eq_(orig['archive_fmt'], 'tar')
  109. eq_(orig['compression'], 'gzip')
  110. eq_(orig['prefix'], '')
  111. def test_spec_3(self):
  112. """Test parsing of yet another valid spec file"""
  113. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-native.spec')
  114. spec = SpecFile(spec_filepath)
  115. # Test basic properties
  116. eq_(spec.name, 'gbp-test-native')
  117. orig = spec.orig_src
  118. eq_(orig['filename'], 'gbp-test-native-1.0.zip')
  119. eq_(orig['archive_fmt'], 'zip')
  120. eq_(orig['compression'], None)
  121. eq_(orig['prefix'], 'gbp-test-native-1.0/')
  122. def test_spec_4(self):
  123. """Test parsing of spec without orig tarball"""
  124. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-native2.spec')
  125. spec = SpecFile(spec_filepath)
  126. # Test basic properties
  127. eq_(spec.name, 'gbp-test-native2')
  128. eq_(spec.orig_src, None)
  129. def test_parse_raw(self):
  130. """Test parsing of a valid spec file"""
  131. with assert_raises(NoSpecError):
  132. SpecFile(None, None)
  133. with assert_raises(NoSpecError):
  134. SpecFile('filename', 'filedata')
  135. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test.spec')
  136. with open(spec_filepath, 'r') as spec_fd:
  137. spec_data = spec_fd.read()
  138. spec = SpecFile(filedata=spec_data)
  139. # Test basic properties
  140. eq_(spec.specfile, None)
  141. eq_(spec.specdir, None)
  142. eq_(spec.name, 'gbp-test')
  143. def test_update_spec(self):
  144. """Test spec autoupdate functionality"""
  145. # Create temporary spec file
  146. tmp_spec = os.path.join(self.tmpdir, 'gbp-test.spec')
  147. shutil.copy2(os.path.join(SPEC_DIR, 'gbp-test.spec'), tmp_spec)
  148. reference_spec = os.path.join(SPEC_DIR, 'gbp-test-reference.spec')
  149. spec = SpecFile(tmp_spec)
  150. spec.update_patches(['new.patch'], {})
  151. spec.write_spec_file()
  152. eq_(filecmp.cmp(tmp_spec, reference_spec), True)
  153. # Test adding the VCS tag and adding changelog
  154. reference_spec = os.path.join(SPEC_DIR, 'gbp-test-reference2.spec')
  155. spec.set_tag('VCS', None, 'myvcstag')
  156. spec.set_changelog("* Wed Feb 05 2014 Name <email> 1\n- New entry\n")
  157. spec.write_spec_file()
  158. eq_(filecmp.cmp(tmp_spec, reference_spec), True)
  159. def test_update_spec2(self):
  160. """Another test for spec autoupdate functionality"""
  161. tmp_spec = os.path.join(self.tmpdir, 'gbp-test2.spec')
  162. shutil.copy2(os.path.join(SPEC_DIR, 'gbp-test2.spec'), tmp_spec)
  163. reference_spec = os.path.join(SPEC_DIR, 'gbp-test2-reference2.spec')
  164. spec = SpecFile(tmp_spec)
  165. spec.update_patches(['1.patch', '2.patch'],
  166. {'1.patch': {'if': 'true'},
  167. '2.patch': {'ifarch': '%ix86'}})
  168. spec.set_tag('VCS', None, 'myvcstag')
  169. spec.write_spec_file()
  170. eq_(filecmp.cmp(tmp_spec, reference_spec), True)
  171. # Test updating patches again, removing the VCS tag and re-writing
  172. # changelog
  173. reference_spec = os.path.join(SPEC_DIR, 'gbp-test2-reference.spec')
  174. spec.update_patches(['new.patch'], {'new.patch': {'if': '1'}})
  175. spec.set_tag('VCS', None, '')
  176. spec.set_changelog("* Wed Feb 05 2014 Name <email> 2\n- New entry\n\n")
  177. spec.write_spec_file()
  178. eq_(filecmp.cmp(tmp_spec, reference_spec), True)
  179. def test_modifying(self):
  180. """Test updating/deleting of tags and macros"""
  181. tmp_spec = os.path.join(self.tmpdir, 'gbp-test.spec')
  182. shutil.copy2(os.path.join(SPEC_DIR, 'gbp-test-updates.spec'), tmp_spec)
  183. reference_spec = os.path.join(SPEC_DIR,
  184. 'gbp-test-updates-reference.spec')
  185. spec = SpecFileTester(tmp_spec)
  186. # Mangle tags
  187. prev = spec.protected('_delete_tag')('Vendor', None)
  188. spec.protected('_set_tag')('License', None, 'new license', prev)
  189. spec.protected('_delete_tag')('source', 0)
  190. eq_(spec.sources(), {})
  191. spec.protected('_delete_tag')('patch', 0)
  192. spec.protected('_delete_tag')('patch', -1)
  193. eq_(spec.protected('_patches')(), {})
  194. prev = spec.protected('_delete_tag')('invalidtag', None)
  195. with assert_raises(GbpError):
  196. # Check that setting empty value fails
  197. spec.protected('_set_tag')('Version', None, '', prev)
  198. with assert_raises(GbpError):
  199. # Check that setting invalid tag with public method fails
  200. spec.set_tag('invalidtag', None, 'value')
  201. # Mangle macros
  202. prev = spec.protected('_delete_special_macro')('patch', -1)
  203. spec.protected('_delete_special_macro')('patch', 123)
  204. spec.protected('_set_special_macro')('patch', 0, 'my new args', prev)
  205. with assert_raises(GbpError):
  206. spec.protected('_delete_special_macro')('invalidmacro', 0)
  207. with assert_raises(GbpError):
  208. spec.protected('_set_special_macro')('invalidmacro', 0, 'args',
  209. prev)
  210. # Check resulting spec file
  211. spec.write_spec_file()
  212. eq_(filecmp.cmp(tmp_spec, reference_spec), True)
  213. def test_modifying_err(self):
  214. """Test error conditions of modification methods"""
  215. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test2.spec')
  216. spec = SpecFileTester(spec_filepath)
  217. # Unknown/invalid section name
  218. with assert_raises(GbpError):
  219. spec.protected('_set_section')('patch', 'new content\n')
  220. # Multiple sections with the same name
  221. with assert_raises(GbpError):
  222. spec.protected('_set_section')('files', '%{_sysconfdir}/foo\n')
  223. def test_changelog(self):
  224. """Test changelog methods"""
  225. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test2.spec')
  226. spec = SpecFile(spec_filepath)
  227. # Read changelog
  228. eq_(spec.get_changelog(),
  229. "* Tue Feb 04 2014 Name <email> 1\n- My change\n\n\n")
  230. # Set changelog and check again
  231. new_text = "* Wed Feb 05 2014 Name <email> 2\n- New entry\n\n\n"
  232. spec.set_changelog(new_text)
  233. eq_(spec.get_changelog(), new_text)
  234. def test_quirks(self):
  235. """Test spec that is broken/has anomalities"""
  236. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-quirks.spec')
  237. spec = SpecFile(spec_filepath)
  238. # Check that we quess orig source and prefix correctly
  239. eq_(spec.orig_src['prefix'], 'foobar/')
  240. def test_tags(self):
  241. """Test parsing of all the different tags of spec file"""
  242. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-tags.spec')
  243. spec = SpecFileTester(spec_filepath)
  244. # Check all the tags
  245. for name, val in six.iteritems(spec.protected('_tags')):
  246. rval = None
  247. if name in ('version', 'release', 'epoch'):
  248. rval = '0'
  249. elif name in ('autoreq', 'autoprov', 'autoreqprov'):
  250. rval = 'No'
  251. elif name not in spec.protected('_listtags'):
  252. rval = 'my_%s' % name
  253. if rval:
  254. eq_(val['value'], rval, ("'%s:' is '%s', expecting '%s'" %
  255. (name, val['value'], rval)))
  256. eq_(spec.ignorepatches, [])
  257. # Check patch numbers and patch filenames
  258. patches = {}
  259. for patch in spec.protected('_tags')['patch']['lines']:
  260. patches[patch['num']] = patch['linevalue']
  261. eq_(patches, {0: 'my_patch0', -1: 'my_patch'})
  262. def test_patch_series(self):
  263. """Test the getting the patches as a patchseries"""
  264. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-native.spec')
  265. spec = SpecFileTester(spec_filepath)
  266. eq_(len(spec.patchseries()), 0)
  267. spec.update_patches(['1.patch', '2.patch', '3.patch'], {})
  268. eq_(len(spec.patchseries()), 3)
  269. spec.protected('_gbp_tags')['ignore-patches'].append({'args': "0"})
  270. spec.update_patches(['4.patch'], {})
  271. eq_(len(spec.patchseries()), 1)
  272. eq_(len(spec.patchseries(ignored=True)), 2)
  273. spec.protected('_delete_special_macro')('patch', 0)
  274. eq_(len(spec.patchseries(ignored=True)), 1)
  275. series = spec.patchseries(unapplied=True, ignored=True)
  276. eq_(len(series), 2)
  277. eq_(os.path.basename(series[-1].path), '1.patch')
  278. def test_patch_series_quirks(self):
  279. """Patches are applied in order different from the patch numbering"""
  280. spec_filepath = os.path.join(SPEC_DIR, 'gbp-test-quirks.spec')
  281. spec = SpecFileTester(spec_filepath)
  282. # Check series is returned in the order the patches are applied
  283. files = [os.path.basename(patch.path) for patch in spec.patchseries()]
  284. eq_(files, ['05.patch', '01.patch'])
  285. # Also ignored patches are returned in the correct order
  286. files = [os.path.basename(patch.path) for patch in
  287. spec.patchseries(ignored=True)]
  288. eq_(files, ['05.patch', '02.patch', '01.patch'])
  289. # Unapplied patches are added to the end of the series
  290. files = [os.path.basename(patch.path) for patch in
  291. spec.patchseries(unapplied=True)]
  292. eq_(files, ['05.patch', '01.patch', '03.patch'])
  293. # Return all patches (for which tag is found)
  294. files = [os.path.basename(patch.path) for patch in
  295. spec.patchseries(unapplied=True, ignored=True)]
  296. eq_(files, ['05.patch', '02.patch', '01.patch', '03.patch', '04.patch'])
  297. class TestUtilityFunctions(RpmTestBase):
  298. """Test utility functions of L{gbp.rpm}"""
  299. def test_guess_spec(self):
  300. """Test guess_spec() function"""
  301. # Spec not found
  302. with assert_raises(NoSpecError):
  303. guess_spec(DATA_DIR, recursive=False)
  304. # Multiple spec files
  305. with assert_raises(NoSpecError):
  306. guess_spec(DATA_DIR, recursive=True)
  307. with assert_raises(NoSpecError):
  308. guess_spec(SPEC_DIR, recursive=False)
  309. # Spec found
  310. spec = guess_spec(SPEC_DIR, recursive=False,
  311. preferred_name='gbp-test2.spec')
  312. eq_(spec.specfile, 'gbp-test2.spec')
  313. eq_(spec.specdir, SPEC_DIR)
  314. def test_guess_spec_repo(self):
  315. """Test guess_spec_repo() and spec_from_repo() functions"""
  316. # Create dummy repository with some commits
  317. repo = GitRepository.create(self.tmpdir)
  318. with open(os.path.join(repo.path, 'foo.txt'), 'w') as fobj:
  319. fobj.write('bar\n')
  320. repo.add_files('foo.txt')
  321. repo.commit_all('Add dummy file')
  322. os.mkdir(os.path.join(repo.path, 'packaging'))
  323. shutil.copy(os.path.join(SPEC_DIR, 'gbp-test.spec'),
  324. os.path.join(repo.path, 'packaging'))
  325. repo.add_files('packaging/gbp-test.spec')
  326. repo.commit_all('Add spec file')
  327. # Spec not found
  328. with assert_raises(NoSpecError):
  329. guess_spec_repo(repo, 'HEAD~1', recursive=True)
  330. with assert_raises(NoSpecError):
  331. guess_spec_repo(repo, 'HEAD', recursive=False)
  332. # Spec found
  333. spec = guess_spec_repo(repo, 'HEAD', 'packaging', recursive=False)
  334. spec = guess_spec_repo(repo, 'HEAD', recursive=True)
  335. eq_(spec.specfile, 'gbp-test.spec')
  336. eq_(spec.specdir, 'packaging')
  337. eq_(spec.specpath, 'packaging/gbp-test.spec')
  338. # Test spec_from_repo()
  339. with assert_raises(NoSpecError):
  340. spec_from_repo(repo, 'HEAD~1', 'packaging/gbp-test.spec')
  341. spec = spec_from_repo(repo, 'HEAD', 'packaging/gbp-test.spec')
  342. eq_(spec.specfile, 'gbp-test.spec')
  343. # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: