gitlab-mail_room 0.0.6 → 0.0.11
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 +4 -4
- data/.gitlab-ci.yml +9 -5
- data/.ruby-version +1 -1
- data/.travis.yml +3 -2
- data/README.md +104 -10
- data/lib/mail_room.rb +2 -0
- data/lib/mail_room/cli.rb +1 -1
- data/lib/mail_room/configuration.rb +11 -1
- data/lib/mail_room/connection.rb +7 -179
- data/lib/mail_room/coordinator.rb +8 -4
- data/lib/mail_room/crash_handler.rb +2 -2
- data/lib/mail_room/health_check.rb +60 -0
- data/lib/mail_room/imap.rb +8 -0
- data/lib/mail_room/imap/connection.rb +200 -0
- data/lib/mail_room/imap/message.rb +19 -0
- data/lib/mail_room/logger/structured.rb +15 -1
- data/lib/mail_room/mailbox.rb +49 -7
- data/lib/mail_room/mailbox_watcher.rb +15 -2
- data/lib/mail_room/message.rb +16 -0
- data/lib/mail_room/microsoft_graph.rb +7 -0
- data/lib/mail_room/microsoft_graph/connection.rb +216 -0
- data/lib/mail_room/version.rb +1 -1
- data/mail_room.gemspec +5 -0
- data/spec/fixtures/test_config.yml +3 -0
- data/spec/lib/cli_spec.rb +3 -3
- data/spec/lib/configuration_spec.rb +9 -1
- data/spec/lib/coordinator_spec.rb +16 -2
- data/spec/lib/health_check_spec.rb +57 -0
- data/spec/lib/{connection_spec.rb → imap/connection_spec.rb} +12 -8
- data/spec/lib/imap/message_spec.rb +36 -0
- data/spec/lib/logger/structured_spec.rb +34 -2
- data/spec/lib/mailbox_spec.rb +58 -10
- data/spec/lib/mailbox_watcher_spec.rb +54 -38
- data/spec/lib/message_spec.rb +35 -0
- data/spec/lib/microsoft_graph/connection_spec.rb +183 -0
- data/spec/spec_helper.rb +11 -0
- metadata +76 -5
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MailRoom::Connection do
|
3
|
+
describe MailRoom::IMAP::Connection do
|
4
4
|
let(:imap) {stub}
|
5
5
|
let(:mailbox) {build_mailbox(delete_after_delivery: true, expunge_deleted: true)}
|
6
6
|
|
@@ -9,7 +9,9 @@ describe MailRoom::Connection do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
context "with imap set up" do
|
12
|
-
let(:connection) {MailRoom::Connection.new(mailbox)}
|
12
|
+
let(:connection) {MailRoom::IMAP::Connection.new(mailbox)}
|
13
|
+
let(:uid) { 1 }
|
14
|
+
let(:seqno) { 8 }
|
13
15
|
|
14
16
|
before :each do
|
15
17
|
imap.stubs(:starttls)
|
@@ -36,19 +38,21 @@ describe MailRoom::Connection do
|
|
36
38
|
end
|
37
39
|
|
38
40
|
it "waits for a message to process" do
|
39
|
-
new_message = 'a message'
|
40
|
-
new_message.stubs(:seqno).returns(8)
|
41
|
+
new_message = MailRoom::IMAP::Message.new(uid: uid, body: 'a message', seqno: seqno)
|
41
42
|
|
42
43
|
connection.on_new_message do |message|
|
43
44
|
expect(message).to eq(new_message)
|
44
45
|
true
|
45
46
|
end
|
46
47
|
|
48
|
+
attr = { 'UID' => uid, 'RFC822' => new_message.body }
|
49
|
+
fetch_data = Net::IMAP::FetchData.new(seqno, attr)
|
50
|
+
|
47
51
|
imap.expects(:idle)
|
48
|
-
imap.stubs(:uid_search).with(mailbox.search_command).returns([], [
|
49
|
-
imap.expects(:uid_fetch).with([
|
50
|
-
mailbox.expects(:deliver?).with(
|
51
|
-
imap.expects(:store).with(
|
52
|
+
imap.stubs(:uid_search).with(mailbox.search_command).returns([], [uid])
|
53
|
+
imap.expects(:uid_fetch).with([uid], "RFC822").returns([fetch_data])
|
54
|
+
mailbox.expects(:deliver?).with(uid).returns(true)
|
55
|
+
imap.expects(:store).with(seqno, "+FLAGS", [Net::IMAP::DELETED])
|
52
56
|
imap.expects(:expunge).once
|
53
57
|
|
54
58
|
connection.wait
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
describe MailRoom::IMAP::Message do
|
7
|
+
let(:uid) { SecureRandom.hex }
|
8
|
+
let(:body) { 'hello world' }
|
9
|
+
let(:seqno) { 5 }
|
10
|
+
|
11
|
+
subject { described_class.new(uid: uid, body: body, seqno: seqno) }
|
12
|
+
|
13
|
+
describe '#initalize' do
|
14
|
+
it 'initializes with required parameters' do
|
15
|
+
subject
|
16
|
+
|
17
|
+
expect(subject.uid).to eq(uid)
|
18
|
+
expect(subject.body).to eq(body)
|
19
|
+
expect(subject.seqno).to eq(seqno)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#==' do
|
24
|
+
let(:dup) { described_class.new(uid: uid, body: body, seqno: seqno) }
|
25
|
+
let(:base_msg) { MailRoom::Message.new(uid: uid, body: body) }
|
26
|
+
|
27
|
+
it 'matches an equivalent message' do
|
28
|
+
expect(dup == subject).to be true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not match a base message' do
|
32
|
+
expect(subject == base_msg).to be false
|
33
|
+
expect(base_msg == subject).to be false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -5,6 +5,7 @@ describe MailRoom::Logger::Structured do
|
|
5
5
|
subject { described_class.new $stdout }
|
6
6
|
|
7
7
|
let!(:now) { Time.now }
|
8
|
+
let(:timestamp) { now.to_datetime.iso8601(3) }
|
8
9
|
let(:message) { { action: 'exciting development', message: 'testing 123' } }
|
9
10
|
|
10
11
|
before do
|
@@ -32,7 +33,7 @@ describe MailRoom::Logger::Structured do
|
|
32
33
|
}
|
33
34
|
expected = {
|
34
35
|
severity: 'DEBUG',
|
35
|
-
time:
|
36
|
+
time: timestamp,
|
36
37
|
additional_field: "some value"
|
37
38
|
}
|
38
39
|
|
@@ -40,10 +41,41 @@ describe MailRoom::Logger::Structured do
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
44
|
+
describe '#format_message' do
|
45
|
+
shared_examples 'timestamp formatting' do
|
46
|
+
it 'outputs ISO8601 timestamps' do
|
47
|
+
data = JSON.parse(subject.format_message('debug', input_timestamp, 'test', { message: 'hello' } ))
|
48
|
+
|
49
|
+
expect(data['time']).to eq(expected_timestamp)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with no timestamp' do
|
54
|
+
let(:input_timestamp) { nil }
|
55
|
+
let(:expected_timestamp) { timestamp }
|
56
|
+
|
57
|
+
it_behaves_like 'timestamp formatting'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'with DateTime' do
|
61
|
+
let(:input_timestamp) { now.to_datetime }
|
62
|
+
let(:expected_timestamp) { timestamp }
|
63
|
+
|
64
|
+
it_behaves_like 'timestamp formatting'
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with string' do
|
68
|
+
let(:input_timestamp) { now.to_s }
|
69
|
+
let(:expected_timestamp) { input_timestamp }
|
70
|
+
|
71
|
+
it_behaves_like 'timestamp formatting'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
43
75
|
def json_matching(level, message)
|
44
76
|
contents = {
|
45
77
|
severity: level,
|
46
|
-
time:
|
78
|
+
time: timestamp
|
47
79
|
}.merge(message)
|
48
80
|
|
49
81
|
as_regex(contents)
|
data/spec/lib/mailbox_spec.rb
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MailRoom::Mailbox do
|
4
|
-
let(:sample_message) {
|
4
|
+
let(:sample_message) { MailRoom::Message.new(uid: 123, body: 'a message') }
|
5
|
+
|
6
|
+
context 'with IMAP configuration' do
|
7
|
+
subject { build_mailbox }
|
8
|
+
|
9
|
+
describe '#imap?' do
|
10
|
+
it 'configured as an IMAP inbox' do
|
11
|
+
expect(subject.imap?).to be true
|
12
|
+
expect(subject.microsoft_graph?).to be false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
5
16
|
|
6
17
|
describe "#deliver" do
|
7
18
|
context "with arbitration_method of noop" do
|
@@ -36,9 +47,9 @@ describe MailRoom::Mailbox do
|
|
36
47
|
noop = stub(:deliver)
|
37
48
|
MailRoom::Delivery['noop'].stubs(:new => noop)
|
38
49
|
|
39
|
-
noop.expects(:deliver).with(
|
50
|
+
noop.expects(:deliver).with(sample_message.body)
|
40
51
|
|
41
|
-
mailbox.deliver(
|
52
|
+
mailbox.deliver(sample_message)
|
42
53
|
end
|
43
54
|
end
|
44
55
|
|
@@ -48,9 +59,9 @@ describe MailRoom::Mailbox do
|
|
48
59
|
logger = stub(:deliver)
|
49
60
|
MailRoom::Delivery['logger'].stubs(:new => logger)
|
50
61
|
|
51
|
-
logger.expects(:deliver).with(
|
62
|
+
logger.expects(:deliver).with(sample_message.body)
|
52
63
|
|
53
|
-
mailbox.deliver(
|
64
|
+
mailbox.deliver(sample_message)
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
@@ -60,9 +71,9 @@ describe MailRoom::Mailbox do
|
|
60
71
|
postback = stub(:deliver)
|
61
72
|
MailRoom::Delivery['postback'].stubs(:new => postback)
|
62
73
|
|
63
|
-
postback.expects(:deliver).with(
|
74
|
+
postback.expects(:deliver).with(sample_message.body)
|
64
75
|
|
65
|
-
mailbox.deliver(
|
76
|
+
mailbox.deliver(sample_message)
|
66
77
|
end
|
67
78
|
end
|
68
79
|
|
@@ -72,9 +83,9 @@ describe MailRoom::Mailbox do
|
|
72
83
|
letter_opener = stub(:deliver)
|
73
84
|
MailRoom::Delivery['letter_opener'].stubs(:new => letter_opener)
|
74
85
|
|
75
|
-
letter_opener.expects(:deliver).with(
|
86
|
+
letter_opener.expects(:deliver).with(sample_message.body)
|
76
87
|
|
77
|
-
mailbox.deliver(
|
88
|
+
mailbox.deliver(sample_message)
|
78
89
|
end
|
79
90
|
end
|
80
91
|
|
@@ -85,7 +96,7 @@ describe MailRoom::Mailbox do
|
|
85
96
|
MailRoom::Delivery['noop'].stubs(:new => noop)
|
86
97
|
noop.expects(:deliver).never
|
87
98
|
|
88
|
-
mailbox.deliver(
|
99
|
+
mailbox.deliver(MailRoom::Message.new(uid: 1234, body: nil))
|
89
100
|
end
|
90
101
|
end
|
91
102
|
|
@@ -125,5 +136,42 @@ describe MailRoom::Mailbox do
|
|
125
136
|
expect { build_mailbox({:host => nil}) }.to raise_error(MailRoom::ConfigurationError)
|
126
137
|
end
|
127
138
|
end
|
139
|
+
|
140
|
+
context "with Microsoft Graph configuration" do
|
141
|
+
let(:options) do
|
142
|
+
{
|
143
|
+
arbitration_method: 'redis',
|
144
|
+
}.merge(REQUIRED_MICROSOFT_GRAPH_DEFAULTS)
|
145
|
+
end
|
146
|
+
|
147
|
+
subject { build_mailbox(options) }
|
148
|
+
|
149
|
+
def delete_inbox_option(key)
|
150
|
+
options[:inbox_options] = options[:inbox_options].dup.delete(key)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'allows password omission' do
|
154
|
+
expect { subject }.not_to raise_error
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'configured as a Microsoft Graph inbox' do
|
158
|
+
expect(subject.imap?).to be false
|
159
|
+
expect(subject.microsoft_graph?).to be true
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'raises an error when the inbox options are not present' do
|
163
|
+
options.delete(:inbox_options)
|
164
|
+
|
165
|
+
expect { subject }.to raise_error(MailRoom::ConfigurationError)
|
166
|
+
end
|
167
|
+
|
168
|
+
%i[tenant_id client_id client_secret].each do |item|
|
169
|
+
it "raises an error when the #{item} is not present" do
|
170
|
+
delete_inbox_option(item)
|
171
|
+
|
172
|
+
expect { subject }.to raise_error(MailRoom::ConfigurationError)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
128
176
|
end
|
129
177
|
end
|
@@ -1,61 +1,77 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MailRoom::MailboxWatcher do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
context 'with IMAP configured' do
|
5
|
+
let(:mailbox) {build_mailbox}
|
6
|
+
|
7
|
+
describe '#running?' do
|
8
|
+
it 'is false by default' do
|
9
|
+
watcher = MailRoom::MailboxWatcher.new(mailbox)
|
10
|
+
expect(watcher.running?).to eq(false)
|
11
|
+
end
|
10
12
|
end
|
11
|
-
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
describe '#run' do
|
15
|
+
let(:imap) {stub(:login => true, :select => true)}
|
16
|
+
let(:watcher) {MailRoom::MailboxWatcher.new(mailbox)}
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
before :each do
|
19
|
+
Net::IMAP.stubs(:new).returns(imap) # prevent connection
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
it 'loops over wait while running' do
|
23
|
+
connection = MailRoom::IMAP::Connection.new(mailbox)
|
23
24
|
|
24
|
-
|
25
|
+
MailRoom::IMAP::Connection.stubs(:new).returns(connection)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
watcher.expects(:running?).twice.returns(true, false)
|
28
|
+
connection.expects(:wait).once
|
29
|
+
connection.expects(:on_new_message).once
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
watcher.run
|
32
|
+
watcher.watching_thread.join # wait for finishing run
|
33
|
+
end
|
32
34
|
end
|
33
|
-
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
describe '#quit' do
|
37
|
+
let(:imap) {stub(:login => true, :select => true)}
|
38
|
+
let(:watcher) {MailRoom::MailboxWatcher.new(mailbox)}
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
before :each do
|
41
|
+
Net::IMAP.stubs(:new).returns(imap) # prevent connection
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'closes and waits for the connection' do
|
45
|
+
connection = MailRoom::IMAP::Connection.new(mailbox)
|
46
|
+
connection.stubs(:wait)
|
47
|
+
connection.stubs(:quit)
|
42
48
|
|
43
|
-
|
44
|
-
connection = MailRoom::Connection.new(mailbox)
|
45
|
-
connection.stubs(:wait)
|
46
|
-
connection.stubs(:quit)
|
49
|
+
MailRoom::IMAP::Connection.stubs(:new).returns(connection)
|
47
50
|
|
48
|
-
|
51
|
+
watcher.run
|
52
|
+
|
53
|
+
expect(watcher.running?).to eq(true)
|
54
|
+
|
55
|
+
connection.expects(:quit)
|
56
|
+
|
57
|
+
watcher.quit
|
58
|
+
|
59
|
+
expect(watcher.running?).to eq(false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
49
63
|
|
50
|
-
|
64
|
+
context 'with Microsoft Graph configured' do
|
65
|
+
let(:mailbox) { build_mailbox(REQUIRED_MICROSOFT_GRAPH_DEFAULTS) }
|
51
66
|
|
52
|
-
|
67
|
+
subject { described_class.new(mailbox) }
|
53
68
|
|
54
|
-
|
69
|
+
it 'initializes a Microsoft Graph connection' do
|
70
|
+
connection = stub(on_new_message: nil)
|
55
71
|
|
56
|
-
|
72
|
+
MailRoom::MicrosoftGraph::Connection.stubs(:new).returns(connection)
|
57
73
|
|
58
|
-
expect(
|
74
|
+
expect(subject.send(:connection)).to eq(connection)
|
59
75
|
end
|
60
76
|
end
|
61
77
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
describe MailRoom::Message do
|
7
|
+
let(:uid) { SecureRandom.hex }
|
8
|
+
let(:body) { 'hello world' }
|
9
|
+
|
10
|
+
subject { described_class.new(uid: uid, body: body) }
|
11
|
+
|
12
|
+
describe '#initalize' do
|
13
|
+
it 'initializes with required parameters' do
|
14
|
+
subject
|
15
|
+
|
16
|
+
expect(subject.uid).to eq(uid)
|
17
|
+
expect(subject.body).to eq(body)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#==' do
|
22
|
+
let(:dup) { described_class.new(uid: uid, body: body) }
|
23
|
+
|
24
|
+
it 'matches an equivalent message' do
|
25
|
+
expect(dup == subject).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'does not match a message with a different UID' do
|
29
|
+
msg = described_class.new(uid: '12345', body: body)
|
30
|
+
|
31
|
+
expect(subject == msg).to be false
|
32
|
+
expect(msg == subject).to be false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'json'
|
6
|
+
require 'webmock/rspec'
|
7
|
+
|
8
|
+
describe MailRoom::MicrosoftGraph::Connection do
|
9
|
+
let(:tenant_id) { options[:inbox_options][:tenant_id] }
|
10
|
+
let(:options) do
|
11
|
+
{
|
12
|
+
delete_after_delivery: true,
|
13
|
+
expunge_deleted: true
|
14
|
+
}.merge(REQUIRED_MICROSOFT_GRAPH_DEFAULTS)
|
15
|
+
end
|
16
|
+
let(:mailbox) { build_mailbox(options) }
|
17
|
+
let(:base_url) { 'https://graph.microsoft.com/v1.0/users/user@example.com/mailFolders/inbox/messages' }
|
18
|
+
let(:message_base_url) { 'https://graph.microsoft.com/v1.0/users/user@example.com/messages' }
|
19
|
+
|
20
|
+
before do
|
21
|
+
WebMock.enable!
|
22
|
+
end
|
23
|
+
|
24
|
+
context '#wait' do
|
25
|
+
let(:connection) { described_class.new(mailbox) }
|
26
|
+
let(:uid) { 1 }
|
27
|
+
let(:access_token) { SecureRandom.hex }
|
28
|
+
let(:refresh_token) { SecureRandom.hex }
|
29
|
+
let(:expires_in) { Time.now + 3600 }
|
30
|
+
let(:unread_messages_body) { '' }
|
31
|
+
let(:status) { 200 }
|
32
|
+
let!(:stub_token) do
|
33
|
+
stub_request(:post, "https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token").to_return(
|
34
|
+
body: { 'access_token' => access_token, 'refresh_token' => refresh_token, 'expires_in' => expires_in }.to_json,
|
35
|
+
headers: { 'Content-Type' => 'application/json' }
|
36
|
+
)
|
37
|
+
end
|
38
|
+
let!(:stub_unread_messages_request) do
|
39
|
+
stub_request(:get, "#{base_url}?$filter=isRead%20eq%20false").to_return(
|
40
|
+
status: status,
|
41
|
+
body: unread_messages_body.to_json,
|
42
|
+
headers: { 'Content-Type' => 'application/json' }
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
before do
|
47
|
+
connection.stubs(:wait_for_new_messages)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'poll interval' do
|
51
|
+
it 'defaults to 60 seconds' do
|
52
|
+
expect(connection.send(:poll_interval)).to eq(60)
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'interval set to 10' do
|
56
|
+
let(:options) do
|
57
|
+
{
|
58
|
+
inbox_method: :microsoft_graph,
|
59
|
+
inbox_options: {
|
60
|
+
tenant_id: '98776',
|
61
|
+
client_id: '12345',
|
62
|
+
client_secret: 'MY-SECRET',
|
63
|
+
poll_interval: '10'
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'sets the poll interval to 10' do
|
69
|
+
expect(connection.send(:poll_interval)).to eq(10)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with a single message' do
|
75
|
+
let(:message_id) { SecureRandom.hex }
|
76
|
+
let(:unread_messages_body) { { value: ['id' => message_id] } }
|
77
|
+
let(:message_url) { "#{message_base_url}/#{message_id}" }
|
78
|
+
let(:message_body) { 'hello world' }
|
79
|
+
|
80
|
+
it 'requests message ID' do
|
81
|
+
stub_get = stub_request(:get, "#{message_url}/$value").to_return(
|
82
|
+
status: 200,
|
83
|
+
body: message_body
|
84
|
+
)
|
85
|
+
stub_patch = stub_request(:patch, message_url).with(body: { "isRead": true }.to_json)
|
86
|
+
stub_delete = stub_request(:delete, message_url)
|
87
|
+
message_count = 0
|
88
|
+
|
89
|
+
connection.on_new_message do |message|
|
90
|
+
message_count += 1
|
91
|
+
expect(message.uid).to eq(message_id)
|
92
|
+
expect(message.body).to eq(message_body)
|
93
|
+
end
|
94
|
+
|
95
|
+
connection.wait
|
96
|
+
|
97
|
+
assert_requested(stub_token)
|
98
|
+
assert_requested(stub_unread_messages_request)
|
99
|
+
assert_requested(stub_get)
|
100
|
+
assert_requested(stub_patch)
|
101
|
+
assert_requested(stub_delete)
|
102
|
+
expect(message_count).to eq(1)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with multiple pages of messages' do
|
107
|
+
let(:message_ids) { [SecureRandom.hex, SecureRandom.hex] }
|
108
|
+
let(:next_page_url) { 'https://graph.microsoft.com/v1.0/nextPage' }
|
109
|
+
let(:unread_messages_body) { { value: ['id' => message_ids.first], '@odata.nextLink' => next_page_url } }
|
110
|
+
let(:message_body) { 'hello world' }
|
111
|
+
|
112
|
+
it 'requests message ID' do
|
113
|
+
stub_request(:get, next_page_url).to_return(
|
114
|
+
status: 200,
|
115
|
+
body: { value: ['id' => message_ids[1]] }.to_json
|
116
|
+
)
|
117
|
+
|
118
|
+
stubs = []
|
119
|
+
message_ids.each do |message_id|
|
120
|
+
rfc822_msg_url = "#{message_base_url}/#{message_id}/$value"
|
121
|
+
stubs << stub_request(:get, rfc822_msg_url).to_return(
|
122
|
+
status: 200,
|
123
|
+
body: message_body
|
124
|
+
)
|
125
|
+
|
126
|
+
msg_url = "#{message_base_url}/#{message_id}"
|
127
|
+
stubs << stub_request(:patch, msg_url).with(body: { "isRead": true }.to_json)
|
128
|
+
stubs << stub_request(:delete, msg_url)
|
129
|
+
end
|
130
|
+
|
131
|
+
message_count = 0
|
132
|
+
|
133
|
+
connection.on_new_message do |message|
|
134
|
+
expect(message.uid).to eq(message_ids[message_count])
|
135
|
+
expect(message.body).to eq(message_body)
|
136
|
+
message_count += 1
|
137
|
+
end
|
138
|
+
|
139
|
+
connection.wait
|
140
|
+
|
141
|
+
stubs.each { |stub| assert_requested(stub) }
|
142
|
+
expect(message_count).to eq(2)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'too many requests' do
|
147
|
+
let(:status) { 429 }
|
148
|
+
|
149
|
+
it 'backs off' do
|
150
|
+
connection.expects(:backoff)
|
151
|
+
|
152
|
+
connection.on_new_message {}
|
153
|
+
connection.wait
|
154
|
+
|
155
|
+
expect(connection.throttled_count).to eq(1)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'invalid JSON response' do
|
160
|
+
let(:body) { 'this is something' }
|
161
|
+
|
162
|
+
it 'ignores the message and logs a warning' do
|
163
|
+
mailbox.logger.expects(:warn)
|
164
|
+
|
165
|
+
connection.on_new_message {}
|
166
|
+
connection.wait
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context '500 error' do
|
171
|
+
let(:status) { 500 }
|
172
|
+
|
173
|
+
it 'resets the state and logs a warning' do
|
174
|
+
connection.expects(:reset)
|
175
|
+
connection.expects(:setup)
|
176
|
+
mailbox.logger.expects(:warn)
|
177
|
+
|
178
|
+
connection.on_new_message {}
|
179
|
+
connection.wait
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|