zulu 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb03707592c2d24585d588b314f25a8667c39761
4
- data.tar.gz: cacfaafd1997215b61e76d413c896212d8243039
3
+ metadata.gz: 1bf65dca8019b224cf68263c2eb02030c6c73ee0
4
+ data.tar.gz: 129978dfebda32e679a14923de6d8e2629339397
5
5
  SHA512:
6
- metadata.gz: 31d1e68b0b9f4225ba64a21871922af7451623928ab1a36322c9517b5d389dbeb5642477facd945862b191608d88a8b9d2750216905dfca2f375036334ddcbe0
7
- data.tar.gz: 21f0083f6077bae9a4713b631b988fe8c0acae5556887ea0b709f206158d986413f993e198213ce709489d8e656c64baa3d41f2f91c1e66f60cfb051ff78158b
6
+ metadata.gz: 26cf2c9f96eaffba2a7e895d9a261e1435e975df1ddad5333101bb4b5d4636fb756c78c893af12ebf6e71a09b3984d52272a9d79b6d064832014e2af274bf546
7
+ data.tar.gz: 473a95bb5c9a92a69879b159e501dcefa2efc05f408aaf380b3e51902be39705fda8988f58abcadfc7889e10048c04edf0d1de58ccb0fc4f44cfcc4114f17711
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Zulu
2
2
 
3
+ [![Build Status](https://travis-ci.org/dweinand/zulu.png?branch=master)](https://travis-ci.org/dweinand/zulu)
4
+
3
5
  Zulu is standalone PuSH-inspired service for scheduling web hook execution.
4
6
 
5
7
  ## Installation
data/lib/zulu.rb CHANGED
@@ -1,9 +1,17 @@
1
1
  require "slop"
2
2
  require "rack"
3
3
  require "reel"
4
+ require "redis"
5
+ require "celluloid/redis"
6
+ require "logger"
4
7
 
5
8
  require "zulu/version"
9
+ require "zulu/challenge"
6
10
  require "zulu/server"
11
+ require "zulu/subscription"
12
+ require "zulu/subscription_request"
13
+ require "zulu/subscription_request_processor"
14
+
7
15
 
8
16
  module Zulu
9
17
  DEFAULTS = {
@@ -11,9 +19,9 @@ module Zulu
11
19
  host: "0.0.0.0",
12
20
  servers: 0,
13
21
  workers: 5,
14
- database: "localhost:6379",
22
+ database: "redis://127.0.0.1:6379",
15
23
  keeper: false
16
- }
24
+ }.freeze
17
25
 
18
26
  def self.options
19
27
  @options ||= DEFAULTS.dup
@@ -34,7 +42,7 @@ module Zulu
34
42
  on :o, :host, 'Listen on HOST (default: 0.0.0.0)', argument: true
35
43
  on :s, :servers, 'Run SERVERS server workers (default: 0)', argument: true, as: Integer
36
44
  on :w, :workers, 'Run WORKERS background workers (default: 5)', argument: true, as: Integer
37
- on :d, :database, "Connect to DATABASE (default: localhost:6379)", argument: true
45
+ on :d, :database, "Connect to DATABASE (default: redis://127.0.0.1:6379)", argument: true
38
46
  on :k, :keeper, "Run a keeper worker (default: false)"
39
47
  end
40
48
  opts.each do |option|
@@ -47,9 +55,17 @@ module Zulu
47
55
  end
48
56
 
49
57
  def self.run
50
- if options[:servers] > 0
51
- run_servers
52
- end
58
+ run_workers if options[:workers] > 0
59
+ run_servers if options[:servers] > 0
60
+ sleep
61
+ rescue Interrupt
62
+ stop
63
+ end
64
+
65
+ def self.stop
66
+ stop_servers if options[:servers] > 0
67
+ stop_workers if options[:workers] > 0
68
+ exit
53
69
  end
54
70
 
55
71
  def self.run_servers
@@ -58,4 +74,25 @@ module Zulu
58
74
  workers: options[:servers]
59
75
  end
60
76
 
77
+ def self.stop_servers
78
+ Celluloid::Actor[:reel_server].terminate if Celluloid::Actor[:reel_server]
79
+ Celluloid::Actor[:reel_rack_pool].terminate if Celluloid::Actor[:reel_rack_pool]
80
+ end
81
+
82
+ def self.run_workers
83
+ Celluloid::Actor[:worker_supervisor] = Celluloid::SupervisionGroup.run!
84
+ Celluloid::Actor[:worker_supervisor].pool(SubscriptionRequestProcessor,
85
+ as: :request_processors,
86
+ size: options[:workers])
87
+ Celluloid::Actor[:request_processors].async.process
88
+ end
89
+
90
+ def self.stop_workers
91
+ Celluloid::Actor[:worker_supervisor].terminate if Celluloid::Actor[:worker_supervisor]
92
+ end
93
+
94
+ def self.redis
95
+ Thread.current[:redis] ||= Redis.new(url: options[:database], driver: :celluloid)
96
+ end
97
+
61
98
  end
@@ -0,0 +1,10 @@
1
+ module Zulu
2
+ class Challenge < String
3
+
4
+ CHARS = [(0..9),('a'..'z'),('A'..'Z')].inject([]) {|a,r| a +=r.to_a; a}
5
+
6
+ def initialize(len=24)
7
+ self << CHARS[(rand(CHARS.size - 1))] until length == len
8
+ end
9
+ end
10
+ end
data/lib/zulu/server.rb CHANGED
@@ -4,16 +4,25 @@ module Zulu
4
4
  class Server < Sinatra::Base
5
5
  CONTENT_TYPES = ['application/x-www-form-urlencoded']
6
6
 
7
+ get '/' do
8
+ Time.now.utc.xmlschema
9
+ end
10
+
7
11
  post '/' do
8
12
  if valid_content_type?
9
13
  process_subscription
10
14
  else
11
- status 406
15
+ error 406
12
16
  end
13
17
  end
14
18
 
15
19
  def process_subscription
16
- status 202
20
+ request = SubscriptionRequest.new(params)
21
+ if request.save
22
+ status 202
23
+ else
24
+ error 400, request.error_messages.join("\n")
25
+ end
17
26
  end
18
27
 
19
28
  def valid_content_type?
@@ -0,0 +1,31 @@
1
+ require "digest/md5"
2
+
3
+ module Zulu
4
+ class Subscription
5
+
6
+ KEY_PREFIX = "subscription".freeze
7
+
8
+ def initialize(options={})
9
+ @id = options[:id]
10
+ @topic = options[:topic]
11
+ @callback = options[:callback]
12
+ end
13
+
14
+ def id
15
+ @id ||= Digest::MD5.hexdigest [@topic, @callback].join(':')
16
+ end
17
+
18
+ def callback
19
+ @callback ||= Zulu.redis.get "#{KEY_PREFIX}:#{id}:callback"
20
+ end
21
+
22
+ def save
23
+ Zulu.redis.set "#{KEY_PREFIX}:#{id}:callback", callback
24
+ end
25
+
26
+ def destroy
27
+ Zulu.redis.del "#{KEY_PREFIX}:#{id}:callback"
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,106 @@
1
+ require "addressable/uri"
2
+ require "oj"
3
+
4
+
5
+ module Zulu
6
+ class SubscriptionRequest
7
+ LIST = "subscription_requests".freeze
8
+ MODES = %w(subscribe unsubscribe).freeze
9
+
10
+ def self.push(request)
11
+ Zulu.redis.lpush(LIST, request.to_json)
12
+ end
13
+
14
+ def self.pop(timeout=nil)
15
+ _, params = Zulu.redis.brpop(LIST, timeout: timeout)
16
+ params and new(Oj.load(params))
17
+ end
18
+
19
+ def initialize(params)
20
+ @mode = params['hub.mode']
21
+ @topic = params['hub.topic']
22
+ @callback = params['hub.callback']
23
+ end
24
+
25
+ def valid?
26
+ @valid ||= begin
27
+ validate_mode
28
+ validate_topic
29
+ validate_callback
30
+ errors.empty?
31
+ end
32
+ end
33
+
34
+ def errors
35
+ @errors ||= []
36
+ end
37
+
38
+ def error_messages
39
+ errors.map {|e| "hub.#{e[0]} #{e[1]}" }
40
+ end
41
+
42
+ def save
43
+ valid? and self.class.push(self)
44
+ end
45
+
46
+ def to_hash
47
+ [:mode, :topic, :callback].inject({}) do |hash, attr|
48
+ hash["hub.#{attr}"] = instance_variable_get(:"@#{attr}")
49
+ hash
50
+ end
51
+ end
52
+
53
+ def to_json
54
+ Oj.dump(to_hash)
55
+ end
56
+
57
+ def ==(other)
58
+ to_hash == other.to_hash
59
+ end
60
+
61
+ def verify
62
+ challenge = Challenge.new
63
+ params = to_hash
64
+ params['hub.challenge'] = challenge
65
+ uri = Addressable::URI.parse(@callback)
66
+ uri.query = URI.encode_www_form(params)
67
+ response = Net::HTTP.get_response(uri)
68
+ response.code == "200" && response.body == challenge
69
+ end
70
+
71
+ def perform
72
+ subscription = Subscription.new(topic: @topic, callback: @callback)
73
+ case @mode
74
+ when 'subscribe'
75
+ subscription.save
76
+ when 'unsubscribe'
77
+ subscription.destroy
78
+ end
79
+ end
80
+
81
+ def process
82
+ verify and perform
83
+ end
84
+
85
+ private
86
+
87
+ def validate_mode
88
+ @mode or errors << [:mode, 'must be present']
89
+ in_list = MODES.include?(@mode)
90
+ in_list or errors << [:mode, "must be either #{MODES.join(' or ')}"]
91
+ end
92
+
93
+ def validate_topic
94
+ @topic or errors << [:topic, 'must be present']
95
+ end
96
+
97
+ def validate_callback
98
+ @callback or errors << [:callback, 'must be present']
99
+ uri = Addressable::URI.parse(@callback)
100
+ uri and %w(http https).include? uri.scheme or fail Addressable::URI::InvalidURIError
101
+ rescue Addressable::URI::InvalidURIError
102
+ errors << [:callback, 'must be a valid http url']
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,33 @@
1
+ require "celluloid/io"
2
+
3
+ module Zulu
4
+ class SubscriptionRequestProcessor
5
+ include Celluloid::IO
6
+ include Celluloid::Logger
7
+
8
+ finalizer :shutdown
9
+
10
+ def initialize
11
+ debug "Request Processor starting up"
12
+ end
13
+
14
+ def process
15
+ debug "Looking for a subscription request"
16
+ request = SubscriptionRequest.pop(1)
17
+ if request
18
+ debug "Request found. Processing..."
19
+ request.process
20
+ end
21
+ async.reprocess
22
+ end
23
+
24
+ def reprocess
25
+ debug "Reprocessing..."
26
+ after(0) { process }
27
+ end
28
+
29
+ def shutdown
30
+ debug "Request Processor shutting down"
31
+ end
32
+ end
33
+ end
data/lib/zulu/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zulu
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,6 +1,14 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require 'zulu'
3
- require 'rack/test'
2
+
4
3
 
5
4
  require 'minitest/autorun'
6
- require 'minitest/english/deny'
5
+ require 'minitest/pride'
6
+ require 'minitest/english/deny'
7
+ require 'rack/test'
8
+ require "webmock/minitest"
9
+
10
+ require 'celluloid/autostart'
11
+ require 'zulu'
12
+
13
+ Celluloid.logger = nil
14
+
@@ -0,0 +1,18 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestChallenge < MiniTest::Test
4
+ include Zulu
5
+
6
+ def test_it_returns_24_characters_by_default
7
+ assert_equal 24, Challenge.new.length
8
+ end
9
+
10
+ def test_it_allows_arbitrary_size
11
+ assert_equal 12, Challenge.new(12).length
12
+ end
13
+
14
+ def test_it_produces_appropriate_string
15
+ assert_match /[a-zA-Z0-9]/, Challenge.new
16
+ end
17
+
18
+ end
data/test/test_server.rb CHANGED
@@ -8,6 +8,10 @@ class TestServer < MiniTest::Test
8
8
  Server
9
9
  end
10
10
 
11
+ def teardown
12
+ Zulu.redis.flushall
13
+ end
14
+
11
15
  def subscribe_options(opts={})
12
16
  {
13
17
  'hub.mode' => 'subscribe',
@@ -16,11 +20,28 @@ class TestServer < MiniTest::Test
16
20
  }.merge(opts)
17
21
  end
18
22
 
23
+ def test_it_renders_current_time_on_get
24
+ now = Time.now.utc
25
+ get '/'
26
+ assert_equal now.xmlschema, last_response.body
27
+ end
28
+
19
29
  def test_it_accepts_subscription_request
20
30
  post '/', subscribe_options
21
31
  assert_equal 202, last_response.status, last_response.body
22
32
  end
23
33
 
34
+ def test_it_errors_if_save_fails
35
+ post '/', subscribe_options('hub.mode' => 'dance')
36
+ assert_equal 400, last_response.status, last_response.body
37
+ end
38
+
39
+ def test_it_displays_errors_if_save_fails
40
+ post '/', subscribe_options('hub.mode' => nil)
41
+ errs = "hub.mode must be present\nhub.mode must be either subscribe or unsubscribe"
42
+ assert_equal errs, last_response.body
43
+ end
44
+
24
45
  def test_it_wont_accept_incorrect_format
25
46
  post '/', '', 'CONTENT_TYPE' => 'application/rss+xml'
26
47
  assert_equal 406, last_response.status
@@ -0,0 +1,50 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestSubscription < MiniTest::Test
4
+ include Zulu
5
+
6
+ def teardown
7
+ Zulu.redis.flushall
8
+ end
9
+
10
+ def subscription_id
11
+ '3a2d38ef403d8f494988a9e1513e7ce0'
12
+ end
13
+
14
+ def subscription_callback
15
+ 'http://www.example.org/callback'
16
+ end
17
+
18
+ def subscription_options_without_id
19
+ {
20
+ topic: '*/15 * * * *',
21
+ callback: subscription_callback
22
+ }
23
+ end
24
+
25
+ def test_it_generates_an_id_for_topic_and_callback
26
+ subscription = Subscription.new(subscription_options_without_id)
27
+ assert_equal subscription_id, subscription.id
28
+ end
29
+
30
+ def test_it_stores_callback_on_save
31
+ subscription = Subscription.new(subscription_options_without_id)
32
+ subscription.save
33
+ callback = Zulu.redis.get "#{Subscription::KEY_PREFIX}:#{subscription_id}:callback"
34
+ assert_equal subscription_callback, callback
35
+ end
36
+
37
+ def test_it_retrieves_callback_for_id
38
+ Subscription.new(subscription_options_without_id).save
39
+ callback = Subscription.new(id: subscription_id).callback
40
+ assert_equal subscription_callback, callback
41
+ end
42
+
43
+ def test_it_removes_callback_on_destroy
44
+ subscription = Subscription.new(subscription_options_without_id)
45
+ subscription.save
46
+ subscription.destroy
47
+ assert_nil Zulu.redis.get "#{Subscription::KEY_PREFIX}:#{subscription_id}:callback"
48
+ end
49
+
50
+ end
@@ -0,0 +1,208 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestSubscriptionRequest < MiniTest::Test
4
+ include Zulu
5
+
6
+ def teardown
7
+ Zulu.redis.flushall
8
+ WebMock.reset!
9
+ end
10
+
11
+ def subscribe_options(opts={})
12
+ {
13
+ 'hub.mode' => 'subscribe',
14
+ 'hub.topic' => '*/15 * * * *',
15
+ 'hub.callback' => 'http://www.example.org/callback'
16
+ }.merge(opts)
17
+ end
18
+
19
+ def subscribe_request(opts={})
20
+ SubscriptionRequest.new(subscribe_options(opts))
21
+ end
22
+
23
+ def test_it_pops_the_next_request
24
+ request = subscribe_request
25
+ request.save
26
+ assert_equal request, SubscriptionRequest.pop
27
+ end
28
+
29
+ def test_it_accepts_timeout_for_pop
30
+ mock = MiniTest::Mock.new
31
+ mock.expect(:brpop, nil, [SubscriptionRequest::LIST, timeout: 5])
32
+ Zulu.stub(:redis, mock) do
33
+ SubscriptionRequest.pop(5)
34
+ end
35
+ mock.verify
36
+ end
37
+
38
+ def test_it_is_valid_with_subscribe
39
+ assert subscribe_request.valid?
40
+ end
41
+
42
+ def test_it_is_valid_with_unsubscribe
43
+ assert subscribe_request('hub.mode' => 'unsubscribe').valid?
44
+ end
45
+
46
+ def test_it_is_not_valid_with_missing_mode
47
+ deny subscribe_request('hub.mode' => nil).valid?
48
+ end
49
+
50
+ def test_it_has_error_with_missing_mode
51
+ request = subscribe_request('hub.mode' => nil)
52
+ request.valid?
53
+ assert_includes request.errors, [:mode, 'must be present']
54
+ end
55
+
56
+ def test_it_is_not_valid_with_wrong_mode
57
+ deny subscribe_request('hub.mode' => 'dance').valid?
58
+ end
59
+
60
+ def test_it_has_error_with_wrong_mode
61
+ request = subscribe_request('hub.mode' => 'dance')
62
+ request.valid?
63
+ assert_includes request.errors, [:mode, "must be either subscribe or unsubscribe"]
64
+ end
65
+
66
+ def test_it_is_not_valid_with_missing_topic
67
+ deny subscribe_request('hub.topic' => nil).valid?
68
+ end
69
+
70
+ def test_it_has_error_with_missing_topic
71
+ request = subscribe_request('hub.topic' => nil)
72
+ request.valid?
73
+ assert_includes request.errors, [:topic, 'must be present']
74
+ end
75
+
76
+ def test_it_is_not_valid_with_missing_callback
77
+ deny subscribe_request('hub.callback' => nil).valid?
78
+ end
79
+
80
+ def test_it_has_error_with_missing_callback
81
+ request = subscribe_request('hub.callback' => nil)
82
+ request.valid?
83
+ assert_includes request.errors, [:callback, 'must be present']
84
+ end
85
+
86
+ def test_it_is_not_valid_with_wrong_callback
87
+ deny subscribe_request('hub.callback' => '!?/#:-)').valid?
88
+ end
89
+
90
+ def test_it_has_error_with_wrong_callback
91
+ request = subscribe_request('hub.callback' => '!?/#:-)')
92
+ request.valid?
93
+ assert_includes request.errors, [:callback, "must be a valid http url"]
94
+ end
95
+
96
+ def test_it_contructs_proper_error_messages
97
+ request = subscribe_request('hub.callback' => nil)
98
+ request.valid?
99
+ assert_includes request.error_messages, 'hub.callback must be present'
100
+ end
101
+
102
+ def test_it_reconstructs_params
103
+ assert_equal subscribe_options, subscribe_request.to_hash
104
+ end
105
+
106
+ def test_it_converts_params_to_json
107
+ assert_equal Oj.dump(subscribe_options), subscribe_request.to_json
108
+ end
109
+
110
+ def test_it_adds_self_to_queue_on_save
111
+ request = subscribe_request
112
+ request.save
113
+ assert_equal request.to_json, Zulu.redis.rpop(SubscriptionRequest::LIST)
114
+ end
115
+
116
+ def test_it_does_not_add_self_to_queue_on_save
117
+ request = subscribe_request('hub.mode' => nil)
118
+ request.save
119
+ assert_nil Zulu.redis.rpop(SubscriptionRequest::LIST)
120
+ end
121
+
122
+ def test_it_passes_save_when_valid
123
+ request = subscribe_request
124
+ assert request.save
125
+ end
126
+
127
+ def test_it_fails_save_when_invalid
128
+ request = subscribe_request('hub.mode' => nil)
129
+ deny request.save
130
+ end
131
+
132
+ def test_it_requests_callback_on_verify
133
+ challenge = 'foobar'
134
+ request = subscribe_request
135
+ stub_get = stub_http_request(:get, "www.example.org/callback").
136
+ with(query: subscribe_options('hub.challenge' => challenge)).
137
+ to_return(body: challenge)
138
+ Challenge.stub(:new, challenge) do
139
+ request.verify
140
+ end
141
+ assert_requested stub_get
142
+ end
143
+
144
+ def test_it_passes_on_good_verify
145
+ challenge = 'foobar'
146
+ request = subscribe_request
147
+ stub_get = stub_http_request(:get, "www.example.org/callback").
148
+ with(query: subscribe_options('hub.challenge' => challenge)).
149
+ to_return(body: challenge)
150
+ Challenge.stub(:new, challenge) do
151
+ assert request.verify
152
+ end
153
+ end
154
+
155
+ def test_it_fails_on_bad_verify
156
+ stub_get = stub_http_request(:get, "www.example.org/callback").
157
+ with(query: hash_including(subscribe_options)).
158
+ to_return(status: [404, "Not Found"])
159
+ deny subscribe_request.verify
160
+ end
161
+
162
+ def test_it_creates_subscription_on_subscribe
163
+ mock = MiniTest::Mock.new
164
+ mock.expect(:save, true)
165
+ request = subscribe_request
166
+ request.stub(:verify, true) do
167
+ Subscription.stub(:new, mock) do
168
+ request.process
169
+ end
170
+ end
171
+ mock.verify
172
+ end
173
+
174
+ def test_it_does_not_create_subscription_if_verify_fails
175
+ mock = MiniTest::Mock.new
176
+ request = subscribe_request
177
+ request.stub(:verify, false) do
178
+ Subscription.stub(:new, mock) do
179
+ request.process
180
+ end
181
+ end
182
+ mock.verify
183
+ end
184
+
185
+ def test_it_destroys_subscription_on_unsubscribe
186
+ mock = MiniTest::Mock.new
187
+ mock.expect(:destroy, true)
188
+ request = subscribe_request('hub.mode' => 'unsubscribe')
189
+ request.stub(:verify, true) do
190
+ Subscription.stub(:new, mock) do
191
+ request.process
192
+ end
193
+ end
194
+ mock.verify
195
+ end
196
+
197
+ def test_it_does_not_destroy_subscription_if_verify_fails
198
+ mock = MiniTest::Mock.new
199
+ request = subscribe_request('hub.mode' => 'unsubscribe')
200
+ request.stub(:verify, false) do
201
+ Subscription.stub(:new, mock) do
202
+ request.process
203
+ end
204
+ end
205
+ mock.verify
206
+ end
207
+
208
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestSubscriptionRequestProcessor < MiniTest::Test
4
+ include Zulu
5
+
6
+ def teardown
7
+ Zulu.redis.flushall
8
+ WebMock.reset!
9
+ end
10
+
11
+ def test_it_processes_request
12
+ processor = SubscriptionRequestProcessor.new
13
+
14
+ request_mock = MiniTest::Mock.new
15
+ request_mock.expect(:process, true)
16
+
17
+ SubscriptionRequest.stub(:pop, request_mock) do
18
+ processor.stub(:reprocess, true) do
19
+ processor.process
20
+ end
21
+ end
22
+
23
+ request_mock.verify
24
+ end
25
+ end
data/test/test_zulu.rb CHANGED
@@ -30,7 +30,7 @@ class TestZulu < MiniTest::Test
30
30
  end
31
31
 
32
32
  def test_it_has_default_option_for_database
33
- assert_equal 'localhost:6379', Zulu.options[:database]
33
+ assert_equal "redis://127.0.0.1:6379", Zulu.options[:database]
34
34
  end
35
35
 
36
36
  def test_it_has_default_option_for_keeper
@@ -58,8 +58,8 @@ class TestZulu < MiniTest::Test
58
58
  end
59
59
 
60
60
  def test_it_accepts_option_for_database
61
- Zulu.parse_options(['-d localhost:9000'])
62
- assert_equal 'localhost:9000', Zulu.options[:database]
61
+ Zulu.parse_options(['-d redis://localhost:9000'])
62
+ assert_equal 'redis://localhost:9000', Zulu.options[:database]
63
63
  end
64
64
 
65
65
  def test_it_accepts_option_for_keeper
@@ -75,7 +75,11 @@ class TestZulu < MiniTest::Test
75
75
  end
76
76
 
77
77
  #
78
- # Zulu.run
78
+ # Zulu.redis
79
79
  #
80
80
 
81
+ def test_it_creates_redis_connection
82
+ assert_kind_of Redis, Zulu.redis
83
+ end
84
+
81
85
  end
data/zulu.gemspec CHANGED
@@ -18,13 +18,18 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "slop", "~> 3.4.6"
22
- spec.add_runtime_dependency "sinatra", "~> 1.4.3"
23
- spec.add_runtime_dependency "reel", "~> 0.3.0"
21
+ spec.add_dependency "slop", "~> 3.4.6"
22
+ spec.add_dependency "sinatra", "~> 1.4.3"
23
+ spec.add_dependency "celluloid-io", "~> 0.14.1"
24
+ spec.add_dependency "reel", "~> 0.3.0"
25
+ spec.add_dependency "celluloid-redis", "~> 0.0.2"
26
+ spec.add_dependency "oj", "~> 2.1.4"
27
+ spec.add_dependency "addressable", "~> 2.3.5"
24
28
 
25
29
  spec.add_development_dependency "bundler", "~> 1.3"
26
30
  spec.add_development_dependency "rake"
27
31
  spec.add_development_dependency "minitest", "~> 5.0.6"
28
32
  spec.add_development_dependency "minitest-english", "~> 0.1.0"
29
33
  spec.add_development_dependency "rack-test", "~> 0.6.2"
34
+ spec.add_development_dependency "webmock", "~> 1.13.0"
30
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zulu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Weinand
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-23 00:00:00.000000000 Z
11
+ date: 2013-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.4.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: celluloid-io
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.14.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.14.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: reel
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,48 @@ dependencies:
52
66
  - - ~>
53
67
  - !ruby/object:Gem::Version
54
68
  version: 0.3.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: celluloid-redis
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: oj
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 2.1.4
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 2.1.4
97
+ - !ruby/object:Gem::Dependency
98
+ name: addressable
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 2.3.5
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 2.3.5
55
111
  - !ruby/object:Gem::Dependency
56
112
  name: bundler
57
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +178,20 @@ dependencies:
122
178
  - - ~>
123
179
  - !ruby/object:Gem::Version
124
180
  version: 0.6.2
181
+ - !ruby/object:Gem::Dependency
182
+ name: webmock
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ~>
186
+ - !ruby/object:Gem::Version
187
+ version: 1.13.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ~>
193
+ - !ruby/object:Gem::Version
194
+ version: 1.13.0
125
195
  description: A standalone PuSH-inspired service for scheduling web hook execution
126
196
  email:
127
197
  - dweinand@gmail.com
@@ -138,10 +208,18 @@ files:
138
208
  - Rakefile
139
209
  - bin/zulu
140
210
  - lib/zulu.rb
211
+ - lib/zulu/challenge.rb
141
212
  - lib/zulu/server.rb
213
+ - lib/zulu/subscription.rb
214
+ - lib/zulu/subscription_request.rb
215
+ - lib/zulu/subscription_request_processor.rb
142
216
  - lib/zulu/version.rb
143
217
  - test/minitest_helper.rb
218
+ - test/test_challenge.rb
144
219
  - test/test_server.rb
220
+ - test/test_subscription.rb
221
+ - test/test_subscription_request.rb
222
+ - test/test_subscription_request_processor.rb
145
223
  - test/test_zulu.rb
146
224
  - zulu.gemspec
147
225
  homepage: ''
@@ -170,5 +248,9 @@ specification_version: 4
170
248
  summary: PuSH-inspired web hook scheduler
171
249
  test_files:
172
250
  - test/minitest_helper.rb
251
+ - test/test_challenge.rb
173
252
  - test/test_server.rb
253
+ - test/test_subscription.rb
254
+ - test/test_subscription_request.rb
255
+ - test/test_subscription_request_processor.rb
174
256
  - test/test_zulu.rb