mailgun-ruby 1.4.1 → 1.4.3

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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +30 -8
  3. data/.rubocop.yml +64 -4
  4. data/Gemfile +3 -1
  5. data/README.md +1 -1
  6. data/Rakefile +5 -8
  7. data/docs/AnalyticsTags.md +63 -0
  8. data/lib/mailgun/address.rb +5 -5
  9. data/lib/mailgun/chains.rb +2 -3
  10. data/lib/mailgun/client.rb +56 -56
  11. data/lib/mailgun/domains/domains.rb +11 -10
  12. data/lib/mailgun/events/events.rb +4 -3
  13. data/lib/mailgun/exceptions/exceptions.rb +12 -15
  14. data/lib/mailgun/helpers/api_version_checker.rb +6 -1
  15. data/lib/mailgun/lists/opt_in_handler.rb +6 -10
  16. data/lib/mailgun/logs/logs.rb +4 -2
  17. data/lib/mailgun/messages/batch_message.rb +10 -10
  18. data/lib/mailgun/messages/message_builder.rb +40 -56
  19. data/lib/mailgun/metrics/metrics.rb +12 -6
  20. data/lib/mailgun/response.rb +12 -10
  21. data/lib/mailgun/subaccounts/subaccounts.rb +13 -8
  22. data/lib/mailgun/suppressions.rb +36 -43
  23. data/lib/mailgun/tags/analytics_tags.rb +37 -2
  24. data/lib/mailgun/tags/tags.rb +29 -19
  25. data/lib/mailgun/templates/templates.rb +40 -29
  26. data/lib/mailgun/version.rb +3 -1
  27. data/lib/mailgun/webhooks/webhooks.rb +22 -19
  28. data/lib/mailgun-ruby.rb +2 -0
  29. data/lib/mailgun.rb +4 -4
  30. data/lib/railgun/attachment.rb +12 -19
  31. data/lib/railgun/errors.rb +2 -3
  32. data/lib/railgun/mailer.rb +37 -41
  33. data/lib/railgun/railtie.rb +2 -0
  34. data/lib/railgun.rb +2 -0
  35. data/mailgun.gemspec +15 -11
  36. data/spec/integration/analytics_tags_spec.rb +54 -0
  37. data/spec/integration/bounces_spec.rb +12 -11
  38. data/spec/integration/campaign_spec.rb +20 -18
  39. data/spec/integration/complaints_spec.rb +8 -6
  40. data/spec/integration/domains_spec.rb +12 -18
  41. data/spec/integration/email_validation_spec.rb +35 -34
  42. data/spec/integration/events_spec.rb +8 -8
  43. data/spec/integration/list_members_spec.rb +27 -26
  44. data/spec/integration/list_spec.rb +22 -21
  45. data/spec/integration/logs_spec.rb +49 -47
  46. data/spec/integration/mailer_spec.rb +7 -3
  47. data/spec/integration/mailgun_spec.rb +85 -92
  48. data/spec/integration/metrics_spec.rb +137 -131
  49. data/spec/integration/routes_spec.rb +41 -40
  50. data/spec/integration/stats_spec.rb +4 -2
  51. data/spec/integration/subaccounts_spec.rb +9 -10
  52. data/spec/integration/suppressions_spec.rb +222 -44
  53. data/spec/integration/templates_spec.rb +14 -12
  54. data/spec/integration/unsubscribes_spec.rb +8 -6
  55. data/spec/integration/webhook_spec.rb +18 -12
  56. data/spec/spec_helper.rb +15 -8
  57. data/spec/unit/client_spec.rb +424 -0
  58. data/spec/unit/connection/test_client.rb +108 -55
  59. data/spec/unit/events/events_spec.rb +48 -29
  60. data/spec/unit/exceptions/exceptions_spec.rb +8 -7
  61. data/spec/unit/helpers/api_version_checker_spec.rb +206 -0
  62. data/spec/unit/lists/opt_in_handler_spec.rb +11 -7
  63. data/spec/unit/mailgun_spec.rb +71 -68
  64. data/spec/unit/messages/batch_message_spec.rb +37 -36
  65. data/spec/unit/messages/message_builder_spec.rb +170 -169
  66. data/spec/unit/railgun/content_type_spec.rb +31 -30
  67. data/spec/unit/railgun/mailer_spec.rb +62 -59
  68. data/spec/unit/response_spec.rb +225 -0
  69. data/vcr_cassettes/For_the_suppressions_handling_class/creates_a_single_bounce.yml +55 -0
  70. data/vcr_cassettes/analytics_tags.yml +187 -0
  71. data/vcr_cassettes/suppressions.yml +1053 -170
  72. metadata +95 -29
  73. data/.rubocop_todo.yml +0 -22
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'mailgun'
3
5
 
4
- vcr_opts = { :cassette_name => "unsubscribes" }
6
+ vcr_opts = { cassette_name: 'unsubscribes' }
5
7
 
6
8
  describe 'For the Unsubscribes endpoint', order: :defined, vcr: vcr_opts do
7
9
  before(:all) do
@@ -14,22 +16,22 @@ describe 'For the Unsubscribes endpoint', order: :defined, vcr: vcr_opts do
14
16
  result = @mg_obj.post "#{@domain}/unsubscribes", address: @email, tag: '*'
15
17
 
16
18
  result.to_h!
17
- expect(result.body["message"]).to eq("Address has been added to the unsubscribes table")
18
- expect(result.body["address"]).to eq(@email)
19
+ expect(result.body['message']).to eq('Address has been added to the unsubscribes table')
20
+ expect(result.body['address']).to eq(@email)
19
21
  end
20
22
 
21
23
  it 'get an unsubscribee.' do
22
24
  result = @mg_obj.get "#{@domain}/unsubscribes/#{@email}"
23
25
 
24
26
  result.to_h!
25
- expect(result.body["address"]).to eq(@email)
27
+ expect(result.body['address']).to eq(@email)
26
28
  end
27
29
 
28
30
  it 'gets a list of unsubscribes.' do
29
31
  result = @mg_obj.get "#{@domain}/unsubscribes"
30
32
 
31
33
  result.to_h!
32
- expect(result.body["items"].length).to be > 0
34
+ expect(result.body['items'].length).to be > 0
33
35
  end
34
36
 
35
37
  it 'removes an unsubscribee' do
@@ -37,6 +39,6 @@ describe 'For the Unsubscribes endpoint', order: :defined, vcr: vcr_opts do
37
39
 
38
40
  result.to_h!
39
41
  expect(result.body['address']).to eq(@email)
40
- expect(result.body["message"]).to eq("Unsubscribe event has been removed")
42
+ expect(result.body['message']).to eq('Unsubscribe event has been removed')
41
43
  end
42
44
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'mailgun'
3
5
 
4
- vcr_opts = { :cassette_name => "webhooks" }
6
+ vcr_opts = { cassette_name: 'webhooks' }
5
7
 
6
8
  describe 'For the webhooks endpoint', order: :defined, vcr: vcr_opts do
7
9
  before(:all) do
@@ -13,42 +15,46 @@ describe 'For the webhooks endpoint', order: :defined, vcr: vcr_opts do
13
15
 
14
16
  it 'creates a webhook' do
15
17
  result = @mg_obj.post("domains/#{@domain}/webhooks", { id: @testhook,
16
- url: "http://example.com/mailgun/events/#{@testhook}" } )
18
+ url: "http://example.com/mailgun/events/#{@testhook}" })
17
19
 
18
20
  result.to_h!
19
- expect(result.body["message"]).to eq("Webhook has been created")
20
- expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
21
+ expect(result.body['message']).to eq('Webhook has been created')
22
+ expect(result.body['webhook']['urls']).to include("http://example.com/mailgun/events/#{@testhook}")
21
23
  end
22
24
 
23
25
  it 'gets a webhook.' do
24
26
  result = @mg_obj.get("domains/#{@domain}/webhooks/#{@testhook}")
25
27
 
26
28
  result.to_h!
27
- expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
29
+ expect(result.body['webhook']['urls']).to include("http://example.com/mailgun/events/#{@testhook}")
28
30
  end
29
31
 
30
32
  it 'gets a list of all webhooks.' do
31
33
  result = @mg_obj.get("domains/#{@domain}/webhooks")
32
34
 
33
35
  result.to_h!
34
- expect(result.body["webhooks"]["accepted"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
36
+ expect(result.body['webhooks']['accepted']['urls']).to include("http://example.com/mailgun/events/#{@testhook}")
35
37
  end
36
38
 
37
39
  it 'updates a webhook.' do
38
- result = @mg_obj.put("domains/#{@domain}/webhooks/#{@testhook}", {:id => @testhook,
39
- :url => "http://example.com/mailgun/events/#{@testhookup}"})
40
+ result = @mg_obj.put(
41
+ "domains/#{@domain}/webhooks/#{@testhook}",
42
+ {
43
+ id: @testhook,
44
+ url: "http://example.com/mailgun/events/#{@testhookup}"
45
+ }
46
+ )
40
47
 
41
48
  result.to_h!
42
- expect(result.body["message"]).to eq("Webhook has been updated")
43
- expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhookup}")
49
+ expect(result.body['message']).to eq('Webhook has been updated')
50
+ expect(result.body['webhook']['urls']).to include("http://example.com/mailgun/events/#{@testhookup}")
44
51
  end
45
52
 
46
53
  it 'removes a webhook' do
47
54
  result = @mg_obj.delete("domains/#{@domain}/webhooks/#{@testhook}")
48
55
 
49
56
  result.to_h!
50
- expect(result.body['message']).to eq("Webhook has been deleted")
57
+ expect(result.body['message']).to eq('Webhook has been deleted')
51
58
  expect(result.body['webhook']['urls']).to include("http://example.com/mailgun/events/#{@testhookup}")
52
59
  end
53
-
54
60
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'simplecov'
4
+ require 'simplecov-json'
5
+ SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
6
+ [
7
+ SimpleCov::Formatter::HTMLFormatter,
8
+ SimpleCov::Formatter::JSONFormatter
9
+ ]
10
+ )
2
11
 
3
12
  SimpleCov.start do
4
- add_filter "/spec/"
13
+ add_filter '/spec/'
5
14
  end
6
15
 
7
16
  require 'mailgun'
@@ -10,22 +19,20 @@ require 'vcr'
10
19
  require 'webmock/rspec'
11
20
  require 'rspec/its'
12
21
 
13
- #WebMock.disable_net_connect!(allow_localhost: true)
22
+ # WebMock.disable_net_connect!(allow_localhost: true)
14
23
  require_relative 'unit/connection/test_client'
15
24
 
16
- RSpec.configure do |c|
17
- c.raise_errors_for_deprecations!
18
- end
25
+ RSpec.configure(&:raise_errors_for_deprecations!)
19
26
 
20
- APIHOST = "api.mailgun.net"
21
- APIVERSION = "v3"
27
+ APIHOST = 'api.mailgun.net'
28
+ APIVERSION = 'v3'
22
29
  SSL = true
23
30
 
24
31
  # For integration tests modify .ruby-env.yml
25
32
  # use .ruby-env.yml.example for an example
26
33
  # alternatively
27
34
  # set environment variables as named in .ruby-env.yml.example
28
- envfile = File.join(File.dirname(__FILE__), '..','.ruby-env.yml')
35
+ envfile = File.join(File.dirname(__FILE__), '..', '.ruby-env.yml')
29
36
  envs = File.exist?(envfile) ? YAML.load_file(envfile) : ENV
30
37
  APIKEY = envs['MAILGUN_APIKEY']
31
38
  PUB_APIKEY = envs['MAILGUN_PUB_APIKEY']
@@ -0,0 +1,424 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mailgun'
5
+ require 'mailgun/exceptions/exceptions'
6
+
7
+ describe Mailgun::Client do
8
+ # ---------------------------------------------------------------------------
9
+ # Shared helpers
10
+ # ---------------------------------------------------------------------------
11
+ # Build a client in test mode so no real HTTP calls are ever made.
12
+ subject(:client) { described_class.new(api_key, 'api.mailgun.net', 'v3', true, true) }
13
+
14
+ let(:api_key) { 'test-api-key-abc123' }
15
+ let(:message_params) do
16
+ {
17
+ from: 'bob@example.com',
18
+ to: 'sally@example.com',
19
+ subject: 'Hello!',
20
+ text: 'Test body.'
21
+ }
22
+ end
23
+ let(:domain) { 'example.com' }
24
+
25
+ # Fake HTTP response double reusable across examples
26
+ def fake_http_response(body: '{"message":"ok"}', status: 200)
27
+ double('http_response', body: body, status: status)
28
+ end
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # .new / #initialize
32
+ # ---------------------------------------------------------------------------
33
+ describe '#initialize' do
34
+ it 'instantiates without raising' do
35
+ expect { described_class.new(api_key) }.not_to raise_error
36
+ end
37
+
38
+ it 'stores the api_version' do
39
+ c = described_class.new(api_key, 'api.mailgun.net', 'v3')
40
+ expect(c.api_version).to eq('v3')
41
+ end
42
+
43
+ it 'defaults test_mode to false when not specified' do
44
+ # Pass test_mode = false explicitly to avoid picking up global config
45
+ c = described_class.new(api_key, 'api.mailgun.net', 'v3', true, false)
46
+ expect(c.test_mode?).to be(false)
47
+ end
48
+
49
+ it 'accepts test_mode = true' do
50
+ c = described_class.new(api_key, 'api.mailgun.net', nil, true, true)
51
+ expect(c.test_mode?).to be(true)
52
+ end
53
+
54
+ it 'supports EU api host' do
55
+ expect { described_class.new(api_key, 'api.eu.mailgun.net') }.not_to raise_error
56
+ end
57
+ end
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # #test_mode?
61
+ # ---------------------------------------------------------------------------
62
+ describe '#test_mode?' do
63
+ it 'returns true when the client is in test mode' do
64
+ expect(client.test_mode?).to be(true)
65
+ end
66
+
67
+ it 'returns false when test mode has been disabled' do
68
+ client.disable_test_mode!
69
+ expect(client.test_mode?).to be(false)
70
+ end
71
+ end
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # #enable_test_mode!
75
+ # ---------------------------------------------------------------------------
76
+ describe '#enable_test_mode!' do
77
+ subject(:non_test_client) do
78
+ described_class.new(api_key, 'api.mailgun.net', 'v3', true, false)
79
+ end
80
+
81
+ it 'sets test_mode to true' do
82
+ non_test_client.enable_test_mode!
83
+ expect(non_test_client.test_mode?).to be(true)
84
+ end
85
+ end
86
+
87
+ # ---------------------------------------------------------------------------
88
+ # #disable_test_mode!
89
+ # ---------------------------------------------------------------------------
90
+ describe '#disable_test_mode!' do
91
+ it 'sets test_mode to false' do
92
+ client.disable_test_mode!
93
+ expect(client.test_mode?).to be(false)
94
+ end
95
+ end
96
+
97
+ # ---------------------------------------------------------------------------
98
+ # .deliveries
99
+ # ---------------------------------------------------------------------------
100
+ describe '.deliveries' do
101
+ before { described_class.deliveries.clear }
102
+
103
+ it 'returns an Array' do
104
+ expect(described_class.deliveries).to be_an(Array)
105
+ end
106
+
107
+ it 'accumulates messages sent in test mode' do
108
+ client.send_message(domain, message_params)
109
+ expect(described_class.deliveries).not_to be_empty
110
+ end
111
+
112
+ it 'stores the message data sent in test mode' do
113
+ client.send_message(domain, message_params)
114
+ expect(described_class.deliveries.last).to include(from: 'bob@example.com')
115
+ end
116
+
117
+ it 'accumulates multiple deliveries' do
118
+ 2.times { client.send_message(domain, message_params) }
119
+ expect(described_class.deliveries.size).to eq(2)
120
+ end
121
+ end
122
+
123
+ # ---------------------------------------------------------------------------
124
+ # #send_message — test mode
125
+ # ---------------------------------------------------------------------------
126
+ describe '#send_message (test mode)' do
127
+ before { described_class.deliveries.clear }
128
+
129
+ it 'returns a Mailgun::Response' do
130
+ result = client.send_message(domain, message_params)
131
+ expect(result).to be_a(Mailgun::Response)
132
+ end
133
+
134
+ it 'returns a 200 status response in test mode' do
135
+ result = client.send_message(domain, message_params)
136
+ expect(result.code).to eq(200)
137
+ end
138
+
139
+ it 'returns a body containing the Queued message in test mode' do
140
+ result = client.send_message(domain, message_params)
141
+ body = JSON.parse(result.body)
142
+ expect(body['message']).to eq('Queued. Thank you.')
143
+ end
144
+
145
+ it 'returns a body with a unique test-mode message id' do
146
+ result = client.send_message(domain, message_params)
147
+ body = JSON.parse(result.body)
148
+ expect(body['id']).to match(/test-mode-mail-.+@localhost/)
149
+ end
150
+
151
+ it 'does not make real HTTP calls in test mode' do
152
+ expect(client.instance_variable_get(:@http_client)).not_to receive(:post)
153
+ client.send_message(domain, message_params)
154
+ end
155
+
156
+ it 'records a copy of message data in .deliveries' do
157
+ client.send_message(domain, message_params)
158
+ expect(described_class.deliveries.last[:subject]).to eq('Hello!')
159
+ end
160
+
161
+ context 'with a MessageBuilder object' do
162
+ it 'stores the MessageBuilder in .deliveries' do
163
+ mb = Mailgun::MessageBuilder.new
164
+ mb.set_from_address('bob@example.com')
165
+ mb.add_recipient(:to, 'sally@example.com')
166
+ mb.set_subject('Hello via builder!')
167
+ mb.set_text_body('Body text.')
168
+
169
+ result = client.send_message(domain, mb)
170
+ expect(result).to be_a(Mailgun::Response)
171
+ expect(described_class.deliveries.last).to be_a(Mailgun::MessageBuilder)
172
+ end
173
+
174
+ it 'raises a Mailgun::ParameterError when mb is empty' do
175
+ mb = Mailgun::MessageBuilder.new
176
+
177
+ expect { client.send_message(domain, mb) }
178
+ .to raise_error(Mailgun::ParameterError)
179
+ end
180
+
181
+ it 'raises a Mailgun::ParameterError when from is missing' do
182
+ mb = Mailgun::MessageBuilder.new
183
+ mb.add_recipient(:to, 'sally@example.com')
184
+
185
+ expect { client.send_message(domain, mb) }
186
+ .to raise_error(Mailgun::ParameterError)
187
+ end
188
+ end
189
+ end
190
+
191
+ # ---------------------------------------------------------------------------
192
+ # #send_message — live mode (HTTP mocked at the Faraday level)
193
+ # ---------------------------------------------------------------------------
194
+ describe '#send_message (live mode)' do
195
+ subject(:live_client) do
196
+ described_class.new(api_key, 'api.mailgun.net', 'v3', true, false)
197
+ end
198
+
199
+ let(:success_response) { fake_http_response }
200
+
201
+ before do
202
+ allow(live_client.instance_variable_get(:@http_client))
203
+ .to receive(:post)
204
+ .and_return(success_response)
205
+ end
206
+
207
+ it 'posts to the messages endpoint and returns a Response' do
208
+ result = live_client.send_message(domain, message_params)
209
+ expect(result).to be_a(Mailgun::Response)
210
+ end
211
+
212
+ it 'strips nil values from the data hash before posting' do
213
+ params_with_nil = message_params.merge(cc: nil)
214
+ http = live_client.instance_variable_get(:@http_client)
215
+ expect(http).to receive(:post) do |_path, data, *|
216
+ expect(data).not_to have_key(:cc)
217
+ success_response
218
+ end
219
+ live_client.send_message(domain, params_with_nil)
220
+ end
221
+
222
+ it 'raises CommunicationError when the underlying request fails' do
223
+ allow(live_client.instance_variable_get(:@http_client))
224
+ .to receive(:post)
225
+ .and_raise(StandardError, 'connection refused')
226
+
227
+ expect { live_client.send_message(domain, message_params) }
228
+ .to raise_error(Mailgun::CommunicationError)
229
+ end
230
+
231
+ context 'with a MessageBuilder object' do
232
+ it 'posts to the messages endpoint and returns a Response' do
233
+ mb = Mailgun::MessageBuilder.new
234
+ mb.set_from_address('bob@example.com')
235
+ mb.add_recipient(:to, 'sally@example.com')
236
+ mb.set_subject('Hello via builder!')
237
+ mb.set_text_body('Body text.')
238
+
239
+ result = live_client.send_message(domain, mb)
240
+ expect(result).to be_a(Mailgun::Response)
241
+ end
242
+ end
243
+ end
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # #get
247
+ # ---------------------------------------------------------------------------
248
+ describe '#get' do
249
+ let(:http_response) { fake_http_response }
250
+
251
+ before do
252
+ allow(client.instance_variable_get(:@http_client))
253
+ .to receive(:get)
254
+ .and_return(http_response)
255
+ end
256
+
257
+ it 'returns a Mailgun::Response' do
258
+ result = client.get("#{domain}/events", { event: 'delivered' })
259
+ expect(result).to be_a(Mailgun::Response)
260
+ end
261
+
262
+ it 'passes the resource path through to the http client' do
263
+ http = client.instance_variable_get(:@http_client)
264
+ expect(http).to receive(:get).with("#{domain}/events", anything, anything)
265
+ .and_return(http_response)
266
+ client.get("#{domain}/events")
267
+ end
268
+
269
+ it 'raises CommunicationError on failure' do
270
+ allow(client.instance_variable_get(:@http_client))
271
+ .to receive(:get)
272
+ .and_raise(StandardError, 'timeout')
273
+
274
+ expect { client.get("#{domain}/events") }
275
+ .to raise_error(Mailgun::CommunicationError)
276
+ end
277
+ end
278
+
279
+ # ---------------------------------------------------------------------------
280
+ # #post
281
+ # ---------------------------------------------------------------------------
282
+ describe '#post' do
283
+ let(:http_response) { fake_http_response }
284
+
285
+ before do
286
+ allow(client.instance_variable_get(:@http_client))
287
+ .to receive(:post)
288
+ .and_return(http_response)
289
+ end
290
+
291
+ it 'returns a Mailgun::Response' do
292
+ result = client.post("#{domain}/messages", message_params)
293
+ expect(result).to be_a(Mailgun::Response)
294
+ end
295
+
296
+ it 'raises CommunicationError on failure' do
297
+ allow(client.instance_variable_get(:@http_client))
298
+ .to receive(:post)
299
+ .and_raise(StandardError, 'connection error')
300
+
301
+ expect { client.post("#{domain}/messages", message_params) }
302
+ .to raise_error(Mailgun::CommunicationError)
303
+ end
304
+ end
305
+
306
+ # ---------------------------------------------------------------------------
307
+ # #put
308
+ # ---------------------------------------------------------------------------
309
+ describe '#put' do
310
+ let(:http_response) { fake_http_response }
311
+
312
+ before do
313
+ allow(client.instance_variable_get(:@http_client))
314
+ .to receive(:put)
315
+ .and_return(http_response)
316
+ end
317
+
318
+ it 'returns a Mailgun::Response' do
319
+ result = client.put("#{domain}/routes/abc123", { description: 'updated' })
320
+ expect(result).to be_a(Mailgun::Response)
321
+ end
322
+
323
+ it 'raises CommunicationError on failure' do
324
+ allow(client.instance_variable_get(:@http_client))
325
+ .to receive(:put)
326
+ .and_raise(StandardError, 'connection error')
327
+
328
+ expect { client.put("#{domain}/routes/abc123", {}) }
329
+ .to raise_error(Mailgun::CommunicationError)
330
+ end
331
+ end
332
+
333
+ # ---------------------------------------------------------------------------
334
+ # #delete
335
+ # ---------------------------------------------------------------------------
336
+ describe '#delete' do
337
+ let(:http_response) { fake_http_response(body: '{"message":"Bounced address has been removed"}') }
338
+
339
+ before do
340
+ allow(client.instance_variable_get(:@http_client))
341
+ .to receive(:delete)
342
+ .and_return(http_response)
343
+ end
344
+
345
+ it 'returns a Mailgun::Response' do
346
+ result = client.delete("#{domain}/bounces/test@example.com")
347
+ expect(result).to be_a(Mailgun::Response)
348
+ end
349
+
350
+ it 'raises CommunicationError on failure' do
351
+ allow(client.instance_variable_get(:@http_client))
352
+ .to receive(:delete)
353
+ .and_raise(StandardError, 'connection error')
354
+
355
+ expect { client.delete("#{domain}/bounces/test@example.com") }
356
+ .to raise_error(Mailgun::CommunicationError)
357
+ end
358
+
359
+ it 'sends params in the request' do
360
+ result = client.delete("#{domain}/bounces/test@example.com", params: 'test')
361
+ expect(result).to be_a(Mailgun::Response)
362
+ end
363
+
364
+ it 'sends params in the request when body_params truthy' do
365
+ result = client.delete("#{domain}/bounces/test@example.com", params: 'test', body_params: true)
366
+ expect(result).to be_a(Mailgun::Response)
367
+ end
368
+ end
369
+
370
+ # ---------------------------------------------------------------------------
371
+ # #set_api_key
372
+ # ---------------------------------------------------------------------------
373
+ describe '#set_api_key' do
374
+ it 'does not raise when updating the api key' do
375
+ expect { client.set_api_key('new-key-xyz') }.not_to raise_error
376
+ end
377
+ end
378
+
379
+ # ---------------------------------------------------------------------------
380
+ # #set_subaccount / #reset_subaccount
381
+ # ---------------------------------------------------------------------------
382
+ describe '#set_subaccount' do
383
+ it 'adds the subaccount header to the http client' do
384
+ client.set_subaccount('subaccount-id-123')
385
+ headers = client.instance_variable_get(:@http_client).headers
386
+ expect(headers[Mailgun::Client::SUBACCOUNT_HEADER]).to eq('subaccount-id-123')
387
+ end
388
+ end
389
+
390
+ describe '#reset_subaccount' do
391
+ it 'removes the subaccount header from the http client' do
392
+ client.set_subaccount('subaccount-id-123')
393
+ client.reset_subaccount
394
+ headers = client.instance_variable_get(:@http_client).headers
395
+ expect(headers[Mailgun::Client::SUBACCOUNT_HEADER]).to be_nil
396
+ end
397
+ end
398
+
399
+ # ---------------------------------------------------------------------------
400
+ # #suppressions
401
+ # ---------------------------------------------------------------------------
402
+ describe '#suppressions' do
403
+ it 'returns a Mailgun::Suppressions instance' do
404
+ expect(client.suppressions(domain)).to be_a(Mailgun::Suppressions)
405
+ end
406
+
407
+ it 'scopes the suppressions client to the given domain' do
408
+ suppressions = client.suppressions(domain)
409
+ expect(suppressions).to be_a(Mailgun::Suppressions)
410
+ end
411
+ end
412
+
413
+ # ---------------------------------------------------------------------------
414
+ # Mailgun.configure integration
415
+ # ---------------------------------------------------------------------------
416
+ describe 'Mailgun.configure integration' do
417
+ after { Mailgun.instance_variable_set(:@configuration, nil) }
418
+
419
+ it 'picks up the api_key from Mailgun.configure' do
420
+ Mailgun.configure { |config| config.api_key = 'configured-key' }
421
+ expect { described_class.new }.not_to raise_error
422
+ end
423
+ end
424
+ end