mail_room 0.5.2 → 0.6.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: 836563b572db61eacd01d2363273d998863e9831
4
- data.tar.gz: de0cab71b636b3c7ffe0f08cd021896e403940c3
3
+ metadata.gz: 7e839c7e9c2857c75d399aca74fe627438432c17
4
+ data.tar.gz: 97d5cbe394fbd50ee36814785ce03af51381c1ae
5
5
  SHA512:
6
- metadata.gz: 9648c21785544fab432cedeca09c6c28ffd7d993f7ff90c30c1bb2d893e00517687f233118ae945be43fe1c0123ce7f0b2a0addf78c7b5fb22876fae81718df9
7
- data.tar.gz: 503a0ac11cf7e0dddb4299c608ba5d87a5820419afb08ed8a65aeed6e04c6e56a54133f61239f193c63a8f11384fe91540b16ad7dac2a81cbbad4044e794ef1d
6
+ metadata.gz: 5dfcca4fe8a7323d5207b232a48351bb78cd4df53f8301aa719c198186d08ceb09ca3ce7dd3178af2d80f513f330a52488ba9bad5a6aa079aa9a0b19f649e002
7
+ data.tar.gz: e2ec188a14291548bc1891459e3ce18066109daa8566d584714d26fc2be3bb3fc17a54b17e1925c5758d785d1daa4e8292735a7db17cba04f045c6801b035a02
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## mail_room 0.6.0 ##
2
+
3
+ * Add redis Arbitration to reduce multiple deliveries of the same message when running multiple MailRoom instances on the same inbox
4
+
5
+ *Douwe Maan <@DouweM>*
6
+
1
7
  ## mail_room 0.5.2 ##
2
8
 
3
9
  * Fix Sidekiq delivery method for non-UTF8 email
data/README.md CHANGED
@@ -203,6 +203,34 @@ If you're seeing the error `Please log in via your web browser: https://support.
203
203
 
204
204
  I suggest running with either upstart or init.d. Check out this wiki page for some example scripts for both: https://github.com/tpitale/mail_room/wiki/Init-Scripts-for-Running-mail_room
205
205
 
206
+ ## Arbitration ##
207
+
208
+ When running multiple instances of MailRoom against a single mailbox, to try to prevent delivery of the same message multiple times, we can configure Arbitration using Redis.
209
+
210
+ ```yaml
211
+ :mailboxes:
212
+ -
213
+ :email: "user1@gmail.com"
214
+ :password: "password"
215
+ :name: "inbox"
216
+ :delivery_method: postback
217
+ :delivery_options:
218
+ :delivery_url: "http://localhost:3000/inbox"
219
+ :delivery_token: "abcdefg"
220
+
221
+ :arbitration_method: redis
222
+ :arbitration_options:
223
+ # The Redis server to connect with. Defaults to redis://localhost:6379.
224
+ :redis_url: redis://redis.example.com:6379
225
+ # The Redis namespace to house the Redis keys under. Optional.
226
+ :namespace: mail_room
227
+
228
+ ```
229
+
230
+ **Note:** This will likely never be a _perfect_ system for preventing multiple deliveries of the same message, so I would advise checking the unique `message_id` if you are running in this situation.
231
+
232
+ **Note:** There are other scenarios for preventing duplication of messages at scale that _may_ be more appropriate in your particular setup. One such example is using multiple inboxes in reply-by-email situations. Another is to use labels and configure a different `SEARCH` command for each instance of MailRoom.
233
+
206
234
  ## Contributing ##
207
235
 
208
236
  1. Fork it
data/lib/mail_room.rb CHANGED
@@ -2,16 +2,7 @@ require 'net/imap'
2
2
  require 'optparse'
3
3
  require 'yaml'
4
4
 
5
- # The MailRoom namespace
6
5
  module MailRoom
7
- # The MailRoom Delivery namespace holds any defined delivery methods
8
- # including:
9
- #
10
- # * postback (default)
11
- # * letter_opener
12
- # * logger
13
- # * noop
14
- module Delivery; end
15
6
  end
16
7
 
17
8
  require "mail_room/version"
@@ -0,0 +1,16 @@
1
+ module MailRoom
2
+ module Arbitration
3
+ def [](name)
4
+ require_relative("./arbitration/#{name}")
5
+
6
+ case name
7
+ when "redis"
8
+ Arbitration::Redis
9
+ else
10
+ Arbitration::Noop
11
+ end
12
+ end
13
+
14
+ module_function :[]
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module MailRoom
2
+ module Arbitration
3
+ class Noop
4
+ Options = Class.new do
5
+ def initialize(*)
6
+ super()
7
+ end
8
+ end
9
+
10
+ def initialize(*)
11
+ end
12
+
13
+ def deliver?(*)
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ require "redis"
2
+
3
+ module MailRoom
4
+ module Arbitration
5
+ class Redis
6
+ Options = Struct.new(:redis_url, :namespace) do
7
+ def initialize(mailbox)
8
+ redis_url = mailbox.arbitration_options[:redis_url] || "redis://localhost:6379"
9
+ namespace = mailbox.arbitration_options[:namespace]
10
+
11
+ super(redis_url, namespace)
12
+ end
13
+ end
14
+
15
+ # Expire after 10 minutes so Redis doesn't get filled up with outdated data.
16
+ EXPIRATION = 600
17
+
18
+ attr_accessor :options
19
+
20
+ def initialize(options)
21
+ @options = options
22
+ end
23
+
24
+ def deliver?(uid)
25
+ key = "delivered:#{uid}"
26
+
27
+ incr = nil
28
+ redis.multi do |client|
29
+ # At this point, `incr` is a future, which will get its value after
30
+ # the MULTI command returns.
31
+ incr = client.incr(key)
32
+
33
+ client.expire(key, EXPIRATION)
34
+ end
35
+
36
+ # If INCR returns 1, that means the key didn't exist before, which means
37
+ # we are the first mail_room to try to deliver this message, so we get to.
38
+ # If we get any other value, another mail_room already (tried to) deliver
39
+ # the message, so we don't have to anymore.
40
+ incr.value == 1
41
+ end
42
+
43
+ private
44
+
45
+ def redis
46
+ @redis ||= begin
47
+ redis = ::Redis.new(url: options.redis_url)
48
+
49
+ namespace = options.namespace
50
+ if namespace
51
+ require 'redis/namespace'
52
+ ::Redis::Namespace.new(namespace, redis: redis)
53
+ else
54
+ redis
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ module MailRoom
2
+ module Delivery
3
+ def [](name)
4
+ require_relative("./delivery/#{name}")
5
+
6
+ case name
7
+ when "postback"
8
+ Delivery::Postback
9
+ when "logger"
10
+ Delivery::Logger
11
+ when "letter_opener"
12
+ Delivery::LetterOpener
13
+ when "sidekiq"
14
+ Delivery::Sidekiq
15
+ when "que"
16
+ Delivery::Que
17
+ else
18
+ Delivery::Noop
19
+ end
20
+ end
21
+
22
+ module_function :[]
23
+ end
24
+ end
@@ -1,3 +1,6 @@
1
+ require "mail_room/delivery"
2
+ require "mail_room/arbitration"
3
+
1
4
  module MailRoom
2
5
  # Mailbox Configuration fields
3
6
  MAILBOX_FIELDS = [
@@ -15,7 +18,9 @@ module MailRoom
15
18
  :delivery_url, # for postback
16
19
  :delivery_token, # for postback
17
20
  :location, # for letter_opener
18
- :delivery_options
21
+ :delivery_options,
22
+ :arbitration_method,
23
+ :arbitration_options
19
24
  ]
20
25
 
21
26
  # Holds configuration for each of the email accounts we wish to monitor
@@ -30,45 +35,52 @@ module MailRoom
30
35
  :ssl => true,
31
36
  :start_tls => false,
32
37
  :delete_after_delivery => false,
33
- :delivery_options => {}
38
+ :delivery_options => {},
39
+ :arbitration_method => 'noop',
40
+ :arbitration_options => {}
34
41
  }
35
42
 
36
43
  # Store the configuration and require the appropriate delivery method
37
44
  # @param attributes [Hash] configuration options
38
45
  def initialize(attributes={})
39
46
  super(*DEFAULTS.merge(attributes).values_at(*members))
40
-
41
- require_relative("./delivery/#{(delivery_method)}")
42
47
  end
43
48
 
44
- # move to a mailbox deliverer class?
45
49
  def delivery_klass
46
- case delivery_method
47
- when "noop"
48
- Delivery::Noop
49
- when "logger"
50
- Delivery::Logger
51
- when "letter_opener"
52
- Delivery::LetterOpener
53
- when "sidekiq"
54
- Delivery::Sidekiq
55
- when "que"
56
- Delivery::Que
57
- else
58
- Delivery::Postback
59
- end
50
+ Delivery[delivery_method]
51
+ end
52
+
53
+ def arbitration_klass
54
+ Arbitration[arbitration_method]
55
+ end
56
+
57
+ def delivery
58
+ @delivery ||= delivery_klass.new(parsed_delivery_options)
59
+ end
60
+
61
+ def arbitrator
62
+ @arbitrator ||= arbitration_klass.new(parsed_arbitration_options)
63
+ end
64
+
65
+ def deliver?(uid)
66
+ arbitrator.deliver?(uid)
60
67
  end
61
68
 
62
69
  # deliver the imap email message
63
70
  # @param message [Net::IMAP::FetchData]
64
71
  def deliver(message)
65
- message = message.attr['RFC822']
66
- return true unless message
67
-
68
- delivery_klass.new(parsed_delivery_options).deliver(message)
72
+ body = message.attr['RFC822']
73
+ return true unless body
74
+
75
+ delivery.deliver(body)
69
76
  end
70
77
 
71
78
  private
79
+
80
+ def parsed_arbitration_options
81
+ arbitration_klass::Options.new(self)
82
+ end
83
+
72
84
  def parsed_delivery_options
73
85
  delivery_klass::Options.new(self)
74
86
  end
@@ -14,14 +14,12 @@ module MailRoom
14
14
  def process
15
15
  # return if idling? || !running?
16
16
 
17
- new_messages.each do |msg|
18
- # puts msg.attr['RFC822']
19
-
17
+ new_messages.each do |message|
20
18
  # loop over delivery methods and deliver each
21
- delivered = @mailbox.deliver(msg)
19
+ delivered = @mailbox.deliver(message)
22
20
 
23
21
  if delivered && @mailbox.delete_after_delivery
24
- @imap.store(msg.seqno, "+FLAGS", [Net::IMAP::DELETED])
22
+ @imap.store(message.seqno, "+FLAGS", [Net::IMAP::DELETED])
25
23
  end
26
24
  end
27
25
 
@@ -45,17 +43,17 @@ module MailRoom
45
43
  # search for all new (unseen) message ids
46
44
  # @return [Array<Integer>] message ids
47
45
  def new_message_ids
48
- @imap.search(@mailbox.search_command)
46
+ @imap.uid_search(@mailbox.search_command).select { |uid| @mailbox.deliver?(uid) }
49
47
  end
50
48
 
51
49
  # @private
52
50
  # fetch the email for all given ids in RFC822 format
53
51
  # @param ids [Array<Integer>] list of message ids
54
52
  # @return [Array<Net::IMAP::FetchData>] the net/imap messages for the given ids
55
- def messages_for_ids(ids)
56
- return [] if ids.empty?
53
+ def messages_for_ids(uids)
54
+ return [] if uids.empty?
57
55
 
58
- @imap.fetch(ids, "RFC822")
56
+ @imap.uid_fetch(uids, "RFC822")
59
57
  end
60
58
  end
61
59
  end
@@ -1,4 +1,4 @@
1
1
  module MailRoom
2
2
  # Current version of MailRoom gem
3
- VERSION = "0.5.2"
3
+ VERSION = "0.6.0"
4
4
  end
data/mail_room.gemspec CHANGED
@@ -22,12 +22,13 @@ Gem::Specification.new do |gem|
22
22
  gem.add_development_dependency "mocha"
23
23
  gem.add_development_dependency "bourne"
24
24
  gem.add_development_dependency "simplecov"
25
+ gem.add_development_dependency "fakeredis"
25
26
 
26
27
  # for testing delivery methods
27
28
  gem.add_development_dependency "faraday"
28
29
  gem.add_development_dependency "mail"
29
30
  gem.add_development_dependency "letter_opener"
30
- gem.add_development_dependency "redis"
31
+ gem.add_development_dependency "redis-namespace"
31
32
  gem.add_development_dependency "pg"
32
33
  gem.add_development_dependency "charlock_holmes"
33
34
  end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ require 'mail_room/arbitration/redis'
3
+
4
+ describe MailRoom::Arbitration::Redis do
5
+ let(:mailbox) {
6
+ MailRoom::Mailbox.new(
7
+ arbitration_options: {
8
+ namespace: "mail_room"
9
+ }
10
+ )
11
+ }
12
+ let(:options) { described_class::Options.new(mailbox) }
13
+ subject { described_class.new(options) }
14
+
15
+ # Private, but we don't care.
16
+ let(:redis) { subject.send(:redis) }
17
+
18
+ describe '#deliver?' do
19
+ context "when called the first time" do
20
+ it "returns true" do
21
+ expect(subject.deliver?(123)).to be_truthy
22
+ end
23
+
24
+ it "increments the delivered flag" do
25
+ subject.deliver?(123)
26
+
27
+ expect(redis.get("delivered:123")).to eq("1")
28
+ end
29
+
30
+ it "sets an expiration on the delivered flag" do
31
+ subject.deliver?(123)
32
+
33
+ expect(redis.ttl("delivered:123")).to be > 0
34
+ end
35
+ end
36
+
37
+ context "when called the second time" do
38
+ before do
39
+ subject.deliver?(123)
40
+ end
41
+
42
+ it "returns false" do
43
+ expect(subject.deliver?(123)).to be_falsey
44
+ end
45
+
46
+ it "increments the delivered flag" do
47
+ subject.deliver?(123)
48
+
49
+ expect(redis.get("delivered:123")).to eq("2")
50
+ end
51
+ end
52
+
53
+ context "when called for another uid" do
54
+ before do
55
+ subject.deliver?(123)
56
+ end
57
+
58
+ it "returns true" do
59
+ expect(subject.deliver?(234)).to be_truthy
60
+ end
61
+ end
62
+ end
63
+ end
@@ -6,31 +6,52 @@ describe MailRoom::MailboxHandler do
6
6
  let(:mailbox) {MailRoom::Mailbox.new}
7
7
 
8
8
  it 'fetches and delivers all new messages from ids' do
9
- imap.stubs(:search).returns([1,2])
10
- imap.stubs(:fetch).returns(['message1', 'message2'])
9
+ imap.stubs(:uid_search).returns([1,2])
10
+ message1 = stub(:attr => {'RFC822' => 'message1'})
11
+ message2 = stub(:attr => {'RFC822' => 'message2'})
12
+ imap.stubs(:uid_fetch).returns([message1, message2])
11
13
  mailbox.stubs(:deliver)
12
14
 
13
15
  handler = MailRoom::MailboxHandler.new(mailbox, imap)
14
16
  handler.process
15
17
 
16
- imap.should have_received(:search).with('UNSEEN')
17
- imap.should have_received(:fetch).with([1,2], 'RFC822')
18
- mailbox.should have_received(:deliver).with('message1')
19
- mailbox.should have_received(:deliver).with('message2')
18
+ imap.should have_received(:uid_search).with('UNSEEN')
19
+ imap.should have_received(:uid_fetch).with([1,2], 'RFC822')
20
+ mailbox.should have_received(:deliver).with(message1)
21
+ mailbox.should have_received(:deliver).with(message2)
22
+ end
23
+
24
+ it "fetches and delivers all new messages from ids that haven't been processed yet" do
25
+ imap.stubs(:uid_search).returns([1,2])
26
+ message1 = stub(:attr => {'RFC822' => 'message1'})
27
+ message2 = stub(:attr => {'RFC822' => 'message2'})
28
+ imap.stubs(:uid_fetch).returns([message2])
29
+ mailbox.stubs(:deliver)
30
+ mailbox.stubs(:deliver?).with(1).returns(false)
31
+ mailbox.stubs(:deliver?).with(2).returns(true)
32
+
33
+ handler = MailRoom::MailboxHandler.new(mailbox, imap)
34
+ handler.process
35
+
36
+ imap.should have_received(:uid_search).with('UNSEEN')
37
+ imap.should have_received(:uid_fetch).with([2], 'RFC822')
38
+
39
+ mailbox.should have_received(:deliver).with(message1).never
40
+ mailbox.should have_received(:deliver).with(message2)
20
41
  end
21
42
 
22
43
  it 'returns no messages if there are no ids' do
23
- imap.stubs(:search).returns([])
24
- imap.stubs(:fetch)
44
+ imap.stubs(:uid_search).returns([])
45
+ imap.stubs(:uid_fetch)
25
46
  mailbox.search_command = 'NEW'
26
47
  mailbox.stubs(:deliver)
27
48
 
28
49
  handler = MailRoom::MailboxHandler.new(mailbox, imap)
29
50
  handler.process
30
51
 
31
- imap.should have_received(:search).with('NEW')
32
- imap.should have_received(:fetch).never
52
+ imap.should have_received(:uid_search).with('NEW')
53
+ imap.should have_received(:uid_fetch).never
33
54
  mailbox.should have_received(:deliver).never
34
55
  end
35
56
  end
36
- end
57
+ end
@@ -2,11 +2,39 @@ require 'spec_helper'
2
2
 
3
3
  describe MailRoom::Mailbox do
4
4
  describe "#deliver" do
5
+ context "with arbitration_method of noop" do
6
+ it 'arbitrates with a Noop instance' do
7
+ mailbox = MailRoom::Mailbox.new({:arbitration_method => 'noop'})
8
+ noop = stub(:deliver?)
9
+ MailRoom::Arbitration['noop'].stubs(:new => noop)
10
+
11
+ uid = 123
12
+
13
+ mailbox.deliver?(uid)
14
+
15
+ noop.should have_received(:deliver?).with(uid)
16
+ end
17
+ end
18
+
19
+ context "with arbitration_method of redis" do
20
+ it 'arbitrates with a Redis instance' do
21
+ mailbox = MailRoom::Mailbox.new({:arbitration_method => 'redis'})
22
+ redis = stub(:deliver?)
23
+ MailRoom::Arbitration['redis'].stubs(:new => redis)
24
+
25
+ uid = 123
26
+
27
+ mailbox.deliver?(uid)
28
+
29
+ redis.should have_received(:deliver?).with(uid)
30
+ end
31
+ end
32
+
5
33
  context "with delivery_method of noop" do
6
34
  it 'delivers with a Noop instance' do
7
35
  mailbox = MailRoom::Mailbox.new({:delivery_method => 'noop'})
8
36
  noop = stub(:deliver)
9
- MailRoom::Delivery::Noop.stubs(:new => noop)
37
+ MailRoom::Delivery['noop'].stubs(:new => noop)
10
38
 
11
39
  mailbox.deliver(stub(:attr => {'RFC822' => 'a message'}))
12
40
 
@@ -18,7 +46,7 @@ describe MailRoom::Mailbox do
18
46
  it 'delivers with a Logger instance' do
19
47
  mailbox = MailRoom::Mailbox.new({:delivery_method => 'logger'})
20
48
  logger = stub(:deliver)
21
- MailRoom::Delivery::Logger.stubs(:new => logger)
49
+ MailRoom::Delivery['logger'].stubs(:new => logger)
22
50
 
23
51
  mailbox.deliver(stub(:attr => {'RFC822' => 'a message'}))
24
52
 
@@ -30,7 +58,7 @@ describe MailRoom::Mailbox do
30
58
  it 'delivers with a Postback instance' do
31
59
  mailbox = MailRoom::Mailbox.new({:delivery_method => 'postback'})
32
60
  postback = stub(:deliver)
33
- MailRoom::Delivery::Postback.stubs(:new => postback)
61
+ MailRoom::Delivery['postback'].stubs(:new => postback)
34
62
 
35
63
  mailbox.deliver(stub(:attr => {'RFC822' => 'a message'}))
36
64
 
@@ -42,7 +70,7 @@ describe MailRoom::Mailbox do
42
70
  it 'delivers with a LetterOpener instance' do
43
71
  mailbox = MailRoom::Mailbox.new({:delivery_method => 'letter_opener'})
44
72
  letter_opener = stub(:deliver)
45
- MailRoom::Delivery::LetterOpener.stubs(:new => letter_opener)
73
+ MailRoom::Delivery['letter_opener'].stubs(:new => letter_opener)
46
74
 
47
75
  mailbox.deliver(stub(:attr => {'RFC822' => 'a message'}))
48
76
 
@@ -54,7 +82,7 @@ describe MailRoom::Mailbox do
54
82
  it "doesn't deliver the message" do
55
83
  mailbox = MailRoom::Mailbox.new({:delivery_method => 'noop'})
56
84
  noop = stub(:deliver)
57
- MailRoom::Delivery::Noop.stubs(:new => noop)
85
+ MailRoom::Delivery['noop'].stubs(:new => noop)
58
86
 
59
87
  mailbox.deliver(stub(:attr => {'FLAGS' => [:Seen, :Recent]}))
60
88
 
data/spec/spec_helper.rb CHANGED
@@ -6,6 +6,7 @@ require 'bundler/setup'
6
6
  require 'rspec'
7
7
  require 'mocha/api'
8
8
  require 'bourne'
9
+ require 'fakeredis/rspec'
9
10
 
10
11
  require File.expand_path('../../lib/mail_room', __FILE__)
11
12
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Pitale
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-24 00:00:00.000000000 Z
11
+ date: 2015-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakeredis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: faraday
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -123,7 +137,7 @@ dependencies:
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
- name: redis
140
+ name: redis-namespace
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - ">="
@@ -183,9 +197,13 @@ files:
183
197
  - Rakefile
184
198
  - bin/mail_room
185
199
  - lib/mail_room.rb
200
+ - lib/mail_room/arbitration.rb
201
+ - lib/mail_room/arbitration/noop.rb
202
+ - lib/mail_room/arbitration/redis.rb
186
203
  - lib/mail_room/cli.rb
187
204
  - lib/mail_room/configuration.rb
188
205
  - lib/mail_room/coordinator.rb
206
+ - lib/mail_room/delivery.rb
189
207
  - lib/mail_room/delivery/letter_opener.rb
190
208
  - lib/mail_room/delivery/logger.rb
191
209
  - lib/mail_room/delivery/noop.rb
@@ -198,6 +216,7 @@ files:
198
216
  - lib/mail_room/version.rb
199
217
  - mail_room.gemspec
200
218
  - spec/fixtures/test_config.yml
219
+ - spec/lib/arbitration/redis_spec.rb
201
220
  - spec/lib/cli_spec.rb
202
221
  - spec/lib/configuration_spec.rb
203
222
  - spec/lib/coordinator_spec.rb
@@ -235,6 +254,7 @@ summary: mail_room will proxy email (gmail) from IMAP to a callback URL, logger,
235
254
  letter_opener
236
255
  test_files:
237
256
  - spec/fixtures/test_config.yml
257
+ - spec/lib/arbitration/redis_spec.rb
238
258
  - spec/lib/cli_spec.rb
239
259
  - spec/lib/configuration_spec.rb
240
260
  - spec/lib/coordinator_spec.rb