xmpp4r 0.4 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +8 -0
- data/README.rdoc +4 -1
- data/Rakefile +10 -20
- data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +20 -1
- data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +7 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +7 -1
- data/lib/xmpp4r/callbacks.rb +9 -0
- data/lib/xmpp4r/caps/c.rb +14 -0
- data/lib/xmpp4r/caps/helper/helper.rb +1 -4
- data/lib/xmpp4r/client.rb +42 -15
- data/lib/xmpp4r/connection.rb +7 -3
- data/lib/xmpp4r/debuglog.rb +22 -1
- data/lib/xmpp4r/discovery.rb +1 -0
- data/lib/xmpp4r/discovery/helper/helper.rb +58 -0
- data/lib/xmpp4r/discovery/iq/discoinfo.rb +2 -2
- data/lib/xmpp4r/discovery/iq/discoitems.rb +2 -2
- data/lib/xmpp4r/errors.rb +5 -2
- data/lib/xmpp4r/httpbinding/client.rb +9 -19
- data/lib/xmpp4r/last.rb +2 -0
- data/lib/xmpp4r/last/helper/helper.rb +37 -0
- data/lib/xmpp4r/last/iq/last.rb +67 -0
- data/lib/xmpp4r/location.rb +2 -0
- data/lib/xmpp4r/location/helper/helper.rb +56 -0
- data/lib/xmpp4r/location/location.rb +179 -0
- data/lib/xmpp4r/message.rb +32 -0
- data/lib/xmpp4r/presence.rb +1 -1
- data/lib/xmpp4r/pubsub/children/configuration.rb +1 -1
- data/lib/xmpp4r/pubsub/children/items.rb +11 -2
- data/lib/xmpp4r/pubsub/children/publish.rb +14 -0
- data/lib/xmpp4r/pubsub/children/retract.rb +41 -0
- data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +2 -3
- data/lib/xmpp4r/pubsub/helper/nodehelper.rb +4 -4
- data/lib/xmpp4r/pubsub/helper/oauth_service_helper.rb +90 -0
- data/lib/xmpp4r/pubsub/helper/servicehelper.rb +58 -19
- data/lib/xmpp4r/reliable.rb +168 -0
- data/lib/xmpp4r/rexmladdons.rb +6 -0
- data/lib/xmpp4r/roster/helper/roster.rb +5 -2
- data/lib/xmpp4r/sasl.rb +19 -8
- data/lib/xmpp4r/stream.rb +133 -31
- data/lib/xmpp4r/streamparser.rb +9 -1
- data/lib/xmpp4r/test/listener_mocker.rb +118 -0
- data/lib/xmpp4r/xmpp4r.rb +3 -1
- data/test/bytestreams/tc_ibb.rb +6 -4
- data/test/bytestreams/tc_socks5bytestreams.rb +3 -2
- data/test/caps/tc_helper.rb +4 -2
- data/test/dataforms/tc_data.rb +1 -1
- data/test/last/tc_helper.rb +75 -0
- data/test/lib/clienttester.rb +43 -14
- data/test/muc/tc_muc_mucclient.rb +6 -2
- data/test/pubsub/tc_helper.rb +131 -8
- data/test/pubsub/tc_nodeconfig.rb +7 -0
- data/test/reliable/tc_disconnect_cleanup.rb +334 -0
- data/test/reliable/tc_disconnect_exception.rb +37 -0
- data/test/reliable/tc_listener_mocked_test.rb +68 -0
- data/test/reliable/tc_reliable_connection.rb +31 -0
- data/test/roster/tc_helper.rb +21 -11
- data/test/rpc/tc_helper.rb +2 -2
- data/test/tc_callbacks.rb +3 -3
- data/test/tc_message.rb +15 -0
- data/test/tc_stream.rb +59 -121
- data/test/tc_streamError.rb +2 -4
- data/test/tc_streamparser.rb +26 -13
- data/test/ts_xmpp4r.rb +0 -9
- data/test/tune/tc_helper_recv.rb +0 -2
- data/test/vcard/tc_helper.rb +1 -1
- data/xmpp4r.gemspec +31 -84
- metadata +116 -167
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb.orig +0 -62
data/lib/xmpp4r/streamparser.rb
CHANGED
@@ -43,7 +43,11 @@ module Jabber
|
|
43
43
|
e.add_attributes attributes
|
44
44
|
@current = @current.nil? ? e : @current.add_element(e)
|
45
45
|
|
46
|
-
|
46
|
+
# Handling <stream:stream> not only when it is being
|
47
|
+
# received as a top-level tag but also as a child of the
|
48
|
+
# top-level element itself. This way, we handle stream
|
49
|
+
# restarts (ie. after SASL authentication).
|
50
|
+
if @current.name == 'stream' and @current.parent.nil?
|
47
51
|
@started = true
|
48
52
|
@listener.receive(@current)
|
49
53
|
@current = nil
|
@@ -60,6 +64,10 @@ module Jabber
|
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
67
|
+
parser.listen( :end_document ) do
|
68
|
+
raise Jabber::ServerDisconnected, "Server Disconnected!"
|
69
|
+
end
|
70
|
+
|
63
71
|
parser.listen( :characters ) do | text |
|
64
72
|
@current.add(REXML::Text.new(text.to_s, @current.whitespace, nil, true)) if @current
|
65
73
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Jabber
|
2
|
+
module Test
|
3
|
+
class ListenerMocker
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :with_socket_mocked_callback_proc
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.with_socket_mocked(callback_proc)
|
10
|
+
TCPSocket.class_eval{ ListenerMocker.with_socket_mocked_callback_proc = callback_proc }
|
11
|
+
TCPSocket.class_eval do
|
12
|
+
alias_method :initialize_old, :initialize
|
13
|
+
def initialize(*args)
|
14
|
+
initialize_old(*args) if ListenerMocker.with_socket_mocked_callback_proc.call(args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
TCPSocket.class_eval do
|
20
|
+
if method_defined?(:initialize_old)
|
21
|
+
alias_method :initialize, :initialize_old
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_accessor :mock_clients, :tracker_of_callers
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.mocker_proc
|
31
|
+
Proc.new do
|
32
|
+
attr_accessor :messagecbs, :connected
|
33
|
+
ListenerMocker.mock_clients ||= {}
|
34
|
+
ListenerMocker.tracker_of_callers ||= {}
|
35
|
+
|
36
|
+
def connect
|
37
|
+
Jabber::debuglog("(in mock) connected #{@jid.bare}")
|
38
|
+
self.connected = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def close!
|
42
|
+
ListenerMocker.mock_clients[@jid.bare.to_s] = nil
|
43
|
+
ListenerMocker.tracker_of_callers[@jid.bare.to_s] = nil
|
44
|
+
self.connected = false
|
45
|
+
end
|
46
|
+
|
47
|
+
def auth(password)
|
48
|
+
auth_nonsasl(password)
|
49
|
+
end
|
50
|
+
|
51
|
+
def auth_nonsasl(password, digest=true)
|
52
|
+
Jabber::debuglog("(in mock) authed #{@jid.bare}")
|
53
|
+
|
54
|
+
if(ListenerMocker.mock_clients[@jid.bare.to_s])
|
55
|
+
#raise a stack trace about multiple clients
|
56
|
+
raise "\n\n ---> READ ME: this is actualy 2 stack traces: <---- \n\n"+
|
57
|
+
"There is already a client connected on that jid #{@jid.bare.to_s}. "+
|
58
|
+
"The mock library cannot support multiple listeners connected as the same user! originally called in:\n"+
|
59
|
+
ListenerMocker.tracker_of_callers[@jid.bare.to_s].backtrace.join("\n")+"\n\n second trace: \n"
|
60
|
+
else
|
61
|
+
#store a stack trace so that next time we have multiple client, we can alert about it...
|
62
|
+
begin
|
63
|
+
throw "just saving a stack trace"
|
64
|
+
rescue => e
|
65
|
+
ListenerMocker.tracker_of_callers[@jid.bare.to_s] = e
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
ListenerMocker.mock_clients[@jid.bare.to_s] = self
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def send(xml, &block)
|
74
|
+
Jabber::debuglog("(in mock) sending #{xml} #{xml.class}")
|
75
|
+
if(xml.is_a?(Jabber::Message))
|
76
|
+
xml.from = @jid
|
77
|
+
# unless xml.to
|
78
|
+
# raise "no jid!"
|
79
|
+
# end
|
80
|
+
if ListenerMocker.mock_clients[xml.to.bare.to_s]
|
81
|
+
Jabber::debuglog("(in mock) to #{xml.to.bare.to_s}")
|
82
|
+
ListenerMocker.mock_clients[xml.to.bare.to_s].messagecbs.process(xml)
|
83
|
+
else
|
84
|
+
Jabber::debuglog("(in mock) no client listening as #{xml.to.bare.to_s}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def is_connected?
|
90
|
+
self.connected
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.mock_out_all_connections
|
96
|
+
Jabber::Reliable::Connection.class_eval(&Jabber::Test::ListenerMocker.mocker_proc)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.mock_out(listener)
|
100
|
+
listener.instance_eval do
|
101
|
+
class << self
|
102
|
+
def setup_connection
|
103
|
+
super
|
104
|
+
@connection.instance_eval do
|
105
|
+
class << self
|
106
|
+
self.class_eval(&Jabber::Test::ListenerMocker.mocker_proc)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
listener
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/xmpp4r/xmpp4r.rb
CHANGED
@@ -8,11 +8,13 @@ module Jabber
|
|
8
8
|
# XMPP4R Version number. This is the ONLY place where the version number
|
9
9
|
# should be specified. This constant is used to determine the version of
|
10
10
|
# package tarballs and generated gems.
|
11
|
-
XMPP4R_VERSION = '0.
|
11
|
+
XMPP4R_VERSION = '0.5'
|
12
12
|
end
|
13
13
|
|
14
14
|
require 'xmpp4r/client'
|
15
|
+
require 'xmpp4r/reliable'
|
15
16
|
require 'xmpp4r/component'
|
16
17
|
require 'xmpp4r/debuglog'
|
17
18
|
require 'xmpp4r/errors'
|
18
19
|
|
20
|
+
require 'xmpp4r/test/listener_mocker'
|
data/test/bytestreams/tc_ibb.rb
CHANGED
@@ -30,6 +30,7 @@ class IBBTest < Test::Unit::TestCase
|
|
30
30
|
target.close
|
31
31
|
end
|
32
32
|
|
33
|
+
target.accept_wait
|
33
34
|
|
34
35
|
initiator.open
|
35
36
|
|
@@ -50,10 +51,9 @@ class IBBTest < Test::Unit::TestCase
|
|
50
51
|
buffer = create_buffer(9999)
|
51
52
|
|
52
53
|
Thread.new do
|
53
|
-
|
54
|
+
target.accept_wait
|
54
55
|
initiator.open
|
55
56
|
initiator.write(buffer)
|
56
|
-
Thread.pass
|
57
57
|
initiator.close
|
58
58
|
end
|
59
59
|
|
@@ -100,6 +100,7 @@ class IBBTest < Test::Unit::TestCase
|
|
100
100
|
assert_equal(1, ignored_stanzas)
|
101
101
|
|
102
102
|
|
103
|
+
target.accept_wait
|
103
104
|
initiator.open
|
104
105
|
|
105
106
|
|
@@ -116,8 +117,8 @@ class IBBTest < Test::Unit::TestCase
|
|
116
117
|
assert_equal(3, ignored_stanzas)
|
117
118
|
|
118
119
|
|
119
|
-
|
120
|
-
buf = create_buffer(
|
120
|
+
5.times do
|
121
|
+
buf = create_buffer(100)
|
121
122
|
initiator.write(buf)
|
122
123
|
initiator.flush
|
123
124
|
|
@@ -147,6 +148,7 @@ class IBBTest < Test::Unit::TestCase
|
|
147
148
|
end
|
148
149
|
|
149
150
|
|
151
|
+
target.accept_wait
|
150
152
|
initiator.open
|
151
153
|
|
152
154
|
assert_nil(initiator.read)
|
@@ -44,6 +44,8 @@ class SOCKS5BytestreamsTest < Test::Unit::TestCase
|
|
44
44
|
target2.close
|
45
45
|
end
|
46
46
|
|
47
|
+
target1.accept_wait
|
48
|
+
target2.accept_wait
|
47
49
|
initiator1.open
|
48
50
|
initiator2.open
|
49
51
|
|
@@ -70,7 +72,6 @@ class SOCKS5BytestreamsTest < Test::Unit::TestCase
|
|
70
72
|
initiator = Bytestreams::SOCKS5BytestreamsInitiator.new(@client, '1', '1@a.com/1', '1@a.com/2')
|
71
73
|
initiator.add_streamhost(@@server)
|
72
74
|
|
73
|
-
|
74
75
|
Thread.new do
|
75
76
|
target.accept
|
76
77
|
|
@@ -81,7 +82,7 @@ class SOCKS5BytestreamsTest < Test::Unit::TestCase
|
|
81
82
|
|
82
83
|
target.close
|
83
84
|
end
|
84
|
-
|
85
|
+
target.accept_wait
|
85
86
|
|
86
87
|
initiator.open
|
87
88
|
|
data/test/caps/tc_helper.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
|
2
3
|
$:.unshift File::dirname(__FILE__) + '/../../lib'
|
3
4
|
|
@@ -17,6 +18,7 @@ class Caps::HelperTest < Test::Unit::TestCase
|
|
17
18
|
# in http://www.xmpp.org/extensions/xep-0115.html#usecases
|
18
19
|
# and assert conformance.
|
19
20
|
def test_caps_reply
|
21
|
+
|
20
22
|
# This will be invoked by 'wait_state' below...
|
21
23
|
state { |presence|
|
22
24
|
assert_kind_of(Jabber::Presence, presence)
|
@@ -30,8 +32,6 @@ class Caps::HelperTest < Test::Unit::TestCase
|
|
30
32
|
assert_equal('sha-1', c.hash)
|
31
33
|
|
32
34
|
assert_equal("http://home.gna.org/xmpp4r/##{Jabber::XMPP4R_VERSION}", c.node)
|
33
|
-
|
34
|
-
send(iq_discovering_capabilities)
|
35
35
|
}
|
36
36
|
|
37
37
|
# Construct Caps::Helper which will send a <presence>
|
@@ -64,6 +64,8 @@ class Caps::HelperTest < Test::Unit::TestCase
|
|
64
64
|
assert_equal(iq.query.features.sort, features.map(&get_var).sort)
|
65
65
|
}
|
66
66
|
|
67
|
+
send(iq_discovering_capabilities)
|
68
|
+
|
67
69
|
# The 'server' will receive the <iq> result from the
|
68
70
|
# 'client' and yield it to the block above. Wait here
|
69
71
|
# until that block exits.
|
data/test/dataforms/tc_data.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
$:.unshift File::dirname(__FILE__) + '/../../lib'
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require File::dirname(__FILE__) + '/../lib/clienttester'
|
7
|
+
|
8
|
+
require 'xmpp4r'
|
9
|
+
require 'xmpp4r/last/helper/helper'
|
10
|
+
include Jabber
|
11
|
+
|
12
|
+
|
13
|
+
class LastActivity::HelperTest < Test::Unit::TestCase
|
14
|
+
include ClientTester
|
15
|
+
|
16
|
+
def test_simple_query
|
17
|
+
state { |iq|
|
18
|
+
assert_kind_of(Iq, iq)
|
19
|
+
assert_equal(JID.new('juliet@capulet.com'), iq.to)
|
20
|
+
assert_equal(:get, iq.type)
|
21
|
+
assert_kind_of(LastActivity::IqQueryLastActivity, iq.query)
|
22
|
+
send("
|
23
|
+
<iq type='result' from='#{iq.to}' to='#{iq.from}' id='#{iq.id}'>
|
24
|
+
<query xmlns='jabber:iq:last' seconds='903'/>
|
25
|
+
</iq>")
|
26
|
+
}
|
27
|
+
|
28
|
+
res = LastActivity::Helper.new(@client).get_last_activity_from('juliet@capulet.com')
|
29
|
+
wait_state
|
30
|
+
assert_equal(903, res.seconds)
|
31
|
+
assert_nil(res.text)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_text_query
|
35
|
+
state { |iq|
|
36
|
+
send("
|
37
|
+
<iq type='result' from='#{iq.to}' to='#{iq.from}' id='#{iq.id}'>
|
38
|
+
<query xmlns='jabber:iq:last' seconds='903'>Heading Home</query>
|
39
|
+
</iq>")
|
40
|
+
}
|
41
|
+
|
42
|
+
res = LastActivity::Helper.new(@client).get_last_activity_from('juliet@capulet.com')
|
43
|
+
wait_state
|
44
|
+
assert_equal(903, res.seconds)
|
45
|
+
assert_equal('Heading Home', res.text)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_empty_query
|
49
|
+
state { |iq|
|
50
|
+
send("
|
51
|
+
<iq type='result' from='#{iq.to}' to='#{iq.from}' id='#{iq.id}'>
|
52
|
+
<query xmlns='jabber:iq:last'/>
|
53
|
+
</iq>")
|
54
|
+
}
|
55
|
+
|
56
|
+
res = LastActivity::Helper.new(@client).get_last_activity_from('juliet@capulet.com')
|
57
|
+
wait_state
|
58
|
+
assert_nil(res.seconds)
|
59
|
+
assert_nil(res.text)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_forbidden_query
|
63
|
+
state { |iq|
|
64
|
+
send("
|
65
|
+
<iq type='error' from='#{iq.to}' to='#{iq.from}' id='#{iq.id}'>
|
66
|
+
<error type='auth'>
|
67
|
+
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
68
|
+
</error>
|
69
|
+
</iq>")
|
70
|
+
}
|
71
|
+
|
72
|
+
assert_raises(ServerError) { LastActivity::Helper.new(@client).get_last_activity_from('juliet@capulet.com') }
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/test/lib/clienttester.rb
CHANGED
@@ -8,6 +8,10 @@ require 'test/unit'
|
|
8
8
|
require 'socket'
|
9
9
|
require 'xmpp4r/semaphore'
|
10
10
|
|
11
|
+
# Jabber::debug = true
|
12
|
+
$ctdebug = false
|
13
|
+
# $ctdebug = true
|
14
|
+
|
11
15
|
# This is sane for tests:
|
12
16
|
Thread::abort_on_exception = true
|
13
17
|
|
@@ -33,6 +37,9 @@ module Jabber
|
|
33
37
|
serverwait = Semaphore.new
|
34
38
|
stream = '<stream:stream xmlns:stream="http://etherx.jabber.org/streams">'
|
35
39
|
|
40
|
+
@state = 0
|
41
|
+
@states = []
|
42
|
+
|
36
43
|
Thread.new do
|
37
44
|
Thread.current.abort_on_exception = true
|
38
45
|
serversock = servlisten.accept
|
@@ -68,31 +75,53 @@ module Jabber
|
|
68
75
|
end
|
69
76
|
#=end
|
70
77
|
@client.start(clientsock)
|
71
|
-
@client.send(stream) { |reply| true }
|
72
78
|
|
73
|
-
@
|
74
|
-
@
|
75
|
-
|
76
|
-
@state_wait2 = Semaphore.new
|
79
|
+
@processdone_wait = Semaphore.new
|
80
|
+
@nextstate_wait = Semaphore.new
|
81
|
+
serverwait.wait
|
77
82
|
@server.add_stanza_callback { |stanza|
|
78
|
-
|
83
|
+
# Client prepares everything, then calls wait_state. Problem: because
|
84
|
+
# of a race condition, it is possible that we receive the stanza before
|
85
|
+
# what to do with it is defined. We busy-wait on @states here.
|
86
|
+
n = 0
|
87
|
+
while @state >= @states.size and n < 1000
|
88
|
+
Thread.pass
|
89
|
+
n += 1
|
90
|
+
end
|
91
|
+
if n == 1000
|
92
|
+
puts "Unmanaged stanza in state. Maybe processed by helper?" if $ctdebug
|
93
|
+
else
|
79
94
|
begin
|
95
|
+
puts "Calling #{@states[@state]} for #{stanza.to_s}" if $ctdebug
|
80
96
|
@states[@state].call(stanza)
|
81
|
-
rescue
|
82
|
-
puts "Exception in state: #{
|
97
|
+
rescue Exception => e
|
98
|
+
puts "Exception in state: #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
83
99
|
end
|
84
100
|
@state += 1
|
85
|
-
@
|
86
|
-
@
|
101
|
+
@nextstate_wait.wait
|
102
|
+
@processdone_wait.run
|
87
103
|
end
|
88
104
|
|
89
105
|
false
|
90
106
|
}
|
107
|
+
@client.send(stream) { |reply| true }
|
91
108
|
|
92
|
-
serverwait.wait
|
93
109
|
end
|
94
110
|
|
95
111
|
def teardown
|
112
|
+
# In some cases, we might lost count of some stanzas
|
113
|
+
# (for example, if the handler raises an exception)
|
114
|
+
# so we can't block forever.
|
115
|
+
n = 0
|
116
|
+
while @client.processing > 0 and n < 1000
|
117
|
+
Thread::pass
|
118
|
+
n += 1
|
119
|
+
end
|
120
|
+
n = 0
|
121
|
+
while @server.processing > 0 and n < 1000
|
122
|
+
Thread::pass
|
123
|
+
n += 1
|
124
|
+
end
|
96
125
|
@client.close
|
97
126
|
@server.close
|
98
127
|
end
|
@@ -106,12 +135,12 @@ module Jabber
|
|
106
135
|
end
|
107
136
|
|
108
137
|
def wait_state
|
109
|
-
@
|
110
|
-
@
|
138
|
+
@nextstate_wait.run
|
139
|
+
@processdone_wait.wait
|
111
140
|
end
|
112
141
|
|
113
142
|
def skip_state
|
114
|
-
@
|
143
|
+
@nextstate_wait.run
|
115
144
|
end
|
116
145
|
end
|
117
146
|
end
|
@@ -86,7 +86,11 @@ class MUCClientTest < Test::Unit::TestCase
|
|
86
86
|
send("<presence from='darkcave@macbeth.shakespeare.lit/thirdwitch' to='crone1@shakespeare.lit/desktop'>" +
|
87
87
|
"<x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='none' jid='hag66@shakespeare.lit/pda' role='participant'/></x>" +
|
88
88
|
"</presence>")
|
89
|
-
|
89
|
+
n = 0
|
90
|
+
while m.roster.size != 3 and n < 1000
|
91
|
+
Thread::pass
|
92
|
+
n += 1
|
93
|
+
end
|
90
94
|
assert_equal(3, m.roster.size)
|
91
95
|
assert_equal(:none, m.roster['thirdwitch'].x.items[0].affiliation)
|
92
96
|
assert_equal(:participant, m.roster['thirdwitch'].x.items[0].role)
|
@@ -408,7 +412,7 @@ class MUCClientTest < Test::Unit::TestCase
|
|
408
412
|
assert_equal(1, messages_muc_private)
|
409
413
|
|
410
414
|
wait_state
|
411
|
-
|
415
|
+
end
|
412
416
|
|
413
417
|
def test_presence_callbacks
|
414
418
|
state { |pres|
|