radamanthus-skates 0.3.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/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +142 -0
- data/bin/skates +8 -0
- data/lib/skates.rb +154 -0
- data/lib/skates/base/controller.rb +116 -0
- data/lib/skates/base/stanza.rb +44 -0
- data/lib/skates/base/view.rb +59 -0
- data/lib/skates/client_connection.rb +234 -0
- data/lib/skates/component_connection.rb +114 -0
- data/lib/skates/ext/array.rb +21 -0
- data/lib/skates/generator.rb +142 -0
- data/lib/skates/router.rb +123 -0
- data/lib/skates/router/dsl.rb +48 -0
- data/lib/skates/runner.rb +164 -0
- data/lib/skates/xmpp_connection.rb +216 -0
- data/lib/skates/xmpp_parser.rb +112 -0
- data/spec/bin/skates_spec.rb +0 -0
- data/spec/em_mock.rb +42 -0
- data/spec/lib/skates/base/controller_spec.rb +205 -0
- data/spec/lib/skates/base/stanza_spec.rb +120 -0
- data/spec/lib/skates/base/view_spec.rb +105 -0
- data/spec/lib/skates/client_connection_spec.rb +309 -0
- data/spec/lib/skates/component_connection_spec.rb +144 -0
- data/spec/lib/skates/generator_spec.rb +10 -0
- data/spec/lib/skates/router/dsl_spec.rb +46 -0
- data/spec/lib/skates/router_spec.rb +252 -0
- data/spec/lib/skates/runner_spec.rb +233 -0
- data/spec/lib/skates/xmpp_connection_spec.rb +222 -0
- data/spec/lib/skates/xmpp_parser_spec.rb +283 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +37 -0
- data/test/skates_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +125 -0
@@ -0,0 +1,233 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../../em_mock'
|
3
|
+
|
4
|
+
describe Skates::Runner do
|
5
|
+
before(:all) do
|
6
|
+
FileUtils.chdir("#{FileUtils.pwd}/templates/skates") unless ("#{FileUtils.pwd}" =~ /\/templates\/skates/ )
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".prepare" do
|
10
|
+
before(:each) do
|
11
|
+
@config = {"production"=>{"port"=>5278, "auto-reconnect"=>true, "jid"=>"component.server.com", "host"=>"localhost", "password"=>"password"}, "development"=>{"auto-reconnect"=>true, "jid"=>"user@server.com", "application_type"=>"client", "password"=>"password"}, "test"=>{"port"=>5278, "auto-reconnect"=>true, "jid"=>"component.server.com", "host"=>"localhost", "password"=>"password"}}
|
12
|
+
Skates.config_file = "config/config.yaml"
|
13
|
+
YAML.stub(:load_file).and_return(@config)
|
14
|
+
Skates::Runner.stub!(:require_directory).and_return(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should add the environment log file as an outputter to skates's default log" do
|
18
|
+
Skates.should_receive(:reopen_logs)
|
19
|
+
Skates::Runner.prepare("test")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should require all models" do
|
23
|
+
Skates::Runner.should_receive(:require_directory).with('app/models/*.rb').and_return(true)
|
24
|
+
Skates::Runner.prepare("test")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should require all stanzas" do
|
28
|
+
Skates::Runner.should_receive(:require_directory).with('app/stanzas/*.rb').and_return(true)
|
29
|
+
Skates::Runner.prepare("test")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should require all controllers" do
|
33
|
+
Skates::Runner.should_receive(:require_directory).with('app/controllers/*_controller.rb').and_return(true)
|
34
|
+
Skates::Runner.prepare("test")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create a router" do
|
38
|
+
router = Skates::StanzaRouter.new
|
39
|
+
Skates::StanzaRouter.should_receive(:new).and_return(router)
|
40
|
+
Skates.should_receive(:router=).with(router)
|
41
|
+
Skates::Runner.prepare("test")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should load the routes" do
|
45
|
+
Skates::Runner.should_receive(:require).with('config/routes.rb')
|
46
|
+
Skates::Runner.prepare("test")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should load the configuration file" do
|
50
|
+
YAML.should_receive(:load_file).with('config/config.yaml').and_return(@config)
|
51
|
+
Skates::Runner.prepare("test")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should assign the configuration" do
|
55
|
+
Skates::Runner.prepare("test")
|
56
|
+
Skates.config.should == {"port"=>5278, "jid"=>"component.server.com", "auto-reconnect"=>true, "host"=>"localhost", "password"=>"password"}
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should cache the views" do
|
60
|
+
Skates.should_receive(:cache_views)
|
61
|
+
Skates::Runner.prepare("test")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "require_directory" do
|
66
|
+
before(:each) do
|
67
|
+
@dir = "/my/dir"
|
68
|
+
@files = ["hello.rb", "byebye.rb"]
|
69
|
+
Dir.stub!(:glob).with(@dir).and_return(@files)
|
70
|
+
@files.each do |f|
|
71
|
+
Skates::Runner.stub!(:require).with(f).and_return(true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
it "should list all files in the directory" do
|
75
|
+
Dir.should_receive(:glob).with(@dir).and_return(@files)
|
76
|
+
Skates::Runner.require_directory(@dir)
|
77
|
+
end
|
78
|
+
it "should require each of the files" do
|
79
|
+
@files.each do |f|
|
80
|
+
Skates::Runner.should_receive(:require).with(f).and_return(true)
|
81
|
+
end
|
82
|
+
Skates::Runner.require_directory(@dir)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe ".run" do
|
87
|
+
before(:each) do
|
88
|
+
Skates::ClientConnection.stub!(:connect).and_return(true)
|
89
|
+
Skates::ComponentConnection.stub!(:connect).and_return(true)
|
90
|
+
EventMachine.stub!(:run).and_yield
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should set the environment" do
|
94
|
+
Skates::Runner.run("test")
|
95
|
+
Skates.environment.should == "test"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should epoll the EventMachine" do
|
99
|
+
EventMachine.should_receive(:epoll)
|
100
|
+
Skates::Runner.run("test")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should run the EventMachine" do
|
104
|
+
EventMachine.should_receive(:run)
|
105
|
+
Skates::Runner.run("test")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should call prepare" do
|
109
|
+
Skates::Runner.should_receive(:prepare).with("test")
|
110
|
+
Skates::Runner.run("test")
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should connect the client connection if specified by the config" do
|
114
|
+
Skates.stub!(:config).and_return({"application_type" => "client"})
|
115
|
+
Skates::ClientConnection.should_receive(:connect).with(Skates.config, Skates::Runner)
|
116
|
+
Skates::Runner.run("test")
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should connect the component connection if no application_type specified by the config" do
|
120
|
+
Skates.stub!(:config).and_return({})
|
121
|
+
Skates::ComponentConnection.should_receive(:connect).with(Skates.config, Skates::Runner)
|
122
|
+
Skates::Runner.run("test")
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe ".connection_observers" do
|
128
|
+
it "should return an array" do
|
129
|
+
Skates::Runner.connection_observers.should be_an_instance_of(Array)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe ".add_connection_observer" do
|
134
|
+
before(:each) do
|
135
|
+
class MyController < Skates::Base::Controller; end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should not accept non-Skates::Base::Controller subclasses" do
|
139
|
+
Skates::Runner.add_connection_observer(Object).should be_false
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should accept" do
|
143
|
+
Skates::Runner.add_connection_observer(MyController).should be_true
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should add it to the list of observers" do
|
147
|
+
observers = Skates::Runner.connection_observers
|
148
|
+
Skates::Runner.add_connection_observer(MyController)
|
149
|
+
observers.include?(MyController).should be_true
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should not add it twice" do
|
153
|
+
observers = Skates::Runner.connection_observers
|
154
|
+
Skates::Runner.add_connection_observer(MyController)
|
155
|
+
Skates::Runner.add_connection_observer(MyController)
|
156
|
+
observers.should == [MyController]
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe ".on_connected" do
|
162
|
+
before(:each) do
|
163
|
+
@connection = mock(Object)
|
164
|
+
Skates.router = Skates::StanzaRouter.new
|
165
|
+
Skates.router.stub!(:connected).with(@connection)
|
166
|
+
Skates.router.stub!(:execute_route).with(MyController, "on_connected")
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should call connected on StanzaRouter" do
|
170
|
+
Skates.router.should_receive(:connected).with(@connection)
|
171
|
+
Skates::Runner.on_connected(@connection)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should call on_connected on the various observers and send the corresponding response" do
|
175
|
+
Skates::Runner.add_connection_observer(MyController)
|
176
|
+
Skates.router.should_receive(:execute_route).with(MyController, "on_connected")
|
177
|
+
Skates::Runner.on_connected(@connection)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe ".on_disconnected" do
|
182
|
+
it "should call on_disconnected on the various observers" do
|
183
|
+
class MyObserver < Skates::Base::Controller; def on_disconnected; end; end
|
184
|
+
my_observer = MyObserver.new
|
185
|
+
Skates::Runner.add_connection_observer(MyObserver)
|
186
|
+
MyObserver.should_receive(:new).and_return(my_observer)
|
187
|
+
my_observer.should_receive(:on_disconnected)
|
188
|
+
Skates::Runner.on_disconnected
|
189
|
+
end
|
190
|
+
|
191
|
+
context "when the application should auto-reconnect" do
|
192
|
+
before(:each) do
|
193
|
+
Skates.config["auto-reconnect"] = true
|
194
|
+
EventMachine.stub!(:reactor_running?).and_return(false)
|
195
|
+
EventMachine.stub!(:add_timer).and_yield()
|
196
|
+
@delay = 15
|
197
|
+
Skates::Runner.stub!(:fib).and_return(@delay)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should determine when is the best time to reconnect with fibonacci" do
|
201
|
+
Skates::Runner.should_receive(:fib).and_return(@delay)
|
202
|
+
Skates::Runner.on_disconnected()
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should try to reconnect at the determined time" do
|
206
|
+
EventMachine.stub!(:reactor_running?).and_return(true)
|
207
|
+
Skates::Runner.should_receive(:reconnect)
|
208
|
+
EventMachine.should_receive(:add_timer).with(@delay).and_yield()
|
209
|
+
Skates::Runner.on_disconnected()
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context "when the application should not auto-reconnect" do
|
214
|
+
before(:each) do
|
215
|
+
Skates.config["auto-reconnect"] = false
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should stop the event loop" do
|
219
|
+
connection = mock(Object)
|
220
|
+
EventMachine.should_receive(:stop_event_loop)
|
221
|
+
Skates::Runner.on_disconnected()
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe ".on_stanza" do
|
227
|
+
it "should call route on StanzaRouter" do
|
228
|
+
stanza = mock(Object)
|
229
|
+
Skates.router.should_receive(:route).with(stanza)
|
230
|
+
Skates::Runner.on_stanza(stanza)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../../em_mock'
|
3
|
+
|
4
|
+
describe Skates::XmppConnection do
|
5
|
+
|
6
|
+
include SkatesSpecHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@params = {"jid" => "jid@server", "password" => "password", "port" => 1234, "host" => "myhost.com"}
|
10
|
+
@connection = Skates::XmppConnection._connect(@params, handler_mock)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "_connect" do
|
14
|
+
it "should connect EventMachine and return it" do
|
15
|
+
EventMachine.should_receive(:connect).with(@params["host"], @params["port"], Skates::XmppConnection, hash_including("handler" => handler_mock)).and_return(@connection)
|
16
|
+
Skates::XmppConnection._connect(@params, handler_mock).should == @connection
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should rescue Connection Errors" do
|
20
|
+
EventMachine.stub!(:connect).with(@params["host"], @params["port"], Skates::XmppConnection, hash_including("handler" => handler_mock)).and_raise(RuntimeError)
|
21
|
+
lambda {
|
22
|
+
Skates::XmppConnection._connect(@params, handler_mock)
|
23
|
+
}.should raise_error(Skates::NotConnected)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "connect" do
|
29
|
+
describe "connect" do
|
30
|
+
it "should not try to resolve the dns if a host IP has been provided" do
|
31
|
+
@params["host"] = "123.123.123.123"
|
32
|
+
Skates::XmppConnection.should_not_receive(:resolve)
|
33
|
+
Skates::XmppConnection.connect(@params, handler_mock)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "when a host is provided, which is not an IP" do
|
37
|
+
it "should resolve it" do
|
38
|
+
@params["host"] = "domain.tld"
|
39
|
+
Skates::XmppConnection.should_receive(:resolve)
|
40
|
+
Skates::XmppConnection.connect(@params, handler_mock)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "when no host is provided, and no port either" do
|
45
|
+
it "should resolve the host to an IP" do
|
46
|
+
Skates::XmppConnection.should_receive(:resolve)
|
47
|
+
Skates::XmppConnection.connect(@params, handler_mock)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "initialize" do
|
54
|
+
it "should assign @connected to false" do
|
55
|
+
@connection.instance_variable_get("@connected").should be_false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should assign @jid to params['jid']" do
|
59
|
+
@connection.instance_variable_get("@jid").should == @params["jid"]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should assign @password to params['password']" do
|
63
|
+
@connection.instance_variable_get("@password").should == @params["password"]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should assign @host to params['host']" do
|
67
|
+
@connection.instance_variable_get("@host").should == @params["host"]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should assign @port to params['port']" do
|
71
|
+
@connection.instance_variable_get("@port").should == @params["port"]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should assign @handler to params['handler']" do
|
75
|
+
@connection.instance_variable_get("@handler").should == handler_mock
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should assign @buffer to ''" do
|
79
|
+
@connection.instance_variable_get("@buffer").should == ""
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "post_init" do
|
84
|
+
it "assigne a new parser" do
|
85
|
+
parser = Skates::XmppParser.new(@connection.method(:receive_stanza))
|
86
|
+
Skates::XmppParser.should_receive(:new).and_return(parser)
|
87
|
+
@connection.post_init
|
88
|
+
@connection.instance_variable_get("@parser").should == parser
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "connection_completed" do
|
93
|
+
it "should set @connected to true" do
|
94
|
+
@connection.connection_completed
|
95
|
+
@connection.instance_variable_get("@connected").should be_true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "unbind" do
|
100
|
+
it "should set @connected to false" do
|
101
|
+
@connection.connection_completed
|
102
|
+
@connection.unbind
|
103
|
+
@connection.instance_variable_get("@connected").should be_false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "receive_stanza" do
|
108
|
+
|
109
|
+
before(:each) do
|
110
|
+
@doc = Nokogiri::XML::Document.new
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "with an stanza that starts with stream:error" do
|
114
|
+
|
115
|
+
before(:each) do
|
116
|
+
@error_stanza = Nokogiri::XML::Node.new("stream:error", @doc)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should close the connection" do
|
120
|
+
@connection.should_receive(:close_connection)
|
121
|
+
@connection.receive_stanza(@error_stanza)
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with a malformed stanza error" do
|
125
|
+
before(:each) do
|
126
|
+
@xml_not_well_formed_stanza = Nokogiri::XML::Node.new("xml-not-well-formed", @doc)
|
127
|
+
@xml_not_well_formed_stanza.add_namespace("xmlns", "urn:ietf:params:xml:ns:xmpp-streams")
|
128
|
+
@error_stanza.add_child(@xml_not_well_formed_stanza)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "with a stanza that is not an error" do
|
135
|
+
it "should call the on_stanza block" do
|
136
|
+
stanza = Nokogiri::XML::Node.new("message", @doc)
|
137
|
+
handler_mock.should_receive(:on_stanza)
|
138
|
+
@connection.receive_stanza(stanza)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "send_chunk" do
|
145
|
+
it "should raise an error if not connected" do
|
146
|
+
@connection.instance_variable_set("@connected", false)
|
147
|
+
lambda {
|
148
|
+
@connection.__send__(:send_chunk, "hello world")
|
149
|
+
}.should raise_error(Skates::NotConnected)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should raise an error if the stanza size is above the limit" do
|
153
|
+
@connection.instance_variable_set("@connected", true)
|
154
|
+
string = "a" * (Skates::XmppConnection.max_stanza_size + 1)
|
155
|
+
lambda {
|
156
|
+
@connection.__send__(:send_chunk, string)
|
157
|
+
}.should raise_error(Skates::StanzaTooBig)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should return if the string is blank" do
|
161
|
+
@connection.instance_variable_set("@connected", true)
|
162
|
+
@connection.should_not_receive(:send_data)
|
163
|
+
@connection.__send__(:send_chunk, "")
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should cann send_data with the string" do
|
167
|
+
@connection.instance_variable_set("@connected", true)
|
168
|
+
string = "hello world"
|
169
|
+
@connection.should_receive(:send_data).with(string)
|
170
|
+
@connection.__send__(:send_chunk, string)
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "send_xml" do
|
176
|
+
|
177
|
+
before(:each) do
|
178
|
+
@connection.instance_variable_set("@connected", true)
|
179
|
+
@connection.stub!(:send_chunk).and_return(true)
|
180
|
+
@doc = Nokogiri::XML::Document.new
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "with a nodeset as argument" do
|
184
|
+
before(:each) do
|
185
|
+
iq = Nokogiri::XML::Node.new("iq", @doc)
|
186
|
+
message = Nokogiri::XML::Node.new("message", @doc)
|
187
|
+
presence = Nokogiri::XML::Node.new("presence", @doc)
|
188
|
+
@node_set = Nokogiri::XML::NodeSet.new(@doc, [message, presence, iq])
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should call send_chunk for each of the nodes in the set" do
|
192
|
+
@node_set.each do |node|
|
193
|
+
@connection.should_receive(:send_chunk).with(node.to_s)
|
194
|
+
end
|
195
|
+
@connection.send_xml(@node_set)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "with an argument with is not a NodeSet" do
|
200
|
+
before(:each) do
|
201
|
+
@message = Nokogiri::XML::Node.new("message", @doc)
|
202
|
+
end
|
203
|
+
it "should call send_chunk for the node" do
|
204
|
+
@connection.should_receive(:send_chunk).with(@message.to_s)
|
205
|
+
@connection.send_xml(@message)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "receive_data" do
|
211
|
+
before(:each) do
|
212
|
+
@connection.instance_variable_get("@parser").stub!(:push).and_return(true)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should push the received data to the parser" do
|
216
|
+
data = "<hello>hello world!</hello>"
|
217
|
+
@connection.instance_variable_get("@parser").should_receive(:push).with(data).and_return(true)
|
218
|
+
@connection.__send__(:receive_data, data)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|