Skip to content
This repository has been archived by the owner on Jan 14, 2024. It is now read-only.

Commit

Permalink
mix: implement create/join/leave
Browse files Browse the repository at this point in the history
  • Loading branch information
horazont committed Sep 16, 2019
1 parent 9728599 commit d0997d3
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 6 deletions.
4 changes: 3 additions & 1 deletion aioxmpp/mix/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@
# <http://www.gnu.org/licenses/>.
#
########################################################################

from .service import MIXClient
from . import xso
from .xso.nodes import Node
19 changes: 19 additions & 0 deletions aioxmpp/mix/xso/core0.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
########################################################################
import typing

import aioxmpp.stanza
import aioxmpp.xso

from aioxmpp.utils import namespaces
Expand Down Expand Up @@ -64,10 +65,28 @@ class Join0(aioxmpp.xso.XSO):

subscribe = aioxmpp.xso.ChildValueList(Subscribe0Type())

participant_id = aioxmpp.xso.Attr(
"id",
default=None,
)

def __init__(self, subscribe_to_nodes: typing.Iterable[nodes.Node] = []):
super().__init__()
self.subscribe[:] = subscribe_to_nodes


class Leave0(aioxmpp.xso.XSO):
TAG = namespaces.xep0369_mix_core_0, "leave"


@aioxmpp.stanza.IQ.as_payload_class
class Create0(aioxmpp.xso.XSO):
TAG = namespaces.xep0369_mix_core_0, "create"

channel = aioxmpp.xso.Attr(
"channel"
)

def __init__(self, channel):
super().__init__()
self.channel = channel
32 changes: 29 additions & 3 deletions aioxmpp/mix/xso/pam0.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# <http://www.gnu.org/licenses/>.
#
########################################################################
import aioxmpp.stanza
import aioxmpp.xso

from aioxmpp.utils import namespaces
Expand All @@ -28,14 +29,39 @@
namespaces.xep0405_mix_pam_0 = "urn:xmpp:mix:pam:0"


@aioxmpp.stanza.IQ.as_payload_class
class ClientJoin0(aioxmpp.xso.XSO):
TAG = namespaces.xep0405_mix_pam_0, "client-join"

join = aioxmpp.xso.Child([core0.Join0])

channel = aioxmpp.xso.Attr("channel", type_=aioxmpp.xso.JID())
channel = aioxmpp.xso.Attr(
"channel",
type_=aioxmpp.xso.JID(),
default=None,
)

def __init__(self, channel, subscribe_to_nodes):
def __init__(self, channel=None, subscribe_to_nodes=None):
super().__init__()
self.channel = channel
self.join = core0.Join0(subscribe_to_nodes)
if subscribe_to_nodes is not None:
self.join = core0.Join0(subscribe_to_nodes)


@aioxmpp.stanza.IQ.as_payload_class
class ClientLeave0(aioxmpp.xso.XSO):
TAG = namespaces.xep0405_mix_pam_0, "client-leave"

leave = aioxmpp.xso.Child([core0.Leave0])

channel = aioxmpp.xso.Attr(
"channel",
type_=aioxmpp.xso.JID(),
default=None,
)

def __init__(self, channel=None):
super().__init__()
self.channel = channel
if channel is not None:
self.leave = core0.Leave0()
37 changes: 37 additions & 0 deletions tests/mix/test_e2e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import uuid

import aioxmpp
import aioxmpp.mix
import aioxmpp.mix.xso.pam0

from aioxmpp.utils import namespaces

from aioxmpp.e2etest import (
TestCase,
require_feature,
blocking,
)


class TestMIX(TestCase):
@require_feature(namespaces.xep0369_mix_core_0, argname="mix_service")
@blocking
async def setUp(self, mix_service):
services = [
aioxmpp.mix.MIXClient,
aioxmpp.DiscoClient,
]

self.firstwitch = await self.provisioner.get_connected_client(
services=services,
)
self.firstmix = self.firstwitch.summon(aioxmpp.mix.MIXClient)
self.test_channel = mix_service.replace(
localpart=str(uuid.uuid4())
)

@blocking
async def test_create_join_leave(self):
await self.firstmix.create(self.test_channel)
await self.firstmix.join(self.test_channel, [aioxmpp.mix.Node.MESSAGES])
await self.firstmix.leave(self.test_channel)
184 changes: 184 additions & 0 deletions tests/mix/test_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
########################################################################
# File name: test_service.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
import unittest

import aioxmpp
import aioxmpp.service
import aioxmpp.im.conversation as im_conversation
import aioxmpp.im.dispatcher as im_dispatcher
import aioxmpp.im.service as im_service
import aioxmpp.mix.service as mix_service
import aioxmpp.mix.xso as mix_xso
import aioxmpp.mix.xso.core0 as core0_xso
import aioxmpp.mix.xso.pam0 as pam0_xso

from aioxmpp.testutils import (
make_connected_client,
run_coroutine,
)


TEST_USER = aioxmpp.JID.fromstr("[email protected]/resource")
TEST_CHANNEL = aioxmpp.JID.fromstr("[email protected]")
TEST_NODES = [mix_xso.Node.MESSAGES, mix_xso.Node.PARTICIPANTS]


class TestMIXClient(unittest.TestCase):
def test_is_service(self):
self.assertTrue(issubclass(
mix_service.MIXClient,
aioxmpp.service.Service,
))

def test_is_conversation_service(self):
self.assertTrue(issubclass(
mix_service.MIXClient,
im_conversation.AbstractConversationService,
))

def setUp(self):
self.cc = make_connected_client()
self.im_dispatcher = im_dispatcher.IMDispatcher(self.cc)
self.im_service = unittest.mock.Mock(
spec=im_service.ConversationService
)
self.disco_client = unittest.mock.Mock(
spec=aioxmpp.DiscoClient,
)
self.s = mix_service.MIXClient(self.cc, dependencies={
im_dispatcher.IMDispatcher: self.im_dispatcher,
im_service.ConversationService: self.im_service,
aioxmpp.DiscoClient: self.disco_client,
})

def tearDown(self):
del self.cc
del self.s

def test_join(self):
reply = pam0_xso.ClientJoin0()
reply.join = core0_xso.Join0()
reply.join.participant_id = "abcdef"

self.cc.send.return_value = reply

result = run_coroutine(self.s.join(TEST_CHANNEL, TEST_NODES))

self.cc.send.assert_called_once_with(unittest.mock.ANY)

_, (request, ), _ = self.cc.send.mock_calls[0]

self.assertIsInstance(
request,
aioxmpp.IQ,
)
self.assertEqual(
request.type_,
aioxmpp.IQType.SET,
)
self.assertEqual(
request.to,
None,
)
self.assertIsInstance(
request.payload,
pam0_xso.ClientJoin0,
)

cj0 = request.payload
self.assertEqual(
cj0.channel,
TEST_CHANNEL,
)
self.assertIsInstance(
cj0.join,
core0_xso.Join0,
)
self.assertCountEqual(
cj0.join.subscribe,
TEST_NODES,
)

self.assertIs(result, reply.join)

def test_create(self):
reply = core0_xso.Create0("foo")

self.cc.send.return_value = reply

run_coroutine(self.s.create(TEST_CHANNEL))

self.cc.send.assert_called_once_with(unittest.mock.ANY)

_, (request, ), _ = self.cc.send.mock_calls[0]

self.assertIsInstance(
request,
aioxmpp.IQ,
)
self.assertEqual(
request.type_,
aioxmpp.IQType.SET,
)
self.assertEqual(
request.to,
TEST_CHANNEL.replace(localpart=None)
)
self.assertIsInstance(
request.payload,
core0_xso.Create0,
)

c0 = request.payload
self.assertEqual(
c0.channel,
TEST_CHANNEL.localpart,
)

def test_leave(self):
reply = pam0_xso.ClientLeave0(TEST_CHANNEL)

self.cc.send.return_value = reply

run_coroutine(self.s.leave(TEST_CHANNEL))

self.cc.send.assert_called_once_with(unittest.mock.ANY)

_, (request, ), _ = self.cc.send.mock_calls[0]

self.assertIsInstance(
request,
aioxmpp.IQ,
)
self.assertEqual(
request.type_,
aioxmpp.IQType.SET,
)
self.assertIsNone(request.to)
self.assertIsInstance(
request.payload,
pam0_xso.ClientLeave0
)

cl0 = request.payload
self.assertEqual(cl0.channel, TEST_CHANNEL)
self.assertIsInstance(cl0.leave, core0_xso.Leave0)
51 changes: 51 additions & 0 deletions tests/mix/xso/test_core0.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,24 @@ def test_subscribe(self):
core0_xso.Subscribe0Type,
)

def test_participant_id(self):
self.assertIsInstance(
core0_xso.Join0.participant_id,
xso.Attr,
)
self.assertEqual(
core0_xso.Join0.participant_id.tag,
(None, "id"),
)
self.assertEqual(
core0_xso.Join0.participant_id.default,
None,
)

def test_init_default(self):
j0 = core0_xso.Join0()
self.assertSequenceEqual(j0.subscribe, [])
self.assertIsNone(j0.participant_id)

def test_init(self):
j0 = core0_xso.Join0(
Expand All @@ -149,6 +164,7 @@ def test_init(self):
mix_xso.Node.PARTICIPANTS,
]
)
self.assertIsNone(j0.participant_id)


class TestLeave0(unittest.TestCase):
Expand All @@ -163,3 +179,38 @@ def test_tag(self):
core0_xso.Leave0.TAG,
(namespaces.xep0369_mix_core_0, "leave")
)


class TestCreate0(unittest.TestCase):
def test_is_xso(self):
self.assertTrue(issubclass(
core0_xso.Create0,
xso.XSO,
))

def test_tag(self):
self.assertEqual(
core0_xso.Create0.TAG,
(namespaces.xep0369_mix_core_0, "create")
)

def test_channel(self):
self.assertIsInstance(
core0_xso.Create0.channel,
xso.Attr,
)
self.assertEqual(
core0_xso.Create0.channel.tag,
(None, "channel")
)

def test_init_nodefault(self):
with self.assertRaisesRegexp(TypeError, "channel"):
c0 = core0_xso.Create0()

def test_init_full(self):
c0 = core0_xso.Create0("some channel")
self.assertEqual(c0.channel, "some channel")

def test_is_iq_payload(self):
aioxmpp.IQ(type_=aioxmpp.IQType.RESULT, payload=core0_xso.Create0("x"))
Loading

0 comments on commit d0997d3

Please sign in to comment.