Beispiel #1
0
    def test_init(self):
        q = roster_xso.Query()
        self.assertIsNone(q.ver)
        self.assertSequenceEqual([], q.items)

        item = roster_xso.Item(TEST_JID)
        q = roster_xso.Query(
            ver="foobar",
            items=(item,)
        )
        self.assertEqual("foobar", q.ver)
        self.assertSequenceEqual([item], q.items)
        self.assertIsInstance(q.items, xso_model.XSOList)
Beispiel #2
0
    def test_groups_update_fires_events(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user1,
                groups=[roster_xso.Group(name="group4")],
            )
        ])

        added_cb = unittest.mock.Mock()
        added_cb.return_value = False
        removed_cb = unittest.mock.Mock()
        removed_cb.return_value = False

        with contextlib.ExitStack() as stack:
            stack.enter_context(
                self.s.on_entry_added_to_group.context_connect(added_cb))
            stack.enter_context(
                self.s.on_entry_removed_from_group.context_connect(removed_cb))
            run_coroutine(
                self.s.handle_roster_push(
                    stanza.IQ(structs.IQType.SET, payload=request)))

        self.assertSequenceEqual([
            unittest.mock.call(self.s.items[self.user1], "group4"),
        ], added_cb.mock_calls)

        self.assertIn(unittest.mock.call(self.s.items[self.user1], "group1"),
                      removed_cb.mock_calls)

        self.assertIn(unittest.mock.call(self.s.items[self.user1], "group3"),
                      removed_cb.mock_calls)
Beispiel #3
0
    def setUp(self):
        self.cc = make_connected_client()
        self.s = roster_service.Service(self.cc)

        self.user1 = structs.JID.fromstr("*****@*****.**")
        self.user2 = structs.JID.fromstr("*****@*****.**")

        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user1,
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group3"),
                            ]),
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both",
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group2"),
                            ])
        ],
                                    ver="foobar")

        self.cc.stream.send_iq_and_wait_for_reply.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.cc.stream.send_iq_and_wait_for_reply.reset_mock()
Beispiel #4
0
    def test_item_removal_fixes_groups(self):
        request = roster_xso.Query(
            items=[roster_xso.Item(
                jid=self.user1,
                subscription="remove",
            )])

        added_cb = unittest.mock.Mock()
        added_cb.return_value = False
        removed_cb = unittest.mock.Mock()
        removed_cb.return_value = False

        with contextlib.ExitStack() as stack:
            stack.enter_context(
                self.s.on_entry_added_to_group.context_connect(added_cb))
            stack.enter_context(
                self.s.on_entry_removed_from_group.context_connect(removed_cb))
            run_coroutine(
                self.s.handle_roster_push(
                    stanza.IQ(structs.IQType.SET, payload=request)))

        self.assertSequenceEqual([], added_cb.mock_calls)
        self.assertSequenceEqual([], removed_cb.mock_calls)

        self.assertSetEqual({"group1", "group2"}, set(self.s.groups.keys()))

        self.assertSetEqual({self.s.items[self.user2]},
                            self.s.groups["group1"])

        self.assertSetEqual({self.s.items[self.user2]},
                            self.s.groups["group2"])
Beispiel #5
0
    def test_initial_roster_does_not_emit_entry_added_for_existing(self):
        old_item = self.s.items[self.user2]

        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="new name",
                            subscription="both"),
            roster_xso.Item(
                jid=self.user2.replace(localpart="user2"),
                name="other name",
            )
        ],
                                    ver="foobar")

        mock = unittest.mock.Mock()
        mock.return_value = False
        self.s.on_entry_added.connect(mock)

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.assertSequenceEqual([
            unittest.mock.call(
                self.s.items[self.user2.replace(localpart="user2")]),
        ], mock.mock_calls)
Beispiel #6
0
    def test_initial_roster_fires_group_event(self):
        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both",
                            groups={
                                roster_xso.Group(name="a"),
                                roster_xso.Group(name="b")
                            }),
            roster_xso.Item(jid=self.user1,
                            name="some foo user",
                            subscription="both",
                            groups={
                                roster_xso.Group(name="a"),
                                roster_xso.Group(name="c")
                            })
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.assertCountEqual(self.listener.on_group_added.mock_calls, [
            unittest.mock.call("a"),
            unittest.mock.call("b"),
            unittest.mock.call("c"),
        ])
Beispiel #7
0
    def test_initial_roster_fires_event(self):
        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both")
        ],
                                    ver="foobar")

        cb = unittest.mock.Mock()
        cb.return_value = True

        def cb_impl():
            cb()
            # assure that the roster update is already finished
            self.assertNotIn(self.user1, self.s.items)

        self.s.on_initial_roster_received.connect(cb_impl)

        self.cc.send.return_value = response
        self.cc.send.delay = 0.05

        task = asyncio.ensure_future(self.cc.before_stream_established())

        run_coroutine(asyncio.sleep(0.01))

        self.assertSequenceEqual([], cb.mock_calls)

        run_coroutine(asyncio.sleep(0.041))

        self.assertSequenceEqual([
            unittest.mock.call(),
        ], cb.mock_calls)
Beispiel #8
0
    def test_initial_roster_removes_contact_from_groups(self):
        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both",
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group2"),
                            ])
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.assertSetEqual(
            self.s.groups["group1"],
            {self.s.items[self.user2]},
        )

        self.assertSetEqual(
            self.s.groups["group2"],
            {self.s.items[self.user2]},
        )

        self.assertSetEqual(
            self.s.groups.get("group3", set()),
            set(),
        )
Beispiel #9
0
    def test_handle_roster_push_accepts_push_from_bare_local_jid(self):
        self.cc.local_jid = structs.JID.fromstr("[email protected]/fnord")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.from_ = structs.JID.fromstr("*****@*****.**")
        iq.payload = roster_xso.Query()

        run_coroutine(self.s.handle_roster_push(iq))
Beispiel #10
0
    def test_do_not_lose_update_during_initial_roster(self):
        self.cc.mock_calls.clear()

        initial = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both")
        ],
                                   ver="foobar")

        push = stanza.IQ(type_=structs.IQType.SET,
                         payload=roster_xso.Query(items=[
                             roster_xso.Item(
                                 jid=self.user1,
                                 name="some foo user",
                             ),
                             roster_xso.Item(
                                 jid=self.user2,
                                 subscription="remove",
                             )
                         ],
                                                  ver="foobar"))

        @asyncio.coroutine
        def send(iq, timeout=None):
            # this is brutal, but a sure way to provoke the race
            asyncio.ensure_future(self.s.handle_roster_push(push))
            # give the roster push a chance to act
            # (we cannot yield from the handle_roster_push() here: in the fixed
            # version that would be a deadlock)
            yield from asyncio.sleep(0)
            return initial

        self.cc.send = unittest.mock.Mock()
        self.cc.send.side_effect = send

        initial_roster = asyncio.ensure_future(
            self.cc.before_stream_established())

        run_coroutine(initial_roster)

        self.assertNotIn(
            self.user2, self.s.items,
            "initial roster processing lost a race against roster push")
Beispiel #11
0
    def test_handle_roster_push_rejects_push_from_full_local_jid(self):
        self.cc.local_jid = structs.JID.fromstr("[email protected]/fnord")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.from_ = structs.JID.fromstr("[email protected]/fnord")
        iq.payload = roster_xso.Query()

        with self.assertRaises(errors.XMPPAuthError) as ctx:
            run_coroutine(self.s.handle_roster_push(iq))

        self.assertEqual(errors.ErrorCondition.FORBIDDEN,
                         ctx.exception.condition)
Beispiel #12
0
    def test_send_versioned_request_if_not_supported_by_server(self):
        self.cc.stream_features[...] = roster_xso.RosterVersioningFeature()

        response = roster_xso.Query()

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        call, = self.cc.send.mock_calls
        _, call_args, call_kwargs = call

        iq_request, = call_args
        self.assertEqual("foobar", iq_request.payload.ver)
Beispiel #13
0
    def test_handle_roster_push_removes_from_roster(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user1, subscription="remove"),
        ],
                                   ver="foobarbaz")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        self.assertIsNone(run_coroutine(self.s.handle_roster_push(iq)))

        self.assertNotIn(self.user1, self.s.items)
        self.assertIn(self.user2, self.s.items)
        self.assertEqual("foobarbaz", self.s.version)
Beispiel #14
0
    def test_on_group_removed_for_removed_contact(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user2,
                subscription="remove",
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        run_coroutine(self.s.handle_roster_push(iq))

        self.listener.on_group_removed.assert_called_once_with("group2")
Beispiel #15
0
    def test_item_objects_do_not_change_during_push(self):
        old_item = self.s.items[self.user1]

        request = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user1, subscription="both"),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        self.assertIsNone(run_coroutine(self.s.handle_roster_push(iq)))

        self.assertIs(old_item, self.s.items[self.user1])
        self.assertEqual("both", old_item.subscription)
Beispiel #16
0
    def test_do_not_send_versioned_request_if_not_supported_by_server(self):
        response = roster_xso.Query()

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        call, = self.cc.send.mock_calls
        _, call_args, call_kwargs = call

        iq_request, = call_args
        self.assertIsNone(iq_request.payload.ver)

        self.assertNotIn(self.user1, self.s.items)
        self.assertNotIn(self.user2, self.s.items)
Beispiel #17
0
    def test_initial_roster_keeps_existing_entries_alive(self):
        old_item = self.s.items[self.user2]

        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="new name",
                            subscription="both")
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.assertIs(old_item, self.s.items[self.user2])
        self.assertEqual("new name", old_item.name)
Beispiel #18
0
    def test_update_groups_on_update(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user1,
                groups=[roster_xso.Group(name="group4")],
            )
        ])

        run_coroutine(
            self.s.handle_roster_push(stanza.IQ("set", payload=request)))

        self.assertNotIn("group3", self.s.groups)
        self.assertSetEqual({self.s.items[self.user2]},
                            self.s.groups["group1"])
        self.assertSetEqual({self.s.items[self.user2]},
                            self.s.groups["group2"])
        self.assertSetEqual({self.s.items[self.user1]},
                            self.s.groups["group4"])
Beispiel #19
0
    def test_on_entry_removed_called_from_initial_roster(self):
        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both")
        ],
                                    ver="foobar")

        old_item = self.s.items[self.user1]

        self.cc.send.return_value = response

        cb = unittest.mock.Mock()
        with self.s.on_entry_removed.context_connect(cb):
            run_coroutine(self.cc.before_stream_established())

        self.assertSequenceEqual([
            unittest.mock.call(old_item),
        ], cb.mock_calls)
Beispiel #20
0
    def test_on_entry_name_changed(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user1,
                name="foobarbaz",
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        cb = unittest.mock.Mock()
        with self.s.on_entry_name_changed.context_connect(cb):
            run_coroutine(self.s.handle_roster_push(iq))
            run_coroutine(self.s.handle_roster_push(iq))

        self.assertSequenceEqual([
            unittest.mock.call(self.s.items[self.user1]),
        ], cb.mock_calls)
Beispiel #21
0
    def test_initial_roster_fires_group_removed_event_for_removed_contact(
            self):  # NOQA
        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both",
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group2"),
                            ])
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.assertCountEqual(self.listener.on_group_removed.mock_calls, [
            unittest.mock.call("group3"),
        ])
Beispiel #22
0
    def test_initial_roster_discards_information(self):
        self.cc.mock_calls.clear()

        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both")
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())
        self.assertSequenceEqual([
            unittest.mock.call.send(
                unittest.mock.ANY,
                timeout=self.cc.negotiation_timeout.total_seconds())
        ], self.cc.mock_calls)

        self.assertNotIn(self.user1, self.s.items)
Beispiel #23
0
    def test_on_entry_subscription_state_changed(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user1,
                            subscription="both",
                            approved=True,
                            ask="subscribe"),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        cb = unittest.mock.Mock()
        with self.s.on_entry_subscription_state_changed.context_connect(cb):
            run_coroutine(self.s.handle_roster_push(iq))
            run_coroutine(self.s.handle_roster_push(iq))

        self.assertSequenceEqual([
            unittest.mock.call(self.s.items[self.user1]),
        ], cb.mock_calls)
Beispiel #24
0
    def test_on_group_added_for_existing_contact(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user2,
                subscription="none",
                groups={
                    roster_xso.Group(name="group1"),
                    roster_xso.Group(name="group2"),
                    roster_xso.Group(name="group4"),
                },
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        run_coroutine(self.s.handle_roster_push(iq))

        self.listener.on_group_added.assert_called_once_with("group4")
Beispiel #25
0
    def test_on_group_added_for_new_contact(self):
        new_jid = structs.JID.fromstr("*****@*****.**")

        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=new_jid,
                subscription="none",
                groups={
                    roster_xso.Group(name="a"),
                    roster_xso.Group(name="group1"),
                },
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        run_coroutine(self.s.handle_roster_push(iq))

        self.listener.on_group_added.assert_called_once_with("a")
Beispiel #26
0
    def test_on_entry_removed(self):
        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user1,
                subscription="remove",
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ("set")
        iq.payload = request

        old_item = self.s.items[self.user1]

        cb = unittest.mock.Mock()
        with self.s.on_entry_removed.context_connect(cb):
            run_coroutine(self.s.handle_roster_push(iq))
            run_coroutine(self.s.handle_roster_push(iq))

        self.assertSequenceEqual([
            unittest.mock.call(old_item),
        ], cb.mock_calls)
Beispiel #27
0
    def test_on_entry_added(self):
        new_jid = structs.JID.fromstr("*****@*****.**")

        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=new_jid,
                subscription="none",
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        cb = unittest.mock.Mock()
        with self.s.on_entry_added.context_connect(cb):
            run_coroutine(self.s.handle_roster_push(iq))
            run_coroutine(self.s.handle_roster_push(iq))

        self.assertSequenceEqual([
            unittest.mock.call(self.s.items[new_jid]),
        ], cb.mock_calls)
Beispiel #28
0
    def test_handle_roster_push_extends_roster(self):
        user1 = structs.JID.fromstr("*****@*****.**")
        user2 = structs.JID.fromstr("*****@*****.**")

        request = roster_xso.Query(items=[
            roster_xso.Item(jid=user1),
            roster_xso.Item(jid=user2,
                            name="some bar user",
                            subscription="both")
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        self.assertIsNone(run_coroutine(self.s.handle_roster_push(iq)))

        self.assertIn(user1, self.s.items)
        self.assertIn(user2, self.s.items)
        self.assertEqual("foobar", self.s.version)

        self.assertEqual("both", self.s.items[user2].subscription)
        self.assertEqual("some bar user", self.s.items[user2].name)
Beispiel #29
0
    def setUp(self):
        self.cc = make_connected_client()
        self.presence_dispatcher = aioxmpp.dispatcher.SimplePresenceDispatcher(
            self.cc)
        self.dependencies = {
            aioxmpp.dispatcher.SimplePresenceDispatcher:
            self.presence_dispatcher,
        }
        self.s = roster_service.RosterClient(self.cc,
                                             dependencies=self.dependencies)

        self.user1 = structs.JID.fromstr("*****@*****.**")
        self.user2 = structs.JID.fromstr("*****@*****.**")

        response = roster_xso.Query(items=[
            roster_xso.Item(jid=self.user1,
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group3"),
                            ]),
            roster_xso.Item(jid=self.user2,
                            name="some bar user",
                            subscription="both",
                            groups=[
                                roster_xso.Group(name="group1"),
                                roster_xso.Group(name="group2"),
                            ])
        ],
                                    ver="foobar")

        self.cc.send.return_value = response

        run_coroutine(self.cc.before_stream_established())

        self.cc.send.reset_mock()

        self.listener = make_listener(self.s)
Beispiel #30
0
    def test_groups_are_cleaned_up_up_when_on_entry_removed_fires_on_push(
            self):
        fut = asyncio.Future()

        def handler(item):
            try:
                for group in item.groups:
                    try:
                        members = self.s.groups[group]
                    except KeyError:
                        members = set()
                    self.assertNotIn(item, members)

            except Exception as exc:
                fut.set_exception(exc)
            else:
                fut.set_result(None)

        new_jid = structs.JID.fromstr("*****@*****.**")

        request = roster_xso.Query(items=[
            roster_xso.Item(
                jid=self.user2,
                subscription="remove",
            ),
        ],
                                   ver="foobar")

        iq = stanza.IQ(type_=structs.IQType.SET)
        iq.payload = request

        self.s.on_entry_removed.connect(handler)

        run_coroutine(self.s.handle_roster_push(iq))

        run_coroutine(fut)