xmpp4r 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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|
|