mail_room 0.9.1 → 0.10.0

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.
@@ -23,6 +23,7 @@ module MailRoom
23
23
 
24
24
  # run the mailbox watcher
25
25
  def run
26
+ @mailbox.logger.info({ context: @mailbox.context, action: "Setting up watcher" })
26
27
  @running = true
27
28
 
28
29
  connection.on_new_message do |message|
@@ -40,6 +41,7 @@ module MailRoom
40
41
 
41
42
  # stop running, cleanup connection
42
43
  def quit
44
+ @mailbox.logger.info({ context: @mailbox.context, action: "Quitting connection..." })
43
45
  @running = false
44
46
 
45
47
  if @connection
@@ -1,4 +1,4 @@
1
1
  module MailRoom
2
2
  # Current version of MailRoom gem
3
- VERSION = "0.9.1"
3
+ VERSION = "0.10.0"
4
4
  end
@@ -0,0 +1 @@
1
+ # Logfile created on 2019-09-26 08:59:35 -0500 by logger.rb/66358
@@ -22,12 +22,12 @@ 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"
26
25
 
27
26
  # for testing delivery methods
28
27
  gem.add_development_dependency "faraday"
29
28
  gem.add_development_dependency "mail"
30
29
  gem.add_development_dependency "letter_opener"
30
+ gem.add_development_dependency "redis", "~> 3.3.1"
31
31
  gem.add_development_dependency "redis-namespace"
32
32
  gem.add_development_dependency "pg"
33
33
  gem.add_development_dependency "charlock_holmes"
@@ -6,6 +6,8 @@
6
6
  :name: "inbox"
7
7
  :delivery_url: "http://localhost:3000/inbox"
8
8
  :delivery_token: "abcdefg"
9
+ :logger:
10
+ :log_path: "logfile.log"
9
11
  -
10
12
  :email: "user2@gmail.com"
11
13
  :password: "password"
@@ -3,7 +3,7 @@ require 'mail_room/arbitration/redis'
3
3
 
4
4
  describe MailRoom::Arbitration::Redis do
5
5
  let(:mailbox) {
6
- MailRoom::Mailbox.new(
6
+ build_mailbox(
7
7
  arbitration_options: {
8
8
  namespace: "mail_room"
9
9
  }
@@ -13,10 +13,14 @@ describe MailRoom::Arbitration::Redis do
13
13
  subject { described_class.new(options) }
14
14
 
15
15
  # Private, but we don't care.
16
- let(:client) { subject.send(:client) }
16
+ let(:redis) { subject.send(:client) }
17
17
 
18
18
  describe '#deliver?' do
19
19
  context "when called the first time" do
20
+ after do
21
+ redis.del("delivered:123")
22
+ end
23
+
20
24
  it "returns true" do
21
25
  expect(subject.deliver?(123)).to be_truthy
22
26
  end
@@ -24,29 +28,35 @@ describe MailRoom::Arbitration::Redis do
24
28
  it "increments the delivered flag" do
25
29
  subject.deliver?(123)
26
30
 
27
- expect(client.get("delivered:123")).to eq("1")
31
+ expect(redis.get("delivered:123")).to eq("1")
28
32
  end
29
33
 
30
34
  it "sets an expiration on the delivered flag" do
31
35
  subject.deliver?(123)
32
36
 
33
- expect(client.ttl("delivered:123")).to be > 0
37
+ expect(redis.ttl("delivered:123")).to be > 0
34
38
  end
35
39
  end
36
40
 
37
41
  context "when called the second time" do
38
42
  before do
39
- subject.deliver?(123)
43
+ #Short expiration, 1 second, for testing
44
+ subject.deliver?(123, 1)
40
45
  end
41
46
 
42
- it "returns false" do
43
- expect(subject.deliver?(123)).to be_falsey
47
+ after do
48
+ redis.del("delivered:123")
44
49
  end
45
50
 
46
- it "increments the delivered flag" do
47
- subject.deliver?(123)
51
+ it "returns false" do
52
+ expect(subject.deliver?(123, 1)).to be_falsey
53
+ end
48
54
 
49
- expect(client.get("delivered:123")).to eq("2")
55
+ it "after expiration returns true" do
56
+ # Fails locally because fakeredis returns 0, not false
57
+ expect(subject.deliver?(123, 1)).to be_falsey
58
+ sleep(redis.ttl("delivered:123")+1)
59
+ expect(subject.deliver?(123, 1)).to be_truthy
50
60
  end
51
61
  end
52
62
 
@@ -55,38 +65,47 @@ describe MailRoom::Arbitration::Redis do
55
65
  subject.deliver?(123)
56
66
  end
57
67
 
68
+ after do
69
+ redis.del("delivered:123")
70
+ redis.del("delivered:124")
71
+ end
72
+
58
73
  it "returns true" do
59
- expect(subject.deliver?(234)).to be_truthy
74
+ expect(subject.deliver?(124)).to be_truthy
60
75
  end
61
76
  end
62
77
  end
63
78
 
64
79
  context 'redis client connection params' do
65
80
  context 'when only url is present' do
66
- let(:redis_url) { "redis://redis.example.com:8888" }
81
+ let(:redis_url) { "redis://localhost:6379" }
67
82
  let(:mailbox) {
68
- MailRoom::Mailbox.new(
83
+ build_mailbox(
69
84
  arbitration_options: {
70
85
  redis_url: redis_url
71
86
  }
72
87
  )
73
88
  }
74
89
 
90
+ after do
91
+ redis.del("delivered:123")
92
+ end
93
+
75
94
  it 'client has same specified url' do
76
95
  subject.deliver?(123)
77
96
 
78
- expect(client.options[:url]).to eq redis_url
97
+ expect(redis.client.options[:url]).to eq redis_url
79
98
  end
80
99
 
81
100
  it 'client is a instance of Redis class' do
82
- expect(client).to be_a Redis
101
+ expect(redis).to be_a Redis
83
102
  end
84
103
  end
85
104
 
86
105
  context 'when namespace is present' do
87
106
  let(:namespace) { 'mail_room' }
88
107
  let(:mailbox) {
89
- MailRoom::Mailbox.new(
108
+ build_mailbox(
90
109
  arbitration_options: {
91
110
  namespace: namespace
92
111
  }
@@ -94,11 +113,11 @@ describe MailRoom::Arbitration::Redis do
94
113
  }
95
114
 
96
115
  it 'client has same specified namespace' do
97
- expect(client.namespace).to eq(namespace)
116
+ expect(redis.namespace).to eq(namespace)
98
117
  end
99
118
 
100
119
  it 'client is a instance of RedisNamespace class' do
101
- expect(client).to be_a ::Redis::Namespace
120
+ expect(redis).to be_a ::Redis::Namespace
102
121
  end
103
122
  end
104
123
 
@@ -106,7 +125,7 @@ describe MailRoom::Arbitration::Redis do
106
125
  let(:redis_url) { 'redis://:mypassword@sentinel-master:6379' }
107
126
  let(:sentinels) { [{ host: '10.0.0.1', port: '26379' }] }
108
127
  let(:mailbox) {
109
- MailRoom::Mailbox.new(
128
+ build_mailbox(
110
129
  arbitration_options: {
111
130
  redis_url: redis_url,
112
131
  sentinels: sentinels
@@ -117,10 +136,10 @@ describe MailRoom::Arbitration::Redis do
117
136
  before { ::Redis::Client::Connector::Sentinel.any_instance.stubs(:resolve).returns(sentinels) }
118
137
 
119
138
  it 'client has same specified sentinel params' do
120
- expect(client.client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
121
- expect(client.client.options[:host]).to eq('sentinel-master')
122
- expect(client.client.options[:password]).to eq('mypassword')
123
- expect(client.client.options[:sentinels]).to eq(sentinels)
139
+ expect(redis.client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
140
+ expect(redis.client.options[:host]).to eq('sentinel-master')
141
+ expect(redis.client.options[:password]).to eq('mypassword')
142
+ expect(redis.client.options[:sentinels]).to eq(sentinels)
124
143
  end
125
144
  end
126
145
  end
@@ -4,22 +4,26 @@ describe MailRoom::Configuration do
4
4
  let(:config_path) {File.expand_path('../fixtures/test_config.yml', File.dirname(__FILE__))}
5
5
 
6
6
  describe 'set_mailboxes' do
7
- it 'parses yaml into mailbox objects' do
8
- MailRoom::Mailbox.stubs(:new).returns('mailbox1', 'mailbox2')
7
+ context 'with config_path' do
8
+ let(:configuration) { MailRoom::Configuration.new(:config_path => config_path) }
9
9
 
10
- configuration = MailRoom::Configuration.new(:config_path => config_path)
10
+ it 'parses yaml into mailbox objects' do
11
+ MailRoom::Mailbox.stubs(:new).returns('mailbox1', 'mailbox2')
11
12
 
12
- expect(configuration.mailboxes).to eq(['mailbox1', 'mailbox2'])
13
+ expect(configuration.mailboxes).to eq(['mailbox1', 'mailbox2'])
14
+ end
13
15
  end
14
16
 
15
- it 'sets mailboxes to an empty set when config_path is missing' do
16
- MailRoom::Mailbox.stubs(:new)
17
+ context 'without config_path' do
18
+ let(:configuration) { MailRoom::Configuration.new }
17
19
 
18
- configuration = MailRoom::Configuration.new
20
+ it 'sets mailboxes to an empty set' do
21
+ MailRoom::Mailbox.stubs(:new)
19
22
 
20
- expect(configuration.mailboxes).to eq([])
23
+ expect(configuration.mailboxes).to eq([])
21
24
 
22
- expect(MailRoom::Mailbox).to have_received(:new).never
25
+ expect(MailRoom::Mailbox).to have_received(:new).never
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe MailRoom::Connection do
4
4
  let(:imap) {stub}
5
- let(:mailbox) {MailRoom::Mailbox.new(delete_after_delivery: true)}
5
+ let(:mailbox) {build_mailbox(delete_after_delivery: true, expunge_deleted: true)}
6
6
 
7
7
  before :each do
8
- MailRoom::IMAP.stubs(:new).returns(imap)
8
+ Net::IMAP.stubs(:new).returns(imap)
9
9
  end
10
10
 
11
11
  context "with imap set up" do
@@ -50,6 +50,7 @@ describe MailRoom::Connection do
50
50
  imap.stubs(:uid_search).returns([]).then.returns([1])
51
51
  imap.stubs(:uid_fetch).returns([new_message])
52
52
  imap.stubs(:store)
53
+ imap.stubs(:expunge)
53
54
 
54
55
  connection.wait
55
56
 
@@ -58,6 +59,7 @@ describe MailRoom::Connection do
58
59
  expect(imap).to have_received(:uid_fetch).with([1], "RFC822")
59
60
  expect(mailbox).to have_received(:deliver?).with(1)
60
61
  expect(imap).to have_received(:store).with(8, "+FLAGS", [Net::IMAP::DELETED])
62
+ expect(imap).to have_received(:expunge).once
61
63
  end
62
64
  end
63
65
  end
@@ -3,7 +3,7 @@ require 'mail_room/delivery/letter_opener'
3
3
 
4
4
  describe MailRoom::Delivery::LetterOpener do
5
5
  describe '#deliver' do
6
- let(:mailbox) {MailRoom::Mailbox.new(:location => '/tmp/somewhere')}
6
+ let(:mailbox) {build_mailbox(:location => '/tmp/somewhere')}
7
7
  let(:delivery_method) {stub(:deliver!)}
8
8
  let(:mail) {stub}
9
9
 
@@ -4,7 +4,7 @@ require 'mail_room/delivery/logger'
4
4
  describe MailRoom::Delivery::Logger do
5
5
  describe '#initialize' do
6
6
  context "without a log path" do
7
- let(:mailbox) {MailRoom::Mailbox.new}
7
+ let(:mailbox) {build_mailbox}
8
8
 
9
9
  it 'creates a new ruby logger' do
10
10
  ::Logger.stubs(:new)
@@ -16,7 +16,7 @@ describe MailRoom::Delivery::Logger do
16
16
  end
17
17
 
18
18
  context "with a log path" do
19
- let(:mailbox) {MailRoom::Mailbox.new(:log_path => '/var/log/mail-room.log')}
19
+ let(:mailbox) {build_mailbox(:log_path => '/var/log/mail-room.log')}
20
20
 
21
21
  it 'creates a new file to append to' do
22
22
  ::Logger.stubs(:new)
@@ -32,7 +32,7 @@ describe MailRoom::Delivery::Logger do
32
32
  end
33
33
 
34
34
  describe '#deliver' do
35
- let(:mailbox) {MailRoom::Mailbox.new}
35
+ let(:mailbox) {build_mailbox}
36
36
 
37
37
  it 'writes the message to info' do
38
38
  logger = stub(:info)
@@ -3,29 +3,69 @@ require 'mail_room/delivery/postback'
3
3
 
4
4
  describe MailRoom::Delivery::Postback do
5
5
  describe '#deliver' do
6
- let(:mailbox) {MailRoom::Mailbox.new({
7
- :delivery_url => 'http://localhost/inbox',
8
- :delivery_token => 'abcdefg'
9
- })}
6
+ context 'with token auth delivery' do
7
+ let(:mailbox) {build_mailbox({
8
+ :delivery_url => 'http://localhost/inbox',
9
+ :delivery_token => 'abcdefg'
10
+ })}
10
11
 
11
- it 'posts the message with faraday' do
12
- connection = stub
13
- request = stub
14
- Faraday.stubs(:new).returns(connection)
12
+ let(:delivery_options) {
13
+ MailRoom::Delivery::Postback::Options.new(mailbox)
14
+ }
15
15
 
16
- connection.stubs(:token_auth)
17
- connection.stubs(:post).yields(request)
16
+ it 'posts the message with faraday' do
17
+ connection = stub
18
+ request = stub
19
+ Faraday.stubs(:new).returns(connection)
18
20
 
19
- request.stubs(:url)
20
- request.stubs(:body=)
21
+ connection.stubs(:token_auth)
22
+ connection.stubs(:post).yields(request)
21
23
 
22
- MailRoom::Delivery::Postback.new(mailbox).deliver('a message')
24
+ request.stubs(:url)
25
+ request.stubs(:body=)
23
26
 
24
- expect(connection).to have_received(:token_auth).with('abcdefg')
25
- expect(connection).to have_received(:post)
27
+ MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
26
28
 
27
- expect(request).to have_received(:url).with('http://localhost/inbox')
28
- expect(request).to have_received(:body=).with('a message')
29
+ expect(connection).to have_received(:token_auth).with('abcdefg')
30
+ expect(connection).to have_received(:post)
31
+
32
+ expect(request).to have_received(:url).with('http://localhost/inbox')
33
+ expect(request).to have_received(:body=).with('a message')
34
+ end
35
+ end
36
+
37
+ context 'with basic auth delivery options' do
38
+ let(:mailbox) {build_mailbox({
39
+ :delivery_options => {
40
+ :url => 'http://localhost/inbox',
41
+ :username => 'user1',
42
+ :password => 'password123abc'
43
+ }
44
+ })}
45
+
46
+ let(:delivery_options) {
47
+ MailRoom::Delivery::Postback::Options.new(mailbox)
48
+ }
49
+
50
+ it 'posts the message with faraday' do
51
+ connection = stub
52
+ request = stub
53
+ Faraday.stubs(:new).returns(connection)
54
+
55
+ connection.stubs(:basic_auth)
56
+ connection.stubs(:post).yields(request)
57
+
58
+ request.stubs(:url)
59
+ request.stubs(:body=)
60
+
61
+ MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
62
+
63
+ expect(connection).to have_received(:basic_auth).with('user1', 'password123abc')
64
+ expect(connection).to have_received(:post)
65
+
66
+ expect(request).to have_received(:url).with('http://localhost/inbox')
67
+ expect(request).to have_received(:body=).with('a message')
68
+ end
29
69
  end
30
70
  end
31
71
  end
@@ -3,7 +3,7 @@ require 'mail_room/delivery/que'
3
3
 
4
4
  describe MailRoom::Delivery::Que do
5
5
  describe '#deliver' do
6
- let(:mailbox) {MailRoom::Mailbox.new({
6
+ let(:mailbox) {build_mailbox({
7
7
  delivery_options: {
8
8
  database: 'delivery_test',
9
9
  username: 'postgres',
@@ -7,11 +7,11 @@ describe MailRoom::Delivery::Sidekiq do
7
7
  let(:options) { MailRoom::Delivery::Sidekiq::Options.new(mailbox) }
8
8
 
9
9
  describe '#options' do
10
- let(:redis_url) { 'redis://redis.example.com' }
10
+ let(:redis_url) { 'redis://localhost' }
11
11
 
12
12
  context 'when only redis_url is specified' do
13
13
  let(:mailbox) {
14
- MailRoom::Mailbox.new(
14
+ build_mailbox(
15
15
  delivery_method: :sidekiq,
16
16
  delivery_options: {
17
17
  redis_url: redis_url
@@ -20,7 +20,7 @@ describe MailRoom::Delivery::Sidekiq do
20
20
  }
21
21
 
22
22
  it 'client has same specified redis_url' do
23
- expect(redis.options[:url]).to eq(redis_url)
23
+ expect(redis.client.options[:url]).to eq(redis_url)
24
24
  end
25
25
 
26
26
  it 'client is a instance of RedisNamespace class' do
@@ -31,7 +31,7 @@ describe MailRoom::Delivery::Sidekiq do
31
31
  context 'when namespace is specified' do
32
32
  let(:namespace) { 'sidekiq_mailman' }
33
33
  let(:mailbox) {
34
- MailRoom::Mailbox.new(
34
+ build_mailbox(
35
35
  delivery_method: :sidekiq,
36
36
  delivery_options: {
37
37
  redis_url: redis_url,
@@ -53,7 +53,7 @@ describe MailRoom::Delivery::Sidekiq do
53
53
  let(:redis_url) { 'redis://:mypassword@sentinel-master:6379' }
54
54
  let(:sentinels) { [{ host: '10.0.0.1', port: '26379' }] }
55
55
  let(:mailbox) {
56
- MailRoom::Mailbox.new(
56
+ build_mailbox(
57
57
  delivery_method: :sidekiq,
58
58
  delivery_options: {
59
59
  redis_url: redis_url,
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailRoom::Logger::Structured do
4
+
5
+ subject { described_class.new $stdout }
6
+
7
+ let!(:now) { Time.now }
8
+ let(:message) { { action: 'exciting development', message: 'testing 123' } }
9
+
10
+ before do
11
+ Time.stubs(:now).returns(now)
12
+ end
13
+
14
+ [:debug, :info, :warn, :error, :fatal].each do |level|
15
+ it "logs #{level}" do
16
+ expect { subject.send(level, message) }.to output(json_matching(level.to_s.upcase, message)).to_stdout_from_any_process
17
+ end
18
+ end
19
+
20
+ it 'logs unknown' do
21
+ expect { subject.unknown(message) }.to output(json_matching("ANY", message)).to_stdout_from_any_process
22
+ end
23
+
24
+ it 'only accepts strings' do
25
+ expect { subject.unknown("just a string!") }.to raise_error(ArgumentError, /must be a Hash/)
26
+ end
27
+
28
+ context 'logging a hash as a message' do
29
+ it 'merges the contents' do
30
+ input = {
31
+ additional_field: "some value"
32
+ }
33
+ expected = {
34
+ severity: 'DEBUG',
35
+ time: now,
36
+ additional_field: "some value"
37
+ }
38
+
39
+ expect { subject.debug(input) }.to output(as_regex(expected)).to_stdout_from_any_process
40
+ end
41
+ end
42
+
43
+ def json_matching(level, message)
44
+ contents = {
45
+ severity: level,
46
+ time: now
47
+ }.merge(message)
48
+
49
+ as_regex(contents)
50
+ end
51
+
52
+ def as_regex(contents)
53
+ /#{Regexp.quote(contents.to_json)}/
54
+ end
55
+ end