julien51-babylon 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/babylon.rb +5 -0
- data/lib/babylon/base/stanza.rb +0 -2
- data/lib/babylon/client_connection.rb +8 -11
- data/lib/babylon/component_connection.rb +4 -5
- data/lib/babylon/generator.rb +0 -2
- data/lib/babylon/runner.rb +3 -1
- data/lib/babylon/xmpp_parser.rb +1 -1
- data/spec/bin/babylon_spec.rb +0 -0
- data/spec/em_mock.rb +42 -0
- data/spec/lib/babylon/base/controller_spec.rb +205 -0
- data/spec/lib/babylon/base/stanza_spec.rb +15 -0
- data/spec/lib/babylon/base/view_spec.rb +64 -0
- data/spec/lib/babylon/client_connection_spec.rb +304 -0
- data/spec/lib/babylon/component_connection_spec.rb +135 -0
- data/spec/lib/babylon/generator_spec.rb +10 -0
- data/spec/lib/babylon/router/dsl_spec.rb +72 -0
- data/spec/lib/babylon/router_spec.rb +179 -0
- data/spec/lib/babylon/runner_spec.rb +213 -0
- data/spec/lib/babylon/xmpp_connection_spec.rb +222 -0
- data/spec/lib/babylon/xmpp_parser_spec.rb +268 -0
- data/spec/lib/babylon/xpath_helper_spec.rb +25 -0
- data/spec/spec_helper.rb +34 -0
- data/templates/babylon/config/dependencies.rb +0 -1
- data/test/babylon_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +34 -15
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
gem.email = "julien.genestoux@gmail.com"
|
10
10
|
gem.homepage = "http://github.com/julien51/babylon"
|
11
11
|
gem.authors = ["julien Genestoux"]
|
12
|
-
gem.requirements = ["eventmachine", "yaml", "fileutils", "log4r", "nokogiri", "sax-machine", "templater", "daemons"]
|
12
|
+
gem.requirements = ["eventmachine", "yaml", "fileutils", "log4r", "nokogiri", "sax-machine", "templater", "daemons", "optparse", "digest/sha1", "base64", "resolv"]
|
13
13
|
gem.executables = "babylon"
|
14
14
|
gem.files = [ "bin/babylon",
|
15
15
|
"lib/babylon.rb",
|
data/lib/babylon.rb
CHANGED
data/lib/babylon/base/stanza.rb
CHANGED
@@ -5,9 +5,6 @@ module Babylon
|
|
5
5
|
# So far, SASL Plain authenticationonly is supported
|
6
6
|
# Upon stanza reception, and depending on the status (connected... etc), this component will handle or forward the stanzas.
|
7
7
|
class ClientConnection < XmppConnection
|
8
|
-
require 'digest/sha1'
|
9
|
-
require 'base64'
|
10
|
-
require 'resolv'
|
11
8
|
|
12
9
|
attr_reader :binding_iq_id, :session_iq_id
|
13
10
|
|
@@ -56,15 +53,15 @@ module Babylon
|
|
56
53
|
# Builds the stream stanza for this client
|
57
54
|
def stream_stanza
|
58
55
|
doc = Nokogiri::XML::Document.new
|
59
|
-
stream = Nokogiri::XML::Node.new("stream", doc)
|
56
|
+
stream = Nokogiri::XML::Node.new("stream:stream", doc)
|
60
57
|
doc.add_child(stream)
|
61
|
-
stream
|
62
|
-
stream
|
58
|
+
stream["xmlns"] = stream_namespace
|
59
|
+
stream["xmlns:stream"] = "http://etherx.jabber.org/streams"
|
63
60
|
stream["to"] = jid.split("/").first.split("@").last
|
64
61
|
stream["version"] = "1.0"
|
65
62
|
paste_content_here = Nokogiri::XML::Node.new("paste_content_here", doc)
|
66
63
|
stream.add_child(paste_content_here)
|
67
|
-
doc.to_xml.split('<
|
64
|
+
doc.to_xml.split('<paste_content_here/>').first
|
68
65
|
end
|
69
66
|
|
70
67
|
##
|
@@ -100,7 +97,7 @@ module Babylon
|
|
100
97
|
doc = Nokogiri::XML::Document.new
|
101
98
|
starttls = Nokogiri::XML::Node.new("starttls", doc)
|
102
99
|
doc.add_child(starttls)
|
103
|
-
starttls
|
100
|
+
starttls["xmlns"] = "urn:ietf:params:xml:ns:xmpp-tls"
|
104
101
|
send_xml(starttls.to_s)
|
105
102
|
@state = :wait_for_proceed
|
106
103
|
elsif stanza.at("mechanisms") # tls is ok
|
@@ -109,7 +106,7 @@ module Babylon
|
|
109
106
|
auth = Nokogiri::XML::Node.new("auth", doc)
|
110
107
|
doc.add_child(auth)
|
111
108
|
auth['mechanism'] = "PLAIN"
|
112
|
-
auth
|
109
|
+
auth["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl"
|
113
110
|
auth.content = Base64::encode64([jid, jid.split("@").first, @password].join("\000")).gsub(/\s/, '')
|
114
111
|
send_xml(auth.to_s)
|
115
112
|
@state = :wait_for_success
|
@@ -142,7 +139,7 @@ module Babylon
|
|
142
139
|
iq["type"] = "set"
|
143
140
|
iq["id"] = binding_iq_id.to_s
|
144
141
|
bind = Nokogiri::XML::Node.new("bind", doc)
|
145
|
-
bind
|
142
|
+
bind["xmlns"] = "urn:ietf:params:xml:ns:xmpp-bind"
|
146
143
|
iq.add_child(bind)
|
147
144
|
resource = Nokogiri::XML::Node.new("resource", doc)
|
148
145
|
if jid.split("/").size == 2
|
@@ -169,7 +166,7 @@ module Babylon
|
|
169
166
|
iq["type"] = "set"
|
170
167
|
iq["id"] = session_iq_id.to_s
|
171
168
|
session = Nokogiri::XML::Node.new("session", doc)
|
172
|
-
session
|
169
|
+
session["xmlns"] = "urn:ietf:params:xml:ns:xmpp-session"
|
173
170
|
iq.add_child(session)
|
174
171
|
send_xml(iq.to_s)
|
175
172
|
@state = :wait_for_confirmed_session
|
@@ -3,7 +3,6 @@ module Babylon
|
|
3
3
|
# ComponentConnection is in charge of the XMPP connection itself.
|
4
4
|
# Upon stanza reception, and depending on the status (connected... etc), this component will handle or forward the stanzas.
|
5
5
|
class ComponentConnection < XmppConnection
|
6
|
-
require 'digest/sha1'
|
7
6
|
|
8
7
|
##
|
9
8
|
# Creates a new ComponentConnection and waits for data in the stream
|
@@ -19,14 +18,14 @@ module Babylon
|
|
19
18
|
def connection_completed
|
20
19
|
super
|
21
20
|
doc = Nokogiri::XML::Document.new
|
22
|
-
stream = Nokogiri::XML::Node.new("stream", doc)
|
23
|
-
stream
|
24
|
-
stream
|
21
|
+
stream = Nokogiri::XML::Node.new("stream:stream", doc)
|
22
|
+
stream["xmlns"] = stream_namespace
|
23
|
+
stream["xmlns:stream"] = "http://etherx.jabber.org/streams"
|
25
24
|
stream["to"] = jid
|
26
25
|
doc.add_child(stream)
|
27
26
|
paste_content_here= Nokogiri::XML::Node.new("paste_content_here", doc)
|
28
27
|
stream.add_child(paste_content_here)
|
29
|
-
start, stop = doc.to_xml.split('<
|
28
|
+
start, stop = doc.to_xml.split('<paste_content_here/>')
|
30
29
|
send_xml(start)
|
31
30
|
end
|
32
31
|
|
data/lib/babylon/generator.rb
CHANGED
data/lib/babylon/runner.rb
CHANGED
@@ -12,7 +12,9 @@ module Babylon
|
|
12
12
|
Babylon.config = YAML.load(config_file)[Babylon.environment]
|
13
13
|
|
14
14
|
# Add an outputter to the logger
|
15
|
-
|
15
|
+
log_file = Log4r::RollingFileOutputter.new("#{Babylon.environment}", :filename => "log/#{Babylon.environment}.log", :trunc => false)
|
16
|
+
log_file.formatter = Log4r::PatternFormatter.new(:pattern => "%d (#{Process.pid}) [%l] :: %m", :date_pattern => "%d/%m %H:%M")
|
17
|
+
Babylon.logger.add(log_file)
|
16
18
|
|
17
19
|
# Requiring all models, stanza, controllers
|
18
20
|
['app/models/*.rb', 'app/stanzas/*.rb', 'app/controllers/*_controller.rb'].each do |dir|
|
data/lib/babylon/xmpp_parser.rb
CHANGED
@@ -89,7 +89,7 @@ module Babylon
|
|
89
89
|
def add_namespaces_and_attributes_to_current_node(attrs)
|
90
90
|
(attrs.size / 2).times do |i|
|
91
91
|
name, value = attrs[2 * i], attrs[2 * i + 1]
|
92
|
-
# TODO : FIX namespaces :they give a lot of problems with
|
92
|
+
# TODO : FIX namespaces :they give a lot of problems with Nokogiri
|
93
93
|
# if name == "xmlns"
|
94
94
|
# @elem.add_namespace(nil, value)
|
95
95
|
# elsif name =~ /\Axmlns:/
|
File without changes
|
data/spec/em_mock.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
##
|
2
|
+
# Mock for EventMachine
|
3
|
+
module EventMachine
|
4
|
+
|
5
|
+
def self.mock?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Mock for the Connection Class
|
11
|
+
class Connection
|
12
|
+
def self.new(*args)
|
13
|
+
allocate.instance_eval do
|
14
|
+
# Call a superclass's #initialize if it has one
|
15
|
+
initialize(*args)
|
16
|
+
# Store signature and run #post_init
|
17
|
+
post_init
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Stub for run
|
25
|
+
def self.run(proc)
|
26
|
+
proc.call
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Stub for epoll
|
31
|
+
def self.epoll; end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Stub! to stop the event loop.
|
35
|
+
def self.stop_event_loop; end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Stub for connect (should return a connection object)
|
39
|
+
def self.connect(host, port, handler, params)
|
40
|
+
handler.new(params)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::Controller do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Babylon.views.stub!(:[]).and_return("") # Stubbing read for view
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".initialize" do
|
10
|
+
before(:each) do
|
11
|
+
@params = {:a => "a", :b => 1, :c => {:key => "value"}, :stanza => "<hello>world</hello>"}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a stanza instance" do
|
15
|
+
stanza = mock(Object)
|
16
|
+
c = Babylon::Base::Controller.new(stanza)
|
17
|
+
|
18
|
+
c.instance_variables.should be_include "@stanza"
|
19
|
+
c.instance_variable_get("@stanza").should == stanza
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not be rendered yet" do
|
23
|
+
c = Babylon::Base::Controller.new(@params)
|
24
|
+
c.rendered.should_not be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".perform" do
|
29
|
+
before(:each) do
|
30
|
+
@action = :subscribe
|
31
|
+
params = {:stanza => "<hello>world</hello>"}
|
32
|
+
@controller = Babylon::Base::Controller.new(params)
|
33
|
+
@controller.class.send(:define_method, @action) do # Defining the action method
|
34
|
+
# Do something
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should setup the action to the param" do
|
39
|
+
@controller.perform(@action) do
|
40
|
+
# Do something
|
41
|
+
end
|
42
|
+
@controller.instance_variable_get("@action_name").should == @action
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should call the action" do
|
46
|
+
@controller.should_receive(:send).with(@action).and_return()
|
47
|
+
@controller.perform(@action) do
|
48
|
+
# Do something
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should write an error to the log in case of failure of the action" do
|
53
|
+
@controller.stub!(:send).with(@action).and_raise(StandardError)
|
54
|
+
Babylon.logger.should_receive(:error)
|
55
|
+
@controller.perform(@action) do
|
56
|
+
# Do something
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should call render" do
|
61
|
+
@controller.should_receive(:render)
|
62
|
+
@controller.perform(@action) do
|
63
|
+
# Do something
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".render" do
|
69
|
+
before(:each) do
|
70
|
+
@controller = Babylon::Base::Controller.new({})
|
71
|
+
@controller.action_name = :subscribe
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should assign a value to view" do
|
75
|
+
@controller.render
|
76
|
+
@controller.instance_variable_get("@view").should_not be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "with :nothing option" do
|
80
|
+
it "should not render any file" do
|
81
|
+
@controller.should_not_receive(:render_for_file)
|
82
|
+
@controller.render :nothing => true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "with no option" do
|
87
|
+
it "should call render with default_file_name if no option is provided" do
|
88
|
+
@controller.should_receive(:default_template_name)
|
89
|
+
@controller.render
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with an :action option" do
|
94
|
+
it "should call render with the file name corresponding to the action given as option" do
|
95
|
+
action = :unsubscribe
|
96
|
+
@controller.should_receive(:default_template_name).with("#{action}")
|
97
|
+
@controller.render(:action => action)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "with a file option" do
|
102
|
+
it "should call render_for_file with the correct path if an option file is provided" do
|
103
|
+
file = "myfile"
|
104
|
+
@controller.should_receive(:render_for_file)
|
105
|
+
@controller.render(:file => file)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not render twice when called twice" do
|
110
|
+
@controller.render
|
111
|
+
@controller.should_not_receive(:render_for_file)
|
112
|
+
@controller.render
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe ".assigns" do
|
117
|
+
|
118
|
+
before(:each) do
|
119
|
+
@stanza = mock(Babylon::Base::Stanza)
|
120
|
+
@controller = Babylon::Base::Controller.new(@stanza)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be a hash" do
|
124
|
+
@controller.assigns.should be_an_instance_of(Hash)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should only contain the @stanza if the action hasn't been called yet" do
|
128
|
+
@controller.assigns.should_not be_empty
|
129
|
+
@controller.assigns["stanza"].should == @stanza
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should return an hash containing all instance variables defined in the action" do
|
133
|
+
vars = {"a" => 1, "b" => "b", "c" => { "d" => 4}}
|
134
|
+
class MyController < Babylon::Base::Controller
|
135
|
+
def do_something
|
136
|
+
@a = 1
|
137
|
+
@b = "b"
|
138
|
+
@c = { "d" => 4 }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
@controller = MyController.new(@stanza)
|
142
|
+
@controller.do_something
|
143
|
+
@controller.assigns.should == vars.merge("stanza" => @stanza)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe ".evaluate" do
|
148
|
+
before(:each) do
|
149
|
+
@controller = Babylon::Base::Controller.new()
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should evaluate the view" do
|
153
|
+
view = mock(Babylon::Base::View)
|
154
|
+
response = "hello"
|
155
|
+
@controller.instance_variable_set("@view", view)
|
156
|
+
view.should_receive(:evaluate).and_return(response)
|
157
|
+
@controller.evaluate.should == response
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe ".view_path" do
|
162
|
+
it "should return complete file path to the file given in param" do
|
163
|
+
@controller = Babylon::Base::Controller.new()
|
164
|
+
file_name = "myfile"
|
165
|
+
@controller.__send__(:view_path, file_name).should == File.join("app/views", "#{"Babylon::Base::Controller".gsub("Controller","").downcase}", file_name)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe ".default_template_name" do
|
170
|
+
before(:each) do
|
171
|
+
@controller = Babylon::Base::Controller.new()
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should return the view file name if a file is given in param" do
|
175
|
+
@controller.__send__(:default_template_name, "myaction").should == "myaction.xml.builder"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should return the view file name based on the action_name if no file has been given" do
|
179
|
+
@controller.action_name = "a_great_action"
|
180
|
+
@controller.__send__(:default_template_name).should == "a_great_action.xml.builder"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe ".render_for_file" do
|
185
|
+
|
186
|
+
before(:each) do
|
187
|
+
@controller = Babylon::Base::Controller.new()
|
188
|
+
@block = Proc.new {
|
189
|
+
# Do something
|
190
|
+
}
|
191
|
+
@controller.class.send(:define_method, "action") do # Defining the action method
|
192
|
+
# Do something
|
193
|
+
end
|
194
|
+
@controller.perform(:action, &@block)
|
195
|
+
@view = Babylon::Base::View.new("path_to_a_file", {})
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should instantiate a new view, with the file provided and the hashed_variables" do
|
199
|
+
Babylon::Base::View.should_receive(:new).with("path_to_a_file",an_instance_of(Hash)).and_return(@view)
|
200
|
+
@controller.__send__(:render_for_file, "path_to_a_file")
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::Stanza do
|
4
|
+
|
5
|
+
describe "initialize" do
|
6
|
+
before(:each) do
|
7
|
+
@stanza_string = "<presence />"
|
8
|
+
@stanza = Babylon::Base::Stanza.new(@stanza_string)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should call parse with the string passed to the builder"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::View do
|
4
|
+
describe ".initialize" do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@view = Babylon::Base::View.new("/a/path/to/a/view/file", {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should assign @view_template to path" do
|
11
|
+
@view.view_template == "/a/path/to/a/view/file"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should assign any variable passed in hash" do
|
15
|
+
{:a => "a", :b => 123, :c => {:d => "d", :e => "123"}}.each do |key, value|
|
16
|
+
@view.instance_variable_get("@#{key}").should == value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".evaluate" do
|
22
|
+
before(:each) do
|
23
|
+
@view_template = "/a/path/to/a/view/file"
|
24
|
+
@view = Babylon::Base::View.new(@view_template, {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
25
|
+
@xml_string = <<-eoxml
|
26
|
+
xml.message(:to => "you", :from => "me", :type => :chat) do
|
27
|
+
xml.body("salut")
|
28
|
+
end
|
29
|
+
eoxml
|
30
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should read the template file" do
|
34
|
+
Babylon.views.should_receive(:[]).twice.with(@view_template).and_return(@xml_string)
|
35
|
+
@view.evaluate
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an error if the view file couldn't be found" do
|
39
|
+
Babylon.views.stub!(:[]).with(@view_template).and_raise(nil)
|
40
|
+
lambda {
|
41
|
+
@view.evaluate
|
42
|
+
}.should raise_error(Babylon::Base::ViewFileNotFound)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a Nokogiri NodeSet" do
|
46
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
47
|
+
@view.evaluate.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should call eval on the view file" do
|
51
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
52
|
+
@view.should_receive(:eval).with(@xml_string)
|
53
|
+
@view.evaluate
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to access context's variables" do
|
57
|
+
@view = Babylon::Base::View.new("/a/path/to/a/view/file", {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
58
|
+
@view.instance_variable_get("@a").should == "a"
|
59
|
+
@view.instance_variable_get("@b").should == 123
|
60
|
+
@view.instance_variable_get("@c").should == {:e=>"123", :d=>"d"}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|