julien51-babylon 0.1.0 → 0.1.2
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/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
|