source: wokkel/test/test_server.py @ 206:a32614b03670

Last change on this file since 206:a32614b03670 was 206:a32614b03670, checked in by Ralph Meijer <ralphm@…>, 3 years ago

imported patch py3-server.patch

  • Property exe set to *
File size: 15.3 KB
Line 
1# Copyright (c) Ralph Meijer.
2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.server}.
6"""
7
8from __future__ import division, absolute_import
9from twisted.internet import defer
10from twisted.python import failure
11from twisted.test.proto_helpers import StringTransport
12from twisted.trial import unittest
13from twisted.words.protocols.jabber import error, jid, xmlstream
14from twisted.words.xish import domish
15
16from wokkel import component, server
17
18NS_STREAMS = 'http://etherx.jabber.org/streams'
19NS_DIALBACK = "jabber:server:dialback"
20
21class GenerateKeyTest(unittest.TestCase):
22    """
23    Tests for L{server.generateKey}.
24    """
25
26    def testBasic(self):
27        originating = "example.org"
28        receiving = "xmpp.example.com"
29        sid = "D60000229F"
30        secret = "s3cr3tf0rd14lb4ck"
31
32        key = server.generateKey(secret, receiving, originating, sid)
33
34        self.assertEqual(key,
35            '37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643')
36
37
38
39class XMPPServerListenAuthenticatorTest(unittest.TestCase):
40    """
41    Tests for L{server.XMPPServerListenAuthenticator}.
42    """
43
44    secret = "s3cr3tf0rd14lb4ck"
45    originating = "example.org"
46    receiving = "xmpp.example.com"
47    sid = "D60000229F"
48    key = '37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643'
49
50    def setUp(self):
51        self.output = []
52
53        class MyService(object):
54            pass
55
56        self.service = MyService()
57        self.service.defaultDomain = self.receiving
58        self.service.domains = [self.receiving, 'pubsub.'+self.receiving]
59        self.service.secret = self.secret
60
61        self.authenticator = server.XMPPServerListenAuthenticator(self.service)
62        self.xmlstream = xmlstream.XmlStream(self.authenticator)
63        self.xmlstream.send = self.output.append
64        self.xmlstream.transport = StringTransport()
65
66
67    def test_attributes(self):
68        """
69        Test attributes of authenticator and stream objects.
70        """
71        self.assertEqual(self.service, self.authenticator.service)
72        self.assertEqual(self.xmlstream.initiating, False)
73
74
75    def test_streamStartedVersion0(self):
76        """
77        The authenticator supports pre-XMPP 1.0 streams.
78        """
79        self.xmlstream.connectionMade()
80        self.xmlstream.dataReceived(
81            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
82                           "xmlns:db='jabber:server:dialback' "
83                           "xmlns='jabber:server' "
84                           "to='xmpp.example.com'>")
85        self.assertEqual((0, 0), self.xmlstream.version)
86
87
88    def test_streamStartedVersion1(self):
89        """
90        The authenticator supports XMPP 1.0 streams.
91        """
92        self.xmlstream.connectionMade()
93        self.xmlstream.dataReceived(
94            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
95                           "xmlns:db='jabber:server:dialback' "
96                           "xmlns='jabber:server' "
97                           "to='xmpp.example.com' "
98                           "version='1.0'>")
99        self.assertEqual((1, 0), self.xmlstream.version)
100
101
102    def test_streamStartedSID(self):
103        """
104        The response stream will have a stream ID.
105        """
106        self.xmlstream.connectionMade()
107        self.assertIdentical(None, self.xmlstream.sid)
108
109        self.xmlstream.dataReceived(
110            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
111                           "xmlns:db='jabber:server:dialback' "
112                           "xmlns='jabber:server' "
113                           "to='xmpp.example.com' "
114                           "version='1.0'>")
115        self.assertNotIdentical(None, self.xmlstream.sid)
116
117
118    def test_streamStartedSentResponseHeader(self):
119        """
120        A stream header is sent in response to the incoming stream header.
121        """
122        self.xmlstream.connectionMade()
123        self.assertFalse(self.xmlstream._headerSent)
124
125        self.xmlstream.dataReceived(
126            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
127                           "xmlns:db='jabber:server:dialback' "
128                           "xmlns='jabber:server' "
129                           "to='xmpp.example.com'>")
130        self.assertTrue(self.xmlstream._headerSent)
131
132
133    def test_streamStartedNotSentFeatures(self):
134        """
135        No features are sent in response to an XMPP < 1.0 stream header.
136        """
137        self.xmlstream.connectionMade()
138        self.xmlstream.dataReceived(
139            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
140                           "xmlns:db='jabber:server:dialback' "
141                           "xmlns='jabber:server' "
142                           "to='xmpp.example.com'>")
143        self.assertEqual(1, len(self.output))
144
145
146    def test_streamStartedSentFeatures(self):
147        """
148        Features are sent in response to an XMPP >= 1.0 stream header.
149        """
150        self.xmlstream.connectionMade()
151        self.xmlstream.dataReceived(
152            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
153                           "xmlns:db='jabber:server:dialback' "
154                           "xmlns='jabber:server' "
155                           "to='xmpp.example.com' "
156                           "version='1.0'>")
157        self.assertEqual(2, len(self.output))
158        features = self.output[-1]
159        self.assertEqual(NS_STREAMS, features.uri)
160        self.assertEqual('features', features.name)
161
162
163    def test_streamRootElement(self):
164        """
165        Test stream error on wrong stream namespace.
166        """
167        self.xmlstream.connectionMade()
168        self.xmlstream.dataReceived(
169            "<stream:stream xmlns:stream='badns' "
170                           "xmlns:db='jabber:server:dialback' "
171                           "xmlns='jabber:server' "
172                           "to='xmpp.example.com'>")
173
174        self.assertEqual(3, len(self.output))
175        exc = error.exceptionFromStreamError(self.output[1])
176        self.assertEqual('invalid-namespace', exc.condition)
177
178
179    def test_streamDefaultNamespace(self):
180        """
181        Test stream error on missing dialback namespace.
182        """
183        self.xmlstream.connectionMade()
184        self.xmlstream.dataReceived(
185            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
186                           "xmlns:db='jabber:server:dialback' "
187                           "xmlns='badns' "
188                           "to='xmpp.example.com'>")
189
190        self.assertEqual(3, len(self.output))
191        exc = error.exceptionFromStreamError(self.output[1])
192        self.assertEqual('invalid-namespace', exc.condition)
193
194
195    def test_streamNoDialbackNamespace(self):
196        """
197        Test stream error on missing dialback namespace.
198        """
199        self.xmlstream.connectionMade()
200        self.xmlstream.dataReceived(
201            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
202                           "xmlns='jabber:server' "
203                           "to='xmpp.example.com'>")
204
205        self.assertEqual(3, len(self.output))
206        exc = error.exceptionFromStreamError(self.output[1])
207        self.assertEqual('invalid-namespace', exc.condition)
208
209
210    def test_streamBadDialbackNamespace(self):
211        """
212        Test stream error on missing dialback namespace.
213        """
214        self.xmlstream.connectionMade()
215        self.xmlstream.dataReceived(
216            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
217                           "xmlns:db='badns' "
218                           "xmlns='jabber:server' "
219                           "to='xmpp.example.com'>")
220
221        self.assertEqual(3, len(self.output))
222        exc = error.exceptionFromStreamError(self.output[1])
223        self.assertEqual('invalid-namespace', exc.condition)
224
225
226    def test_streamToUnknownHost(self):
227        """
228        Test stream error on stream's to attribute having unknown host.
229        """
230        self.xmlstream.connectionMade()
231        self.xmlstream.dataReceived(
232            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
233                           "xmlns:db='jabber:server:dialback' "
234                           "xmlns='jabber:server' "
235                           "to='badhost'>")
236
237        self.assertEqual(3, len(self.output))
238        exc = error.exceptionFromStreamError(self.output[1])
239        self.assertEqual('host-unknown', exc.condition)
240
241
242    def test_streamToOtherLocalHost(self):
243        """
244        The authenticator supports XMPP 1.0 streams.
245        """
246        self.xmlstream.connectionMade()
247        self.xmlstream.dataReceived(
248            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
249                           "xmlns:db='jabber:server:dialback' "
250                           "xmlns='jabber:server' "
251                           "to='pubsub.xmpp.example.com' "
252                           "version='1.0'>")
253
254        self.assertEqual(2, len(self.output))
255        self.assertEqual(jid.JID('pubsub.xmpp.example.com'),
256                         self.xmlstream.thisEntity)
257
258    def test_onResult(self):
259        def cb(result):
260            self.assertEqual(1, len(self.output))
261            reply = self.output[0]
262            self.assertEqual(self.originating, reply['to'])
263            self.assertEqual(self.receiving, reply['from'])
264            self.assertEqual('valid', reply['type'])
265
266        def validateConnection(thisHost, otherHost, sid, key):
267            self.assertEqual(thisHost, self.receiving)
268            self.assertEqual(otherHost, self.originating)
269            self.assertEqual(sid, self.sid)
270            self.assertEqual(key, self.key)
271            return defer.succeed(None)
272
273        self.xmlstream.sid = self.sid
274        self.service.validateConnection = validateConnection
275
276        result = domish.Element((NS_DIALBACK, 'result'))
277        result['to'] = self.receiving
278        result['from'] = self.originating
279        result.addContent(self.key)
280
281        d = self.authenticator.onResult(result)
282        d.addCallback(cb)
283        return d
284
285
286    def test_onResultFailure(self):
287        class TestError(Exception):
288            pass
289
290        def cb(result):
291            reply = self.output[0]
292            self.assertEqual('invalid', reply['type'])
293            self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
294
295
296        def validateConnection(thisHost, otherHost, sid, key):
297            return defer.fail(TestError())
298
299        self.xmlstream.sid = self.sid
300        self.service.validateConnection = validateConnection
301
302        result = domish.Element((NS_DIALBACK, 'result'))
303        result['to'] = self.receiving
304        result['from'] = self.originating
305        result.addContent(self.key)
306
307        d = self.authenticator.onResult(result)
308        d.addCallback(cb)
309        return d
310
311
312
313class FakeService(object):
314    domains = set(['example.org', 'pubsub.example.org'])
315    defaultDomain = 'example.org'
316    secret = 'mysecret'
317
318    def __init__(self):
319        self.dispatched = []
320
321    def dispatch(self, xs, element):
322        self.dispatched.append(element)
323
324
325
326class XMPPS2SServerFactoryTest(unittest.TestCase):
327    """
328    Tests for L{component.XMPPS2SServerFactory}.
329    """
330
331    def setUp(self):
332        self.service = FakeService()
333        self.factory = server.XMPPS2SServerFactory(self.service)
334        self.xmlstream = self.factory.buildProtocol(None)
335        self.transport = StringTransport()
336        self.xmlstream.thisEntity = jid.JID('example.org')
337        self.xmlstream.otherEntity = jid.JID('example.com')
338
339
340    def test_makeConnection(self):
341        """
342        A new connection increases the stream serial count. No logs by default.
343        """
344        self.xmlstream.makeConnection(self.transport)
345        self.assertEqual(0, self.xmlstream.serial)
346        self.assertEqual(1, self.factory.serial)
347        self.assertIdentical(None, self.xmlstream.rawDataInFn)
348        self.assertIdentical(None, self.xmlstream.rawDataOutFn)
349
350
351    def test_makeConnectionLogTraffic(self):
352        """
353        Setting logTraffic should set up raw data loggers.
354        """
355        self.factory.logTraffic = True
356        self.xmlstream.makeConnection(self.transport)
357        self.assertNotIdentical(None, self.xmlstream.rawDataInFn)
358        self.assertNotIdentical(None, self.xmlstream.rawDataOutFn)
359
360
361    def test_onError(self):
362        """
363        An observer for stream errors should trigger onError to log it.
364        """
365        self.xmlstream.makeConnection(self.transport)
366
367        class TestError(Exception):
368            pass
369
370        reason = failure.Failure(TestError())
371        self.xmlstream.dispatch(reason, xmlstream.STREAM_ERROR_EVENT)
372        self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
373
374
375    def test_connectionInitialized(self):
376        """
377        """
378        self.xmlstream.makeConnection(self.transport)
379        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
380
381
382    def test_connectionLost(self):
383        """
384        """
385        self.xmlstream.makeConnection(self.transport)
386        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
387        self.xmlstream.dispatch(None, xmlstream.STREAM_END_EVENT)
388
389
390    def test_Element(self):
391        self.xmlstream.makeConnection(self.transport)
392        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
393
394        stanza = domish.Element((None, "presence"))
395        self.xmlstream.dispatch(stanza)
396        self.assertEqual(1, len(self.service.dispatched))
397        self.assertIdentical(stanza, self.service.dispatched[-1])
398
399
400    def test_ElementNotAuthenticated(self):
401        self.xmlstream.makeConnection(self.transport)
402
403        stanza = domish.Element((None, "presence"))
404        self.xmlstream.dispatch(stanza)
405        self.assertEqual(0, len(self.service.dispatched))
406
407
408
409class ServerServiceTest(unittest.TestCase):
410
411    def setUp(self):
412        self.output = []
413
414        self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator())
415        self.xmlstream.thisEntity = jid.JID('example.org')
416        self.xmlstream.otherEntity = jid.JID('example.com')
417        self.xmlstream.send = self.output.append
418
419        self.router = component.Router()
420        self.service = server.ServerService(self.router,
421                                            secret='mysecret',
422                                            domain='example.org')
423        self.service.xmlstream = self.xmlstream
424
425
426    def test_defaultDomainInDomains(self):
427        """
428        The default domain is part of the domains considered local.
429        """
430        self.assertIn(self.service.defaultDomain, self.service.domains)
431
432
433    def test_dispatch(self):
434        stanza = domish.Element((None, "presence"))
435        stanza['to'] = 'user@example.org'
436        stanza['from'] = 'other@example.com'
437        self.service.dispatch(self.xmlstream, stanza)
438
439        self.assertEqual(1, len(self.output))
440        self.assertIdentical(stanza, self.output[-1])
441
442
443    def test_dispatchNoTo(self):
444        errors = []
445        self.xmlstream.sendStreamError = errors.append
446
447        stanza = domish.Element((None, "presence"))
448        stanza['from'] = 'other@example.com'
449        self.service.dispatch(self.xmlstream, stanza)
450
451        self.assertEqual(1, len(errors))
452
453
454    def test_generatedSecret(self):
455        self.router = component.Router()
456        self.service = server.ServerService(self.router,
457                                            domain='example.org')
458        self.assertEqual(32, len(self.service.secret))
Note: See TracBrowser for help on using the repository browser.