test_user.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. # -*- coding: utf-8 -*-
  2. '''
  3. tests for user state
  4. user absent
  5. user present
  6. user present with custom homedir
  7. '''
  8. # Import Python libs
  9. from __future__ import absolute_import, print_function, unicode_literals
  10. import os
  11. import sys
  12. from random import randint
  13. import pytest
  14. # Import Salt Testing libs
  15. from tests.support.case import ModuleCase
  16. from tests.support.unit import skipIf
  17. from tests.support.helpers import requires_system_grains
  18. from tests.support.mixins import SaltReturnAssertsMixin
  19. # Import Salt libs
  20. import salt.utils.platform
  21. try:
  22. import grp
  23. except ImportError:
  24. grp = None
  25. if salt.utils.platform.is_darwin():
  26. USER = 'macuser'
  27. GROUP = 'macuser'
  28. GID = randint(400, 500)
  29. NOGROUPGID = randint(400, 500)
  30. elif salt.utils.platform.is_windows():
  31. USER = 'winuser'
  32. GROUP = 'winuser'
  33. GID = randint(400, 500)
  34. NOGROUPGID = randint(400, 500)
  35. else:
  36. USER = 'nobody'
  37. GROUP = 'nobody'
  38. GID = 'nobody'
  39. NOGROUPGID = 'nogroup'
  40. @pytest.mark.destructive_test
  41. @pytest.mark.skip_if_not_root
  42. @pytest.mark.windows_whitelisted
  43. class UserTest(ModuleCase, SaltReturnAssertsMixin):
  44. '''
  45. test for user absent
  46. '''
  47. user_name = 'salt-test'
  48. user_home = '/var/lib/{0}'.format(user_name) if not salt.utils.platform.is_windows() else os.path.join('tmp', user_name)
  49. def test_user_absent(self):
  50. ret = self.run_state('user.absent', name='unpossible')
  51. self.assertSaltTrueReturn(ret)
  52. def test_user_if_present(self):
  53. ret = self.run_state('user.present', name=USER)
  54. self.assertSaltTrueReturn(ret)
  55. def test_user_if_present_with_gid(self):
  56. if self.run_function('group.info', [USER]):
  57. ret = self.run_state('user.present', name=USER, gid=GID)
  58. elif self.run_function('group.info', ['nogroup']):
  59. ret = self.run_state('user.present', name=USER, gid=NOGROUPGID)
  60. else:
  61. self.skipTest(
  62. 'Neither \'nobody\' nor \'nogroup\' are valid groups'
  63. )
  64. self.assertSaltTrueReturn(ret)
  65. def test_user_not_present(self):
  66. '''
  67. This is a DESTRUCTIVE TEST it creates a new user on the minion.
  68. And then destroys that user.
  69. Assume that it will break any system you run it on.
  70. '''
  71. ret = self.run_state('user.present', name=self.user_name)
  72. self.assertSaltTrueReturn(ret)
  73. def test_user_present_when_home_dir_does_not_18843(self):
  74. '''
  75. This is a DESTRUCTIVE TEST it creates a new user on the minion.
  76. And then destroys that user.
  77. Assume that it will break any system you run it on.
  78. '''
  79. if salt.utils.platform.is_darwin():
  80. HOMEDIR = '/Users/home_of_' + self.user_name
  81. else:
  82. HOMEDIR = '/home/home_of_' + self.user_name
  83. ret = self.run_state('user.present', name=self.user_name,
  84. home=HOMEDIR)
  85. self.assertSaltTrueReturn(ret)
  86. self.run_function('file.absent', name=HOMEDIR)
  87. ret = self.run_state('user.present', name=self.user_name,
  88. home=HOMEDIR)
  89. self.assertSaltTrueReturn(ret)
  90. @requires_system_grains
  91. def test_user_present_nondefault(self, grains=None):
  92. '''
  93. This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
  94. '''
  95. ret = self.run_state('user.present', name=self.user_name,
  96. home=self.user_home)
  97. self.assertSaltTrueReturn(ret)
  98. ret = self.run_function('user.info', [self.user_name])
  99. self.assertReturnNonEmptySaltType(ret)
  100. if salt.utils.platform.is_windows():
  101. group_name = self.run_function('user.list_groups', [self.user_name])
  102. else:
  103. group_name = grp.getgrgid(ret['gid']).gr_name
  104. if not salt.utils.platform.is_darwin() and not salt.utils.platform.is_windows():
  105. self.assertTrue(os.path.isdir(self.user_home))
  106. if grains['os_family'] in ('Suse',):
  107. self.assertEqual(group_name, 'users')
  108. elif grains['os_family'] == 'MacOS':
  109. self.assertEqual(group_name, 'staff')
  110. elif salt.utils.platform.is_windows():
  111. self.assertEqual([], group_name)
  112. else:
  113. self.assertEqual(group_name, self.user_name)
  114. @skipIf(salt.utils.platform.is_windows(), 'windows minion does not support gid_from_name')
  115. @requires_system_grains
  116. def test_user_present_gid_from_name_default(self, grains=None):
  117. '''
  118. This is a DESTRUCTIVE TEST. It creates a new user on the on the minion.
  119. This is an integration test. Not all systems will automatically create
  120. a group of the same name as the user, but I don't have access to any.
  121. If you run the test and it fails, please fix the code it's testing to
  122. work on your operating system.
  123. '''
  124. # MacOS users' primary group defaults to staff (20), not the name of
  125. # user
  126. gid_from_name = False if grains['os_family'] == 'MacOS' else True
  127. ret_user_present = self.run_state('user.present', name=self.user_name,
  128. gid_from_name=gid_from_name, home=self.user_home)
  129. if gid_from_name:
  130. self.assertSaltFalseReturn(ret_user_present)
  131. ret_user_present = ret_user_present[next(iter(ret_user_present))]
  132. self.assertTrue('is not present' in ret_user_present['comment'])
  133. else:
  134. self.assertSaltTrueReturn(ret_user_present)
  135. ret_user_info = self.run_function('user.info', [self.user_name])
  136. self.assertReturnNonEmptySaltType(ret_user_info)
  137. group_name = grp.getgrgid(ret_user_info['gid']).gr_name
  138. if not salt.utils.platform.is_darwin():
  139. self.assertTrue(os.path.isdir(self.user_home))
  140. if grains['os_family'] in ('Suse',):
  141. self.assertEqual(group_name, 'users')
  142. elif grains['os_family'] == 'MacOS':
  143. self.assertEqual(group_name, 'staff')
  144. else:
  145. self.assertEqual(group_name, self.user_name)
  146. @skipIf(salt.utils.platform.is_windows(), 'windows minion does not support gid_from_name')
  147. def test_user_present_gid_from_name(self):
  148. '''
  149. This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
  150. This is a unit test, NOT an integration test. We create a group of the
  151. same name as the user beforehand, so it should all run smoothly.
  152. '''
  153. ret = self.run_state('group.present', name=self.user_name)
  154. self.assertSaltTrueReturn(ret)
  155. ret = self.run_state('user.present', name=self.user_name,
  156. gid_from_name=True, home=self.user_home)
  157. self.assertSaltTrueReturn(ret)
  158. ret = self.run_function('user.info', [self.user_name])
  159. self.assertReturnNonEmptySaltType(ret)
  160. group_name = grp.getgrgid(ret['gid']).gr_name
  161. if not salt.utils.platform.is_darwin():
  162. self.assertTrue(os.path.isdir(self.user_home))
  163. self.assertEqual(group_name, self.user_name)
  164. ret = self.run_state('user.absent', name=self.user_name)
  165. self.assertSaltTrueReturn(ret)
  166. ret = self.run_state('group.absent', name=self.user_name)
  167. self.assertSaltTrueReturn(ret)
  168. @skipIf(sys.getfilesystemencoding().startswith('ANSI'), 'A system encoding which supports Unicode characters must be set. Current setting is: {0}. Try setting $LANG=\'en_US.UTF-8\''.format(sys.getfilesystemencoding()))
  169. def test_user_present_unicode(self):
  170. '''
  171. This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
  172. It ensures that unicode GECOS data will be properly handled, without
  173. any encoding-related failures.
  174. '''
  175. ret = self.run_state(
  176. 'user.present',
  177. name=self.user_name,
  178. fullname='Sålt Test',
  179. roomnumber='①②③',
  180. workphone='١٢٣٤',
  181. homephone='६७८'
  182. )
  183. self.assertSaltTrueReturn(ret)
  184. # Ensure updating a user also works
  185. ret = self.run_state(
  186. 'user.present',
  187. name=self.user_name,
  188. fullname='Sølt Test',
  189. roomnumber='①③②',
  190. workphone='٣٤١٢',
  191. homephone='६८७'
  192. )
  193. self.assertSaltTrueReturn(ret)
  194. @skipIf(salt.utils.platform.is_windows(), 'windows minon does not support roomnumber or phone')
  195. def test_user_present_gecos(self):
  196. '''
  197. This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
  198. It ensures that numeric GECOS data will be properly coerced to strings,
  199. otherwise the state will fail because the GECOS fields are written as
  200. strings (and show up in the user.info output as such). Thus the
  201. comparison will fail, since '12345' != 12345.
  202. '''
  203. ret = self.run_state(
  204. 'user.present',
  205. name=self.user_name,
  206. fullname=12345,
  207. roomnumber=123,
  208. workphone=1234567890,
  209. homephone=1234567890
  210. )
  211. self.assertSaltTrueReturn(ret)
  212. @skipIf(salt.utils.platform.is_windows(), 'windows minon does not support roomnumber or phone')
  213. def test_user_present_gecos_none_fields(self):
  214. '''
  215. This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
  216. It ensures that if no GECOS data is supplied, the fields will be coerced
  217. into empty strings as opposed to the string "None".
  218. '''
  219. ret = self.run_state(
  220. 'user.present',
  221. name=self.user_name,
  222. fullname=None,
  223. roomnumber=None,
  224. workphone=None,
  225. homephone=None
  226. )
  227. self.assertSaltTrueReturn(ret)
  228. ret = self.run_function('user.info', [self.user_name])
  229. self.assertReturnNonEmptySaltType(ret)
  230. self.assertEqual('', ret['fullname'])
  231. # MacOS does not supply the following GECOS fields
  232. if not salt.utils.platform.is_darwin():
  233. self.assertEqual('', ret['roomnumber'])
  234. self.assertEqual('', ret['workphone'])
  235. self.assertEqual('', ret['homephone'])
  236. def tearDown(self):
  237. if salt.utils.platform.is_darwin():
  238. check_user = self.run_function('user.list_users')
  239. if USER in check_user:
  240. del_user = self.run_function('user.delete', [USER], remove=True)
  241. self.assertSaltTrueReturn(
  242. self.run_state('user.absent', name=self.user_name)
  243. )
  244. @pytest.mark.destructive_test
  245. @pytest.mark.skip_if_not_root
  246. @skipIf(not salt.utils.platform.is_windows(), 'Windows only tests')
  247. @pytest.mark.windows_whitelisted
  248. class WinUserTest(ModuleCase, SaltReturnAssertsMixin):
  249. '''
  250. test for user absent
  251. '''
  252. def tearDown(self):
  253. self.assertSaltTrueReturn(
  254. self.run_state('user.absent', name=USER)
  255. )
  256. def test_user_present_existing(self):
  257. ret = self.run_state('user.present',
  258. name=USER,
  259. win_homedrive='U:',
  260. win_profile='C:\\User\\{0}'.format(USER),
  261. win_logonscript='C:\\logon.vbs',
  262. win_description='Test User Account')
  263. self.assertSaltTrueReturn(ret)
  264. ret = self.run_state('user.present',
  265. name=USER,
  266. win_homedrive='R:',
  267. win_profile='C:\\Users\\{0}'.format(USER),
  268. win_logonscript='C:\\Windows\\logon.vbs',
  269. win_description='Temporary Account')
  270. self.assertSaltTrueReturn(ret)
  271. self.assertSaltStateChangesEqual(ret, 'R:', keys=['homedrive'])
  272. self.assertSaltStateChangesEqual(
  273. ret, 'C:\\Users\\{0}'.format(USER), keys=['profile'])
  274. self.assertSaltStateChangesEqual(
  275. ret, 'C:\\Windows\\logon.vbs', keys=['logonscript'])
  276. self.assertSaltStateChangesEqual(
  277. ret, 'Temporary Account', keys=['description'])