postmark 1.18.0 → 1.19.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.
- 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
|