@@ -53,8 +53,15 @@ def test_invalid_tokens_type(self, tokens):
5353 expected = 'MulticastMessage.tokens must be a list of strings.'
5454 assert str (excinfo .value ) == expected
5555
56+ def test_tokens_over_one_hundred (self ):
57+ with pytest .raises (ValueError ) as excinfo :
58+ messaging .MulticastMessage (tokens = ['token' for i in xrange (0 , 101 )])
59+ expected = 'MulticastMessage.tokens must not contain more than 100 tokens.'
60+ assert str (excinfo .value ) == expected
61+
5662 def test_tokens_type (self ):
5763 messaging .MulticastMessage (tokens = ['token' ])
64+ messaging .MulticastMessage (tokens = ['token' for i in xrange (0 , 100 )])
5865
5966
6067class TestMessageEncoder (object ):
@@ -1335,12 +1342,7 @@ def test_send_fcm_error_code(self, status):
13351342 assert json .loads (recorder [0 ].body .decode ()) == body
13361343
13371344
1338- class TestSendAll (object ):
1339-
1340- _PAYLOAD_FORMAT = """--boundary\r \n Content-Type: application/http\r \n \
1341- Content-ID: <uuid + 1>\r \n \r \n HTTP/1.1 {} Success\r \n \
1342- Content-Type: application/json; charset=UTF-8\r \n \r \n {}\r \n \r \n --boundary--"""
1343- _CLIENT_VERSION = 'fire-admin-python/{0}' .format (firebase_admin .__version__ )
1345+ class TestBatch (object ):
13441346
13451347 @classmethod
13461348 def setup_class (cls ):
@@ -1364,8 +1366,19 @@ def _instrument_batch_messaging_service(self, app=None, status=200, payload=''):
13641366 ])
13651367 return fcm_service
13661368
1367- def _get_url (self , project_id ):
1368- return messaging ._MessagingService .FCM_URL .format (project_id )
1369+ def _batch_payload (self , payloads ):
1370+ # payloads should be a list of (status_code, content) tuples
1371+ payload = ''
1372+ _playload_format = """--boundary\r \n Content-Type: application/http\r \n \
1373+ Content-ID: <uuid + {}>\r \n \r \n HTTP/1.1 {} Success\r \n \
1374+ Content-Type: application/json; charset=UTF-8\r \n \r \n {}\r \n \r \n """
1375+ for (index , (status_code , content )) in enumerate (payloads ):
1376+ payload += _playload_format .format (str (index + 1 ), str (status_code ), content )
1377+ payload += '--boundary--'
1378+ return payload
1379+
1380+
1381+ class TestSendAll (TestBatch ):
13691382
13701383 def test_no_project_id (self ):
13711384 def evaluate ():
@@ -1385,62 +1398,86 @@ def test_invalid_send_all(self, msg):
13851398 expected = 'Messages must be an list of messaging.Message instances.'
13861399 assert str (excinfo .value ) == expected
13871400
1401+ def test_invalid_over_one_hundred (self ):
1402+ msg = messaging .Message (topic = 'foo' )
1403+ with pytest .raises (ValueError ) as excinfo :
1404+ messaging .send_all ([msg for i in xrange (0 , 101 )])
1405+ expected = 'send_all messages must not contain more than 100 messages.'
1406+ assert str (excinfo .value ) == expected
1407+
13881408 def test_send_all (self ):
13891409 payload = json .dumps ({'name' : 'message-id' })
13901410 _ = self ._instrument_batch_messaging_service (
1391- payload = self ._PAYLOAD_FORMAT . format ( ' 200' , payload ))
1411+ payload = self ._batch_payload ([( 200 , payload ), ( 200 , payload )] ))
13921412 msg = messaging .Message (topic = 'foo' )
1393- batch_response = messaging .send_all ([msg ], dry_run = True )
1394- assert batch_response .success_count is 1
1413+ batch_response = messaging .send_all ([msg , msg ], dry_run = True )
1414+ assert batch_response .success_count is 2
13951415 assert batch_response .failure_count is 0
1396- assert len (batch_response .responses ) == 1
1397- assert [r .message_id for r in batch_response .responses ] == ['message-id' ]
1416+ assert len (batch_response .responses ) == 2
1417+ assert [r .message_id for r in batch_response .responses ] == ['message-id' , 'message-id' ]
13981418 assert all ([r .success for r in batch_response .responses ])
13991419 assert not any ([r .exception for r in batch_response .responses ])
14001420
14011421 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
14021422 def test_send_all_detailed_error (self , status ):
1403- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1423+ success_payload = json .dumps ({'name' : 'message-id' })
1424+ error_payload = json .dumps ({
14041425 'error' : {
14051426 'status' : 'INVALID_ARGUMENT' ,
14061427 'message' : 'test error'
14071428 }
1408- }))
1409- _ = self ._instrument_batch_messaging_service (payload = payload )
1429+ })
1430+ _ = self ._instrument_batch_messaging_service (
1431+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
14101432 msg = messaging .Message (topic = 'foo' )
1411- batch_response = messaging .send_all ([msg ])
1412- assert batch_response .success_count is 0
1433+ batch_response = messaging .send_all ([msg , msg ])
1434+ assert batch_response .success_count is 1
14131435 assert batch_response .failure_count is 1
1414- assert len (batch_response .responses ) == 1
1415- assert not any ([r .message_id for r in batch_response .responses ])
1416- assert not all ([r .success for r in batch_response .responses ])
1417- exception = batch_response .responses [0 ].exception
1436+ assert len (batch_response .responses ) == 2
1437+ success_response = batch_response .responses [0 ]
1438+ assert success_response .message_id == 'message-id'
1439+ assert success_response .success
1440+ assert success_response .exception is None
1441+ error_response = batch_response .responses [1 ]
1442+ assert error_response .message_id is None
1443+ assert not error_response .success
1444+ assert error_response .exception
1445+ exception = error_response .exception
14181446 assert str (exception ) == 'test error'
14191447 assert str (exception .code ) == 'invalid-argument'
14201448
14211449 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
14221450 def test_send_all_canonical_error_code (self , status ):
1423- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1451+ success_payload = json .dumps ({'name' : 'message-id' })
1452+ error_payload = json .dumps ({
14241453 'error' : {
14251454 'status' : 'NOT_FOUND' ,
14261455 'message' : 'test error'
14271456 }
1428- }))
1429- _ = self ._instrument_batch_messaging_service (payload = payload )
1457+ })
1458+ _ = self ._instrument_batch_messaging_service (
1459+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
14301460 msg = messaging .Message (topic = 'foo' )
1431- batch_response = messaging .send_all ([msg ])
1432- assert batch_response .success_count is 0
1461+ batch_response = messaging .send_all ([msg , msg ])
1462+ assert batch_response .success_count is 1
14331463 assert batch_response .failure_count is 1
1434- assert len (batch_response .responses ) == 1
1435- assert not any ([r .message_id for r in batch_response .responses ])
1436- assert not all ([r .success for r in batch_response .responses ])
1437- exception = batch_response .responses [0 ].exception
1464+ assert len (batch_response .responses ) == 2
1465+ success_response = batch_response .responses [0 ]
1466+ assert success_response .message_id == 'message-id'
1467+ assert success_response .success
1468+ assert success_response .exception is None
1469+ error_response = batch_response .responses [1 ]
1470+ assert error_response .message_id is None
1471+ assert not error_response .success
1472+ assert error_response .exception
1473+ exception = error_response .exception
14381474 assert str (exception ) == 'test error'
14391475 assert str (exception .code ) == 'registration-token-not-registered'
14401476
14411477 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
14421478 def test_send_all_fcm_error_code (self , status ):
1443- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1479+ success_payload = json .dumps ({'name' : 'message-id' })
1480+ error_payload = json .dumps ({
14441481 'error' : {
14451482 'status' : 'INVALID_ARGUMENT' ,
14461483 'message' : 'test error' ,
@@ -1451,16 +1488,23 @@ def test_send_all_fcm_error_code(self, status):
14511488 },
14521489 ],
14531490 }
1454- }))
1455- _ = self ._instrument_batch_messaging_service (payload = payload )
1491+ })
1492+ _ = self ._instrument_batch_messaging_service (
1493+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
14561494 msg = messaging .Message (topic = 'foo' )
1457- batch_response = messaging .send_all ([msg ])
1458- assert batch_response .success_count is 0
1495+ batch_response = messaging .send_all ([msg , msg ])
1496+ assert batch_response .success_count is 1
14591497 assert batch_response .failure_count is 1
1460- assert len (batch_response .responses ) == 1
1461- assert not any ([r .message_id for r in batch_response .responses ])
1462- assert not all ([r .success for r in batch_response .responses ])
1463- exception = batch_response .responses [0 ].exception
1498+ assert len (batch_response .responses ) == 2
1499+ success_response = batch_response .responses [0 ]
1500+ assert success_response .message_id == 'message-id'
1501+ assert success_response .success
1502+ assert success_response .exception is None
1503+ error_response = batch_response .responses [1 ]
1504+ assert error_response .message_id is None
1505+ assert not error_response .success
1506+ assert error_response .exception
1507+ exception = error_response .exception
14641508 assert str (exception ) == 'test error'
14651509 assert str (exception .code ) == 'registration-token-not-registered'
14661510
@@ -1526,37 +1570,7 @@ def test_send_all_batch_fcm_error_code(self, status):
15261570 assert str (excinfo .value .code ) == 'registration-token-not-registered'
15271571
15281572
1529- class TestSendMulticast (object ):
1530-
1531- _PAYLOAD_FORMAT = """--boundary\r \n Content-Type: application/http\r \n \
1532- Content-ID: <uuid + 1>\r \n \r \n HTTP/1.1 {} Success\r \n \
1533- Content-Type: application/json; charset=UTF-8\r \n \r \n {}\r \n \r \n --boundary--"""
1534- _CLIENT_VERSION = 'fire-admin-python/{0}' .format (firebase_admin .__version__ )
1535-
1536- @classmethod
1537- def setup_class (cls ):
1538- cred = testutils .MockCredential ()
1539- firebase_admin .initialize_app (cred , {'projectId' : 'explicit-project-id' })
1540-
1541- @classmethod
1542- def teardown_class (cls ):
1543- testutils .cleanup_apps ()
1544-
1545- def _instrument_batch_messaging_service (self , app = None , status = 200 , payload = '' ):
1546- if not app :
1547- app = firebase_admin .get_app ()
1548- fcm_service = messaging ._get_messaging_service (app )
1549- if status == 200 :
1550- content_type = 'multipart/mixed; boundary=boundary'
1551- else :
1552- content_type = 'application/json'
1553- fcm_service ._transport = HttpMockSequence ([
1554- ({'status' : str (status ), 'content-type' : content_type }, payload ),
1555- ])
1556- return fcm_service
1557-
1558- def _get_url (self , project_id ):
1559- return messaging ._MessagingService .FCM_URL .format (project_id )
1573+ class TestSendMulticast (TestBatch ):
15601574
15611575 def test_no_project_id (self ):
15621576 def evaluate ():
@@ -1575,59 +1589,76 @@ def test_invalid_send_multicast(self, msg):
15751589 def test_send_multicast (self ):
15761590 payload = json .dumps ({'name' : 'message-id' })
15771591 _ = self ._instrument_batch_messaging_service (
1578- payload = self ._PAYLOAD_FORMAT . format ( ' 200' , payload ))
1579- msg = messaging .MulticastMessage (tokens = ['foo' ])
1592+ payload = self ._batch_payload ([( 200 , payload ), ( 200 , payload )] ))
1593+ msg = messaging .MulticastMessage (tokens = ['foo' , 'foo' ])
15801594 batch_response = messaging .send_multicast (msg , dry_run = True )
1581- assert batch_response .success_count is 1
1595+ assert batch_response .success_count is 2
15821596 assert batch_response .failure_count is 0
1583- assert len (batch_response .responses ) == 1
1584- assert [r .message_id for r in batch_response .responses ] == ['message-id' ]
1597+ assert len (batch_response .responses ) == 2
1598+ assert [r .message_id for r in batch_response .responses ] == ['message-id' , 'message-id' ]
15851599 assert all ([r .success for r in batch_response .responses ])
15861600 assert not any ([r .exception for r in batch_response .responses ])
15871601
15881602 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
15891603 def test_send_multicast_detailed_error (self , status ):
1590- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1604+ success_payload = json .dumps ({'name' : 'message-id' })
1605+ error_payload = json .dumps ({
15911606 'error' : {
15921607 'status' : 'INVALID_ARGUMENT' ,
15931608 'message' : 'test error'
15941609 }
1595- }))
1596- _ = self ._instrument_batch_messaging_service (payload = payload )
1597- msg = messaging .MulticastMessage (tokens = ['foo' ])
1610+ })
1611+ _ = self ._instrument_batch_messaging_service (
1612+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
1613+ msg = messaging .MulticastMessage (tokens = ['foo' , 'foo' ])
15981614 batch_response = messaging .send_multicast (msg )
1599- assert batch_response .success_count is 0
1615+ assert batch_response .success_count is 1
16001616 assert batch_response .failure_count is 1
1601- assert len (batch_response .responses ) == 1
1602- assert not any ([r .message_id for r in batch_response .responses ])
1603- assert not all ([r .success for r in batch_response .responses ])
1604- exception = batch_response .responses [0 ].exception
1617+ assert len (batch_response .responses ) == 2
1618+ success_response = batch_response .responses [0 ]
1619+ assert success_response .message_id == 'message-id'
1620+ assert success_response .success
1621+ assert success_response .exception is None
1622+ error_response = batch_response .responses [1 ]
1623+ assert error_response .message_id is None
1624+ assert not error_response .success
1625+ assert error_response .exception
1626+ exception = error_response .exception
16051627 assert str (exception ) == 'test error'
16061628 assert str (exception .code ) == 'invalid-argument'
16071629
16081630 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
16091631 def test_send_multicast_canonical_error_code (self , status ):
1610- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1632+ success_payload = json .dumps ({'name' : 'message-id' })
1633+ error_payload = json .dumps ({
16111634 'error' : {
16121635 'status' : 'NOT_FOUND' ,
16131636 'message' : 'test error'
16141637 }
1615- }))
1616- _ = self ._instrument_batch_messaging_service (payload = payload )
1617- msg = messaging .MulticastMessage (tokens = ['foo' ])
1638+ })
1639+ _ = self ._instrument_batch_messaging_service (
1640+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
1641+ msg = messaging .MulticastMessage (tokens = ['foo' , 'foo' ])
16181642 batch_response = messaging .send_multicast (msg )
1619- assert batch_response .success_count is 0
1643+ assert batch_response .success_count is 1
16201644 assert batch_response .failure_count is 1
1621- assert len (batch_response .responses ) == 1
1622- assert not any ([r .message_id for r in batch_response .responses ])
1623- assert not all ([r .success for r in batch_response .responses ])
1624- exception = batch_response .responses [0 ].exception
1645+ assert len (batch_response .responses ) == 2
1646+ success_response = batch_response .responses [0 ]
1647+ assert success_response .message_id == 'message-id'
1648+ assert success_response .success
1649+ assert success_response .exception is None
1650+ error_response = batch_response .responses [1 ]
1651+ assert error_response .message_id is None
1652+ assert not error_response .success
1653+ assert error_response .exception
1654+ exception = error_response .exception
16251655 assert str (exception ) == 'test error'
16261656 assert str (exception .code ) == 'registration-token-not-registered'
16271657
16281658 @pytest .mark .parametrize ('status' , HTTP_ERRORS )
1629- def test_send_multicast_fcm_error_code (self , status ):
1630- payload = self ._PAYLOAD_FORMAT .format (str (status ), json .dumps ({
1659+ def test_send_multicast_canonical_error_code (self , status ):
1660+ success_payload = json .dumps ({'name' : 'message-id' })
1661+ error_payload = json .dumps ({
16311662 'error' : {
16321663 'status' : 'INVALID_ARGUMENT' ,
16331664 'message' : 'test error' ,
@@ -1638,16 +1669,23 @@ def test_send_multicast_fcm_error_code(self, status):
16381669 },
16391670 ],
16401671 }
1641- }))
1642- _ = self ._instrument_batch_messaging_service (payload = payload )
1643- msg = messaging .MulticastMessage (tokens = ['foo' ])
1672+ })
1673+ _ = self ._instrument_batch_messaging_service (
1674+ payload = self ._batch_payload ([(200 , success_payload ), (status , error_payload )]))
1675+ msg = messaging .MulticastMessage (tokens = ['foo' , 'foo' ])
16441676 batch_response = messaging .send_multicast (msg )
1645- assert batch_response .success_count is 0
1677+ assert batch_response .success_count is 1
16461678 assert batch_response .failure_count is 1
1647- assert len (batch_response .responses ) == 1
1648- assert not any ([r .message_id for r in batch_response .responses ])
1649- assert not all ([r .success for r in batch_response .responses ])
1650- exception = batch_response .responses [0 ].exception
1679+ assert len (batch_response .responses ) == 2
1680+ success_response = batch_response .responses [0 ]
1681+ assert success_response .message_id == 'message-id'
1682+ assert success_response .success
1683+ assert success_response .exception is None
1684+ error_response = batch_response .responses [1 ]
1685+ assert error_response .message_id is None
1686+ assert not error_response .success
1687+ assert error_response .exception
1688+ exception = error_response .exception
16511689 assert str (exception ) == 'test error'
16521690 assert str (exception .code ) == 'registration-token-not-registered'
16531691
0 commit comments