def test_truncate_alert(self): overhead = len(json_for_payload(payload_for_aps({'alert': ''}))) txt = simplestring(10) aps = {'alert': txt} self.assertEquals( txt[:5], truncate(payload_for_aps(aps), overhead + 5)['aps']['alert'])
def test_truncate_string_with_multibyte(self): overhead = len(json_for_payload(payload_for_aps({'alert': ''}))) txt = u"\U0001F430" + simplestring(30) aps = {'alert': txt} # NB. The number of characters of the string we get is dependent # on the json encoding used. self.assertEquals( txt[:17], truncate(payload_for_aps(aps), overhead + 20)['aps']['alert'])
def test_efficient_multibyte(self): txt = u"\U0001F414" aps = {'alert': txt} json_with_multibyte = json_for_payload({'aps': aps}) # Shortest encoding uses literal UTF8, not \u escape sequences, and # doesn't put unneccesary space after commas and colons. shortest_encoding = u"{\"aps\":{\"alert\":\"\U0001F414\"}}".encode( 'utf8') self.assertEquals(shortest_encoding, json_with_multibyte)
def test_truncate_loc_arg(self): overhead = len( json_for_payload(payload_for_aps({'alert': { 'loc-args': [''] }}))) txt = simplestring(10) aps = {'alert': {'loc-args': [txt]}} self.assertEquals( txt[:5], truncate(payload_for_aps(aps), overhead + 5)['aps']['alert']['loc-args'][0])
def test_truncate_multibyte(self): overhead = len(json_for_payload(payload_for_aps({'alert': ''}))) txt = sillystring(30) aps = {'alert': txt} trunc = truncate(payload_for_aps(aps), overhead + 30) # The string is all 4 byte characters so the trunctaed UTF-8 string # should be a multiple of 4 bytes long self.assertEquals(len(trunc['aps']['alert'].encode('utf8')) % 4, 0) # NB. The number of characters of the string we get is dependent # on the json encoding used. self.assertEquals(txt[:7], trunc['aps']['alert'])
def _reallysend(self, payload, token, expiration=None, priority=None, identifier=None): """ Args: payload (dict): The payload dictionary of the push to send descriptor (any): Opaque variable that is passed back to the pushbaby on failure """ if not self.alive: raise ConnectionDeadException() if not self.useable: raise ConnectionDeadException() seq = self._nextSeq() if seq >= PushConnection.MAX_PUSHES_PER_CONNECTION: # IDs are 4 byte so rather than worry about wrapping IDs, just make a new connection # Note we don't close the connection because we want to wait to see if any errors arrive self._retire_connection() payload_str = json_for_payload(truncate(payload)) items = '' items += self._apns_item(PushConnection.ITEM_DEVICE_TOKEN, token) items += self._apns_item(PushConnection.ITEM_PAYLOAD, payload_str) items += self._apns_item(PushConnection.ITEM_IDENTIFIER, seq) if expiration: items += self._apns_item(PushConnection.ITEM_EXPIRATION, expiration) if priority: items += self._apns_item(PushConnection.ITEM_PRIORITY, priority) apnsFrame = struct.pack("!BI", PushConnection.COMMAND_SENDPUSH, len(items)) + items try: written = 0 while written < len(apnsFrame): written += self.sock.send(apnsFrame[written:]) except: logger.exception("Caught exception sending push") raise self.sent[seq] = PushConnection.SentMessage(time.time(), token, payload, expiration, priority, identifier) self.last_push_sent = time.time()