pheme 3.4.0 → 4.0.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: 04243d79c91d1f19e0e2e2e9d04290a3a9dafa5acd907eec7e2dc0d80c99e21c
4
- data.tar.gz: 9229a8eb9e453971f4b780954b7be9e770e784ffc6a129fbf331c232e9471247
3
+ metadata.gz: '0711608ea3831e4718cb928b6e3db90bd049c302b5ae864c4e457f3797215add'
4
+ data.tar.gz: 1387f1048aef3104ff08aad3fb5cdc7d3a542bfbb9b2c71e49f02b78fe67b8c3
5
5
  SHA512:
6
- metadata.gz: bf5242abbfcc3b4ae522cbc0479c597d59a69835c33a1de2afe5e0a0eb70ef2afec4d73765367bb28c9c765ed702137f1d35117c5837e4eb3858a036ce5d6b5f
7
- data.tar.gz: 773072b1e6c9ab9ae6437ae5ff61effca1ac3a3a389c933df8970acc35dc7bae26af6af9e030d5ab371080f12c4d140ad5ce1e161d4bd98d6e71015449dc3781
6
+ metadata.gz: f6ef008cf929f3eb8e6f9d846ee316982e378039f9a40b7900eb52bedd073fbfb80221d6de1dfb72d74b660f7faf75e0bad5d9f20148368d9332446704267dda
7
+ data.tar.gz: be52cf4fe2479f239568488fd5c498642842bb92646496907598a211700a1ad994fd889fb9d99c8923f411c24c0d258224fddbb3eb88414207ee92aff7bf437e
@@ -6,4 +6,4 @@ inherit_gem:
6
6
 
7
7
  AllCops:
8
8
  # Specify your target Ruby version here (only major/minor versions):
9
- TargetRubyVersion: 2.4
9
+ TargetRubyVersion: 2.4
@@ -4,6 +4,12 @@ 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
+ ## 4.0.0 - 2020-03-18
8
+ ### Breaking Changes
9
+ - Add the ability for SQS to receive message attributes
10
+ - `handle` function of `QueuePoller` now takes a third parameter `message_attributes`
11
+ - blocks or `MessageHandler`s passed to `QueuePoller` can use this `message_attributes`
12
+
7
13
  ## 3.4.0 - 2020-03-17
8
14
  ### Added
9
15
  - Add the ability to pass message attributes to SNS
@@ -1,10 +1,11 @@
1
1
  module Pheme
2
2
  class MessageHandler
3
- attr_reader :message, :metadata, :timestamp
3
+ attr_reader :message, :metadata, :message_attributes, :timestamp
4
4
 
5
- def initialize(message:, metadata: {})
5
+ def initialize(message:, metadata: {}, message_attributes: {})
6
6
  @message = message
7
7
  @metadata = metadata
8
+ @message_attributes = message_attributes
8
9
  end
9
10
 
10
11
  def handle
@@ -1,6 +1,7 @@
1
1
  require_relative 'compression'
2
2
 
3
3
  module Pheme
4
+ # rubocop:disable Metrics/ClassLength
4
5
  class QueuePoller
5
6
  include Compression
6
7
 
@@ -51,6 +52,7 @@ module Pheme
51
52
  end
52
53
  end
53
54
 
55
+ # rubocop:disable Metrics/AbcSize
54
56
  def poll
55
57
  time_start = log_polling_start
56
58
  queue_poller.poll(poller_configuration) do |queue_message|
@@ -59,7 +61,8 @@ module Pheme
59
61
  begin
60
62
  content = parse_body(queue_message)
61
63
  metadata = parse_metadata(queue_message)
62
- with_optional_connection_pool_block { handle(content, metadata) }
64
+ message_attributes = parse_message_attributes(queue_message)
65
+ with_optional_connection_pool_block { handle(content, metadata, message_attributes) }
63
66
  queue_poller.delete_message(queue_message)
64
67
  log_delete(queue_message)
65
68
  @messages_processed += 1
@@ -73,6 +76,7 @@ module Pheme
73
76
  end
74
77
  log_polling_end(time_start)
75
78
  end
79
+ # rubocop:enable Metrics/AbcSize
76
80
 
77
81
  # returns queue_message.body as hash,
78
82
  # stores and parses get_content to body[:content]
@@ -105,6 +109,15 @@ module Pheme
105
109
  { timestamp: message_body['Timestamp'], topic_arn: message_body['TopicArn'] }
106
110
  end
107
111
 
112
+ def parse_message_attributes(queue_message)
113
+ message_attributes = {}
114
+ queue_message.message_attributes&.each do |key, value|
115
+ message_attributes[key.to_sym] = coerce_message_attribute(value)
116
+ end
117
+
118
+ message_attributes
119
+ end
120
+
108
121
  def get_metadata(message_body)
109
122
  message_body.except('Message', 'Records')
110
123
  end
@@ -123,11 +136,11 @@ module Pheme
123
136
  RecursiveOpenStruct.new({ wrapper: parsed_body }, recurse_over_arrays: true).wrapper
124
137
  end
125
138
 
126
- def handle(message, metadata)
139
+ def handle(message, metadata, message_attributes)
127
140
  if @message_handler
128
- @message_handler.new(message: message, metadata: metadata).handle
141
+ @message_handler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
129
142
  elsif @block_message_handler
130
- @block_message_handler.call(message, metadata)
143
+ @block_message_handler.call(message, metadata, message_attributes)
131
144
  else
132
145
  raise NotImplementedError
133
146
  end
@@ -135,6 +148,22 @@ module Pheme
135
148
 
136
149
  private
137
150
 
151
+ def coerce_message_attribute(value)
152
+ case value['data_type']
153
+ when 'String'
154
+ value['string_value']
155
+ when 'Number'
156
+ JSON.parse(value['string_value'])
157
+ when 'String.Array'
158
+ JSON.parse(value['string_value'])
159
+ when 'Binary'
160
+ value['binary_value']
161
+ else
162
+ Pheme.logger.info("Unsupported custom data type")
163
+ value["binary_value"] || value["string_value"]
164
+ end
165
+ end
166
+
138
167
  def with_optional_connection_pool_block
139
168
  if connection_pool_block
140
169
  ActiveRecord::Base.connection_pool.with_connection { yield }
@@ -192,4 +221,5 @@ module Pheme
192
221
  }.to_json)
193
222
  end
194
223
  end
224
+ # rubocop:enable Metrics/ClassLength
195
225
  end
@@ -1,3 +1,3 @@
1
1
  module Pheme
2
- VERSION = '3.4.0'.freeze
2
+ VERSION = '4.0.0'.freeze
3
3
  end
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_dependency "smarter_csv", "~> 1"
30
30
 
31
31
  s.add_development_dependency 'bundler'
32
- s.add_development_dependency 'coveralls'
32
+ s.add_development_dependency 'coveralls', "~> 0.8"
33
33
  s.add_development_dependency 'git'
34
34
  s.add_development_dependency 'rake'
35
35
  s.add_development_dependency 'rspec'
@@ -14,7 +14,7 @@ describe Pheme::QueuePoller do
14
14
  let(:message_id) { SecureRandom.uuid }
15
15
 
16
16
  context 'base poller' do
17
- subject { described_class.new(queue_url: queue_url).handle(nil, nil) }
17
+ subject { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }
18
18
 
19
19
  it 'does not implement handle' do
20
20
  expect { subject }.to raise_error(NotImplementedError)
@@ -90,13 +90,13 @@ describe Pheme::QueuePoller do
90
90
  context 'when handling messages' do
91
91
  context 'when doing it the old way, via the handle function' do
92
92
  it 'uses the handle function by default' do
93
- expect { described_class.new(queue_url: queue_url).handle(nil, nil) }.to raise_error(NotImplementedError)
93
+ expect { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
94
94
  end
95
95
  end
96
96
 
97
97
  context 'when given a message_handler as parameter' do
98
98
  it 'uses default when given nil' do
99
- expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil) }.to raise_error(NotImplementedError)
99
+ expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
100
100
  end
101
101
 
102
102
  it 'uses default when given invalid message_handler' do
@@ -106,9 +106,11 @@ describe Pheme::QueuePoller do
106
106
  it 'uses handler when given one' do
107
107
  mock_handler = double('MessageHandler')
108
108
  allow(mock_handler).to receive(:handle)
109
- allow(ExampleMessageHandler).to receive(:new).with(message: 'message', metadata: 'metadata').and_return(mock_handler)
109
+ allow(ExampleMessageHandler).to receive(:new).
110
+ with(message: 'message', metadata: 'metadata', message_attributes: 'message_attributes').
111
+ and_return(mock_handler)
110
112
 
111
- described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata')
113
+ described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata', 'message_attributes')
112
114
  expect(mock_handler).to have_received(:handle).once
113
115
  end
114
116
  end
@@ -117,12 +119,12 @@ describe Pheme::QueuePoller do
117
119
  it 'uses handler when given one' do
118
120
  mock_handler = spy('MessageHandler')
119
121
 
120
- poller = described_class.new(queue_url: queue_url) do |message, metadata|
121
- mock_handler.process(message, metadata)
122
+ poller = described_class.new(queue_url: queue_url) do |message, metadata, message_attributes|
123
+ mock_handler.process(message, metadata, message_attributes)
122
124
  end
123
- poller.handle('message', 'metadata')
125
+ poller.handle('message', 'metadata', 'message_attributes')
124
126
 
125
- expect(mock_handler).to have_received(:process).with('message', 'metadata').once
127
+ expect(mock_handler).to have_received(:process).with('message', 'metadata', 'message_attributes').once
126
128
  end
127
129
 
128
130
  it 'fails on invalid handler' do
@@ -134,6 +136,63 @@ describe Pheme::QueuePoller do
134
136
  end
135
137
  end
136
138
 
139
+ describe '#parse_message_attributes' do
140
+ subject { described_class.new(queue_url: queue_url).parse_message_attributes(queue_message) }
141
+
142
+ context 'when no message_attributes' do
143
+ it { is_expected.to eq({}) }
144
+ end
145
+
146
+ context 'when message attributes' do
147
+ let(:queue_message) do
148
+ OpenStruct.new(
149
+ body: { Message: message }.to_json,
150
+ message_id: message_id,
151
+ message_attributes: {
152
+ "key" => {
153
+ "data_type" => data_type,
154
+ "string_value" => string_value,
155
+ },
156
+ },
157
+ )
158
+ end
159
+
160
+ context 'when data_type is String' do
161
+ let(:data_type) { 'String' }
162
+ let(:string_value) { 'some-string-value' }
163
+ let(:expected_value) { 'some-string-value' }
164
+
165
+ its([:key]) { is_expected.to eq(expected_value) }
166
+ end
167
+
168
+ context 'when data_type is Number' do
169
+ let(:data_type) { 'Number' }
170
+
171
+ context 'and it is an int' do
172
+ let(:string_value) { '1' }
173
+ let(:expected_value) { 1 }
174
+
175
+ its([:key]) { is_expected.to eq(expected_value) }
176
+ end
177
+
178
+ context 'and it is a float' do
179
+ let(:string_value) { '1.5' }
180
+ let(:expected_value) { 1.5 }
181
+
182
+ its([:key]) { is_expected.to eq(expected_value) }
183
+ end
184
+ end
185
+
186
+ context 'when data_type is String.array' do
187
+ let(:data_type) { 'String.Array' }
188
+ let(:string_value) { '["sdfsdf",1,2,null,true,false]' }
189
+ let(:expected_value) { ["sdfsdf", 1, 2, nil, true, false] }
190
+
191
+ its([:key]) { is_expected.to eq(expected_value) }
192
+ end
193
+ end
194
+ end
195
+
137
196
  describe "#parse_body" do
138
197
  subject { poller.parse_body(queue_message) }
139
198
 
@@ -305,6 +364,7 @@ describe Pheme::QueuePoller do
305
364
  expect(ExampleMessageHandler).to receive(:new).with(
306
365
  message: RecursiveOpenStruct.new(message),
307
366
  metadata: { timestamp: timestamp, topic_arn: topic_arn },
367
+ message_attributes: {},
308
368
  )
309
369
  subject.poll
310
370
  end
@@ -3,10 +3,10 @@ class ExampleQueuePoller < Pheme::QueuePoller
3
3
  super(queue_url: queue_url, **kwargs)
4
4
  end
5
5
 
6
- def handle(message, metadata)
6
+ def handle(message, metadata, message_attributes)
7
7
  case message.status
8
8
  when 'complete', 'rejected'
9
- ExampleMessageHandler.new(message: message, metadata: metadata).handle
9
+ ExampleMessageHandler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
10
10
  else
11
11
  raise ArgumentError, "Unknown message status: #{message.status}"
12
12
  end
@@ -1,5 +1,6 @@
1
- Pheme::QueuePoller.new(queue_url: 'http://mock_url.test') do |message, metadata|
1
+ Pheme::QueuePoller.new(queue_url: 'http://mock_url.test') do |message, metadata, message_attributes|
2
2
  # handle the message
3
3
  pp message
4
4
  pp metadata
5
+ pp message_attributes
5
6
  end
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.4.0
4
+ version: 4.0.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: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2020-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -98,16 +98,16 @@ dependencies:
98
98
  name: coveralls
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '0.8'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '0.8'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: git
113
113
  requirement: !ruby/object:Gem::Requirement