sprsquish-blather 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +17 -2
- data/Rakefile +1 -1
- data/examples/ping_pong.rb +37 -0
- data/lib/blather.rb +1 -4
- data/lib/blather/client.rb +75 -3
- data/lib/blather/client/client.rb +67 -53
- data/lib/blather/client/dsl.rb +13 -18
- data/lib/blather/stanza/disco/disco_info.rb +0 -12
- data/lib/blather/stanza/disco/disco_items.rb +0 -7
- data/lib/blather/stream.rb +4 -4
- data/lib/blather/stream/component.rb +1 -1
- data/spec/blather/client/client_spec.rb +389 -0
- data/spec/blather/client/dsl_spec.rb +105 -0
- data/spec/blather/stream/client_spec.rb +18 -18
- data/spec/blather/stream/component_spec.rb +3 -3
- data/spec/spec_helper.rb +4 -1
- metadata +6 -3
data/README.rdoc
CHANGED
@@ -60,7 +60,7 @@ Guards act like AND statements. Each condition must be met if the handler is to
|
|
60
60
|
# Equivalent to saying (stanza.chat? && stanza.body)
|
61
61
|
message :chat?, :body
|
62
62
|
|
63
|
-
|
63
|
+
The different types of guards are:
|
64
64
|
|
65
65
|
# Symbol
|
66
66
|
# Checks for a non-false reply to calling the symbol on the stanza
|
@@ -93,9 +93,24 @@ There are 5 different types of guards:
|
|
93
93
|
# Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
|
94
94
|
message [{:body => 'foo'}, {:body => 'baz'}]
|
95
95
|
|
96
|
+
== On the Command Line:
|
97
|
+
|
98
|
+
Default usage is:
|
99
|
+
|
100
|
+
[blather_script] [options] node@domain.com/resource password [host] [port]
|
101
|
+
|
102
|
+
Command line options:
|
103
|
+
|
104
|
+
-D, --debug Run in debug mode (you will see all XMPP communication)
|
105
|
+
-d, --daemonize Daemonize the process
|
106
|
+
--pid=[PID] Write the PID to this file
|
107
|
+
--log=[LOG] Write to the [LOG] file instead of stdout/stderr
|
108
|
+
-h, --help Show this message
|
109
|
+
-v, --version Show version
|
110
|
+
|
111
|
+
|
96
112
|
= TODO
|
97
113
|
|
98
|
-
* Better Documentation
|
99
114
|
* Add XPath guard that passes the result to the handler
|
100
115
|
* Add Disco the the DSL
|
101
116
|
* PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ begin
|
|
16
16
|
gem.extensions = ['Rakefile']
|
17
17
|
|
18
18
|
gem.add_dependency 'eventmachine', '>= 0.12.6'
|
19
|
-
gem.add_dependency 'libxml-ruby', '>= 1.1.
|
19
|
+
gem.add_dependency 'libxml-ruby', '>= 1.1.2'
|
20
20
|
|
21
21
|
gem.files = FileList['examples/**/*', 'lib/**/*', 'ext/*.{rb,c}'].to_a
|
22
22
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'blather/client/dsl'
|
2
|
+
$stdout.sync = true
|
3
|
+
|
4
|
+
module Ping
|
5
|
+
extend Blather::DSL
|
6
|
+
def self.run; client.run; end
|
7
|
+
|
8
|
+
setup 'echo@jabber.local/ping', 'echo'
|
9
|
+
|
10
|
+
status :from => Blather::JID.new('echo@jabber.local/pong') do |s|
|
11
|
+
puts "serve!"
|
12
|
+
say s.from, 'ping'
|
13
|
+
end
|
14
|
+
|
15
|
+
message :chat?, :body => 'pong' do |m|
|
16
|
+
puts "ping!"
|
17
|
+
say m.from, 'ping'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Pong
|
22
|
+
extend Blather::DSL
|
23
|
+
def self.run; client.run; end
|
24
|
+
|
25
|
+
setup 'echo@jabber.local/pong', 'echo'
|
26
|
+
message :chat?, :body => 'ping' do |m|
|
27
|
+
puts "pong!"
|
28
|
+
say m.from, 'pong'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
trap(:INT) { EM.stop }
|
33
|
+
trap(:TERM) { EM.stop }
|
34
|
+
EM.run do
|
35
|
+
Ping.run
|
36
|
+
Pong.run
|
37
|
+
end
|
data/lib/blather.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
2
|
-
$:.unshift File.join(File.dirname(__FILE__), '..')
|
3
|
-
|
4
1
|
# Require the necessary files
|
5
2
|
%w[
|
6
3
|
rubygems
|
@@ -48,6 +45,6 @@ $:.unshift File.join(File.dirname(__FILE__), '..')
|
|
48
45
|
XML.indent_tree_output = false
|
49
46
|
|
50
47
|
module Blather
|
51
|
-
LOG = Logger.new(
|
48
|
+
LOG = Logger.new($stdout) unless const_defined?(:LOG)
|
52
49
|
LOG.level = Logger::INFO
|
53
50
|
end
|
data/lib/blather/client.rb
CHANGED
@@ -1,13 +1,85 @@
|
|
1
|
+
require 'optparse'
|
1
2
|
require File.join(File.dirname(__FILE__), *%w[client dsl])
|
2
3
|
|
3
4
|
include Blather::DSL
|
4
5
|
|
6
|
+
options = {}
|
7
|
+
optparse = OptionParser.new do |opts|
|
8
|
+
opts.banner = "Run with #{$0} [options] user@server/resource password [host] [port]"
|
9
|
+
|
10
|
+
opts.on('-D', '--debug', 'Run in debug mode (you will see all XMPP communication)') do |debug|
|
11
|
+
options[:debug] = debug
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on('-d', '--daemonize', 'Daemonize the process') do |daemonize|
|
15
|
+
options[:daemonize] = daemonize
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on('--pid=[PID]', 'Write the PID to this file') do |pid|
|
19
|
+
if !File.writable?(File.dirname(pid))
|
20
|
+
$stderr.puts "Unable to write log file to #{pid}"
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
options[:pid] = pid
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on('--log=[LOG]', 'Write to the [LOG] file instead of stdout/stderr') do |log|
|
27
|
+
if !File.writable?(File.dirname(log))
|
28
|
+
$stderr.puts "Unable to write log file to #{log}"
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
options[:log] = log
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
35
|
+
puts opts
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
40
|
+
require 'yaml'
|
41
|
+
version = YAML.load_file File.join(File.dirname(__FILE__), %w[.. .. VERSION.yml])
|
42
|
+
puts "Blather v#{version[:major]}.#{version[:minor]}.#{version[:patch]}"
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
optparse.parse!
|
47
|
+
|
5
48
|
at_exit do
|
6
49
|
unless client.setup?
|
7
50
|
if ARGV.length < 2
|
8
|
-
puts
|
9
|
-
|
10
|
-
|
51
|
+
puts optparse
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
client.setup(*ARGV)
|
55
|
+
end
|
56
|
+
|
57
|
+
def run(options)
|
58
|
+
$stdin.reopen "/dev/null"
|
59
|
+
|
60
|
+
if options[:log]
|
61
|
+
log = File.new(options[:log], 'a')
|
62
|
+
log.sync = options[:debug]
|
63
|
+
Blather::LOG.level = Logger::DEBUG if options[:debug]
|
64
|
+
$stdout.reopen log
|
65
|
+
$stderr.reopen $stdout
|
66
|
+
end
|
67
|
+
trap(:INT) { EM.stop }
|
68
|
+
trap(:TERM) { EM.stop }
|
69
|
+
EM.run { client.run }
|
70
|
+
end
|
71
|
+
|
72
|
+
if options[:daemonize]
|
73
|
+
pid = fork do
|
74
|
+
Process.setsid
|
75
|
+
exit if fork
|
76
|
+
File.open(options[:pid], 'w') { |f| f << Process.pid } if options[:pid]
|
77
|
+
run options
|
78
|
+
FileUtils.rm(options[:pid]) if options[:pid]
|
11
79
|
end
|
80
|
+
::Process.detach pid
|
81
|
+
exit
|
82
|
+
else
|
83
|
+
run options
|
12
84
|
end
|
13
85
|
end
|
@@ -3,8 +3,8 @@ require File.join(File.dirname(__FILE__), *%w[.. .. blather])
|
|
3
3
|
module Blather #:nodoc:
|
4
4
|
|
5
5
|
class Client #:nodoc:
|
6
|
-
|
7
|
-
|
6
|
+
attr_reader :jid,
|
7
|
+
:roster
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@state = :initializing
|
@@ -17,6 +17,24 @@ module Blather #:nodoc:
|
|
17
17
|
setup_initial_handlers
|
18
18
|
end
|
19
19
|
|
20
|
+
def jid=(new_jid)
|
21
|
+
@jid = JID.new new_jid
|
22
|
+
end
|
23
|
+
|
24
|
+
def status
|
25
|
+
@status.state
|
26
|
+
end
|
27
|
+
|
28
|
+
def status=(state)
|
29
|
+
state, msg, to = state
|
30
|
+
|
31
|
+
status = Stanza::Presence::Status.new state, msg
|
32
|
+
status.to = to
|
33
|
+
@status = status unless to
|
34
|
+
|
35
|
+
write status
|
36
|
+
end
|
37
|
+
|
20
38
|
def setup?
|
21
39
|
@setup.is_a? Array
|
22
40
|
end
|
@@ -30,11 +48,8 @@ module Blather #:nodoc:
|
|
30
48
|
|
31
49
|
def run
|
32
50
|
raise 'not setup!' unless setup?
|
33
|
-
|
34
|
-
|
35
|
-
klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
|
36
|
-
klass.start self, *@setup
|
37
|
-
}
|
51
|
+
klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
|
52
|
+
@stream = klass.start self, *@setup
|
38
53
|
end
|
39
54
|
|
40
55
|
def register_tmp_handler(id, &handler)
|
@@ -42,62 +57,38 @@ module Blather #:nodoc:
|
|
42
57
|
end
|
43
58
|
|
44
59
|
def register_handler(type, *guards, &handler)
|
60
|
+
check_guards guards
|
45
61
|
@handlers[type] ||= []
|
46
62
|
@handlers[type] << [guards, handler]
|
47
63
|
end
|
48
64
|
|
49
|
-
def status
|
50
|
-
@status.state
|
51
|
-
end
|
52
|
-
|
53
|
-
def status=(state)
|
54
|
-
state, msg, to = state
|
55
|
-
|
56
|
-
status = Stanza::Presence::Status.new state, msg
|
57
|
-
status.to = to
|
58
|
-
@status = status unless to
|
59
|
-
|
60
|
-
write status
|
61
|
-
end
|
62
|
-
|
63
65
|
def write(stanza)
|
64
66
|
stanza.from ||= jid if stanza.respond_to?(:from)
|
65
67
|
@stream.send(stanza) if @stream
|
66
68
|
end
|
67
69
|
|
68
|
-
def write_with_handler(stanza, &
|
70
|
+
def write_with_handler(stanza, &handler)
|
69
71
|
register_tmp_handler stanza.id, &handler
|
70
72
|
write stanza
|
71
73
|
end
|
72
74
|
|
73
|
-
def
|
74
|
-
@stream
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
@state = :ready
|
79
|
-
call_handler_for :ready, nil
|
80
|
-
else
|
81
|
-
r = Stanza::Iq::Roster.new
|
82
|
-
register_tmp_handler r.id do |node|
|
83
|
-
roster.process node
|
84
|
-
@state = :ready
|
85
|
-
write @status
|
86
|
-
call_handler_for :ready, nil
|
87
|
-
end
|
88
|
-
write r
|
75
|
+
def post_init
|
76
|
+
case @stream
|
77
|
+
when Stream::Component then ready!
|
78
|
+
when Stream::Client then client_post_init
|
79
|
+
else raise "Don't know #{@stream.class} stream type. How the hell did this happen!?"
|
89
80
|
end
|
90
81
|
end
|
91
82
|
|
92
|
-
def
|
83
|
+
def close
|
93
84
|
@stream.close_connection_after_writing
|
94
85
|
end
|
95
86
|
|
96
|
-
def
|
97
|
-
EM.stop
|
87
|
+
def unbind
|
88
|
+
EM.stop if EM.reactor_running?
|
98
89
|
end
|
99
90
|
|
100
|
-
def
|
91
|
+
def receive_data(stanza)
|
101
92
|
if handler = @tmp_handlers.delete(stanza.id)
|
102
93
|
handler.call stanza
|
103
94
|
else
|
@@ -107,21 +98,14 @@ module Blather #:nodoc:
|
|
107
98
|
end
|
108
99
|
end
|
109
100
|
|
110
|
-
def call_handler_for(type, stanza)
|
111
|
-
if @handlers[type]
|
112
|
-
@handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
|
113
|
-
true
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
101
|
protected
|
118
102
|
def setup_initial_handlers
|
119
103
|
register_handler :error do |err|
|
120
104
|
raise err
|
121
105
|
end
|
122
106
|
|
123
|
-
register_handler :iq do |iq|
|
124
|
-
write(StanzaError.new(iq, 'service-unavailable', :cancel).to_node)
|
107
|
+
register_handler :iq, :type => [:get, :set] do |iq|
|
108
|
+
write(StanzaError.new(iq, 'service-unavailable', :cancel).to_node)
|
125
109
|
end
|
126
110
|
|
127
111
|
register_handler :status do |status|
|
@@ -133,8 +117,30 @@ module Blather #:nodoc:
|
|
133
117
|
end
|
134
118
|
end
|
135
119
|
|
120
|
+
def ready!
|
121
|
+
@state = :ready
|
122
|
+
call_handler_for :ready, nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def client_post_init
|
126
|
+
write_with_handler Stanza::Iq::Roster.new do |node|
|
127
|
+
roster.process node
|
128
|
+
write @status
|
129
|
+
ready!
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def call_handler_for(type, stanza)
|
134
|
+
if @handlers[type]
|
135
|
+
@handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
|
136
|
+
true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
136
140
|
##
|
137
141
|
# If any of the guards returns FALSE this returns true
|
142
|
+
# the logic is reversed to allow short circuiting
|
143
|
+
# (why would anyone want to loop over more values than necessary?)
|
138
144
|
def guarded?(guards, stanza)
|
139
145
|
guards.find do |guard|
|
140
146
|
case guard
|
@@ -158,8 +164,16 @@ module Blather #:nodoc:
|
|
158
164
|
end
|
159
165
|
when Proc
|
160
166
|
!guard.call(stanza)
|
161
|
-
|
162
|
-
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def check_guards(guards)
|
172
|
+
guards.each do |guard|
|
173
|
+
case guard
|
174
|
+
when Array then guard.each { |g| check_guards([g]) }
|
175
|
+
when Symbol, Proc, Hash then nil
|
176
|
+
else raise "Bad guard: #{guard.inspect}"
|
163
177
|
end
|
164
178
|
end
|
165
179
|
end
|
data/lib/blather/client/dsl.rb
CHANGED
@@ -13,14 +13,13 @@ module Blather
|
|
13
13
|
# host and port are optional defaulting to the domain in the JID and 5222 respectively
|
14
14
|
def setup(jid, password, host = nil, port = nil)
|
15
15
|
client.setup(jid, password, host, port)
|
16
|
-
at_exit { client.run }
|
17
16
|
end
|
18
17
|
|
19
18
|
##
|
20
19
|
# Shutdown the connection.
|
21
20
|
# Flushes the write buffer then stops EventMachine
|
22
21
|
def shutdown
|
23
|
-
client.
|
22
|
+
client.close
|
24
23
|
end
|
25
24
|
|
26
25
|
##
|
@@ -37,13 +36,13 @@ module Blather
|
|
37
36
|
|
38
37
|
##
|
39
38
|
# Set current status
|
40
|
-
def
|
39
|
+
def set_status(state = nil, msg = nil)
|
41
40
|
client.status = state, msg
|
42
41
|
end
|
43
42
|
|
44
43
|
##
|
45
44
|
# Direct access to the roster
|
46
|
-
def
|
45
|
+
def my_roster
|
47
46
|
client.roster
|
48
47
|
end
|
49
48
|
|
@@ -51,7 +50,7 @@ module Blather
|
|
51
50
|
# Write data to the stream
|
52
51
|
# Anything that resonds to #to_s can be paseed to the stream
|
53
52
|
def write(stanza)
|
54
|
-
client.write
|
53
|
+
client.write stanza
|
55
54
|
end
|
56
55
|
|
57
56
|
##
|
@@ -68,7 +67,9 @@ module Blather
|
|
68
67
|
end
|
69
68
|
|
70
69
|
##
|
71
|
-
#
|
70
|
+
# Request items or info from an entity
|
71
|
+
# discover (items|info), [jid], [node] do |response|
|
72
|
+
# end
|
72
73
|
def discover(what, who, where, &callback)
|
73
74
|
stanza = Blather::Stanza.class_from_registration(:query, "http://jabber.org/protocol/disco##{what}").new
|
74
75
|
stanza.to = who
|
@@ -78,22 +79,16 @@ module Blather
|
|
78
79
|
write stanza
|
79
80
|
end
|
80
81
|
|
81
|
-
##
|
82
|
-
# PubSub proxy
|
83
|
-
def pubsub
|
84
|
-
client.pubsub
|
85
|
-
end
|
86
|
-
|
87
82
|
##
|
88
83
|
# Checks to see if the method is part of the handlers list.
|
89
84
|
# If so it creates a handler, otherwise it'll pass it back
|
90
85
|
# to Ruby's method_missing handler
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
86
|
+
Blather::Stanza.handler_list.each do |handler_name|
|
87
|
+
module_eval <<-METHOD, __FILE__, __LINE__
|
88
|
+
def #{handler_name}(*args, &callback)
|
89
|
+
handle :#{handler_name}, *args, &callback
|
90
|
+
end
|
91
|
+
METHOD
|
97
92
|
end
|
98
93
|
end #DSL
|
99
94
|
end #Blather
|
@@ -52,13 +52,6 @@ class Stanza
|
|
52
52
|
self.category = category
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
56
|
-
def eql?(other)
|
57
|
-
other.kind_of?(self.class) &&
|
58
|
-
other.name == self.name &&
|
59
|
-
other.type == self.type &&
|
60
|
-
other.category == self.category
|
61
|
-
end
|
62
55
|
end
|
63
56
|
|
64
57
|
class Feature < XMPPNode
|
@@ -72,11 +65,6 @@ class Stanza
|
|
72
65
|
self.var = var
|
73
66
|
end
|
74
67
|
end
|
75
|
-
|
76
|
-
def eql?(other)
|
77
|
-
other.kind_of?(self.class) &&
|
78
|
-
other.var == self.var
|
79
|
-
end
|
80
68
|
end
|
81
69
|
end
|
82
70
|
|
data/lib/blather/stream.rb
CHANGED
@@ -87,8 +87,8 @@ module Blather
|
|
87
87
|
def unbind # :nodoc:
|
88
88
|
# @keepalive.cancel
|
89
89
|
@state = :stopped
|
90
|
-
@client.
|
91
|
-
@client.
|
90
|
+
@client.receive_data @error if @error
|
91
|
+
@client.unbind
|
92
92
|
end
|
93
93
|
|
94
94
|
##
|
@@ -162,7 +162,7 @@ module Blather
|
|
162
162
|
# Called when @state == :ready
|
163
163
|
# Simply passes the stanza to the client
|
164
164
|
def ready
|
165
|
-
@client.
|
165
|
+
@client.receive_data @node.to_stanza
|
166
166
|
end
|
167
167
|
|
168
168
|
def handle_stream_error
|
@@ -242,7 +242,7 @@ module Blather
|
|
242
242
|
@session = Session.new self, @to
|
243
243
|
# on success destroy the session object, let the client know the stream has been started
|
244
244
|
# then continue the features dispatch process
|
245
|
-
@session.on_success { LOG.debug "SESSION: SUCCESS"; @session = nil; @client.
|
245
|
+
@session.on_success { LOG.debug "SESSION: SUCCESS"; @session = nil; @client.post_init; @state = :features; dispatch }
|
246
246
|
# on failure end the stream
|
247
247
|
@session.on_failure { |err| LOG.debug "SESSION: FAILURE"; @error = err; stop }
|
248
248
|
|
@@ -0,0 +1,389 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
require 'blather/client/client'
|
3
|
+
|
4
|
+
describe 'Blather::Client' do
|
5
|
+
before do
|
6
|
+
@client = Blather::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'provides a JID accessor' do
|
10
|
+
@client.must_respond_to :jid
|
11
|
+
@client.jid.must_be_nil
|
12
|
+
|
13
|
+
jid = 'me@me.com/test'
|
14
|
+
@client.must_respond_to :jid=
|
15
|
+
@client.jid = jid
|
16
|
+
@client.jid.must_be_kind_of JID
|
17
|
+
@client.jid.must_equal JID.new(jid)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'provides a reader for the roster' do
|
21
|
+
@client.must_respond_to :roster
|
22
|
+
@client.roster.must_be_kind_of Roster
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'provides a status reader' do
|
26
|
+
@client.must_respond_to :status
|
27
|
+
@client.status = :away
|
28
|
+
@client.status.must_equal :away
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can be setup' do
|
32
|
+
@client.must_respond_to :setup
|
33
|
+
@client.setup('me@me.com', 'pass').must_equal @client
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'knows if it has been setup' do
|
37
|
+
@client.must_respond_to :setup?
|
38
|
+
@client.setup?.must_equal false
|
39
|
+
@client.setup 'me@me.com', 'pass'
|
40
|
+
@client.setup?.must_equal true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'cannot be run before being setup' do
|
44
|
+
lambda { @client.run }.must_raise RuntimeError
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'starts up a Component connection when setup without a node' do
|
48
|
+
setup = 'pubsub.jabber.local', 'secret'
|
49
|
+
@client.setup *setup
|
50
|
+
Blather::Stream::Component.expects(:start).with @client, *setup
|
51
|
+
@client.run
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'starts up a Client connection when setup with a node' do
|
55
|
+
setup = 'test@jabber.local', 'secret'
|
56
|
+
@client.setup *setup
|
57
|
+
Blather::Stream::Client.expects(:start).with @client, *setup
|
58
|
+
@client.run
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'writes to the connection the closes when #close is called' do
|
62
|
+
stream = mock()
|
63
|
+
stream.expects(:close_connection_after_writing)
|
64
|
+
Blather::Stream::Component.stubs(:start).returns stream
|
65
|
+
@client.setup('me.com', 'secret').run
|
66
|
+
@client.close
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'shuts down EM when #unbind is called if it is running' do
|
70
|
+
EM.expects(:reactor_running?).returns true
|
71
|
+
EM.expects(:stop)
|
72
|
+
@client.unbind
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does nothing when #unbind is called and EM is not running' do
|
76
|
+
EM.expects(:reactor_running?).returns false
|
77
|
+
EM.expects(:stop).never
|
78
|
+
@client.unbind
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'raises an error if the stream type somehow is not supported' do
|
82
|
+
Blather::Stream::Component.stubs(:start).returns nil
|
83
|
+
@client.setup('me.com', 'secret').run
|
84
|
+
lambda { @client.post_init }.must_raise RuntimeError
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'can register a temporary handler based on stanza ID' do
|
88
|
+
stanza = Stanza::Iq.new
|
89
|
+
response = mock()
|
90
|
+
response.expects(:call)
|
91
|
+
@client.register_tmp_handler(stanza.id) { |_| response.call }
|
92
|
+
@client.receive_data stanza
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'removes a tmp handler as soon as it is used' do
|
96
|
+
stanza = Stanza::Iq.new
|
97
|
+
response = mock()
|
98
|
+
response.expects(:call)
|
99
|
+
@client.register_tmp_handler(stanza.id) { |_| response.call }
|
100
|
+
@client.receive_data stanza
|
101
|
+
@client.receive_data stanza
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'will create a handler then write the stanza' do
|
105
|
+
stanza = Stanza::Iq.new
|
106
|
+
response = mock()
|
107
|
+
response.expects(:call)
|
108
|
+
@client.expects(:write).with do |s|
|
109
|
+
@client.receive_data stanza
|
110
|
+
s.must_equal stanza
|
111
|
+
end
|
112
|
+
@client.write_with_handler(stanza) { |_| response.call }
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'can register a handler' do
|
116
|
+
stanza = Stanza::Iq.new
|
117
|
+
response = mock()
|
118
|
+
response.expects(:call).times(2)
|
119
|
+
@client.register_handler(:iq) { |_| response.call }
|
120
|
+
@client.receive_data stanza
|
121
|
+
@client.receive_data stanza
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'Blather::Client#write' do
|
126
|
+
before do
|
127
|
+
@client = Blather::Client.new
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'sets the from attr on a stanza' do
|
131
|
+
jid = 'me@me.com'
|
132
|
+
stanza = mock(:from => nil)
|
133
|
+
stanza.expects(:from=).with jid
|
134
|
+
@client.jid = jid
|
135
|
+
@client.write stanza
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'does not set the from attr if it already exists' do
|
139
|
+
jid = 'me@me.com'
|
140
|
+
stanza = Stanza::Iq.new
|
141
|
+
stanza.from = jid
|
142
|
+
stanza.expects(:from).returns jid
|
143
|
+
stanza.expects(:from=).never
|
144
|
+
@client.jid = jid
|
145
|
+
@client.write stanza
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'writes to the stream' do
|
149
|
+
stanza = Stanza::Iq.new
|
150
|
+
stream = mock()
|
151
|
+
stream.expects(:send).with stanza
|
152
|
+
Blather::Stream::Client.expects(:start).returns stream
|
153
|
+
@client.setup('me@me.com', 'me').run
|
154
|
+
@client.write stanza
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe 'Blather::Client#status=' do
|
159
|
+
before do
|
160
|
+
@client = Blather::Client.new
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'updates the state when not sending to a JID' do
|
164
|
+
@client.status.wont_equal :away
|
165
|
+
@client.status = :away, 'message'
|
166
|
+
@client.status.must_equal :away
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'does not update the state when sending to a JID' do
|
170
|
+
@client.status.wont_equal :away
|
171
|
+
@client.status = :away, 'message', 'me@me.com'
|
172
|
+
@client.status.wont_equal :away
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'writes the new status to the stream' do
|
176
|
+
Stanza::Presence::Status.stubs(:next_id).returns 0
|
177
|
+
status = [:away, 'message']
|
178
|
+
@client.expects(:write).with do |s|
|
179
|
+
s.must_be_kind_of Stanza::Presence::Status
|
180
|
+
s.to_s.must_equal Stanza::Presence::Status.new(*status).to_s
|
181
|
+
end
|
182
|
+
@client.status = status
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'Blather::Client default handlers' do
|
187
|
+
before do
|
188
|
+
@client = Blather::Client.new
|
189
|
+
end
|
190
|
+
|
191
|
+
it 're-raises errors' do
|
192
|
+
err = BlatherError.new
|
193
|
+
lambda { @client.receive_data err }.must_raise BlatherError
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'responds to iq:get with a "service-unavailable" error' do
|
197
|
+
get = Stanza::Iq.new :get
|
198
|
+
err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
199
|
+
@client.expects(:write).with err
|
200
|
+
@client.receive_data get
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'responds to iq:get with a "service-unavailable" error' do
|
204
|
+
get = Stanza::Iq.new :get
|
205
|
+
err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
206
|
+
@client.expects(:write).with err
|
207
|
+
@client.receive_data get
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'responds to iq:set with a "service-unavailable" error' do
|
211
|
+
get = Stanza::Iq.new :set
|
212
|
+
err = StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
213
|
+
@client.expects(:write).with err
|
214
|
+
@client.receive_data get
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'handles status changes by updating the roster if the status is from a JID in the roster' do
|
218
|
+
jid = 'friend@jabber.local'
|
219
|
+
status = Stanza::Presence::Status.new :away
|
220
|
+
status.stubs(:from).returns jid
|
221
|
+
roster_item = mock()
|
222
|
+
roster_item.expects(:status=).with status
|
223
|
+
@client.stubs(:roster).returns({status.from => roster_item})
|
224
|
+
@client.receive_data status
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'handles an incoming roster node by processing it through the roster' do
|
228
|
+
roster = Stanza::Iq::Roster.new
|
229
|
+
client_roster = mock()
|
230
|
+
client_roster.expects(:process).with roster
|
231
|
+
@client.stubs(:roster).returns client_roster
|
232
|
+
@client.receive_data roster
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe 'Blather::Client with a Component stream' do
|
237
|
+
before do
|
238
|
+
class MockComponent < Blather::Stream::Component; def initialize(); end; end
|
239
|
+
@client = Blather::Client.new
|
240
|
+
Blather::Stream::Component.stubs(:start).returns MockComponent.new('')
|
241
|
+
@client.setup('me.com', 'secret').run
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'calls the ready handler when sent post_init' do
|
245
|
+
ready = mock()
|
246
|
+
ready.expects(:call)
|
247
|
+
@client.register_handler(:ready) { ready.call }
|
248
|
+
@client.post_init
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe 'Blather::Client with a Client stream' do
|
253
|
+
before do
|
254
|
+
class MockClientStream < Blather::Stream::Client; def initialize(); end; end
|
255
|
+
@stream = MockClientStream.new('')
|
256
|
+
@client = Blather::Client.new
|
257
|
+
Blather::Stream::Client.stubs(:start).returns @stream
|
258
|
+
@client.setup('me@me.com', 'secret').run
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'sends a request for the roster when post_init is called' do
|
262
|
+
@stream.expects(:send).with { |stanza| stanza.must_be_kind_of Stanza::Iq::Roster }
|
263
|
+
@client.post_init
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'calls the ready handler after post_init and roster is received' do
|
267
|
+
result_roster = Stanza::Iq::Roster.new :result
|
268
|
+
@stream.stubs(:send).with { |s| result_roster.id = s.id; @client.receive_data result_roster; true }
|
269
|
+
|
270
|
+
ready = mock()
|
271
|
+
ready.expects(:call)
|
272
|
+
@client.register_handler(:ready) { ready.call }
|
273
|
+
@client.post_init
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe 'Blather::Client guards' do
|
278
|
+
before do
|
279
|
+
@client = Blather::Client.new
|
280
|
+
@stanza = Stanza::Iq.new
|
281
|
+
@response = mock()
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'can be a symbol' do
|
285
|
+
@response.expects :call
|
286
|
+
@client.register_handler(:iq, :chat?) { |_| @response.call }
|
287
|
+
|
288
|
+
@stanza.expects(:chat?).returns true
|
289
|
+
@client.receive_data @stanza
|
290
|
+
|
291
|
+
@stanza.expects(:chat?).returns false
|
292
|
+
@client.receive_data @stanza
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'can be a hash with string match' do
|
296
|
+
@response.expects :call
|
297
|
+
@client.register_handler(:iq, :body => 'exit') { |_| @response.call }
|
298
|
+
|
299
|
+
@stanza.expects(:body).returns 'exit'
|
300
|
+
@client.receive_data @stanza
|
301
|
+
|
302
|
+
@stanza.expects(:body).returns 'not-exit'
|
303
|
+
@client.receive_data @stanza
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'can be a hash with a value' do
|
307
|
+
@response.expects :call
|
308
|
+
@client.register_handler(:iq, :number => 0) { |_| @response.call }
|
309
|
+
|
310
|
+
@stanza.expects(:number).returns 0
|
311
|
+
@client.receive_data @stanza
|
312
|
+
|
313
|
+
@stanza.expects(:number).returns 1
|
314
|
+
@client.receive_data @stanza
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'can be a hash with a regexp' do
|
318
|
+
@response.expects :call
|
319
|
+
@client.register_handler(:iq, :body => /exit/) { |_| @response.call }
|
320
|
+
|
321
|
+
@stanza.expects(:body).returns 'more than just exit, but exit still'
|
322
|
+
@client.receive_data @stanza
|
323
|
+
|
324
|
+
@stanza.expects(:body).returns 'keyword not found'
|
325
|
+
@client.receive_data @stanza
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'can be a hash with an array' do
|
329
|
+
@response.expects(:call).times(2)
|
330
|
+
@client.register_handler(:iq, :type => [:result, :error]) { |_| @response.call }
|
331
|
+
|
332
|
+
stanza = Stanza::Iq.new
|
333
|
+
stanza.expects(:type).at_least_once.returns :result
|
334
|
+
@client.receive_data stanza
|
335
|
+
|
336
|
+
stanza = Stanza::Iq.new
|
337
|
+
stanza.expects(:type).at_least_once.returns :error
|
338
|
+
@client.receive_data stanza
|
339
|
+
|
340
|
+
stanza = Stanza::Iq.new
|
341
|
+
stanza.expects(:type).at_least_once.returns :get
|
342
|
+
@client.receive_data stanza
|
343
|
+
end
|
344
|
+
|
345
|
+
it 'chained are treated like andand (short circuited)' do
|
346
|
+
@response.expects :call
|
347
|
+
@client.register_handler(:iq, :type => :get, :body => 'test') { |_| @response.call }
|
348
|
+
|
349
|
+
stanza = Stanza::Iq.new
|
350
|
+
stanza.expects(:type).at_least_once.returns :get
|
351
|
+
stanza.expects(:body).returns 'test'
|
352
|
+
@client.receive_data stanza
|
353
|
+
|
354
|
+
stanza = Stanza::Iq.new
|
355
|
+
stanza.expects(:type).at_least_once.returns :set
|
356
|
+
stanza.expects(:body).never
|
357
|
+
@client.receive_data stanza
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'within an Array are treated as oror (short circuited)' do
|
361
|
+
@response.expects(:call).times 2
|
362
|
+
@client.register_handler(:iq, [{:type => :get}, {:body => 'test'}]) { |_| @response.call }
|
363
|
+
|
364
|
+
stanza = Stanza::Iq.new
|
365
|
+
stanza.expects(:type).at_least_once.returns :set
|
366
|
+
stanza.expects(:body).returns 'test'
|
367
|
+
@client.receive_data stanza
|
368
|
+
|
369
|
+
stanza = Stanza::Iq.new
|
370
|
+
stanza.stubs(:type).at_least_once.returns :get
|
371
|
+
stanza.expects(:body).never
|
372
|
+
@client.receive_data stanza
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'can be a lambda' do
|
376
|
+
@response.expects :call
|
377
|
+
@client.register_handler(:iq, lambda { |s| s.number % 3 == 0 }) { |_| @response.call }
|
378
|
+
|
379
|
+
@stanza.expects(:number).at_least_once.returns 3
|
380
|
+
@client.receive_data @stanza
|
381
|
+
|
382
|
+
@stanza.expects(:number).at_least_once.returns 2
|
383
|
+
@client.receive_data @stanza
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'raises an error when a bad guard is tried' do
|
387
|
+
lambda { @client.register_handler(:iq, 0) {} }.must_raise RuntimeError
|
388
|
+
end
|
389
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
require 'blather/client/dsl'
|
3
|
+
|
4
|
+
describe 'Blather::DSL' do
|
5
|
+
before do
|
6
|
+
@client = mock()
|
7
|
+
@dsl = class MockDSL; include Blather::DSL; end.new
|
8
|
+
Client.stubs(:new).returns(@client)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'wraps the setup' do
|
12
|
+
args = ['jid', 'pass', 'host', 0000]
|
13
|
+
@client.expects(:setup).with *args
|
14
|
+
@dsl.setup *args
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows host to be nil in setup' do
|
18
|
+
args = ['jid', 'pass']
|
19
|
+
@client.expects(:setup).with *(args + [nil, nil])
|
20
|
+
@dsl.setup *args
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'allows port to be nil in setup' do
|
24
|
+
args = ['jid', 'pass', 'host']
|
25
|
+
@client.expects(:setup).with *(args + [nil])
|
26
|
+
@dsl.setup *args
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'stops when shutdown is called' do
|
30
|
+
@client.expects(:close)
|
31
|
+
@dsl.shutdown
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'sets up handlers' do
|
35
|
+
type = :message
|
36
|
+
guards = [:chat?, {:body => 'exit'}]
|
37
|
+
@client.expects(:register_handler).with type, *guards
|
38
|
+
@dsl.handle type, *guards
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'provides a helper for ready state' do
|
42
|
+
@client.expects(:register_handler).with :ready
|
43
|
+
@dsl.when_ready
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'sets the initial status' do
|
47
|
+
state = :away
|
48
|
+
msg = 'do not disturb'
|
49
|
+
@client.expects(:status=).with [state, msg]
|
50
|
+
@dsl.set_status state, msg
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'provides a roster accessor' do
|
54
|
+
@client.expects :roster
|
55
|
+
@dsl.my_roster
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'provides a writer' do
|
59
|
+
stanza = Blather::Stanza::Iq.new
|
60
|
+
@client.expects(:write).with stanza
|
61
|
+
@dsl.write stanza
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'provides a "say" helper' do
|
65
|
+
to, msg = 'me@me.com', 'hello!'
|
66
|
+
Blather::Stanza::Message.stubs(:next_id).returns 0
|
67
|
+
@client.expects(:write).with Blather::Stanza::Message.new(to, msg)
|
68
|
+
@dsl.say to, msg
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'provides a JID accessor' do
|
72
|
+
@client.expects :jid
|
73
|
+
@dsl.jid
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'provides a disco helper for items' do
|
77
|
+
what, who, where = :items, 'me@me.com', 'my/node'
|
78
|
+
Blather::Stanza::Disco::DiscoItems.stubs(:next_id).returns 0
|
79
|
+
@client.expects(:temporary_handler).with '0'
|
80
|
+
expected_stanza = Blather::Stanza::Disco::DiscoItems.new
|
81
|
+
expected_stanza.to = who
|
82
|
+
expected_stanza.node = where
|
83
|
+
@client.expects(:write).with expected_stanza
|
84
|
+
@dsl.discover what, who, where
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'provides a disco helper for info' do
|
88
|
+
what, who, where = :info, 'me@me.com', 'my/node'
|
89
|
+
Blather::Stanza::Disco::DiscoInfo.stubs(:next_id).returns 0
|
90
|
+
@client.expects(:temporary_handler).with '0'
|
91
|
+
expected_stanza = Blather::Stanza::Disco::DiscoInfo.new
|
92
|
+
expected_stanza.to = who
|
93
|
+
expected_stanza.node = where
|
94
|
+
@client.expects(:write).with expected_stanza
|
95
|
+
@dsl.discover what, who, where
|
96
|
+
end
|
97
|
+
|
98
|
+
Blather::Stanza.handler_list.each do |handler_method|
|
99
|
+
it "provides a helper method for #{handler_method}" do
|
100
|
+
guards = [:chat?, {:body => 'exit'}]
|
101
|
+
@client.expects(:register_handler).with handler_method, *guards
|
102
|
+
@dsl.__send__(handler_method, *guards)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -11,7 +11,7 @@ describe 'Blather::Stream::Client' do
|
|
11
11
|
|
12
12
|
def mocked_server(times = nil, &block)
|
13
13
|
@client ||= mock()
|
14
|
-
@client.stubs(:
|
14
|
+
@client.stubs(:unbind) unless @client.respond_to?(:unbind)
|
15
15
|
@client.stubs(:jid=) unless @client.respond_to?(:jid=)
|
16
16
|
|
17
17
|
MockServer.any_instance.expects(:receive_data).send(*(times ? [:times, times] : [:at_least, 1])).with &block
|
@@ -58,7 +58,7 @@ describe 'Blather::Stream::Client' do
|
|
58
58
|
|
59
59
|
it 'sends stanzas to the client when the stream is ready' do
|
60
60
|
@client = mock()
|
61
|
-
@client.expects(:
|
61
|
+
@client.expects(:receive_data).with do |n|
|
62
62
|
EM.stop
|
63
63
|
n.kind_of?(Stanza::Message) && @stream.ready?.must_equal(true)
|
64
64
|
end
|
@@ -72,7 +72,7 @@ describe 'Blather::Stream::Client' do
|
|
72
72
|
|
73
73
|
it 'puts itself in the stopped state and calls @client.stopped when stopped' do
|
74
74
|
@client = mock()
|
75
|
-
@client.expects(:
|
75
|
+
@client.expects(:unbind).at_least_once
|
76
76
|
|
77
77
|
started = false
|
78
78
|
mocked_server(2) do |val, server|
|
@@ -95,8 +95,8 @@ describe 'Blather::Stream::Client' do
|
|
95
95
|
it 'will be in the negotiating state during feature negotiations' do
|
96
96
|
state = nil
|
97
97
|
@client = mock()
|
98
|
-
@client.stubs(:
|
99
|
-
@client.expects(:
|
98
|
+
@client.stubs(:post_init)
|
99
|
+
@client.expects(:receive_data).with do |n|
|
100
100
|
EM.stop
|
101
101
|
state.must_equal(:negotiated) && @stream.negotiating?.must_equal(false)
|
102
102
|
end
|
@@ -154,7 +154,7 @@ describe 'Blather::Stream::Client' do
|
|
154
154
|
|
155
155
|
it 'sends client an error on stream:error' do
|
156
156
|
@client = mock()
|
157
|
-
@client.expects(:
|
157
|
+
@client.expects(:receive_data).with do |v|
|
158
158
|
v.name.must_equal :conflict
|
159
159
|
v.text.must_equal 'Already signed in'
|
160
160
|
v.to_s.must_equal "Stream Error (conflict): #{v.text}"
|
@@ -216,7 +216,7 @@ describe 'Blather::Stream::Client' do
|
|
216
216
|
it 'will fail if TLS negotiation fails' do
|
217
217
|
state = nil
|
218
218
|
@client = mock()
|
219
|
-
@client.expects(:
|
219
|
+
@client.expects(:receive_data).with { |v| v.must_be_kind_of TLSFailure }
|
220
220
|
mocked_server(3) do |val, server|
|
221
221
|
case state
|
222
222
|
when nil
|
@@ -245,7 +245,7 @@ describe 'Blather::Stream::Client' do
|
|
245
245
|
it 'will fail if a bad node comes through TLS negotiations' do
|
246
246
|
state = nil
|
247
247
|
@client = mock()
|
248
|
-
@client.expects(:
|
248
|
+
@client.expects(:receive_data).with do |v|
|
249
249
|
v.must_be_kind_of UnknownResponse
|
250
250
|
v.node.element_name.must_equal 'foo-bar'
|
251
251
|
end
|
@@ -400,7 +400,7 @@ describe 'Blather::Stream::Client' do
|
|
400
400
|
it 'tries each possible mechanism until it fails completely' do
|
401
401
|
state = nil
|
402
402
|
@client = mock()
|
403
|
-
@client.expects(:
|
403
|
+
@client.expects(:receive_data).with do |n|
|
404
404
|
n.must_be_kind_of(SASLError)
|
405
405
|
n.name.must_equal :not_authorized
|
406
406
|
end
|
@@ -473,7 +473,7 @@ describe 'Blather::Stream::Client' do
|
|
473
473
|
|
474
474
|
it 'sends client an error when an unknown mechanism is sent' do
|
475
475
|
@client = mock()
|
476
|
-
@client.expects(:
|
476
|
+
@client.expects(:receive_data).with { |v| v.must_be_kind_of(Stream::SASL::UnknownMechanism) }
|
477
477
|
started = false
|
478
478
|
mocked_server(2) do |val, server|
|
479
479
|
if !started
|
@@ -500,7 +500,7 @@ describe 'Blather::Stream::Client' do
|
|
500
500
|
].each do |error_type|
|
501
501
|
it "fails on #{error_type}" do
|
502
502
|
@client = mock()
|
503
|
-
@client.expects(:
|
503
|
+
@client.expects(:receive_data).with do |n|
|
504
504
|
n.name.must_equal error_type.gsub('-','_').to_sym
|
505
505
|
end
|
506
506
|
state = nil
|
@@ -532,7 +532,7 @@ describe 'Blather::Stream::Client' do
|
|
532
532
|
|
533
533
|
it 'fails when an unkown node comes through during SASL negotiation' do
|
534
534
|
@client = mock()
|
535
|
-
@client.expects(:
|
535
|
+
@client.expects(:receive_data).with do |n|
|
536
536
|
n.must_be_instance_of UnknownResponse
|
537
537
|
n.node.element_name.must_equal 'foo-bar'
|
538
538
|
end
|
@@ -629,7 +629,7 @@ describe 'Blather::Stream::Client' do
|
|
629
629
|
it 'will return an error if resource binding errors out' do
|
630
630
|
state = nil
|
631
631
|
@client = mock()
|
632
|
-
@client.expects(:
|
632
|
+
@client.expects(:receive_data).with do |n|
|
633
633
|
n.name.must_equal :bad_request
|
634
634
|
end
|
635
635
|
mocked_server(3) do |val, server|
|
@@ -660,7 +660,7 @@ describe 'Blather::Stream::Client' do
|
|
660
660
|
it 'will return an error if an unkown node comes through during resouce binding' do
|
661
661
|
state = nil
|
662
662
|
@client = mock()
|
663
|
-
@client.expects(:
|
663
|
+
@client.expects(:receive_data).with do |n|
|
664
664
|
n.must_be_instance_of UnknownResponse
|
665
665
|
n.node.element_name.must_equal 'foo-bar'
|
666
666
|
end
|
@@ -692,7 +692,7 @@ describe 'Blather::Stream::Client' do
|
|
692
692
|
it 'will establish a session if requested' do
|
693
693
|
state = nil
|
694
694
|
@client = mock()
|
695
|
-
@client.expects(:
|
695
|
+
@client.expects(:post_init)
|
696
696
|
|
697
697
|
mocked_server(3) do |val, server|
|
698
698
|
case state
|
@@ -723,7 +723,7 @@ describe 'Blather::Stream::Client' do
|
|
723
723
|
it 'will return an error if session establishment errors out' do
|
724
724
|
state = nil
|
725
725
|
@client = mock()
|
726
|
-
@client.expects(:
|
726
|
+
@client.expects(:receive_data).with do |n|
|
727
727
|
n.name.must_equal :internal_server_error
|
728
728
|
end
|
729
729
|
mocked_server(3) do |val, server|
|
@@ -754,7 +754,7 @@ describe 'Blather::Stream::Client' do
|
|
754
754
|
it 'will return an error if an unknown node come through during session establishment' do
|
755
755
|
state = nil
|
756
756
|
@client = mock()
|
757
|
-
@client.expects(:
|
757
|
+
@client.expects(:receive_data).with do |n|
|
758
758
|
n.must_be_instance_of UnknownResponse
|
759
759
|
n.node.element_name.must_equal 'foo-bar'
|
760
760
|
end
|
@@ -785,7 +785,7 @@ describe 'Blather::Stream::Client' do
|
|
785
785
|
|
786
786
|
it 'sends client an error on parse error' do
|
787
787
|
@client = mock()
|
788
|
-
@client.expects(:
|
788
|
+
@client.expects(:receive_data).with do |v|
|
789
789
|
v.must_be_kind_of ParseError
|
790
790
|
v.message.must_match(/generate\-parse\-error/)
|
791
791
|
end
|
@@ -11,7 +11,7 @@ describe 'Blather::Stream::Component' do
|
|
11
11
|
|
12
12
|
def mocked_server(times = nil, &block)
|
13
13
|
@client ||= mock()
|
14
|
-
@client.stubs(:
|
14
|
+
@client.stubs(:unbind) unless @client.respond_to?(:unbind)
|
15
15
|
@client.stubs(:jid=) unless @client.respond_to?(:jid=)
|
16
16
|
|
17
17
|
MockServer.any_instance.expects(:receive_data).send(*(times ? [:times, times] : [:at_least, 1])).with &block
|
@@ -60,8 +60,8 @@ describe 'Blather::Stream::Component' do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'sends stanzas to the client when the stream is ready' do
|
63
|
-
@client = mock(:
|
64
|
-
@client.expects(:
|
63
|
+
@client = mock(:post_init)
|
64
|
+
@client.expects(:receive_data).with do |n|
|
65
65
|
EM.stop
|
66
66
|
n.kind_of?(Stanza::Message) && @stream.ready?.must_equal(true)
|
67
67
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), *%w[.. lib]))
|
3
|
+
|
4
|
+
require 'blather'
|
2
5
|
require 'rubygems'
|
3
6
|
require 'minitest/spec'
|
4
7
|
require 'mocha'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sprsquish-blather
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Smick
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-14 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.1.
|
33
|
+
version: 1.1.2
|
34
34
|
version:
|
35
35
|
description:
|
36
36
|
email: sprsquish@gmail.com
|
@@ -44,6 +44,7 @@ extra_rdoc_files:
|
|
44
44
|
files:
|
45
45
|
- examples/drb_client.rb
|
46
46
|
- examples/echo.rb
|
47
|
+
- examples/ping_pong.rb
|
47
48
|
- examples/print_heirarchy.rb
|
48
49
|
- ext/extconf.rb
|
49
50
|
- ext/push_parser.c
|
@@ -110,6 +111,8 @@ signing_key:
|
|
110
111
|
specification_version: 3
|
111
112
|
summary: An evented XMPP library written on EventMachine and libxml-ruby
|
112
113
|
test_files:
|
114
|
+
- spec/blather/client/client_spec.rb
|
115
|
+
- spec/blather/client/dsl_spec.rb
|
113
116
|
- spec/blather/core_ext/libxml_spec.rb
|
114
117
|
- spec/blather/errors/sasl_error_spec.rb
|
115
118
|
- spec/blather/errors/stanza_error_spec.rb
|