def test_multiple_message(self):
        """ Receive two messages in one data buffer """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9])

        self.assertFalse(parser.is_parsing)
        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=5',
                                       '35=A',
                                       '10=178',
                                       '8=FIX.4.2',
                                       '9=17',
                                       '35=E',
                                       '99=forsooth',
                                       '10=013'))
        self.assertFalse(parser.is_parsing)
        self.assertEquals(2, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(5, len(message))
        self.assertTrue(message.verify(fields=[(8, 'FIX.4.2'),
                                               (9, '17'),
                                               (35, 'E'),
                                               (99, 'forsooth'),
                                               (10, '013')]))
    def test_bad_binary_fields(self):
        """ Test bad binary fields """
        parser = FIXParser(self.receiver,
                           binary_fields=[1000],
                           header_fields=[8, 9])

        # Missing binary value portion of binary field
        # BUGBUG: This can cause some problems, because the parser
        # does not attempt to validate until the entire
        # field has been read in.  Which this will fail because
        # the length goes past the end of the message.
        # For now, live with this.
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '1000=5',
                                           '999=11',
                                           '10=001'))

        # Missing binary length portion (the only time this
        # really impacts something is if the field has an
        # embedded \x01).
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '1001=1010\x011010',
                                           '10=001'))

        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=14',
                                       '1001=10101010',
                                       '10=127'))
        self.assertIsNone(self.receiver.last_error)
        self.assertEquals(1, self.receiver.count)
        self.assertIsNotNone(self.receiver.last_received_message)
    def test_simple_group_fields(self):
        """ Simple group field testing. """
        parser = FIXParser(self.receiver,
                           group_fields={100: [101, 102, 200],
                                         200: [201, 202], },
                           header_fields=[8, 9])

        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=18',
                                       '100=1',
                                       '101=a',
                                       '102=b',
                                       '10=099'))
        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(4, len(message))

        self.assertTrue(100 in message)
        self.assertEquals(1, len(message[100]))

        group = message[100]
        self.assertIsNotNone(group)
        self.assertEquals(1, len(group))
        self.assertEquals(2, len(group[0]))
        self.assertTrue(101 in group[0])
        self.assertTrue(102 in group[0])
        self.assertEquals('a', group[0][101])
        self.assertEquals('b', group[0][102])
    def test_message_bad_binary_length(self):
        """ Test for message with missing binary data """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9],
                           binary_fields=[1000],
                           max_length=100)

        # length too short
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '42=A',
                                           '1000=2',
                                           '1001=abababababab',
                                           '10=000'))

        # length too long
        # This will not raise an error
        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=32',
                                       '42=A',
                                       '1000=20',
                                       '1001=ab',
                                       '10=000'))
        self.assertEquals(0, self.receiver.count)
        self.assertTrue(parser.is_parsing)
    def test_parse_field(self):
        """ Basic _parse_field function test """
        parser = FIXParser(self.receiver)

        field = parser._parse_field('8=a')
        self.assertEquals(8, field[0])
        self.assertEquals('a', field[1])
    def test_message_too_large(self):
        """ Test for too long message """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9],
                           max_length=100)

        with self.assertRaises(FIXLengthTooLongError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '42=A' + 'BB'*100))
Exemple #7
0
    def __init__(self, name, transport, **kwargs):
        """ FIXProtocol initialization

            Args:
                name: A descriptive name given to this connection.
                transport: The transport used to interface with the
                    networking layer.
                config: A dict() for the endpoint configuration.
                    See the ROLES section in sample_config.py for examples.
                link_config: A dict for the link configuration.
                    See the CONNECTIONS section in sample_config.py for
                    examples and documentation.
                debug: Set this to True for debug logging.  (Default: False)

            Raises:
                ValueError: name and queue are required parameters.
        """
        if name is None:
            raise ValueError("name is None")
        if transport is None:
            raise ValueError("name is None")

        self.name = name
        self.transport = transport
        self.config = kwargs.get('config', dict())
        self.link_config = kwargs.get('link_config', dict())
        self._debug = kwargs.get('debug')

        if len(self.link_config.get('protocol_version', '')) == 0:
            raise ValueError('link_config missing protocol_version')

        # heartbeat processing
        self.heartbeat = self.link_config.get('heartbeat', 0)
        self.filter_heartbeat = False
        self._testrequest_id = None
        self._testrequest_time = None

        # protocol state information
        self._send_seqno = self.link_config.get('send_seqno', 0)
        self._last_send_time = datetime.datetime.now()
        self._received_seqno = 0
        self._last_received_time = datetime.datetime.now()

        self._parser = FIXParser(self,
                                 header_fields=self.link_config.get(
                                     'header_fields', None),
                                 binary_fields=self.link_config.get(
                                     'binary_fields', None),
                                 group_fields=self.link_config.get(
                                     'group_fields', None),
                                 max_length=self.link_config.get(
                                     'max_length', 2048))

        self._logger = logging.getLogger(__name__)
    def test_partial_message(self):
        """ Test for partial input. """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9])

        self.assertFalse(parser.is_parsing)
        self.assertEquals(0, self.receiver.count)
        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=32',
                                       '35=A'))
        self.assertEquals(0, self.receiver.count)
        self.assertTrue(parser.is_parsing)
    def test_parser_reset(self):
        """ Test that the parser resets on an error """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9])

        # Tag ID is not a number
        self.assertFalse(parser.is_parsing)
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           'abcd=A'))
        self.assertFalse(parser.is_parsing)
    def test_message_binary_too_long(self):
        """ Test for message with missing binary data """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9],
                           binary_fields=[1000],
                           max_length=100)

        # length too short
        with self.assertRaises(FIXLengthTooLongError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '42=A',
                                           '1000=128',
                                           '1001=abababababab',
                                           '10=000'))
    def test_nested_groups(self):
        """ Test the receiving of nested groups """
        parser = FIXParser(self.receiver,
                           debug=True,
                           group_fields={100: [101, 102, 200],
                                         200: [201, 202], },
                           header_fields=[8, 9])

        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=40',
                                       '100=1',
                                       '101=a',
                                       '102=b',
                                       '200=1',
                                       '201=abc',
                                       '202=def',
                                       '10=087'))
        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(4, len(message))

        self.assertTrue(100 in message)
        self.assertEquals(1, len(message[100]))

        group = message[100]
        self.assertIsNotNone(group)
        self.assertEquals(1, len(group))
        self.assertEquals(3, len(group[0]))
        self.assertTrue(101 in group[0])
        self.assertTrue(102 in group[0])
        self.assertTrue(200 in group[0])
        self.assertEquals('a', group[0][101])
        self.assertEquals('b', group[0][102])

        subgroup = group[0]
        self.assertIsNotNone(subgroup)
        self.assertEquals(3, len(subgroup))
        self.assertEquals(1, len(subgroup[200]))
        subgroup200 = subgroup[200]
        self.assertEquals(2, len(subgroup200[0]))
        self.assertTrue(201 in subgroup200[0])
        self.assertTrue(202 in subgroup200[0])
        self.assertEquals('abc', subgroup200[0][201])
        self.assertEquals('def', subgroup200[0][202])
    def test_parse_field_bad_input(self):
        """ Test bad _parse_field inputs """
        parser = FIXParser(self.receiver)

        # missing '='
        with self.assertRaises(FIXParserError):
            parser._parse_field('abcde')

        # bad tag id
        with self.assertRaises(FIXParserError):
            parser._parse_field('a=a')

        # missing tag id
        with self.assertRaises(FIXParserError):
            parser._parse_field('=a')

        # bad tag id
        with self.assertRaises(FIXParserError):
            parser._parse_field('10b=a')
    def test_grouped_binary_fields(self):
        """ Test binary fields that are in a group. """
        parser = FIXParser(self.receiver,
                           debug=True,
                           group_fields={200: [201, 202, 99, 100]},
                           binary_fields=[99],
                           header_fields=[8, 9])

        text = to_fix('8=FIX.4.2',
                      '9=80',
                      '35=A',
                      '200=2',
                      '201=aabc',
                      '99=5',
                      '100=abcde',
                      '201=zzzaa',
                      '202=myname',
                      '99=5',
                      '100=zztop',
                      '955=that',
                      '10=201')
        parser.on_data_received(text)
        self.assertFalse(parser.is_parsing)

        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(6, len(message))
        self.assertEquals(2, len(message[200]))
        self.assertTrue(200 in message)
        self.assertTrue(955 in message)
        subgroup = message[200][0]
        self.assertEquals(3, len(subgroup))
        self.assertTrue(201 in subgroup)
        self.assertTrue(99 in subgroup)
        self.assertTrue(100 in subgroup)
        subgroup = message[200][1]
        self.assertEquals(4, len(subgroup))
        self.assertTrue(201 in subgroup)
        self.assertTrue(202 in subgroup)
        self.assertTrue(99 in subgroup)
        self.assertTrue(100 in subgroup)
    def test_message_starts_incorrectly(self):
        """ Message must start with tag 8 """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9])

        # message does not start with tag 8
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('18=FIX.4.2',
                                           '9=32',
                                           '8=FIX.4.2',
                                           '35=A',
                                           '10=100'))

        # unexpected tag 8
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           '8=abcdef',
                                           '35=A',
                                           '10=100'))
    def test_header_fields(self):
        """ Header field testing. """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9, 320])

        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=5',
                                       '35=A',
                                       '10=178'))
        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        message[320] = 'hello there'
        self.assertEquals(5, len(message))

        # verify the order of the message
        items = [(k, v) for k, v in message.items()]
        self.assertEquals(8, items[0][0])
        self.assertEquals(9, items[1][0])
        self.assertEquals(320, items[2][0])
    def test_binary_fields(self):
        """ Binary field testing. """
        parser = FIXParser(self.receiver,
                           binary_fields=[1000, 1010],
                           header_fields=[8, 9])

        # Test with embedded binary \x01
        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=18',
                                       '1000=5',
                                       '1001=\x01\x02\x03\x04\x05',
                                       '10=066'))
        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(5, len(message))
        self.assertTrue(message.verify(fields=[(8, 'FIX.4.2'),
                                               (9, '18'),
                                               (1000, '5'),
                                               (1001, '\x01\x02\x03\x04\x05'),
                                               (10, '066')]))

        # Test with embedded '=' signs
        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=18',
                                       '1000=5',
                                       '1001=31=20',
                                       '10=054'))
        self.assertEquals(2, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(5, len(message))
        self.assertTrue(message.verify(fields=[(8, 'FIX.4.2'),
                                               (9, '18'),
                                               (1000, '5'),
                                               (1001, '31=20'),
                                               (10, '054')]))
    def test_bad_syntax(self):
        """ Test for various bad syntax cases """
        parser = FIXParser(self.receiver,
                           header_fields=[8, 9])

        # Tag ID is not a number
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4.2',
                                           '9=32',
                                           'abcd=A'))

        # Missing '=' and value portion
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4',
                                           '9=32',
                                           '35'))

        # Missing tag ID portion
        with self.assertRaises(FIXParserError):
            parser.on_data_received(to_fix('8=FIX.4',
                                           '9=32',
                                           '=A'))
    def test_multiple_groups(self):
        """ Test the receiving of multiple groups """
        parser = FIXParser(self.receiver,
                           group_fields={100: [101, 102, 200],
                                         200: [201, 202], },
                           header_fields=[8, 9])

        parser.on_data_received(to_fix('8=FIX.4.2',
                                       '9=32',
                                       '100=2',
                                       '101=a',
                                       '102=b',
                                       '101=aa',
                                       '102=bb',
                                       '10=135'))
        self.assertEquals(1, self.receiver.count)

        message = self.receiver.last_received_message
        self.assertIsNotNone(message)
        self.assertEquals(4, len(message))

        self.assertTrue(100 in message)
        self.assertEquals(2, len(message[100]))

        group = message[100]
        self.assertIsNotNone(group)
        self.assertEquals(2, len(group))
        self.assertEquals(2, len(group[0]))
        self.assertTrue(101 in group[0])
        self.assertTrue(102 in group[0])
        self.assertEquals('a', group[0][101])
        self.assertEquals('b', group[0][102])
        self.assertEquals(2, len(group[1]))
        self.assertTrue(101 in group[1])
        self.assertTrue(102 in group[1])
        self.assertEquals('aa', group[1][101])
        self.assertEquals('bb', group[1][102])