socky-server 0.4.1 → 0.5.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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