postmark 1.18.0 → 1.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/postmark/api_client.rb +26 -1
- data/lib/postmark/version.rb +1 -1
- data/spec/integration/api_client_hashes_spec.rb +29 -35
- data/spec/integration/api_client_messages_spec.rb +16 -16
- data/spec/integration/api_client_resources_spec.rb +15 -31
- data/spec/spec_helper.rb +1 -7
- data/spec/support/custom_matchers.rb +6 -0
- data/spec/support/shared_examples.rb +16 -16
- data/spec/unit/postmark/account_api_client_spec.rb +1 -50
- data/spec/unit/postmark/api_client_spec.rb +51 -66
- data/spec/unit/postmark/bounce_spec.rb +37 -49
- data/spec/unit/postmark/client_spec.rb +0 -6
- data/spec/unit/postmark/error_spec.rb +44 -44
- data/spec/unit/postmark/handlers/mail_spec.rb +3 -3
- data/spec/unit/postmark/helpers/hash_helper_spec.rb +5 -6
- data/spec/unit/postmark/http_client_spec.rb +47 -49
- data/spec/unit/postmark/inbound_spec.rb +34 -34
- data/spec/unit/postmark/inflector_spec.rb +11 -13
- data/spec/unit/postmark/json_spec.rb +2 -2
- data/spec/unit/postmark/mail_message_converter_spec.rb +79 -82
- data/spec/unit/postmark_spec.rb +32 -32
- metadata +3 -3
@@ -1,13 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Postmark::Client do
|
4
|
-
|
5
4
|
subject { Postmark::Client.new('abcd-efgh') }
|
6
5
|
|
7
6
|
describe 'instance' do
|
8
|
-
|
9
7
|
describe '#find_each' do
|
10
|
-
|
11
8
|
let(:path) { 'resources' }
|
12
9
|
let(:name) { 'Resources' }
|
13
10
|
let(:response) {
|
@@ -44,9 +41,6 @@ describe Postmark::Client do
|
|
44
41
|
to receive(:get).exactly(5).times.and_return(response)
|
45
42
|
expect(subject.find_each(path, name, :count => 2).count).to eq(10)
|
46
43
|
end
|
47
|
-
|
48
44
|
end
|
49
|
-
|
50
45
|
end
|
51
|
-
|
52
46
|
end
|
@@ -1,47 +1,47 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe(Postmark::Error) do
|
4
|
-
it {
|
4
|
+
it {is_expected.to be_a(StandardError)}
|
5
5
|
end
|
6
6
|
|
7
7
|
describe(Postmark::HttpClientError) do
|
8
|
-
it {
|
9
|
-
it {
|
8
|
+
it {is_expected.to be_a(Postmark::Error)}
|
9
|
+
it {expect(subject.retry?).to be true}
|
10
10
|
end
|
11
11
|
|
12
12
|
describe(Postmark::HttpServerError) do
|
13
|
-
it {
|
13
|
+
it {is_expected.to be_a(Postmark::Error)}
|
14
14
|
|
15
15
|
describe '.build' do
|
16
16
|
context 'picks an appropriate subclass for code' do
|
17
|
-
subject {
|
17
|
+
subject {Postmark::HttpServerError.build(code, Postmark::Json.encode({}))}
|
18
18
|
|
19
19
|
context '401' do
|
20
|
-
let(:code) {
|
20
|
+
let(:code) {'401'}
|
21
21
|
|
22
|
-
it {
|
23
|
-
its(:status_code) {
|
22
|
+
it {is_expected.to be_a(Postmark::InvalidApiKeyError)}
|
23
|
+
its(:status_code) {is_expected.to eq 401}
|
24
24
|
end
|
25
25
|
|
26
26
|
context '422' do
|
27
|
-
let(:code) {
|
27
|
+
let(:code) {'422'}
|
28
28
|
|
29
|
-
it {
|
30
|
-
its(:status_code) {
|
29
|
+
it {is_expected.to be_a(Postmark::ApiInputError)}
|
30
|
+
its(:status_code) {is_expected.to eq 422}
|
31
31
|
end
|
32
32
|
|
33
33
|
context '500' do
|
34
|
-
let(:code) {
|
34
|
+
let(:code) {'500'}
|
35
35
|
|
36
|
-
it {
|
37
|
-
its(:status_code) {
|
36
|
+
it {is_expected.to be_a(Postmark::InternalServerError)}
|
37
|
+
its(:status_code) {is_expected.to eq 500}
|
38
38
|
end
|
39
39
|
|
40
40
|
context 'others' do
|
41
|
-
let(:code) {
|
41
|
+
let(:code) {'999'}
|
42
42
|
|
43
|
-
it {
|
44
|
-
its(:status_code) {
|
43
|
+
it {is_expected.to be_a(Postmark::UnexpectedHttpResponseError)}
|
44
|
+
its(:status_code) {is_expected.to eq code.to_i}
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -62,7 +62,7 @@ describe(Postmark::HttpServerError) do
|
|
62
62
|
|
63
63
|
describe '#message ' do
|
64
64
|
it 'uses "Message" field on postmark response if available' do
|
65
|
-
data = {
|
65
|
+
data = {'Message' => 'Postmark error message'}
|
66
66
|
error = Postmark::HttpServerError.new(502, Postmark::Json.encode(data), data)
|
67
67
|
expect(error.message).to eq data['Message']
|
68
68
|
end
|
@@ -77,28 +77,28 @@ end
|
|
77
77
|
describe(Postmark::ApiInputError) do
|
78
78
|
describe '.build' do
|
79
79
|
context 'picks an appropriate subclass for error code' do
|
80
|
-
let(:response) {
|
80
|
+
let(:response) {{'ErrorCode' => code}}
|
81
81
|
|
82
82
|
subject do
|
83
83
|
Postmark::ApiInputError.build(Postmark::Json.encode(response), response)
|
84
84
|
end
|
85
85
|
|
86
86
|
shared_examples_for 'api input error' do
|
87
|
-
its(:status_code) {
|
88
|
-
it {
|
89
|
-
it {
|
90
|
-
it {
|
87
|
+
its(:status_code) {is_expected.to eq 422}
|
88
|
+
it {expect(subject.retry?).to be false}
|
89
|
+
it {is_expected.to be_a(Postmark::ApiInputError)}
|
90
|
+
it {is_expected.to be_a(Postmark::HttpServerError)}
|
91
91
|
end
|
92
92
|
|
93
93
|
context '406' do
|
94
|
-
let(:code) {
|
94
|
+
let(:code) {Postmark::ApiInputError::INACTIVE_RECIPIENT}
|
95
95
|
|
96
|
-
it {
|
96
|
+
it {is_expected.to be_a(Postmark::InactiveRecipientError)}
|
97
97
|
it_behaves_like 'api input error'
|
98
98
|
end
|
99
99
|
|
100
100
|
context 'others' do
|
101
|
-
let(:code) {
|
101
|
+
let(:code) {'9999'}
|
102
102
|
|
103
103
|
it_behaves_like 'api input error'
|
104
104
|
end
|
@@ -107,7 +107,7 @@ describe(Postmark::ApiInputError) do
|
|
107
107
|
end
|
108
108
|
|
109
109
|
describe Postmark::InvalidTemplateError do
|
110
|
-
subject(:error) {
|
110
|
+
subject(:error) {Postmark::InvalidTemplateError.new(:foo => 'bar')}
|
111
111
|
|
112
112
|
it 'is created with a response' do
|
113
113
|
expect(error.message).to start_with('Failed to render the template.')
|
@@ -116,8 +116,8 @@ describe Postmark::InvalidTemplateError do
|
|
116
116
|
end
|
117
117
|
|
118
118
|
describe(Postmark::TimeoutError) do
|
119
|
-
it {
|
120
|
-
it {
|
119
|
+
it {is_expected.to be_a(Postmark::Error)}
|
120
|
+
it {expect(subject.retry?).to be true}
|
121
121
|
end
|
122
122
|
|
123
123
|
describe(Postmark::UnknownMessageType) do
|
@@ -127,19 +127,19 @@ describe(Postmark::UnknownMessageType) do
|
|
127
127
|
end
|
128
128
|
|
129
129
|
describe(Postmark::InvalidApiKeyError) do
|
130
|
-
it {
|
130
|
+
it {is_expected.to be_a(Postmark::Error)}
|
131
131
|
end
|
132
132
|
|
133
133
|
describe(Postmark::InternalServerError) do
|
134
|
-
it {
|
134
|
+
it {is_expected.to be_a(Postmark::Error)}
|
135
135
|
end
|
136
136
|
|
137
137
|
describe(Postmark::UnexpectedHttpResponseError) do
|
138
|
-
it {
|
138
|
+
it {is_expected.to be_a(Postmark::Error)}
|
139
139
|
end
|
140
140
|
|
141
141
|
describe(Postmark::MailAdapterError) do
|
142
|
-
it {
|
142
|
+
it {is_expected.to be_a(Postmark::Error)}
|
143
143
|
end
|
144
144
|
|
145
145
|
describe(Postmark::InactiveRecipientError) do
|
@@ -148,7 +148,7 @@ describe(Postmark::InactiveRecipientError) do
|
|
148
148
|
%w(nothing@wildbit.com noth.ing+2@wildbit.com noth.ing+2-1@wildbit.com)
|
149
149
|
end
|
150
150
|
|
151
|
-
subject {
|
151
|
+
subject {Postmark::InactiveRecipientError.parse_recipients(message)}
|
152
152
|
|
153
153
|
context '1/1 inactive' do
|
154
154
|
let(:message) do
|
@@ -158,7 +158,7 @@ describe(Postmark::InactiveRecipientError) do
|
|
158
158
|
'bounce or a spam complaint.'
|
159
159
|
end
|
160
160
|
|
161
|
-
it {
|
161
|
+
it {is_expected.to eq(recipients.take(1))}
|
162
162
|
end
|
163
163
|
|
164
164
|
context 'i/n inactive, n > 1, i < n' do
|
@@ -168,7 +168,7 @@ describe(Postmark::InactiveRecipientError) do
|
|
168
168
|
'have generated a hard bounce or a spam complaint.'
|
169
169
|
end
|
170
170
|
|
171
|
-
it {
|
171
|
+
it {is_expected.to eq(recipients.take(2))}
|
172
172
|
end
|
173
173
|
|
174
174
|
context 'n/n inactive, n > 1' do
|
@@ -178,25 +178,25 @@ describe(Postmark::InactiveRecipientError) do
|
|
178
178
|
'Inactive recipients are ones that have generated a hard bounce or a spam complaint.'
|
179
179
|
end
|
180
180
|
|
181
|
-
it {
|
181
|
+
it {is_expected.to eq(recipients)}
|
182
182
|
end
|
183
183
|
|
184
184
|
context 'unknown error format' do
|
185
|
-
let(:message) {
|
185
|
+
let(:message) {recipients.join(', ')}
|
186
186
|
|
187
|
-
it {
|
187
|
+
it {is_expected.to eq([])}
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
191
191
|
describe '.new' do
|
192
|
-
let(:address) {
|
193
|
-
let(:response) {
|
192
|
+
let(:address) {'user@example.org'}
|
193
|
+
let(:response) {{'Message' => message}}
|
194
194
|
|
195
195
|
subject do
|
196
196
|
Postmark::InactiveRecipientError.new(
|
197
|
-
|
198
|
-
|
199
|
-
|
197
|
+
Postmark::ApiInputError::INACTIVE_RECIPIENT,
|
198
|
+
Postmark::Json.encode(response),
|
199
|
+
response)
|
200
200
|
end
|
201
201
|
|
202
202
|
let(:message) do
|
@@ -25,18 +25,18 @@ describe Mail::Postmark do
|
|
25
25
|
describe '#deliver!' do
|
26
26
|
it "returns self by default" do
|
27
27
|
expect_any_instance_of(Postmark::ApiClient).to receive(:deliver_message).with(message)
|
28
|
-
message.deliver.
|
28
|
+
expect(message.deliver).to eq message
|
29
29
|
end
|
30
30
|
|
31
31
|
it "returns the actual response if :return_response setting is present" do
|
32
32
|
expect_any_instance_of(Postmark::ApiClient).to receive(:deliver_message).with(message)
|
33
33
|
message.delivery_method Mail::Postmark, :return_response => true
|
34
|
-
message.deliver.
|
34
|
+
expect(message.deliver).to eq message
|
35
35
|
end
|
36
36
|
|
37
37
|
it "allows setting the api token" do
|
38
38
|
message.delivery_method Mail::Postmark, :api_token => 'api-token'
|
39
|
-
message.delivery_method.settings[:api_token].
|
39
|
+
expect(message.delivery_method.settings[:api_token]).to eq 'api-token'
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'uses provided API token' do
|
@@ -6,11 +6,11 @@ describe Postmark::HashHelper do
|
|
6
6
|
let(:target) { {"From" => "support@postmarkapp.com", "ReplyTo" => "contact@wildbit.com"} }
|
7
7
|
|
8
8
|
it 'converts Hash keys to Postmark format' do
|
9
|
-
subject.to_postmark(source).
|
9
|
+
expect(subject.to_postmark(source)).to eq target
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'acts idempotentely' do
|
13
|
-
subject.to_postmark(target).
|
13
|
+
expect(subject.to_postmark(target)).to eq target
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -19,16 +19,15 @@ describe Postmark::HashHelper do
|
|
19
19
|
let(:target) { {:from => "support@postmarkapp.com", :reply_to => "contact@wildbit.com"} }
|
20
20
|
|
21
21
|
it 'converts Hash keys to Ruby format' do
|
22
|
-
subject.to_ruby(source).
|
22
|
+
expect(subject.to_ruby(source)).to eq target
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'has compatible mode' do
|
26
|
-
subject.to_ruby(source, true).
|
26
|
+
expect(subject.to_ruby(source, true)).to eq target.merge(source)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'acts idempotentely' do
|
30
|
-
subject.to_ruby(target).
|
30
|
+
expect(subject.to_ruby(target)).to eq target
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
34
33
|
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Postmark::HttpClient do
|
4
4
|
|
5
5
|
def response_body(status, message = "")
|
6
|
-
|
6
|
+
{"ErrorCode" => status, "Message" => message}.to_json
|
7
7
|
end
|
8
8
|
|
9
9
|
let(:api_token) { "provided-postmark-api-token" }
|
@@ -11,39 +11,39 @@ describe Postmark::HttpClient do
|
|
11
11
|
subject { http_client }
|
12
12
|
|
13
13
|
context "attr writers" do
|
14
|
-
it {
|
15
|
-
it {
|
14
|
+
it { expect(subject).to respond_to(:api_token=) }
|
15
|
+
it { expect(subject).to respond_to(:api_key=) }
|
16
16
|
end
|
17
17
|
|
18
18
|
context "attr readers" do
|
19
|
-
it {
|
20
|
-
it {
|
21
|
-
it {
|
22
|
-
it {
|
23
|
-
it {
|
24
|
-
it {
|
25
|
-
it {
|
26
|
-
it {
|
27
|
-
it {
|
28
|
-
it {
|
29
|
-
it {
|
30
|
-
it {
|
31
|
-
it {
|
19
|
+
it { expect(subject).to respond_to(:http) }
|
20
|
+
it { expect(subject).to respond_to(:secure) }
|
21
|
+
it { expect(subject).to respond_to(:api_token) }
|
22
|
+
it { expect(subject).to respond_to(:api_key) }
|
23
|
+
it { expect(subject).to respond_to(:proxy_host) }
|
24
|
+
it { expect(subject).to respond_to(:proxy_port) }
|
25
|
+
it { expect(subject).to respond_to(:proxy_user) }
|
26
|
+
it { expect(subject).to respond_to(:proxy_pass) }
|
27
|
+
it { expect(subject).to respond_to(:host) }
|
28
|
+
it { expect(subject).to respond_to(:port) }
|
29
|
+
it { expect(subject).to respond_to(:path_prefix) }
|
30
|
+
it { expect(subject).to respond_to(:http_open_timeout) }
|
31
|
+
it { expect(subject).to respond_to(:http_read_timeout) }
|
32
32
|
end
|
33
33
|
|
34
34
|
context "when it is created without options" do
|
35
|
-
its(:api_token) {
|
36
|
-
its(:api_key) {
|
37
|
-
its(:host) {
|
38
|
-
its(:port) {
|
39
|
-
its(:secure) {
|
40
|
-
its(:path_prefix) {
|
41
|
-
its(:http_read_timeout) {
|
42
|
-
its(:http_open_timeout) {
|
35
|
+
its(:api_token) { is_expected.to eq api_token }
|
36
|
+
its(:api_key) { is_expected.to eq api_token }
|
37
|
+
its(:host) { is_expected.to eq 'api.postmarkapp.com' }
|
38
|
+
its(:port) { is_expected.to eq 443 }
|
39
|
+
its(:secure) { is_expected.to be true }
|
40
|
+
its(:path_prefix) { is_expected.to eq '/' }
|
41
|
+
its(:http_read_timeout) { is_expected.to eq 15 }
|
42
|
+
its(:http_open_timeout) { is_expected.to eq 5 }
|
43
43
|
|
44
44
|
it 'uses TLS encryption', :skip_ruby_version => ['1.8.7'] do
|
45
45
|
http_client = subject.http
|
46
|
-
http_client.ssl_version.
|
46
|
+
expect(http_client.ssl_version).to eq :TLSv1
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -71,18 +71,18 @@ describe Postmark::HttpClient do
|
|
71
71
|
:http_open_timeout => http_open_timeout,
|
72
72
|
:http_read_timeout => http_read_timeout) }
|
73
73
|
|
74
|
-
its(:api_token) {
|
75
|
-
its(:api_key) {
|
76
|
-
its(:secure) {
|
77
|
-
its(:proxy_host) {
|
78
|
-
its(:proxy_port) {
|
79
|
-
its(:proxy_user) {
|
80
|
-
its(:proxy_pass) {
|
81
|
-
its(:host) {
|
82
|
-
its(:port) {
|
83
|
-
its(:path_prefix) {
|
84
|
-
its(:http_open_timeout) {
|
85
|
-
its(:http_read_timeout) {
|
74
|
+
its(:api_token) { is_expected.to eq api_token }
|
75
|
+
its(:api_key) { is_expected.to eq api_token }
|
76
|
+
its(:secure) { is_expected.to eq secure }
|
77
|
+
its(:proxy_host) { is_expected.to eq proxy_host }
|
78
|
+
its(:proxy_port) { is_expected.to eq proxy_port }
|
79
|
+
its(:proxy_user) { is_expected.to eq proxy_user }
|
80
|
+
its(:proxy_pass) { is_expected.to eq proxy_pass }
|
81
|
+
its(:host) { is_expected.to eq host }
|
82
|
+
its(:port) { is_expected.to eq port }
|
83
|
+
its(:path_prefix) { is_expected.to eq path_prefix }
|
84
|
+
its(:http_open_timeout) { is_expected.to eq http_open_timeout }
|
85
|
+
its(:http_read_timeout) { is_expected.to eq http_read_timeout }
|
86
86
|
|
87
87
|
it 'uses port 80 for plain HTTP connections' do
|
88
88
|
expect(Postmark::HttpClient.new(api_token, :secure => false).port).to eq(80)
|
@@ -106,18 +106,17 @@ describe Postmark::HttpClient do
|
|
106
106
|
it "sends a POST request to provided URI" do
|
107
107
|
FakeWeb.register_uri(:post, target_url, :body => response_body(200))
|
108
108
|
subject.post(target_path)
|
109
|
-
FakeWeb.
|
109
|
+
expect(FakeWeb.last_request.method).to eq('POST')
|
110
|
+
expect(FakeWeb.last_request.path).to eq('/' + target_path)
|
110
111
|
end
|
111
112
|
|
112
113
|
it "raises a custom error when API token authorization fails" do
|
113
|
-
FakeWeb.register_uri(:post, target_url, :body => response_body(401),
|
114
|
-
:status => [ "401", "Unauthorized" ])
|
114
|
+
FakeWeb.register_uri(:post, target_url, :body => response_body(401), :status => [ "401", "Unauthorized" ])
|
115
115
|
expect { subject.post(target_path) }.to raise_error Postmark::InvalidApiKeyError
|
116
116
|
end
|
117
117
|
|
118
118
|
it "raises a custom error when sent JSON was not valid" do
|
119
|
-
FakeWeb.register_uri(:post, target_url, :body => response_body(422),
|
120
|
-
:status => [ "422", "Invalid" ])
|
119
|
+
FakeWeb.register_uri(:post, target_url, :body => response_body(422), :status => [ "422", "Invalid" ])
|
121
120
|
expect { subject.post(target_path) }.to raise_error Postmark::InvalidMessageError
|
122
121
|
end
|
123
122
|
|
@@ -147,18 +146,17 @@ describe Postmark::HttpClient do
|
|
147
146
|
it "sends a GET request to provided URI" do
|
148
147
|
FakeWeb.register_uri(:get, target_url, :body => response_body(200))
|
149
148
|
subject.get(target_path)
|
150
|
-
FakeWeb.
|
149
|
+
expect(FakeWeb.last_request.method).to eq('GET')
|
150
|
+
expect(FakeWeb.last_request.path).to eq('/' + target_path)
|
151
151
|
end
|
152
152
|
|
153
153
|
it "raises a custom error when API token authorization fails" do
|
154
|
-
FakeWeb.register_uri(:get, target_url, :body => response_body(401),
|
155
|
-
:status => [ "401", "Unauthorized" ])
|
154
|
+
FakeWeb.register_uri(:get, target_url, :body => response_body(401), :status => [ "401", "Unauthorized" ])
|
156
155
|
expect { subject.get(target_path) }.to raise_error Postmark::InvalidApiKeyError
|
157
156
|
end
|
158
157
|
|
159
158
|
it "raises a custom error when sent JSON was not valid" do
|
160
|
-
FakeWeb.register_uri(:get, target_url, :body => response_body(422),
|
161
|
-
:status => [ "422", "Invalid" ])
|
159
|
+
FakeWeb.register_uri(:get, target_url, :body => response_body(422), :status => [ "422", "Invalid" ])
|
162
160
|
expect { subject.get(target_path) }.to raise_error Postmark::InvalidMessageError
|
163
161
|
end
|
164
162
|
|
@@ -188,7 +186,8 @@ describe Postmark::HttpClient do
|
|
188
186
|
it "sends a PUT request to provided URI" do
|
189
187
|
FakeWeb.register_uri(:put, target_url, :body => response_body(200))
|
190
188
|
subject.put(target_path)
|
191
|
-
FakeWeb.
|
189
|
+
expect(FakeWeb.last_request.method).to eq('PUT')
|
190
|
+
expect(FakeWeb.last_request.path).to eq('/' + target_path)
|
192
191
|
end
|
193
192
|
|
194
193
|
it "raises a custom error when API token authorization fails" do
|
@@ -219,6 +218,5 @@ describe Postmark::HttpClient do
|
|
219
218
|
:status => [ "485", "Custom HTTP response status" ])
|
220
219
|
expect { subject.put(target_path) }.to raise_error Postmark::UnknownError
|
221
220
|
end
|
222
|
-
|
223
221
|
end
|
224
222
|
end
|