test_boto_elasticsearch_domain.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. # -*- coding: utf-8 -*-
  2. # Import Python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import copy
  5. import logging
  6. import random
  7. import string
  8. import salt.loader
  9. import salt.modules.boto_elasticsearch_domain as boto_elasticsearch_domain
  10. # Import Salt libs
  11. from salt.ext import six
  12. from salt.ext.six.moves import range
  13. from salt.utils.versions import LooseVersion
  14. # Import Salt Testing libs
  15. from tests.support.mixins import LoaderModuleMockMixin
  16. from tests.support.mock import MagicMock, patch
  17. from tests.support.unit import TestCase, skipIf
  18. # Import 3rd-party libs
  19. # pylint: disable=import-error,no-name-in-module
  20. try:
  21. import boto3
  22. from botocore.exceptions import ClientError
  23. HAS_BOTO = True
  24. except ImportError:
  25. HAS_BOTO = False
  26. # pylint: enable=import-error,no-name-in-module
  27. # the boto_elasticsearch_domain module relies on the connect_to_region() method
  28. # which was added in boto 2.8.0
  29. # https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
  30. required_boto3_version = "1.2.1"
  31. def _has_required_boto():
  32. """
  33. Returns True/False boolean depending on if Boto is installed and correct
  34. version.
  35. """
  36. if not HAS_BOTO:
  37. return False
  38. elif LooseVersion(boto3.__version__) < LooseVersion(required_boto3_version):
  39. return False
  40. else:
  41. return True
  42. if _has_required_boto():
  43. region = "us-east-1"
  44. access_key = "GKTADJGHEIQSXMKKRBJ08H"
  45. secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs"
  46. conn_parameters = {
  47. "region": region,
  48. "key": access_key,
  49. "keyid": secret_key,
  50. "profile": {},
  51. }
  52. error_message = (
  53. "An error occurred (101) when calling the {0} operation: Test-defined error"
  54. )
  55. error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}}
  56. not_found_error = ClientError(
  57. {
  58. "Error": {
  59. "Code": "ResourceNotFoundException",
  60. "Message": "Test-defined error",
  61. }
  62. },
  63. "msg",
  64. )
  65. domain_ret = dict(
  66. DomainName="testdomain",
  67. ElasticsearchClusterConfig={},
  68. EBSOptions={},
  69. AccessPolicies={},
  70. SnapshotOptions={},
  71. AdvancedOptions={},
  72. )
  73. log = logging.getLogger(__name__)
  74. class BotoElasticsearchDomainTestCaseBase(TestCase, LoaderModuleMockMixin):
  75. conn = None
  76. def setup_loader_modules(self):
  77. self.opts = salt.config.DEFAULT_MINION_OPTS.copy()
  78. utils = salt.loader.utils(
  79. self.opts,
  80. whitelist=["boto3", "args", "systemd", "path", "platform"],
  81. context={},
  82. )
  83. return {boto_elasticsearch_domain: {"__utils__": utils}}
  84. def setUp(self):
  85. super(BotoElasticsearchDomainTestCaseBase, self).setUp()
  86. boto_elasticsearch_domain.__init__(self.opts)
  87. del self.opts
  88. # Set up MagicMock to replace the boto3 session
  89. # connections keep getting cached from prior tests, can't find the
  90. # correct context object to clear it. So randomize the cache key, to prevent any
  91. # cache hits
  92. conn_parameters["key"] = "".join(
  93. random.choice(string.ascii_lowercase + string.digits) for _ in range(50)
  94. )
  95. self.patcher = patch("boto3.session.Session")
  96. self.addCleanup(self.patcher.stop)
  97. self.addCleanup(delattr, self, "patcher")
  98. mock_session = self.patcher.start()
  99. session_instance = mock_session.return_value
  100. self.conn = MagicMock()
  101. self.addCleanup(delattr, self, "conn")
  102. session_instance.client.return_value = self.conn
  103. class BotoElasticsearchDomainTestCaseMixin(object):
  104. pass
  105. @skipIf(True, "Skip these tests while investigating failures")
  106. @skipIf(HAS_BOTO is False, "The boto module must be installed.")
  107. @skipIf(
  108. _has_required_boto() is False,
  109. "The boto3 module must be greater than"
  110. " or equal to version {0}".format(required_boto3_version),
  111. )
  112. class BotoElasticsearchDomainTestCase(
  113. BotoElasticsearchDomainTestCaseBase, BotoElasticsearchDomainTestCaseMixin
  114. ):
  115. """
  116. TestCase for salt.modules.boto_elasticsearch_domain module
  117. """
  118. def test_that_when_checking_if_a_domain_exists_and_a_domain_exists_the_domain_exists_method_returns_true(
  119. self,
  120. ):
  121. """
  122. Tests checking domain existence when the domain already exists
  123. """
  124. result = boto_elasticsearch_domain.exists(
  125. DomainName="testdomain", **conn_parameters
  126. )
  127. self.assertTrue(result["exists"])
  128. def test_that_when_checking_if_a_domain_exists_and_a_domain_does_not_exist_the_domain_exists_method_returns_false(
  129. self,
  130. ):
  131. """
  132. Tests checking domain existence when the domain does not exist
  133. """
  134. self.conn.describe_elasticsearch_domain.side_effect = not_found_error
  135. result = boto_elasticsearch_domain.exists(
  136. DomainName="mydomain", **conn_parameters
  137. )
  138. self.assertFalse(result["exists"])
  139. def test_that_when_checking_if_a_domain_exists_and_boto3_returns_an_error_the_domain_exists_method_returns_error(
  140. self,
  141. ):
  142. """
  143. Tests checking domain existence when boto returns an error
  144. """
  145. self.conn.describe_elasticsearch_domain.side_effect = ClientError(
  146. error_content, "list_domains"
  147. )
  148. result = boto_elasticsearch_domain.exists(
  149. DomainName="mydomain", **conn_parameters
  150. )
  151. self.assertEqual(
  152. result.get("error", {}).get("message"), error_message.format("list_domains")
  153. )
  154. def test_that_when_checking_domain_status_and_a_domain_exists_the_domain_status_method_returns_info(
  155. self,
  156. ):
  157. """
  158. Tests checking domain existence when the domain already exists
  159. """
  160. self.conn.describe_elasticsearch_domain.return_value = {
  161. "DomainStatus": domain_ret
  162. }
  163. result = boto_elasticsearch_domain.status(
  164. DomainName="testdomain", **conn_parameters
  165. )
  166. self.assertTrue(result["domain"])
  167. def test_that_when_checking_domain_status_and_boto3_returns_an_error_the_domain_status_method_returns_error(
  168. self,
  169. ):
  170. """
  171. Tests checking domain existence when boto returns an error
  172. """
  173. self.conn.describe_elasticsearch_domain.side_effect = ClientError(
  174. error_content, "list_domains"
  175. )
  176. result = boto_elasticsearch_domain.status(
  177. DomainName="mydomain", **conn_parameters
  178. )
  179. self.assertEqual(
  180. result.get("error", {}).get("message"), error_message.format("list_domains")
  181. )
  182. def test_that_when_describing_domain_it_returns_the_dict_of_properties_returns_true(
  183. self,
  184. ):
  185. """
  186. Tests describing parameters if domain exists
  187. """
  188. domainconfig = {}
  189. for k, v in six.iteritems(domain_ret):
  190. if k == "DomainName":
  191. continue
  192. domainconfig[k] = {"Options": v}
  193. self.conn.describe_elasticsearch_domain_config.return_value = {
  194. "DomainConfig": domainconfig
  195. }
  196. result = boto_elasticsearch_domain.describe(
  197. DomainName=domain_ret["DomainName"], **conn_parameters
  198. )
  199. log.warning(result)
  200. desired_ret = copy.copy(domain_ret)
  201. desired_ret.pop("DomainName")
  202. self.assertEqual(result, {"domain": desired_ret})
  203. def test_that_when_describing_domain_on_client_error_it_returns_error(self):
  204. """
  205. Tests describing parameters failure
  206. """
  207. self.conn.describe_elasticsearch_domain_config.side_effect = ClientError(
  208. error_content, "list_domains"
  209. )
  210. result = boto_elasticsearch_domain.describe(
  211. DomainName="testdomain", **conn_parameters
  212. )
  213. self.assertTrue("error" in result)
  214. def test_that_when_creating_a_domain_succeeds_the_create_domain_method_returns_true(
  215. self,
  216. ):
  217. """
  218. tests True domain created.
  219. """
  220. self.conn.create_elasticsearch_domain.return_value = {
  221. "DomainStatus": domain_ret
  222. }
  223. args = copy.copy(domain_ret)
  224. args.update(conn_parameters)
  225. result = boto_elasticsearch_domain.create(**args)
  226. self.assertTrue(result["created"])
  227. def test_that_when_creating_a_domain_fails_the_create_domain_method_returns_error(
  228. self,
  229. ):
  230. """
  231. tests False domain not created.
  232. """
  233. self.conn.create_elasticsearch_domain.side_effect = ClientError(
  234. error_content, "create_domain"
  235. )
  236. args = copy.copy(domain_ret)
  237. args.update(conn_parameters)
  238. result = boto_elasticsearch_domain.create(**args)
  239. self.assertEqual(
  240. result.get("error", {}).get("message"),
  241. error_message.format("create_domain"),
  242. )
  243. def test_that_when_deleting_a_domain_succeeds_the_delete_domain_method_returns_true(
  244. self,
  245. ):
  246. """
  247. tests True domain deleted.
  248. """
  249. result = boto_elasticsearch_domain.delete(
  250. DomainName="testdomain", **conn_parameters
  251. )
  252. self.assertTrue(result["deleted"])
  253. def test_that_when_deleting_a_domain_fails_the_delete_domain_method_returns_false(
  254. self,
  255. ):
  256. """
  257. tests False domain not deleted.
  258. """
  259. self.conn.delete_elasticsearch_domain.side_effect = ClientError(
  260. error_content, "delete_domain"
  261. )
  262. result = boto_elasticsearch_domain.delete(
  263. DomainName="testdomain", **conn_parameters
  264. )
  265. self.assertFalse(result["deleted"])
  266. def test_that_when_updating_a_domain_succeeds_the_update_domain_method_returns_true(
  267. self,
  268. ):
  269. """
  270. tests True domain updated.
  271. """
  272. self.conn.update_elasticsearch_domain_config.return_value = {
  273. "DomainConfig": domain_ret
  274. }
  275. args = copy.copy(domain_ret)
  276. args.update(conn_parameters)
  277. result = boto_elasticsearch_domain.update(**args)
  278. self.assertTrue(result["updated"])
  279. def test_that_when_updating_a_domain_fails_the_update_domain_method_returns_error(
  280. self,
  281. ):
  282. """
  283. tests False domain not updated.
  284. """
  285. self.conn.update_elasticsearch_domain_config.side_effect = ClientError(
  286. error_content, "update_domain"
  287. )
  288. args = copy.copy(domain_ret)
  289. args.update(conn_parameters)
  290. result = boto_elasticsearch_domain.update(**args)
  291. self.assertEqual(
  292. result.get("error", {}).get("message"),
  293. error_message.format("update_domain"),
  294. )
  295. def test_that_when_adding_tags_succeeds_the_add_tags_method_returns_true(self):
  296. """
  297. tests True tags added.
  298. """
  299. self.conn.describe_elasticsearch_domain.return_value = {
  300. "DomainStatus": domain_ret
  301. }
  302. result = boto_elasticsearch_domain.add_tags(
  303. DomainName="testdomain", a="b", **conn_parameters
  304. )
  305. self.assertTrue(result["tagged"])
  306. def test_that_when_adding_tags_fails_the_add_tags_method_returns_false(self):
  307. """
  308. tests False tags not added.
  309. """
  310. self.conn.add_tags.side_effect = ClientError(error_content, "add_tags")
  311. self.conn.describe_elasticsearch_domain.return_value = {
  312. "DomainStatus": domain_ret
  313. }
  314. result = boto_elasticsearch_domain.add_tags(
  315. DomainName=domain_ret["DomainName"], a="b", **conn_parameters
  316. )
  317. self.assertFalse(result["tagged"])
  318. def test_that_when_removing_tags_succeeds_the_remove_tags_method_returns_true(self):
  319. """
  320. tests True tags removed.
  321. """
  322. self.conn.describe_elasticsearch_domain.return_value = {
  323. "DomainStatus": domain_ret
  324. }
  325. result = boto_elasticsearch_domain.remove_tags(
  326. DomainName=domain_ret["DomainName"], TagKeys=["a"], **conn_parameters
  327. )
  328. self.assertTrue(result["tagged"])
  329. def test_that_when_removing_tags_fails_the_remove_tags_method_returns_false(self):
  330. """
  331. tests False tags not removed.
  332. """
  333. self.conn.remove_tags.side_effect = ClientError(error_content, "remove_tags")
  334. self.conn.describe_elasticsearch_domain.return_value = {
  335. "DomainStatus": domain_ret
  336. }
  337. result = boto_elasticsearch_domain.remove_tags(
  338. DomainName=domain_ret["DomainName"], TagKeys=["b"], **conn_parameters
  339. )
  340. self.assertFalse(result["tagged"])
  341. def test_that_when_listing_tags_succeeds_the_list_tags_method_returns_true(self):
  342. """
  343. tests True tags listed.
  344. """
  345. self.conn.describe_elasticsearch_domain.return_value = {
  346. "DomainStatus": domain_ret
  347. }
  348. result = boto_elasticsearch_domain.list_tags(
  349. DomainName=domain_ret["DomainName"], **conn_parameters
  350. )
  351. self.assertEqual(result["tags"], {})
  352. def test_that_when_listing_tags_fails_the_list_tags_method_returns_false(self):
  353. """
  354. tests False tags not listed.
  355. """
  356. self.conn.list_tags.side_effect = ClientError(error_content, "list_tags")
  357. self.conn.describe_elasticsearch_domain.return_value = {
  358. "DomainStatus": domain_ret
  359. }
  360. result = boto_elasticsearch_domain.list_tags(
  361. DomainName=domain_ret["DomainName"], **conn_parameters
  362. )
  363. self.assertTrue(result["error"])