test_user.py 13 KB

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