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,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'time'
2
4
  require 'json'
3
5
 
4
6
  module Mailgun
5
7
  class UnitClient < Mailgun::Client
6
-
7
8
  attr_reader :options, :block, :body, :code, :response
8
9
 
9
10
  def initialize(endpoint, &block)
@@ -14,9 +15,10 @@ module Mailgun
14
15
  end
15
16
 
16
17
  def [](endpoint, &new_block)
17
- case
18
- when block_given? then self.class.new(endpoint, &new_block)
19
- when block then self.class.new(endpoint, &block)
18
+ if block_given?
19
+ self.class.new(endpoint, &new_block)
20
+ elsif block
21
+ self.class.new(endpoint, &block)
20
22
  else
21
23
  self.class.new(endpoint)
22
24
  end
@@ -26,10 +28,8 @@ module Mailgun
26
28
  perform_data_validation(working_domain, data)
27
29
  case data
28
30
  when Hash
29
- if data.has_key?(:message)
30
- if data[:message].is_a?(String)
31
- data[:message] = convert_string_to_file(data[:message])
32
- end
31
+ if data.key?(:message)
32
+ data[:message] = convert_string_to_file(data[:message]) if data[:message].is_a?(String)
33
33
  post("#{working_domain}/messages.mime", data)
34
34
  else
35
35
  post("#{working_domain}/messages", data)
@@ -37,80 +37,133 @@ module Mailgun
37
37
  when MessageBuilder
38
38
  post("#{working_domain}/messages", data.message)
39
39
  else
40
- raise ParameterError.new("Unknown data type for data parameter.", data)
40
+ raise ParameterError.new('Unknown data type for data parameter.', data)
41
41
  end
42
42
  end
43
43
 
44
- def post(path, data)
45
- begin
46
- Mailgun::Response.new(response_generator(@endpoint))
47
- rescue => e
48
- p e
49
- raise CommunicationError.new(e), e.response if e.respond_to? :response
50
- raise CommunicationError.new(e.message)
51
- end
44
+ def post(_path, _data)
45
+ Mailgun::Response.new(response_generator(@endpoint))
46
+ rescue StandardError => e
47
+ p e
48
+ raise CommunicationError.new(e), e.response if e.respond_to? :response
49
+
50
+ raise CommunicationError, e.message
52
51
  end
53
52
 
54
- def get(path, query_string = nil)
55
- begin
56
- Mailgun::Response.new(response_generator(@endpoint))
57
- rescue => e
58
- raise CommunicationError.new(e), e.response
59
- end
53
+ def get(_path, _query_string = nil)
54
+ Mailgun::Response.new(response_generator(@endpoint))
55
+ rescue StandardError => e
56
+ raise CommunicationError.new(e), e.response
60
57
  end
61
58
 
62
- def put(path, data)
63
- begin
64
- Mailgun::Response.new(response_generator(@endpoint))
65
- rescue => e
66
- raise CommunicationError.new(e), e.response
67
- end
59
+ def put(_path, _data)
60
+ Mailgun::Response.new(response_generator(@endpoint))
61
+ rescue StandardError => e
62
+ raise CommunicationError.new(e), e.response
68
63
  end
69
64
 
70
- def delete(path)
71
- begin
72
- Mailgun::Response.new(response_generator(@endpoint))
73
- rescue => e
74
- raise CommunicationError.new(e), e.response
75
- end
65
+ def delete(_path)
66
+ Mailgun::Response.new(response_generator(@endpoint))
67
+ rescue StandardError => e
68
+ raise CommunicationError.new(e), e.response
76
69
  end
77
70
 
78
71
  private
79
72
 
80
73
  def perform_data_validation(working_domain, data)
81
- fail ParameterError.new('Missing working domain', working_domain) unless working_domain
74
+ raise ParameterError.new('Missing working domain', working_domain) unless working_domain
82
75
  return true unless data.is_a?(Hash) && data.present?
76
+
83
77
  message = data.respond_to?(:message) ? data.message : data
84
78
 
85
- fail ParameterError.new(
86
- 'Missing `to` recipient, message should contain at least 1 recipient',
87
- working_domain
88
- ) if message.fetch('to', []).empty? && message.fetch(:to, []).empty?
89
- fail ParameterError.new(
79
+ if message.fetch('to', []).empty? && message.fetch(:to, []).empty?
80
+ raise ParameterError.new(
81
+ 'Missing `to` recipient, message should contain at least 1 recipient',
82
+ working_domain
83
+ )
84
+ end
85
+ return unless message.fetch('from', []).empty? && message.fetch(:from, []).empty?
86
+
87
+ raise ParameterError.new(
90
88
  'Missing a `from` sender, message should contain at least 1 `from` sender',
91
89
  working_domain
92
- ) if message.fetch('from', []).empty? && message.fetch(:from, []).empty?
90
+ )
93
91
  end
94
92
 
95
93
  def response_generator(resource_endpoint)
96
- if resource_endpoint == "messages"
94
+ if resource_endpoint == 'messages'
97
95
  t = Time.now
98
- id = "<#{t.to_i}.#{rand(99999999)}.5817@example.com>"
99
- return Response.from_hash({ body: JSON.generate({"message" => "Queued. Thank you.", "id" => id}) })
96
+ id = "<#{t.to_i}.#{rand(99_999_999)}.5817@example.com>"
97
+ return Response.from_hash({ body: JSON.generate({ 'message' => 'Queued. Thank you.', 'id' => id }) })
100
98
  end
101
- if resource_endpoint == "bounces"
102
- return Response.from_hash({ body: JSON.generate({"total_count" => 1, "items" => {"created_at" => "Fri, 21 Oct 2011 11:02:55 GMT", "status" => 550, "address" => "baz@example.com", "error" => "Message was not accepted -- invalid mailbox. Local mailbox baz@example.com is unavailable: user not found"}}) })
99
+ if resource_endpoint == 'bounces'
100
+ return Response.from_hash(
101
+ { body: JSON.generate(
102
+ {
103
+ 'total_count' => 1,
104
+ 'items' =>
105
+ {
106
+ 'created_at' => 'Fri, 21 Oct 2011 11:02:55 GMT',
107
+ 'status' => 550,
108
+ 'address' => 'baz@example.com',
109
+ 'error' => "Message was not accepted -- invalid mailbox. \
110
+ Local mailbox baz@example.com is unavailable: user not found"
111
+ }
112
+ }
113
+ ) }
114
+ )
103
115
  end
104
- if resource_endpoint == "lists"
105
- return Response.from_hash({ body: JSON.generate({"member" => {"vars" => {"age" => 26}, "name" => "Foo Bar", "subscribed" => false, "address" => "bar@example.com"}, "message" => "Mailing list member has been updated"}) })
116
+ if resource_endpoint == 'lists'
117
+ return Response.from_hash(
118
+ { body: JSON.generate(
119
+ {
120
+ 'member' =>
121
+ {
122
+ 'vars' => { 'age' => 26 },
123
+ 'name' => 'Foo Bar',
124
+ 'subscribed' => false,
125
+ 'address' => 'bar@example.com'
126
+ },
127
+ 'message' => 'Mailing list member has been updated'
128
+ }
129
+ ) }
130
+ )
106
131
  end
107
- if resource_endpoint == "campaigns"
108
- return Response.from_hash({ body: JSON.generate({"message" => "Campaign has been deleted", "id" => "ABC123"}) })
109
- end
110
- if resource_endpoint == "events"
111
- return Response.from_hash({ body: JSON.generate({"items" => [], "paging" => {"next"=> "https://api.mailgun.net/v3/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIFsiZiJdLCBudWxsLCB7ImFjY291bnQuaWQiOiAiNGU4MjMwZjYxNDc2ZDg2NzEzMDBjNDc2IiwgImRvbWFpbi5uYW1lIjogInRoaXNpc2F0ZXN0ZG9tYWluZm9ybWFpbGd1bi5jb20iLCAic2V2ZXJpdHkiOiAiTk9UIGludGVybmFsIn0sIDEwMCwgbnVsbF0=", "previous"=> "https://api.mailgun.net/v2/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDdUMDA6NDU6NTEuNzQxODkyKzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIHsiYWNjb3VudC5pZCI6ICI0ZTgyMzBmNjE0NzZkODY3MTMwMGM0NzYiLCAiZG9tYWluLm5hbWUiOiAidGhpc2lzYXRlc3Rkb21haW5mb3JtYWlsZ3VuLmNvbSIsICJzZXZlcml0eSI6ICJOT1QgaW50ZXJuYWwifSwgMTAwLCBudWxsXQ=="}}) })
132
+ if resource_endpoint == 'campaigns'
133
+ return Response.from_hash(
134
+ {
135
+ body: JSON.generate(
136
+ {
137
+ 'message' => 'Campaign has been deleted',
138
+ 'id' => 'ABC123'
139
+ }
140
+ )
141
+ }
142
+ )
112
143
  end
144
+ return unless resource_endpoint == 'events'
145
+
146
+ Response.from_hash(
147
+ { body: JSON.generate(
148
+ { 'items' => [],
149
+ 'paging' => {
150
+ 'next' =>
151
+ "https://api.mailgun.net/v3/thisisatestdomainformailgun.com/events/W3siYiI6I\
152
+ CIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzK\
153
+ zAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUM\
154
+ DA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIFsiZiJdLCBudWxsLCB7ImFjY291bnQuaWQiOiAiNGU4MjMwZjYxNDc2ZDg2N\
155
+ zEzMDBjNDc2IiwgImRvbWFpbi5uYW1lIjogInRoaXNpc2F0ZXN0ZG9tYWluZm9ybWFpbGd1bi5jb20iLCAic2V2ZXJpd\
156
+ HkiOiAiTk9UIGludGVybmFsIn0sIDEwMCwgbnVsbF0=",
157
+ 'previous' =>
158
+ "https://api.mailgun.net/v2/thisisatestdomainformailgun.com/events/W3siYiI6IC\
159
+ IyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzA\
160
+ wOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDdUMDA6\
161
+ NDU6NTEuNzQxODkyKzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIHsiYWNjb3VudC5pZCI6ICI0ZTgyMzBmNjE0NzZkO\
162
+ DY3MTMwMGM0NzYiLCAiZG9tYWluLm5hbWUiOiAidGhpc2lzYXRlc3Rkb21haW5mb3JtYWlsZ3VuLmNvbSIsICJzZXZlcm\
163
+ l0eSI6ICJOT1QgaW50ZXJuYWwifSwgMTAwLCBudWxsXQ=="
164
+ } }
165
+ ) }
166
+ )
113
167
  end
114
168
  end
115
-
116
169
  end
@@ -1,66 +1,85 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'The method get' do
4
- it 'should return a proper hash of log data.' do
6
+ it 'returns a proper hash of log data.' do
5
7
  @mg_obj = Mailgun::UnitClient.new('events')
6
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
7
- result = events.get()
8
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
9
+ result = events.get
8
10
 
9
- expect(result.body).to include("items")
10
- expect(result.body).to include("paging")
11
+ expect(result.body).to include('items')
12
+ expect(result.body).to include('paging')
11
13
  end
12
14
  end
13
15
 
14
16
  describe 'Pagination' do
15
- it 'should return a proper hash of log data.' do
17
+ it 'returns a proper hash of log data.' do
16
18
  @mg_obj = Mailgun::UnitClient.new('events')
17
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
18
- result = events.get()
19
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
20
+ result = events.get
19
21
 
20
22
  json = JSON.parse(result.body)
21
- expect(json).to include("paging")
22
- expect(json["paging"]).to include("next")
23
- expect(json["paging"]).to include("previous")
23
+ expect(json).to include('paging')
24
+ expect(json['paging']).to include('next')
25
+ expect(json['paging']).to include('previous')
24
26
  end
25
27
 
26
- it 'should calculate proper next-page url' do
27
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
28
- output = events.send(:extract_endpoint_from, '/v3/samples.mailgun.org/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ==')
28
+ it 'calculates proper next-page url' do
29
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
30
+ output = events.send(
31
+ :extract_endpoint_from,
32
+ "/v3/samples.mailgun.org/events/W3siYiI6ICIyMDE3LTA1\
33
+ LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMj\
34
+ A6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2\
35
+ OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNT\
36
+ c3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4\
37
+ MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgIn\
38
+ NhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWls\
39
+ Z3VuLm9yZyJdXSwgMTAwLCBudWxsXQ=="
40
+ )
29
41
 
30
- expect(output).to eq 'W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ=='
42
+ expect(output).to eq "W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2O\
43
+ jU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3\
44
+ KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDo\
45
+ wMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIF\
46
+ siZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2M\
47
+ TNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUy\
48
+ YWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTA\
49
+ wLCBudWxsXQ=="
31
50
  end
32
51
  end
33
52
 
34
53
  describe 'The method next' do
35
- it 'should return the next series of data.' do
54
+ it 'returns the next series of data.' do
36
55
  @mg_obj = Mailgun::UnitClient.new('events')
37
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
38
- result = events.next()
56
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
57
+ result = events.next
39
58
 
40
- expect(result.body).to include("items")
41
- expect(result.body).to include("paging")
59
+ expect(result.body).to include('items')
60
+ expect(result.body).to include('paging')
42
61
  end
43
62
  end
44
63
 
45
64
  describe 'The method previous' do
46
- it 'should return the previous series of data.' do
65
+ it 'returns the previous series of data.' do
47
66
  @mg_obj = Mailgun::UnitClient.new('events')
48
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
49
- result = events.previous()
67
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
68
+ result = events.previous
50
69
 
51
- expect(result.body).to include("items")
52
- expect(result.body).to include("paging")
70
+ expect(result.body).to include('items')
71
+ expect(result.body).to include('paging')
53
72
  end
54
73
  end
55
74
 
56
75
  describe 'The method each' do
57
- it 'should iterate over all event items.' do
76
+ it 'iterates over all event items.' do
58
77
  @mg_obj = Mailgun::UnitClient.new('events')
59
- events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
78
+ events = Mailgun::Events.new(@mg_obj, 'samples.mailgun.org')
60
79
  # Events from the UnitClient are actually empty.
61
80
  count = 0
62
- events.each do |e|
63
- count = count + 1
81
+ events.each do |_e|
82
+ count += 1
64
83
  end
65
84
 
66
85
  # Better than nothing..
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  RSpec.describe Mailgun::CommunicationError do
@@ -9,22 +11,21 @@ RSpec.describe Mailgun::CommunicationError do
9
11
  end.not_to raise_error
10
12
  end
11
13
 
12
- context "when the Response body has an `Error` property" do
13
- it "uses the `Error` property as the API message" do
14
+ context 'when the Response body has an `Error` property' do
15
+ it 'uses the `Error` property as the API message' do
14
16
  subject = described_class.new('Boom!', { status: 401, body: '{"Error":"unauthorized"}' })
15
17
 
16
- expect(subject.message).to eq("Boom!: unauthorized")
18
+ expect(subject.message).to eq('Boom!: unauthorized')
17
19
  end
18
20
  end
19
21
 
20
- context "when the Response body has an `error` property" do
21
- it "uses the `Error` property as the API message" do
22
+ context 'when the Response body has an `error` property' do
23
+ it 'uses the `Error` property as the API message' do
22
24
  subject = described_class.new('Boom!', { status: 401, body: '{"error":"not found"}' })
23
25
 
24
- expect(subject.message).to eq("Boom!: not found")
26
+ expect(subject.message).to eq('Boom!: not found')
25
27
  end
26
28
  end
27
-
28
29
  end
29
30
  end
30
31
  end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'mailgun'
6
+ require 'mailgun/helpers/api_version_checker'
7
+
8
+ describe Mailgun::ApiVersionChecker do
9
+ # Build a minimal host class that includes the module, with a controllable
10
+ # @client so we can set api_version per example.
11
+ subject(:instance) { host_class.new(client) }
12
+
13
+ let(:client) { double(:client) }
14
+
15
+ let(:host_class) do
16
+ Class.new do
17
+ include Mailgun::ApiVersionChecker
18
+
19
+ attr_reader :result
20
+
21
+ def initialize(client)
22
+ @client = client
23
+ end
24
+
25
+ def do_something(arg = nil)
26
+ @result = arg || :called
27
+ end
28
+ end
29
+ end
30
+
31
+ # ──────────────────────────────────────────────────────────────────────────
32
+ # .included / module structure
33
+ # ──────────────────────────────────────────────────────────────────────────
34
+
35
+ describe '.included' do
36
+ it 'extends the including class with ClassMethods' do
37
+ expect(host_class).to respond_to(:requires_api_version)
38
+ expect(host_class).to respond_to(:enforces_api_version)
39
+ end
40
+
41
+ it 'does not expose ClassMethods as instance methods' do
42
+ expect(instance).not_to respond_to(:requires_api_version)
43
+ expect(instance).not_to respond_to(:enforces_api_version)
44
+ end
45
+ end
46
+
47
+ # ──────────────────────────────────────────────────────────────────────────
48
+ # .requires_api_version (warns but still calls through)
49
+ # ──────────────────────────────────────────────────────────────────────────
50
+
51
+ describe '.requires_api_version' do
52
+ before { host_class.requires_api_version('v3', :do_something) }
53
+
54
+ context 'when the client is on the expected version' do
55
+ before { allow(client).to receive(:api_version).and_return('v3') }
56
+
57
+ it 'does not emit a warning' do
58
+ expect { instance.do_something }.not_to output.to_stderr
59
+ end
60
+
61
+ it 'still calls the original method' do
62
+ instance.do_something(:payload)
63
+ expect(instance.result).to eq(:payload)
64
+ end
65
+
66
+ it 'forwards all arguments to the original method' do
67
+ instance.do_something(:forwarded_arg)
68
+ expect(instance.result).to eq(:forwarded_arg)
69
+ end
70
+ end
71
+
72
+ context 'when the client is on a different version' do
73
+ before { allow(client).to receive(:api_version).and_return('v4') }
74
+
75
+ it 'emits a warning to stderr' do
76
+ expect { instance.do_something }
77
+ .to output(/WARN: Client api version must be v3/).to_stderr
78
+ end
79
+
80
+ it 'still calls the original method despite the warning' do
81
+ instance.do_something(:payload)
82
+ expect(instance.result).to eq(:payload)
83
+ end
84
+
85
+ it 'warning message includes the expected version' do
86
+ expect { instance.do_something }
87
+ .to output(/v3/).to_stderr
88
+ end
89
+ end
90
+
91
+ it 'wraps multiple methods when given a list' do
92
+ host_class.class_eval { def do_other = @result = :other }
93
+ host_class.requires_api_version('v3', :do_something, :do_other)
94
+
95
+ allow(client).to receive(:api_version).and_return('v4')
96
+
97
+ expect { instance.do_something }.to output(/v3/).to_stderr
98
+ expect { instance.do_other }.to output(/v3/).to_stderr
99
+ end
100
+
101
+ it 'wraps only the listed methods, leaving others unwrapped' do
102
+ host_class.class_eval { def unwrapped = @result = :unwrapped }
103
+ host_class.requires_api_version('v3', :do_something)
104
+
105
+ allow(client).to receive(:api_version).and_return('v4')
106
+
107
+ # unwrapped should not warn
108
+ expect { instance.unwrapped }.not_to output.to_stderr
109
+ end
110
+ end
111
+
112
+ # ──────────────────────────────────────────────────────────────────────────
113
+ # .enforces_api_version (raises on version mismatch)
114
+ # ──────────────────────────────────────────────────────────────────────────
115
+
116
+ describe '.enforces_api_version' do
117
+ before { host_class.enforces_api_version('v3', :do_something) }
118
+
119
+ context 'when the client is on the expected version' do
120
+ before { allow(client).to receive(:api_version).and_return('v3') }
121
+
122
+ it 'does not raise' do
123
+ expect { instance.do_something }.not_to raise_error
124
+ end
125
+
126
+ it 'calls the original method' do
127
+ instance.do_something(:payload)
128
+ expect(instance.result).to eq(:payload)
129
+ end
130
+
131
+ it 'forwards all arguments to the original method' do
132
+ instance.do_something(:forwarded_arg)
133
+ expect(instance.result).to eq(:forwarded_arg)
134
+ end
135
+ end
136
+
137
+ context 'when the client is on a different version' do
138
+ before { allow(client).to receive(:api_version).and_return('v4') }
139
+
140
+ it 'raises Mailgun::ParameterError' do
141
+ expect { instance.do_something }
142
+ .to raise_error(Mailgun::ParameterError)
143
+ end
144
+
145
+ it 'raises with a message including the expected version' do
146
+ expect { instance.do_something }
147
+ .to raise_error(Mailgun::ParameterError, /v3/)
148
+ end
149
+
150
+ it 'does not call the original method' do
151
+ begin
152
+ instance.do_something
153
+ rescue StandardError
154
+ nil
155
+ end
156
+ expect(instance.result).to be_nil
157
+ end
158
+ end
159
+
160
+ it 'wraps multiple methods when given a list' do
161
+ host_class.class_eval { def do_other = @result = :other }
162
+ host_class.enforces_api_version('v3', :do_something, :do_other)
163
+
164
+ allow(client).to receive(:api_version).and_return('v4')
165
+
166
+ expect { instance.do_something }.to raise_error(Mailgun::ParameterError)
167
+ expect { instance.do_other }.to raise_error(Mailgun::ParameterError)
168
+ end
169
+
170
+ it 'wraps only the listed methods, leaving others unwrapped' do
171
+ host_class.class_eval { def unwrapped = @result = :unwrapped }
172
+ host_class.enforces_api_version('v3', :do_something)
173
+
174
+ allow(client).to receive(:api_version).and_return('v4')
175
+
176
+ expect { instance.unwrapped }.not_to raise_error
177
+ end
178
+ end
179
+
180
+ # ──────────────────────────────────────────────────────────────────────────
181
+ # requires vs enforces contrast
182
+ # ──────────────────────────────────────────────────────────────────────────
183
+
184
+ describe 'requires_api_version vs enforces_api_version' do
185
+ before do
186
+ host_class.class_eval do
187
+ def soft_method = @result = :soft
188
+ def hard_method = @result = :hard
189
+ end
190
+ host_class.requires_api_version('v3', :soft_method)
191
+ host_class.enforces_api_version('v3', :hard_method)
192
+
193
+ allow(client).to receive(:api_version).and_return('v4')
194
+ end
195
+
196
+ it 'requires_api_version warns but does not raise' do
197
+ expect { instance.soft_method }.to output(/v3/).to_stderr
198
+ expect(instance.result).to eq(:soft)
199
+ end
200
+
201
+ it 'enforces_api_version raises and does not call through' do
202
+ expect { instance.hard_method }.to raise_error(Mailgun::ParameterError)
203
+ expect(instance.result).not_to eq(:hard)
204
+ end
205
+ end
206
+ end
@@ -1,22 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'The method generate_hash' do
4
- before(:each) do
5
- @mailing_list = "mylist@example.com"
6
- @secret_app_id = "mysupersecretpassword"
7
- @recipient_address = "bob@example.com"
8
- @precalculated_hash = "eyJoIjoiMmY3ZmY1MzFlOGJmMjA0OWNhMTI3ZmU4ZTQyNjZkOTljYzhkMTdk%0AMiIsInAiOiJleUpzSWpvaWJYbHNhWE4wUUdWNFlXMXdiR1V1WTI5dElpd2lj%0AaUk2SW1KdllrQmxlR0Z0Y0d4bExtTnZcbmJTSjlcbiJ9%0A"
6
+ before do
7
+ @mailing_list = 'mylist@example.com'
8
+ @secret_app_id = 'mysupersecretpassword'
9
+ @recipient_address = 'bob@example.com'
10
+ @precalculated_hash =
11
+ "eyJoIjoiMmY3ZmY1MzFlOGJmMjA0OWNhMTI3ZmU4ZTQyNjZkOTljYzhkMTdk%0AMiIsInAiOiJleUpzSWpv\
12
+ aWJYbHNhWE4wUUdWNFlXMXdiR1V1WTI5dElpd2lj%0AaUk2SW1KdllrQmxlR0Z0Y0d4bExtTnZcbmJTSjlcbiJ9%0A"
9
13
  end
10
14
 
11
15
  it 'generates a web safe hash for the recipient wishing to subscribe' do
12
16
  my_hash = Mailgun::OptInHandler.generate_hash(@mailing_list, @secret_app_id, @recipient_address)
13
-
17
+
14
18
  expect(my_hash).to eq(@precalculated_hash)
15
19
  end
16
20
 
17
21
  it 'generates a web safe hash for the recipient wishing to subscribe' do
18
22
  validate_result = Mailgun::OptInHandler.validate_hash(@secret_app_id, @precalculated_hash)
19
-
23
+
20
24
  expect(validate_result.length).to eq(2)
21
25
  expect(validate_result['recipient_address']).to eq(@recipient_address)
22
26
  expect(validate_result['mailing_list']).to eq(@mailing_list)