1import logging
2import random
3import string
4
5import salt.config
6import salt.loader
7import salt.modules.boto_iot as boto_iot
8from salt.utils.versions import LooseVersion
9from tests.support.mixins import LoaderModuleMockMixin
10from tests.support.mock import MagicMock, patch
11from tests.support.unit import TestCase, skipIf
12
13# pylint: disable=import-error,no-name-in-module,unused-import
14try:
15    import boto
16    import boto3
17    from botocore.exceptions import ClientError
18    from botocore import __version__ as found_botocore_version
19
20    HAS_BOTO = True
21except ImportError:
22    HAS_BOTO = False
23
24# pylint: enable=import-error,no-name-in-module,unused-import
25
26# the boto_iot module relies on the connect_to_region() method
27# which was added in boto 2.8.0
28# https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
29required_boto3_version = "1.2.1"
30required_botocore_version = "1.4.41"
31
32log = logging.getLogger(__name__)
33
34
35def _has_required_boto():
36    """
37    Returns True/False boolean depending on if Boto is installed and correct
38    version.
39    """
40    if not HAS_BOTO:
41        return False
42    elif LooseVersion(boto3.__version__) < LooseVersion(required_boto3_version):
43        return False
44    elif LooseVersion(found_botocore_version) < LooseVersion(required_botocore_version):
45        return False
46    else:
47        return True
48
49
50if _has_required_boto():
51    region = "us-east-1"
52    access_key = "GKTADJGHEIQSXMKKRBJ08H"
53    secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs"
54    conn_parameters = {
55        "region": region,
56        "key": access_key,
57        "keyid": secret_key,
58        "profile": {},
59    }
60    error_message = (
61        "An error occurred (101) when calling the {0} operation: Test-defined error"
62    )
63    not_found_error = ClientError(
64        {
65            "Error": {
66                "Code": "ResourceNotFoundException",
67                "Message": "Test-defined error",
68            }
69        },
70        "msg",
71    )
72    topic_rule_not_found_error = ClientError(
73        {"Error": {"Code": "UnauthorizedException", "Message": "Test-defined error"}},
74        "msg",
75    )
76    error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}}
77    policy_ret = dict(
78        policyName="testpolicy",
79        policyDocument=(
80            '{"Version": "2012-10-17", "Statement": [{"Action": ["iot:Publish"],'
81            ' "Resource": ["*"], "Effect": "Allow"}]}'
82        ),
83        policyArn="arn:aws:iot:us-east-1:123456:policy/my_policy",
84        policyVersionId=1,
85        defaultVersionId=1,
86    )
87    topic_rule_ret = dict(
88        ruleName="testrule",
89        sql="SELECT * FROM 'iot/test'",
90        description="topic rule description",
91        createdAt="1970-01-01",
92        actions=[{"lambda": {"functionArn": "arn:aws:::function"}}],
93        ruleDisabled=True,
94    )
95
96    thing_type_name = "test_thing_type"
97    thing_type_desc = "test_thing_type_desc"
98    thing_type_attr_1 = "test_thing_type_search_attr_1"
99    thing_type_ret = dict(
100        thingTypeName=thing_type_name,
101        thingTypeProperties=dict(
102            thingTypeDescription=thing_type_desc,
103            searchableAttributes=[thing_type_attr_1],
104        ),
105        thingTypeMetadata=dict(
106            deprecated=False, creationDate="test_thing_type_create_date"
107        ),
108    )
109    thing_type_arn = "test_thing_type_arn"
110    create_thing_type_ret = dict(
111        thingTypeName=thing_type_name, thingTypeArn=thing_type_arn
112    )
113
114
115@skipIf(HAS_BOTO is False, "The boto module must be installed.")
116@skipIf(
117    _has_required_boto() is False,
118    "The boto3 module must be greater than or equal to version {}".format(
119        required_boto3_version
120    ),
121)
122class BotoIoTTestCaseBase(TestCase, LoaderModuleMockMixin):
123    conn = None
124
125    def setup_loader_modules(self):
126        self.opts = opts = salt.config.DEFAULT_MINION_OPTS.copy()
127        utils = salt.loader.utils(
128            opts, whitelist=["boto3", "args", "systemd", "path", "platform"], context={}
129        )
130        return {boto_iot: {"__utils__": utils}}
131
132    def setUp(self):
133        super().setUp()
134        boto_iot.__init__(self.opts)
135        del self.opts
136
137        # Set up MagicMock to replace the boto3 session
138        # connections keep getting cached from prior tests, can't find the
139        # correct context object to clear it. So randomize the cache key, to prevent any
140        # cache hits
141        conn_parameters["key"] = "".join(
142            random.choice(string.ascii_lowercase + string.digits) for _ in range(50)
143        )
144
145        self.patcher = patch("boto3.session.Session")
146        self.addCleanup(self.patcher.stop)
147        self.addCleanup(delattr, self, "patcher")
148        mock_session = self.patcher.start()
149
150        session_instance = mock_session.return_value
151        self.conn = MagicMock()
152        self.addCleanup(delattr, self, "conn")
153        session_instance.client.return_value = self.conn
154
155
156class BotoIoTTestCaseMixin:
157    pass
158
159
160class BotoIoTThingTypeTestCase(BotoIoTTestCaseBase, BotoIoTTestCaseMixin):
161    """
162    TestCase for salt.modules.boto_iot module
163    """
164
165    def test_that_when_checking_if_a_thing_type_exists_and_a_thing_type_exists_the_thing_type_exists_method_returns_true(
166        self,
167    ):
168        """
169        Tests checking iot thing type existence when the iot thing type already exists
170        """
171        self.conn.describe_thing_type.return_value = thing_type_ret
172        result = boto_iot.thing_type_exists(
173            thingTypeName=thing_type_name, **conn_parameters
174        )
175
176        self.assertTrue(result["exists"])
177
178    def test_that_when_checking_if_a_thing_type_exists_and_a_thing_type_does_not_exist_the_thing_type_exists_method_returns_false(
179        self,
180    ):
181        """
182        Tests checking iot thing type existence when the iot thing type does not exist
183        """
184        self.conn.describe_thing_type.side_effect = not_found_error
185        result = boto_iot.thing_type_exists(
186            thingTypeName="non existent thing type", **conn_parameters
187        )
188
189        self.assertFalse(result["exists"])
190
191    def test_that_when_checking_if_a_thing_type_exists_and_boto3_returns_an_error_the_thing_type_exists_method_returns_error(
192        self,
193    ):
194        """
195        Tests checking iot thing type existence when boto returns an error
196        """
197        self.conn.describe_thing_type.side_effect = ClientError(
198            error_content, "describe_thing_type"
199        )
200        result = boto_iot.thing_type_exists(
201            thingTypeName="mythingtype", **conn_parameters
202        )
203
204        self.assertEqual(
205            result.get("error", {}).get("message"),
206            error_message.format("describe_thing_type"),
207        )
208
209    def test_that_when_describing_thing_type_and_thing_type_exists_the_describe_thing_type_method_returns_thing_type(
210        self,
211    ):
212        """
213        Tests describe thing type for an existing thing type
214        """
215        self.conn.describe_thing_type.return_value = thing_type_ret
216        result = boto_iot.describe_thing_type(
217            thingTypeName=thing_type_name, **conn_parameters
218        )
219
220        self.assertEqual(result.get("thing_type"), thing_type_ret)
221
222    def test_that_when_describing_thing_type_and_thing_type_does_not_exists_the_describe_thing_type_method_returns_none(
223        self,
224    ):
225        """
226        Tests describe thing type for an non existent thing type
227        """
228        self.conn.describe_thing_type.side_effect = not_found_error
229        result = boto_iot.describe_thing_type(
230            thingTypeName="non existent thing type", **conn_parameters
231        )
232
233        self.assertEqual(result.get("thing_type"), None)
234
235    def test_that_when_describing_thing_type_and_boto3_returns_error_an_error_the_describe_thing_type_method_returns_error(
236        self,
237    ):
238        self.conn.describe_thing_type.side_effect = ClientError(
239            error_content, "describe_thing_type"
240        )
241        result = boto_iot.describe_thing_type(
242            thingTypeName="mythingtype", **conn_parameters
243        )
244
245        self.assertEqual(
246            result.get("error", {}).get("message"),
247            error_message.format("describe_thing_type"),
248        )
249
250    def test_that_when_creating_a_thing_type_succeeds_the_create_thing_type_method_returns_true(
251        self,
252    ):
253        """
254        tests True when thing type created
255        """
256        self.conn.create_thing_type.return_value = create_thing_type_ret
257        result = boto_iot.create_thing_type(
258            thingTypeName=thing_type_name,
259            thingTypeDescription=thing_type_desc,
260            searchableAttributesList=[thing_type_attr_1],
261            **conn_parameters
262        )
263        self.assertTrue(result["created"])
264        self.assertTrue(result["thingTypeArn"], thing_type_arn)
265
266    def test_that_when_creating_a_thing_type_fails_the_create_thing_type_method_returns_error(
267        self,
268    ):
269        """
270        tests False when thing type not created
271        """
272        self.conn.create_thing_type.side_effect = ClientError(
273            error_content, "create_thing_type"
274        )
275        result = boto_iot.create_thing_type(
276            thingTypeName=thing_type_name,
277            thingTypeDescription=thing_type_desc,
278            searchableAttributesList=[thing_type_attr_1],
279            **conn_parameters
280        )
281        self.assertEqual(
282            result.get("error", {}).get("message"),
283            error_message.format("create_thing_type"),
284        )
285
286    def test_that_when_deprecating_a_thing_type_succeeds_the_deprecate_thing_type_method_returns_true(
287        self,
288    ):
289        """
290        tests True when deprecate thing type succeeds
291        """
292        self.conn.deprecate_thing_type.return_value = {}
293        result = boto_iot.deprecate_thing_type(
294            thingTypeName=thing_type_name, undoDeprecate=False, **conn_parameters
295        )
296
297        self.assertTrue(result.get("deprecated"))
298        self.assertEqual(result.get("error"), None)
299
300    def test_that_when_deprecating_a_thing_type_fails_the_deprecate_thing_type_method_returns_error(
301        self,
302    ):
303        """
304        tests False when thing type fails to deprecate
305        """
306        self.conn.deprecate_thing_type.side_effect = ClientError(
307            error_content, "deprecate_thing_type"
308        )
309        result = boto_iot.deprecate_thing_type(
310            thingTypeName=thing_type_name, undoDeprecate=False, **conn_parameters
311        )
312
313        self.assertFalse(result.get("deprecated"))
314        self.assertEqual(
315            result.get("error", {}).get("message"),
316            error_message.format("deprecate_thing_type"),
317        )
318
319    def test_that_when_deleting_a_thing_type_succeeds_the_delete_thing_type_method_returns_true(
320        self,
321    ):
322        """
323        tests True when delete thing type succeeds
324        """
325        self.conn.delete_thing_type.return_value = {}
326        result = boto_iot.delete_thing_type(
327            thingTypeName=thing_type_name, **conn_parameters
328        )
329
330        self.assertTrue(result.get("deleted"))
331        self.assertEqual(result.get("error"), None)
332
333    def test_that_when_deleting_a_thing_type_fails_the_delete_thing_type_method_returns_error(
334        self,
335    ):
336        """
337        tests False when delete thing type fails
338        """
339        self.conn.delete_thing_type.side_effect = ClientError(
340            error_content, "delete_thing_type"
341        )
342        result = boto_iot.delete_thing_type(
343            thingTypeName=thing_type_name, **conn_parameters
344        )
345        self.assertFalse(result.get("deleted"))
346        self.assertEqual(
347            result.get("error", {}).get("message"),
348            error_message.format("delete_thing_type"),
349        )
350
351
352class BotoIoTPolicyTestCase(BotoIoTTestCaseBase, BotoIoTTestCaseMixin):
353    """
354    TestCase for salt.modules.boto_iot module
355    """
356
357    def test_that_when_checking_if_a_policy_exists_and_a_policy_exists_the_policy_exists_method_returns_true(
358        self,
359    ):
360        """
361        Tests checking iot policy existence when the iot policy already exists
362        """
363        self.conn.get_policy.return_value = {"policy": policy_ret}
364        result = boto_iot.policy_exists(
365            policyName=policy_ret["policyName"], **conn_parameters
366        )
367
368        self.assertTrue(result["exists"])
369
370    def test_that_when_checking_if_a_policy_exists_and_a_policy_does_not_exist_the_policy_exists_method_returns_false(
371        self,
372    ):
373        """
374        Tests checking iot policy existence when the iot policy does not exist
375        """
376        self.conn.get_policy.side_effect = not_found_error
377        result = boto_iot.policy_exists(policyName="mypolicy", **conn_parameters)
378
379        self.assertFalse(result["exists"])
380
381    def test_that_when_checking_if_a_policy_exists_and_boto3_returns_an_error_the_policy_exists_method_returns_error(
382        self,
383    ):
384        """
385        Tests checking iot policy existence when boto returns an error
386        """
387        self.conn.get_policy.side_effect = ClientError(error_content, "get_policy")
388        result = boto_iot.policy_exists(policyName="mypolicy", **conn_parameters)
389
390        self.assertEqual(
391            result.get("error", {}).get("message"), error_message.format("get_policy")
392        )
393
394    def test_that_when_creating_a_policy_succeeds_the_create_policy_method_returns_true(
395        self,
396    ):
397        """
398        tests True policy created.
399        """
400        self.conn.create_policy.return_value = policy_ret
401        result = boto_iot.create_policy(
402            policyName=policy_ret["policyName"],
403            policyDocument=policy_ret["policyDocument"],
404            **conn_parameters
405        )
406
407        self.assertTrue(result["created"])
408
409    def test_that_when_creating_a_policy_fails_the_create_policy_method_returns_error(
410        self,
411    ):
412        """
413        tests False policy not created.
414        """
415        self.conn.create_policy.side_effect = ClientError(
416            error_content, "create_policy"
417        )
418        result = boto_iot.create_policy(
419            policyName=policy_ret["policyName"],
420            policyDocument=policy_ret["policyDocument"],
421            **conn_parameters
422        )
423        self.assertEqual(
424            result.get("error", {}).get("message"),
425            error_message.format("create_policy"),
426        )
427
428    def test_that_when_deleting_a_policy_succeeds_the_delete_policy_method_returns_true(
429        self,
430    ):
431        """
432        tests True policy deleted.
433        """
434        result = boto_iot.delete_policy(policyName="testpolicy", **conn_parameters)
435
436        self.assertTrue(result["deleted"])
437
438    def test_that_when_deleting_a_policy_fails_the_delete_policy_method_returns_false(
439        self,
440    ):
441        """
442        tests False policy not deleted.
443        """
444        self.conn.delete_policy.side_effect = ClientError(
445            error_content, "delete_policy"
446        )
447        result = boto_iot.delete_policy(policyName="testpolicy", **conn_parameters)
448        self.assertFalse(result["deleted"])
449
450    def test_that_when_describing_policy_it_returns_the_dict_of_properties_returns_true(
451        self,
452    ):
453        """
454        Tests describing parameters if policy exists
455        """
456        self.conn.get_policy.return_value = {"policy": policy_ret}
457
458        result = boto_iot.describe_policy(
459            policyName=policy_ret["policyName"], **conn_parameters
460        )
461
462        self.assertTrue(result["policy"])
463
464    def test_that_when_describing_policy_it_returns_the_dict_of_properties_returns_false(
465        self,
466    ):
467        """
468        Tests describing parameters if policy does not exist
469        """
470        self.conn.get_policy.side_effect = not_found_error
471        result = boto_iot.describe_policy(policyName="testpolicy", **conn_parameters)
472
473        self.assertFalse(result["policy"])
474
475    def test_that_when_describing_policy_on_client_error_it_returns_error(self):
476        """
477        Tests describing parameters failure
478        """
479        self.conn.get_policy.side_effect = ClientError(error_content, "get_policy")
480        result = boto_iot.describe_policy(policyName="testpolicy", **conn_parameters)
481        self.assertTrue("error" in result)
482
483    def test_that_when_checking_if_a_policy_version_exists_and_a_policy_version_exists_the_policy_version_exists_method_returns_true(
484        self,
485    ):
486        """
487        Tests checking iot policy existence when the iot policy version already exists
488        """
489        self.conn.get_policy.return_value = {"policy": policy_ret}
490        result = boto_iot.policy_version_exists(
491            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
492        )
493
494        self.assertTrue(result["exists"])
495
496    def test_that_when_checking_if_a_policy_version_exists_and_a_policy_version_does_not_exist_the_policy_version_exists_method_returns_false(
497        self,
498    ):
499        """
500        Tests checking iot policy_version existence when the iot policy_version does not exist
501        """
502        self.conn.get_policy_version.side_effect = not_found_error
503        result = boto_iot.policy_version_exists(
504            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
505        )
506
507        self.assertFalse(result["exists"])
508
509    def test_that_when_checking_if_a_policy_version_exists_and_boto3_returns_an_error_the_policy_version_exists_method_returns_error(
510        self,
511    ):
512        """
513        Tests checking iot policy_version existence when boto returns an error
514        """
515        self.conn.get_policy_version.side_effect = ClientError(
516            error_content, "get_policy_version"
517        )
518        result = boto_iot.policy_version_exists(
519            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
520        )
521
522        self.assertEqual(
523            result.get("error", {}).get("message"),
524            error_message.format("get_policy_version"),
525        )
526
527    def test_that_when_creating_a_policy_version_succeeds_the_create_policy_version_method_returns_true(
528        self,
529    ):
530        """
531        tests True policy_version created.
532        """
533        self.conn.create_policy_version.return_value = policy_ret
534        result = boto_iot.create_policy_version(
535            policyName=policy_ret["policyName"],
536            policyDocument=policy_ret["policyDocument"],
537            **conn_parameters
538        )
539
540        self.assertTrue(result["created"])
541
542    def test_that_when_creating_a_policy_version_fails_the_create_policy_version_method_returns_error(
543        self,
544    ):
545        """
546        tests False policy_version not created.
547        """
548        self.conn.create_policy_version.side_effect = ClientError(
549            error_content, "create_policy_version"
550        )
551        result = boto_iot.create_policy_version(
552            policyName=policy_ret["policyName"],
553            policyDocument=policy_ret["policyDocument"],
554            **conn_parameters
555        )
556        self.assertEqual(
557            result.get("error", {}).get("message"),
558            error_message.format("create_policy_version"),
559        )
560
561    def test_that_when_deleting_a_policy_version_succeeds_the_delete_policy_version_method_returns_true(
562        self,
563    ):
564        """
565        tests True policy_version deleted.
566        """
567        result = boto_iot.delete_policy_version(
568            policyName="testpolicy", policyVersionId=1, **conn_parameters
569        )
570
571        self.assertTrue(result["deleted"])
572
573    def test_that_when_deleting_a_policy_version_fails_the_delete_policy_version_method_returns_false(
574        self,
575    ):
576        """
577        tests False policy_version not deleted.
578        """
579        self.conn.delete_policy_version.side_effect = ClientError(
580            error_content, "delete_policy_version"
581        )
582        result = boto_iot.delete_policy_version(
583            policyName="testpolicy", policyVersionId=1, **conn_parameters
584        )
585        self.assertFalse(result["deleted"])
586
587    def test_that_when_describing_policy_version_it_returns_the_dict_of_properties_returns_true(
588        self,
589    ):
590        """
591        Tests describing parameters if policy_version exists
592        """
593        self.conn.get_policy_version.return_value = {"policy": policy_ret}
594
595        result = boto_iot.describe_policy_version(
596            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
597        )
598
599        self.assertTrue(result["policy"])
600
601    def test_that_when_describing_policy_version_it_returns_the_dict_of_properties_returns_false(
602        self,
603    ):
604        """
605        Tests describing parameters if policy_version does not exist
606        """
607        self.conn.get_policy_version.side_effect = not_found_error
608        result = boto_iot.describe_policy_version(
609            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
610        )
611
612        self.assertFalse(result["policy"])
613
614    def test_that_when_describing_policy_version_on_client_error_it_returns_error(self):
615        """
616        Tests describing parameters failure
617        """
618        self.conn.get_policy_version.side_effect = ClientError(
619            error_content, "get_policy_version"
620        )
621        result = boto_iot.describe_policy_version(
622            policyName=policy_ret["policyName"], policyVersionId=1, **conn_parameters
623        )
624        self.assertTrue("error" in result)
625
626    def test_that_when_listing_policies_succeeds_the_list_policies_method_returns_true(
627        self,
628    ):
629        """
630        tests True policies listed.
631        """
632        self.conn.list_policies.return_value = {"policies": [policy_ret]}
633        result = boto_iot.list_policies(**conn_parameters)
634
635        self.assertTrue(result["policies"])
636
637    def test_that_when_listing_policy_fails_the_list_policy_method_returns_false(self):
638        """
639        tests False no policy listed.
640        """
641        self.conn.list_policies.return_value = {"policies": []}
642        result = boto_iot.list_policies(**conn_parameters)
643        self.assertFalse(result["policies"])
644
645    def test_that_when_listing_policy_fails_the_list_policy_method_returns_error(self):
646        """
647        tests False policy error.
648        """
649        self.conn.list_policies.side_effect = ClientError(
650            error_content, "list_policies"
651        )
652        result = boto_iot.list_policies(**conn_parameters)
653        self.assertEqual(
654            result.get("error", {}).get("message"),
655            error_message.format("list_policies"),
656        )
657
658    def test_that_when_listing_policy_versions_succeeds_the_list_policy_versions_method_returns_true(
659        self,
660    ):
661        """
662        tests True policy versions listed.
663        """
664        self.conn.list_policy_versions.return_value = {"policyVersions": [policy_ret]}
665        result = boto_iot.list_policy_versions(
666            policyName="testpolicy", **conn_parameters
667        )
668
669        self.assertTrue(result["policyVersions"])
670
671    def test_that_when_listing_policy_versions_fails_the_list_policy_versions_method_returns_false(
672        self,
673    ):
674        """
675        tests False no policy versions listed.
676        """
677        self.conn.list_policy_versions.return_value = {"policyVersions": []}
678        result = boto_iot.list_policy_versions(
679            policyName="testpolicy", **conn_parameters
680        )
681        self.assertFalse(result["policyVersions"])
682
683    def test_that_when_listing_policy_versions_fails_the_list_policy_versions_method_returns_error(
684        self,
685    ):
686        """
687        tests False policy versions error.
688        """
689        self.conn.list_policy_versions.side_effect = ClientError(
690            error_content, "list_policy_versions"
691        )
692        result = boto_iot.list_policy_versions(
693            policyName="testpolicy", **conn_parameters
694        )
695        self.assertEqual(
696            result.get("error", {}).get("message"),
697            error_message.format("list_policy_versions"),
698        )
699
700    def test_that_when_setting_default_policy_version_succeeds_the_set_default_policy_version_method_returns_true(
701        self,
702    ):
703        """
704        tests True policy version set.
705        """
706        result = boto_iot.set_default_policy_version(
707            policyName="testpolicy", policyVersionId=1, **conn_parameters
708        )
709
710        self.assertTrue(result["changed"])
711
712    def test_that_when_set_default_policy_version_fails_the_set_default_policy_version_method_returns_error(
713        self,
714    ):
715        """
716        tests False policy version error.
717        """
718        self.conn.set_default_policy_version.side_effect = ClientError(
719            error_content, "set_default_policy_version"
720        )
721        result = boto_iot.set_default_policy_version(
722            policyName="testpolicy", policyVersionId=1, **conn_parameters
723        )
724        self.assertEqual(
725            result.get("error", {}).get("message"),
726            error_message.format("set_default_policy_version"),
727        )
728
729    def test_that_when_list_principal_policies_succeeds_the_list_principal_policies_method_returns_true(
730        self,
731    ):
732        """
733        tests True policies listed.
734        """
735        self.conn.list_principal_policies.return_value = {"policies": [policy_ret]}
736        result = boto_iot.list_principal_policies(
737            principal="us-east-1:GUID-GUID-GUID", **conn_parameters
738        )
739
740        self.assertTrue(result["policies"])
741
742    def test_that_when_list_principal_policies_fails_the_list_principal_policies_method_returns_error(
743        self,
744    ):
745        """
746        tests False policy version error.
747        """
748        self.conn.list_principal_policies.side_effect = ClientError(
749            error_content, "list_principal_policies"
750        )
751        result = boto_iot.list_principal_policies(
752            principal="us-east-1:GUID-GUID-GUID", **conn_parameters
753        )
754        self.assertEqual(
755            result.get("error", {}).get("message"),
756            error_message.format("list_principal_policies"),
757        )
758
759    def test_that_when_attach_principal_policy_succeeds_the_attach_principal_policy_method_returns_true(
760        self,
761    ):
762        """
763        tests True policy attached.
764        """
765        result = boto_iot.attach_principal_policy(
766            policyName="testpolicy",
767            principal="us-east-1:GUID-GUID-GUID",
768            **conn_parameters
769        )
770
771        self.assertTrue(result["attached"])
772
773    def test_that_when_attach_principal_policy_version_fails_the_attach_principal_policy_version_method_returns_error(
774        self,
775    ):
776        """
777        tests False policy version error.
778        """
779        self.conn.attach_principal_policy.side_effect = ClientError(
780            error_content, "attach_principal_policy"
781        )
782        result = boto_iot.attach_principal_policy(
783            policyName="testpolicy",
784            principal="us-east-1:GUID-GUID-GUID",
785            **conn_parameters
786        )
787        self.assertEqual(
788            result.get("error", {}).get("message"),
789            error_message.format("attach_principal_policy"),
790        )
791
792    def test_that_when_detach_principal_policy_succeeds_the_detach_principal_policy_method_returns_true(
793        self,
794    ):
795        """
796        tests True policy detached.
797        """
798        result = boto_iot.detach_principal_policy(
799            policyName="testpolicy",
800            principal="us-east-1:GUID-GUID-GUID",
801            **conn_parameters
802        )
803
804        self.assertTrue(result["detached"])
805
806    def test_that_when_detach_principal_policy_version_fails_the_detach_principal_policy_version_method_returns_error(
807        self,
808    ):
809        """
810        tests False policy version error.
811        """
812        self.conn.detach_principal_policy.side_effect = ClientError(
813            error_content, "detach_principal_policy"
814        )
815        result = boto_iot.detach_principal_policy(
816            policyName="testpolicy",
817            principal="us-east-1:GUID-GUID-GUID",
818            **conn_parameters
819        )
820        self.assertEqual(
821            result.get("error", {}).get("message"),
822            error_message.format("detach_principal_policy"),
823        )
824
825
826@skipIf(HAS_BOTO is False, "The boto module must be installed.")
827@skipIf(
828    _has_required_boto() is False,
829    "The boto3 module must be greater than"
830    " or equal to version {}.  The botocore"
831    " module must be greater than or equal to"
832    " version {}.".format(required_boto3_version, required_botocore_version),
833)
834class BotoIoTTopicRuleTestCase(BotoIoTTestCaseBase, BotoIoTTestCaseMixin):
835    """
836    TestCase for salt.modules.boto_iot module
837    """
838
839    def test_that_when_checking_if_a_topic_rule_exists_and_a_topic_rule_exists_the_topic_rule_exists_method_returns_true(
840        self,
841    ):
842        """
843        Tests checking iot topic_rule existence when the iot topic_rule already exists
844        """
845        self.conn.get_topic_rule.return_value = {"rule": topic_rule_ret}
846        result = boto_iot.topic_rule_exists(
847            ruleName=topic_rule_ret["ruleName"], **conn_parameters
848        )
849
850        self.assertTrue(result["exists"])
851
852    def test_that_when_checking_if_a_rule_exists_and_a_rule_does_not_exist_the_topic_rule_exists_method_returns_false(
853        self,
854    ):
855        """
856        Tests checking iot rule existence when the iot rule does not exist
857        """
858        self.conn.get_topic_rule.side_effect = topic_rule_not_found_error
859        result = boto_iot.topic_rule_exists(ruleName="mypolicy", **conn_parameters)
860
861        self.assertFalse(result["exists"])
862
863    def test_that_when_checking_if_a_topic_rule_exists_and_boto3_returns_an_error_the_topic_rule_exists_method_returns_error(
864        self,
865    ):
866        """
867        Tests checking iot topic_rule existence when boto returns an error
868        """
869        self.conn.get_topic_rule.side_effect = ClientError(
870            error_content, "get_topic_rule"
871        )
872        result = boto_iot.topic_rule_exists(ruleName="myrule", **conn_parameters)
873
874        self.assertEqual(
875            result.get("error", {}).get("message"),
876            error_message.format("get_topic_rule"),
877        )
878
879    def test_that_when_creating_a_topic_rule_succeeds_the_create_topic_rule_method_returns_true(
880        self,
881    ):
882        """
883        tests True topic_rule created.
884        """
885        self.conn.create_topic_rule.return_value = topic_rule_ret
886        result = boto_iot.create_topic_rule(
887            ruleName=topic_rule_ret["ruleName"],
888            sql=topic_rule_ret["sql"],
889            description=topic_rule_ret["description"],
890            actions=topic_rule_ret["actions"],
891            **conn_parameters
892        )
893
894        self.assertTrue(result["created"])
895
896    def test_that_when_creating_a_topic_rule_fails_the_create_topic_rule_method_returns_error(
897        self,
898    ):
899        """
900        tests False topic_rule not created.
901        """
902        self.conn.create_topic_rule.side_effect = ClientError(
903            error_content, "create_topic_rule"
904        )
905        result = boto_iot.create_topic_rule(
906            ruleName=topic_rule_ret["ruleName"],
907            sql=topic_rule_ret["sql"],
908            description=topic_rule_ret["description"],
909            actions=topic_rule_ret["actions"],
910            **conn_parameters
911        )
912        self.assertEqual(
913            result.get("error", {}).get("message"),
914            error_message.format("create_topic_rule"),
915        )
916
917    def test_that_when_replacing_a_topic_rule_succeeds_the_replace_topic_rule_method_returns_true(
918        self,
919    ):
920        """
921        tests True topic_rule replaced.
922        """
923        self.conn.replace_topic_rule.return_value = topic_rule_ret
924        result = boto_iot.replace_topic_rule(
925            ruleName=topic_rule_ret["ruleName"],
926            sql=topic_rule_ret["sql"],
927            description=topic_rule_ret["description"],
928            actions=topic_rule_ret["actions"],
929            **conn_parameters
930        )
931
932        self.assertTrue(result["replaced"])
933
934    def test_that_when_replacing_a_topic_rule_fails_the_replace_topic_rule_method_returns_error(
935        self,
936    ):
937        """
938        tests False topic_rule not replaced.
939        """
940        self.conn.replace_topic_rule.side_effect = ClientError(
941            error_content, "replace_topic_rule"
942        )
943        result = boto_iot.replace_topic_rule(
944            ruleName=topic_rule_ret["ruleName"],
945            sql=topic_rule_ret["sql"],
946            description=topic_rule_ret["description"],
947            actions=topic_rule_ret["actions"],
948            **conn_parameters
949        )
950        self.assertEqual(
951            result.get("error", {}).get("message"),
952            error_message.format("replace_topic_rule"),
953        )
954
955    def test_that_when_deleting_a_topic_rule_succeeds_the_delete_topic_rule_method_returns_true(
956        self,
957    ):
958        """
959        tests True topic_rule deleted.
960        """
961        result = boto_iot.delete_topic_rule(ruleName="testrule", **conn_parameters)
962
963        self.assertTrue(result["deleted"])
964
965    def test_that_when_deleting_a_topic_rule_fails_the_delete_topic_rule_method_returns_false(
966        self,
967    ):
968        """
969        tests False topic_rule not deleted.
970        """
971        self.conn.delete_topic_rule.side_effect = ClientError(
972            error_content, "delete_topic_rule"
973        )
974        result = boto_iot.delete_topic_rule(ruleName="testrule", **conn_parameters)
975        self.assertFalse(result["deleted"])
976
977    def test_that_when_describing_topic_rule_it_returns_the_dict_of_properties_returns_true(
978        self,
979    ):
980        """
981        Tests describing parameters if topic_rule exists
982        """
983        self.conn.get_topic_rule.return_value = {"rule": topic_rule_ret}
984
985        result = boto_iot.describe_topic_rule(
986            ruleName=topic_rule_ret["ruleName"], **conn_parameters
987        )
988
989        self.assertTrue(result["rule"])
990
991    def test_that_when_describing_topic_rule_on_client_error_it_returns_error(self):
992        """
993        Tests describing parameters failure
994        """
995        self.conn.get_topic_rule.side_effect = ClientError(
996            error_content, "get_topic_rule"
997        )
998        result = boto_iot.describe_topic_rule(ruleName="testrule", **conn_parameters)
999        self.assertTrue("error" in result)
1000
1001    def test_that_when_listing_topic_rules_succeeds_the_list_topic_rules_method_returns_true(
1002        self,
1003    ):
1004        """
1005        tests True topic_rules listed.
1006        """
1007        self.conn.list_topic_rules.return_value = {"rules": [topic_rule_ret]}
1008        result = boto_iot.list_topic_rules(**conn_parameters)
1009
1010        self.assertTrue(result["rules"])
1011
1012    def test_that_when_listing_topic_rules_fails_the_list_topic_rules_method_returns_error(
1013        self,
1014    ):
1015        """
1016        tests False policy error.
1017        """
1018        self.conn.list_topic_rules.side_effect = ClientError(
1019            error_content, "list_topic_rules"
1020        )
1021        result = boto_iot.list_topic_rules(**conn_parameters)
1022        self.assertEqual(
1023            result.get("error", {}).get("message"),
1024            error_message.format("list_topic_rules"),
1025        )
1026