22import gzip
33import json
44import logging
5- import os
65import threading
76import time
87from datetime import UTC , datetime , timedelta , timezone
2423from localstack .utils .common import retry , short_uid , to_str
2524from localstack .utils .sync import poll_condition , wait_until
2625
26+ from .conftest import is_old_provider
2727from .utils import get_cloudwatch_client
2828
2929if TYPE_CHECKING :
3030 from mypy_boto3_logs import CloudWatchLogsClient
31+
3132PUBLICATION_RETRIES = 5
3233
3334LOG = logging .getLogger (__name__ )
3435
3536
36- def is_old_provider ():
37- return os .environ .get ("PROVIDER_OVERRIDE_CLOUDWATCH" ) == "v1" and not is_aws_cloud ()
38-
39-
4037class TestCloudwatch :
4138 @markers .aws .validated
42- def test_put_metric_data_values_list (self , snapshot , aws_client ):
39+ def test_put_metric_data_values_list (self , snapshot , aws_cloudwatch_client ):
4340 metric_name = "test-metric"
4441 namespace = f"ns-{ short_uid ()} "
45- utc_now = datetime .utcnow (). replace ( tzinfo = UTC )
42+ utc_now = datetime .now ( tz = UTC )
4643 snapshot .add_transformer (
4744 snapshot .transform .key_value ("Timestamp" , reference_replacement = False )
4845 )
4946
50- aws_client . cloudwatch .put_metric_data (
47+ aws_cloudwatch_client .put_metric_data (
5148 Namespace = namespace ,
5249 MetricData = [
5350 {
@@ -60,9 +57,11 @@ def test_put_metric_data_values_list(self, snapshot, aws_client):
6057 ],
6158 )
6259
60+ stats = {}
61+
6362 def get_stats () -> int :
64- global stats
65- stats = aws_client . cloudwatch .get_metric_statistics (
63+ nonlocal stats
64+ stats = aws_cloudwatch_client .get_metric_statistics (
6665 Namespace = namespace ,
6766 MetricName = metric_name ,
6867 StartTime = utc_now - timedelta (seconds = 60 ),
@@ -77,7 +76,7 @@ def get_stats() -> int:
7776 snapshot .match ("get_metric_statistics" , stats )
7877
7978 @markers .aws .only_localstack
80- def test_put_metric_data_gzip (self , aws_client , region_name ):
79+ def test_put_metric_data_gzip_with_query_protocol (self , aws_client , region_name ):
8180 metric_name = "test-metric"
8281 namespace = "namespace"
8382 data = (
@@ -117,13 +116,13 @@ def test_put_metric_data_gzip(self, aws_client, region_name):
117116
118117 @markers .aws .validated
119118 @pytest .mark .skipif (is_old_provider (), reason = "not supported by the old provider" )
120- def test_put_metric_data_validation (self , aws_client ):
119+ def test_put_metric_data_validation (self , aws_cloudwatch_client , snapshot ):
121120 namespace = f"ns-{ short_uid ()} "
122- utc_now = datetime .utcnow (). replace ( tzinfo = UTC )
121+ utc_now = datetime .now ( tz = UTC )
123122
124123 # test invalid due to having both Values and Value
125- with pytest .raises (Exception ) as ex :
126- aws_client . cloudwatch .put_metric_data (
124+ with pytest .raises (ClientError ) as ex :
125+ aws_cloudwatch_client .put_metric_data (
127126 Namespace = namespace ,
128127 MetricData = [
129128 {
@@ -135,16 +134,11 @@ def test_put_metric_data_validation(self, aws_client):
135134 }
136135 ],
137136 )
138- err = ex .value .response ["Error" ]
139- assert err ["Code" ] == "InvalidParameterCombination"
140- assert (
141- err ["Message" ]
142- == "The parameters MetricData.member.1.Value and MetricData.member.1.Values are mutually exclusive and you have specified both."
143- )
137+ snapshot .match ("invalid-param-combination" , ex .value .response )
144138
145139 # test invalid due to data can not have and values mismatched_counts
146- with pytest .raises (Exception ) as ex :
147- aws_client . cloudwatch .put_metric_data (
140+ with pytest .raises (ClientError ) as ex :
141+ aws_cloudwatch_client .put_metric_data (
148142 Namespace = namespace ,
149143 MetricData = [
150144 {
@@ -156,16 +150,11 @@ def test_put_metric_data_validation(self, aws_client):
156150 }
157151 ],
158152 )
159- err = ex .value .response ["Error" ]
160- assert err ["Code" ] == "InvalidParameterValue"
161- assert (
162- err ["Message" ]
163- == "The parameters MetricData.member.1.Values and MetricData.member.1.Counts must be of the same size."
164- )
153+ snapshot .match ("invalid-param-value" , ex .value .response )
165154
166155 # test invalid due to inserting both value and statistic values
167- with pytest .raises (Exception ) as ex :
168- aws_client . cloudwatch .put_metric_data (
156+ with pytest .raises (ClientError ) as ex :
157+ aws_cloudwatch_client .put_metric_data (
169158 Namespace = namespace ,
170159 MetricData = [
171160 {
@@ -182,15 +171,10 @@ def test_put_metric_data_validation(self, aws_client):
182171 }
183172 ],
184173 )
185- err = ex .value .response ["Error" ]
186- assert err ["Code" ] == "InvalidParameterCombination"
187- assert (
188- err ["Message" ]
189- == "The parameters MetricData.member.1.Value and MetricData.member.1.StatisticValues are mutually exclusive and you have specified both."
190- )
174+ snapshot .match ("invalid-param-combination-2" , ex .value .response )
191175
192176 # For some strange reason the AWS implementation allows this
193- aws_client . cloudwatch .put_metric_data (
177+ aws_cloudwatch_client .put_metric_data (
194178 Namespace = namespace ,
195179 MetricData = [
196180 {
@@ -2937,8 +2921,6 @@ def test_invalid_amount_of_datapoints(self, aws_client, snapshot):
29372921
29382922
29392923class TestCloudWatchMultiProtocol :
2940- # TODO: run the whole test suite with all available protocols
2941-
29422924 @pytest .fixture
29432925 def cloudwatch_http_client (self , region_name , aws_http_client_factory ):
29442926 def _create_client (protocol : str ):
@@ -2948,6 +2930,22 @@ def _create_client(protocol: str):
29482930
29492931 return _create_client
29502932
2933+ @markers .aws .validated
2934+ def test_multi_protocol_client_fixture (self , aws_cloudwatch_client ):
2935+ """
2936+ Smoke test to validate that the client is indeed using the right protocol
2937+ """
2938+ response = aws_cloudwatch_client .describe_alarms ()
2939+ response_headers = response ["ResponseMetadata" ]["HTTPHeaders" ]
2940+ content_type = response_headers ["content-type" ]
2941+ if aws_cloudwatch_client .test_client_protocol == "query" :
2942+ assert content_type in ("text/xml" , "application/xml" )
2943+ elif aws_cloudwatch_client .test_client_protocol == "json" :
2944+ assert content_type == "application/x-amz-json-1.0"
2945+ elif aws_cloudwatch_client .test_client_protocol == "smithy-rpc-v2-cbor" :
2946+ assert content_type == "application/cbor"
2947+ assert response_headers ["smithy-protocol" ] == "rpc-v2-cbor"
2948+
29512949 @markers .aws .validated
29522950 @pytest .mark .parametrize ("protocol" , ["json" , "smithy-rpc-v2-cbor" , "query" ])
29532951 @markers .snapshot .skip_snapshot_verify (
0 commit comments