Beispiel #1
0
    def test_deliver_delta_without_dealer(self):
        dm = DealerManager()

        # Send a delta of a model class without dealers
        delta = InsertionDelta('test_model', {'id': 1})

        with self.assertRaises(UnknownModelClass):
            dm.deliver_delta(delta)
Beispiel #2
0
    def test_deliver_delta_other_model_class(self):
        dm = DealerManager()
        dm.register_dealer(self.dealer1)

        # Send a delta of a model class without dealers
        delta = InsertionDelta('unknown_model', {'id': 1})

        with self.assertRaises(UnknownModelClass):
            dm.deliver_delta(delta)
Beispiel #3
0
    def test_deliver_delta(self):
        dm = DealerManager()
        dm.register_dealer(self.dealer1)

        # Send a delta of the same model class of the registered dealer
        delta = InsertionDelta('test_model', {'id': 1})
        dm.deliver_delta(delta)

        self.dealer1.deliver_delta.assert_called_once_with(delta)
Beispiel #4
0
    def test_unrelated_creation(self):
        dealer = PlayersWithColorDealer()
        dealer.add_subscription_item(self.subscription_item)

        # Alice record is created with color blue
        original_delta = InsertionDelta('player',
                {'id': 1, 'name': 'Alice', 'color': 'blue'})

        dealer.deliver_delta(original_delta)

        # No delta is received
        self.assertFalse(self.deliver_delta.called)
Beispiel #5
0
    def test_update_creation(self):
        dealer = PlayersWithColorDealer()
        dealer.add_subscription_item(self.subscription_item)

        # Alice changes her color
        original_delta = UpdateDelta('player',
                old_data={'id': 1, 'name': 'Alice', 'color': 'blue'},
                new_data={'id': 1, 'name': 'Alice', 'color': 'red'})

        dealer.deliver_delta(original_delta)

        # Subscription item should receive a creation
        self.deliver_delta.assert_called_once_with(
            InsertionDelta("player", {
                'id': 1,
                'name': 'Alice',
                'color': 'red'
            }))
Beispiel #6
0
    def publishDeltas(self, req, deltas):
        """Distributes one or more deltas to the appropriate dealers which, in
        turn, will distribute them to browser clients.

        :param list deltas: A list of deltas represented as dictionaries.
        """
        # deltas = [{
        #    "type": "insert",
        #    "model": "player",
        #    "data": { "color": "blue" }
        # }]
        obj_deltas = []
        try:
            for delta in deltas:
                snorky_log.info(delta)

                delta_type = delta["type"]
                model = delta["model"]
                if not is_string(model):
                    raise RPCError("model must be string")

                if delta_type == "insert":
                    obj_delta = InsertionDelta(model, delta["data"])
                elif delta_type == "delete":
                    obj_delta = DeletionDelta(model, delta["data"])
                elif delta_type == "update":
                    obj_delta = UpdateDelta(model, delta["newData"],
                                            delta["oldData"])
                else:
                    raise RPCError("Invalid delta type")

                obj_deltas.append(obj_delta)
        except KeyError:
            raise RPCError("Missing field")

        for delta_obj in obj_deltas:
            self.frontend.dm.deliver_delta(delta_obj)
Beispiel #7
0
    def test_insertion(self):
        insertion = InsertionDelta('foo', {'id': 1, 'name': 'Alice'})
        self.dealer.deliver_delta(insertion)

        self.deliver_delta.assert_called_once_with(insertion)
Beispiel #8
0
    def deliver_delta(self, delta):
        """Receives a delta, computes a set of destination subscriptions
        items and forwards the delta to them.

        Please note that altough InsertionDelta and DeletionDelta will
        always trigger deltas of the same time on the client, UpdateDelta
        may not. To understand this fact, see the next example:

        Suppose our model class composes a player name and a color, i.e.
        'id: 1, name: Alice, color: blue'.

        We may also have a dealer named 'Players with color' that uses the
        `color` attribute to filter players.

        A client maybe subscribed to players with color red, showing them in a
        list. Now, if Alice changes its color to red, this client will receive
        a insertion delta instead of an update one because they had no previous
        knowledge of Alice's model and will have to render it as a new row.

        If then Alice decides to change her player name, the client will
        receive a delta update because they already knew Alice's model.

        And lastly, if Alice changes its color again to other than red the new
        model will no longer satisfy the filter and thus a deletion delta will
        be sent to the client.
        """

        if isinstance(delta, InsertionDelta) or \
           isinstance(delta, DeletionDelta):
            deliver_to = self.get_subscription_items_for_model(delta.data)

            for subscription_item in deliver_to:
                subscription_item.subscription.deliver_delta(delta)

        else:
            # If origin delta is an update
            model = delta.model
            new_data = delta.new_data
            old_data = delta.old_data

            set_old = self.get_subscription_items_for_model(old_data)
            set_new = self.get_subscription_items_for_model(new_data)

            # Prepare every type of destination delta
            insertion_delta = InsertionDelta(model, new_data)
            update_delta = delta
            deletion_delta = DeletionDelta(model, old_data)

            # For the subscription items that do not match the filter with the
            # old data but do with the new data, send a insertion delta.
            for item in set_new - set_old:
                item.subscription.deliver_delta(insertion_delta)

            # For the subscription items that match the filter with both the
            # new and old data, send an update delta.
            for item in set_old.intersection(set_new):
                item.subscription.deliver_delta(update_delta)

            # For the subscription items that match the filter with the old
            # data but do not match with the new data, send a deletion delta.
            for item in set_old - set_new:
                item.subscription.deliver_delta(deletion_delta)