1
0

test_pkg.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. # -*- coding: utf-8 -*-
  2. # Import Python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import os
  5. import pprint
  6. # Import Salt Testing libs
  7. from tests.support.case import ModuleCase
  8. from tests.support.mixins import SaltReturnAssertsMixin
  9. from tests.support.helpers import (
  10. destructiveTest,
  11. flaky,
  12. requires_network,
  13. requires_salt_modules,
  14. )
  15. from tests.support.unit import skipIf
  16. # Import Salt libs
  17. import salt.utils.pkg
  18. import salt.utils.platform
  19. @flaky
  20. class PkgModuleTest(ModuleCase, SaltReturnAssertsMixin):
  21. '''
  22. Validate the pkg module
  23. '''
  24. def setUp(self):
  25. if salt.utils.platform.is_windows():
  26. self.run_function('pkg.refresh_db')
  27. os_release = self.run_function('grains.get', ['osrelease'])
  28. if salt.utils.platform.is_darwin() and int(os_release.split('.')[1]) >= 13:
  29. self.pkg = 'wget'
  30. elif salt.utils.platform.is_windows():
  31. self.pkg = 'putty'
  32. else:
  33. self.pkg = 'htop'
  34. def test_list(self):
  35. '''
  36. verify that packages are installed
  37. '''
  38. ret = self.run_function('pkg.list_pkgs')
  39. self.assertNotEqual(len(ret.keys()), 0)
  40. @requires_salt_modules('pkg.version_cmp')
  41. def test_version_cmp(self):
  42. '''
  43. test package version comparison on supported platforms
  44. '''
  45. func = 'pkg.version_cmp'
  46. os_family = self.run_function('grains.item', ['os_family'])['os_family']
  47. if os_family == 'Debian':
  48. lt = ['0.2.4-0ubuntu1', '0.2.4.1-0ubuntu1']
  49. eq = ['0.2.4-0ubuntu1', '0.2.4-0ubuntu1']
  50. gt = ['0.2.4.1-0ubuntu1', '0.2.4-0ubuntu1']
  51. self.assertEqual(self.run_function(func, lt), -1)
  52. self.assertEqual(self.run_function(func, eq), 0)
  53. self.assertEqual(self.run_function(func, gt), 1)
  54. elif os_family == 'Suse':
  55. lt = ['2.3.0-1', '2.3.1-15.1']
  56. eq = ['2.3.1-15.1', '2.3.1-15.1']
  57. gt = ['2.3.2-15.1', '2.3.1-15.1']
  58. self.assertEqual(self.run_function(func, lt), -1)
  59. self.assertEqual(self.run_function(func, eq), 0)
  60. self.assertEqual(self.run_function(func, gt), 1)
  61. else:
  62. self.skipTest('{0} is unavailable on {1}'.format(func, os_family))
  63. @requires_salt_modules('pkg.mod_repo', 'pkg.del_repo')
  64. @requires_network()
  65. @destructiveTest
  66. def test_mod_del_repo(self):
  67. '''
  68. test modifying and deleting a software repository
  69. '''
  70. os_grain = self.run_function('grains.item', ['os'])['os']
  71. repo = None
  72. try:
  73. if os_grain == 'Ubuntu':
  74. repo = 'ppa:otto-kesselgulasch/gimp-edge'
  75. uri = 'http://ppa.launchpad.net/otto-kesselgulasch/gimp-edge/ubuntu'
  76. ret = self.run_function('pkg.mod_repo', [repo, 'comps=main'])
  77. self.assertNotEqual(ret, {})
  78. ret = self.run_function('pkg.get_repo', [repo])
  79. if not isinstance(ret, dict):
  80. self.fail(
  81. 'The \'pkg.get_repo\' command did not return the excepted dictionary. Output:\n{}'.format(ret)
  82. )
  83. self.assertEqual(
  84. ret['uri'],
  85. uri,
  86. msg='The URI did not match. Full return:\n{}'.format(
  87. pprint.pformat(ret)
  88. )
  89. )
  90. elif os_grain == 'CentOS':
  91. major_release = int(
  92. self.run_function(
  93. 'grains.item',
  94. ['osmajorrelease']
  95. )['osmajorrelease']
  96. )
  97. repo = 'saltstack'
  98. name = 'SaltStack repo for RHEL/CentOS {0}'.format(major_release)
  99. baseurl = 'http://repo.saltstack.com/yum/redhat/{0}/x86_64/latest/'.format(major_release)
  100. gpgkey = 'https://repo.saltstack.com/yum/rhel{0}/SALTSTACK-GPG-KEY.pub'.format(major_release)
  101. gpgcheck = 1
  102. enabled = 1
  103. ret = self.run_function(
  104. 'pkg.mod_repo',
  105. [repo],
  106. name=name,
  107. baseurl=baseurl,
  108. gpgkey=gpgkey,
  109. gpgcheck=gpgcheck,
  110. enabled=enabled,
  111. )
  112. # return data from pkg.mod_repo contains the file modified at
  113. # the top level, so use next(iter(ret)) to get that key
  114. self.assertNotEqual(ret, {})
  115. repo_info = ret[next(iter(ret))]
  116. self.assertIn(repo, repo_info)
  117. self.assertEqual(repo_info[repo]['baseurl'], baseurl)
  118. ret = self.run_function('pkg.get_repo', [repo])
  119. self.assertEqual(ret['baseurl'], baseurl)
  120. finally:
  121. if repo is not None:
  122. self.run_function('pkg.del_repo', [repo])
  123. @requires_salt_modules('pkg.owner')
  124. def test_owner(self):
  125. '''
  126. test finding the package owning a file
  127. '''
  128. func = 'pkg.owner'
  129. available = self.run_function('sys.doc', [func])
  130. if available:
  131. ret = self.run_function(func, ['/bin/ls'])
  132. self.assertNotEqual(len(ret), 0)
  133. else:
  134. os_grain = self.run_function('grains.item', ['os'])['os']
  135. self.skipTest('{0} is unavailable on {1}'.format(func, os_grain))
  136. @requires_network()
  137. @destructiveTest
  138. def test_install_remove(self):
  139. '''
  140. successfully install and uninstall a package
  141. '''
  142. version = self.run_function('pkg.version', [self.pkg])
  143. def test_install():
  144. install_ret = self.run_function('pkg.install', [self.pkg])
  145. self.assertIn(self.pkg, install_ret)
  146. def test_remove():
  147. remove_ret = self.run_function('pkg.remove', [self.pkg])
  148. self.assertIn(self.pkg, remove_ret)
  149. if version and isinstance(version, dict):
  150. version = version[self.pkg]
  151. if version:
  152. test_remove()
  153. test_install()
  154. else:
  155. test_install()
  156. test_remove()
  157. @skipIf(salt.utils.platform.is_windows(), "Skip on windows")
  158. @requires_salt_modules('pkg.hold', 'pkg.unhold')
  159. @requires_network()
  160. @destructiveTest
  161. def test_hold_unhold(self):
  162. '''
  163. test holding and unholding a package
  164. '''
  165. os_family = self.run_function('grains.item', ['os_family'])['os_family']
  166. available = self.run_function('sys.doc', ['pkg.hold'])
  167. version_lock = None
  168. lock_pkg = 'yum-plugin-versionlock'
  169. if available:
  170. self.run_function('pkg.install', [self.pkg])
  171. if os_family == 'RedHat':
  172. version_lock = self.run_function('pkg.version', [lock_pkg])
  173. if not version_lock:
  174. self.run_function('pkg.install', [lock_pkg])
  175. hold_ret = self.run_function('pkg.hold', [self.pkg])
  176. self.assertIn(self.pkg, hold_ret)
  177. self.assertTrue(hold_ret[self.pkg]['result'])
  178. unhold_ret = self.run_function('pkg.unhold', [self.pkg])
  179. self.assertIn(self.pkg, unhold_ret)
  180. self.assertTrue(unhold_ret[self.pkg]['result'])
  181. if os_family == 'RedHat':
  182. if not version_lock:
  183. self.run_function('pkg.remove', [lock_pkg])
  184. self.run_function('pkg.remove', [self.pkg])
  185. else:
  186. os_grain = self.run_function('grains.item', ['os'])['os']
  187. self.skipTest('{0} is unavailable on {1}'.format('pkg.hold', os_grain))
  188. @requires_network()
  189. @destructiveTest
  190. def test_refresh_db(self):
  191. '''
  192. test refreshing the package database
  193. '''
  194. func = 'pkg.refresh_db'
  195. os_family = self.run_function('grains.item', ['os_family'])['os_family']
  196. rtag = salt.utils.pkg.rtag(self.minion_opts)
  197. salt.utils.pkg.write_rtag(self.minion_opts)
  198. self.assertTrue(os.path.isfile(rtag))
  199. if os_family == 'RedHat':
  200. ret = self.run_function(func)
  201. self.assertIn(ret, (True, None))
  202. elif os_family == 'Suse':
  203. ret = self.run_function(func)
  204. if not isinstance(ret, dict):
  205. self.skipTest('Upstream repo did not return coherent results. Skipping test.')
  206. self.assertNotEqual(ret, {})
  207. elif os_family == 'Debian':
  208. ret = self.run_function(func)
  209. if not isinstance(ret, dict):
  210. self.skipTest('{0} encountered an error: {1}'.format(func, ret))
  211. self.assertNotEqual(ret, {})
  212. if not isinstance(ret, dict):
  213. self.skipTest('Upstream repo did not return coherent results. Skipping test.')
  214. for source, state in ret.items():
  215. self.assertIn(state, (True, False, None))
  216. else:
  217. os_grain = self.run_function('grains.item', ['os'])['os']
  218. self.skipTest('{0} is unavailable on {1}'.format(func, os_grain))
  219. self.assertFalse(os.path.isfile(rtag))
  220. @requires_salt_modules('pkg.info_installed')
  221. def test_pkg_info(self):
  222. '''
  223. Test returning useful information on Ubuntu systems.
  224. '''
  225. func = 'pkg.info_installed'
  226. os_family = self.run_function('grains.item', ['os_family'])['os_family']
  227. if os_family == 'Debian':
  228. ret = self.run_function(func, ['bash-completion', 'dpkg'])
  229. keys = ret.keys()
  230. self.assertIn('bash-completion', keys)
  231. self.assertIn('dpkg', keys)
  232. elif os_family == 'RedHat':
  233. ret = self.run_function(func, ['rpm', 'bash'])
  234. keys = ret.keys()
  235. self.assertIn('rpm', keys)
  236. self.assertIn('bash', keys)
  237. elif os_family == 'Suse':
  238. ret = self.run_function(func, ['less', 'zypper'])
  239. keys = ret.keys()
  240. self.assertIn('less', keys)
  241. self.assertIn('zypper', keys)
  242. @requires_network()
  243. @destructiveTest
  244. @skipIf(salt.utils.platform.is_windows(), 'pkg.upgrade not available on Windows')
  245. def test_pkg_upgrade_has_pending_upgrades(self):
  246. '''
  247. Test running a system upgrade when there are packages that need upgrading
  248. '''
  249. func = 'pkg.upgrade'
  250. os_family = self.run_function('grains.item', ['os_family'])['os_family']
  251. # First make sure that an up-to-date copy of the package db is available
  252. self.run_function('pkg.refresh_db')
  253. if os_family == 'Suse':
  254. # This test assumes that there are multiple possible versions of a
  255. # package available. That makes it brittle if you pick just one
  256. # target, as changes in the available packages will break the test.
  257. # Therefore, we'll choose from several packages to make sure we get
  258. # one that is suitable for this test.
  259. packages = ('hwinfo', 'avrdude', 'diffoscope', 'vim')
  260. available = self.run_function('pkg.list_repo_pkgs', packages)
  261. for package in packages:
  262. try:
  263. new, old = available[package][:2]
  264. except (KeyError, ValueError):
  265. # Package not available, or less than 2 versions
  266. # available. This is not a suitable target.
  267. continue
  268. else:
  269. target = package
  270. break
  271. else:
  272. # None of the packages have more than one version available, so
  273. # we need to find new package(s). pkg.list_repo_pkgs can be
  274. # used to get an overview of the available packages. We should
  275. # try to find packages with few dependencies and small download
  276. # sizes, to keep this test from taking longer than necessary.
  277. self.fail('No suitable package found for this test')
  278. # Make sure we have the 2nd-oldest available version installed
  279. ret = self.run_function('pkg.install', [target], version=old)
  280. if not isinstance(ret, dict):
  281. if ret.startswith('ERROR'):
  282. self.skipTest(
  283. 'Could not install older {0} to complete '
  284. 'test.'.format(target)
  285. )
  286. # Run a system upgrade, which should catch the fact that the
  287. # targeted package needs upgrading, and upgrade it.
  288. ret = self.run_function(func)
  289. # The changes dictionary should not be empty.
  290. if 'changes' in ret:
  291. self.assertIn(target, ret['changes'])
  292. else:
  293. self.assertIn(target, ret)
  294. else:
  295. ret = self.run_function('pkg.list_upgrades')
  296. if ret == '' or ret == {}:
  297. self.skipTest('No updates available for this machine. Skipping pkg.upgrade test.')
  298. else:
  299. args = []
  300. if os_family == 'Debian':
  301. args = ['dist_upgrade=True']
  302. ret = self.run_function(func, args)
  303. self.assertNotEqual(ret, {})
  304. @destructiveTest
  305. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  306. @skipIf(salt.utils.platform.is_darwin(), 'minion is mac')
  307. def test_pkg_latest_version(self):
  308. '''
  309. Check that pkg.latest_version returns the latest version of the uninstalled package.
  310. The package is not installed. Only the package version is checked.
  311. '''
  312. grains = self.run_function('grains.items')
  313. remove = False
  314. if salt.utils.platform.is_windows():
  315. cmd_info = self.run_function('pkg.version', [self.pkg])
  316. remove = False if cmd_info == '' else True
  317. else:
  318. cmd_info = self.run_function('pkg.info_installed', [self.pkg])
  319. if cmd_info != 'ERROR: package {0} is not installed'.format(self.pkg):
  320. remove = True
  321. # remove package if its installed
  322. if remove:
  323. self.run_function('pkg.remove', [self.pkg])
  324. cmd_pkg = []
  325. if grains['os_family'] == 'RedHat':
  326. cmd_pkg = self.run_function('cmd.run', ['yum list {0}'.format(self.pkg)])
  327. elif salt.utils.platform.is_windows():
  328. cmd_pkg = self.run_function('pkg.list_available', [self.pkg])
  329. elif grains['os_family'] == 'Debian':
  330. cmd_pkg = self.run_function('cmd.run', ['apt list {0}'.format(self.pkg)])
  331. elif grains['os_family'] == 'Arch':
  332. cmd_pkg = self.run_function('cmd.run', ['pacman -Si {0}'.format(self.pkg)])
  333. elif grains['os_family'] == 'Suse':
  334. cmd_pkg = self.run_function('cmd.run', ['zypper info {0}'.format(self.pkg)])
  335. pkg_latest = self.run_function('pkg.latest_version', [self.pkg])
  336. self.assertIn(pkg_latest, cmd_pkg)