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,144 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../../em_mock'
|
3
|
+
|
4
|
+
describe Skates::ComponentConnection do
|
5
|
+
|
6
|
+
include SkatesSpecHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@params = {"jid" => "jid@server", "password" => "password", "port" => 1234, "host" => "0.0.0.0"}
|
10
|
+
@component = Skates::ComponentConnection.connect(@params, handler_mock)
|
11
|
+
@component.stub!(:send_xml).and_return(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "initialize" do
|
15
|
+
it "should set the state to :wait_for_stream" do
|
16
|
+
@component.instance_variable_get("@state").should == :wait_for_stream
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "connection_completed" do
|
21
|
+
it "should send a <stream> element that initiates the communication" do
|
22
|
+
@component.should_receive(:send_xml).with("<?xml version=\"1.0\"?>\n<stream:stream xmlns=\"jabber:component:accept\" xmlns:stream=\"http://etherx.jabber.org/streams\" to=\"jid@server\">\n ")
|
23
|
+
@component.connection_completed
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "receive_stanza" do
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@component.instance_variable_set("@connected", true)
|
31
|
+
@doc = Nokogiri::XML::Document.new
|
32
|
+
@stanza = Nokogiri::XML::Node.new("presence", @doc)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "when connected" do
|
36
|
+
before(:each) do
|
37
|
+
@component.instance_variable_set("@state", :connected)
|
38
|
+
end
|
39
|
+
it "should call the receive_stanza on super"
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when waiting for stream" do
|
43
|
+
before(:each) do
|
44
|
+
@component.connection_completed
|
45
|
+
@component.instance_variable_set("@state", :wait_for_stream)
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "if the stanza is stream" do
|
49
|
+
before(:each) do
|
50
|
+
@stanza = Nokogiri::XML::Node.new("stream:stream", @doc)
|
51
|
+
@stanza["xmlns:stream"] = 'http://etherx.jabber.org/streams'
|
52
|
+
@stanza["xmlns"] = 'jabber:component:accept'
|
53
|
+
@stanza["from"] = 'plays.shakespeare.lit'
|
54
|
+
@stanza["id"] = "1234"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should send a handshake" do
|
58
|
+
@component.should_receive(:handshake)
|
59
|
+
@component.receive_stanza(@stanza)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should change state to wait_for_handshake" do
|
63
|
+
@component.receive_stanza(@stanza)
|
64
|
+
@component.instance_variable_get("@state").should == :wait_for_handshake
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "if the stanza is not stream or deosn't have an id" do
|
70
|
+
it "should raise an error" do
|
71
|
+
lambda {@component.receive_stanza(Nokogiri::XML::Node.new("else", @doc))}.should raise_error
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "when waiting for handshake" do
|
78
|
+
before(:each) do
|
79
|
+
@component.instance_variable_set("@state", :wait_for_handshake)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "if we actually get a handshake stanza" do
|
83
|
+
|
84
|
+
before(:each) do
|
85
|
+
@handshake = Nokogiri::XML::Node.new("handshake", @doc)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set the status as connected" do
|
89
|
+
@component.receive_stanza(@handshake)
|
90
|
+
@component.instance_variable_get("@state").should == :connected
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should call the connection callback" do
|
94
|
+
handler_mock.should_receive(:on_connected).with(@component)
|
95
|
+
@component.receive_stanza(@handshake)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "if we receive a stream:error" do
|
100
|
+
it "should raise an Authentication Error" do
|
101
|
+
lambda {@component.receive_stanza(Nokogiri::XML::Node.new("stream:error", @doc))}.should raise_error(Skates::AuthenticationError)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "if we receive something else" do
|
106
|
+
it "should raise an error" do
|
107
|
+
lambda {@component.receive_stanza(Nokogiri::XML::Node.new("else", @doc))}.should raise_error
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "stream_namespace" do
|
116
|
+
it "should return jabber:component:accept" do
|
117
|
+
@component.stream_namespace.should == 'jabber:component:accept'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "handshake" do
|
122
|
+
it "should build a handshake Element with the password and the id of the stanza" do
|
123
|
+
@component.connection_completed
|
124
|
+
doc = Nokogiri::XML::Document.new
|
125
|
+
stanza = Nokogiri::XML::Node.new("stream:stream", doc)
|
126
|
+
stanza["xmlns:stream"] = 'http://etherx.jabber.org/streams'
|
127
|
+
stanza["xmlns"] = 'jabber:component:accept'
|
128
|
+
stanza["from"] = 'plays.shakespeare.lit'
|
129
|
+
stanza["id"] = "1234"
|
130
|
+
@component.__send__(:handshake, stanza).xpath("//handshake").first.content.should == Digest::SHA1::hexdigest(stanza.attributes['id'].content + @params["password"])
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "when resolving" do
|
136
|
+
it "should resolve records" do
|
137
|
+
Skates::ComponentConnection.resolve("xmpp2.superfeedr.com") do |res|
|
138
|
+
res["host"].should == "173.45.226.99"
|
139
|
+
true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Skates::Router::DSL do
|
4
|
+
before(:each) do
|
5
|
+
Skates.router = Skates::StanzaRouter.new
|
6
|
+
Skates.router.purge_routes!
|
7
|
+
class ControllerController; end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "raises an exception if the route lacks a controller" do
|
11
|
+
lambda { Skates.router.draw do
|
12
|
+
xpath("/test").to(:action => "foo")
|
13
|
+
end }.should raise_error(/controller/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "raises an exception if the route lacks an action" do
|
17
|
+
lambda { Skates.router.draw do
|
18
|
+
xpath("/test").to(:controller => "foo")
|
19
|
+
end }.should raise_error(/action/)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises an exception if the route has no destination" do
|
23
|
+
lambda { Skates.router.draw do
|
24
|
+
xpath("//test")
|
25
|
+
end }.should raise_error(/destination/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "creates a route with the specified xpath, controller, action and priority" do
|
29
|
+
Skates.router.draw do
|
30
|
+
xpath("//test"
|
31
|
+
).to(:controller => "controller", :action => "action").priority(5)
|
32
|
+
end
|
33
|
+
routes = Skates.router.instance_variable_get("@routes")
|
34
|
+
routes.length.should == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create routes with the right namespace" do
|
38
|
+
Skates.router.draw do
|
39
|
+
xpath("//ns:test", {"ns" => "http://my.namespace.uri"}
|
40
|
+
).to(:controller => "controller", :action => "action").priority(5)
|
41
|
+
end
|
42
|
+
route = Skates.router.instance_variable_get("@routes").first
|
43
|
+
route.xpath.should == ["//ns:test", {"ns"=>"http://my.namespace.uri"}]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Skates::Route do
|
4
|
+
before(:each) do
|
5
|
+
@controller = "bar"
|
6
|
+
@action = "bar"
|
7
|
+
@xpath = "//message"
|
8
|
+
Kernel.stub!(:const_get).with("#{@controller.capitalize}Controller")
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".initialize" do
|
12
|
+
it "should raise an exception if no controller is specified" do
|
13
|
+
lambda { Skates::Route.new("action" => @action, "xpath" => @xpath) }.should raise_error(/controller/)
|
14
|
+
end
|
15
|
+
it "should raise an exception if no action is specified" do
|
16
|
+
lambda { Skates::Route.new("controller" => @controller, "xpath" => @xpath) }.should raise_error(/action/)
|
17
|
+
end
|
18
|
+
it "should raise an exception if no xpath is specified" do
|
19
|
+
lambda { Skates::Route.new("action" => @action, "controller" => @controller) }.should raise_error(/xpath/)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".accepts?" do
|
24
|
+
it "should check the stanza with Xpath" do
|
25
|
+
mock_stanza = mock(Object)
|
26
|
+
route = Skates::Route.new("controller" => "bar", "action" => "bar", "xpath" => ["//message", {}])
|
27
|
+
mock_stanza.should_receive(:xpath).with("//message", {}).and_return([])
|
28
|
+
route.accepts?(mock_stanza)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe Skates::StanzaRouter do
|
35
|
+
|
36
|
+
before(:each) do
|
37
|
+
@router = Skates::StanzaRouter.new
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "initialize" do
|
41
|
+
it "should have an empty array as routes" do
|
42
|
+
@router.routes.should == []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "connected" do
|
47
|
+
it "should set the connection" do
|
48
|
+
connection = mock(Object)
|
49
|
+
@router.connected(connection)
|
50
|
+
@router.connection.should == connection
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "route" do
|
55
|
+
before(:each) do
|
56
|
+
@xml = mock(Nokogiri::XML::Node)
|
57
|
+
3.times do |t|
|
58
|
+
@router.routes << mock(Skates::Route, :accepts? => false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when the before_route callback is defined" do
|
63
|
+
before(:each) do
|
64
|
+
@proc = Proc.new { |stanza|
|
65
|
+
}
|
66
|
+
@router.before_route(&@proc)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should call the callback" do
|
70
|
+
@proc.should_receive(:call).with(@xml)
|
71
|
+
@router.route(@xml)
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when the callback returns true" do
|
75
|
+
before(:each) do
|
76
|
+
@proc = Proc.new { |stanza|
|
77
|
+
true
|
78
|
+
}
|
79
|
+
@router.before_route(&@proc)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should not even check if a route accepts this stanza" do
|
83
|
+
@router.routes.each do |r|
|
84
|
+
r.should_not_receive(:accepts?).with(@xml)
|
85
|
+
end
|
86
|
+
@router.route(@xml)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when the callback returns false" do
|
91
|
+
before(:each) do
|
92
|
+
@proc = Proc.new { |stanza|
|
93
|
+
false
|
94
|
+
}
|
95
|
+
@router.before_route(&@proc)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should check if a route accepts this stanza" do
|
99
|
+
@router.routes.each do |r|
|
100
|
+
r.should_receive(:accepts?).with(@xml)
|
101
|
+
end
|
102
|
+
@router.route(@xml)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when the callback raises an error" do
|
107
|
+
before(:each) do
|
108
|
+
@proc = Proc.new { |stanza|
|
109
|
+
raise
|
110
|
+
}
|
111
|
+
@router.before_route(&@proc)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should check if a route accepts this stanza" do
|
115
|
+
@router.routes.each do |r|
|
116
|
+
r.should_receive(:accepts?).with(@xml)
|
117
|
+
end
|
118
|
+
@router.route(@xml)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when the before_route callback is not defined" do
|
125
|
+
it "should check each routes to see if they match the stanza and take the first of the matching" do
|
126
|
+
@router.routes.each do |r|
|
127
|
+
r.should_receive(:accepts?).with(@xml)
|
128
|
+
end
|
129
|
+
@router.route(@xml)
|
130
|
+
end
|
131
|
+
|
132
|
+
context "if one route is found" do
|
133
|
+
before(:each) do
|
134
|
+
@accepting_route = mock(Skates::Route, :accepts? => true, :action => "action", :controller => "controller", :xpath => "xpath")
|
135
|
+
@router.routes << @accepting_route
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should call execute_route" do
|
139
|
+
@router.should_receive(:execute_route).with(@accepting_route.controller, @accepting_route.action, @xml)
|
140
|
+
@router.route(@xml)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "if no route matches the stanza" do
|
145
|
+
it "should return false" do
|
146
|
+
@router.route(@xml).should be_false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "execute_route" do
|
153
|
+
before(:each) do
|
154
|
+
@action = "action"
|
155
|
+
@controller = Skates::Base::Controller
|
156
|
+
@xml = mock(Nokogiri::XML::Node)
|
157
|
+
@mock_stanza = mock(Skates::Base::Stanza)
|
158
|
+
@mock_controller = mock(Skates::Base::Controller, {:new => true, :evaluate => "hello world"})
|
159
|
+
Kernel.stub!(:const_get).with(@action.capitalize).and_return(Skates::Base::Stanza)
|
160
|
+
Skates::Base::Stanza.stub!(:new).with(@xml).and_return(@mock_stanza)
|
161
|
+
@connection = mock(Skates::XmppConnection, :send_xml => true)
|
162
|
+
@router.stub!(:connection).and_return(@connection)
|
163
|
+
@controller.stub!(:new).and_return(@mock_controller)
|
164
|
+
@mock_controller.stub!(:perform).with(@action)
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "when the Stanza class exists" do
|
168
|
+
it "should instantiate the route's stanza " do
|
169
|
+
Kernel.should_receive(:const_get).with(@action.capitalize).and_return(Skates::Base::Stanza)
|
170
|
+
Skates::Base::Stanza.should_receive(:new).with(@xml).and_return(@mock_stanza)
|
171
|
+
@router.execute_route(@controller, @action, @xml)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should instantiate the route's controller" do
|
175
|
+
@controller.should_receive(:new).with(@mock_stanza).and_return(@mock_controller)
|
176
|
+
@router.execute_route(@controller, @action, @xml)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "when the stanza class doesn't exist" do
|
181
|
+
it "should instantiate the route's controller with the xml" do
|
182
|
+
Kernel.should_receive(:const_get).with(@action.capitalize).and_raise(NameError)
|
183
|
+
@controller.should_receive(:new).with(@xml).and_return(@mock_controller)
|
184
|
+
@router.execute_route(@controller, @action, @xml)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should call perform on the controller with the action's name" do
|
189
|
+
@mock_controller.should_receive(:perform).with(@action)
|
190
|
+
@router.execute_route(@controller, @action, @xml)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should send the controller's response to the connection" do
|
194
|
+
@connection.should_receive(:send_xml).with(@mock_controller.evaluate)
|
195
|
+
@router.execute_route(@controller, @action, @xml)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "purge_routes!" do
|
200
|
+
it "should delete all routes" do
|
201
|
+
@router.instance_variable_set("@routes", [mock(Skates::Route), mock(Skates::Route)])
|
202
|
+
@router.purge_routes!
|
203
|
+
@router.routes.should == []
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "draw" do
|
208
|
+
before(:each) do
|
209
|
+
@dsl = Skates::Router::DSL.new
|
210
|
+
Skates::Router::DSL.stub!(:new).and_return(@dsl)
|
211
|
+
@routes = [mock(Skates::Route, :is_a? => true), mock(Skates::Route, :is_a? => true), mock(Skates::Route, :is_a? => true)]
|
212
|
+
@router.stub!(:sort)
|
213
|
+
@dsl.stub!(:routes).and_return(@routes)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "shoudl instantiate a new DSL" do
|
217
|
+
Skates::Router::DSL.should_receive(:new).and_return(@dsl)
|
218
|
+
@router.draw {}
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should instance_eval the block" do
|
222
|
+
block = Proc.new {}
|
223
|
+
@dsl.should_receive(:instance_eval).with(&block)
|
224
|
+
@router.draw &block
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should check that each route is a Route" do
|
228
|
+
@dsl.should_receive(:routes).twice.and_return(@routes)
|
229
|
+
@router.draw {}
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should raise an error if one of the routes is not valid" do
|
233
|
+
@dsl.should_receive(:routes).and_return([mock(Skates::Route, :is_a? => false)])
|
234
|
+
lambda {
|
235
|
+
@router.draw {}
|
236
|
+
}.should raise_error()
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should assign the dsl routes as @routes" do
|
240
|
+
@dsl.should_receive(:routes).twice.and_return(@routes)
|
241
|
+
@router.draw {}
|
242
|
+
@router.routes.should == @routes
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should sort the routes" do
|
246
|
+
@router.should_receive(:sort)
|
247
|
+
@router.draw {}
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|