1
0

test_user.py 12 KB

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