danthes 1.0.1
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/.gitignore +7 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +54 -0
- data/Gemfile +11 -0
- data/Guardfile +7 -0
- data/LICENSE +21 -0
- data/README.md +153 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/danthes.js.coffee +142 -0
- data/danthes.gemspec +17 -0
- data/lib/danthes/engine.rb +16 -0
- data/lib/danthes/faye_extension.rb +40 -0
- data/lib/danthes/version.rb +3 -0
- data/lib/danthes/view_helpers.rb +22 -0
- data/lib/danthes.rb +109 -0
- data/lib/generators/danthes/install_generator.rb +16 -0
- data/lib/generators/danthes/redis_install_generator.rb +17 -0
- data/lib/generators/danthes.rb +25 -0
- data/lib/generators/templates/danthes.ru +16 -0
- data/lib/generators/templates/danthes.yml +16 -0
- data/lib/generators/templates/danthes_redis.yml +14 -0
- data/spec/coffeescripts/danthes_spec.js.coffee +127 -0
- data/spec/danthes/faye_extension_spec.rb +67 -0
- data/spec/danthes_spec.rb +183 -0
- data/spec/fixtures/danthes.yml +10 -0
- data/spec/fixtures/danthes_redis.yml +6 -0
- data/spec/javascripts/support/jasmine.yml +6 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/spec/spec_helper.rb +8 -0
- metadata +104 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'generators/danthes'
|
2
|
+
|
3
|
+
module Danthes
|
4
|
+
module Generators
|
5
|
+
class RedisInstallGenerator < Base
|
6
|
+
desc 'Create sample redis config file and add faye-redis gem to Gemfile'
|
7
|
+
|
8
|
+
def copy_files
|
9
|
+
template "danthes_redis.yml", "config/danthes_redis.yml"
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_redis_gem
|
13
|
+
add_gem 'faye-redis'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Danthes
|
4
|
+
module Generators
|
5
|
+
class Base < Rails::Generators::Base
|
6
|
+
def self.source_root
|
7
|
+
File.dirname(__FILE__) + "/templates"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.banner
|
11
|
+
"rails generate danthes:#{generator_name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def add_gem(name, options = {})
|
17
|
+
gemfile_path = File.join(destination_root, 'Gemfile')
|
18
|
+
gemfile_content = File.read(gemfile_path)
|
19
|
+
File.open(gemfile_path, 'a') { |f| f.write("\n") } unless gemfile_content =~ /\n\Z/
|
20
|
+
gem name, options unless gemfile_content.include? name
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Run with: rackup private_pub.ru -s thin -E production
|
2
|
+
require "bundler/setup"
|
3
|
+
require "yaml"
|
4
|
+
require "faye"
|
5
|
+
require "danthes"
|
6
|
+
require "thin"
|
7
|
+
|
8
|
+
Danthes.load_config(File.expand_path("../config/danthes.yml", __FILE__))
|
9
|
+
Faye::WebSocket.load_adapter(Danthes.config[:adapter])
|
10
|
+
|
11
|
+
path = File.expand_path("../config/danthes_redis.yml", __FILE__)
|
12
|
+
if File.exist?(path)
|
13
|
+
Danthes.load_redis_config(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
run Danthes.faye_app
|
@@ -0,0 +1,16 @@
|
|
1
|
+
development:
|
2
|
+
adapter: thin
|
3
|
+
server: "http://localhost:9292"
|
4
|
+
secret_token: "secret"
|
5
|
+
mount: '/faye'
|
6
|
+
test:
|
7
|
+
adapter: thin
|
8
|
+
server: "http://localhost:9292"
|
9
|
+
secret_token: "secret"
|
10
|
+
mount: '/faye'
|
11
|
+
production:
|
12
|
+
adapter: thin
|
13
|
+
server: "http://faye.example.com"
|
14
|
+
mount: '/faye'
|
15
|
+
secret_token: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
|
16
|
+
signature_expiration: 3600 # one hour
|
@@ -0,0 +1,14 @@
|
|
1
|
+
development:
|
2
|
+
host: localhost
|
3
|
+
port: 6379
|
4
|
+
namespace: '/danthes'
|
5
|
+
test:
|
6
|
+
host: localhost
|
7
|
+
port: 6379
|
8
|
+
namespace: '/danthes'
|
9
|
+
production:
|
10
|
+
host: redis_host
|
11
|
+
port: redis_port
|
12
|
+
password: redis_password
|
13
|
+
database: redis_database
|
14
|
+
namespace: '/namespace'
|
@@ -0,0 +1,127 @@
|
|
1
|
+
describe "Danthes", ->
|
2
|
+
window.Faye = undefined
|
3
|
+
pub = undefined
|
4
|
+
|
5
|
+
signToChannel = (channel) ->
|
6
|
+
faye = {subscribe: jasmine.createSpy()}
|
7
|
+
spyOn(pub, 'faye').andCallFake (callback) ->
|
8
|
+
callback(faye)
|
9
|
+
options = {server: "server", channel: "#{channel}"}
|
10
|
+
pub.sign(options)
|
11
|
+
return [faye, options]
|
12
|
+
|
13
|
+
beforeEach ->
|
14
|
+
pub = window.Danthes
|
15
|
+
pub.reset()
|
16
|
+
script = document.getElementById('faye-connection-script')
|
17
|
+
if script?
|
18
|
+
script.parentNode.removeChild(script)
|
19
|
+
|
20
|
+
it "not adds a subscription callback without signing", ->
|
21
|
+
expect(pub.subscribe("hello", "callback")).toBe(false)
|
22
|
+
expect(pub.subscriptions).toEqual({})
|
23
|
+
|
24
|
+
it "adds a subscription callback", ->
|
25
|
+
signToChannel('hello')
|
26
|
+
pub.subscribe("hello", "callback")
|
27
|
+
expect(pub.subscriptions["hello"]['callback']).toEqual("callback")
|
28
|
+
|
29
|
+
it "has a fayeExtension which adds matching subscription signature and timestamp to outgoing message", ->
|
30
|
+
called = false
|
31
|
+
message = {channel: "/meta/subscribe", subscription: "hello"}
|
32
|
+
pub.subscriptions['hello'] = {}
|
33
|
+
pub.subscriptions['hello']['opts'] = {signature: "abcd", timestamp: "1234"}
|
34
|
+
pub.fayeExtension.outgoing message, (message) ->
|
35
|
+
expect(message.ext.danthes_signature).toEqual("abcd")
|
36
|
+
expect(message.ext.danthes_timestamp).toEqual("1234")
|
37
|
+
called = true
|
38
|
+
expect(called).toBeTruthy()
|
39
|
+
|
40
|
+
it "evaluates javascript in message response", ->
|
41
|
+
pub.handleResponse(eval: 'this.subscriptions.foo = "bar"')
|
42
|
+
expect(pub.subscriptions.foo).toEqual("bar")
|
43
|
+
|
44
|
+
it "triggers callback matching message channel in response", ->
|
45
|
+
called = false
|
46
|
+
signToChannel('test')
|
47
|
+
pub.subscribe "test", (data, channel) ->
|
48
|
+
expect(data).toEqual("abcd")
|
49
|
+
expect(channel).toEqual("test")
|
50
|
+
called = true
|
51
|
+
pub.handleResponse(channel: "test", data: "abcd")
|
52
|
+
expect(called).toBeTruthy()
|
53
|
+
|
54
|
+
it "triggers faye callback function immediately when fayeClient is available", ->
|
55
|
+
called = false
|
56
|
+
pub.fayeClient = "faye"
|
57
|
+
pub.faye (faye) ->
|
58
|
+
expect(faye).toEqual("faye")
|
59
|
+
called = true
|
60
|
+
expect(called).toBeTruthy()
|
61
|
+
|
62
|
+
it "adds fayeCallback when client and server aren't available", ->
|
63
|
+
pub.faye("callback")
|
64
|
+
expect(pub.fayeCallbacks[0]).toEqual("callback")
|
65
|
+
|
66
|
+
it "adds a script tag loading faye js when the server is present", ->
|
67
|
+
client = {addExtension: jasmine.createSpy()}
|
68
|
+
callback = jasmine.createSpy()
|
69
|
+
pub.server = "path/to/faye"
|
70
|
+
pub.faye(callback)
|
71
|
+
expect(pub.fayeCallbacks[0]).toEqual(callback)
|
72
|
+
script = document.getElementById('faye-connection-script')
|
73
|
+
expect(script).toBeDefined()
|
74
|
+
expect(script.type).toEqual("text/javascript")
|
75
|
+
expect(script.src).toMatch("path/to/faye/client.js")
|
76
|
+
|
77
|
+
it "adds a faye subscription with response handler when signing", ->
|
78
|
+
pub.fayeClient = 'string'
|
79
|
+
[faye, options] = signToChannel('somechannel')
|
80
|
+
expect(faye.subscribe).toHaveBeenCalled()
|
81
|
+
expect(pub.server).toEqual("server")
|
82
|
+
expect(pub.subscriptions.somechannel.opts).toEqual(options)
|
83
|
+
|
84
|
+
it "connects to faye server, adds extension, and executes callbacks", ->
|
85
|
+
callback = jasmine.createSpy()
|
86
|
+
client = {addExtension: jasmine.createSpy()}
|
87
|
+
window.Faye = {}
|
88
|
+
window.Faye.Client = (server) ->
|
89
|
+
expect(server).toEqual("server")
|
90
|
+
return client
|
91
|
+
pub.server = "server"
|
92
|
+
pub.fayeCallbacks.push(callback)
|
93
|
+
spyOn(pub, 'fayeExtension')
|
94
|
+
pub.connectToFaye()
|
95
|
+
expect(pub.fayeClient).toEqual(client)
|
96
|
+
expect(client.addExtension).toHaveBeenCalledWith(pub.fayeExtension)
|
97
|
+
expect(callback).toHaveBeenCalledWith(client)
|
98
|
+
|
99
|
+
it "adds subscription faye object into channel object", ->
|
100
|
+
sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy()}
|
101
|
+
pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
|
102
|
+
options = {server: "server", channel: 'somechannel'}
|
103
|
+
pub.sign(options)
|
104
|
+
expect(sub.callback).toHaveBeenCalled()
|
105
|
+
expect(sub.errback).toHaveBeenCalled()
|
106
|
+
expect(pub.subscriptions.somechannel.sub).toEqual(sub)
|
107
|
+
|
108
|
+
it "removes subscription to the channel", ->
|
109
|
+
sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy(), cancel: jasmine.createSpy()}
|
110
|
+
pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
|
111
|
+
options = {server: "server", channel: 'somechannel'}
|
112
|
+
pub.sign(options)
|
113
|
+
pub.unsubscribe('somechannel')
|
114
|
+
expect(sub.cancel).toHaveBeenCalled()
|
115
|
+
expect(pub.subscriptions.somechannel).toBeUndefined()
|
116
|
+
expect(pub.subscriptions).toEqual({})
|
117
|
+
|
118
|
+
it "removes all subscription to the channels", ->
|
119
|
+
sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy(), cancel: jasmine.createSpy()}
|
120
|
+
pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
|
121
|
+
options = {server: "server", channel: 'somechannel'}
|
122
|
+
pub.sign(options)
|
123
|
+
pub.unsubscribeAll()
|
124
|
+
expect(sub.cancel).toHaveBeenCalled()
|
125
|
+
expect(pub.subscriptions.somechannel).toBeUndefined()
|
126
|
+
expect(pub.subscriptions).toEqual({})
|
127
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Danthes::FayeExtension do
|
4
|
+
before(:each) do
|
5
|
+
Danthes.startup
|
6
|
+
@faye = Danthes::FayeExtension.new
|
7
|
+
@message = {"channel" => "/meta/subscribe", "ext" => {}}
|
8
|
+
end
|
9
|
+
|
10
|
+
it "adds an error on an incoming subscription with a bad signature" do
|
11
|
+
@message["subscription"] = "hello"
|
12
|
+
@message["ext"]["danthes_signature"] = "bad"
|
13
|
+
@message["ext"]["danthes_timestamp"] = "123"
|
14
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
15
|
+
message["error"].should eq("Incorrect signature.")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "has no error when the signature matches the subscription" do
|
19
|
+
sub = Danthes.subscription(:channel => "hello")
|
20
|
+
@message["subscription"] = sub[:channel]
|
21
|
+
@message["ext"]["danthes_signature"] = sub[:signature]
|
22
|
+
@message["ext"]["danthes_timestamp"] = sub[:timestamp]
|
23
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
24
|
+
message["error"].should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "has an error when signature just expired" do
|
28
|
+
Danthes.config[:signature_expiration] = 1
|
29
|
+
sub = Danthes.subscription(:timestamp => 123, :channel => "hello")
|
30
|
+
@message["subscription"] = sub[:channel]
|
31
|
+
@message["ext"]["danthes_signature"] = sub[:signature]
|
32
|
+
@message["ext"]["danthes_timestamp"] = sub[:timestamp]
|
33
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
34
|
+
message["error"].should eq("Signature has expired.")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has an error when trying to publish to a custom channel with a bad token" do
|
38
|
+
Danthes.config[:secret_token] = "good"
|
39
|
+
@message["channel"] = "/custom/channel"
|
40
|
+
@message["ext"]["danthes_token"] = "bad"
|
41
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
42
|
+
message["error"].should eq("Incorrect token.")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises an exception when attempting to call a custom channel without a secret_token set" do
|
46
|
+
@message["channel"] = "/custom/channel"
|
47
|
+
@message["ext"]["danthes_token"] = "bad"
|
48
|
+
lambda {
|
49
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
50
|
+
}.should raise_error("No secret_token config set, ensure danthes.yml is loaded properly.")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "has no error on other meta calls" do
|
54
|
+
@message["channel"] = "/meta/connect"
|
55
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
56
|
+
message["error"].should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not let message carry the private pub token after server's validation" do
|
60
|
+
Danthes.config[:secret_token] = "good"
|
61
|
+
@message["channel"] = "/custom/channel"
|
62
|
+
@message["ext"]["danthes_token"] = Danthes.config[:secret_token]
|
63
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
64
|
+
message['ext']["danthes_token"].should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Danthes do
|
4
|
+
before(:each) do
|
5
|
+
Danthes.startup
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:config) { Danthes.config }
|
9
|
+
|
10
|
+
it "defaults server to nil" do
|
11
|
+
config[:server].should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "defaults signature_expiration to nil" do
|
15
|
+
config[:signature_expiration].should be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "defaults subscription timestamp to current time in milliseconds" do
|
19
|
+
time = Time.now
|
20
|
+
Time.stub!(:now).and_return(time)
|
21
|
+
Danthes.subscription[:timestamp].should eq((time.to_f * 1000).round)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads a simple configuration file via load_config" do
|
25
|
+
Danthes.env = 'production'
|
26
|
+
Danthes.load_config("spec/fixtures/danthes.yml")
|
27
|
+
config[:server].should eq("http://example.com/faye")
|
28
|
+
config[:secret_token].should eq("PRODUCTION_SECRET_TOKEN")
|
29
|
+
config[:signature_expiration].should eq(600)
|
30
|
+
config[:adapter].should eq('thin')
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when redis config exists" do
|
34
|
+
before do
|
35
|
+
Danthes.env = 'test'
|
36
|
+
Danthes.load_redis_config("spec/fixtures/danthes_redis.yml")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "passes redis config to faye engine options" do
|
40
|
+
config[:engine][:type].should eq Faye::Redis
|
41
|
+
config[:engine][:host].should eq 'redis_host'
|
42
|
+
config[:engine][:port].should eq 'redis_port'
|
43
|
+
config[:engine][:password].should eq 'redis_password'
|
44
|
+
config[:engine][:database].should eq 'redis_database'
|
45
|
+
config[:engine][:namespace].should eq '/namespace'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should pass redis config and default options to faye" do
|
49
|
+
Faye::RackAdapter.should_receive(:new) do |options|
|
50
|
+
options[:engine].should eq Danthes.config[:engine]
|
51
|
+
options[:mount].should eq '/faye'
|
52
|
+
end
|
53
|
+
Danthes.faye_app
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when redis config does not exist" do
|
58
|
+
it "should not have :engine inside of config hash" do
|
59
|
+
config.should_not include :engine
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have mount point" do
|
63
|
+
config[:mount].should eq '/faye'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "raises an exception if an invalid environment is passed to load_config" do
|
68
|
+
lambda {
|
69
|
+
Danthes.load_config("spec/fixtures/danthes.yml", 'foo')
|
70
|
+
}.should raise_error ArgumentError
|
71
|
+
end
|
72
|
+
|
73
|
+
it "includes channel, server, and custom time in subscription" do
|
74
|
+
Danthes.config[:server] = "server"
|
75
|
+
Danthes.config[:mount] = '/faye'
|
76
|
+
subscription = Danthes.subscription(:timestamp => 123, :channel => "hello")
|
77
|
+
subscription[:timestamp].should eq(123)
|
78
|
+
subscription[:channel].should eq("hello")
|
79
|
+
subscription[:server].should eq("server/faye")
|
80
|
+
end
|
81
|
+
|
82
|
+
it "returns full server url from server and mount configs" do
|
83
|
+
Danthes.config[:server] = "server.com"
|
84
|
+
Danthes.config[:mount] = '/faye'
|
85
|
+
Danthes.server_url.should == 'server.com/faye'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "does a sha1 digest of channel, timestamp, and secret token" do
|
89
|
+
Danthes.config[:secret_token] = "token"
|
90
|
+
subscription = Danthes.subscription(:timestamp => 123, :channel => "channel")
|
91
|
+
subscription[:signature].should eq(Digest::SHA1.hexdigest("tokenchannel123"))
|
92
|
+
end
|
93
|
+
|
94
|
+
it "formats a message hash given a channel and a string for eval" do
|
95
|
+
Danthes.config[:secret_token] = "token"
|
96
|
+
Danthes.message("chan", "foo").should eq(
|
97
|
+
:ext => {:danthes_token => "token"},
|
98
|
+
:channel => "chan",
|
99
|
+
:data => {
|
100
|
+
:channel => "chan",
|
101
|
+
:eval => "foo"
|
102
|
+
}
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "formats a message hash given a channel and a hash" do
|
107
|
+
Danthes.config[:secret_token] = "token"
|
108
|
+
Danthes.message("chan", :foo => "bar").should eq(
|
109
|
+
:ext => {:danthes_token => "token"},
|
110
|
+
:channel => "chan",
|
111
|
+
:data => {
|
112
|
+
:channel => "chan",
|
113
|
+
:data => {:foo => "bar"}
|
114
|
+
}
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "publish message as json to server using Net::HTTP" do
|
119
|
+
Danthes.config[:server] = "http://localhost"
|
120
|
+
Danthes.config[:mount] = '/faye/path'
|
121
|
+
message = 'foo'
|
122
|
+
faye = stub_request(:post, "http://localhost/faye/path").
|
123
|
+
with(:body => {"message"=>"\"foo\""},
|
124
|
+
:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'}).
|
125
|
+
to_return(:status => 200, :body => "", :headers => {})
|
126
|
+
Danthes.publish_message(message)
|
127
|
+
faye.should have_been_made.once
|
128
|
+
end
|
129
|
+
|
130
|
+
it "it should use HTTPS if the server URL says so" do
|
131
|
+
Danthes.config[:server] = "https://localhost"
|
132
|
+
Danthes.config[:mount] = '/faye/path'
|
133
|
+
http = mock(:http).as_null_object
|
134
|
+
|
135
|
+
Net::HTTP.should_receive(:new).and_return(http)
|
136
|
+
http.should_receive(:use_ssl=).with(true)
|
137
|
+
|
138
|
+
Danthes.publish_message('foo')
|
139
|
+
end
|
140
|
+
|
141
|
+
it "it should not use HTTPS if the server URL says not to" do
|
142
|
+
Danthes.config[:server] = "http://localhost"
|
143
|
+
http = mock(:http).as_null_object
|
144
|
+
|
145
|
+
Net::HTTP.should_receive(:new).and_return(http)
|
146
|
+
http.should_receive(:use_ssl=).with(false)
|
147
|
+
|
148
|
+
Danthes.publish_message('foo')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "raises an exception if no server is specified when calling publish_message" do
|
152
|
+
lambda {
|
153
|
+
Danthes.publish_message("foo")
|
154
|
+
}.should raise_error(Danthes::Error)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "publish_to passes message to publish_message call" do
|
158
|
+
Danthes.should_receive(:message).with("chan", "foo").and_return("message")
|
159
|
+
Danthes.should_receive(:publish_message).with("message").and_return(:result)
|
160
|
+
Danthes.publish_to("chan", "foo").should eq(:result)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "has a Faye rack app instance" do
|
164
|
+
Danthes.faye_app.should be_kind_of(Faye::RackAdapter)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "says signature has expired when time passed in is greater than expiration" do
|
168
|
+
Danthes.config[:signature_expiration] = 30*60
|
169
|
+
time = Danthes.subscription[:timestamp] - 31*60*1000
|
170
|
+
Danthes.signature_expired?(time).should be_true
|
171
|
+
end
|
172
|
+
|
173
|
+
it "says signature has not expired when time passed in is less than expiration" do
|
174
|
+
Danthes.config[:signature_expiration] = 30*60
|
175
|
+
time = Danthes.subscription[:timestamp] - 29*60*1000
|
176
|
+
Danthes.signature_expired?(time).should be_false
|
177
|
+
end
|
178
|
+
|
179
|
+
it "says signature has not expired when expiration is nil" do
|
180
|
+
Danthes.config[:signature_expiration] = nil
|
181
|
+
Danthes.signature_expired?(0).should be_false
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
development:
|
2
|
+
adapter: thin
|
3
|
+
server: http://dev.local:9292/faye
|
4
|
+
secret_token: DEVELOPMENT_SECRET_TOKEN
|
5
|
+
signature_expiration: 600
|
6
|
+
production:
|
7
|
+
adapter: thin
|
8
|
+
server: http://example.com/faye
|
9
|
+
secret_token: PRODUCTION_SECRET_TOKEN
|
10
|
+
signature_expiration: 600
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jasmine
|
2
|
+
class Config
|
3
|
+
|
4
|
+
# Add your overrides or custom config code here
|
5
|
+
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# Note - this is necessary for rspec2, which has removed the backtrace
|
11
|
+
module Jasmine
|
12
|
+
class SpecBuilder
|
13
|
+
def declare_spec(parent, spec)
|
14
|
+
me = self
|
15
|
+
example_name = spec["name"]
|
16
|
+
@spec_ids << spec["id"]
|
17
|
+
backtrace = @example_locations[parent.description + " " + example_name]
|
18
|
+
parent.it example_name, {} do
|
19
|
+
me.report_spec(spec["id"])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'jasmine'
|
5
|
+
jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
|
6
|
+
require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
|
7
|
+
if Jasmine::Dependencies.rspec2?
|
8
|
+
require 'rspec'
|
9
|
+
else
|
10
|
+
require 'spec'
|
11
|
+
end
|
12
|
+
|
13
|
+
jasmine_config = Jasmine::Config.new
|
14
|
+
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
|
15
|
+
|
16
|
+
should_stop = false
|
17
|
+
|
18
|
+
if Jasmine::Dependencies.rspec2?
|
19
|
+
RSpec.configuration.after(:suite) do
|
20
|
+
spec_builder.stop if should_stop
|
21
|
+
end
|
22
|
+
else
|
23
|
+
Spec::Runner.configure do |config|
|
24
|
+
config.after(:suite) do
|
25
|
+
spec_builder.stop if should_stop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
spec_builder.start
|
31
|
+
should_stop = true
|
32
|
+
spec_builder.declare_suites
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: danthes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexander Simonov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: faye
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.8.0
|
30
|
+
description: Private pub/sub messaging in Rails through Faye. More Faye features supported.
|
31
|
+
Based on PrivatePub.
|
32
|
+
email:
|
33
|
+
- alex@simonov.me
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- .rspec
|
40
|
+
- .rvmrc
|
41
|
+
- .travis.yml
|
42
|
+
- CHANGELOG.md
|
43
|
+
- Gemfile
|
44
|
+
- Guardfile
|
45
|
+
- LICENSE
|
46
|
+
- README.md
|
47
|
+
- Rakefile
|
48
|
+
- app/assets/javascripts/danthes.js.coffee
|
49
|
+
- danthes.gemspec
|
50
|
+
- lib/danthes.rb
|
51
|
+
- lib/danthes/engine.rb
|
52
|
+
- lib/danthes/faye_extension.rb
|
53
|
+
- lib/danthes/version.rb
|
54
|
+
- lib/danthes/view_helpers.rb
|
55
|
+
- lib/generators/danthes.rb
|
56
|
+
- lib/generators/danthes/install_generator.rb
|
57
|
+
- lib/generators/danthes/redis_install_generator.rb
|
58
|
+
- lib/generators/templates/danthes.ru
|
59
|
+
- lib/generators/templates/danthes.yml
|
60
|
+
- lib/generators/templates/danthes_redis.yml
|
61
|
+
- spec/coffeescripts/danthes_spec.js.coffee
|
62
|
+
- spec/danthes/faye_extension_spec.rb
|
63
|
+
- spec/danthes_spec.rb
|
64
|
+
- spec/fixtures/danthes.yml
|
65
|
+
- spec/fixtures/danthes_redis.yml
|
66
|
+
- spec/javascripts/support/jasmine.yml
|
67
|
+
- spec/javascripts/support/jasmine_config.rb
|
68
|
+
- spec/javascripts/support/jasmine_runner.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
homepage: http://github.com/phenomena/danthes
|
71
|
+
licenses: []
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.8.24
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: Private pub/sub messaging through Faye.
|
94
|
+
test_files:
|
95
|
+
- spec/coffeescripts/danthes_spec.js.coffee
|
96
|
+
- spec/danthes/faye_extension_spec.rb
|
97
|
+
- spec/danthes_spec.rb
|
98
|
+
- spec/fixtures/danthes.yml
|
99
|
+
- spec/fixtures/danthes_redis.yml
|
100
|
+
- spec/javascripts/support/jasmine.yml
|
101
|
+
- spec/javascripts/support/jasmine_config.rb
|
102
|
+
- spec/javascripts/support/jasmine_runner.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
has_rdoc:
|