Repository: getmoto/moto
Pull request #8152 (2024-09-24 14:12:03)

[BUG FIX] Firehose - Snowflake destination: Fix `put_record` and `put_record_batch` functions
Hello, based on my last PR (https://github.com/getmoto/moto/pull/8122), I completely forgot to add the modifications for the `put_record_batch` function.

I'm sorry, here is the FIX :) :) 

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/getmoto/moto/pull/8152?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 94.50%. Comparing base [(`6c68326`)](https://app.codecov.io/gh/getmoto/moto/commit/6c68326479024619214119c6d8835153e5f7804a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) to head [(`0769c5c`)](https://app.codecov.io/gh/getmoto/moto/commit/0769c5c0998993d2b8b8518d7d668936d7853c7c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).
> Report is 1 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #8152   +/-   ##
=======================================
  Coverage   94.50%   94.50%           
=======================================
  Files        1150     1150           
  Lines       99203    99203           
=======================================
  Hits        93752    93752           
  Misses       5451     5451           
```

| [Flag](https://app.codecov.io/gh/getmoto/moto/pull/8152/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | Coverage Δ | |
|---|---|---|
| [servertests](https://app.codecov.io/gh/getmoto/moto/pull/8152/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `28.79% <0.00%> (ø)` | |
| [unittests](https://app.codecov.io/gh/getmoto/moto/pull/8152/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `94.47% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/getmoto/moto/pull/8152?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).


Patch:
diff --git a/moto/ec2/models/tags.py b/moto/ec2/models/tags.py
index fdf9a1205..82b70d1e6 100644
--- a/moto/ec2/models/tags.py
+++ b/moto/ec2/models/tags.py
@@ -26,7 +26,14 @@ class TagBackend:
             if resource_id in self.tags:
                 if (
                     len(self.tags[resource_id])
-                    + len([tag for tag in tags if not tag.startswith("aws:")])
+                    + len(
+                        [
+                            tag
+                            for tag in tags
+                            if not tag.startswith("aws:")
+                            and tag not in self.tags[resource_id]
+                        ]
+                    )
                     > 50
                 ):
                     raise TagLimitExceeded()
diff --git a/moto/firehose/models.py b/moto/firehose/models.py
index 45165953b..ffc7ac989 100644
--- a/moto/firehose/models.py
+++ b/moto/firehose/models.py
@@ -517,8 +517,8 @@ class FirehoseBackend(BaseBackend):
                 request_responses = self.put_http_records(
                     destination["HttpEndpoint"], records
                 )
-            elif "Elasticsearch" in destination or "Redshift" in destination:
-                # This isn't implmented as these services aren't implemented,
+            elif {"Elasticsearch", "Redshift", "Snowflake"} & set(destination):
+                # This isn't implemented as these services aren't implemented,
                 # so ignore the data, but return a "proper" response.
                 request_responses = [
                     {"RecordId": str(mock_random.uuid4())} for _ in range(len(records))


Test patch:
diff --git a/tests/test_firehose/test_firehose_put.py b/tests/test_firehose/test_firehose_put.py
index 8d58d6ce5..851bd17ed 100644
--- a/tests/test_firehose/test_firehose_put.py
+++ b/tests/test_firehose/test_firehose_put.py
@@ -149,3 +149,69 @@ def test_put_record_batch_extended_s3_destination():
     assert re.match(
         r"^[0-9]{4}/[0-9]{2}/[0-9]{2}/[0-9]{2}/", bucket_objects["Contents"][0]["Key"]
     )
+
+
+@mock_aws
+def test_put_record_snowflake_destination():
+    """Test invocations of put_record() to a Snowflake destination."""
+    client = boto3.client("firehose", region_name=TEST_REGION)
+
+    stream_name = f"test_put_record_{mock_random.get_random_hex(6)}"
+    client.create_delivery_stream(
+        DeliveryStreamName=stream_name,
+        SnowflakeDestinationConfiguration={
+            "RoleARN": f"arn:aws:iam::{ACCOUNT_ID}:role/firehose_delivery_role",
+            "AccountUrl": f"fake-account.{TEST_REGION}.snowflakecomputing.com",
+            "Database": "myDatabase",
+            "Schema": "mySchema",
+            "Table": "myTable",
+            "S3BackupMode": "FailedDataOnly",
+            "S3Configuration": {
+                "RoleARN": f"arn:aws:iam::{ACCOUNT_ID}:role/firehose_delivery_role",
+                "BucketARN": "arn:aws:s3:::firehose-test",
+            },
+        },
+    )
+    result = client.put_record(
+        DeliveryStreamName=stream_name, Record={"Data": "some test data"}
+    )
+
+    assert set(result.keys()) == {"RecordId", "Encrypted", "ResponseMetadata"}
+    assert result["Encrypted"] is False
+    assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
+
+
+@mock_aws
+def test_put_record_batch_snowflake_destination():
+    """Test invocations of put_record_batch() to a Snowflake destination."""
+    client = boto3.client("firehose", region_name=TEST_REGION)
+
+    stream_name = f"test_put_record_{mock_random.get_random_hex(6)}"
+    client.create_delivery_stream(
+        DeliveryStreamName=stream_name,
+        SnowflakeDestinationConfiguration={
+            "RoleARN": f"arn:aws:iam::{ACCOUNT_ID}:role/firehose_delivery_role",
+            "AccountUrl": f"fake-account.{TEST_REGION}.snowflakecomputing.com",
+            "Database": "myDatabase",
+            "Schema": "mySchema",
+            "Table": "myTable",
+            "S3BackupMode": "FailedDataOnly",
+            "S3Configuration": {
+                "RoleARN": f"arn:aws:iam::{ACCOUNT_ID}:role/firehose_delivery_role",
+                "BucketARN": "arn:aws:s3:::firehose-test",
+            },
+        },
+    )
+
+    records = [{"Data": "one"}, {"Data": "two"}, {"Data": "three"}]
+    result = client.put_record_batch(DeliveryStreamName=stream_name, Records=records)
+
+    assert set(result.keys()) == {
+        "RequestResponses",
+        "FailedPutCount",
+        "ResponseMetadata",
+        "Encrypted",
+    }
+    assert len(result["RequestResponses"]) == 3
+    assert result["Encrypted"] is False
+    assert result["ResponseMetadata"]["HTTPStatusCode"] == 200