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()
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"), ])
def test_update_from_xso_item(self): xso_item = roster_xso.Item(jid=self.jid, subscription="to", ask="subscribe", approved=False, name="test", groups=[ roster_xso.Group(name="foo"), roster_xso.Group(name="bar"), ]) item = roster_service.Item(self.jid) item.update_from_xso_item(xso_item) self.assertEqual(xso_item.jid, item.jid) self.assertEqual(xso_item.subscription, item.subscription) self.assertEqual(xso_item.ask, item.ask) self.assertEqual(xso_item.approved, item.approved) self.assertEqual(xso_item.name, item.name) self.assertSetEqual({"foo", "bar"}, item.groups) xso_item = roster_xso.Item(jid=structs.JID.fromstr("*****@*****.**"), subscription="from", ask=None, approved=True, name="other test", groups=[roster_xso.Group(name="a")]) item.update_from_xso_item(xso_item) self.assertEqual(self.jid, item.jid) self.assertEqual(xso_item.subscription, item.subscription) self.assertEqual(xso_item.ask, item.ask) self.assertEqual(xso_item.approved, item.approved) self.assertEqual(xso_item.name, item.name) self.assertSetEqual({"a"}, item.groups)
def test_init(self): jid = structs.JID.fromstr("*****@*****.**") item = roster_xso.Item(jid) self.assertEqual(item.jid, jid) self.assertIsNone(item.name) self.assertSequenceEqual([], item.groups) self.assertEqual("none", item.subscription) self.assertIs(False, item.approved) self.assertIsNone(item.ask) group = roster_xso.Group() item = roster_xso.Item( jid=jid, name="foobar", groups=(group,), subscription="to", approved=True, ask="subscribe" ) self.assertEqual(jid, item.jid) self.assertEqual("foobar", item.name) self.assertSequenceEqual([group], item.groups) self.assertIsInstance(item.groups, xso_model.XSOList) self.assertEqual("to", item.subscription) self.assertIs(True, item.approved) self.assertEqual("subscribe", item.ask)
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)
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(), )
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"])
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)
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)
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")
def test_from_xso_item(self, update_from_xso_item): xso_item = roster_xso.Item(jid=structs.JID.fromstr("*****@*****.**"), subscription="from", ask=None, approved=True) item = roster_service.Item.from_xso_item(xso_item) self.assertEqual(xso_item.jid, item.jid) self.assertSequenceEqual([unittest.mock.call(xso_item)], update_from_xso_item.mock_calls)
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)
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)
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)
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)
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)
def test_initial_roster_fires_group_removed_event_for_changed_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"), ]), roster_xso.Item(jid=self.user1, name="some foo user", subscription="both", groups={roster_xso.Group(name="group1")}) ], ver="foobar") self.cc.stream.send.return_value = response run_coroutine(self.cc.before_stream_established()) self.assertCountEqual(self.listener.on_group_removed.mock_calls, [ unittest.mock.call("group3"), ])
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")
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)
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"])
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)
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)
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)
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)
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")
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")
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)
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)
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)
def test_groups_are_set_up_when_on_entry_added_fires(self): fut = asyncio.Future() def handler(item): try: for group in item.groups: self.assertIn(group, self.s.groups) self.assertIn(item, self.s.groups[group]) 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=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 self.s.on_entry_added.connect(handler) run_coroutine(self.s.handle_roster_push(iq)) run_coroutine(fut)