@@ -49,3 +49,83 @@ def test_construct_usage_plan_with_invalid_usage_plan_fields(self, AuthPropertie
4949 with self .assertRaises (InvalidResourceException ) as cm :
5050 api_generator ._construct_usage_plan ()
5151 self .assertIn ("Invalid property for" , str (cm .exception ))
52+
53+ def test_add_cors_with_trailing_slash_paths (self ):
54+ """Test that CORS doesn't create duplicate OPTIONS methods for paths with/without trailing slash"""
55+ # Create a simple swagger definition with paths that differ only by trailing slash
56+ definition_body = {
57+ "swagger" : "2.0" ,
58+ "info" : {"title" : "TestAPI" , "version" : "1.0" },
59+ "paths" : {
60+ "/datasets" : {
61+ "post" : {
62+ "x-amazon-apigateway-integration" : {
63+ "type" : "aws_proxy" ,
64+ "httpMethod" : "POST" ,
65+ "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/func/invocations" ,
66+ }
67+ }
68+ },
69+ "/datasets/" : {
70+ "put" : {
71+ "x-amazon-apigateway-integration" : {
72+ "type" : "aws_proxy" ,
73+ "httpMethod" : "POST" ,
74+ "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/func/invocations" ,
75+ }
76+ }
77+ },
78+ },
79+ }
80+
81+ api_generator = ApiGenerator (
82+ logical_id = "TestApi" ,
83+ cache_cluster_enabled = None ,
84+ cache_cluster_size = None ,
85+ variables = None ,
86+ depends_on = None ,
87+ definition_body = definition_body ,
88+ definition_uri = None ,
89+ name = None ,
90+ stage_name = "Prod" ,
91+ shared_api_usage_plan = None , # Added required parameter
92+ template_conditions = None , # Added required parameter
93+ tags = None ,
94+ endpoint_configuration = None ,
95+ method_settings = None ,
96+ binary_media = None ,
97+ minimum_compression_size = None ,
98+ cors = "'*'" , # Enable CORS
99+ auth = None ,
100+ gateway_responses = None ,
101+ access_log_setting = None ,
102+ canary_setting = None ,
103+ tracing_enabled = None ,
104+ resource_attributes = None ,
105+ passthrough_resource_attributes = None ,
106+ open_api_version = None ,
107+ models = None ,
108+ domain = None ,
109+ fail_on_warnings = None ,
110+ description = None ,
111+ mode = None ,
112+ api_key_source_type = None ,
113+ disable_execute_api_endpoint = None ,
114+ )
115+
116+ # Call _add_cors which should normalize paths and avoid duplicates
117+ api_generator ._add_cors ()
118+
119+ # Check that OPTIONS method is not added to both /datasets and /datasets/
120+ # It should only be added once to avoid the duplicate OPTIONS error
121+ paths_with_options = [
122+ path
123+ for path , methods in api_generator .definition_body ["paths" ].items ()
124+ if "options" in methods or "OPTIONS" in methods
125+ ]
126+
127+ # We should have only ONE path with OPTIONS method (the normalized one)
128+ # Both /datasets and /datasets/ normalize to /datasets
129+ self .assertEqual (
130+ len (paths_with_options ), 1 , "CORS should only add OPTIONS to one of the paths that differ by trailing slash"
131+ )
0 commit comments