socky-server 0.4.1 → 0.5.0.beta1

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.
Files changed (65) hide show
  1. data/.gitignore +0 -4
  2. data/.travis.yml +6 -0
  3. data/CHANGELOG.md +11 -5
  4. data/Gemfile +2 -0
  5. data/README.md +47 -68
  6. data/Rakefile +5 -7
  7. data/config.ru +19 -0
  8. data/example/config.yml +4 -0
  9. data/lib/socky/server.rb +23 -0
  10. data/lib/socky/server/application.rb +51 -0
  11. data/lib/socky/server/channel.rb +30 -0
  12. data/lib/socky/server/channel/base.rb +80 -0
  13. data/lib/socky/server/channel/presence.rb +49 -0
  14. data/lib/socky/server/channel/private.rb +44 -0
  15. data/lib/socky/server/channel/public.rb +43 -0
  16. data/lib/socky/server/channel/stub.rb +17 -0
  17. data/lib/socky/server/config.rb +52 -0
  18. data/lib/socky/server/connection.rb +66 -0
  19. data/lib/socky/server/http.rb +95 -0
  20. data/lib/socky/server/logger.rb +24 -0
  21. data/lib/socky/server/message.rb +35 -0
  22. data/lib/socky/server/misc.rb +18 -0
  23. data/lib/socky/server/version.rb +5 -0
  24. data/lib/socky/server/websocket.rb +43 -0
  25. data/socky-server.gemspec +5 -7
  26. data/spec/fixtures/example_config.yml +3 -0
  27. data/spec/integration/ws_channels_spec.rb +144 -0
  28. data/spec/integration/ws_connection_spec.rb +48 -0
  29. data/spec/integration/ws_presence_spec.rb +118 -0
  30. data/spec/integration/ws_rights_spec.rb +133 -0
  31. data/spec/spec_helper.rb +24 -2
  32. data/spec/support/websocket_application.rb +14 -0
  33. data/spec/unit/socky/server/application_spec.rb +54 -0
  34. data/spec/unit/socky/server/config_spec.rb +50 -0
  35. data/spec/unit/socky/server/connection_spec.rb +67 -0
  36. data/spec/unit/socky/server/message_spec.rb +64 -0
  37. metadata +93 -126
  38. data/bin/socky +0 -5
  39. data/lib/em-websocket_hacks.rb +0 -15
  40. data/lib/socky.rb +0 -75
  41. data/lib/socky/connection.rb +0 -137
  42. data/lib/socky/connection/authentication.rb +0 -99
  43. data/lib/socky/connection/finders.rb +0 -67
  44. data/lib/socky/message.rb +0 -85
  45. data/lib/socky/misc.rb +0 -74
  46. data/lib/socky/net_request.rb +0 -27
  47. data/lib/socky/options.rb +0 -39
  48. data/lib/socky/options/config.rb +0 -79
  49. data/lib/socky/options/parser.rb +0 -93
  50. data/lib/socky/runner.rb +0 -95
  51. data/spec/em-websocket_spec.rb +0 -36
  52. data/spec/files/default.yml +0 -18
  53. data/spec/files/invalid.yml +0 -1
  54. data/spec/socky/connection/authentication_spec.rb +0 -183
  55. data/spec/socky/connection/finders_spec.rb +0 -188
  56. data/spec/socky/connection_spec.rb +0 -151
  57. data/spec/socky/message_spec.rb +0 -102
  58. data/spec/socky/misc_spec.rb +0 -74
  59. data/spec/socky/net_request_spec.rb +0 -42
  60. data/spec/socky/options/config_spec.rb +0 -72
  61. data/spec/socky/options/parser_spec.rb +0 -76
  62. data/spec/socky/options_spec.rb +0 -60
  63. data/spec/socky/runner_spec.rb +0 -88
  64. data/spec/socky_spec.rb +0 -89
  65. data/spec/support/stallion.rb +0 -96
@@ -1,102 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Socky::Message do
4
- before(:each) do
5
- @connection = mock(:connection, :name => "connection", :send_message => nil)
6
- end
7
-
8
- context "class" do
9
- context "#process" do
10
- before(:each) { @message = mock(:message, :process => nil) }
11
- it "should create new instance of self with provided params" do
12
- described_class.stub!(:new).and_return(@message)
13
- described_class.should_receive(:new).with(@connection, "test")
14
- described_class.process(@connection, "test")
15
- end
16
- it "should send #process to instance if valid message" do
17
- described_class.stub!(:new).and_return(@message)
18
- @message.should_receive(:process)
19
- described_class.process(@connection, "test")
20
- end
21
- it "should rescue from error if creating instance raise error" do
22
- described_class.stub!(:new).and_raise(Socky::SockyError)
23
- lambda{ described_class.process(@connection, "test") }.should_not raise_error
24
- end
25
- it "should rescue from error if parsing instance raise error" do
26
- @message.stub!(:process).and_raise(Socky::SockyError)
27
- described_class.stub!(:new).and_return(@message)
28
- lambda{ described_class.process(@connection, "test") }.should_not raise_error
29
- end
30
- end
31
- context "#new" do
32
- it "should create message with provided creator and message is message is JSON hash" do
33
- message = described_class.new(@connection, {:test => true}.to_json)
34
- message.params.should eql(:test => true)
35
- message.creator.should eql(@connection)
36
- end
37
- it "should raise error if message is not JSON" do
38
- lambda{described_class.new(@connection, {:test => true})}.should raise_error Socky::SockyError
39
- lambda{described_class.new(@connection, "test")}.should raise_error Socky::SockyError
40
- end
41
- it "should raise error if message is JSON but not JSON hash" do
42
- lambda{described_class.new(@connection, "test".to_json)}.should raise_error Socky::SockyError
43
- end
44
- end
45
- end
46
-
47
- context "instance" do
48
- before(:each) { @message = described_class.new(@connection, {}.to_json) }
49
- context "#process" do
50
- before(:each) do
51
- @message.stub!(:send_message)
52
- end
53
- it "should raise error if message command is nil" do
54
- @message.stub!(:params).and_return({:command => nil})
55
- lambda {@message.process}.should raise_error(Socky::SockyError, "unknown command")
56
- end
57
- it "should raise error if message command is neither :broadcast nor :query" do
58
- @message.stub!(:params).and_return({:command => :invalid})
59
- lambda {@message.process}.should raise_error(Socky::SockyError, "unknown command")
60
- end
61
- it "should not distinguish between string and symbol in command" do
62
- @message.stub!(:params).and_return({:command => 'broadcast'})
63
- lambda {@message.process}.should_not raise_error(Socky::SockyError, "unknown command")
64
- end
65
- context ":broadcast" do
66
- it "should select target connections basing on params" do
67
- @message.stub!(:params).and_return({:command => :broadcast, :some => :abstract})
68
- Socky::Connection.should_receive(:find).with(:some => :abstract)
69
- @message.process
70
- end
71
- it "should send_message with message body and connection list" do
72
- @message.stub!(:params).and_return({:command => :broadcast, :body => "some message"})
73
- Socky::Connection.stub!(:find).and_return(["first","second"])
74
- @message.should_receive(:send_message).with("some message", ["first", "second"])
75
- @message.process
76
- end
77
- end
78
- context ":query" do
79
- it "should raise error if query type is nil" do
80
- @message.stub!(:params).and_return(:command => :query, :type => nil)
81
- lambda{ @message.process }.should raise_error(Socky::SockyError, "unknown query type")
82
- end
83
- it "should raise error if query type is invalid" do
84
- @message.stub!(:params).and_return(:command => :query, :type => :invalid)
85
- lambda{ @message.process }.should raise_error(Socky::SockyError, "unknown query type")
86
- end
87
- it "should not distinguish between string and symbol in command" do
88
- @message.stub!(:params).and_return({:command => :query, :type => "show_connections"})
89
- lambda {@message.process}.should_not raise_error(Socky::SockyError, "unknown query type")
90
- end
91
- context "=> :show_connections" do
92
- it "should return current connection list to creator" do
93
- @message.stub!(:params).and_return(:command => :query, :type => :show_connections)
94
- Socky::Connection.stub!(:find_all).and_return(["find results"])
95
- @connection.should_receive(:send_message).with(["find results"])
96
- @message.process
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,74 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Socky::Misc do
4
- include Socky::Misc
5
-
6
- shared_examples_for "socky_misc" do
7
- it "#option should return Socky.options" do
8
- Socky.stub!(:options).and_return({:test => true})
9
- @object.options.should eql({:test => true})
10
- end
11
- it "#options= should set Socky.options" do
12
- default_options = Socky.options
13
- begin
14
- Socky.options = {}
15
- @object.options = {:test => true}
16
- Socky.options.should eql({:test => true})
17
- ensure
18
- Socky.options = default_options
19
- end
20
- end
21
- it "#name should return self formatted name" do
22
- @object.name.should eql("#{@object.class.to_s.split("::").last}(#{@object.object_id})")
23
- end
24
- it "#log_path should return Socky.log_path" do
25
- Socky.stub!(:log_path).and_return("abstract")
26
- @object.log_path.should eql("abstract")
27
- end
28
- it "#config_path should return Socky.config_path" do
29
- Socky.stub!(:config_path).and_return("abstract")
30
- @object.config_path.should eql("abstract")
31
- end
32
- it "#info should send joined args to Socky.logger.info" do
33
- Socky.logger.stub!(:info)
34
- Socky.logger.should_receive(:info).with("first second third")
35
- @object.info(["first","second","third"])
36
- end
37
- it "#debug should send joined args to Socky.logger.debug" do
38
- Socky.logger.stub!(:debug)
39
- Socky.logger.should_receive(:debug).with("first second third")
40
- @object.debug(["first","second","third"])
41
- end
42
- it "#error should send self name and error message to self.debug" do
43
- @object.stub!(:debug)
44
- error = mock(:abstract_error, :class => "AbstractError", :message => "abstract")
45
- @object.should_receive(:debug).with([@object.name,"raised:","AbstractError","abstract"])
46
- @object.error(@object.name, error)
47
- end
48
- context "#symbolize_keys" do
49
- it "return args if args are not hash" do
50
- @object.symbolize_keys("abstract").should eql("abstract")
51
- end
52
- it "return hash with symbolized keys if args is hash" do
53
- hash = {"aaa" => "a", 123 => "b"}
54
- @object.symbolize_keys(hash).should eql({:aaa => "a", 123 => "b"})
55
- end
56
- end
57
- end
58
-
59
- context "class" do
60
- before(:each) do
61
- @object = self.class
62
- end
63
- it_should_behave_like "socky_misc"
64
- end
65
-
66
- context "instance" do
67
- before(:each) do
68
- @object = self
69
- end
70
- it_should_behave_like "socky_misc"
71
- end
72
-
73
- end
74
-
@@ -1,42 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Socky::NetRequest do
4
-
5
- context "class" do
6
- context "#post" do
7
- it "should send EventMachine::HttpRequest to url" do
8
- EventMachine::HttpRequest.should_receive(:new).with("some url")
9
- described_class.post("some url")
10
- end
11
- it "should send EventMachine::HttpRequest post request with specified params" do
12
- request = mock(:request)
13
- EventMachine::HttpRequest.stub!(:new).and_return(request)
14
- request.should_receive(:post).with({:body => {:test => true}, :timeout => 3})
15
- described_class.post("some url", :test => true)
16
- end
17
- it "should rescue from EM::HttpRequest and return false" do
18
- EM.run do
19
- described_class.post("inexistent").should be_false
20
- EM.stop
21
- end
22
- end
23
- it "should call block with false if request return status other than 200" do
24
- EM.run do
25
- described_class.post("http://127.0.0.1:8765/fail") do |response|
26
- response.should be_false
27
- EM.stop
28
- end.should be_true
29
- end
30
- end
31
- it "should call block with true if request return status 200" do
32
- EM.run do
33
- described_class.post("http://127.0.0.1:8765/") do |response|
34
- response.should be_true
35
- EM.stop
36
- end.should be_true
37
- end
38
- end
39
- end
40
- end
41
-
42
- end
@@ -1,72 +0,0 @@
1
- require '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 not raise error if :kill option is provided" do
22
- described_class.should_not_receive(:puts).with("Provided config file is invalid.")
23
- lambda { described_class.read(FILES_DIR + "/invalid.yml", :kill => true) }.should_not raise_error SystemExit
24
- end
25
- it "should return valid options if file is valid" do
26
- lambda { described_class.read(FILES_DIR + "/default.yml") }.should_not raise_error SystemExit
27
- described_class.read(FILES_DIR + "/default.yml").should eql(default_options)
28
- end
29
- end
30
-
31
- context "#generate" do
32
- it "should raise error if file exists" do
33
- described_class.should_receive(:puts).with("Config file already exists. You must remove it before generating a new one.")
34
- lambda { described_class.generate(FILES_DIR + "/invalid.yml") }.should raise_error SystemExit
35
- end
36
- it "should raise error if path is not valid" do
37
- described_class.should_receive(:puts).with("Config file is unavailable - please choose another.")
38
- lambda { described_class.generate("/proc/inexistent") }.should raise_error SystemExit
39
- end
40
- it "should create file and exit if path is valid" do
41
- path = FILES_DIR + "/inexistent.yml"
42
- begin
43
- described_class.should_receive(:puts).with("Config file generated at #{path}")
44
- lambda { described_class.generate(path) }.should raise_error SystemExit
45
- ensure
46
- FileUtils.rm(path, :force => true)
47
- end
48
- end
49
- it "should generate file that after parsing will equal default config" do
50
- path = FILES_DIR + "/inexistent.yml"
51
- begin
52
- described_class.should_receive(:puts).with("Config file generated at #{path}")
53
- lambda { described_class.generate(path) }.should raise_error SystemExit
54
- lambda { described_class.read(path) }.should_not raise_error SystemExit
55
- described_class.read(path).should eql(default_options)
56
- ensure
57
- FileUtils.rm(path, :force => true)
58
- end
59
- end
60
- end
61
- end
62
-
63
- def default_options
64
- {
65
- :port => 8080,
66
- :debug => false,
67
- :secret => "my_secret_key",
68
- :secure => false
69
- }
70
- end
71
-
72
- end
@@ -1,76 +0,0 @@
1
- require '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
- ["-p","--port"].each do |function|
32
- described_class.parse([function,"222"]).should eql({:port => 222})
33
- end
34
- end
35
- it "on -s or --secure should set secure mode on" do
36
- ["-s","--secure"].each do |function|
37
- described_class.parse([function]).should eql({:secure => true})
38
- end
39
- end
40
- it "on -P or --pid should set pid_path to provided path" do
41
- ["-P","--pid"].each do |function|
42
- described_class.parse([function,"/tmp/socky.pid"]).should eql({:pid_path => "/tmp/socky.pid"})
43
- end
44
- end
45
- it "on -d or --daemon should set daemon mode on" do
46
- ["-d","--daemon"].each do |function|
47
- described_class.parse([function]).should eql({:daemonize => true})
48
- end
49
- end
50
- it "on -l or --log should set log_path to provided path" do
51
- ["-l","--log"].each do |function|
52
- described_class.parse([function,"/tmp/socky.log"]).should eql({:log_path => "/tmp/socky.log"})
53
- end
54
- end
55
- it "on --debug should set debug to true" do
56
- described_class.parse(["--debug"]).should eql({:debug => true})
57
- end
58
- it "on --deep-debug should set debug and deep_debug to true" do
59
- described_class.parse(["--deep-debug"]).should eql({:debug => true, :deep_debug => true})
60
- end
61
- it "on -? or --help should display usage" do
62
- ["-?","--help"].each do |function|
63
- described_class.should_receive(:puts).with(/Usage: socky \[options\]/)
64
- lambda { described_class.parse([function]) }.should raise_error SystemExit
65
- end
66
- end
67
- it "on -v or --version should dosplay current version" do
68
- ["-v","--version"].each do |function|
69
- described_class.should_receive(:puts).with("Socky #{Socky::VERSION}")
70
- lambda { described_class.parse([function]) }.should raise_error SystemExit
71
- end
72
- end
73
-
74
- end
75
- end
76
- end
@@ -1,60 +0,0 @@
1
- require '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", :kill => nil)
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(default_options)
29
- end
30
- it "should value parse_options over default values" do
31
- Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
32
- Socky::Options.prepare([])
33
- Socky.options.should eql(default_options.merge(:log_path=>"parsed"))
34
- end
35
- it "should value read_config over default values" do
36
- Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
37
- Socky::Options.prepare([])
38
- Socky.options.should eql(default_options.merge(:log_path=>"from config"))
39
- end
40
- it "should value parse_options over read_config" do
41
- Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
42
- Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
43
- Socky::Options.prepare([])
44
- Socky.options.should eql(default_options.merge(:log_path=>"parsed"))
45
- end
46
- end
47
- end
48
-
49
- def default_options
50
- {
51
- :port => 8080,
52
- :log_path => nil,
53
- :debug => false,
54
- :deep_debug => false,
55
- :secure => false,
56
- :config_path => "/var/run/socky.yml"
57
- }
58
- end
59
-
60
- end
@@ -1,88 +0,0 @@
1
- require '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 if daemonize option is false" do
16
- Socky.stub(:options).and_return({:daemonize => false})
17
- @server.should_receive(:start)
18
- described_class.run
19
- end
20
- it "should call #daemonize on new instance of self if daemonize option is true" do
21
- Socky.stub(:options).and_return({:daemonize => true})
22
- @server.should_receive(:daemonize)
23
- described_class.run
24
- end
25
- it "should call #kill_pid on new instance of self if kill option is true" do
26
- Socky.stub(:options).and_return({:kill => true})
27
- @server.should_receive(:kill_pid)
28
- described_class.run
29
- end
30
- end
31
- context "#new" do
32
- it "should prepare options from args" do
33
- begin
34
- described_class.new(["-c", File.dirname(__FILE__) + "/../files/default.yml"])
35
- Socky.options.class.should eql(Hash)
36
- Socky.options.should_not be_empty
37
- ensure
38
- Socky.options = nil
39
- end
40
- end
41
- end
42
- end
43
-
44
- context "#instance" do
45
- before(:each) do
46
- Socky::Options.stub!(:prepare)
47
- @runner = described_class.new
48
- end
49
-
50
- context "#start" do
51
- it "should create valid websocket server" do
52
- begin
53
- EM.run do
54
- MSG = "Hello World!"
55
- EventMachine.add_timer(0.1) do
56
- http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
57
- http.errback {
58
- EM.stop
59
- fail
60
- }
61
- http.callback {
62
- http.response_header.status.should == 101
63
- EM.stop
64
- }
65
- end
66
-
67
- Socky.stub!(:options).and_return({:port => 12345})
68
- Socky.logger = mock(:logger, :info => nil, :debug => nil)
69
- @runner.start
70
- end
71
- ensure
72
- Socky.logger = nil
73
- end
74
- end
75
- end
76
-
77
- it "#stop should call EM.stop" do
78
- begin
79
- Socky.logger = mock(:logger, :info => nil, :debug => nil)
80
- EM.should_receive(:stop)
81
- @runner.stop
82
- ensure
83
- Socky.logger = nil
84
- end
85
- end
86
-
87
- end
88
- end