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.
@@ -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)