예제 #1
0
class IpcServerTest(AbstractGatewayRpcIntegrationTest):
    @async_test
    async def setUp(self) -> None:
        await super().setUp()
        self.gateway_node.NODE_TYPE = NodeType.INTERNAL_GATEWAY
        self.transaction_streamer_peer = OutboundPeerModel(
            "127.0.0.1", 8006, node_type=NodeType.INTERNAL_GATEWAY)
        self.feed_manager = FeedManager(self.gateway_node)
        self.server = IpcServer("bxgateway.ipc", self.feed_manager,
                                self.gateway_node, Case.SNAKE)
        self.ipc_path = self.server.ipc_path
        await self.server.start()

    def get_gateway_opts(self) -> GatewayOpts:
        super().get_gateway_opts()
        return gateway_helpers.get_gateway_opts(
            8000,
            blockchain_protocol="Ethereum",
            account_model=self._account_model)

    async def request(self, req: BxJsonRpcRequest) -> JsonRpcResponse:
        async with websockets.unix_connect(self.ipc_path) as ws:
            await ws.send(req.to_jsons())
            return JsonRpcResponse.from_jsons(await ws.recv())

    @async_test
    async def test_startup(self):
        async with websockets.unix_connect(self.ipc_path) as _ws:
            await asyncio.sleep(0.01)

            self.assertEqual(1, len(self.server._connections))
            connection = self.server._connections[0]
            self.assertFalse(connection.request_handler.done())
            self.assertFalse(connection.publish_handler.done())

    @async_test
    async def test_subscribe_and_unsubscribe(self):
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        def publish():
            feed.publish(1)
            feed.publish(2)
            feed.publish(3)

        async with websockets.unix_connect(self.ipc_path) as ws:
            asyncio.get_event_loop().call_later(0.1, publish)
            await ws.send(
                BxJsonRpcRequest("2", RpcRequestType.SUBSCRIBE,
                                 ["foo", {}]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)

            self.assertEqual("2", parsed_response.id)
            self.assertIsNotNone("1", parsed_response.result)
            subscriber_id = parsed_response.result

            self._assert_notification(1, subscriber_id, await ws.recv())
            self._assert_notification(2, subscriber_id, await ws.recv())
            self._assert_notification(3, subscriber_id, await ws.recv())

            await ws.send(
                BxJsonRpcRequest("3", RpcRequestType.UNSUBSCRIBE,
                                 [subscriber_id]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)
            self.assertEqual("3", parsed_response.id)
            self.assertTrue(parsed_response.result)

            publish()
            with self.assertRaises(TimeoutError):
                await asyncio.wait_for(ws.recv(), 0.1)

    @async_test
    async def tearDown(self) -> None:
        await self.server.stop()

    @async_test
    async def test_blxr_tx(self):
        pass

    def _assert_notification(self, expected_result: Any, subscriber_id: str,
                             message: str):
        parsed_notification = BxJsonRpcRequest.from_jsons(message)
        self.assertIsNone(parsed_notification.id)
        self.assertEqual(RpcRequestType.SUBSCRIBE, parsed_notification.method)
        self.assertEqual(subscriber_id,
                         parsed_notification.params["subscription"])
        self.assertEqual(expected_result, parsed_notification.params["result"])
예제 #2
0
class FilterDslTest(AbstractTestCase):
    def setUp(self) -> None:
        self.gateway = MockGatewayNode(gateway_helpers.get_gateway_opts(8000))
        self.feed_manager = FeedManager(self.gateway)
        self.rpc = SubscriptionRpcHandler(self.gateway, self.feed_manager,
                                          Case.SNAKE)

    @async_test
    async def test_subscribe_to_feed_with_filters(self):
        feed = TestFeed("bar")
        feed.FILTERS = ["field1", "field2"]

        self.feed_manager.register_feed(feed)
        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            ["bar", {
                "filters": {
                    "AND": [{
                        "field1": ["bar"]
                    }]
                }
            }],
        )

        rpc_handler = self.rpc.get_request_handler(subscribe_request1)
        result = await rpc_handler.process_request()
        self.assertTrue(result)

    @async_test
    async def test_subscribe_to_feed_with_invalid_filters(self):
        feed = TestFeed("foo")
        feed.FILTERS = ["filter1", "OR", "filter2"]
        self.feed_manager.register_feed(feed)
        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            ["foo", {
                "filters": [{
                    "field1": []
                }, "AND", {
                    "field2": []
                }]
            }],
        )

        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request1)
            await rpc_handler.process_request()

        subscribe_request2 = BxJsonRpcRequest(
            "1", RpcRequestType.SUBSCRIBE,
            ["foo", {
                "filters": [True, False, 1, 2]
            }])
        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request2)
            await rpc_handler.process_request()

        subscribe_request3 = BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE,
                                              ["foo", {
                                                  "filters": "OR"
                                              }])
        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request3)
            await rpc_handler.process_request()
        subscribe_request4 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [
                "foo", {
                    "filters": {
                        "AND": [{
                            "field1": ["bar"]
                        }, {
                            "OR": {
                                "field2": ["hi"]
                            }
                        }]
                    }
                }
            ],
        )
        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request4)
            await rpc_handler.process_request()
예제 #3
0
class WsServerTest(AbstractGatewayRpcIntegrationTest):
    @async_test
    async def setUp(self) -> None:
        await super().setUp()
        self.feed_manager = FeedManager()
        self.server = WsServer(constants.LOCALHOST, 8005, self.feed_manager,
                               self.gateway_node)
        self.ws_uri = f"ws://{constants.LOCALHOST}:8005"
        await self.server.start()

    def get_gateway_opts(self) -> GatewayOpts:
        super().get_gateway_opts()
        return gateway_helpers.get_gateway_opts(8000, )

    async def request(self, req: BxJsonRpcRequest) -> JsonRpcResponse:
        async with websockets.connect(self.ws_uri) as ws:
            await ws.send(req.to_jsons())
            return JsonRpcResponse.from_jsons(await ws.recv())

    @async_test
    async def test_startup(self):
        async with websockets.connect(self.ws_uri) as _ws:
            await asyncio.sleep(0.01)

            self.assertEqual(1, len(self.server._connections))
            connection = self.server._connections[0]
            self.assertFalse(connection.request_handler.done())
            self.assertFalse(connection.publish_handler.done())

    @async_test
    async def test_subscribe_and_unsubscribe(self):
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        def publish():
            feed.publish(1)
            feed.publish(2)
            feed.publish(3)

        async with websockets.connect(self.ws_uri) as ws:
            asyncio.get_event_loop().call_later(0.1, publish)
            await ws.send(
                BxJsonRpcRequest("2", RpcRequestType.SUBSCRIBE,
                                 ["foo", {}]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)

            self.assertEqual("2", parsed_response.id)
            self.assertIsNotNone("1", parsed_response.result)
            subscriber_id = parsed_response.result

            self._assert_notification(1, subscriber_id, await ws.recv())
            self._assert_notification(2, subscriber_id, await ws.recv())
            self._assert_notification(3, subscriber_id, await ws.recv())

            await ws.send(
                BxJsonRpcRequest("3", RpcRequestType.UNSUBSCRIBE,
                                 [subscriber_id]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)
            self.assertEqual("3", parsed_response.id)
            self.assertTrue(parsed_response.result)

            publish()
            with self.assertRaises(TimeoutError):
                await asyncio.wait_for(ws.recv(), 0.1)

    @async_test
    async def tearDown(self) -> None:
        await self.server.stop()

    @async_test
    async def test_blxr_tx(self):
        pass

    def _assert_notification(self, expected_result: Any, subscriber_id: str,
                             message: str):
        parsed_notification = BxJsonRpcRequest.from_jsons(message)
        self.assertIsNone(parsed_notification.id)
        self.assertEqual(RpcRequestType.SUBSCRIBE, parsed_notification.method)
        self.assertEqual(subscriber_id,
                         parsed_notification.params["subscription"])
        self.assertEqual(expected_result, parsed_notification.params["result"])
class SubscriptionRpcHandlerTest(AbstractTestCase):
    def setUp(self) -> None:
        self.gateway = MockGatewayNode(gateway_helpers.get_gateway_opts(8000))
        self.feed_manager = FeedManager()
        self.rpc = SubscriptionRpcHandler(self.gateway, self.feed_manager)

    @async_test
    async def test_help(self):
        print(await self.rpc.help())

    @async_test
    async def test_subscribe_to_feed(self):
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)
        subscribe_request = BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE,
                                             ["foo", {}])

        rpc_handler = self.rpc.get_request_handler(subscribe_request)
        self.assertIsInstance(rpc_handler, SubscribeRpcRequest)

        result = await rpc_handler.process_request()
        self.assertIsNotNone(result.result)
        self.assertIsNone(result.error)
        subscriber_id = result.result

        self.assertEqual(1, self.feed_manager.feeds["foo"].subscriber_count())
        self.assertEqual(1, len(self.rpc.subscriptions))
        self.assertIn(subscriber_id, self.rpc.subscriptions)

        next_message_task: Future[BxJsonRpcRequest] = asyncio.ensure_future(
            self.rpc.get_next_subscribed_message())
        await asyncio.sleep(0)
        self.assertFalse(next_message_task.done())

        feed.publish("foobar")
        await asyncio.sleep(0)  # publish to subscriber
        await asyncio.sleep(0)  # subscriber publishes to queue

        self.assertTrue(next_message_task.done())
        next_message = next_message_task.result()

        self.assertEqual("2.0", next_message.json_rpc_version)
        self.assertEqual(RpcRequestType.SUBSCRIBE, next_message.method)
        self.assertEqual(subscriber_id, next_message.params["subscription"])
        self.assertEqual("foobar", next_message.params["result"])

    @async_test
    async def test_subscribe_to_feed_validation(self):
        feed = TestFeed("foo")
        feed.FIELDS = ["field1", "field2", "field3"]
        self.feed_manager.register_feed(feed)
        subscribe_request = BxJsonRpcRequest(
            "1", RpcRequestType.SUBSCRIBE,
            ["foo", {
                "include": ["field1", "field4"]
            }])

        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request)
            await rpc_handler.process_request()

    @async_test
    async def test_subscribe_to_feed_with_filter(self):
        feed = TestFeed("foo")
        feed.FIELDS = ["field1", "field2", "field3"]
        self.feed_manager.register_feed(feed)
        subscribe_request = BxJsonRpcRequest(
            "1", RpcRequestType.SUBSCRIBE,
            ["foo", {
                "include": ["field1", "field2"]
            }])

        rpc_handler = self.rpc.get_request_handler(subscribe_request)
        result = await rpc_handler.process_request()
        subscriber_id = result.result

        next_message_task: Future[BxJsonRpcRequest] = asyncio.ensure_future(
            self.rpc.get_next_subscribed_message())

        feed.publish({"field1": "foo", "field2": "bar", "field3": "baz"})
        await asyncio.sleep(0)  # publish to subscriber
        await asyncio.sleep(0)  # subscriber publishes to queue

        self.assertTrue(next_message_task.done())
        next_message = next_message_task.result()

        self.assertEqual("2.0", next_message.json_rpc_version)
        self.assertEqual(RpcRequestType.SUBSCRIBE, next_message.method)
        self.assertEqual(subscriber_id, next_message.params["subscription"])

        expected_result = {
            "field1": "foo",
            "field2": "bar",
        }
        self.assertEqual(expected_result, next_message.params["result"])

    @async_test
    async def test_subscribe_to_multiple_feeds(self):
        feed1 = TestFeed("foo1")
        feed2 = TestFeed("foo2")
        feed3 = TestFeed("foo3")
        for feed in [feed1, feed2, feed3]:
            self.feed_manager.register_feed(feed)

        subscribe_requests = [
            BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE, ["foo1", {}]),
            BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE, ["foo2", {}]),
            BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE, ["foo3", {}])
        ]
        subscriber_ids = []
        for subscribe_request in subscribe_requests:
            rpc_handler = self.rpc.get_request_handler(subscribe_request)
            result = await rpc_handler.process_request()
            subscriber_ids.append(result.result)

        next_message_task: Future[BxJsonRpcRequest] = asyncio.ensure_future(
            self.rpc.get_next_subscribed_message())
        await asyncio.sleep(0)
        self.assertFalse(next_message_task.done())

        feed2.publish("message 1")
        await asyncio.sleep(0)
        feed1.publish("message 2")
        await asyncio.sleep(0)
        feed2.publish("message 3")
        await asyncio.sleep(0)
        feed3.publish("message 4")
        await asyncio.sleep(0)

        self.assertTrue(next_message_task.done())

        message_1 = next_message_task.result()
        self.assertEqual(subscriber_ids[1], message_1.params["subscription"])
        self.assertEqual("message 1", message_1.params["result"])

        message_2 = await self.rpc.get_next_subscribed_message()
        self.assertEqual(subscriber_ids[0], message_2.params["subscription"])
        self.assertEqual("message 2", message_2.params["result"])

        message_3 = await self.rpc.get_next_subscribed_message()
        self.assertEqual(subscriber_ids[1], message_3.params["subscription"])
        self.assertEqual("message 3", message_3.params["result"])

        message_4 = await self.rpc.get_next_subscribed_message()
        self.assertEqual(subscriber_ids[2], message_4.params["subscription"])
        self.assertEqual("message 4", message_4.params["result"])

    @async_test
    async def test_unsubscribe(self):
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        subscribe_request = BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE,
                                             ["foo", {}])
        rpc_handler = self.rpc.get_request_handler(subscribe_request)
        result = await rpc_handler.process_request()
        subscriber_id = result.result

        # message is received
        next_message_task: Future[BxJsonRpcRequest] = asyncio.ensure_future(
            self.rpc.get_next_subscribed_message())
        await asyncio.sleep(0)
        self.assertFalse(next_message_task.done())
        feed.publish("foobar")
        await asyncio.sleep(0)  # publish to subscriber
        await asyncio.sleep(0)  # subscriber publishes to queue
        self.assertTrue(next_message_task.done())

        unsubscribe_request = BxJsonRpcRequest("1", RpcRequestType.UNSUBSCRIBE,
                                               [subscriber_id])
        rpc_handler = self.rpc.get_request_handler(unsubscribe_request)
        result = await rpc_handler.process_request()
        self.assertTrue(result.result)

        next_message_task: Future[BxJsonRpcRequest] = asyncio.ensure_future(
            self.rpc.get_next_subscribed_message())
        feed.publish("foobar_not_received")
        feed.publish("foobar_not_received_2")
        await asyncio.sleep(0)  # publish to subscriber
        await asyncio.sleep(0)  # subscriber publishes to queue
        self.assertFalse(next_message_task.done())  # no message

        self.assertEqual(0, len(self.rpc.subscriptions))
        self.assertEqual(0, self.feed_manager.feeds["foo"].subscriber_count())

    @async_test
    async def test_close_bad_subscribers(self):
        self.rpc.subscribed_messages = asyncio.Queue(5)

        close_listener = asyncio.create_task(self.rpc.wait_for_close())

        feed1 = TestFeed("foo1")
        self.feed_manager.register_feed(feed1)

        rpc_request = BxJsonRpcRequest("1", RpcRequestType.SUBSCRIBE,
                                       ["foo1", {}])
        await self.rpc.get_request_handler(rpc_request).process_request()

        for i in range(10):
            feed1.publish(i)

        await asyncio.sleep(0.1)

        self.assertTrue(self.rpc.disconnect_event.is_set())
        self.assertTrue(close_listener.done())

    @async_test
    async def tearDown(self) -> None:
        self.rpc.close()