Skip to content

Commit 9ff16bd

Browse files
authored
fix(fcm): A workaround for the concurrency issues in googleapiclient (firebase#558)
* fix(fcm): FA workaround for the concurrency issues in googleapiclient * fix: Added test case
1 parent 172f200 commit 9ff16bd

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

firebase_admin/messaging.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,9 @@ def __init__(self, app):
330330
'X-FIREBASE-CLIENT': 'fire-admin-python/{0}'.format(firebase_admin.__version__),
331331
}
332332
timeout = app.options.get('httpTimeout', _http_client.DEFAULT_TIMEOUT_SECONDS)
333-
self._client = _http_client.JsonHttpClient(
334-
credential=app.credential.get_credential(), timeout=timeout)
335-
self._transport = _auth.authorized_http(app.credential.get_credential())
333+
self._credential = app.credential.get_credential()
334+
self._client = _http_client.JsonHttpClient(credential=self._credential, timeout=timeout)
335+
self._build_transport = _auth.authorized_http
336336

337337
@classmethod
338338
def encode_message(cls, message):
@@ -373,10 +373,11 @@ def batch_callback(_, response, error):
373373

374374
batch = http.BatchHttpRequest(
375375
callback=batch_callback, batch_uri=_MessagingService.FCM_BATCH_URL)
376+
transport = self._build_transport(self._credential)
376377
for message in messages:
377378
body = json.dumps(self._message_data(message, dry_run))
378379
req = http.HttpRequest(
379-
http=self._transport,
380+
http=transport,
380381
postproc=self._postproc,
381382
uri=self._fcm_url,
382383
method='POST',

tests/test_messaging.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,20 +1813,23 @@ def teardown_class(cls):
18131813
testutils.cleanup_apps()
18141814

18151815
def _instrument_batch_messaging_service(self, app=None, status=200, payload='', exc=None):
1816-
if not app:
1817-
app = firebase_admin.get_app()
1816+
def build_mock_transport(_):
1817+
if exc:
1818+
return _HttpMockException(exc)
18181819

1819-
fcm_service = messaging._get_messaging_service(app)
1820-
if exc:
1821-
fcm_service._transport = _HttpMockException(exc)
1822-
else:
18231820
if status == 200:
18241821
content_type = 'multipart/mixed; boundary=boundary'
18251822
else:
18261823
content_type = 'application/json'
1827-
fcm_service._transport = http.HttpMockSequence([
1824+
return http.HttpMockSequence([
18281825
({'status': str(status), 'content-type': content_type}, payload),
18291826
])
1827+
1828+
if not app:
1829+
app = firebase_admin.get_app()
1830+
1831+
fcm_service = messaging._get_messaging_service(app)
1832+
fcm_service._build_transport = build_mock_transport
18301833
return fcm_service
18311834

18321835
def _batch_payload(self, payloads):
@@ -2053,6 +2056,29 @@ def test_send_all_runtime_exception(self):
20532056
assert excinfo.value.cause is exc
20542057
assert excinfo.value.http_response is None
20552058

2059+
def test_send_transport_init(self):
2060+
def track_call_count(build_transport):
2061+
def wrapper(credential):
2062+
wrapper.calls += 1
2063+
return build_transport(credential)
2064+
wrapper.calls = 0
2065+
return wrapper
2066+
2067+
payload = json.dumps({'name': 'message-id'})
2068+
fcm_service = self._instrument_batch_messaging_service(
2069+
payload=self._batch_payload([(200, payload), (200, payload)]))
2070+
build_mock_transport = fcm_service._build_transport
2071+
fcm_service._build_transport = track_call_count(build_mock_transport)
2072+
msg = messaging.Message(topic='foo')
2073+
2074+
batch_response = messaging.send_all([msg, msg], dry_run=True)
2075+
assert batch_response.success_count == 2
2076+
assert fcm_service._build_transport.calls == 1
2077+
2078+
batch_response = messaging.send_all([msg, msg], dry_run=True)
2079+
assert batch_response.success_count == 2
2080+
assert fcm_service._build_transport.calls == 2
2081+
20562082

20572083
class TestSendMulticast(TestBatch):
20582084

0 commit comments

Comments
 (0)