Repository: getmoto/moto

Issue:
IoT ListThingPrincipals should return ResourceNotFoundException if target thing does not exist
IoT ListThingPrincipals should return ResourceNotFoundException if target thing does not exist.
but, moto returnes 200 OK and  empty principals

## Use boto3

```
>>> import boto3
>>> iot = boto3.client('iot')
>>> iot.list_thing_principals(thingName='non_exists_thing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/xxxxxxxxxx/.venv/lib/python3.7/site-packages/botocore/client.py", line 276, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/Users/xxxxxxxxxx/.venv/lib/python3.7/site-packages/botocore/client.py", line 586, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the ListThingPrincipals operation: Failed to list principals for thing non_exists_thing because the thing does not exist in your account
>>>
```

## Use moto
```
>>> import moto
>>> import boto3
>>> iot = boto3.client('iot')
>>> moto.mock_iot().start()
>>> iot.list_thing_principals(thingName='non_exists_thing')

{'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': {'server': 'amazon.com'}, 'RetryAttempts': 0}, 'principals': []}
```


Discussion:

Resolving patch:
diff --git a/moto/iot/exceptions.py b/moto/iot/exceptions.py
--- a/moto/iot/exceptions.py
+++ b/moto/iot/exceptions.py
@@ -7,10 +7,10 @@ class IoTClientError(JsonRESTError):
 
 
 class ResourceNotFoundException(IoTClientError):
-    def __init__(self):
+    def __init__(self, msg=None):
         self.code = 404
         super(ResourceNotFoundException, self).__init__(
-            "ResourceNotFoundException", "The specified resource does not exist"
+            "ResourceNotFoundException", msg or "The specified resource does not exist"
         )
 
 
diff --git a/moto/iot/models.py b/moto/iot/models.py
--- a/moto/iot/models.py
+++ b/moto/iot/models.py
@@ -805,6 +805,14 @@ def list_principal_things(self, principal_arn):
         return thing_names
 
     def list_thing_principals(self, thing_name):
+
+        things = [_ for _ in self.things.values() if _.thing_name == thing_name]
+        if len(things) == 0:
+            raise ResourceNotFoundException(
+                "Failed to list principals for thing %s because the thing does not exist in your account"
+                % thing_name
+            )
+
         principals = [
             k[0] for k, v in self.principal_things.items() if k[1] == thing_name
         ]


Test patch:
diff --git a/tests/test_iot/test_iot.py b/tests/test_iot/test_iot.py
--- a/tests/test_iot/test_iot.py
+++ b/tests/test_iot/test_iot.py
@@ -728,6 +728,14 @@ def test_principal_thing():
     res = client.list_thing_principals(thingName=thing_name)
     res.should.have.key("principals").which.should.have.length_of(0)
 
+    with assert_raises(ClientError) as e:
+        client.list_thing_principals(thingName="xxx")
+
+    e.exception.response["Error"]["Code"].should.equal("ResourceNotFoundException")
+    e.exception.response["Error"]["Message"].should.equal(
+        "Failed to list principals for thing xxx because the thing does not exist in your account"
+    )
+
 
 @mock_iot
 def test_delete_principal_thing():