socky 0.0.7 → 0.0.8
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/CHANGELOG.textile +25 -0
- data/README.textile +27 -0
- data/Rakefile +19 -0
- data/VERSION +1 -1
- data/lib/em-websocket_hacks.rb +1 -3
- data/lib/socky.rb +17 -15
- data/lib/socky/connection.rb +12 -6
- data/lib/socky/connection/authentication.rb +7 -6
- data/lib/socky/connection/finders.rb +3 -3
- data/lib/socky/message.rb +26 -20
- data/lib/socky/misc.rb +2 -2
- data/lib/socky/net_request.rb +2 -2
- data/lib/socky/options.rb +16 -18
- data/lib/socky/options/config.rb +37 -18
- data/lib/socky/options/parser.rb +50 -40
- data/lib/socky/runner.rb +3 -4
- data/lib/socky/server.rb +1 -1
- data/spec/em-websocket_spec.rb +37 -0
- data/spec/files/default.yml +7 -0
- data/spec/files/invalid.yml +1 -0
- data/spec/socky/connection/authentication_spec.rb +162 -0
- data/spec/socky/connection/finders_spec.rb +96 -0
- data/spec/socky/connection_spec.rb +143 -0
- data/spec/socky/message_spec.rb +260 -0
- data/spec/socky/misc_spec.rb +74 -0
- data/spec/socky/net_request_spec.rb +43 -0
- data/spec/socky/options/config_spec.rb +67 -0
- data/spec/socky/options/parser_spec.rb +59 -0
- data/spec/socky/options_spec.rb +65 -0
- data/spec/socky/runner_spec.rb +73 -0
- data/spec/socky/server_spec.rb +35 -0
- data/spec/socky_spec.rb +82 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stallion.rb +96 -0
- metadata +39 -7
- data/README +0 -10
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'spec/stallion'
|
3
|
+
|
4
|
+
describe Socky::NetRequest do
|
5
|
+
|
6
|
+
context "class" do
|
7
|
+
context "#post" do
|
8
|
+
it "should send EventMachine::HttpRequest to url" do
|
9
|
+
EventMachine::HttpRequest.should_receive(:new).with("some url")
|
10
|
+
described_class.post("some url")
|
11
|
+
end
|
12
|
+
it "should send EventMachine::HttpRequest post request with specified params" do
|
13
|
+
request = mock(:request)
|
14
|
+
EventMachine::HttpRequest.stub!(:new).and_return(request)
|
15
|
+
request.should_receive(:post).with({:body => {:test => true}, :timeout => 3})
|
16
|
+
described_class.post("some url", :test => true)
|
17
|
+
end
|
18
|
+
it "should rescue from EM::HttpRequest and return false" do
|
19
|
+
EM.run do
|
20
|
+
described_class.post("inexistent").should be_false
|
21
|
+
EM.stop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
it "should call block with false if request return status other than 200" do
|
25
|
+
EM.run do
|
26
|
+
described_class.post("http://127.0.0.1:8080/fail") do |response|
|
27
|
+
response.should be_false
|
28
|
+
EM.stop
|
29
|
+
end.should be_true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
it "should call block with true if request return status 200" do
|
33
|
+
EM.run do
|
34
|
+
described_class.post("http://127.0.0.1:8080/") do |response|
|
35
|
+
response.should be_true
|
36
|
+
EM.stop
|
37
|
+
end.should be_true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
FILES_DIR = File.join(File.dirname(__FILE__), '..', '..', 'files')
|
4
|
+
|
5
|
+
describe Socky::Options::Config do
|
6
|
+
|
7
|
+
context "class" do
|
8
|
+
before(:each) do
|
9
|
+
described_class.stub!(:puts)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#read" do
|
13
|
+
it "should raise error if file doesn't exists" do
|
14
|
+
described_class.should_receive(:puts).with("You must generate a config file (socky -g filename.yml)")
|
15
|
+
lambda { described_class.read("abstract") }.should raise_error SystemExit
|
16
|
+
end
|
17
|
+
it "should raise error if file is corrupted" do
|
18
|
+
described_class.should_receive(:puts).with("Provided config file is invalid.")
|
19
|
+
lambda { described_class.read(FILES_DIR + "/invalid.yml") }.should raise_error SystemExit
|
20
|
+
end
|
21
|
+
it "should return valid options if file is valid" do
|
22
|
+
lambda { described_class.read(FILES_DIR + "/default.yml") }.should_not raise_error SystemExit
|
23
|
+
described_class.read(FILES_DIR + "/default.yml").should eql(default_options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "#generate" do
|
28
|
+
it "should raise error if file exists" do
|
29
|
+
described_class.should_receive(:puts).with("Config file already exists. You must remove it before generating a new one.")
|
30
|
+
lambda { described_class.generate(FILES_DIR + "/invalid.yml") }.should raise_error SystemExit
|
31
|
+
end
|
32
|
+
it "should raise error if path is not valid" do
|
33
|
+
described_class.should_receive(:puts).with("Config file is unavailable - please choose another.")
|
34
|
+
lambda { described_class.generate("/proc/inexistent") }.should raise_error SystemExit
|
35
|
+
end
|
36
|
+
it "should create file and exit if path is valid" do
|
37
|
+
path = FILES_DIR + "/inexistent.yml"
|
38
|
+
begin
|
39
|
+
described_class.should_receive(:puts).with("Config file generated at #{path}")
|
40
|
+
lambda { described_class.generate(path) }.should raise_error SystemExit
|
41
|
+
ensure
|
42
|
+
FileUtils.rm(path, :force => true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
it "should generate file that after parsing will equal default config" do
|
46
|
+
path = FILES_DIR + "/inexistent.yml"
|
47
|
+
begin
|
48
|
+
described_class.should_receive(:puts).with("Config file generated at #{path}")
|
49
|
+
lambda { described_class.generate(path) }.should raise_error SystemExit
|
50
|
+
lambda { described_class.read(path) }.should_not raise_error SystemExit
|
51
|
+
described_class.read(path).should eql(default_options)
|
52
|
+
ensure
|
53
|
+
FileUtils.rm(path, :force => true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def default_options
|
61
|
+
{ :port => 8080,
|
62
|
+
:debug => false,
|
63
|
+
:subscribe_url => "http://localhost:3000/socky/subscribe",
|
64
|
+
:unsubscribe_url => "http://localhost:3000/socky/unsubscribe",
|
65
|
+
:secret => "my_secret_key"
|
66
|
+
}
|
67
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Options::Parser do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
context "#parse" do
|
7
|
+
before(:each) do
|
8
|
+
described_class.stub!(:puts)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return empty hash on empty array" do
|
12
|
+
described_class.parse([]).should eql({})
|
13
|
+
end
|
14
|
+
it "should inform about inexistent option and exit" do
|
15
|
+
described_class.should_receive(:puts).with("invalid option: -z")
|
16
|
+
lambda { described_class.parse(["-z"]) }.should raise_error SystemExit
|
17
|
+
end
|
18
|
+
it "on -g or --generate should set config_path and generate default config file in specified destination" do
|
19
|
+
Socky::Options::Config.stub!(:generate)
|
20
|
+
["-g","--generate"].each do |function|
|
21
|
+
Socky::Options::Config.should_receive(:generate).with("/tmp/socky.yml")
|
22
|
+
described_class.parse([function,"/tmp/socky.yml"]).should eql({:config_path => "/tmp/socky.yml"})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
it "on -c or --config should set config_path to provided path" do
|
26
|
+
["-c","--config"].each do |function|
|
27
|
+
described_class.parse([function,"/tmp/socky.yml"]).should eql({:config_path => "/tmp/socky.yml"})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
it "on -p or --port should set port" do
|
31
|
+
described_class.parse(["-p","222"]).should eql({:port => 222})
|
32
|
+
end
|
33
|
+
it "on -l or --log should set log_path to provided path" do
|
34
|
+
["-l","--log"].each do |function|
|
35
|
+
described_class.parse([function,"/tmp/socky.log"]).should eql({:log_path => "/tmp/socky.log"})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
it "on --debug should set debug to true" do
|
39
|
+
described_class.parse(["--debug"]).should eql({:debug => true})
|
40
|
+
end
|
41
|
+
it "on --deep-debug should set debug and deep_debug to true" do
|
42
|
+
described_class.parse(["--deep-debug"]).should eql({:debug => true, :deep_debug => true})
|
43
|
+
end
|
44
|
+
it "on -? or --help should display usage" do
|
45
|
+
["-?","--help"].each do |function|
|
46
|
+
described_class.should_receive(:puts).with(/Usage: socky \[options\]/)
|
47
|
+
lambda { described_class.parse([function]) }.should raise_error SystemExit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
it "on -v or --version should dosplay current version" do
|
51
|
+
["-v","--version"].each do |function|
|
52
|
+
described_class.should_receive(:puts).with("Socky #{Socky::VERSION}")
|
53
|
+
lambda { described_class.parse([function]) }.should raise_error SystemExit
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Options do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
before(:all) do
|
7
|
+
@default_options = Socky.options
|
8
|
+
end
|
9
|
+
after(:each) do
|
10
|
+
Socky.options = @default_options
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#prepare" do
|
14
|
+
before(:each) do
|
15
|
+
Socky::Options::Parser.stub!(:parse).and_return({})
|
16
|
+
Socky::Options::Config.stub!(:read).and_return({})
|
17
|
+
end
|
18
|
+
it "should call parser with self option" do
|
19
|
+
Socky::Options::Parser.should_receive(:parse).with([:a,:b,:c])
|
20
|
+
Socky::Options.prepare([:a,:b,:c])
|
21
|
+
end
|
22
|
+
it "should call read_config with patch" do
|
23
|
+
Socky::Options::Config.should_receive(:read).with("/var/run/socky.yml")
|
24
|
+
Socky::Options.prepare([])
|
25
|
+
end
|
26
|
+
it "should set Socky options to default hash when parse_options and read_config don't do anything" do
|
27
|
+
Socky::Options.prepare([])
|
28
|
+
Socky.options.should eql({:port=>8080,
|
29
|
+
:log_path=>"/var/run/socky.log",
|
30
|
+
:debug=>false,
|
31
|
+
:deep_debug=>false,
|
32
|
+
:config_path=>"/var/run/socky.yml"})
|
33
|
+
end
|
34
|
+
it "should value parse_options over default values" do
|
35
|
+
Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
|
36
|
+
Socky::Options.prepare([])
|
37
|
+
Socky.options.should eql({:port=>8080,
|
38
|
+
:log_path=>"parsed",
|
39
|
+
:debug=>false,
|
40
|
+
:deep_debug=>false,
|
41
|
+
:config_path=>"/var/run/socky.yml"})
|
42
|
+
end
|
43
|
+
it "should value read_config over default values" do
|
44
|
+
Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
|
45
|
+
Socky::Options.prepare([])
|
46
|
+
Socky.options.should eql({:port=>8080,
|
47
|
+
:log_path=>"from config",
|
48
|
+
:debug=>false,
|
49
|
+
:deep_debug=>false,
|
50
|
+
:config_path=>"/var/run/socky.yml"})
|
51
|
+
end
|
52
|
+
it "should value parse_options over read_config" do
|
53
|
+
Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
|
54
|
+
Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
|
55
|
+
Socky::Options.prepare([])
|
56
|
+
Socky.options.should eql({:port=>8080,
|
57
|
+
:log_path=>"parsed",
|
58
|
+
:debug=>false,
|
59
|
+
:deep_debug=>false,
|
60
|
+
:config_path=>"/var/run/socky.yml"})
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Runner do
|
4
|
+
|
5
|
+
context "#class" do
|
6
|
+
context "#run" do
|
7
|
+
before(:each) do
|
8
|
+
@server = mock(:server, :start => nil)
|
9
|
+
described_class.stub!(:new).and_return(@server)
|
10
|
+
end
|
11
|
+
it "should create new instance of self" do
|
12
|
+
described_class.should_receive(:new).with("some args")
|
13
|
+
described_class.run("some args")
|
14
|
+
end
|
15
|
+
it "should call #start on new instance of self" do
|
16
|
+
@server.should_receive(:start)
|
17
|
+
described_class.run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
context "#new" do
|
21
|
+
it "should prepare options from args" do
|
22
|
+
Socky::Options.stub!(:prepare)
|
23
|
+
Socky::Options.should_receive(:prepare).with("some args")
|
24
|
+
described_class.new("some args")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "#instance" do
|
30
|
+
before(:each) do
|
31
|
+
Socky::Options.stub!(:prepare)
|
32
|
+
@runner = described_class.new
|
33
|
+
end
|
34
|
+
|
35
|
+
context "#start" do
|
36
|
+
it "should create valid websocket server" do
|
37
|
+
begin
|
38
|
+
EM.run do
|
39
|
+
MSG = "Hello World!"
|
40
|
+
EventMachine.add_timer(0.1) do
|
41
|
+
http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
42
|
+
http.errback {
|
43
|
+
EM.stop
|
44
|
+
fail
|
45
|
+
}
|
46
|
+
http.callback {
|
47
|
+
http.response_header.status.should == 101
|
48
|
+
EM.stop
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
Socky.stub!(:options).and_return({:port => 12345})
|
53
|
+
Socky.logger = mock(:logger, :info => nil, :debug => nil)
|
54
|
+
@runner.start
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
Socky.logger = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "#stop should call EM.stop" do
|
63
|
+
begin
|
64
|
+
Socky.logger = mock(:logger, :info => nil, :debug => nil)
|
65
|
+
EM.should_receive(:stop)
|
66
|
+
@runner.stop
|
67
|
+
ensure
|
68
|
+
Socky.logger = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Server do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
it "#send_data should call send_message on each of provided connections" do
|
7
|
+
connections = []
|
8
|
+
3.times {|i| connections << mock("connection#{i}", :send_message => nil)}
|
9
|
+
connections.each{|connection| connection.should_receive(:send_message).with("abstract")}
|
10
|
+
described_class.send_data("abstract",connections)
|
11
|
+
end
|
12
|
+
it "#send_to_clients should find connections by clients and call #send_data on them" do
|
13
|
+
Socky::Connection.stub!(:find_by_clients).and_return(["first","second","third"])
|
14
|
+
described_class.stub!(:send_data)
|
15
|
+
Socky::Connection.should_receive(:find_by_clients).with("abstract")
|
16
|
+
described_class.should_receive(:send_data).with("message", ["first","second","third"])
|
17
|
+
described_class.send_to_clients("message","abstract")
|
18
|
+
end
|
19
|
+
it "#send_to_channels should find connections by channels and call #send_data on them" do
|
20
|
+
Socky::Connection.stub!(:find_by_channels).and_return(["first","second","third"])
|
21
|
+
described_class.stub!(:send_data)
|
22
|
+
Socky::Connection.should_receive(:find_by_channels).with("abstract")
|
23
|
+
described_class.should_receive(:send_data).with("message", ["first","second","third"])
|
24
|
+
described_class.send_to_channels("message","abstract")
|
25
|
+
end
|
26
|
+
it "#send_to_clients_on_channels should find connections by clients and channels and call #send_data on them" do
|
27
|
+
Socky::Connection.stub!(:find_by_clients_and_channels).and_return(["first","second","third"])
|
28
|
+
described_class.stub!(:send_data)
|
29
|
+
Socky::Connection.should_receive(:find_by_clients_and_channels).with("abstract1","abstract2")
|
30
|
+
described_class.should_receive(:send_data).with("message", ["first","second","third"])
|
31
|
+
described_class.send_to_clients_on_channels("message","abstract1","abstract2")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/spec/socky_spec.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Socky do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
|
7
|
+
it "should have non-blank version" do
|
8
|
+
Socky::VERSION.should_not be_nil
|
9
|
+
end
|
10
|
+
it "should have options in hash form" do
|
11
|
+
Socky.options.should_not be_nil
|
12
|
+
Socky.options.class.should eql(Hash)
|
13
|
+
end
|
14
|
+
it "should allow to set options" do
|
15
|
+
Socky.options.should eql(Hash.new)
|
16
|
+
begin
|
17
|
+
Socky.options = {:key => :value}
|
18
|
+
Socky.options.should eql({:key => :value})
|
19
|
+
ensure
|
20
|
+
Socky.options = Hash.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
it "should have logger" do
|
24
|
+
Socky.logger.should_not be_nil
|
25
|
+
Socky.logger.class.should eql(Logger)
|
26
|
+
end
|
27
|
+
it "should have logger with STDOUT at default" do
|
28
|
+
Socky.logger.instance_variable_get('@logdev').dev.class.should eql(IO)
|
29
|
+
end
|
30
|
+
it "should be able to set logger" do
|
31
|
+
begin
|
32
|
+
logger = Logger.new(STDOUT)
|
33
|
+
Socky.logger.should_not equal(logger)
|
34
|
+
Socky.logger = logger
|
35
|
+
Socky.logger.should equal(logger)
|
36
|
+
ensure
|
37
|
+
Socky.logger = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
it "should be able to change verbosity of logger by setting debug option" do
|
41
|
+
begin
|
42
|
+
Socky.logger.level.should eql(Logger::INFO)
|
43
|
+
Socky.logger = nil
|
44
|
+
Socky.stub!(:options).and_return({:debug => true})
|
45
|
+
Socky.logger.level.should eql(Logger::DEBUG)
|
46
|
+
Socky.logger = nil
|
47
|
+
Socky.stub!(:options).and_return({:debug => false})
|
48
|
+
Socky.logger.level.should eql(Logger::INFO)
|
49
|
+
ensure
|
50
|
+
Socky.logger = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
it "should have default log path" do
|
54
|
+
Socky.log_path.should_not be_nil
|
55
|
+
Socky.log_path.should eql("/var/run/socky.log")
|
56
|
+
end
|
57
|
+
it "should be able to change log path by settion log_path option" do
|
58
|
+
Socky.stub!(:options).and_return({:log_path => "abstract"})
|
59
|
+
Socky.log_path.should eql("abstract")
|
60
|
+
end
|
61
|
+
it "should be able to change logger write place" do
|
62
|
+
begin
|
63
|
+
Socky.options = {:log_path => File.join(File.dirname(__FILE__), 'files', 'socky.log')}
|
64
|
+
Socky.logger.should_not be_nil
|
65
|
+
Socky.logger.instance_variable_get('@logdev').dev.class.should eql(File)
|
66
|
+
ensure
|
67
|
+
Socky.logger = nil
|
68
|
+
Socky.options = {}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
it "should have default config path" do
|
72
|
+
Socky.config_path.should_not be_nil
|
73
|
+
Socky.config_path.should eql("/var/run/socky.yml")
|
74
|
+
end
|
75
|
+
it "should be able to change config path by settion config_path option" do
|
76
|
+
Socky.stub!(:options).and_return({:config_path => "abstract"})
|
77
|
+
Socky.config_path.should eql("abstract")
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/stallion.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# #--
|
2
|
+
# Includes portion originally Copyright (C)2008 Michael Fellinger
|
3
|
+
# license See file LICENSE for details
|
4
|
+
# #--
|
5
|
+
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
module Stallion
|
9
|
+
class Mount
|
10
|
+
def initialize(name, *methods, &block)
|
11
|
+
@name, @methods, @block = name, methods, block
|
12
|
+
end
|
13
|
+
|
14
|
+
def ride
|
15
|
+
@block.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def match?(request)
|
19
|
+
method = request['REQUEST_METHOD']
|
20
|
+
right_method = @methods.empty? or @methods.include?(method)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Stable
|
25
|
+
attr_reader :request, :response
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@boxes = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def in(path, *methods, &block)
|
32
|
+
mount = Mount.new(path, *methods, &block)
|
33
|
+
@boxes[[path, methods]] = mount
|
34
|
+
mount
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(request, response)
|
38
|
+
@request, @response = request, response
|
39
|
+
@boxes.each do |(path, methods), mount|
|
40
|
+
if mount.match?(request)
|
41
|
+
mount.ride
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
STABLES = {}
|
48
|
+
|
49
|
+
def self.saddle(name = nil)
|
50
|
+
STABLES[name] = stable = Stable.new
|
51
|
+
yield stable
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.run(options = {})
|
55
|
+
options = {:Host => "127.0.0.1", :Port => 8080}.merge(options)
|
56
|
+
Rack::Handler::Mongrel.run(Rack::Lint.new(self), options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.call(env)
|
60
|
+
request = Rack::Request.new(env)
|
61
|
+
response = Rack::Response.new
|
62
|
+
|
63
|
+
STABLES.each do |name, stable|
|
64
|
+
stable.call(request, response)
|
65
|
+
end
|
66
|
+
|
67
|
+
response.finish
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Stallion.saddle :spec do |stable|
|
72
|
+
stable.in '/' do
|
73
|
+
|
74
|
+
if stable.request.path_info == '/fail'
|
75
|
+
stable.response.status = 404
|
76
|
+
|
77
|
+
elsif stable.request.path_info == '/timeout'
|
78
|
+
sleep(10)
|
79
|
+
stable.response.write 'timeout'
|
80
|
+
|
81
|
+
elsif
|
82
|
+
stable.response.write 'Hello, World!'
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Thread.new do
|
89
|
+
begin
|
90
|
+
Stallion.run :Host => '127.0.0.1', :Port => 8080
|
91
|
+
rescue Exception => e
|
92
|
+
print e
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
sleep(1)
|