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,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
|