chasqui 0.8.0 → 0.9.0

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: f308ee6114cf27680f344bbb770e4eeee946f467
4
- data.tar.gz: 749dbc74254f92306c8204f799a99d54d5e83017
3
+ metadata.gz: fb1a85b1db2129a864d5c04845365d0d27ee155a
4
+ data.tar.gz: 6391c76b1ab99c388d37d7db0292f524baf14f11
5
5
  SHA512:
6
- metadata.gz: a9fe9a92bba7c1be6ef419fae3f0adbb3db94010b966773b5b32d127a5e43302a6b01bb522f33b0bfd4d291fe389d2da47576a9197cd93a172fdadff875e519b
7
- data.tar.gz: f7957a3fd5ea629fcb5ac05f5cb80a1d8231385ee7dddf1f8b8dd9a349be580a3b5a1e7908be04ae21be682b9d84af4fd3433ab92b3199b02a348059c1b47803
6
+ metadata.gz: 843753b80abeea5ec7e101dd74208ff14a159f69ca15d77673bc0354e47f85e31c473278209d9a4535eaf674bc37e3522a2cdb5d786e23eea67188220bd39c7d
7
+ data.tar.gz: e4fe21a58162022da38d9a0e897879f2cf6ac73f8eb1fb54a3807952b0fda0b02ce89869d1fd5bc1af446186ec7ed3fa82635c6c6e01c9851bf65b939d446ad1
data/.travis.yml CHANGED
@@ -4,3 +4,6 @@ services:
4
4
  rvm:
5
5
  - 2.2.2
6
6
  - 1.9.3
7
+ addons:
8
+ code_climate:
9
+ repo_token: 6097f1f853daed3be96340594c273d2c5d921d860a9c21ecbc7e5f7a1ba90f43
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  [![Build Status](https://travis-ci.org/jbgo/chasqui.svg?branch=master)](https://travis-ci.org/jbgo/chasqui)
2
+ [![Code Climate](https://codeclimate.com/github/jbgo/chasqui/badges/gpa.svg)](https://codeclimate.com/github/jbgo/chasqui)
3
+ [![Test Coverage](https://codeclimate.com/github/jbgo/chasqui/badges/coverage.svg)](https://codeclimate.com/github/jbgo/chasqui/coverage)
2
4
 
3
5
  # Chasqui
4
6
 
@@ -86,7 +88,7 @@ Now when you call `Chasqui.publish 'event.name', data, ...`, Chasqui will publis
86
88
 
87
89
  ```rb
88
90
  # file: otherapp/app/subscribers/user_events.rb
89
- Chasqui.subscribe queue: 'unique_queue_name_for_app', channel: 'com.example.myapp' do
91
+ Chasqui.subscribe 'com.example.myapp', queue: 'unique_queue_name_for_app' do
90
92
 
91
93
  on 'user.sign-up' do |user_id|
92
94
  user = User.find user_id
data/chasqui.gemspec CHANGED
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "guard-rspec"
27
27
  spec.add_development_dependency "resque"
28
28
  spec.add_development_dependency "sidekiq"
29
+ spec.add_development_dependency "codeclimate-test-reporter"
29
30
  end
data/examples/full.rb CHANGED
@@ -28,7 +28,7 @@ Chasqui.configure do |config|
28
28
  end
29
29
 
30
30
  # file: transcoder/app/subscribers/video_subscriber.rb
31
- Chasqui.subscribe queue: 'transcoder.video', channel: 'com.example.admin' do
31
+ Chasqui.subscribe 'com.example.admin', queue: 'transcoder.video' do
32
32
  on 'video.upload' do |video_id|
33
33
  begin
34
34
  Transcorder.transcode video_url(video_id)
@@ -41,7 +41,7 @@ Chasqui.subscribe queue: 'transcoder.video', channel: 'com.example.admin' do
41
41
  end
42
42
 
43
43
  # file: admin/app/subscribers/video_subscriber.rb
44
- Chasqui.subscribe queue: 'admin.events', channel: 'com.example.transcoder' do
44
+ Chasqui.subscribe 'com.example.transcoder', queue: 'admin.events' do
45
45
 
46
46
  on 'transcoder.video.complete' do |video_id|
47
47
  video = Video.find video_id
@@ -1,12 +1,14 @@
1
+ require 'securerandom'
2
+
1
3
  class Chasqui::MultiBroker < Chasqui::Broker
2
4
 
3
5
  def forward_event
4
6
  event = receive or return
5
- subscribers = subscribers_for(event)
7
+ subscriptions = subscriptions_for(event)
6
8
 
7
9
  redis.multi do
8
- subscribers.each do |subscriber_id|
9
- dispatch event, subscriber_id
10
+ subscriptions.each do |subscription_id|
11
+ dispatch event, subscription_id
10
12
  end
11
13
  redis.rpop(in_progress_queue)
12
14
  end
@@ -15,11 +17,23 @@ class Chasqui::MultiBroker < Chasqui::Broker
15
17
  end
16
18
 
17
19
  def in_progress_queue
18
- to_key inbox, 'in_progress'
20
+ with_namespace inbox, 'in_progress'
19
21
  end
20
22
 
21
23
  def inbox_queue
22
- to_key inbox
24
+ with_namespace inbox
25
+ end
26
+
27
+ def build_job(queue, event)
28
+ {
29
+ class: "Chasqui::#{Chasqui.subscriber_class_name(queue)}",
30
+ args: [event],
31
+ queue: 'my-queue',
32
+ jid: SecureRandom.hex(12),
33
+ created_at: (event['created_at'] || Time.now).to_f,
34
+ enqueued_at: Time.now.to_f,
35
+ retry: !!event['retry']
36
+ }.to_json
23
37
  end
24
38
 
25
39
  private
@@ -50,8 +64,8 @@ class Chasqui::MultiBroker < Chasqui::Broker
50
64
  end
51
65
  end
52
66
 
53
- def dispatch(event, subscriber_id)
54
- backend, queue = subscriber_id.split('/', 2)
67
+ def dispatch(event, subscription_id)
68
+ backend, queue = subscription_id.split('/', 2)
55
69
  job = build_job queue, event
56
70
 
57
71
  logger.debug "dispatching event queue=#{queue} backend=#{backend} job=#{job}"
@@ -64,18 +78,12 @@ class Chasqui::MultiBroker < Chasqui::Broker
64
78
  end
65
79
  end
66
80
 
67
- def build_job(queue, event)
68
- {
69
- class: "Chasqui::#{Chasqui.subscriber_class_name(queue)}",
70
- args: [event]
71
- }.to_json
72
- end
73
-
74
- def subscribers_for(event)
75
- redis.smembers to_key('subscribers', event['channel'])
81
+ def subscriptions_for(event)
82
+ subscription_key = Chasqui.subscription_key event['channel']
83
+ redis.smembers with_namespace(subscription_key)
76
84
  end
77
85
 
78
- def to_key(*args)
86
+ def with_namespace(*args)
79
87
  ([redis_namespace] + args).join(':')
80
88
  end
81
89
 
@@ -0,0 +1,46 @@
1
+ module Chasqui
2
+ class Subscription
3
+ attr_reader :queue, :channel, :subscriber_type
4
+
5
+ def initialize(queue, channel, subscriber_type=Chasqui::Subscriber)
6
+ @queue = queue
7
+ @channel = channel
8
+ @subscriber_type = subscriber_type
9
+ end
10
+
11
+ def subscription_id
12
+ queue_name = [worker.namespace, 'queue', queue].compact.join(':')
13
+ "#{worker_backend}/#{queue_name}"
14
+ end
15
+
16
+ def subscriber
17
+ @subscriber ||= subscriber_type.new queue, channel
18
+ end
19
+
20
+ def worker
21
+ # TODO How can we store this in an instance variable without breaking things?
22
+ case worker_backend
23
+ when :resque
24
+ Chasqui::ResqueWorker.create subscriber
25
+ when :sidekiq
26
+ Chasqui::SidekiqWorker.create subscriber
27
+ else
28
+ raise ConfigurationError.new(
29
+ "Please choose a supported worker_backend. Choices: #{supported_worker_backends}")
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def worker_backend
36
+ Chasqui.config.worker_backend
37
+ end
38
+
39
+ SUPPORTED_WORKER_BACKENDS = [:resque, :sidekiq].freeze
40
+
41
+ def supported_worker_backends
42
+ SUPPORTED_WORKER_BACKENDS.join(', ')
43
+ end
44
+
45
+ end
46
+ end
@@ -1,3 +1,3 @@
1
1
  module Chasqui
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/chasqui.rb CHANGED
@@ -9,6 +9,7 @@ require "chasqui/config"
9
9
  require "chasqui/broker"
10
10
  require "chasqui/multi_broker"
11
11
  require "chasqui/subscriber"
12
+ require "chasqui/subscription"
12
13
  require "chasqui/workers/worker"
13
14
  require "chasqui/workers/resque_worker"
14
15
  require "chasqui/workers/sidekiq_worker"
@@ -28,23 +29,30 @@ module Chasqui
28
29
  end
29
30
 
30
31
  def publish(event, *args)
31
- payload = { event: event, channel: channel, data: args }
32
- redis.lpush inbox_queue, payload.to_json
32
+ redis.lpush inbox_queue, build_payload(event, *args).to_json
33
+ end
34
+
35
+ def subscribe(channel, options={}, &block)
36
+ queue = options.fetch :queue
37
+
38
+ create_subscription(queue, channel).tap do |subscription|
39
+ subscription.subscriber.evaluate(&block) if block_given?
40
+ redis.sadd subscription_key(channel), subscription.subscription_id
41
+ end
33
42
  end
34
43
 
35
- def subscribe(options={}, &block)
44
+ def unsubscribe(channel, options={}, &block)
36
45
  queue = options.fetch :queue
37
- channel = options.fetch :channel
46
+ subscription = subscriptions[queue.to_s]
38
47
 
39
- register_subscriber(queue, channel).tap do |sub|
40
- sub.evaluate(&block) if block_given?
41
- worker = create_worker(sub)
42
- redis.sadd "subscribers:#{channel}", subscriber_id(worker, queue)
48
+ if subscription
49
+ redis.srem subscription_key(channel), subscription.subscription_id
50
+ subscription.subscription_id
43
51
  end
44
52
  end
45
53
 
46
- def subscriber(queue)
47
- subscribers[queue.to_s]
54
+ def subscription(queue)
55
+ subscriptions[queue.to_s]
48
56
  end
49
57
 
50
58
  def subscriber_class_name(queue)
@@ -52,37 +60,34 @@ module Chasqui
52
60
  "Subscriber__#{queue_name_constant}".to_sym
53
61
  end
54
62
 
55
- def create_worker(subscriber)
56
- case config.worker_backend
57
- when :resque
58
- Chasqui::ResqueWorker.create subscriber
59
- when :sidekiq
60
- Chasqui::SidekiqWorker.create subscriber
61
- else
62
- raise ConfigurationError.new(
63
- "Please choose a supported worker_backend. Choices: #{supported_worker_backends}")
64
- end
63
+ def subscription_key(channel)
64
+ "subscriptions:#{channel}"
65
65
  end
66
66
 
67
67
  private
68
68
 
69
- def subscriber_id(worker, queue)
70
- queue_name = [worker.namespace, 'queue', queue].compact.join(':')
71
- "#{config.worker_backend}/#{queue_name}"
69
+ def create_subscription(queue, channel)
70
+ subscriptions[queue.to_s] ||= Subscription.new queue, channel
72
71
  end
73
72
 
74
- def register_subscriber(queue, channel)
75
- subscribers[queue.to_s] ||= Subscriber.new queue, channel
73
+ def subscriptions
74
+ @subscriptions ||= {}
76
75
  end
77
76
 
78
- def subscribers
79
- @subscribers ||= {}
80
- end
77
+ def build_payload(event, *args)
78
+ opts = extract_job_options!(*args)
79
+
80
+ payload = { event: event, channel: channel, data: args }
81
+ payload[:retry] = opts[:retry] || opts['retry'] if opts
82
+ payload[:created_at] = Time.now.to_f.to_s
81
83
 
82
- SUPPORTED_WORKER_BACKENDS = [:resque, :sidekiq].freeze
84
+ payload
85
+ end
83
86
 
84
- def supported_worker_backends
85
- SUPPORTED_WORKER_BACKENDS.join(', ')
87
+ def extract_job_options!(*args)
88
+ if args.last.kind_of?(Hash)
89
+ args.last.delete(:job_options)
90
+ end
86
91
  end
87
92
  end
88
93
  end
@@ -4,11 +4,11 @@ def log_event subscriber, args
4
4
  subscriber.redis.rpush "#{subscriber.queue}:event_log", payload
5
5
  end
6
6
 
7
- Chasqui.subscribe queue: 'app1', channel: 'integration' do
7
+ Chasqui.subscribe 'integration', queue: 'app1' do
8
8
  on('user.signup') { |*args| log_event self, args }
9
9
  end
10
10
 
11
- Chasqui.subscribe queue: 'app2', channel: 'integration' do
11
+ Chasqui.subscribe 'integration', queue: 'app2' do
12
12
  on('account.*') { |*args| log_event self, args }
13
13
  on('user.cancel') { |*args| log_event self, args }
14
14
  end
@@ -7,14 +7,15 @@ describe Chasqui::MultiBroker do
7
7
  reset_chasqui
8
8
  Chasqui.config.worker_backend = :resque
9
9
  Resque.redis.namespace = nil
10
+ allow(Time).to receive(:now).and_return(Time.now)
10
11
  end
11
12
 
12
13
  describe '#forward_event' do
13
14
  before do
14
15
  Chasqui.config.channel = 'app1'
15
- Chasqui.subscribe queue: 'queue1', channel: 'app1'
16
- Chasqui.subscribe queue: 'queue2', channel: 'app2'
17
- Chasqui.subscribe queue: 'queue3', channel: 'app1'
16
+ Chasqui.subscribe 'app1', queue: 'queue1'
17
+ Chasqui.subscribe 'app2', queue: 'queue2'
18
+ Chasqui.subscribe 'app1', queue: 'queue3'
18
19
  end
19
20
 
20
21
  it 'places the event on all subscriber queues' do
@@ -27,7 +28,7 @@ describe Chasqui::MultiBroker do
27
28
  expect(nnredis.llen('queue:queue2')).to eq(0)
28
29
  expect(nnredis.llen('queue:queue3')).to eq(1)
29
30
 
30
- event = { 'event' => 'foo.bar', 'channel' => 'app1', 'data' => ['A'] }
31
+ event = { 'event' => 'foo.bar', 'channel' => 'app1', 'data' => ['A'], 'created_at' => Time.now.to_f.to_s }
31
32
 
32
33
  job1 = JSON.parse nnredis.lpop('queue:queue1')
33
34
  expect(job1['args']).to include(event)
@@ -48,7 +49,7 @@ describe Chasqui::MultiBroker do
48
49
  job = JSON.parse nnredis.blpop('queue:queue2')[1]
49
50
  expect(job).to include('class' => 'Chasqui::Subscriber__queue2')
50
51
  expect(job).to include('args' =>
51
- [{ 'event' => 'foo.bar', 'channel' => 'app2', 'data' => ['A'] }])
52
+ [{ 'event' => 'foo.bar', 'channel' => 'app2', 'data' => ['A'], 'created_at' => Time.now.to_f.to_s }])
52
53
  end
53
54
  ensure
54
55
  thread.kill
@@ -71,7 +72,7 @@ describe Chasqui::MultiBroker do
71
72
 
72
73
  job = JSON.parse nnredis.lpop('queue:queue2')
73
74
  expect(job['args']).to include(
74
- 'event' => 'foo', 'channel' => 'app2', 'data' => ['process'])
75
+ 'event' => 'foo', 'channel' => 'app2', 'data' => ['process'], 'created_at' => Time.now.to_f.to_s)
75
76
  expect(nnredis.llen(broker.in_progress_queue)).to eq(0)
76
77
  end
77
78
 
@@ -80,4 +81,36 @@ describe Chasqui::MultiBroker do
80
81
  expect(-> { broker.forward_event }).not_to raise_error
81
82
  end
82
83
  end
84
+
85
+ describe '#build_job' do
86
+ it 'includes useful metadata' do
87
+ event = { 'event' => 'foo', 'channel' => 'bar', 'data' => [] }
88
+ job = JSON.parse broker.build_job('my-queue', event)
89
+
90
+ expect(job['class']).to eq('Chasqui::Subscriber__my_queue')
91
+ expect(job['args']).to include(event)
92
+ expect(job['queue']).to eq('my-queue')
93
+ expect(job['jid']).to match(/^[0-9a-f]{24}/i)
94
+ expect(job['created_at']).to be_within(0.01).of(Time.now.to_f)
95
+ expect(job['enqueued_at']).to be_within(0.01).of(Time.now.to_f)
96
+ expect(job['retry']).to eq(false)
97
+ end
98
+
99
+ it 'uses the event created_at time' do
100
+ created_at = (Time.now - 3).to_f
101
+ job = JSON.parse broker.build_job('my-queue', 'created_at' => created_at.to_s)
102
+ expect(job['created_at']).to eq(created_at)
103
+ end
104
+
105
+ it 'uses the event retry value' do
106
+ job = JSON.parse broker.build_job('my-queue', 'retry' => true)
107
+ expect(job['retry']).to be true
108
+
109
+ job = JSON.parse broker.build_job('my-queue', 'retry' => false)
110
+ expect(job['retry']).to be false
111
+
112
+ job = JSON.parse broker.build_job('my-queue', 'retry' => nil)
113
+ expect(job['retry']).to be false
114
+ end
115
+ end
83
116
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chasqui::Subscription do
4
+
5
+ def new_subscription(queue='default')
6
+ Chasqui::Subscription.new queue, 'fake-channel', FakeSubscriber
7
+ end
8
+
9
+ describe '#worker' do
10
+ it 'raises when no worker backend configured' do
11
+ Chasqui.config.worker_backend = nil
12
+ expect(-> {
13
+ new_subscription.worker
14
+ }).to raise_error(Chasqui::ConfigurationError)
15
+ end
16
+
17
+ it 'creates a resque worker' do
18
+ Chasqui.config.worker_backend = :resque
19
+ worker = new_subscription('resque-queue').worker
20
+ expect(worker.new).to be_kind_of(Chasqui::ResqueWorker)
21
+ end
22
+
23
+ if sidekiq_supported_ruby_version?
24
+ it 'creates a sidekiq worker' do
25
+ Chasqui.config.worker_backend = :sidekiq
26
+ worker = new_subscription('sidekiq-queue').worker
27
+ expect(worker.new).to be_kind_of(Chasqui::SidekiqWorker)
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -111,6 +111,7 @@ describe Chasqui do
111
111
  expect(event['event']).to eq('test.event')
112
112
  expect(event['channel']).to eq('__default')
113
113
  expect(event['data']).to eq(data)
114
+ expect(event['created_at'].to_f).to be_within(0.01).of(Time.now.to_f)
114
115
  end
115
116
  end
116
117
 
@@ -122,31 +123,11 @@ describe Chasqui do
122
123
  expect(event['channel']).to eq('my.app')
123
124
  expect(event['data']).to eq(['foo'])
124
125
  end
125
- end
126
-
127
- describe '.create_worker' do
128
- let(:subscriber) { j }
129
-
130
- it 'raises when no worker backend configured' do
131
- expect(-> {
132
- Chasqui.create_worker nil
133
- }).to raise_error(Chasqui::ConfigurationError)
134
- end
135
-
136
- it 'creates a resque worker' do
137
- subscriber = FakeSubscriber.new 'resque-queue', 'fake-channel'
138
- Chasqui.config.worker_backend = :resque
139
- worker = Chasqui.create_worker subscriber
140
- expect(worker.new).to be_kind_of(Chasqui::ResqueWorker)
141
- end
142
126
 
143
- if sidekiq_supported_ruby_version?
144
- it 'creates a sidekiq worker' do
145
- subscriber = FakeSubscriber.new 'sidekiq-queue', 'fake-channel'
146
- Chasqui.config.worker_backend = :sidekiq
147
- worker = Chasqui.create_worker subscriber
148
- expect(worker.new).to be_kind_of(Chasqui::SidekiqWorker)
149
- end
127
+ it 'supports retries' do
128
+ Chasqui.publish 'test.event', :foo, :bar, foo: 'bar', job_options: { retry: true }
129
+ event = JSON.load Chasqui.redis.rpop('inbox')
130
+ expect(event['retry']).to eq(true)
150
131
  end
151
132
  end
152
133
 
@@ -160,18 +141,18 @@ describe Chasqui do
160
141
  before { Resque.redis.namespace = 'blah' }
161
142
 
162
143
  it 'creates subscriptions using the appropriate redis namespace' do
163
- sub1 = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
164
- sub2 = Chasqui.subscribe queue: 'app2-queue', channel: 'com.example.admin'
165
- sub3 = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.video'
144
+ sub1 = Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
145
+ sub2 = Chasqui.subscribe 'com.example.admin', queue: 'app2-queue'
146
+ sub3 = Chasqui.subscribe 'com.example.video', queue: 'app1-queue'
166
147
 
167
- queues = Chasqui.redis.smembers "subscribers:com.example.admin"
148
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
168
149
  expect(queues.sort).to eq(['resque/blah:queue:app1-queue', 'resque/blah:queue:app2-queue'])
169
150
 
170
- queues = Chasqui.redis.smembers "subscribers:com.example.video"
151
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.video")
171
152
  expect(queues).to eq(['resque/blah:queue:app1-queue'])
172
153
 
173
- expect(Chasqui.subscriber('app1-queue')).to eq(sub1)
174
- expect(Chasqui.subscriber('app2-queue')).to eq(sub2)
154
+ expect(Chasqui.subscription('app1-queue')).to eq(sub1)
155
+ expect(Chasqui.subscription('app2-queue')).to eq(sub2)
175
156
  expect(sub1).to eq(sub3)
176
157
  end
177
158
  end
@@ -183,32 +164,55 @@ describe Chasqui do
183
164
  end
184
165
 
185
166
  it 'creates subscriptions using the appropriate redis namespace' do
186
- Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
187
- queues = Chasqui.redis.smembers "subscribers:com.example.admin"
167
+ Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
168
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
188
169
  expect(queues.sort).to eq(['sidekiq/queue:app1-queue'])
189
170
 
190
171
  Sidekiq.redis = { url: redis.client.options[:url], namespace: 'foobar' }
191
- Chasqui.subscribe queue: 'app2-queue', channel: 'com.example.video'
192
- queues = Chasqui.redis.smembers "subscribers:com.example.video"
172
+ Chasqui.subscribe 'com.example.video', queue: 'app2-queue'
173
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.video")
193
174
  expect(queues.sort).to eq(['sidekiq/foobar:queue:app2-queue'])
194
175
  end
195
176
  end
196
177
  end
197
178
 
198
- it 'returns a subscriber' do
199
- subscriber = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
200
- expect(subscriber).to be_kind_of(Chasqui::Subscriber)
179
+ it 'returns a subscription' do
180
+ subscription = Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
181
+ expect(subscription.subscriber).to be_kind_of(Chasqui::Subscriber)
201
182
  end
202
183
 
203
184
  it 'yields a subscriber configuration context' do
204
185
  $context = nil
205
- Chasqui.subscribe queue: 'foo', channel: 'bar' do
186
+ Chasqui.subscribe 'bar', queue: 'foo' do
206
187
  $context = self
207
188
  end
208
189
  expect($context).to be_kind_of(Chasqui::Subscriber)
209
190
  end
210
191
  end
211
192
 
193
+ describe '.unsubscribe' do
194
+ before do
195
+ reset_chasqui
196
+ Chasqui.config.worker_backend = :resque
197
+ Resque.redis.namespace = 'ns0'
198
+ Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
199
+ Chasqui.subscribe 'com.example.admin', queue: 'app2-queue'
200
+ Chasqui.subscribe 'com.example.video', queue: 'app1-queue'
201
+ end
202
+
203
+ it 'removes the subscription' do
204
+ subscription_id = Chasqui.unsubscribe 'com.example.admin', queue: 'app1-queue'
205
+ expect(subscription_id).to eq('resque/ns0:queue:app1-queue')
206
+ expect(redis.smembers(Chasqui.subscription_key 'com.example.admin').sort).to eq(['resque/ns0:queue:app2-queue'])
207
+ expect(redis.smembers(Chasqui.subscription_key 'com.example.video').sort).to eq(['resque/ns0:queue:app1-queue'])
208
+ end
209
+
210
+ it 'returns nil for unknown subscriptions' do
211
+ subscription_id = Chasqui.unsubscribe 'unknown', queue: 'unknown'
212
+ expect(subscription_id).to be nil
213
+ end
214
+ end
215
+
212
216
  describe '.subscriber_class_name' do
213
217
  it 'transforms queue name into a subscribe class name' do
214
218
  expect(Chasqui.subscriber_class_name('my-queue')).to eq(:Subscriber__my_queue)
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
1
4
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
5
  require 'chasqui'
3
6
  require 'resque'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chasqui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Bach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-01 00:00:00.000000000 Z
11
+ date: 2015-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: codeclimate-test-reporter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description:
126
140
  email:
127
141
  - jordan@opensolitude.com
@@ -147,6 +161,7 @@ files:
147
161
  - lib/chasqui/config.rb
148
162
  - lib/chasqui/multi_broker.rb
149
163
  - lib/chasqui/subscriber.rb
164
+ - lib/chasqui/subscription.rb
150
165
  - lib/chasqui/version.rb
151
166
  - lib/chasqui/workers/resque_worker.rb
152
167
  - lib/chasqui/workers/sidekiq_worker.rb
@@ -162,6 +177,7 @@ files:
162
177
  - spec/lib/chasqui/config_spec.rb
163
178
  - spec/lib/chasqui/multi_broker_spec.rb
164
179
  - spec/lib/chasqui/subscriber_spec.rb
180
+ - spec/lib/chasqui/subscription_spec.rb
165
181
  - spec/lib/chasqui/workers/resque_worker_spec.rb
166
182
  - spec/lib/chasqui/workers/sidekiq_worker_spec.rb
167
183
  - spec/lib/chasqui_spec.rb
@@ -208,6 +224,7 @@ test_files:
208
224
  - spec/lib/chasqui/config_spec.rb
209
225
  - spec/lib/chasqui/multi_broker_spec.rb
210
226
  - spec/lib/chasqui/subscriber_spec.rb
227
+ - spec/lib/chasqui/subscription_spec.rb
211
228
  - spec/lib/chasqui/workers/resque_worker_spec.rb
212
229
  - spec/lib/chasqui/workers/sidekiq_worker_spec.rb
213
230
  - spec/lib/chasqui_spec.rb
@@ -216,3 +233,4 @@ test_files:
216
233
  - spec/support/fake_logger.rb
217
234
  - spec/support/fake_subscriber.rb
218
235
  - spec/support/sidekiq_compatibility_check.rb
236
+ has_rdoc: