test_url.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. # -*- coding: utf-8 -*-
  2. # Import python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. # Import Salt Libs
  5. import salt.utils.platform
  6. import salt.utils.url
  7. from tests.support.mock import MagicMock, patch
  8. # Import Salt Testing Libs
  9. from tests.support.unit import TestCase
  10. class UrlTestCase(TestCase):
  11. """
  12. TestCase for salt.utils.url module
  13. """
  14. # parse tests
  15. def test_parse_path(self):
  16. """
  17. Test parsing an ordinary path
  18. """
  19. path = "interesting?/path&.conf:and other things"
  20. self.assertEqual(salt.utils.url.parse(path), (path, None))
  21. def test_parse_salt_url(self):
  22. """
  23. Test parsing a 'salt://' URL
  24. """
  25. path = "?funny/path with {interesting|chars}"
  26. url = "salt://" + path
  27. if salt.utils.platform.is_windows():
  28. path = "_funny/path with {interesting_chars}"
  29. self.assertEqual(salt.utils.url.parse(url), (path, None))
  30. def test_parse_salt_saltenv(self):
  31. """
  32. Test parsing a 'salt://' URL with a '?saltenv=' query
  33. """
  34. saltenv = "ambience"
  35. path = "?funny/path&with {interesting|chars}"
  36. url = "salt://" + path + "?saltenv=" + saltenv
  37. if salt.utils.platform.is_windows():
  38. path = "_funny/path&with {interesting_chars}"
  39. self.assertEqual(salt.utils.url.parse(url), (path, saltenv))
  40. # create tests
  41. def test_create_url(self):
  42. """
  43. Test creating a 'salt://' URL
  44. """
  45. path = "? interesting/&path.filetype"
  46. url = "salt://" + path
  47. if salt.utils.platform.is_windows():
  48. url = "salt://_ interesting/&path.filetype"
  49. self.assertEqual(salt.utils.url.create(path), url)
  50. def test_create_url_saltenv(self):
  51. """
  52. Test creating a 'salt://' URL with a saltenv
  53. """
  54. saltenv = "raumklang"
  55. path = "? interesting/&path.filetype"
  56. if salt.utils.platform.is_windows():
  57. path = "_ interesting/&path.filetype"
  58. url = "salt://" + path + "?saltenv=" + saltenv
  59. self.assertEqual(salt.utils.url.create(path, saltenv), url)
  60. # is_escaped tests
  61. def test_is_escaped_windows(self):
  62. """
  63. Test not testing a 'salt://' URL on windows
  64. """
  65. url = "salt://dir/file.ini"
  66. with patch("salt.utils.platform.is_windows", MagicMock(return_value=True)):
  67. self.assertFalse(salt.utils.url.is_escaped(url))
  68. def test_is_escaped_escaped_path(self):
  69. """
  70. Test testing an escaped path
  71. """
  72. path = "|dir/file.conf?saltenv=basic"
  73. self.assertTrue(salt.utils.url.is_escaped(path))
  74. def test_is_escaped_unescaped_path(self):
  75. """
  76. Test testing an unescaped path
  77. """
  78. path = "dir/file.conf"
  79. self.assertFalse(salt.utils.url.is_escaped(path))
  80. def test_is_escaped_escaped_url(self):
  81. """
  82. Test testing an escaped 'salt://' URL
  83. """
  84. url = "salt://|dir/file.conf?saltenv=basic"
  85. self.assertTrue(salt.utils.url.is_escaped(url))
  86. def test_is_escaped_unescaped_url(self):
  87. """
  88. Test testing an unescaped 'salt://' URL
  89. """
  90. url = "salt://dir/file.conf"
  91. self.assertFalse(salt.utils.url.is_escaped(url))
  92. def test_is_escaped_generic_url(self):
  93. """
  94. Test testing an unescaped 'salt://' URL
  95. """
  96. url = "https://gentoo.org/"
  97. self.assertFalse(salt.utils.url.is_escaped(url))
  98. # escape tests
  99. def test_escape_windows(self):
  100. """
  101. Test not escaping a 'salt://' URL on windows
  102. """
  103. url = "salt://dir/file.ini"
  104. with patch("salt.utils.platform.is_windows", MagicMock(return_value=True)):
  105. self.assertEqual(salt.utils.url.escape(url), url)
  106. def test_escape_escaped_path(self):
  107. """
  108. Test escaping an escaped path
  109. """
  110. resource = "|dir/file.conf?saltenv=basic"
  111. self.assertEqual(salt.utils.url.escape(resource), resource)
  112. def test_escape_unescaped_path(self):
  113. """
  114. Test escaping an unescaped path
  115. """
  116. path = "dir/file.conf"
  117. escaped_path = "|" + path
  118. if salt.utils.platform.is_windows():
  119. escaped_path = path
  120. self.assertEqual(salt.utils.url.escape(path), escaped_path)
  121. def test_escape_escaped_url(self):
  122. """
  123. Test testing an escaped 'salt://' URL
  124. """
  125. url = "salt://|dir/file.conf?saltenv=basic"
  126. self.assertEqual(salt.utils.url.escape(url), url)
  127. def test_escape_unescaped_url(self):
  128. """
  129. Test testing an unescaped 'salt://' URL
  130. """
  131. path = "dir/file.conf"
  132. url = "salt://" + path
  133. escaped_url = "salt://|" + path
  134. if salt.utils.platform.is_windows():
  135. escaped_url = url
  136. self.assertEqual(salt.utils.url.escape(url), escaped_url)
  137. def test_escape_generic_url(self):
  138. """
  139. Test testing an unescaped 'salt://' URL
  140. """
  141. url = "https://gentoo.org/"
  142. self.assertEqual(salt.utils.url.escape(url), url)
  143. # unescape tests
  144. def test_unescape_windows(self):
  145. """
  146. Test not escaping a 'salt://' URL on windows
  147. """
  148. url = "salt://dir/file.ini"
  149. with patch("salt.utils.platform.is_windows", MagicMock(return_value=True)):
  150. self.assertEqual(salt.utils.url.unescape(url), url)
  151. def test_unescape_escaped_path(self):
  152. """
  153. Test escaping an escaped path
  154. """
  155. resource = "dir/file.conf?saltenv=basic"
  156. escaped_path = "|" + resource
  157. self.assertEqual(salt.utils.url.unescape(escaped_path), resource)
  158. def test_unescape_unescaped_path(self):
  159. """
  160. Test escaping an unescaped path
  161. """
  162. path = "dir/file.conf"
  163. self.assertEqual(salt.utils.url.unescape(path), path)
  164. def test_unescape_escaped_url(self):
  165. """
  166. Test testing an escaped 'salt://' URL
  167. """
  168. resource = "dir/file.conf?saltenv=basic"
  169. url = "salt://" + resource
  170. escaped_url = "salt://|" + resource
  171. self.assertEqual(salt.utils.url.unescape(escaped_url), url)
  172. def test_unescape_unescaped_url(self):
  173. """
  174. Test testing an unescaped 'salt://' URL
  175. """
  176. url = "salt://dir/file.conf"
  177. self.assertEqual(salt.utils.url.unescape(url), url)
  178. def test_unescape_generic_url(self):
  179. """
  180. Test testing an unescaped 'salt://' URL
  181. """
  182. url = "https://gentoo.org/"
  183. self.assertEqual(salt.utils.url.unescape(url), url)
  184. # add_env tests
  185. def test_add_env_not_salt(self):
  186. """
  187. Test not adding a saltenv to a non 'salt://' URL
  188. """
  189. saltenv = "higgs"
  190. url = "https://pdg.lbl.gov/"
  191. self.assertEqual(salt.utils.url.add_env(url, saltenv), url)
  192. def test_add_env(self):
  193. """
  194. Test adding a saltenv to a 'salt://' URL
  195. """
  196. saltenv = "erstwhile"
  197. url = "salt://salted/file.conf"
  198. url_env = url + "?saltenv=" + saltenv
  199. self.assertEqual(salt.utils.url.add_env(url, saltenv), url_env)
  200. # split_env tests
  201. def test_split_env_non_salt(self):
  202. """
  203. Test not splitting a saltenv from a non 'salt://' URL
  204. """
  205. saltenv = "gravitodynamics"
  206. url = "https://arxiv.org/find/all/?" + saltenv
  207. self.assertEqual(salt.utils.url.split_env(url), (url, None))
  208. def test_split_env(self):
  209. """
  210. Test splitting a 'salt://' URL
  211. """
  212. saltenv = "elsewhere"
  213. url = "salt://salted/file.conf"
  214. url_env = url + "?saltenv=" + saltenv
  215. self.assertEqual(salt.utils.url.split_env(url_env), (url, saltenv))
  216. # validate tests
  217. def test_validate_valid(self):
  218. """
  219. Test URL valid validation
  220. """
  221. url = "salt://config/file.name?saltenv=vapid"
  222. protos = ["salt", "pepper", "cinnamon", "melange"]
  223. self.assertTrue(salt.utils.url.validate(url, protos))
  224. def test_validate_invalid(self):
  225. """
  226. Test URL invalid validation
  227. """
  228. url = "cumin://config/file.name?saltenv=vapid"
  229. protos = ["salt", "pepper", "cinnamon", "melange"]
  230. self.assertFalse(salt.utils.url.validate(url, protos))
  231. # strip tests
  232. def test_strip_url_with_scheme(self):
  233. """
  234. Test stripping of URL scheme
  235. """
  236. scheme = "git+salt+rsync+AYB://"
  237. resource = "all/the/things.stuff;parameter?query=I guess"
  238. url = scheme + resource
  239. self.assertEqual(salt.utils.url.strip_proto(url), resource)
  240. def test_strip_url_without_scheme(self):
  241. """
  242. Test stripping of a URL without a scheme
  243. """
  244. resource = "all/the/things.stuff;parameter?query=I guess"
  245. self.assertEqual(salt.utils.url.strip_proto(resource), resource)
  246. def test_http_basic_auth(self):
  247. """
  248. Tests that adding basic auth to a URL works as expected
  249. """
  250. # ((user, password), expected) tuples
  251. test_inputs = (
  252. ((None, None), "http://example.com"),
  253. (("user", None), "http://user@example.com"),
  254. (("user", "pass"), "http://user:pass@example.com"),
  255. )
  256. for (user, password), expected in test_inputs:
  257. kwargs = {
  258. "url": "http://example.com",
  259. "user": user,
  260. "password": password,
  261. }
  262. # Test http
  263. result = salt.utils.url.add_http_basic_auth(**kwargs)
  264. self.assertEqual(result, expected)
  265. # Test https
  266. kwargs["url"] = kwargs["url"].replace("http://", "https://", 1)
  267. expected = expected.replace("http://", "https://", 1)
  268. result = salt.utils.url.add_http_basic_auth(**kwargs)
  269. self.assertEqual(result, expected)
  270. def test_http_basic_auth_https_only(self):
  271. """
  272. Tests that passing a non-https URL with https_only=True will raise a
  273. ValueError.
  274. """
  275. kwargs = {
  276. "url": "http://example.com",
  277. "user": "foo",
  278. "password": "bar",
  279. "https_only": True,
  280. }
  281. self.assertRaises(ValueError, salt.utils.url.add_http_basic_auth, **kwargs)
  282. def test_redact_http_basic_auth(self):
  283. sensitive_outputs = (
  284. "https://deadbeaf@example.com",
  285. "https://user:pw@example.com",
  286. )
  287. sanitized = "https://<redacted>@example.com"
  288. for sensitive_output in sensitive_outputs:
  289. result = salt.utils.url.redact_http_basic_auth(sensitive_output)
  290. self.assertEqual(result, sanitized)
  291. def test_redact_non_auth_output(self):
  292. non_auth_output = "This is just normal output"
  293. self.assertEqual(
  294. non_auth_output, salt.utils.url.redact_http_basic_auth(non_auth_output)
  295. )