test_spm.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # coding: utf-8
  2. # Import Python libs
  3. from __future__ import absolute_import
  4. import os
  5. import shutil
  6. import tempfile
  7. import pytest
  8. # Import Salt Testing libs
  9. from tests.support.unit import TestCase
  10. from tests.support.mock import patch, MagicMock
  11. from tests.support.mixins import AdaptedConfigurationTestCaseMixin
  12. import salt.config
  13. import salt.utils.files
  14. import salt.spm
  15. _F1 = {
  16. 'definition': {
  17. 'name': 'formula1',
  18. 'version': '1.2',
  19. 'release': '2',
  20. 'summary': 'test',
  21. 'description': 'testing, nothing to see here',
  22. }
  23. }
  24. _F1['contents'] = (
  25. ('FORMULA', ('name: {name}\n'
  26. 'version: {version}\n'
  27. 'release: {release}\n'
  28. 'summary: {summary}\n'
  29. 'description: {description}').format(**_F1['definition'])),
  30. ('modules/mod1.py', '# mod1.py'),
  31. ('modules/mod2.py', '# mod2.py'),
  32. ('states/state1.sls', '# state1.sls'),
  33. ('states/state2.sls', '# state2.sls'),
  34. )
  35. @pytest.mark.destructive_test
  36. class SPMTestUserInterface(salt.spm.SPMUserInterface):
  37. '''
  38. Unit test user interface to SPMClient
  39. '''
  40. def __init__(self):
  41. self._status = []
  42. self._confirm = []
  43. self._error = []
  44. def status(self, msg):
  45. self._status.append(msg)
  46. def confirm(self, action):
  47. self._confirm.append(action)
  48. def error(self, msg):
  49. self._error.append(msg)
  50. class SPMTest(TestCase, AdaptedConfigurationTestCaseMixin):
  51. def setUp(self):
  52. self._tmp_spm = tempfile.mkdtemp()
  53. self.addCleanup(shutil.rmtree, self._tmp_spm, ignore_errors=True)
  54. minion_config = self.get_temp_config('minion', **{
  55. 'spm_logfile': os.path.join(self._tmp_spm, 'log'),
  56. 'spm_repos_config': os.path.join(self._tmp_spm, 'etc', 'spm.repos'),
  57. 'spm_cache_dir': os.path.join(self._tmp_spm, 'cache'),
  58. 'spm_build_dir': os.path.join(self._tmp_spm, 'build'),
  59. 'spm_build_exclude': ['.git'],
  60. 'spm_db_provider': 'sqlite3',
  61. 'spm_files_provider': 'local',
  62. 'spm_db': os.path.join(self._tmp_spm, 'packages.db'),
  63. 'extension_modules': os.path.join(self._tmp_spm, 'modules'),
  64. 'file_roots': {'base': [self._tmp_spm, ]},
  65. 'formula_path': os.path.join(self._tmp_spm, 'spm'),
  66. 'pillar_path': os.path.join(self._tmp_spm, 'pillar'),
  67. 'reactor_path': os.path.join(self._tmp_spm, 'reactor'),
  68. 'assume_yes': True,
  69. 'force': False,
  70. 'verbose': False,
  71. 'cache': 'localfs',
  72. 'cachedir': os.path.join(self._tmp_spm, 'cache'),
  73. 'spm_repo_dups': 'ignore',
  74. 'spm_share_dir': os.path.join(self._tmp_spm, 'share'),
  75. })
  76. self.ui = SPMTestUserInterface()
  77. self.client = salt.spm.SPMClient(self.ui, minion_config)
  78. self.minion_config = minion_config
  79. for attr in ('client', 'ui', '_tmp_spm', 'minion_config'):
  80. self.addCleanup(delattr, self, attr)
  81. def _create_formula_files(self, formula):
  82. fdir = os.path.join(self._tmp_spm, formula['definition']['name'])
  83. shutil.rmtree(fdir, ignore_errors=True)
  84. os.mkdir(fdir)
  85. for path, contents in formula['contents']:
  86. path = os.path.join(fdir, path)
  87. dirname, _ = os.path.split(path)
  88. if not os.path.exists(dirname):
  89. os.makedirs(dirname)
  90. with salt.utils.files.fopen(path, 'w') as f:
  91. f.write(contents)
  92. return fdir
  93. def test_build_install(self):
  94. # Build package
  95. fdir = self._create_formula_files(_F1)
  96. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  97. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  98. self.client.run(['build', fdir])
  99. pkgpath = self.ui._status[-1].split()[-1]
  100. assert os.path.exists(pkgpath)
  101. # Install package
  102. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  103. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  104. self.client.run(['local', 'install', pkgpath])
  105. # Check filesystem
  106. for path, contents in _F1['contents']:
  107. path = os.path.join(self.minion_config['file_roots']['base'][0], _F1['definition']['name'], path)
  108. assert os.path.exists(path)
  109. with salt.utils.files.fopen(path, 'r') as rfh:
  110. assert rfh.read() == contents
  111. # Check database
  112. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  113. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  114. self.client.run(['info', _F1['definition']['name']])
  115. lines = self.ui._status[-1].split('\n')
  116. for key, line in (
  117. ('name', 'Name: {0}'),
  118. ('version', 'Version: {0}'),
  119. ('release', 'Release: {0}'),
  120. ('summary', 'Summary: {0}')):
  121. assert line.format(_F1['definition'][key]) in lines
  122. # Reinstall with force=False, should fail
  123. self.ui._error = []
  124. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  125. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  126. self.client.run(['local', 'install', pkgpath])
  127. assert len(self.ui._error) > 0
  128. # Reinstall with force=True, should succeed
  129. with patch.dict(self.minion_config, {'force': True}):
  130. self.ui._error = []
  131. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  132. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  133. self.client.run(['local', 'install', pkgpath])
  134. assert len(self.ui._error) == 0
  135. def test_failure_paths(self):
  136. fail_args = (
  137. ['bogus', 'command'],
  138. ['create_repo'],
  139. ['build'],
  140. ['build', '/nonexistent/path'],
  141. ['info'],
  142. ['info', 'not_installed'],
  143. ['files'],
  144. ['files', 'not_installed'],
  145. ['install'],
  146. ['install', 'nonexistent.spm'],
  147. ['remove'],
  148. ['remove', 'not_installed'],
  149. ['local', 'bogus', 'command'],
  150. ['local', 'info'],
  151. ['local', 'info', '/nonexistent/path/junk.spm'],
  152. ['local', 'files'],
  153. ['local', 'files', '/nonexistent/path/junk.spm'],
  154. ['local', 'install'],
  155. ['local', 'install', '/nonexistent/path/junk.spm'],
  156. ['local', 'list'],
  157. ['local', 'list', '/nonexistent/path/junk.spm'],
  158. # XXX install failure due to missing deps
  159. # XXX install failure due to missing field
  160. )
  161. for args in fail_args:
  162. self.ui._error = []
  163. with patch('salt.client.Caller', MagicMock(return_value=self.minion_opts)):
  164. with patch('salt.client.get_local_client', MagicMock(return_value=self.minion_opts['conf_file'])):
  165. self.client.run(args)
  166. assert len(self.ui._error) > 0