예제 #1
0
    def test_manager_table_schema(self):
        post_callback = partial(self.validate_post,
                                expected={
                                    "id": 1,
                                    "data": {
                                        "a": "integer",
                                        "b": "string"
                                    }
                                })

        message = {
            "id": 1,
            "name": "table1",
            "cmd": "table_method",
            "method": "schema",
            "args": [False]
        }
        manager = PerspectiveManager()
        table = Table(data)
        view = table.view()
        manager.host_table("table1", table)
        manager.host_view("view1", view)
        manager._process(message, post_callback)
예제 #2
0
    def test_manager_on_update(self, sentinel):
        s = sentinel(0)

        def update_callback(port_id):
            s.set(s.get() + 1)

        # create a table and view using manager
        make_table = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
        manager = PerspectiveManager()
        manager._process(make_table, self.post)
        make_view = {"id": 2, "table_name": "table1", "view_name": "view1", "cmd": "view"}
        manager._process(make_view, self.post)

        # hook into the created view and pass it the callback
        view = manager._views["view1"]
        view.on_update(update_callback)

        # call updates
        update1 = {"id": 3, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [4], "b": ["d"]}]}
        update2 = {"id": 4, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [5], "b": ["e"]}]}
        manager._process(update1, self.post)
        manager._process(update2, self.post)
        assert s.get() == 2
예제 #3
0
def make_app():
    here = os.path.abspath(os.path.dirname(__file__))

    DATA_HOST = DataHost()
    MANAGER = PerspectiveManager(lock=True)
    STATE_TABLE = DATA_HOST.state_table
    COUNTY_TABLE = DATA_HOST.county_table
    MANAGER.host_view("state_data_source", STATE_TABLE.view())
    MANAGER.host_view("county_data_source", COUNTY_TABLE.view())

    return tornado.web.Application([
        (r"/", MainHandler),
        # create a websocket endpoint that the client Javascript can access
        (r"/static/(.*)", StaticHandler, {"path": os.path.join(here, "static")}),
        (r"/ws", PerspectiveTornadoHandler, {"manager": MANAGER, "check_origin": True})
    ])
예제 #4
0
 def test_manager_delete_view(self):
     make_table = {
         "id": 1,
         "name": "table1",
         "cmd": "table",
         "args": [data]
     }
     manager = PerspectiveManager()
     manager._process(make_table, self.post)
     make_view = {
         "id": 2,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view"
     }
     manager._process(make_view, self.post)
     delete_view = {
         "id": 3,
         "name": "view1",
         "cmd": "view_method",
         "method": "delete"
     }
     manager._process(delete_view, self.post)
     assert len(manager._views) == 0
예제 #5
0
    def test_manager_set_queue_process(self, sentinel):
        s = sentinel(0)
        manager = PerspectiveManager()
        table = Table({"a": [1, 2, 3]})
        manager.host_table("tbl", table)
        table.update({"a": [4, 5, 6]})
        assert table.view().to_dict() == {
            "a": [1, 2, 3, 4, 5, 6]
        }

        def fake_queue_process(table_id, state_manager):
            s.set(s.get() + 1)
            state_manager.call_process(table_id)

        manager._set_queue_process(fake_queue_process)
        table.update({"a": [7, 8, 9]})
        assert s.get() == 1
예제 #6
0
    def test_async_queue_process_csv(self):
        """Make sure GIL release during CSV loading works"""
        tbl = Table("x,y,z\n1,a,true\n2,b,false\n3,c,true\n4,d,false")
        manager = PerspectiveManager()
        manager.set_loop_callback(TestAsync.loop.add_callback)
        manager.host(tbl)

        @syncify
        def _task():
            assert tbl.size() == 4
            for i in range(5):
                tbl.update("x,y,z\n1,a,true\n2,b,false\n3,c,true\n4,d,false")
            return tbl.size()

        assert _task() == 24

        tbl.delete()
예제 #7
0
 def test_manager_clear_view(self):
     messages = [{
         "id": 1,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view"
     }, {
         "id": 2,
         "table_name": "table1",
         "view_name": "view2",
         "cmd": "view"
     }, {
         "id": 3,
         "table_name": "table1",
         "view_name": "view3",
         "cmd": "view"
     }]
     manager = PerspectiveManager()
     table = Table(data)
     manager.host_table("table1", table)
     for message in messages:
         manager._process(message, self.post, client_id=1)
     manager.clear_views(1)
     assert manager._views == {}
예제 #8
0
    def test_manager_table_get_computation_input_types(self):
        post_callback = partial(self.validate_post, expected={
            "id": 1,
            "data": ["string"]
        })

        message = {
            "id": 1,
            "name": "table1",
            "cmd": "table_method",
            "method": "get_computation_input_types",
            "args": ["concat_comma"]
        }
        manager = PerspectiveManager()
        table = Table(data)
        manager.host_table("table1", table)
        manager._process(message, post_callback)
예제 #9
0
    def test_manager_set_queue_process(self, sentinel):
        s = sentinel(0)
        manager = PerspectiveManager()
        table = Table({"a": [1, 2, 3]})
        manager.host_table("tbl", table)
        table.update({"a": [4, 5, 6]})
        assert table.view().to_dict() == {
            "a": [1, 2, 3, 4, 5, 6]
        }

        def fake_queue_process(f, *args, **kwargs):
            s.set(s.get() + 1)
            f(*args, **kwargs)

        manager.set_loop_callback(fake_queue_process)
        table.update({"a": [7, 8, 9]})
        assert s.get() == 2
예제 #10
0
 def test_manager_clear_view_no_client_id(self):
     messages = [{
         "id": 1,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view"
     }, {
         "id": 2,
         "table_name": "table1",
         "view_name": "view2",
         "cmd": "view"
     }, {
         "id": 3,
         "table_name": "table1",
         "view_name": "view3",
         "cmd": "view"
     }]
     manager = PerspectiveManager()
     table = Table(data)
     manager.host_table("table1", table)
     for message in messages:
         manager._process(message, self.post)
     with raises(PerspectiveError):
         manager.clear_views(None)
예제 #11
0
    def test_manager_create_indexed_table(self):
        message = {
            "id": 1,
            "name": "table1",
            "cmd": "table",
            "args": [data],
            "options": {
                "index": "a"
            }
        }
        manager = PerspectiveManager()
        table = Table(data)
        manager.host_table("table1", table)
        manager._process(message, self.post)
        assert manager._tables["table1"].schema() == {"a": int, "b": str}

        assert manager._tables["table1"]._index == "a"
예제 #12
0
def make_app():
    manager = PerspectiveManager()

    # Run Perspective in its own thread with its own IOLoop
    thread = threading.Thread(target=perspective_thread, args=(manager, ))
    thread.daemon = True
    thread.start()

    return tornado.web.Application(
        [
            (
                r"/websocket",
                PerspectiveTornadoHandler,
                {
                    "manager": manager,
                    "check_origin": True
                },
            ),
            (
                r"/node_modules/(.*)",
                tornado.web.StaticFileHandler,
                {
                    "path": "../../../node_modules/@finos/"
                },
            ),
            (
                r"/(.*)",
                tornado.web.StaticFileHandler,
                {
                    "path": os.path.join(here, "..", "dist"),
                    "default_filename": "index.html",
                },
            ),
        ],
        websocket_ping_interval=15,
    )
예제 #13
0
 def test_manager_create_view_one(self):
     message = {
         "id": 1,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view",
         "config": {
             "row_pivots": ["a"]
         }
     }
     manager = PerspectiveManager()
     table = Table(data)
     manager.host_table("table1", table)
     manager._process(message, self.post)
     assert manager._views["view1"].to_dict() == {
         "__ROW_PATH__": [[], ["1"], ["2"], ["3"]],
         "a": [6, 1, 2, 3],
         "b": [3, 1, 1, 1]
     }
예제 #14
0
    def test_async_queue_process(self):
        tbl = Table({"a": int, "b": float, "c": str})
        manager = PerspectiveManager()
        manager._set_queue_process(TestAsync.wrapped_queue_process)
        manager.host(tbl)

        assert tbl.size() == 0

        for i in range(5):
            tbl.update([data[i]])

        table_id = tbl._table.get_id()
        pool = tbl._table.get_pool()

        assert _PerspectiveStateManager.TO_PROCESS == {table_id: pool}
        assert tbl.view().to_records() == data[:5]

        # should have flushed the process queue
        assert _PerspectiveStateManager.TO_PROCESS == {}
예제 #15
0
    def test_async_queue_process(self):
        tbl = Table({
            "a": int,
            "b": float,
            "c": str
        })
        manager = PerspectiveManager()
        manager._set_queue_process(TestAsync.wrapped_queue_process)
        manager.host(tbl)

        assert tbl.size() == 0

        for i in range(5):
            tbl.update([data[i]])

        # process should have been called at least once
        assert SENTINEL.get() > 0

        tbl.delete()
예제 #16
0
    def test_async_queue_process_multiple_ports(self):
        tbl = Table({
            "a": int,
            "b": float,
            "c": str
        })

        port_ids = [0]
        port_data = [{
            "a": 0,
            "b": 0,
            "c": "0"
        }]

        for i in range(10):
            port_id = tbl.make_port()
            port_ids.append(port_id)
            port_data.append({
                "a": port_id,
                "b": port_id * 1.5,
                "c": str(port_id)
            })

        assert port_ids == list(range(0, 11))

        manager = PerspectiveManager()
        manager._set_queue_process(TestAsync.wrapped_queue_process)
        manager.host(tbl)

        assert tbl.size() == 0

        random.shuffle(port_ids)

        for port_id in port_ids:
            idx = port_id if port_id < len(port_ids) else len(port_ids) - 1
            tbl.update([port_data[idx]], port_id=port_id)

        # assert that process is being called asynchronously
        assert SENTINEL.get() > 0

        tbl.delete()
예제 #17
0
    def test_manager_table_validate_expressions(self):
        post_callback = partial(self.validate_post, expected={
            "id": 1,
            "data": {
                "expression_schema": {
                    "abc": "float"
                },
                "errors": {}
            }
        })

        message = {
            "id": 1,
            "name": "table1",
            "cmd": "table_method",
            "method": "validate_expressions",
            "args": [['// abc \n "a" + "a"']]
        }
        manager = PerspectiveManager()
        table = Table(data)
        manager.host_table("table1", table)
        manager._process(message, post_callback)
예제 #18
0
    def test_session_new_session(self, sentinel):
        s = sentinel(False)

        def handle_to_dict(msg):
            s.set(True)
            message = json.loads(msg)
            assert message["data"] == data

        message = {
            "id": 1,
            "table_name": "table1",
            "view_name": "view1",
            "cmd": "view"
        }

        manager = PerspectiveManager()
        session = manager.new_session()
        client_id = session.client_id
        table = Table(data)

        manager.host_table("table1", table)

        # create a view through the session to make sure it has a client id
        session.process(message, self.post)

        # make sure the client ID is attached to the new view
        assert len(manager._views.keys()) == 1
        assert manager._get_view("view1")._client_id == client_id

        to_dict_message = {
            "id": 2,
            "name": "view1",
            "cmd": "view_method",
            "method": "to_dict"
        }

        session.process(to_dict_message, handle_to_dict)
        assert s.get() is True
예제 #19
0
def make_app():
    # Create an instance of `PerspectiveManager` and a table.
    MANAGER = PerspectiveManager()
    TABLE = None

    TABLE = Table(pd.read_csv(os.path.join(here, "superstore.csv")),
                  index="Row ID")

    # Track the table with the name "data_source_one", which will be used in
    # the front-end to access the Table.
    MANAGER.host_table("data_source_one", TABLE)
    MANAGER.host_view("view_one", TABLE.view())

    return tornado.web.Application(
        [
            (r"/", MainHandler),
            # create a websocket endpoint that the client Javascript can access
            (r"/websocket", PerspectiveTornadoHandler, {
                "manager": MANAGER,
                "check_origin": True
            })
        ],
        websocket_ping_interval=15)
예제 #20
0
 def test_manager_create_view_two(self):
     message = {
         "id": 1,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view",
         "config": {
             "group_by": ["a"],
             "split_by": ["b"]
         }
     }
     manager = PerspectiveManager()
     table = Table(data)
     manager.host_table("table1", table)
     manager._process(message, self.post)
     assert manager._views["view1"].to_dict() == {
         "__ROW_PATH__": [[], [1], [2], [3]],
         "a|a": [1, 1, None, None],
         "a|b": [1, 1, None, None],
         "b|a": [2, None, 2, None],
         "b|b": [1, None, 1, None],
         "c|a": [3, None, None, 3],
         "c|b": [1, None, None, 1]
     }
예제 #21
0
    def test_session_close_multiple_sessions_with_callbacks(self, sentinel):
        s = sentinel(0)

        manager = PerspectiveManager()
        sessions = [manager.new_session() for i in range(5)]

        # create a table and view using manager
        make_table = {
            "id": 1,
            "name": "table1",
            "cmd": "table",
            "args": [data]
        }
        manager._process(make_table, self.post)

        # create a view on each session
        for i, session in enumerate(sessions):
            # IDs have to conflict - each viewer will send the first message as
            # ID = 1, so we need to make sure we handle that.
            msg = {
                "id": 2,
                "table_name": "table1",
                "view_name": "view" + str(i),
                "cmd": "view"
            }
            session.process(msg, self.post)

        manager_views = list(manager._views.keys())
        for key in ["view" + str(i) for i in range(5)]:
            assert key in manager_views

        for i, session in enumerate(sessions):
            view = manager._get_view("view" + str(i))
            assert view._client_id == session.client_id

        def callback(updated):
            assert updated["port_id"] == 0
            s.set(s.get() + 100)

        # simulate a client that holds callbacks by id
        callbacks = {3: callback}

        def post_update(msg):
            # when `on_update` is triggered, this callback gets the message
            # and has to decide which callback to trigger.
            message = json.loads(msg)
            assert message["id"] is not None
            if message["id"] == 3:
                # trigger callback
                assert message["data"] == {"port_id": 0}
                callbacks[message["id"]](message["data"])

        # create a view and an on_update on each session
        for i, session in enumerate(sessions):
            view_name = "view" + str(i)
            # IDs have to conflict - each viewer will send the first message as
            # ID = 1, so we need to make sure we handle that.
            msg = {
                "id": 2,
                "table_name": "table1",
                "view_name": view_name,
                "cmd": "view"
            }
            session.process(msg, self.post)
            make_on_update = {
                "id": 3,
                "name": view_name,
                "cmd": "view_method",
                "subscribe": True,
                "method": "on_update",
                "callback_id": "callback_1"
            }
            session.process(make_on_update, post_update)

        # call updates using a random session - they should propagate
        random_session_id = random.randint(0, 4)
        random_session = sessions[random_session_id]
        random_client_id = random_session.client_id

        update1 = {
            "id": 4,
            "name": "table1",
            "cmd": "table_method",
            "method": "update",
            "args": [{
                "a": [4],
                "b": ["d"]
            }]
        }
        update2 = {
            "id": 5,
            "name": "table1",
            "cmd": "table_method",
            "method": "update",
            "args": [{
                "a": [5],
                "b": ["e"]
            }]
        }

        random_session.process(update1, self.post)
        random_session.process(update2, self.post)

        # all updates processed, all callbacks fired
        assert s.get() == 1000

        # close a random session, and make sure the other views and callbacks
        # are not affected
        random_session.close()

        # make sure the view is gone - but not the table
        assert "table1" in manager._tables

        assert "view" + str(random_session_id) not in manager._views.keys()
        assert len(manager._views.keys()) == 4

        for callback in manager._callback_cache:
            assert callback["client_id"] != random_client_id

        assert len(manager._callback_cache) == 4
예제 #22
0
    def test_session_close_session_with_callbacks(self, sentinel):
        s = sentinel(0)

        manager = PerspectiveManager()
        session = manager.new_session()
        client_id = session.client_id

        # create a table and view using manager
        make_table = {
            "id": 1,
            "name": "table1",
            "cmd": "table",
            "args": [data]
        }
        session.process(make_table, self.post)

        make_view = {
            "id": 2,
            "table_name": "table1",
            "view_name": "view1",
            "cmd": "view"
        }
        session.process(make_view, self.post)

        # make sure the client ID is attached to the new view
        assert len(manager._views.keys()) == 1
        assert manager._get_view("view1")._client_id == client_id

        def callback(updated):
            assert updated["port_id"] == 0
            s.set(s.get() + 100)

        # simulate a client that holds callbacks by id
        callbacks = {3: callback}

        def post_update(msg):
            # when `on_update` is triggered, this callback gets the message
            # and has to decide which callback to trigger.
            message = json.loads(msg)
            assert message["id"] is not None
            if message["id"] == 3:
                # trigger callback
                assert message["data"] == {"port_id": 0}
                callbacks[message["id"]](message["data"])

        # hook into the created view and pass it the callback
        make_on_update = {
            "id": 3,
            "name": "view1",
            "cmd": "view_method",
            "subscribe": True,
            "method": "on_update",
            "callback_id": "callback_1"
        }
        session.process(make_on_update, post_update)

        # call updates
        update1 = {
            "id": 4,
            "name": "table1",
            "cmd": "table_method",
            "method": "update",
            "args": [{
                "a": [4],
                "b": ["d"]
            }]
        }
        update2 = {
            "id": 5,
            "name": "table1",
            "cmd": "table_method",
            "method": "update",
            "args": [{
                "a": [5],
                "b": ["e"]
            }]
        }

        session.process(update1, self.post)
        session.process(update2, self.post)

        assert s.get() == 200

        # close the session
        session.close()

        # make sure the view is gone - but not the table
        assert "table1" in manager._tables
        assert manager._views == {}
        assert len(manager._callback_cache) == 0
예제 #23
0
    def test_manager_remove_update_through_wire_API(self, sentinel):
        s = sentinel(0)

        def update_callback(port_id, delta):
            s.set(s.get() + 1)

        # create a table and view using manager
        make_table = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
        manager = PerspectiveManager()
        manager._process(make_table, self.post)
        make_view = {"id": 2, "table_name": "table1", "view_name": "view1", "cmd": "view"}
        manager._process(make_view, self.post)

        def callback(updated):
            assert updated["port_id"] == 0
            s.set(s.get() + 100)

        # simulate a client that holds callbacks by id
        callbacks = {
            3: callback
        }

        def post_update(msg):
            # when `on_update` is triggered, this callback gets the message
            # and has to decide which callback to trigger.
            message = json.loads(msg)
            assert message["id"] is not None
            if message["id"] == 3:
                # trigger callback
                assert message["data"] == {
                    "port_id": 0
                }
                callbacks[message["id"]](message["data"])

        # create an on_update callback
        make_on_update = {"id": 3, "name": "view1", "cmd": "view_method", "subscribe": True, "method": "on_update", "callback_id": "callback_1"}
        manager._process(make_on_update, post_update)

        # call updates
        update1 = {"id": 4, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [4], "b": ["d"]}]}
        manager._process(update1, self.post)

        # remove update callback
        remove_on_update = {"id": 5, "name": "view1", "cmd": "view_method", "subscribe": True, "method": "remove_update", "callback_id": "callback_1"}
        manager._process(remove_on_update, self.post)

        update2 = {"id": 6, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [5], "b": ["e"]}]}
        manager._process(update2, self.post)
        assert s.get() == 100
예제 #24
0
    def test_manager_on_update_rows_with_port_id_through_wire_API(self, sentinel):
        s = sentinel(0)

        def update_callback(port_id, delta):
            table = Table(delta)
            assert table.size() == 1
            assert table.schema() == {
                "a": int,
                "b": str
            }
            table.delete()
            s.set(s.get() + 1)

        # create a table and view using manager
        make_table = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
        manager = PerspectiveManager()
        manager._process(make_table, self.post)
        make_view = {"id": 2, "table_name": "table1", "view_name": "view1", "cmd": "view"}
        manager._process(make_view, self.post)

        # Get two ports on the table
        make_port = {"id": 3, "name": "table1", "cmd": "table_method", "method": "make_port"}
        make_port2 = {"id": 4, "name": "table1", "cmd": "table_method", "method": "make_port"}

        manager._process(make_port, self.post)
        manager._process(make_port2, self.post)

        # define an update callback
        def callback(delta):
            table = Table(delta)
            assert table.size() == 1
            assert table.schema() == {
                "a": int,
                "b": str
            }
            table.delete()
            s.set(s.get() + 100)

        # simulate a client that holds callbacks by id
        callbacks = {
            3: callback
        }

        def post_update(msg, binary=False):
            # when `on_update` is triggered, this callback gets the message
            # and has to decide which callback to trigger.
            if binary:
                # trigger callback - "msg" here is binary
                callbacks[3](msg)
                return

            message = json.loads(msg)

            assert message["id"] is not None

            if message["id"] == 3:
                # wait for transferable
                assert message["data"]["port_id"] in (1, 2)
                return

        # hook into the created view and pass it the callback
        make_on_update = {
            "id": 5,
            "name": "view1",
            "cmd": "view_method",
            "subscribe": True,
            "method": "on_update",
            "callback_id": "callback_1",
            "args": [{"mode": "row"}]
        }
        manager._process(make_on_update, post_update)

        # call updates
        update1 = {"id": 6, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [4], "b": ["d"]}, {"port_id": 1}]}
        update2 = {"id": 7, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [5], "b": ["e"]}, {"port_id": 2}]}

        manager._process(update1, self.post)
        manager._process(update2, self.post)

        assert s.get() == 200
예제 #25
0
    def test_manager_on_update_rows_with_port_id(self, sentinel):
        s = sentinel(0)

        def update_callback(port_id, delta):
            table = Table(delta)
            assert table.size() == 1
            assert table.schema() == {
                "a": int,
                "b": str
            }
            table.delete()
            s.set(s.get() + 1)

        # create a table and view using manager
        make_table = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
        manager = PerspectiveManager()
        manager._process(make_table, self.post)
        make_view = {"id": 2, "table_name": "table1", "view_name": "view1", "cmd": "view"}
        manager._process(make_view, self.post)

        # Get two ports on the table
        make_port = {"id": 3, "name": "table1", "cmd": "table_method", "method": "make_port"}
        make_port2 = {"id": 4, "name": "table1", "cmd": "table_method", "method": "make_port"}

        manager._process(make_port, self.post)
        manager._process(make_port2, self.post)

        # hook into the created view and pass it the callback
        view = manager._views["view1"]
        view.on_update(update_callback, mode="row")

        # call updates
        update1 = {"id": 5, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [4], "b": ["d"]}, {"port_id": 1}]}
        update2 = {"id": 6, "name": "table1", "cmd": "table_method", "method": "update", "args": [{"a": [5], "b": ["e"]}, {"port_id": 2}]}

        manager._process(update1, self.post)
        manager._process(update2, self.post)

        assert s.get() == 2
예제 #26
0
 def test_manager_host_table_transitive(self):
     manager = PerspectiveManager()
     table = Table(data)
     manager.host_table("table1", table)
     table.update({"a": [4, 5, 6], "b": ["d", "e", "f"]})
     assert manager.get_table("table1").size() == 6
예제 #27
0
 def test_manager_host_invalid(self):
     manager = PerspectiveManager()
     with raises(PerspectiveError):
         manager.host({})
예제 #28
0
 def test_arbitary_lock_unlock_manager(self):
     manager = PerspectiveManager(lock=True)
     make_table_message = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
     manager._process(make_table_message, partial(self.validate_post, expected={
         "id": 1,
         "error": "`table` failed - access denied"
     }))
     manager.unlock()
     manager._process(make_table_message, self.post)
     assert manager._tables["table1"].schema() == {
         "a": int,
         "b": str
     }
     update_message = {"id": 2, "name": "table1", "cmd": "table_method", "method": "update", "args": [data]}
     manager._process(update_message, self.post)
     assert manager._tables["table1"].size() == 6
     manager.lock()
     update_message_new = {"id": 3, "name": "table1", "cmd": "table_method", "method": "update", "args": [data]}
     manager._process(update_message_new, partial(self.validate_post, expected={
         "id": 3,
         "error": "`table_method.update` failed - access denied"
     }))
예제 #29
0
    def test_session_multiple_new_sessions(self, sentinel):
        s = sentinel(0)

        def handle_to_dict(msg):
            s.set(s.get() + 1)

            message = json.loads(msg)

            assert message["data"] == {
                "a": [1, 2, 3, 1, 2, 3],
                "b": ["a", "b", "c", "str1", "str2", "str3"]
            }

        manager = PerspectiveManager()
        sessions = [manager.new_session() for i in range(5)]
        table = Table(data)

        manager.host_table("table1", table)

        # create a view on each session
        for i, session in enumerate(sessions):
            # IDs have to conflict - each viewer will send the first message as
            # ID = 1, so we need to make sure we handle that.
            msg = {
                "id": 1,
                "table_name": "table1",
                "view_name": "view" + str(i),
                "cmd": "view"
            }
            session.process(msg, self.post)

        manager_views = list(manager._views.keys())
        for key in ["view" + str(i) for i in range(5)]:
            assert key in manager_views

        for i, session in enumerate(sessions):
            view = manager._get_view("view" + str(i))
            assert view._client_id == session.client_id

        # arbitrarily do an update
        random_session_id = random.randint(0, 4)
        update_message = {
            "id": 2,
            "name": "table1",
            "cmd": "table_method",
            "method": "update",
            "args": [{
                "a": [1, 2, 3],
                "b": ["str1", "str2", "str3"]
            }]
        }
        sessions[random_session_id].process(update_message, self.post)

        # should reflect in all sessions
        for i, session in enumerate(sessions):
            to_dict_message = {
                "id": 3,
                "name": "view" + str(i),
                "cmd": "view_method",
                "method": "to_dict"
            }
            session.process(to_dict_message, handle_to_dict)

        assert s.get() == 5
예제 #30
0
    def start(self):
        if self.debug:
            logging.getLogger().setLevel(logging.DEBUG)

        self.port = int(os.environ.get('PORT', self.port))
        self.wspath = self.wspath.format(self.port)

        self._stash = []
        engine = create_engine(self.sql_url, echo=False)
        Base.metadata.create_all(engine)

        self.sessionmaker = sessionmaker(bind=engine)
        session = self.sessionmaker()
        clients = session.query(Client).all()

        self._clients = {c.client_id: c for c in clients}
        self._manager = PerspectiveManager()

        self._competitions = Table(
            list(c.to_dict() for c in session.query(Competition).all()))
        self._submissions = Table(
            list(s.to_dict() for s in session.query(Submission).all()))
        self._leaderboards = Table({"a": int})
        self._stash = []
        self._table = Table([{"a": 1, "b": 2}])
        self._manager.host_table("data_source_one", self._table)
        self._manager.host_table("competitions", self._competitions)
        self._manager.host_table("submissions", self._submissions)
        self._manager.host_table("leaderboards", self._leaderboards)

        root = os.path.join(os.path.dirname(__file__), 'assets')
        static = os.path.join(root, 'static')

        context = {
            'sessionmaker': self.sessionmaker,
            'clients': self._clients,
            'competitions': self._competitions,
            'submissions': self._submissions,
            'leaderboards': self._leaderboards,
            'stash': self._stash,
            'basepath': self.basepath,
            'wspath': self.wspath,
            'proxies': 'test'
        }

        default_handlers = [
            (r"/", HTMLOpenHandler, {
                'template': 'index.html',
                'context': context
            }),
            (r"/index.html", HTMLOpenHandler, {
                'template': 'index.html',
                'context': context,
                'template_kwargs': {}
            }),
            (r"/home", HTMLOpenHandler, {
                'template': 'home.html',
                'context': context
            }),
            (r"/login", HTMLOpenHandler, {
                'template': 'login.html',
                'context': context
            }),
            (r"/register", HTMLOpenHandler, {
                'template': 'login.html',
                'context': context
            }),
            (r"/logout", HTMLOpenHandler, {
                'template': 'logout.html',
                'context': context
            }),
        ]

        default_handlers.extend([
            (r"/api/v1/login", LoginHandler, context),
            (r"/api/v1/logout", LogoutHandler, context),
            (r"/api/v1/register", RegisterHandler, context),
            (r"/api/v1/apikeys", APIKeyHandler, context),
            (r"/api/v1/competition", CompetitionHandler, context),
            (r"/api/v1/wscompetition", PerspectiveTornadoHandler, {
                "manager": self._manager,
                "check_origin": True
            }), (r"/api/v1/submission", SubmissionHandler, context),
            (r"/api/v1/leaderboard", LeaderboardHandler, context),
            (r"/static/(.*)", tornado.web.StaticFileHandler, {
                "path": static
            }),
            (r"/(.*)", HTMLOpenHandler, {
                'template': '404.html',
                'context': context
            })
        ])

        for handler in self.handlers:
            for i, default in enumerate(default_handlers):
                if default[0] == handler[0]:
                    # override default handler
                    d = default[2]
                    d.update(handler[2])
                    default_handlers[i] = (handler[0], handler[1], d)

        settings = {
            "cookie_secret": self.cookie_secret,
            "login_url": self.basepath + "login",
            "debug": self.debug,
            "template_path": os.path.join(root, 'templates'),
        }

        application = tornado.web.Application(default_handlers, **settings)

        logging.critical('LISTENING: %d', self.port)
        application.listen(self.port)
        tornado.ioloop.IOLoop.current().start()