Skip to content

Commit 73f4b47

Browse files
committed
Fix error messages and MulticastMessage constructor and add mix types of fids and tokens
1 parent 1831f6a commit 73f4b47

3 files changed

Lines changed: 69 additions & 38 deletions

File tree

firebase_admin/_messaging_encoder.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def __init__(self, data=None, notification=None, android=None, webpush=None, apn
5050
fcm_options=None, token=None, topic=None, condition=None, fid=None):
5151
if token is not None:
5252
warnings.warn(
53-
"Message.token is deprecated. Use fid instead.",
53+
"Message.token is deprecated. Use Message.fid instead.",
5454
DeprecationWarning,
5555
stacklevel=2
5656
)
@@ -73,7 +73,6 @@ class MulticastMessage:
7373
"""A message that can be sent to multiple tokens or fids via Firebase Cloud Messaging.
7474
7575
Args:
76-
fids: A list of Firebase Installation IDs of targeted app instances (optional).
7776
tokens: Deprecated. Use ``fids`` instead (optional).
7877
data: A dictionary of data fields (optional). All keys and values in the dictionary must be
7978
strings.
@@ -82,33 +81,35 @@ class MulticastMessage:
8281
webpush: An instance of ``messaging.WebpushConfig`` (optional).
8382
apns: An instance of ``messaging.ApnsConfig`` (optional).
8483
fcm_options: An instance of ``messaging.FCMOptions`` (optional).
84+
fids: A list of Firebase Installation IDs of targeted app instances (optional).
8585
"""
8686
def __init__(
87-
self, tokens=None, fids=None, data=None, notification=None, android=None,
88-
webpush=None, apns=None, fcm_options=None):
87+
self, tokens=None, data=None, notification=None, android=None,
88+
webpush=None, apns=None, fcm_options=None, fids=None):
8989
if tokens is not None:
9090
warnings.warn(
91-
"MulticastMessage.tokens is deprecated. Use fids instead.",
91+
"MulticastMessage.tokens is deprecated. Use MulticastMessage.fids instead.",
9292
DeprecationWarning,
9393
stacklevel=2
9494
)
9595

96-
if (tokens is None and fids is None) or (tokens is not None and fids is not None):
97-
raise ValueError("Must specify either 'tokens' or 'fids'.")
96+
if tokens is None and fids is None:
97+
raise ValueError(
98+
"Must specify at least one of MulticastMessage.tokens or MulticastMessage.fids.")
9899

99100
if tokens is not None:
100101
_Validators.check_string_list('MulticastMessage.tokens', tokens)
101-
if len(tokens) > 500:
102-
raise ValueError('MulticastMessage.tokens must not contain more than 500 tokens.')
103-
self.tokens = tokens
104-
self.fids = None
105-
else:
102+
if fids is not None:
106103
_Validators.check_string_list('MulticastMessage.fids', fids)
107-
if len(fids) > 500:
108-
raise ValueError('MulticastMessage.fids must not contain more than 500 fids.')
109-
self.fids = fids
110-
self.tokens = None
111104

105+
tokens_len = len(tokens) if tokens is not None else 0
106+
fids_len = len(fids) if fids is not None else 0
107+
if tokens_len + fids_len > 500:
108+
raise ValueError(
109+
'Total number of tokens and fids must not exceed 500.')
110+
111+
self.tokens = tokens
112+
self.fids = fids
112113
self.data = data
113114
self.notification = notification
114115
self.android = android

firebase_admin/messaging.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -177,28 +177,33 @@ def _get_messages_from_multicast(multicast_message: MulticastMessage) -> List[Me
177177
"""Extracts individual Message objects from a MulticastMessage."""
178178
if not isinstance(multicast_message, MulticastMessage):
179179
raise ValueError('Message must be an instance of messaging.MulticastMessage class.')
180+
181+
messages = []
180182
if multicast_message.tokens is not None:
181183
with warnings.catch_warnings():
182184
warnings.simplefilter("ignore", DeprecationWarning)
183-
return [Message(
185+
messages.extend([Message(
184186
data=multicast_message.data,
185187
notification=multicast_message.notification,
186188
android=multicast_message.android,
187189
webpush=multicast_message.webpush,
188190
apns=multicast_message.apns,
189191
fcm_options=multicast_message.fcm_options,
190192
token=token
191-
) for token in multicast_message.tokens]
192-
193-
return [Message(
194-
data=multicast_message.data,
195-
notification=multicast_message.notification,
196-
android=multicast_message.android,
197-
webpush=multicast_message.webpush,
198-
apns=multicast_message.apns,
199-
fcm_options=multicast_message.fcm_options,
200-
fid=fid
201-
) for fid in multicast_message.fids]
193+
) for token in multicast_message.tokens])
194+
195+
if multicast_message.fids is not None:
196+
messages.extend([Message(
197+
data=multicast_message.data,
198+
notification=multicast_message.notification,
199+
android=multicast_message.android,
200+
webpush=multicast_message.webpush,
201+
apns=multicast_message.apns,
202+
fcm_options=multicast_message.fcm_options,
203+
fid=fid
204+
) for fid in multicast_message.fids])
205+
206+
return messages
202207

203208
async def send_each_for_multicast_async(
204209
multicast_message: MulticastMessage,

tests/test_messaging.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,8 @@ class TestMulticastMessage:
102102
def test_invalid_targets(self):
103103
with pytest.raises(ValueError) as excinfo:
104104
messaging.MulticastMessage()
105-
assert str(excinfo.value) == "Must specify either 'tokens' or 'fids'."
106-
107-
with pytest.raises(ValueError) as excinfo:
108-
messaging.MulticastMessage(tokens=['token'], fids=['fid'])
109-
assert str(excinfo.value) == "Must specify either 'tokens' or 'fids'."
105+
expected = "Must specify at least one of MulticastMessage.tokens or MulticastMessage.fids."
106+
assert str(excinfo.value) == expected
110107

111108
@pytest.mark.parametrize('tokens', NON_LIST_ARGS)
112109
def test_invalid_tokens_type(self, tokens):
@@ -122,7 +119,7 @@ def test_invalid_tokens_type(self, tokens):
122119
def test_tokens_over_500(self):
123120
with pytest.raises(ValueError) as excinfo:
124121
messaging.MulticastMessage(tokens=['token' for _ in range(0, 501)])
125-
expected = 'MulticastMessage.tokens must not contain more than 500 tokens.'
122+
expected = 'Total number of tokens and fids must not exceed 500.'
126123
assert str(excinfo.value) == expected
127124

128125
def test_tokens_type(self):
@@ -146,7 +143,7 @@ def test_invalid_fids_type(self, fids):
146143
def test_fids_over_500(self):
147144
with pytest.raises(ValueError) as excinfo:
148145
messaging.MulticastMessage(fids=['fid' for _ in range(0, 501)])
149-
expected = 'MulticastMessage.fids must not contain more than 500 fids.'
146+
expected = 'Total number of tokens and fids must not exceed 500.'
150147
assert str(excinfo.value) == expected
151148

152149
def test_fids_type(self):
@@ -156,13 +153,27 @@ def test_fids_type(self):
156153
message = messaging.MulticastMessage(fids=['fid' for _ in range(0, 500)])
157154
assert len(message.fids) == 500
158155

156+
def test_combined_over_500(self):
157+
with pytest.raises(ValueError) as excinfo:
158+
messaging.MulticastMessage(
159+
tokens=['token' for _ in range(0, 250)],
160+
fids=['fid' for _ in range(0, 251)]
161+
)
162+
expected = 'Total number of tokens and fids must not exceed 500.'
163+
assert str(excinfo.value) == expected
164+
165+
def test_mixed_targets(self):
166+
message = messaging.MulticastMessage(tokens=['token'], fids=['fid'])
167+
assert len(message.tokens) == 1
168+
assert len(message.fids) == 1
169+
159170
def test_tokens_deprecation_warning(self):
160-
msg = 'MulticastMessage.tokens is deprecated. Use fids instead.'
171+
msg = 'MulticastMessage.tokens is deprecated. Use MulticastMessage.fids instead.'
161172
with pytest.warns(DeprecationWarning, match=msg):
162173
messaging.MulticastMessage(tokens=['token'])
163174

164175
def test_tokens_deprecation_warning_positional(self):
165-
msg = 'MulticastMessage.tokens is deprecated. Use fids instead.'
176+
msg = 'MulticastMessage.tokens is deprecated. Use MulticastMessage.fids instead.'
166177
with pytest.warns(DeprecationWarning, match=msg):
167178
messaging.MulticastMessage(['token'])
168179

@@ -222,7 +233,7 @@ def test_empty_message(self):
222233
check_encoding(messaging.Message(condition='value'), {'condition': 'value'})
223234

224235
def test_token_deprecation_warning(self):
225-
msg = 'Message.token is deprecated. Use fid instead.'
236+
msg = 'Message.token is deprecated. Use Message.fid instead.'
226237
with pytest.warns(DeprecationWarning, match=msg):
227238
messaging.Message(token='value')
228239

@@ -2290,6 +2301,20 @@ def test_send_each_for_multicast_fids(self):
22902301
assert all(r.success for r in batch_response.responses)
22912302
assert not any(r.exception for r in batch_response.responses)
22922303

2304+
def test_send_each_for_multicast_mixed(self):
2305+
payload1 = json.dumps({'name': 'message-id1'})
2306+
payload2 = json.dumps({'name': 'message-id2'})
2307+
_ = self._instrument_messaging_service(
2308+
response_dict={'foo1': [200, payload1], 'foo2': [200, payload2]})
2309+
msg = messaging.MulticastMessage(tokens=['foo1'], fids=['foo2'])
2310+
batch_response = messaging.send_each_for_multicast(msg, dry_run=True)
2311+
assert batch_response.success_count == 2
2312+
assert batch_response.failure_count == 0
2313+
assert len(batch_response.responses) == 2
2314+
assert [r.message_id for r in batch_response.responses] == ['message-id1', 'message-id2']
2315+
assert all(r.success for r in batch_response.responses)
2316+
assert not any(r.exception for r in batch_response.responses)
2317+
22932318
@respx.mock
22942319
@pytest.mark.asyncio
22952320
async def test_send_each_for_multicast_async(self):

0 commit comments

Comments
 (0)