Repository: localstack/localstack

Issue:
Kinesis Error Probability - wrong HTTP Status code returned
When trying to setup our localstack to include the error probability to test our setup, we encountered an issue with it.
Regarding the documentation, on an error like ProvisionedThroughputExceededException it should return a 400 http status code, but instead we get a 200.
Due to this, our retries option set in the client does not work as expected and we can not test some scenarios.


Discussion:
@applike-ss Super late response to this so not sure if relevant, but I actually just ran into this issue as well, and to get around that, I manually modified the file and mounted it to my docker container but putting in the volumes section.

- "$PWD/kinesis_listener.py:/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py"

But I do wish it returned 400 by default and not a 200 ok.

Resolving patch:
diff --git a/localstack/services/kinesis/kinesis_listener.py b/localstack/services/kinesis/kinesis_listener.py
--- a/localstack/services/kinesis/kinesis_listener.py
+++ b/localstack/services/kinesis/kinesis_listener.py
@@ -22,8 +22,9 @@ def forward_request(self, method, path, data, headers):
         data = json.loads(to_str(data))
 
         if random.random() < config.KINESIS_ERROR_PROBABILITY:
-            if headers.get('X-Amz-Target') in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:
-                return kinesis_error_response(data)
+            action = headers.get('X-Amz-Target')
+            if action in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:
+                return kinesis_error_response(data, action)
         return True
 
     def return_response(self, method, path, data, headers, response):
@@ -33,8 +34,9 @@ def return_response(self, method, path, data, headers, response):
         records = []
         if action in (ACTION_CREATE_STREAM, ACTION_DELETE_STREAM):
             event_type = (event_publisher.EVENT_KINESIS_CREATE_STREAM if action == ACTION_CREATE_STREAM
-                else event_publisher.EVENT_KINESIS_DELETE_STREAM)
-            event_publisher.fire_event(event_type, payload={'n': event_publisher.get_hash(data.get('StreamName'))})
+                          else event_publisher.EVENT_KINESIS_DELETE_STREAM)
+            event_publisher.fire_event(
+                event_type, payload={'n': event_publisher.get_hash(data.get('StreamName'))})
         elif action == ACTION_PUT_RECORD:
             response_body = json.loads(to_str(response.content))
             event_record = {
@@ -87,14 +89,23 @@ def return_response(self, method, path, data, headers, response):
 UPDATE_KINESIS = ProxyListenerKinesis()
 
 
-def kinesis_error_response(data):
+def kinesis_error_response(data, action):
     error_response = Response()
-    error_response.status_code = 200
-    content = {'FailedRecordCount': 1, 'Records': []}
-    for record in data.get('Records', []):
-        content['Records'].append({
+
+    if action == ACTION_PUT_RECORD:
+        error_response.status_code = 400
+        content = {
             'ErrorCode': 'ProvisionedThroughputExceededException',
             'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'
-        })
+        }
+    else:
+        error_response.status_code = 200
+        content = {'FailedRecordCount': 1, 'Records': []}
+        for record in data.get('Records', []):
+            content['Records'].append({
+                'ErrorCode': 'ProvisionedThroughputExceededException',
+                'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'
+            })
+
     error_response._content = json.dumps(content)
     return error_response


Test patch: