osbourne 0.1.3 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94cc1a3817307ef19a415268a6a00f8a68240191259e3f26f8a1576741d57378
4
- data.tar.gz: fa5ed1ced8f45f6aa568aaaf66c59bb670e7df2952b55322d989175776c89a42
3
+ metadata.gz: 699bb698e3dae6272c3038bdc052597e0a6677e8f380bc1f64c12ae1c18c63a0
4
+ data.tar.gz: ca0bf27de44bff4a2e96755d0c041a73bbb75bc941c7166c44dfdd144630d3e1
5
5
  SHA512:
6
- metadata.gz: '009ae71c9cd7c3d9e37920fe48ac5a5f66b9fb2f4b96e86ad4681d33358a2b8bad7d4dab5b165ac1313f866d86b449440a14b4095e7d27ae8d0d1303b5e27e42'
7
- data.tar.gz: 825664fc5c5f5fca4b72e7757dbc47e7faae7aa67794260497c52c370ce8b51cdbf86e97e9c86d7cb0617294f16d6848259dc8af40df96263339905641e9610a
6
+ metadata.gz: b464098af275a72c4aa7a2ba600b1bdb709485f4ddaac98462f6513b8c2ae6930c9e8b8bdb478cf58618e39f1d224070957af61fa4633a4032e53ea0e10c3c9e
7
+ data.tar.gz: 32b5e08de9d525e95408525e0d9c0723383a33d3ac8aa688e323af9c49db1bbb15023e2fde9de099750e10a166770d58e3aba8826392702f61355bfd715bb308
data/README.md CHANGED
@@ -1,5 +1,18 @@
1
1
  [![Maintainability](https://api.codeclimate.com/v1/badges/295897ee565c04ad1aa5/maintainability)](https://codeclimate.com/github/stevenallen05/osbourne/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/295897ee565c04ad1aa5/test_coverage)](https://codeclimate.com/github/stevenallen05/osbourne/test_coverage)
2
2
 
3
+ - [Osbourne](#osbourne)
4
+ + [Features](#features)
5
+ * [Installation](#installation)
6
+ + [AWS credentials](#aws-credentials)
7
+ + [Production AWS](#production-aws)
8
+ + [Mock AWS for local devlopment](#mock-aws-for-local-devlopment)
9
+ + [RSpec](#rspec)
10
+ * [Usage](#usage)
11
+ + [Publishing a message](#publishing-a-message)
12
+ + [Generating a worker](#generating-a-worker)
13
+ + [Running workers](#running-workers)
14
+ * [License](#license)
15
+
3
16
  # Osbourne
4
17
 
5
18
  A fan-out pubsub message implementation for Rails 5. Named after the world's most famous plumber, Ozzy Osbourne.
@@ -11,6 +24,7 @@ A fan-out pubsub message implementation for Rails 5. Named after the world's mos
11
24
  * Worker generator via `rails g osbourne:worker worker_name topic`
12
25
  * Auto-provisioning of SQS queues, SNS topics, and subscriptions between them
13
26
  * Built-in support for locking to prevent accidental duplicate message delivery
27
+ * Test helpers
14
28
 
15
29
  Inspired heavily by the excellent Shoryuken & Circuitry gems
16
30
 
@@ -71,6 +85,51 @@ AWS_REGION=us-east-1
71
85
 
72
86
  There must be a region set. Use whichever is appropriate for your situation.
73
87
 
88
+ ### RSpec
89
+
90
+ To turn on test mode, in your spec helper:
91
+
92
+ ```ruby
93
+ require 'osbourne/test'
94
+ ```
95
+
96
+ This will enable test mode for provisioning and publishing. Example:
97
+
98
+ ```ruby
99
+ class TestWorker < Osbourne::WorkerBase
100
+ worker_config topics: %w[test_topic]
101
+
102
+ def process(message)
103
+ # Do stuff here...
104
+ end
105
+ end
106
+
107
+ RSpec.describe TestWorker do
108
+ subject(:worker) { described_class.new }
109
+
110
+ before do
111
+ # This will call `#publish` on `TestWorker`
112
+ Osbourne.publish('test_topic', 'message')
113
+ end
114
+ end
115
+
116
+ ```
117
+
118
+ There is also a test `Message` object you can use and pass directly into your workers. It stubs out the message validation, and creates a mock `message` as if it had been broadcast from SNS.
119
+
120
+ Example:
121
+
122
+ ```ruby
123
+
124
+ let(:test_worker) { TestWorker.new }
125
+ let(:message) { Osbourne::Test::Message.new(topic: "test", body: "thing") }
126
+
127
+ # Now you can use `test_worker.process(message)` in your specs
128
+
129
+ ```
130
+
131
+
132
+
74
133
  ## Usage
75
134
 
76
135
  ### Publishing a message
@@ -5,7 +5,6 @@ class <%= name.singularize.camelcase %>Worker < Osbourne::WorkerBase
5
5
  worker_config topics: %w[<%= topic.join(" ") %>] #, max_batch_size: 10, max_wait: 10
6
6
 
7
7
  def process(message)
8
- puts message.raw_body # This will always be a string, representing the entirety of the message
9
8
  puts message.parsed_body # If the message came from a SNS broadcast,
10
9
  # as opposed to a direct SQS message, it will come from here
11
10
  puts message.topic # The topic this message was published to.
data/lib/osbourne.rb CHANGED
@@ -25,10 +25,14 @@ module Osbourne
25
25
  attr_writer :sns_client, :sqs_client
26
26
 
27
27
  def sns_client
28
+ return if Osbourne.test_mode?
29
+
28
30
  @sns_client ||= Aws::SNS::Client.new(Osbourne.config.sns_config)
29
31
  end
30
32
 
31
33
  def sqs_client
34
+ return if Osbourne.test_mode?
35
+
32
36
  @sqs_client ||= Aws::SQS::Client.new(Osbourne.config.sqs_config)
33
37
  end
34
38
 
@@ -8,7 +8,7 @@ module Osbourne
8
8
  module Config
9
9
  module FileLoader
10
10
  def self.load(cfile, environment="development")
11
- return nil unless File.exist?(cfile)
11
+ return false unless should_run?(cfile)
12
12
 
13
13
  base_opts = YAML.safe_load(ERB.new(IO.read(cfile)).result) || {}
14
14
  env_opts = base_opts[environment] || {}
@@ -17,6 +17,10 @@ module Osbourne
17
17
  Osbourne.config.sqs_config = env_opts["subscriber"].symbolize_keys || {}
18
18
  true
19
19
  end
20
+
21
+ def self.should_run?(cfile)
22
+ File.exist?(cfile) && !Osbourne.test_mode?
23
+ end
20
24
  end
21
25
  end
22
26
  end
@@ -13,6 +13,18 @@ module Osbourne
13
13
  config.cache ||= ActiveSupport::Cache::NullStore.new
14
14
  end
15
15
 
16
+ def test_mode?
17
+ false
18
+ end
19
+
20
+ def test_mode!
21
+ @test_mode = true
22
+ end
23
+
24
+ def test_mode=(test_mode)
25
+ @test_mode = test_mode
26
+ end
27
+
16
28
  def dead_letter
17
29
  config.dead_letter ||= true
18
30
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "osbourne"
4
- require "byebug"
5
4
 
6
5
  module Osbourne
7
6
  class Launcher
@@ -13,8 +13,6 @@ module Osbourne
13
13
  %w[config/osbourne.yml.erb config/osbourne.yml].find do |filename|
14
14
  Osbourne::Config::FileLoader.load(filename, env)
15
15
  end
16
-
17
- Osbourne.provision_worker_queues
18
16
  end
19
17
  end
20
18
  end
@@ -29,6 +29,7 @@ module Osbourne
29
29
  @launcher = Osbourne::Launcher.new
30
30
 
31
31
  begin
32
+ Osbourne.provision_worker_queues
32
33
  @launcher.start!
33
34
 
34
35
  while readable_io = IO.select([self_read]) # rubocop:disable Lint/AssignmentInCondition
@@ -4,6 +4,8 @@ module Osbourne
4
4
  module Services
5
5
  module QueueProvisioner
6
6
  def provision_worker_queues
7
+ return if Osbourne.test_mode?
8
+
7
9
  Osbourne.logger.info "Workers found: #{Osbourne::WorkerBase.descendants.map(&:name).join(', ')}"
8
10
  Osbourne.logger.info "Provisioning queues for all workers"
9
11
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "osbourne/test/mock_pubsub"
4
+ require "osbourne/test/message"
5
+
6
+ module Osbourne
7
+ class << self
8
+ def test_mode?
9
+ true
10
+ end
11
+
12
+ def publish(topic, message)
13
+ Osbourne::Test::MockPubsub.mock_publish(topic, message)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osbourne
4
+ module Test
5
+ class Message
6
+ attr_reader :topic, :parsed_body
7
+ def initialize(topic:, body:)
8
+ @topic = topic
9
+ @parsed_body = body
10
+ end
11
+
12
+ def id
13
+ @id ||= SecureRandom.uuid
14
+ end
15
+
16
+ def valid?
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "osbourne/test/message"
4
+ module Osbourne
5
+ module Test
6
+ class MockPubsub
7
+ class << self
8
+ def mock_publish(topic, message)
9
+ Osbourne::WorkerBase.descendants.each do |worker|
10
+ msg = Osbourne::Test::Message.new(topic: topic, body: message)
11
+ worker.new.process(msg) if worker.config[:topic_names].include? topic
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -14,6 +14,8 @@ module Osbourne
14
14
  end
15
15
 
16
16
  def publish(message)
17
+ return if Osbourne.test_mode?
18
+
17
19
  Osbourne.logger.info "[PUB] TOPIC: `#{name}` MESSAGE: `#{message}`"
18
20
  sns.publish(topic_arn: arn, message: message.is_a?(String) ? message : message.to_json)
19
21
  end
@@ -21,6 +23,8 @@ module Osbourne
21
23
  private
22
24
 
23
25
  def ensure_topic
26
+ return if Osbourne.test_mode?
27
+
24
28
  Osbourne.logger.debug "Ensuring topic `#{name}` exists"
25
29
  Osbourne.cache.fetch("osbourne_existing_topic_arn_for_#{name}") do
26
30
  sns.create_topic(name: name).topic_arn
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Osbourne
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,85 +1,109 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osbourne
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Allen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-09 00:00:00.000000000 Z
11
+ date: 2018-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '3'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: aws-sdk-sns
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: '1'
39
+ version: '1.5'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '2'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
39
48
  - !ruby/object:Gem::Version
40
- version: '1'
49
+ version: '1.5'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '2'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: aws-sdk-sqs
43
55
  requirement: !ruby/object:Gem::Requirement
44
56
  requirements:
45
- - - "~>"
57
+ - - ">="
46
58
  - !ruby/object:Gem::Version
47
- version: '1'
59
+ version: '1.6'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '2'
48
63
  type: :runtime
49
64
  prerelease: false
50
65
  version_requirements: !ruby/object:Gem::Requirement
51
66
  requirements:
52
- - - "~>"
67
+ - - ">="
53
68
  - !ruby/object:Gem::Version
54
- version: '1'
69
+ version: '1.6'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '2'
55
73
  - !ruby/object:Gem::Dependency
56
74
  name: rails
57
75
  requirement: !ruby/object:Gem::Requirement
58
76
  requirements:
59
- - - "~>"
77
+ - - ">="
60
78
  - !ruby/object:Gem::Version
61
79
  version: '5'
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '6'
62
83
  type: :runtime
63
84
  prerelease: false
64
85
  version_requirements: !ruby/object:Gem::Requirement
65
86
  requirements:
66
- - - "~>"
87
+ - - ">="
67
88
  - !ruby/object:Gem::Version
68
89
  version: '5'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '6'
69
93
  - !ruby/object:Gem::Dependency
70
94
  name: thor
71
95
  requirement: !ruby/object:Gem::Requirement
72
96
  requirements:
73
- - - "~>"
97
+ - - ">="
74
98
  - !ruby/object:Gem::Version
75
- version: '0'
99
+ version: '0.19'
76
100
  type: :runtime
77
101
  prerelease: false
78
102
  version_requirements: !ruby/object:Gem::Requirement
79
103
  requirements:
80
- - - "~>"
104
+ - - ">="
81
105
  - !ruby/object:Gem::Version
82
- version: '0'
106
+ version: '0.19'
83
107
  - !ruby/object:Gem::Dependency
84
108
  name: bundler
85
109
  requirement: !ruby/object:Gem::Requirement
@@ -112,30 +136,30 @@ dependencies:
112
136
  name: guard
113
137
  requirement: !ruby/object:Gem::Requirement
114
138
  requirements:
115
- - - "~>"
139
+ - - ">="
116
140
  - !ruby/object:Gem::Version
117
141
  version: '2'
118
142
  type: :development
119
143
  prerelease: false
120
144
  version_requirements: !ruby/object:Gem::Requirement
121
145
  requirements:
122
- - - "~>"
146
+ - - ">="
123
147
  - !ruby/object:Gem::Version
124
148
  version: '2'
125
149
  - !ruby/object:Gem::Dependency
126
150
  name: guard-bundler
127
151
  requirement: !ruby/object:Gem::Requirement
128
152
  requirements:
129
- - - "~>"
153
+ - - ">="
130
154
  - !ruby/object:Gem::Version
131
- version: '2.1'
155
+ version: '2'
132
156
  type: :development
133
157
  prerelease: false
134
158
  version_requirements: !ruby/object:Gem::Requirement
135
159
  requirements:
136
- - - "~>"
160
+ - - ">="
137
161
  - !ruby/object:Gem::Version
138
- version: '2.1'
162
+ version: '2'
139
163
  - !ruby/object:Gem::Dependency
140
164
  name: guard-rspec
141
165
  requirement: !ruby/object:Gem::Requirement
@@ -154,86 +178,98 @@ dependencies:
154
178
  name: mock_redis
155
179
  requirement: !ruby/object:Gem::Requirement
156
180
  requirements:
157
- - - "~>"
181
+ - - ">="
158
182
  - !ruby/object:Gem::Version
159
- version: '0'
183
+ version: '0.19'
160
184
  type: :development
161
185
  prerelease: false
162
186
  version_requirements: !ruby/object:Gem::Requirement
163
187
  requirements:
164
- - - "~>"
188
+ - - ">="
165
189
  - !ruby/object:Gem::Version
166
- version: '0'
190
+ version: '0.19'
167
191
  - !ruby/object:Gem::Dependency
168
192
  name: pry-byebug
169
193
  requirement: !ruby/object:Gem::Requirement
170
194
  requirements:
171
- - - "~>"
195
+ - - ">="
172
196
  - !ruby/object:Gem::Version
173
197
  version: '3.6'
174
198
  type: :development
175
199
  prerelease: false
176
200
  version_requirements: !ruby/object:Gem::Requirement
177
201
  requirements:
178
- - - "~>"
202
+ - - ">="
179
203
  - !ruby/object:Gem::Version
180
204
  version: '3.6'
181
205
  - !ruby/object:Gem::Dependency
182
206
  name: rake
183
207
  requirement: !ruby/object:Gem::Requirement
184
208
  requirements:
185
- - - "~>"
209
+ - - ">="
186
210
  - !ruby/object:Gem::Version
187
- version: '10.0'
211
+ version: '10'
188
212
  type: :development
189
213
  prerelease: false
190
214
  version_requirements: !ruby/object:Gem::Requirement
191
215
  requirements:
192
- - - "~>"
216
+ - - ">="
193
217
  - !ruby/object:Gem::Version
194
- version: '10.0'
218
+ version: '10'
195
219
  - !ruby/object:Gem::Dependency
196
220
  name: redis
197
221
  requirement: !ruby/object:Gem::Requirement
198
222
  requirements:
199
- - - "~>"
223
+ - - ">="
200
224
  - !ruby/object:Gem::Version
201
225
  version: '4'
226
+ - - "<"
227
+ - !ruby/object:Gem::Version
228
+ version: '5'
202
229
  type: :development
203
230
  prerelease: false
204
231
  version_requirements: !ruby/object:Gem::Requirement
205
232
  requirements:
206
- - - "~>"
233
+ - - ">="
207
234
  - !ruby/object:Gem::Version
208
235
  version: '4'
236
+ - - "<"
237
+ - !ruby/object:Gem::Version
238
+ version: '5'
209
239
  - !ruby/object:Gem::Dependency
210
240
  name: rspec
211
241
  requirement: !ruby/object:Gem::Requirement
212
242
  requirements:
213
- - - "~>"
243
+ - - ">="
214
244
  - !ruby/object:Gem::Version
215
- version: '3'
245
+ version: '3.2'
246
+ - - "<"
247
+ - !ruby/object:Gem::Version
248
+ version: '4'
216
249
  type: :development
217
250
  prerelease: false
218
251
  version_requirements: !ruby/object:Gem::Requirement
219
252
  requirements:
220
- - - "~>"
253
+ - - ">="
221
254
  - !ruby/object:Gem::Version
222
- version: '3'
255
+ version: '3.2'
256
+ - - "<"
257
+ - !ruby/object:Gem::Version
258
+ version: '4'
223
259
  - !ruby/object:Gem::Dependency
224
260
  name: rubocop
225
261
  requirement: !ruby/object:Gem::Requirement
226
262
  requirements:
227
- - - "~>"
263
+ - - ">="
228
264
  - !ruby/object:Gem::Version
229
- version: '0'
265
+ version: '0.50'
230
266
  type: :development
231
267
  prerelease: false
232
268
  version_requirements: !ruby/object:Gem::Requirement
233
269
  requirements:
234
- - - "~>"
270
+ - - ">="
235
271
  - !ruby/object:Gem::Version
236
- version: '0'
272
+ version: '0.50'
237
273
  - !ruby/object:Gem::Dependency
238
274
  name: rubocop-rspec
239
275
  requirement: !ruby/object:Gem::Requirement
@@ -316,6 +352,9 @@ files:
316
352
  - lib/osbourne/services/sns.rb
317
353
  - lib/osbourne/services/sqs.rb
318
354
  - lib/osbourne/subscription.rb
355
+ - lib/osbourne/test.rb
356
+ - lib/osbourne/test/message.rb
357
+ - lib/osbourne/test/mock_pubsub.rb
319
358
  - lib/osbourne/topic.rb
320
359
  - lib/osbourne/version.rb
321
360
  - lib/osbourne/worker_base.rb