Repository: localstack/localstack

Issue:
bug: DynamoDB - PutItem default response is not the same as AWS
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

PutItem on dynamodb returns ConsumedCapacity Information.
```json
{
  "ConsumedCapacity": {
    "TableName": "put-item-response",
    "CapacityUnits": 1.0
  }
}
```

### Expected Behavior

The response should be an empty map.

### How are you starting LocalStack?

With a `docker run` command

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)
I have tested this against the following images:
```bash
# docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:latest
LocalStack version: 0.13.0.4
LocalStack build date: 2021-11-24
LocalStack build git hash: f1dfb02b
```

```bash
# docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:0.14.5
LocalStack version: 0.14.5
LocalStack build date: 2022-07-08
LocalStack build git hash: db54501d
```

#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)
```bash
# Create table to repro the issue
awslocal dynamodb create-table \
  --table-name "put-item-response" \
  --billing-mode "PAY_PER_REQUEST" \
  --attribute-definitions \
    AttributeName=pkey,AttributeType=S \
  --key-schema \
    AttributeName=pkey,KeyType=HASH \
  --region eu-west-1

# This is the main issue, note the response on this command.
awslocal dynamodb put-item \
  --table-name "put-item-response" \
  --item '{"pkey":{"S":"test"}}'

# Cleanup resources
awslocal dynamodb delete-table \
  --table-name "put-item-response"
```

### Environment

```markdown
- OS: MacOS Monterey, ARM
- LocalStack: latest,0.15.4
```


### Anything else?

_No response_


Discussion:
Welcome to LocalStack! Thanks for reporting your first issue and our team will be working towards fixing the issue for you or reach out for more background information. We recommend joining our [Slack Community](https://localstack.cloud/contact/) for real-time help and drop a message to LocalStack Pro Support if you are a Pro user! If you are willing to contribute towards fixing this issue, please have a look at our [contributing guidelines](https://github.com/localstack/.github/blob/main/CONTRIBUTING.md) and our [developer guide](https://docs.localstack.cloud/developer-guide/).

Resolving patch:
diff --git a/localstack/services/dynamodb/provider.py b/localstack/services/dynamodb/provider.py
--- a/localstack/services/dynamodb/provider.py
+++ b/localstack/services/dynamodb/provider.py
@@ -536,7 +536,6 @@ def put_item(self, context: RequestContext, put_item_input: PutItemInput) -> Put
             existing_item = ItemFinder.find_existing_item(put_item_input)
 
         # forward request to backend
-        self.fix_return_consumed_capacity(put_item_input)
         result = self.forward_request(context, put_item_input)
 
         # Get stream specifications details for the table
@@ -574,7 +573,6 @@ def delete_item(
             existing_item = ItemFinder.find_existing_item(delete_item_input)
 
         # forward request to backend
-        self.fix_return_consumed_capacity(delete_item_input)
         result = self.forward_request(context, delete_item_input)
 
         # determine and forward stream record
@@ -612,7 +610,6 @@ def update_item(
             existing_item = ItemFinder.find_existing_item(update_item_input)
 
         # forward request to backend
-        self.fix_return_consumed_capacity(update_item_input)
         result = self.forward_request(context, update_item_input)
 
         # construct and forward stream record
@@ -1039,15 +1036,6 @@ def _replace(regex, replace):
             rf"Credential=\1/{aws_stack.get_local_region()}/",
         )
 
-    def fix_return_consumed_capacity(self, request_dict):
-        # Fix incorrect values if ReturnValues==ALL_OLD and ReturnConsumedCapacity is
-        # empty, see https://github.com/localstack/localstack/issues/2049
-        return_values_all = (request_dict.get("ReturnValues") == "ALL_OLD") or (
-            not request_dict.get("ReturnValues")
-        )
-        if return_values_all and not request_dict.get("ReturnConsumedCapacity"):
-            request_dict["ReturnConsumedCapacity"] = "TOTAL"
-
     def fix_consumed_capacity(self, request: Dict, result: Dict):
         # make sure we append 'ConsumedCapacity', which is properly
         # returned by dynalite, but not by AWS's DynamoDBLocal


Test patch:
diff --git a/tests/integration/test_dynamodb.py b/tests/integration/test_dynamodb.py
--- a/tests/integration/test_dynamodb.py
+++ b/tests/integration/test_dynamodb.py
@@ -421,35 +421,60 @@ def test_more_than_20_global_secondary_indexes(self, dynamodb, dynamodb_client):
         # clean up
         delete_table(table_name)
 
-    def test_return_values_in_put_item(self, dynamodb):
-        aws_stack.create_dynamodb_table(TEST_DDB_TABLE_NAME, partition_key=PARTITION_KEY)
+    @pytest.mark.aws_validated
+    def test_return_values_in_put_item(self, dynamodb, dynamodb_client):
+        aws_stack.create_dynamodb_table(
+            TEST_DDB_TABLE_NAME, partition_key=PARTITION_KEY, client=dynamodb_client
+        )
         table = dynamodb.Table(TEST_DDB_TABLE_NAME)
 
+        def _validate_response(response, expected: dict = {}):
+            """
+            Validates the response against the optionally expected one.
+            It checks that the response doesn't contain `Attributes`,
+            `ConsumedCapacity` and `ItemCollectionMetrics` unless they are expected.
+            """
+            should_not_contain = {
+                "Attributes",
+                "ConsumedCapacity",
+                "ItemCollectionMetrics",
+            } - expected.keys()
+            assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
+            assert expected.items() <= response.items()
+            assert response.keys().isdisjoint(should_not_contain)
+
         # items which are being used to put in the table
         item1 = {PARTITION_KEY: "id1", "data": "foobar"}
+        item1b = {PARTITION_KEY: "id1", "data": "barfoo"}
         item2 = {PARTITION_KEY: "id2", "data": "foobar"}
 
         response = table.put_item(Item=item1, ReturnValues="ALL_OLD")
         # there is no data present in the table already so even if return values
         # is set to 'ALL_OLD' as there is no data it will not return any data.
-        assert not response.get("Attributes")
+        _validate_response(response)
         # now the same data is present so when we pass return values as 'ALL_OLD'
         # it should give us attributes
         response = table.put_item(Item=item1, ReturnValues="ALL_OLD")
-        assert response.get("Attributes")
-        assert item1.get("id") == response.get("Attributes").get("id")
-        assert item1.get("data") == response.get("Attributes").get("data")
+        _validate_response(response, expected={"Attributes": item1})
+
+        # now a previous version of data is present, so when we pass return
+        # values as 'ALL_OLD' it should give us the old attributes
+        response = table.put_item(Item=item1b, ReturnValues="ALL_OLD")
+        _validate_response(response, expected={"Attributes": item1})
 
         response = table.put_item(Item=item2)
         # we do not have any same item as item2 already so when we add this by default
         # return values is set to None so no Attribute values should be returned
-        assert not response.get("Attributes")
+        _validate_response(response)
 
         response = table.put_item(Item=item2)
         # in this case we already have item2 in the table so on this request
         # it should not return any data as return values is set to None so no
         # Attribute values should be returned
-        assert not response.get("Attributes")
+        _validate_response(response)
+
+        # cleanup
+        table.delete()
 
     @pytest.mark.aws_validated
     def test_empty_and_binary_values(self, dynamodb, dynamodb_client):