Skip to content

Commit 3ad5130

Browse files
committed
fix: merge APIs should merge reasons
1 parent 01b392b commit 3ad5130

File tree

2 files changed

+140
-5
lines changed

2 files changed

+140
-5
lines changed

src/firebase_functions/private/serving.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ def convert_value(obj):
6565
return without_nones
6666

6767

68+
def merge_required_apis(
69+
required_apis: list[_manifest.ManifestRequiredApi]
70+
) -> list[_manifest.ManifestRequiredApi]:
71+
api_to_reasons: dict[str, list[str]] = {}
72+
for api_reason in required_apis:
73+
api = api_reason["api"]
74+
reason = api_reason["reason"]
75+
if api not in api_to_reasons:
76+
api_to_reasons[api] = []
77+
78+
if reason not in api_to_reasons[api]:
79+
# Append unique reasons only
80+
api_to_reasons[api].append(reason)
81+
82+
merged: list[_manifest.ManifestRequiredApi] = []
83+
for api, reasons in api_to_reasons.items():
84+
merged.append({"api": api, "reason": " ".join(reasons)})
85+
86+
return merged
87+
88+
6889
def functions_as_yaml(functions: dict) -> str:
6990
endpoints: dict[str, _manifest.ManifestEndpoint] = {}
7091
required_apis: list[_manifest.ManifestRequiredApi] = []
@@ -74,10 +95,13 @@ def functions_as_yaml(functions: dict) -> str:
7495
if hasattr(function, "__required_apis"):
7596
for api in function.__required_apis:
7697
required_apis.append(api)
77-
manifest_stack = _manifest.ManifestStack(endpoints=endpoints,
78-
requiredAPIs=required_apis,
79-
params=list(
80-
_params._params.values()))
98+
99+
required_apis = merge_required_apis(required_apis)
100+
manifest_stack = _manifest.ManifestStack(
101+
endpoints=endpoints,
102+
requiredAPIs=required_apis,
103+
params=list(_params._params.values()),
104+
)
81105
manifest_spec = _manifest.manifest_to_spec_dict(manifest_stack)
82106
manifest_spec_with_sentinels = to_spec(manifest_spec)
83107

tests/test_options.py

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"""
1717
from firebase_functions import options, https_fn
1818
from firebase_functions import params
19-
from firebase_functions.private.serving import functions_as_yaml
19+
from firebase_functions.private.serving import functions_as_yaml, merge_required_apis
2020
# pylint: disable=protected-access
2121

2222

@@ -106,3 +106,114 @@ def test_options_preserve_external_changes():
106106
yaml = functions_as_yaml(firebase_functions2)
107107
assert " availableMemoryMb: null\n" not in yaml, "availableMemoryMb found in yaml"
108108
assert " serviceAccountEmail: null\n" not in yaml, "serviceAccountEmail found in yaml"
109+
110+
111+
def test_merge_apis_empty_input():
112+
"""
113+
This test checks the behavior of the merge_required_apis function
114+
when the input is an empty list. The desired outcome for this test
115+
is to receive an empty list as output. This test ensures that the
116+
function can handle the situation where there are no input APIs to merge.
117+
"""
118+
required_apis = []
119+
expected_output = []
120+
merged_apis = merge_required_apis(required_apis)
121+
122+
assert merged_apis == expected_output, f"Expected {expected_output}, but got {merged_apis}"
123+
124+
125+
def test_merge_apis_no_duplicate_apis():
126+
"""
127+
This test verifies that the merge_required_apis function functions
128+
correctly when the input is a list of unique APIs with no duplicates.
129+
The expected result is a list containing the same unique APIs in the
130+
input list. This test confirms that the function processes and returns
131+
APIs without modification when there is no duplication.
132+
"""
133+
required_apis = [
134+
{
135+
"api": "API1",
136+
"reason": "Reason 1"
137+
},
138+
{
139+
"api": "API2",
140+
"reason": "Reason 2"
141+
},
142+
{
143+
"api": "API3",
144+
"reason": "Reason 3"
145+
},
146+
]
147+
148+
expected_output = [
149+
{
150+
"api": "API1",
151+
"reason": "Reason 1"
152+
},
153+
{
154+
"api": "API2",
155+
"reason": "Reason 2"
156+
},
157+
{
158+
"api": "API3",
159+
"reason": "Reason 3"
160+
},
161+
]
162+
163+
merged_apis = merge_required_apis(required_apis)
164+
165+
assert merged_apis == expected_output, f"Expected {expected_output}, but got {merged_apis}"
166+
167+
168+
def test_merge_apis_duplicate_apis():
169+
"""
170+
This test evaluates the merge_required_apis function when the
171+
input list contains duplicate APIs with different reasons.
172+
The desired outcome for this test is a list where the duplicate
173+
APIs are merged properly and reasons are combined.
174+
This test ensures that the function correctly merges the duplicate
175+
APIs and combines the reasons associated with them.
176+
"""
177+
required_apis = [
178+
{
179+
"api": "API1",
180+
"reason": "Reason 1"
181+
},
182+
{
183+
"api": "API2",
184+
"reason": "Reason 2"
185+
},
186+
{
187+
"api": "API1",
188+
"reason": "Reason 3"
189+
},
190+
{
191+
"api": "API2",
192+
"reason": "Reason 4"
193+
},
194+
]
195+
196+
expected_output = [
197+
{
198+
"api": "API1",
199+
"reason": "Reason 1 Reason 3"
200+
},
201+
{
202+
"api": "API2",
203+
"reason": "Reason 2 Reason 4"
204+
},
205+
]
206+
207+
merged_apis = merge_required_apis(required_apis)
208+
209+
assert len(merged_apis) == len(
210+
expected_output
211+
), f"Expected a list of length {len(expected_output)}, but got {len(merged_apis)}"
212+
213+
for expected_item in expected_output:
214+
assert (expected_item in merged_apis
215+
), f"Expected item {expected_item} missing from the merged list"
216+
217+
for actual_item in merged_apis:
218+
assert (actual_item in expected_output
219+
), f"Unexpected item {actual_item} found in the merged list"

0 commit comments

Comments
 (0)