pheme 3.1.3 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43b82532ae9c2d1e266860d9553d1b9e6c47fba937de781431f50f87921fa8b6
4
- data.tar.gz: 14cd293a8fdbabab40154bf10a6e1cee36d4c609749a7ca4f0ee44d4df1780ee
3
+ metadata.gz: 5ead3f77e54732d0ec25696ec63984cca421f38a96f398c36c886f575ef05270
4
+ data.tar.gz: 62af0c6807a8fcec1f00f8a1e2217b056bd3307d99a5a191f35512acac352afa
5
5
  SHA512:
6
- metadata.gz: 1b1da30552e2ba5fb12a898c1af86a0f48654a6c3a3bca615ae00d7a762bd4a7db6f660bcfd99149d00ec0ebeaccdd4b115c06ce5233b382706045aa5d470d9e
7
- data.tar.gz: d86bfe1b06f0d5040e4461a24bfc5cfe2e264c8014563b26c8e0e49912834f3db03286f49dd042f65b6f13a38547c8866406ff04a8f82814bfb644ef5b24c288
6
+ metadata.gz: 2570dcdd9712acc03aa8ae0b25d6744e6aa2c2594aa2566cae59fb9e9b35c3143cf879a83fa4968026b1e47ee4d6a245f1122c673b354167e1421b928168a0d7
7
+ data.tar.gz: 828eca04402d568ed88fe5deb4b89320feea9961089a6218f8efc8d0ac989bf82ab30b89cea2fb711919cf1ace55d9fe91b67aee43eabc3f9eab3272991b3413
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  inherit_gem:
2
4
  ws-style:
3
5
  - default.yml
@@ -34,6 +36,9 @@ Metrics/LineLength:
34
36
  Metrics/MethodLength:
35
37
  Max: 22
36
38
 
39
+ RSpec/FilePath:
40
+ Enabled: false
41
+
37
42
  # Offense count: 1
38
43
  # Configuration parameters: MinBodyLength.
39
44
  Style/GuardClause:
@@ -0,0 +1,53 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2019-05-29 15:19:13 -0400 using RuboCop version 0.70.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 12
10
+ # Configuration parameters: Prefixes.
11
+ # Prefixes: when, with, without
12
+ RSpec/ContextWording:
13
+ Exclude:
14
+ - 'spec/configuration_spec.rb'
15
+ - 'spec/message_handler_spec.rb'
16
+ - 'spec/queue_poller_spec.rb'
17
+ - 'spec/topic_publisher_spec.rb'
18
+
19
+ # Offense count: 5
20
+ # Configuration parameters: CustomTransform, IgnoreMethods.
21
+ RSpec/FilePath:
22
+ Exclude:
23
+ - 'spec/configuration_spec.rb'
24
+ - 'spec/logger_spec.rb'
25
+ - 'spec/message_handler_spec.rb'
26
+ - 'spec/message_type/aws_event_spec.rb'
27
+ - 'spec/message_type/sns_message_spec.rb'
28
+ - 'spec/queue_poller_spec.rb'
29
+ - 'spec/rollbar_spec.rb'
30
+ - 'spec/topic_publisher_spec.rb'
31
+ - 'spec/version_spec.rb'
32
+
33
+ # Offense count: 14
34
+ # Configuration parameters: EnforcedStyle.
35
+ # SupportedStyles: have_received, receive
36
+ RSpec/MessageSpies:
37
+ Exclude:
38
+ - 'spec/message_handler_spec.rb'
39
+ - 'spec/queue_poller_spec.rb'
40
+ - 'spec/rollbar_spec.rb'
41
+ - 'spec/topic_publisher_spec.rb'
42
+
43
+ # Offense count: 39
44
+ # Configuration parameters: IgnoreSharedExamples.
45
+ RSpec/NamedSubject:
46
+ Exclude:
47
+ - 'spec/configuration_spec.rb'
48
+ - 'spec/logger_spec.rb'
49
+ - 'spec/message_handler_spec.rb'
50
+ - 'spec/message_type/sns_message_spec.rb'
51
+ - 'spec/queue_poller_spec.rb'
52
+ - 'spec/rollbar_spec.rb'
53
+ - 'spec/topic_publisher_spec.rb'
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 3.2.0 - 2019-05-29
8
+ ### Added
9
+ - Support for Pheme::TopicPublisher to publish to an explicit SNS client.
10
+
7
11
  ## 3.1.3 - 2019-02-14
8
12
  ### Fixed
9
13
  - Increase code coverage to 100%.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # pheme [![CircleCI](https://circleci.com/gh/wealthsimple/pheme.svg?style=svg&circle-token=76942be0b1712ac066627be264886ee18039ad11)](https://circleci.com/gh/wealthsimple/pheme) [![Coverage Status](https://coveralls.io/repos/github/wealthsimple/pheme/badge.svg)](https://coveralls.io/github/wealthsimple/pheme?branch=3.1.0-rc)
1
+ # pheme [![CircleCI](https://circleci.com/gh/wealthsimple/pheme.svg?style=svg&circle-token=76942be0b1712ac066627be264886ee18039ad11)](https://circleci.com/gh/wealthsimple/pheme) [![Coverage Status](https://coveralls.io/repos/github/wealthsimple/pheme/badge.svg)](https://coveralls.io/github/wealthsimple/pheme)
2
2
 
3
3
  Ruby SNS publisher + SQS poller & message handler
4
4
 
@@ -34,7 +34,7 @@ module Pheme
34
34
  raise NotImplementedError
35
35
  end
36
36
 
37
- def publish(message)
37
+ def publish(message, sns_client: Pheme.configuration.sns_client)
38
38
  payload = {
39
39
  message: "#{self.class} publishing message to #{topic_arn}",
40
40
  body: message,
@@ -42,7 +42,7 @@ module Pheme
42
42
  topic_arn: topic_arn,
43
43
  }
44
44
  Pheme.logger.info(payload.to_json)
45
- Pheme.configuration.sns_client.publish(topic_arn: topic_arn, message: serialize(message))
45
+ sns_client.publish(topic_arn: topic_arn, message: serialize(message))
46
46
  end
47
47
 
48
48
  def serialize(message)
@@ -1,3 +1,3 @@
1
1
  module Pheme
2
- VERSION = '3.1.3'.freeze
2
+ VERSION = '3.2.0'.freeze
3
3
  end
@@ -3,6 +3,7 @@ describe Pheme do
3
3
  let(:sns_client) { double }
4
4
  let(:sqs_client) { double }
5
5
  let(:custom_logger) { double }
6
+
6
7
  it "sets global configuration" do
7
8
  expect(described_class.configuration.sns_client).to be_nil
8
9
  expect(described_class.configuration.sqs_client).to be_nil
@@ -1,10 +1,10 @@
1
1
  RSpec.describe Pheme do
2
2
  describe '.log' do
3
+ subject { described_class.log(method, text) }
4
+
3
5
  let(:method) { 'info' }
4
6
  let(:text) { 'Some informational message' }
5
7
 
6
- subject { Pheme.log(method, text) }
7
-
8
8
  it { subject }
9
9
  end
10
10
  end
@@ -1,8 +1,10 @@
1
1
  describe Pheme::MessageHandler do
2
- before(:each) { use_default_configuration! }
2
+ subject { ExampleMessageHandler.new(message: message, metadata: { timestamp: timestamp }) }
3
+
4
+ before { use_default_configuration! }
5
+
3
6
  let(:message) { RecursiveOpenStruct.new(status: status) }
4
7
  let(:timestamp) { '2018-04-17T21:45:05.915Z' }
5
- subject { ExampleMessageHandler.new(message: message, metadata: { timestamp: timestamp }) }
6
8
 
7
9
  describe "#handle" do
8
10
  context 'complete message' do
@@ -15,6 +15,7 @@ describe Pheme::MessageType::AwsEvent do
15
15
 
16
16
  context "with JSON message" do
17
17
  let!(:records) { [{ 'eventVersion' => '2.0' }] }
18
+
18
19
  its('first.eventVersion') { is_expected.to eq('2.0') }
19
20
  end
20
21
  end
@@ -15,7 +15,7 @@ describe Pheme::MessageType::SnsMessage do
15
15
  poller
16
16
  end
17
17
 
18
- before(:each) do
18
+ before do
19
19
  use_default_configuration!
20
20
  allow(Aws::SQS::QueuePoller).to receive(:new) { poller }
21
21
  end
@@ -24,7 +24,7 @@ describe Pheme::MessageType::SnsMessage do
24
24
  context "with JSON message" do
25
25
  let!(:message) { OpenStruct.new({ body: '{"Message":"{\"test\":\"test\"}"}' }) }
26
26
 
27
- it 'should parse the message correctly' do
27
+ it 'parses the message correctly' do
28
28
  expect(subject.parse_body(message).test).to eq("test")
29
29
  end
30
30
  end
@@ -2,6 +2,16 @@ describe Pheme::QueuePoller do
2
2
  let(:queue_url) { "https://sqs.us-east-1.amazonaws.com/whatever" }
3
3
  let(:timestamp) { '2018-04-17T21:45:05.915Z' }
4
4
 
5
+ let!(:queue_message) do
6
+ OpenStruct.new(
7
+ body: { Message: message }.to_json,
8
+ message_id: message_id,
9
+ )
10
+ end
11
+ let(:message) { nil }
12
+ let(:message_id) { SecureRandom.uuid }
13
+ let(:poller) { ExampleQueuePoller.new(queue_url: queue_url, format: format) }
14
+
5
15
  context 'base poller' do
6
16
  subject { described_class.new(queue_url: 'https://sqs.aws.com').handle(nil, nil) }
7
17
 
@@ -24,7 +34,7 @@ describe Pheme::QueuePoller do
24
34
  end
25
35
 
26
36
  context "when initialized with max_messages" do
27
- it "should set max_messages" do
37
+ it "sets max_messages" do
28
38
  expect(ExampleQueuePoller.new(queue_url: "queue_url", max_messages: 5).max_messages).to eq(5)
29
39
  end
30
40
  end
@@ -32,13 +42,15 @@ describe Pheme::QueuePoller do
32
42
  context "when initialized with sqs_client" do
33
43
  let(:sqs_client) { Object.new }
34
44
 
35
- it "should set custom sqs_client" do
45
+ it "sets custom sqs_client" do
36
46
  expect(Aws::SQS::QueuePoller).to receive(:new).with("queue_url", client: sqs_client)
37
47
  ExampleQueuePoller.new(queue_url: "queue_url", sqs_client: sqs_client)
38
48
  end
39
49
  end
40
50
 
41
51
  context 'received too many messages' do
52
+ subject { described_class.new(queue_url: 'http://sqs.aws.com', max_messages: max_messages) }
53
+
42
54
  let(:aws_poller) { instance_double('Aws::SQS::QueuePoller') }
43
55
  let(:max_messages) { 50 }
44
56
 
@@ -47,30 +59,19 @@ describe Pheme::QueuePoller do
47
59
  allow(aws_poller).to receive(:before_request).and_yield(OpenStruct.new(received_message_count: max_messages))
48
60
  end
49
61
 
50
- subject { described_class.new(queue_url: 'http://sqs.aws.com', max_messages: max_messages) }
51
-
52
62
  it 'throws error' do
53
63
  expect { subject }.to raise_error(UncaughtThrowError, /stop_polling/)
54
64
  end
55
65
  end
56
66
  end
57
67
 
58
- let(:poller) { ExampleQueuePoller.new(queue_url: queue_url, format: format) }
59
- let(:message_id) { SecureRandom.uuid }
60
- let(:message) { nil }
61
- let!(:queue_message) do
62
- OpenStruct.new(
63
- body: { Message: message }.to_json,
64
- message_id: message_id,
65
- )
66
- end
67
-
68
68
  describe "#parse_body" do
69
69
  subject { poller.parse_body(queue_message) }
70
70
 
71
71
  context "message is JSON string" do
72
72
  let(:format) { :json }
73
73
  let!(:message) { { test: 'test' }.to_json }
74
+
74
75
  its([:test]) { is_expected.to eq('test') }
75
76
  end
76
77
 
@@ -98,7 +99,7 @@ describe Pheme::QueuePoller do
98
99
  let(:format) { :invalid_format }
99
100
  let(:message) { 'unkonwn' }
100
101
 
101
- it "should raise error" do
102
+ it "raises error" do
102
103
  expect { subject }.to raise_error(ArgumentError)
103
104
  end
104
105
  end
@@ -128,7 +129,7 @@ describe Pheme::QueuePoller do
128
129
  end
129
130
 
130
131
  describe "#poll" do
131
- before(:each) do
132
+ before do
132
133
  module ActiveRecord
133
134
  class Base
134
135
  def self.connection_pool; end
@@ -137,8 +138,10 @@ describe Pheme::QueuePoller do
137
138
  end
138
139
 
139
140
  context "with connection pool block" do
140
- let(:mock_connection_pool) { double }
141
141
  subject { ExampleQueuePoller.new(queue_url: queue_url, connection_pool_block: true) }
142
+
143
+ let(:mock_connection_pool) { double }
144
+
142
145
  let(:message) { { status: 'complete' } }
143
146
  let(:notification) { { 'MessageId' => SecureRandom.uuid, 'Message' => message.to_json, 'Type' => 'Notification', 'Timestamp' => timestamp } }
144
147
  let!(:queue_message) do
@@ -148,7 +151,7 @@ describe Pheme::QueuePoller do
148
151
  )
149
152
  end
150
153
 
151
- before(:each) do
154
+ before do
152
155
  allow(ActiveRecord::Base).to receive(:connection_pool) { mock_connection_pool }
153
156
  allow(mock_connection_pool).to receive(:with_connection).and_yield
154
157
  allow(subject.queue_poller).to receive(:poll).and_yield(queue_message)
@@ -163,6 +166,7 @@ describe Pheme::QueuePoller do
163
166
 
164
167
  context "without connection pool block" do
165
168
  subject { ExampleQueuePoller.new(queue_url: queue_url) }
169
+
166
170
  let(:message) { { status: 'complete' } }
167
171
  let(:notification) { { 'MessageId' => SecureRandom.uuid, 'Message' => message.to_json, 'Type' => 'Notification', 'Timestamp' => timestamp } }
168
172
  let!(:queue_message) do
@@ -172,7 +176,7 @@ describe Pheme::QueuePoller do
172
176
  )
173
177
  end
174
178
 
175
- before(:each) do
179
+ before do
176
180
  allow(subject.queue_poller).to receive(:poll).and_yield(queue_message)
177
181
  allow(subject.queue_poller).to receive(:delete_message).with(queue_message)
178
182
  end
@@ -185,6 +189,7 @@ describe Pheme::QueuePoller do
185
189
 
186
190
  context "when a valid message is yielded" do
187
191
  subject { ExampleQueuePoller.new(queue_url: queue_url) }
192
+
188
193
  let(:message) { { id: "id-123", status: "complete" } }
189
194
  let(:notification) do
190
195
  {
@@ -201,7 +206,7 @@ describe Pheme::QueuePoller do
201
206
  )
202
207
  end
203
208
 
204
- before(:each) do
209
+ before do
205
210
  allow(subject.queue_poller).to receive(:poll).and_yield(queue_message)
206
211
  allow(subject.queue_poller).to receive(:delete_message).with(queue_message)
207
212
  end
@@ -219,6 +224,7 @@ describe Pheme::QueuePoller do
219
224
 
220
225
  context "when an invalid message is yielded" do
221
226
  subject { ExampleQueuePoller.new(queue_url: queue_url) }
227
+
222
228
  let(:message) { { id: "id-123", status: "unknown-abc" } }
223
229
  let(:notification) do
224
230
  {
@@ -235,7 +241,7 @@ describe Pheme::QueuePoller do
235
241
  )
236
242
  end
237
243
 
238
- before(:each) do
244
+ before do
239
245
  allow(subject.queue_poller).to receive(:poll).and_yield(queue_message)
240
246
  allow(subject.queue_poller).to receive(:delete).with(queue_message)
241
247
  allow(Pheme.logger).to receive(:error)
@@ -257,11 +263,13 @@ describe Pheme::QueuePoller do
257
263
 
258
264
  context "AWS-event message" do
259
265
  subject { ExampleAwsEventQueuePoller.new(queue_url: queue_url) }
266
+
260
267
  let(:queue_message) { OpenStruct.new(body: { 'Records' => records }.to_json) }
261
268
  let(:records) do
262
269
  [{ 'eventVersion' => '2.0', 'eventSource': 'aws:s3' }]
263
270
  end
264
- before(:each) do
271
+
272
+ before do
265
273
  allow(subject.queue_poller).to receive(:poll).and_yield(queue_message)
266
274
  allow(subject.queue_poller).to receive(:delete).with(queue_message)
267
275
  end
@@ -272,6 +280,8 @@ describe Pheme::QueuePoller do
272
280
  end
273
281
 
274
282
  context 'SignalException' do
283
+ subject { ExampleQueuePoller.new(queue_url: queue_url) }
284
+
275
285
  let(:message) { { status: 'complete' } }
276
286
  let(:notification) { { 'MessageId' => SecureRandom.uuid, 'Message' => message.to_json, 'Type' => 'Notification', 'Timestamp' => timestamp } }
277
287
  let!(:queue_message) do
@@ -286,8 +296,6 @@ describe Pheme::QueuePoller do
286
296
  allow(subject.queue_poller).to receive(:delete_message).and_raise(SignalException.new('KILL'))
287
297
  end
288
298
 
289
- subject { ExampleQueuePoller.new(queue_url: queue_url) }
290
-
291
299
  it 'stops polling' do
292
300
  expect { subject.poll }.to raise_error(UncaughtThrowError, /stop_polling/)
293
301
  end
@@ -2,18 +2,18 @@ RSpec.describe Pheme do
2
2
  let(:rollbar) { double }
3
3
 
4
4
  describe '.rollbar' do
5
+ subject { described_class.rollbar(exception, message, data) }
6
+
5
7
  let(:exception) { StandardError }
6
8
  let(:message) { 'Unable to poll for messages' }
7
9
  let(:data) { { sqs_url: 'arn::foo::bar' } }
8
10
 
9
11
  before do
10
- Pheme.configure do |config|
12
+ described_class.configure do |config|
11
13
  config.rollbar = rollbar
12
14
  end
13
15
  end
14
16
 
15
- subject { Pheme.rollbar(exception, message, data) }
16
-
17
17
  it 'sends error message to rollbar' do
18
18
  expect(rollbar).to receive(:error).with(exception, message, data)
19
19
  subject
@@ -24,7 +24,7 @@ RSpec.configure do |config|
24
24
 
25
25
  ENV['AWS_REGION'] = 'us-east-1'
26
26
 
27
- config.before(:each) do
27
+ config.before do
28
28
  Pheme.reset_configuration!
29
29
  end
30
30
  end
@@ -1,5 +1,5 @@
1
1
  describe Pheme::TopicPublisher do
2
- before(:each) { use_default_configuration! }
2
+ before { use_default_configuration! }
3
3
 
4
4
  context 'base publisher' do
5
5
  subject { described_class.new(topic_arn: 'arn::foo::bar').publish_events }
@@ -45,11 +45,11 @@ describe Pheme::TopicPublisher do
45
45
  end
46
46
 
47
47
  context 'with string message' do
48
+ subject { described_class.new(topic_arn: topic_arn) }
49
+
48
50
  let(:topic_arn) { "arn:aws:sns:anything" }
49
51
  let(:message) { "don't touch my string" }
50
52
 
51
- subject { Pheme::TopicPublisher.new(topic_arn: topic_arn) }
52
-
53
53
  it "publishes unchanged message" do
54
54
  expect(Pheme.configuration.sns_client).to receive(:publish).with({
55
55
  topic_arn: topic_arn,
@@ -57,14 +57,26 @@ describe Pheme::TopicPublisher do
57
57
  })
58
58
  subject.publish(message)
59
59
  end
60
+
61
+ context 'with an explicit sns client' do
62
+ let(:sns_client) { double }
63
+
64
+ it "publishes unchanged message" do
65
+ expect(sns_client).to receive(:publish).with({
66
+ topic_arn: topic_arn,
67
+ message: message,
68
+ })
69
+ subject.publish(message, sns_client: sns_client)
70
+ end
71
+ end
60
72
  end
61
73
 
62
74
  context 'with message too large' do
75
+ subject { described_class.new(topic_arn: topic_arn).publish(message) }
76
+
63
77
  let(:topic_arn) { "arn:aws:sns:anything" }
64
78
  let(:message) { 'x' * (described_class::MESSAGE_SIZE_LIMIT + 1) }
65
79
 
66
- subject { Pheme::TopicPublisher.new(topic_arn: topic_arn).publish(message) }
67
-
68
80
  let(:compressed_message) do
69
81
  gz = Zlib::GzipWriter.new(StringIO.new)
70
82
  gz << message
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pheme
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.3
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Graham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-14 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -233,6 +233,7 @@ files:
233
233
  - ".gitignore"
234
234
  - ".rspec"
235
235
  - ".rubocop.yml"
236
+ - ".rubocop_todo.yml"
236
237
  - ".ruby-version"
237
238
  - CHANGELOG.md
238
239
  - Gemfile
@@ -285,7 +286,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
285
286
  - !ruby/object:Gem::Version
286
287
  version: '0'
287
288
  requirements: []
288
- rubygems_version: 3.0.1
289
+ rubyforge_project:
290
+ rubygems_version: 2.7.6
289
291
  signing_key:
290
292
  specification_version: 4
291
293
  summary: Ruby SNS publisher + SQS poller & message handler