radamanthus-skates 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|