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