zulu 0.0.2 → 0.0.3

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