socky 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require "spec/autorun"
4
+
5
+ require 'lib/socky'
6
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
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)