def assert_routing_entries(self, routing_table, expected_entries):
     self.assertEqual(
         sorted(routing_table.entries()),
         sorted(
             (GoConnector.parse(str(sc)), se, GoConnector.parse(str(dc)), de) for sc, se, dc, de in expected_entries
         ),
     )
Example #2
0
    def acquire_source(self, msg, connector_type, direction, push_hops=True):
        """Determine the `str(go_connector)` value that a msg came
        in on by looking at the connector_type and fetching the
        appropriate values from the `msg` helper_metadata.

        Raises `UnroutableMessageError` if the connector_type has a
        value not appropriate for the direction.

        Note: `str(go_connector)` is what is stored in Go routing tables.
        """
        msg_mdh = self.get_metadata_helper(msg)

        if direction == self.INBOUND:
            allowed_types = (self.TRANSPORT_TAG, self.ROUTER, self.BILLING)
        else:
            allowed_types = (self.CONVERSATION, self.ROUTER,
                             self.OPT_OUT, self.BILLING)

        if connector_type not in allowed_types:
            raise UnroutableMessageError(
                "Source connector of invalid type: %s" % connector_type, msg)

        if connector_type == self.CONVERSATION:
            conv_info = msg_mdh.get_conversation_info()
            src_conn = str(GoConnector.for_conversation(
                conv_info['conversation_type'], conv_info['conversation_key']))

        elif connector_type == self.ROUTER:
            router_info = msg_mdh.get_router_info()
            src_conn = str(GoConnector.for_router(
                router_info['router_type'], router_info['router_key'],
                self.router_direction(direction)))

        elif connector_type == self.TRANSPORT_TAG:
            src_conn = str(GoConnector.for_transport_tag(*msg_mdh.tag))

        elif connector_type == self.OPT_OUT:
            src_conn = str(GoConnector.for_opt_out())

        elif connector_type == self.BILLING:
            # when the source is a billing router, outbound messages
            # are always received from the inbound billing connector
            # and inbound messages are always received from the outbound
            # billing connector.
            src_conn = str(
                GoConnector.for_billing(self.router_direction(direction)))

        else:
            raise UnroutableMessageError(
                "Serious error. Reached apparently unreachable state"
                " in which source connector type is both valid"
                " but unknown. Bad connector type is: %s"
                % connector_type, msg)

        src_conn_str = str(src_conn)
        if push_hops:
            rmeta = RoutingMetadata(msg)
            rmeta.push_source(src_conn_str, msg.get_routing_endpoint())
        return src_conn_str
Example #3
0
 def test_remove_router(self):
     rt = self.make_rt({})
     router = FakeRouter("router_1", "12345")
     rin_conn = str(GoConnector.for_router(
         router.router_type, router.key, GoConnector.INBOUND))
     rout_conn = str(GoConnector.for_router(
         router.router_type, router.key, GoConnector.OUTBOUND))
     rt.add_entry(self.CHANNEL_2, 'default', rin_conn, 'default')
     rt.add_entry(rin_conn, 'default', self.CHANNEL_2, 'default')
     rt.add_entry(self.CONV_1, 'default', rout_conn, 'default')
     rt.add_entry(rout_conn, 'default', self.CONV_1, 'default')
     self.assertNotEqual(list(rt.entries()), [])
     rt.remove_router(router)
     self.assert_routing_entries(rt, [])
    def test_connector_direction(self):
        def assert_inbound(conn):
            self.assertEqual(GoConnector.INBOUND, conn.direction)

        def assert_outbound(conn):
            self.assertEqual(GoConnector.OUTBOUND, conn.direction)

        assert_inbound(GoConnector.for_opt_out())
        assert_inbound(GoConnector.for_conversation("conv_type_1", "12345"))
        assert_outbound(GoConnector.for_transport_tag("tagpool_1", "tag_1"))
        assert_inbound(
            GoConnector.for_router("rb_type_1", "12345", GoConnector.INBOUND))
        assert_outbound(
            GoConnector.for_router("rb_type_1", "12345", GoConnector.OUTBOUND))
Example #5
0
    def test_connector_direction(self):
        def assert_inbound(conn):
            self.assertEqual(GoConnector.INBOUND, conn.direction)

        def assert_outbound(conn):
            self.assertEqual(GoConnector.OUTBOUND, conn.direction)

        assert_inbound(GoConnector.for_opt_out())
        assert_inbound(GoConnector.for_conversation("conv_type_1", "12345"))
        assert_outbound(GoConnector.for_transport_tag("tagpool_1", "tag_1"))
        assert_inbound(
            GoConnector.for_router("rb_type_1", "12345", GoConnector.INBOUND))
        assert_outbound(
            GoConnector.for_router("rb_type_1", "12345", GoConnector.OUTBOUND))
 def test_create_router_connector(self):
     c = GoConnector.for_router("rb_type_1", "12345", GoConnector.INBOUND)
     self.assertEqual(c.ctype, GoConnector.ROUTER)
     self.assertEqual(c.router_type, "rb_type_1")
     self.assertEqual(c.router_key, "12345")
     self.assertEqual(c.direction, GoConnector.INBOUND)
     self.assertEqual(str(c), "ROUTER:rb_type_1:12345:INBOUND")
Example #7
0
    def publish_inbound_to_billing(self, config, msg):
        """Publish an inbound message to the billing worker."""
        target = (str(GoConnector.for_billing(self.INBOUND)), 'default')
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.INBOUND)

        yield self.publish_inbound(msg, dst_connector_name, dst_endpoint)
 def test_remove_router(self):
     rt = self.make_rt({})
     router = FakeRouter("router_1", "12345")
     rin_conn = str(
         GoConnector.for_router(router.router_type, router.key,
                                GoConnector.INBOUND))
     rout_conn = str(
         GoConnector.for_router(router.router_type, router.key,
                                GoConnector.OUTBOUND))
     rt.add_entry(self.CHANNEL_2, 'default', rin_conn, 'default')
     rt.add_entry(rin_conn, 'default', self.CHANNEL_2, 'default')
     rt.add_entry(self.CONV_1, 'default', rout_conn, 'default')
     rt.add_entry(rout_conn, 'default', self.CONV_1, 'default')
     self.assertNotEqual(list(rt.entries()), [])
     rt.remove_router(router)
     self.assert_routing_entries(rt, [])
Example #9
0
    def publish_inbound_to_billing(self, config, msg):
        """Publish an inbound message to the billing worker."""
        target = (str(GoConnector.for_billing(self.INBOUND)), 'default')
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.INBOUND)

        yield self.publish_inbound(msg, dst_connector_name, dst_endpoint)
Example #10
0
 def test_create_router_connector_for_model(self):
     c = GoConnector.for_model(
         FakeRouter("rb_type_1", "12345"), GoConnector.INBOUND)
     self.assertEqual(c.ctype, GoConnector.ROUTER)
     self.assertEqual(c.router_type, "rb_type_1")
     self.assertEqual(c.router_key, "12345")
     self.assertEqual(c.direction, GoConnector.INBOUND)
     self.assertEqual(str(c), "ROUTER:rb_type_1:12345:INBOUND")
Example #11
0
 def test_remove_transport_tag(self):
     tag = ["pool1", "tag1"]
     rt = self.make_rt({})
     tag_conn = str(GoConnector.for_transport_tag(*tag))
     rt.add_entry(tag_conn, "default", self.CONV_1, "default")
     rt.add_entry(self.CONV_1, "default", tag_conn, "default")
     rt.remove_transport_tag(tag)
     self.assert_routing_entries(rt, [])
Example #12
0
 def test_remove_transport_tag(self):
     tag = ["pool1", "tag1"]
     rt = self.make_rt({})
     tag_conn = str(GoConnector.for_transport_tag(*tag))
     rt.add_entry(tag_conn, "default", self.CONV_1, "default")
     rt.add_entry(self.CONV_1, "default", tag_conn, "default")
     rt.remove_transport_tag(tag)
     self.assert_routing_entries(rt, [])
Example #13
0
    def publish_outbound_to_billing(self, config, msg, tag):
        """Publish an outbound message to the billing worker."""
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_tag(tag)
        target = (str(GoConnector.for_billing(self.OUTBOUND)), 'default')
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #14
0
    def publish_outbound_to_billing(self, config, msg, tag):
        """Publish an outbound message to the billing worker."""
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_tag(tag)
        target = (str(GoConnector.for_billing(self.OUTBOUND)), 'default')
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #15
0
 def test_remove_conversation(self):
     rt = self.make_rt({})
     conv = FakeConversation("conv_type_1", "12345")
     conv_conn = str(
         GoConnector.for_conversation(conv.conversation_type, conv.key))
     rt.add_entry(conv_conn, "default", self.CHANNEL_2, "default")
     rt.add_entry(self.CHANNEL_2, "default", conv_conn, "default")
     rt.remove_conversation(conv)
     self.assert_routing_entries(rt, [])
Example #16
0
 def test_flip_router_connector(self):
     c1 = GoConnector.for_router("dummy", "1", GoConnector.INBOUND)
     c2 = c1.flip_direction()
     self.assertEqual(c2.direction, GoConnector.OUTBOUND)
     self.assertEqual(c2.ctype, GoConnector.ROUTER)
     self.assertEqual(c2.router_type, "dummy")
     self.assertEqual(c2.router_key, "1")
     c3 = c2.flip_direction()
     self.assertEqual(c3.direction, GoConnector.INBOUND)
Example #17
0
 def test_remove_conversation(self):
     rt = self.make_rt({})
     conv = FakeConversation("conv_type_1", "12345")
     conv_conn = str(
         GoConnector.for_conversation(conv.conversation_type, conv.key))
     rt.add_entry(conv_conn, "default", self.CHANNEL_2, "default")
     rt.add_entry(self.CHANNEL_2, "default", conv_conn, "default")
     rt.remove_conversation(conv)
     self.assert_routing_entries(rt, [])
Example #18
0
    def publish_outbound_from_billing(self, config, msg):
        """Publish an outbound message to its intended destination
        after billing.
        """
        msg_mdh = self.get_metadata_helper(msg)
        dst_conn = GoConnector.for_transport_tag(*msg_mdh.tag)
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, [str(dst_conn), 'default'], self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #19
0
 def test_flip_router_connector(self):
     c1 = GoConnector.for_router(
         "dummy", "1", GoConnector.INBOUND)
     c2 = c1.flip_direction()
     self.assertEqual(c2.direction, GoConnector.OUTBOUND)
     self.assertEqual(c2.ctype, GoConnector.ROUTER)
     self.assertEqual(c2.router_type, "dummy")
     self.assertEqual(c2.router_key, "1")
     c3 = c2.flip_direction()
     self.assertEqual(c3.direction, GoConnector.INBOUND)
Example #20
0
    def publish_outbound_from_billing(self, config, msg):
        """Publish an outbound message to its intended destination
        after billing.
        """
        msg_mdh = self.get_metadata_helper(msg)
        dst_conn = GoConnector.for_transport_tag(*msg_mdh.tag)
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, [str(dst_conn), 'default'], self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #21
0
    def process_outbound(self, config, msg, connector_name):
        """Process an outbound message.

        Outbound messages can be from:

        * conversations
        * routers
        * the opt-out worker
        * the billing worker

        And may go to:

        * routers
        * transports
        * the billing worker
        """
        log.debug("Processing outbound: %s" % (msg,))
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_user_account(config.user_account_key)

        connector_type = self.connector_type(connector_name)
        src_conn = self.acquire_source(msg, connector_type, self.OUTBOUND)

        if self.billing_outbound_connector:
            if connector_type in (self.CONVERSATION, self.ROUTER):
                msg_mdh.reset_paid()
            elif connector_type == self.OPT_OUT:
                tag = yield self.tag_for_reply(msg)
                yield self.publish_outbound_to_billing(config, msg, tag)
                return
            elif connector_type == self.BILLING:
                yield self.publish_outbound_from_billing(config, msg)
                return
        else:
            if connector_type == self.OPT_OUT:
                yield self.publish_outbound_optout(config, msg)
                return

        target = self.find_target(config, msg, src_conn)
        if target is None:
            raise NoTargetError(
                "No target found for outbound message from '%s': %s" % (
                    connector_name, msg), msg)

        if self.billing_outbound_connector:
            target_conn = GoConnector.parse(target[0])
            if target_conn.ctype == target_conn.TRANSPORT_TAG:
                tag = [target_conn.tagpool, target_conn.tagname]
                yield self.publish_outbound_to_billing(config, msg, tag)
                return

        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #22
0
    def process_outbound(self, config, msg, connector_name):
        """Process an outbound message.

        Outbound messages can be from:

        * conversations
        * routers
        * the opt-out worker
        * the billing worker

        And may go to:

        * routers
        * transports
        * the billing worker
        """
        log.debug("Processing outbound: %s" % (msg, ))
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_user_account(config.user_account_key)

        connector_type = self.connector_type(connector_name)
        src_conn = self.acquire_source(msg, connector_type, self.OUTBOUND)

        if self.billing_outbound_connector:
            if connector_type in (self.CONVERSATION, self.ROUTER):
                msg_mdh.reset_paid()
            elif connector_type == self.OPT_OUT:
                tag = yield self.tag_for_reply(msg)
                yield self.publish_outbound_to_billing(config, msg, tag)
                return
            elif connector_type == self.BILLING:
                yield self.publish_outbound_from_billing(config, msg)
                return
        else:
            if connector_type == self.OPT_OUT:
                yield self.publish_outbound_optout(config, msg)
                return

        target = self.find_target(config, msg, src_conn)
        if target is None:
            raise NoTargetError(
                "No target found for outbound message from '%s': %s" %
                (connector_name, msg), msg)

        if self.billing_outbound_connector:
            target_conn = GoConnector.parse(target[0])
            if target_conn.ctype == target_conn.TRANSPORT_TAG:
                tag = [target_conn.tagpool, target_conn.tagname]
                yield self.publish_outbound_to_billing(config, msg, tag)
                return

        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.OUTBOUND)

        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #23
0
    def publish_outbound_optout(self, config, msg):
        """Publish a reply from the opt-out worker.

        It does this by looking up the original message and
        sending the reply out via the same tag the original
        message came in on.
        """
        tag = yield self.tag_for_reply(msg)
        dst_conn = GoConnector.for_transport_tag(*tag)
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, [str(dst_conn), 'default'], self.OUTBOUND)
        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #24
0
    def publish_outbound_optout(self, config, msg):
        """Publish a reply from the opt-out worker.

        It does this by looking up the original message and
        sending the reply out via the same tag the original
        message came in on.
        """
        tag = yield self.tag_for_reply(msg)
        dst_conn = GoConnector.for_transport_tag(*tag)
        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, [str(dst_conn), 'default'], self.OUTBOUND)
        yield self.publish_outbound(msg, dst_connector_name, dst_endpoint)
Example #25
0
    def setup_routing(self, user, account_objects):
        connectors = {}
        for conv in account_objects['conversations']:
            connectors[conv['key']] = GoConnector.for_conversation(
                conv['conversation_type'], conv['key'])
        for tag in account_objects['channels']:
            connectors[tag] = GoConnector.for_transport_tag(*(tag.split(':')))
        for router in account_objects['routers']:
            connectors[router['key'] + ':INBOUND'] = GoConnector.for_router(
                router['router_type'], router['key'], GoConnector.INBOUND)
            connectors[router['key'] + ':OUTBOUND'] = GoConnector.for_router(
                router['router_type'], router['key'], GoConnector.OUTBOUND)

        rt = RoutingTable()
        for src, src_ep, dst, dst_ep in account_objects['routing_entries']:
            rt.add_entry(
                str(connectors[src]), src_ep, str(connectors[dst]), dst_ep)

        user_account = vumi_api_for_user(user).get_user_account()
        user_account.routing_table = rt
        user_account.save()

        self.stdout.write('Routing table for %s built\n' % (user.email,))
Example #26
0
    def process_inbound(self, config, msg, connector_name):
        """Process an inbound message.

        Inbound messages can be from:

        * transports (these might be opt-out messages)
        * routers
        * the billing worker

        And may go to:

        * routers
        * conversations
        * the opt-out worker
        * the billing worker
        """
        log.debug("Processing inbound: %r" % (msg,))
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_user_account(config.user_account_key)

        connector_type = self.connector_type(connector_name)
        src_conn = self.acquire_source(msg, connector_type, self.INBOUND)

        if self.billing_inbound_connector:
            if connector_type == self.TRANSPORT_TAG:
                yield self.publish_inbound_to_billing(config, msg)
                return
            if connector_type == self.BILLING:
                # set the src_conn to the transport and keep routing
                src_conn = str(GoConnector.for_transport_tag(*msg_mdh.tag))

        if msg_mdh.is_optout_message():
            yield self.publish_inbound_optout(config, msg)
            return

        target = self.find_target(config, msg, src_conn)
        if target is None:
            raise NoTargetError(
                "No target found for inbound message from %r"
                % (connector_name,), msg)

        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.INBOUND)

        yield self.publish_inbound(msg, dst_connector_name, dst_endpoint)
Example #27
0
    def process_inbound(self, config, msg, connector_name):
        """Process an inbound message.

        Inbound messages can be from:

        * transports (these might be opt-out messages)
        * routers
        * the billing worker

        And may go to:

        * routers
        * conversations
        * the opt-out worker
        * the billing worker
        """
        log.debug("Processing inbound: %r" % (msg, ))
        msg_mdh = self.get_metadata_helper(msg)
        msg_mdh.set_user_account(config.user_account_key)

        connector_type = self.connector_type(connector_name)
        src_conn = self.acquire_source(msg, connector_type, self.INBOUND)

        if self.billing_inbound_connector:
            if connector_type == self.TRANSPORT_TAG:
                yield self.publish_inbound_to_billing(config, msg)
                return
            if connector_type == self.BILLING:
                # set the src_conn to the transport and keep routing
                src_conn = str(GoConnector.for_transport_tag(*msg_mdh.tag))

        if msg_mdh.is_optout_message():
            yield self.publish_inbound_optout(config, msg)
            return

        target = self.find_target(config, msg, src_conn)
        if target is None:
            raise NoTargetError(
                "No target found for inbound message from %r" %
                (connector_name, ), msg)

        dst_connector_name, dst_endpoint = yield self.set_destination(
            msg, target, self.INBOUND)

        yield self.publish_inbound(msg, dst_connector_name, dst_endpoint)
Example #28
0
 def handle_remove(self, user_api, options):
     src_conn, src_endpoint, dst_conn, dst_endpoint = options['remove']
     account = user_api.get_user_account()
     if account.routing_table is None:
         raise CommandError("No routing table found.")
     target = account.routing_table.lookup_target(src_conn, src_endpoint)
     if target is None:
         raise CommandError("No routing entry found for (%s, %s)." %
                            (src_conn, src_endpoint))
     elif target != [GoConnector.parse(dst_conn), dst_endpoint]:
         raise CommandError(
             "Existing entry (%s, %s) does not match (%s, %s)." %
             (target[0], target[1], dst_conn, dst_endpoint))
     account.routing_table.remove_entry(src_conn, src_endpoint)
     try:
         user_api.validate_routing_table(account)
     except Exception as e:
         raise CommandError(e)
     account.save()
     self.stdout.write("Routing table entry removed.\n")
 def handle_remove(self, user_api, options):
     src_conn, src_endpoint, dst_conn, dst_endpoint = options['remove']
     account = user_api.get_user_account()
     if account.routing_table is None:
         raise CommandError("No routing table found.")
     target = account.routing_table.lookup_target(src_conn, src_endpoint)
     if target is None:
         raise CommandError("No routing entry found for (%s, %s)." % (
             src_conn, src_endpoint))
     elif target != [GoConnector.parse(dst_conn), dst_endpoint]:
         raise CommandError(
             "Existing entry (%s, %s) does not match (%s, %s)." % (
                 target[0], target[1], dst_conn, dst_endpoint))
     account.routing_table.remove_entry(src_conn, src_endpoint)
     try:
         user_api.validate_routing_table(account)
     except Exception as e:
         raise CommandError(e)
     account.save()
     self.stdout.write("Routing table entry removed.\n")
Example #30
0
 def assert_connectors(self, connectors, expected_connectors):
     self.assertEqual(
         sorted(connectors),
         sorted(
             GoConnector.parse(str(conn)) for conn in expected_connectors))
Example #31
0
 def test_create_transport_tag_connector_for_model(self):
     c = GoConnector.for_model(FakePlasticChannel("tagpool_1", "tag_1"))
     self.assertEqual(c.ctype, GoConnector.TRANSPORT_TAG)
     self.assertEqual(c.tagpool, "tagpool_1")
     self.assertEqual(c.tagname, "tag_1")
     self.assertEqual(str(c), "TRANSPORT_TAG:tagpool_1:tag_1")
Example #32
0
 def test_parse_conversation_connector(self):
     c = GoConnector.parse("CONVERSATION:conv_type_1:12345")
     self.assertEqual(c.ctype, GoConnector.CONVERSATION)
     self.assertEqual(c.conv_type, "conv_type_1")
     self.assertEqual(c.conv_key, "12345")
Example #33
0
 def test_parse_opt_out_connector(self):
     c = GoConnector.parse("OPT_OUT")
     self.assertEqual(c.ctype, GoConnector.OPT_OUT)
Example #34
0
 def test_parse_router_connector(self):
     c = GoConnector.parse("ROUTER:rb_type_1:12345:OUTBOUND")
     self.assertEqual(c.ctype, GoConnector.ROUTER)
     self.assertEqual(c.router_type, "rb_type_1")
     self.assertEqual(c.router_key, "12345")
     self.assertEqual(c.direction, GoConnector.OUTBOUND)
Example #35
0
 def test_create_opt_out_connector(self):
     c = GoConnector.for_opt_out()
     self.assertEqual(c.ctype, GoConnector.OPT_OUT)
     self.assertEqual(str(c), "OPT_OUT")
Example #36
0
 def get_outbound_connector(self):
     return GoConnector.for_model(self, GoConnector.OUTBOUND)
Example #37
0
 def get_connector(self):
     return GoConnector.for_model(self)
Example #38
0
 def test_create_transport_tag_connector_for_model(self):
     c = GoConnector.for_model(FakePlasticChannel("tagpool_1", "tag_1"))
     self.assertEqual(c.ctype, GoConnector.TRANSPORT_TAG)
     self.assertEqual(c.tagpool, "tagpool_1")
     self.assertEqual(c.tagname, "tag_1")
     self.assertEqual(str(c), "TRANSPORT_TAG:tagpool_1:tag_1")
Example #39
0
 def assert_connectors(self, connectors, expected_connectors):
     self.assertEqual(sorted(connectors), sorted(
         GoConnector.parse(str(conn)) for conn in expected_connectors))
Example #40
0
    def set_destination(self, msg, target, direction, push_hops=True):
        """Parse a target `(str(go_connector), endpoint)` pair and determine
        the corresponding dispatcher connector to publish on. Set any
        appropriate Go helper_metadata required by the destination.

        Raises `UnroutableMessageError` if the parsed `GoConnector` has a
        connector type not approriate to the message direction.

        Note: `str(go_connector)` is what is stored in Go routing tables.
        """
        msg_mdh = self.get_metadata_helper(msg)
        conn = GoConnector.parse(target[0])

        if direction == self.INBOUND:
            allowed_types = (
                self.CONVERSATION, self.ROUTER, self.OPT_OUT, self.BILLING)
        else:
            allowed_types = (
                self.ROUTER, self.TRANSPORT_TAG, self.BILLING)

        if conn.ctype not in allowed_types:
            raise UnroutableMessageError(
                "Destination connector of invalid type: %s" % conn, msg)

        if conn.ctype == conn.CONVERSATION:
            msg_mdh.set_conversation_info(conn.conv_type, conn.conv_key)
            dst_connector_name = self.get_application_connector(conn.conv_type)

        elif conn.ctype == conn.ROUTER:
            msg_mdh.set_router_info(conn.router_type, conn.router_key)
            dst_connector_name = self.get_router_connector(
                conn.router_type, self.router_direction(direction))

        elif conn.ctype == conn.TRANSPORT_TAG:
            msg_mdh.set_tag([conn.tagpool, conn.tagname])
            tagpool_metadata = yield msg_mdh.get_tagpool_metadata()
            transport_name = tagpool_metadata.get('transport_name')
            if transport_name is None:
                raise UnroutableMessageError(
                    "No transport name found for tagpool %r"
                    % conn.tagpool, msg)
            if self.connector_type(transport_name) != self.TRANSPORT_TAG:
                raise UnroutableMessageError(
                    "Transport name %r found in tagpool metadata for pool"
                    " %r is invalid." % (transport_name, conn.tagpool), msg)
            dst_connector_name = transport_name
            msg['transport_name'] = transport_name

            transport_type = tagpool_metadata.get('transport_type')
            if transport_type is not None:
                msg['transport_type'] = transport_type
            else:
                log.error(
                    "No transport type found for tagpool %r while routing %s"
                    % (conn.tagpool, msg))

        elif conn.ctype == conn.OPT_OUT:
            dst_connector_name = self.opt_out_connector

        elif conn.ctype == conn.BILLING:
            if direction == self.INBOUND:
                dst_connector_name = self.billing_inbound_connector
            else:
                dst_connector_name = self.billing_outbound_connector

        else:
            raise UnroutableMessageError(
                "Serious error. Reached apparently unreachable state"
                " in which destination connector type is valid but"
                " unknown. Bad connector is: %s" % conn, msg)

        if push_hops:
            rmeta = RoutingMetadata(msg)
            rmeta.push_destination(str(conn), target[1])
        returnValue((dst_connector_name, target[1]))
Example #41
0
 def publish_inbound_optout(self, config, msg):
     """Publish an inbound opt-out request to the opt-out worker."""
     target = [str(GoConnector.for_opt_out()), 'default']
     dst_connector_name, dst_endpoint = yield self.set_destination(
         msg, target, self.INBOUND)
     yield self.publish_inbound(msg, dst_connector_name, dst_endpoint)
Example #42
0
 def get_inbound_connector(self):
     return GoConnector.for_model(self, GoConnector.INBOUND)
Example #43
0
 def test_create_conversation_connector_for_model(self):
     c = GoConnector.for_model(FakeConversation("conv_type_1", "12345"))
     self.assertEqual(c.ctype, GoConnector.CONVERSATION)
     self.assertEqual(c.conv_type, "conv_type_1")
     self.assertEqual(c.conv_key, "12345")
     self.assertEqual(str(c), "CONVERSATION:conv_type_1:12345")
Example #44
0
 def test_parse_router_connector(self):
     c = GoConnector.parse("ROUTER:rb_type_1:12345:OUTBOUND")
     self.assertEqual(c.ctype, GoConnector.ROUTER)
     self.assertEqual(c.router_type, "rb_type_1")
     self.assertEqual(c.router_key, "12345")
     self.assertEqual(c.direction, GoConnector.OUTBOUND)
Example #45
0
 def get_outbound_connector(self):
     return GoConnector.for_router(
         self.router_type, self.key, GoConnector.OUTBOUND)
Example #46
0
 def test_parse_conversation_connector(self):
     c = GoConnector.parse("CONVERSATION:conv_type_1:12345")
     self.assertEqual(c.ctype, GoConnector.CONVERSATION)
     self.assertEqual(c.conv_type, "conv_type_1")
     self.assertEqual(c.conv_key, "12345")
Example #47
0
 def get_connector(self):
     return GoConnector.for_conversation(self.conversation_type, self.key)
Example #48
0
 def test_parse_transport_tag_connector(self):
     c = GoConnector.parse("TRANSPORT_TAG:tagpool_1:tag_1")
     self.assertEqual(c.ctype, GoConnector.TRANSPORT_TAG)
     self.assertEqual(c.tagpool, "tagpool_1")
     self.assertEqual(c.tagname, "tag_1")
Example #49
0
 def test_lookup_targets(self):
     rt = self.make_rt()
     self.assertEqual(sorted(rt.lookup_targets(self.CONV_1)), [
         ("default1.1", [GoConnector.parse(self.CHANNEL_2), "default2"]),
         ("default1.2", [GoConnector.parse(self.CHANNEL_3), "default3"]),
     ])
Example #50
0
 def get_connector(self):
     return GoConnector.for_model(self)
Example #51
0
 def test_lookup_sources(self):
     rt = self.make_rt()
     self.assertEqual(sorted(rt.lookup_sources(self.CHANNEL_3)), [
         ("default3", [GoConnector.parse(self.CONV_1), "default1.2"]),
     ])
Example #52
0
 def test_flip_non_router_connector(self):
     c = GoConnector.for_conversation("dummy", "1")
     self.assertRaises(GoConnectorError, c.flip_direction)
Example #53
0
 def test_flip_non_router_connector(self):
     c = GoConnector.for_conversation("dummy", "1")
     self.assertRaises(GoConnectorError, c.flip_direction)
Example #54
0
 def test_create_conversation_connector_for_model(self):
     c = GoConnector.for_model(FakeConversation("conv_type_1", "12345"))
     self.assertEqual(c.ctype, GoConnector.CONVERSATION)
     self.assertEqual(c.conv_type, "conv_type_1")
     self.assertEqual(c.conv_key, "12345")
     self.assertEqual(str(c), "CONVERSATION:conv_type_1:12345")
Example #55
0
 def test_parse_opt_out_connector(self):
     c = GoConnector.parse("OPT_OUT")
     self.assertEqual(c.ctype, GoConnector.OPT_OUT)
Example #56
0
 def assert_routing_entries(self, routing_table, expected_entries):
     self.assertEqual(
         sorted(routing_table.entries()),
         sorted((GoConnector.parse(str(sc)), se, GoConnector.parse(str(dc)),
                 de) for sc, se, dc, de in expected_entries))
Example #57
0
 def test_parse_transport_tag_connector(self):
     c = GoConnector.parse("TRANSPORT_TAG:tagpool_1:tag_1")
     self.assertEqual(c.ctype, GoConnector.TRANSPORT_TAG)
     self.assertEqual(c.tagpool, "tagpool_1")
     self.assertEqual(c.tagname, "tag_1")
Example #58
0
 def test_lookup_target(self):
     rt = self.make_rt()
     self.assertEqual(rt.lookup_target(self.CONV_1, "default1.1"),
                      [GoConnector.parse(self.CHANNEL_2), "default2"])
     self.assertEqual(rt.lookup_target(self.CONV_1, "default1.2"),
                      [GoConnector.parse(self.CHANNEL_3), "default3"])
Example #59
0
 def mkconn(thing):
     if isinstance(thing, basestring):
         return GoConnector.parse(thing)
     else:
         # Assume it's a conversation/channel/router.
         return thing.get_connector()