Example #1
0
    def test_manager_on_update_rows(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)

        # 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": 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
Example #2
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)
Example #3
0
    def test_manager_view_schema(self):
        post_callback = partial(self.validate_post,
                                expected={
                                    "id": 1,
                                    "data": {
                                        "a": "integer",
                                        "b": "integer"
                                    }
                                })

        message = {
            "id": 1,
            "name": "view1",
            "cmd": "view_method",
            "method": "schema",
            "args": [False]
        }
        manager = PerspectiveManager()
        table = Table(data)
        view = table.view(row_pivots=["a"])
        manager.host_table("table1", table)
        manager.host_view("view1", view)
        manager._process(message, post_callback)
Example #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
Example #5
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)
Example #6
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 == {}
Example #7
0
 def test_manager_create_view_two(self):
     message = {
         "id": 1,
         "table_name": "table1",
         "view_name": "view1",
         "cmd": "view",
         "config": {
             "row_pivots": ["a"],
             "column_pivots": ["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]
     }
Example #8
0
    def test_manager_remove_update(self, sentinel):
        s = sentinel(0)

        def update_callback():
            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)
        view.remove_update(update_callback)

        # 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"]
            }]
        }
        manager._process(update1, self.post)
        manager._process(update2, self.post)
        assert s.get() == 0
Example #9
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"
                 }))
Example #10
0
    def test_manager_on_update_through_wire_API(self, sentinel):
        s = sentinel(0)

        # 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"])

        # 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"}
        manager._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"]}]}
        manager._process(update1, self.post)
        manager._process(update2, self.post)
        assert s.get() == 200
Example #11
0
    def test_manager_on_delete_view(self, sentinel):
        s = sentinel(False)

        def delete_callback():
            s.set(True)

        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)

        view = manager._get_view("view1")
        view.on_delete(delete_callback)

        delete_view = {"id": 3, "name": "view1", "cmd": "view_method", "method": "delete"}

        manager._process(delete_view, self.post)

        assert len(manager._views) == 0
        assert s.get() is True
Example #12
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
Example #13
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
Example #14
0
 def test_manager_create_table(self):
     message = {"id": 1, "name": "table1", "cmd": "table", "args": [data]}
     manager = PerspectiveManager()
     manager._process(message, self.post)
     assert manager._tables["table1"].schema() == {"a": int, "b": str}