fastly_nsq 0.1.2 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 48ea2dde563e4b7556c6d9a9f6841f4350e45013
4
- data.tar.gz: bc4035a845e23506b744860d886091c02656832e
3
+ metadata.gz: ed99890b9268655e4d1e7b151e53274bcbe147c9
4
+ data.tar.gz: 42d9dffa0b05e5a02be41dd92192c3a3f9834462
5
5
  SHA512:
6
- metadata.gz: 05ca0f0d7ec7e3c8145462725964424d417a4b4fc714cc1f8a73324ebdf1c2996b618b8f89ae6fc2586e46080ce5a641c155a05d09f4dcef8b189cc2c9a01b4c
7
- data.tar.gz: 5fa5f796f804491aeeac0f66e3238c28b404c75d459ebfc749e5317fbc86319a6dfed4bdb6816bc84b275dc9bd88847ad25d76c95ff15abe493fda602459aad8
6
+ metadata.gz: 81b4855596f0aa86d2457ac2e1375e086999fb37b62be50b6f39d5895de51c34cf807b08355963697062423591dfa69e02567b7b2e1610b097e86caa33472cd2
7
+ data.tar.gz: b4e51dada6b9cb4b2ac0110911dd86a029be91ed4f3cf8f542095acb68333ba16a8c23f2879a26822b3fcd60cc2b3b4d8aae022e47e7a3438b7ff3c8ca81637b
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ README.md
3
+ CHANGELOG.md
4
+
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /.bundle
2
+ /Gemfile.lock
3
+ /html/
4
+ /pkg/
5
+ /vendor/cache/*.gem
data/.rdoc_options ADDED
@@ -0,0 +1,16 @@
1
+ --- !ruby/object:RDoc::Options
2
+ encoding: UTF-8
3
+ static_path: []
4
+ rdoc_include:
5
+ - .
6
+ charset: UTF-8
7
+ exclude:
8
+ hyperlink_all: false
9
+ line_numbers: false
10
+ main_page: README.md
11
+ markup: markdown
12
+ show_hash: false
13
+ tab_width: 8
14
+ title: fastly_nsq Documentation
15
+ visibility: :protected
16
+ webcvs:
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.1.8
5
+ - 2.2.4
6
+ - 2.3.0
7
+ script:
8
+ - bundle exec rake test
9
+ notifications:
10
+ slack:
11
+ rooms:
12
+ - 'fastly:hFvhBQKliYl9QAO3VujcrLhe#billy'
13
+ on_success: change
14
+ on_failure: change
15
+ email:
16
+ on_success: never
17
+ on_failure: never
data/ChangeLog.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.1.0 / 2016-01-25
2
+
3
+ * Initial release:
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'minitest-utils', require: false
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Fastly, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # fastly_nsq [![Build Status](https://travis-ci.org/fastly/fastly_nsq.svg?branch=master)](https://travis-ci.org/fastly/fastly_nsq)
2
+
3
+ *NOTE: This is a point-release
4
+ which is not yet suitable for production.
5
+ Use at your own peril.*
6
+
7
+ NSQ adapter and testing objects
8
+ for using the NSQ messaging system
9
+ in your Ruby project.
10
+
11
+ This library is intended
12
+ to facilitate publishing and consuming
13
+ messages on an NSQ messaging queue.
14
+
15
+ We also include fakes
16
+ to make testing easier.
17
+
18
+ This library is dependent
19
+ on the [`nsq-ruby`] gem.
20
+
21
+ [`nsq-ruby`]: https://github.com/wistia/nsq-ruby
22
+
23
+ Please use [GitHub Issues] to report bugs.
24
+
25
+ [GitHub Issues]: https://github.com/fastly/fastly_nsq/issues
26
+
27
+
28
+ ## Install
29
+
30
+ `fastly_nsq` is a Ruby Gem
31
+ tested against Rails `>= 4.2`
32
+ and Ruby `>= 2.0`.
33
+
34
+ To get started,
35
+ add `fastly_nsq` to your `Gemfile`
36
+ and `bundle install`.
37
+
38
+ ## Usage
39
+
40
+ *IMPORTANT NOTE:* You must create your own `MessageProcessor` class
41
+ for this gem to work in your application.
42
+
43
+ See more information below.
44
+
45
+ ### `MessageQueue::Producer`
46
+
47
+ This is a class
48
+ which provides an adapter to the
49
+ fake and real NSQ producers.
50
+ These are used to
51
+ write messages onto the queue:
52
+
53
+ ```ruby
54
+ message_data = {
55
+ "event_type": "heartbeat",
56
+ "data": {
57
+ "key": "value"
58
+ }
59
+ }
60
+
61
+ producer = MessageQueue::Producer.new(
62
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
63
+ topic: topic,
64
+ ).connection
65
+
66
+ producer.write(message_data.to_json)
67
+ ```
68
+
69
+ The mock/real strategy used
70
+ can be switched
71
+ by adding an environment variable
72
+ to your application:
73
+
74
+ ```ruby
75
+ # for the fake
76
+ ENV['FAKE_QUEUE'] == true
77
+
78
+ # for the real thing
79
+ ENV['FAKE_QUEUE'] == false
80
+ ```
81
+
82
+ ### `MessageQueue::Consumer`
83
+ This is a class
84
+ which provides an adapter to the
85
+ fake and real NSQ consumers.
86
+ These are used to
87
+ read messages off of the queue:
88
+
89
+ ```ruby
90
+ consumer = MessageQueue::Consumer.new(
91
+ topic: 'topic',
92
+ channel: 'channel'
93
+ ).connection
94
+
95
+ consumer.size #=> 1
96
+ message = consumer.pop
97
+ message.body #=>'hey this is my message!'
98
+ message.finish
99
+ consumer.size #=> 0
100
+ ```
101
+
102
+ As above,
103
+ the mock/real strategy used
104
+ can be switched by setting the
105
+ `FAKE_QUEUE` environment variable appropriately.
106
+
107
+ ### `MessageQueue::Listener`
108
+
109
+ To process the next message on the queue:
110
+
111
+ ```ruby
112
+ topic = 'user_created'
113
+ channel = 'my_consuming_service'
114
+
115
+ MessageQueue::Listener.new(topic: topic, channel: channel).process_next_message
116
+ ```
117
+
118
+ This will pop the next message
119
+ off of the queue
120
+ and send it to `MessageProcessor.new(message).go`.
121
+
122
+ To initiate a blocking loop to process messages continuously:
123
+
124
+ ```ruby
125
+ topic = 'user_created'
126
+ channel = 'my_consuming_service'
127
+
128
+ MessageQueue::Listener.new(topic: topic, channel: channel).go
129
+ ```
130
+
131
+ This will block until
132
+ there is a new message on the queue,
133
+ pop the next message
134
+ off of the queue
135
+ and send it to `MessageProcessor.new(message).go`.
136
+
137
+
138
+ ### Real vs. Fake
139
+
140
+ The real strategy
141
+ creates a connection
142
+ to `nsq-ruby`'s
143
+ `Nsq::Producer` and `Nsq::Consumer` classes.
144
+
145
+ The fake strategy
146
+ mocks the connection
147
+ to NSQ for testing purposes.
148
+ It adheres to the same API
149
+ as the real adapter.
150
+
151
+
152
+ ## Configuration
153
+
154
+ ### Processing Messages
155
+
156
+ This gem expects you to create a
157
+ new class called `MessageProcessor`
158
+ which will process messages
159
+ once they are consumed off of the queue topic.
160
+
161
+ This class needs to adhere to the following API:
162
+
163
+ ```ruby
164
+ class MessageProcessor
165
+ # This an instance of NSQ::Message or FakeMessageQueue::Message
166
+ def initialize(message)
167
+ @message = message
168
+ end
169
+
170
+ def start
171
+ # Do things with the message. It's JSON body is accessible by @message.body.
172
+
173
+ # Finish the message to let the queue know it is complete like so:
174
+ @message.finish
175
+ end
176
+ end
177
+ ```
178
+
179
+ ### Environment Variables
180
+
181
+ The URLs for the various
182
+ NSQ endpoints are expected
183
+ in `ENV` variables.
184
+
185
+ Below are the required variables
186
+ and sample values for using
187
+ stock NSQ on OS X,
188
+ installed via Homebrew:
189
+
190
+ ```shell
191
+ BROADCAST_ADDRESS='127.0.0.1'
192
+ NSQD_TCP_ADDRESS='127.0.0.1:4150'
193
+ NSQD_HTTP_ADDRESS='127.0.0.1:4151'
194
+ NSQLOOKUPD_TCP_ADDRESS='127.0.0.1:4160'
195
+ NSQLOOKUPD_HTTP_ADDRESS='127.0.0.1:4161'
196
+ ```
197
+
198
+ See the [`.sample.env`](examples/.sample.env) file
199
+ for more detail.
200
+
201
+ ### Testing Against the Fake
202
+
203
+ In the gem's test suite,
204
+ the fake message queue is used.
205
+
206
+ If you would like to force
207
+ use of the real NSQ adapter,
208
+ ensure `FAKE_QUEUE` is set to `false`.
209
+
210
+ When you are developing your application,
211
+ it is recommended to
212
+ start by using the fake queue:
213
+
214
+ ```shell
215
+ FAKE_QUEUE=true
216
+ ```
217
+
218
+ Also note that during gem tests,
219
+ we are aliasing `MessageProcessor` to `SampleMessageProcessor`.
220
+ You can also refer to the latter
221
+ as an example of how
222
+ you might write your own processor.
223
+
224
+ ## Acknowledgements
225
+
226
+ * Documentation inspired by [Steve Losh's "Teach Don't Tell"] post.
227
+ * Thanks to Wistia for `nsq-ruby`.
228
+
229
+ [Steve Losh's "Teach Don't Tell"]: http://stevelosh.com/blog/2013/09/teach-dont-tell/
230
+
231
+
232
+ ## Copyright
233
+
234
+ Copyright (c) 2016 Fastly, Inc under an MIT license.
235
+
236
+ See [LICENSE.txt](LICENSE.txt) for details.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler/setup'
7
+ rescue LoadError => e
8
+ abort e.message
9
+ end
10
+
11
+ require 'rake'
12
+
13
+ require 'rubygems/tasks'
14
+ Gem::Tasks.new
15
+
16
+ require 'rdoc/task'
17
+ RDoc::Task.new
18
+ task doc: :rdoc
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new do |test|
23
+ test.libs << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ require 'bundler/audit/cli'
29
+
30
+ namespace :bundler do
31
+ desc 'Updates the ruby-advisory-db and runs audit'
32
+ task :audit do
33
+ %w(update check).each do |command|
34
+ Bundler::Audit::CLI.start [command]
35
+ end
36
+ end
37
+ end
38
+
39
+ task(:default).clear
40
+ task default: ['test', 'bundler:audit']
@@ -0,0 +1,6 @@
1
+ BROADCAST_ADDRESS: '127.0.0.1'
2
+ NSQD_TCP_ADDRESS: '127.0.0.1:4150'
3
+ NSQD_HTTP_ADDRESS: '127.0.0.1:4151'
4
+ NSQLOOKUPD_TCP_ADDRESS: '127.0.0.1:4160'
5
+ NSQLOOKUPD_HTTP_ADDRESS: '127.0.0.1:4161'
6
+ FAKE_QUEUE: 'true'
@@ -0,0 +1,17 @@
1
+ # NSQ
2
+ # In the Fastly Dev VM
3
+ BROADCAST_ADDRESS='billing'
4
+ NSQD_TCP_ADDRESS='billing:1910'
5
+ NSQD_HTTP_ADDRESS='billing:1911'
6
+ NSQLOOKUPD_TCP_ADDRESS='billing:4160'
7
+ NSQLOOKUPD_HTTP_ADDRESS='billing:4161'
8
+
9
+ # On OSX with Homebrew defaults (brew install nsq)
10
+ BROADCAST_ADDRESS='127.0.0.1'
11
+ NSQD_TCP_ADDRESS='127.0.0.1:4150'
12
+ NSQD_HTTP_ADDRESS='127.0.0.1:4151'
13
+ NSQLOOKUPD_TCP_ADDRESS='127.0.0.1:4160'
14
+ NSQLOOKUPD_HTTP_ADDRESS='127.0.0.1:4161'
15
+
16
+ # Uncomment to test against a live queue
17
+ #LIVE_QUEUE=true
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'fastly_nsq/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = 'fastly_nsq'
9
+ gem.version = FastlyNsq::VERSION
10
+ gem.summary = 'Fastly NSQ Adapter'
11
+ gem.description = "Helper classes for Fastly's NSQ Services"
12
+ gem.license = 'MIT'
13
+ gem.authors = ["Tommy O'Neil", 'Adarsh Pandit']
14
+ gem.email = 'tommy@fastly.com'
15
+ gem.homepage = 'https://github.com/fastly/fastly-nsq'
16
+
17
+ gem.files = `git ls-files`.split("\n")
18
+
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|features)/})
21
+ gem.require_paths = ['lib']
22
+
23
+ gem.add_development_dependency 'awesome_print', '~> 1.6'
24
+ gem.add_development_dependency 'bundler', '~> 1.10'
25
+ gem.add_development_dependency 'bundler-audit', '~> 0.4'
26
+ gem.add_development_dependency 'minitest', '~> 5.8'
27
+ gem.add_development_dependency 'pry-byebug', '~> 3.3'
28
+ gem.add_development_dependency 'rake', '~> 10.5'
29
+ gem.add_development_dependency 'rdoc', '~> 4.2'
30
+ gem.add_development_dependency 'rspec-mocks', '~> 3.4'
31
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
32
+
33
+ gem.add_dependency 'nsq-ruby', '~> 1.5.0', '>= 1.5.0'
34
+ end
data/lib/fastly_nsq.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'fastly_nsq/version'
2
+
3
+ require 'fastly_nsq/message_queue'
@@ -0,0 +1,59 @@
1
+ module FakeMessageQueue
2
+ def self.queue
3
+ @@queue
4
+ end
5
+
6
+ def self.queue=(message)
7
+ @@queue = message
8
+ end
9
+
10
+ def self.reset!
11
+ self.queue = []
12
+ end
13
+
14
+ class Producer
15
+ def initialize(nsqd:, topic:)
16
+ end
17
+
18
+ def write(string)
19
+ message = Message.new(string)
20
+ queue.push(message)
21
+ end
22
+
23
+ private
24
+
25
+ def queue
26
+ FakeMessageQueue.queue
27
+ end
28
+ end
29
+
30
+ class Consumer
31
+ def initialize(nsqlookupd:, topic:, channel:)
32
+ end
33
+
34
+ def pop
35
+ queue.pop
36
+ end
37
+
38
+ def size
39
+ queue.size
40
+ end
41
+
42
+ private
43
+
44
+ def queue
45
+ FakeMessageQueue.queue
46
+ end
47
+ end
48
+
49
+ class Message
50
+ attr_reader :body
51
+
52
+ def initialize(body)
53
+ @body = body
54
+ end
55
+
56
+ def finish
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ require 'nsq'
2
+ require_relative 'fake_message_queue'
3
+ require_relative 'message_queue/listener'
4
+ require_relative 'message_queue/producer'
5
+ require_relative 'message_queue/consumer'
6
+ require_relative 'message_queue/strategy'
7
+
8
+ module MessageQueue
9
+ FALSY_VALUES = [false, 0, '0', 'false', 'FALSE', 'off', 'OFF', nil]
10
+ TRUTHY_VALUES = [true, 1, '1', 'true', 'TRUE', 'on', 'ON']
11
+ end
@@ -0,0 +1,30 @@
1
+ class InvalidParameterError < StandardError; end;
2
+
3
+ module MessageQueue
4
+ class Consumer
5
+ def initialize(topic:, channel:)
6
+ @topic = topic
7
+ @channel = channel
8
+ end
9
+
10
+ def connection
11
+ consumer.new(params)
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :channel, :topic
17
+
18
+ def consumer
19
+ Strategy.for_queue::Consumer
20
+ end
21
+
22
+ def params
23
+ {
24
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
25
+ topic: topic,
26
+ channel: channel,
27
+ }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module MessageQueue
2
+ class Listener
3
+ def initialize(topic:, channel:)
4
+ @topic = topic
5
+ @channel = channel
6
+ end
7
+
8
+ def go
9
+ loop do
10
+ process_next_message
11
+ end
12
+ end
13
+
14
+ def process_next_message
15
+ message = consumer.pop
16
+ MessageProcessor.new(message).go
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :channel, :topic
22
+
23
+ def consumer
24
+ MessageQueue::Consumer.new(topic: topic, channel: channel).connection
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ class InvalidParameterError < StandardError; end;
2
+
3
+ module MessageQueue
4
+ class Producer
5
+ def initialize(topic:)
6
+ @topic = topic
7
+ end
8
+
9
+ def connection
10
+ producer.new(params)
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :topic
16
+
17
+ def producer
18
+ Strategy.for_queue::Producer
19
+ end
20
+
21
+ def params
22
+ {
23
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
24
+ topic: topic,
25
+ }
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ class Strategy
2
+ def self.for_queue
3
+ if MessageQueue::FALSY_VALUES.include?(ENV['FAKE_QUEUE'])
4
+ Nsq
5
+ elsif MessageQueue::TRUTHY_VALUES.include?(ENV['FAKE_QUEUE'])
6
+ FakeMessageQueue
7
+ else
8
+ message = "You must set ENV['FAKE_QUEUE'] to either true or false"
9
+ raise InvalidParameterError, message
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ class HeartbeatWorker; end
2
+ class UnknownMessageWorker; end
3
+
4
+ class SampleMessageProcessor
5
+ EVENT_TYPE_TO_WORKER_MAP = {
6
+ 'heartbeat' => HeartbeatWorker,
7
+ }.freeze
8
+
9
+ def initialize(message)
10
+ @message = message
11
+ end
12
+
13
+ def go
14
+ process_message
15
+ message.finish
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :message
21
+
22
+ def process_message
23
+ message_processor.perform_async(message_data)
24
+ end
25
+
26
+ def message_processor
27
+ EVENT_TYPE_TO_WORKER_MAP.fetch(event_type, UnknownMessageWorker)
28
+ end
29
+
30
+ def event_type
31
+ parsed_message_body['event_type']
32
+ end
33
+
34
+ def message_data
35
+ parsed_message_body['data']
36
+ end
37
+
38
+ def parsed_message_body
39
+ JSON.parse(message_body)
40
+ end
41
+
42
+ def message_body
43
+ message.body
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module FastlyNsq
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+
3
+ describe FakeMessageQueue do
4
+ describe '.reset!' do
5
+ it 'resets the fake message queue' do
6
+ FakeMessageQueue.queue = ['hello']
7
+ assert_equal 1, FakeMessageQueue.queue.size
8
+
9
+ FakeMessageQueue.reset!
10
+
11
+ assert_empty FakeMessageQueue.queue
12
+ end
13
+ end
14
+ end
15
+
16
+ describe FakeMessageQueue::Producer do
17
+ describe '#write' do
18
+ it 'adds a new message to the queue' do
19
+ topic = 'death_star'
20
+
21
+ producer = FakeMessageQueue::Producer.new(
22
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
23
+ topic: topic,
24
+ )
25
+ producer.write('hello')
26
+
27
+ assert_equal 1, FakeMessageQueue.queue.size
28
+ end
29
+ end
30
+ end
31
+
32
+ describe FakeMessageQueue::Message do
33
+ describe '#body' do
34
+ it 'returns the body of the message' do
35
+ topic = 'death_star'
36
+ content = 'hello'
37
+ producer = FakeMessageQueue::Producer.new(
38
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
39
+ topic: topic,
40
+ )
41
+ producer.write(content)
42
+
43
+ message = FakeMessageQueue.queue.pop
44
+ body = message.body
45
+
46
+ assert_equal content, body
47
+ end
48
+ end
49
+ end
50
+
51
+ describe FakeMessageQueue::Consumer do
52
+ describe '#size' do
53
+ it 'tells you how many messages are in the queue' do
54
+ FakeMessageQueue.queue = ['hello']
55
+ topic = 'death_star'
56
+ channel = 'star_killer_base'
57
+
58
+ consumer = FakeMessageQueue::Consumer.new(
59
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
60
+ topic: topic,
61
+ channel: channel,
62
+ )
63
+ queue_size = consumer.size
64
+
65
+ assert_equal 1, queue_size
66
+ end
67
+ end
68
+
69
+ describe '#pop' do
70
+ it 'returns the last message off of the queue' do
71
+ message = FakeMessageQueue::Message.new('hello')
72
+ FakeMessageQueue.queue = [message]
73
+ topic = 'death_star'
74
+ channel = 'star_killer_base'
75
+
76
+ consumer = FakeMessageQueue::Consumer.new(
77
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
78
+ topic: topic,
79
+ channel: channel,
80
+ )
81
+ popped_message = consumer.pop
82
+
83
+ assert_equal message, popped_message
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+ require 'fastly_nsq'
3
+
4
+ describe FastlyNsq do
5
+ it 'has a version number' do
6
+ version = FastlyNsq.const_get('VERSION')
7
+
8
+ assert(!version.empty?, 'should have a VERSION constant')
9
+ end
10
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ describe MessageQueue::Consumer do
4
+ describe '#connection' do
5
+ describe 'when using the real queue' do
6
+ it 'returns an instance of the queue consumer' do
7
+ MessageQueue::FALSY_VALUES.each do |no|
8
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(no)
9
+ allow(Nsq::Consumer).to receive(:new)
10
+ topic = 'death_star'
11
+ channel = 'star_killer_base'
12
+
13
+ MessageQueue::Consumer.new(topic: topic, channel: channel).connection
14
+
15
+ expect(Nsq::Consumer).to have_received(:new).
16
+ with(
17
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
18
+ topic: topic,
19
+ channel: channel,
20
+ ).at_least(:once)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ describe 'when using the fake queue' do
27
+ it 'returns an instance of the queue consumer' do
28
+ MessageQueue::TRUTHY_VALUES.each do |yes|
29
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(yes)
30
+ allow(FakeMessageQueue::Consumer).to receive(:new)
31
+ topic = 'death_star'
32
+ channel = 'star_killer_base'
33
+
34
+ MessageQueue::Consumer.new(topic: topic, channel: channel).connection
35
+
36
+ expect(FakeMessageQueue::Consumer).to have_received(:new).
37
+ with(
38
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
39
+ topic: topic,
40
+ channel: channel,
41
+ ).at_least(:once)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe 'when the ENV is set incorrectly' do
47
+ it 'raises with a helpful error' do
48
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
49
+ topic = 'death_star'
50
+ channel = 'star_killer_base'
51
+
52
+ consumer = MessageQueue::Consumer.new(topic: topic, channel: channel)
53
+
54
+ assert_raises(InvalidParameterError) do
55
+ consumer.connection
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+
3
+ describe MessageQueue::Listener do
4
+ describe '#process_next_message' do
5
+ it 'pass the topic and channel to the consumer' do
6
+ allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
7
+ allow(MessageQueue::Consumer).to receive_message_chain(
8
+ :new,
9
+ :connection,
10
+ :pop,
11
+ )
12
+ topic = 'minitest'
13
+ channel = 'northstar'
14
+
15
+ MessageQueue::Listener.new(topic: topic, channel: channel).
16
+ process_next_message
17
+
18
+ expect(MessageQueue::Consumer).to have_received(:new).
19
+ with(topic: topic, channel: channel)
20
+ end
21
+
22
+ it 'processes the message' do
23
+ process_message = double(go: nil)
24
+ allow(MessageProcessor).to receive(:new).and_return(process_message)
25
+ message = double
26
+ allow(MessageQueue::Consumer).to receive_message_chain(
27
+ :new,
28
+ :connection,
29
+ pop: message
30
+ )
31
+ topic = 'minitest'
32
+ channel = 'northstar'
33
+
34
+ MessageQueue::Listener.new(topic: topic, channel: channel).
35
+ process_next_message
36
+
37
+ expect(MessageProcessor).to have_received(:new).with(message)
38
+ expect(process_message).to have_received(:go)
39
+ end
40
+ end
41
+
42
+ describe '#go' do
43
+ # Infinite loops are untestable
44
+ end
45
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ describe MessageQueue::Producer do
4
+ describe '#connection' do
5
+ describe 'when using the real queue' do
6
+ it 'returns an instance of the queue producer' do
7
+ MessageQueue::FALSY_VALUES.each do |no|
8
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(no)
9
+ allow(Nsq::Producer).to receive(:new)
10
+ topic = 'death_star'
11
+
12
+ MessageQueue::Producer.new(topic: topic).connection
13
+
14
+ expect(Nsq::Producer).to have_received(:new).
15
+ with(
16
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
17
+ topic: topic,
18
+ ).at_least(:once)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ describe 'when using the fake queue' do
25
+ it 'returns an instance of the queue producer' do
26
+ MessageQueue::TRUTHY_VALUES.each do |yes|
27
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(yes)
28
+ allow(FakeMessageQueue::Producer).to receive(:new)
29
+ topic = 'death_star'
30
+
31
+ MessageQueue::Producer.new(topic: topic).connection
32
+
33
+ expect(FakeMessageQueue::Producer).to have_received(:new).
34
+ with(
35
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
36
+ topic: topic,
37
+ ).at_least(:once)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'when the ENV is set incorrectly' do
43
+ it 'raises with a helpful error' do
44
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
45
+ topic = 'death_star'
46
+
47
+ producer = MessageQueue::Producer.new(topic: topic)
48
+
49
+ assert_raises(InvalidParameterError) do
50
+ producer.connection
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ describe Strategy do
4
+ describe '.for_queue' do
5
+ describe 'when using the fake queue' do
6
+ it 'returns the strategy based on the ENV variable' do
7
+ MessageQueue::TRUTHY_VALUES.each do |yes|
8
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(yes)
9
+
10
+ strategy = Strategy.for_queue
11
+
12
+ assert equal FakeMessageQueue, strategy
13
+ end
14
+ end
15
+ end
16
+
17
+ describe 'when using the real queue' do
18
+ it 'returns the strategy based on the ENV variable' do
19
+ MessageQueue::FALSY_VALUES.each do |no|
20
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(no)
21
+
22
+ strategy = Strategy.for_queue
23
+
24
+ assert equal Nsq, strategy
25
+ end
26
+ end
27
+ end
28
+
29
+ describe 'when the ENV is set incorrectly' do
30
+ it 'raises with a helpful error' do
31
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
32
+
33
+ assert_raises(InvalidParameterError) do
34
+ Strategy.for_queue
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ describe SampleMessageProcessor do
4
+ describe '#start' do
5
+ it 'enqueues the appropriate message processor' do
6
+ data = { 'key' => 'value' }
7
+ body = { 'event_type' => 'heartbeat', 'data' => data }.to_json
8
+ message = double('Message', body: body, finish: nil)
9
+ allow(HeartbeatWorker).to receive(:perform_async)
10
+
11
+ SampleMessageProcessor.new(message).go
12
+
13
+ expect(HeartbeatWorker).to have_received(:perform_async).with(data)
14
+ end
15
+
16
+ it 'finishes the message' do
17
+ data = { 'key' => 'value' }
18
+ body = { 'event_type' => 'heartbeat', 'data' => data }.to_json
19
+ message = double('Message', body: body, finish: nil)
20
+ allow(HeartbeatWorker).to receive(:perform_async)
21
+
22
+ SampleMessageProcessor.new(message).go
23
+
24
+ expect(message).to have_received(:finish)
25
+ end
26
+
27
+ describe 'when the message event_type is not known' do
28
+ it 'uses the null object processor' do
29
+ data = { 'sample_key' => 'sample value' }
30
+ body = {
31
+ 'event_type' => 'unregistered_message_type',
32
+ 'data' => data,
33
+ }.to_json
34
+ message = double('Message', body: body, finish: nil)
35
+ allow(UnknownMessageWorker).to receive(:perform_async)
36
+
37
+ SampleMessageProcessor.new(message).go
38
+
39
+ expect(UnknownMessageWorker).to have_received(:perform_async).with(data)
40
+ end
41
+ end
42
+
43
+ describe 'when the message lacks an event_type' do
44
+ it 'uses the null object processor' do
45
+ data = { 'sample_key' => 'sample value' }
46
+ body = {
47
+ 'not_the_event_type_key' => 'unregistered_message_type',
48
+ 'data' => data,
49
+ }.to_json
50
+ message = double('Message', body: body, finish: nil)
51
+ allow(UnknownMessageWorker).to receive(:perform_async)
52
+
53
+ SampleMessageProcessor.new(message).go
54
+
55
+ expect(UnknownMessageWorker).to have_received(:perform_async).with(data)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError => error
6
+ abort error.message
7
+ end
8
+
9
+ require 'fastly_nsq'
10
+
11
+ require 'minitest/autorun'
12
+ require 'awesome_print'
13
+ require 'pry-byebug'
14
+ require_relative '../lib/fastly_nsq/sample_message_processor'
15
+
16
+ MessageProcessor = SampleMessageProcessor
17
+
18
+ MiniTest::Spec.before do
19
+ load_sample_environment_variables
20
+ FakeMessageQueue.reset!
21
+ end
22
+
23
+ def load_sample_environment_variables
24
+ env_file = File.open('env_configuration_for_local_gem_tests.yml')
25
+
26
+ YAML.load(env_file).each do |key, value|
27
+ ENV[key.to_s] = value
28
+ end
29
+ end
30
+
31
+ require 'rspec/mocks'
32
+ module MinitestRSpecMocksIntegration
33
+ include ::RSpec::Mocks::ExampleMethods
34
+
35
+ def before_setup
36
+ ::RSpec::Mocks.setup
37
+ super
38
+ end
39
+
40
+ def after_teardown
41
+ super
42
+ ::RSpec::Mocks.verify
43
+ ensure
44
+ ::RSpec::Mocks.teardown
45
+ end
46
+ end
47
+
48
+ class MiniTest::Spec
49
+ include MinitestRSpecMocksIntegration
50
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastly_nsq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tommy O'Neil
@@ -162,7 +162,36 @@ email: tommy@fastly.com
162
162
  executables: []
163
163
  extensions: []
164
164
  extra_rdoc_files: []
165
- files: []
165
+ files:
166
+ - ".document"
167
+ - ".gitignore"
168
+ - ".rdoc_options"
169
+ - ".travis.yml"
170
+ - ChangeLog.md
171
+ - Gemfile
172
+ - LICENSE.txt
173
+ - README.md
174
+ - Rakefile
175
+ - env_configuration_for_local_gem_tests.yml
176
+ - examples/.sample.env
177
+ - fastly_nsq.gemspec
178
+ - lib/fastly_nsq.rb
179
+ - lib/fastly_nsq/fake_message_queue.rb
180
+ - lib/fastly_nsq/message_queue.rb
181
+ - lib/fastly_nsq/message_queue/consumer.rb
182
+ - lib/fastly_nsq/message_queue/listener.rb
183
+ - lib/fastly_nsq/message_queue/producer.rb
184
+ - lib/fastly_nsq/message_queue/strategy.rb
185
+ - lib/fastly_nsq/sample_message_processor.rb
186
+ - lib/fastly_nsq/version.rb
187
+ - test/lib/fastly_nsq/fake_message_queue_test.rb
188
+ - test/lib/fastly_nsq/fastly_nsq_test.rb
189
+ - test/lib/fastly_nsq/message_queue/consumer_test.rb
190
+ - test/lib/fastly_nsq/message_queue/listener_test.rb
191
+ - test/lib/fastly_nsq/message_queue/producer_test.rb
192
+ - test/lib/fastly_nsq/message_queue/strategy.rb
193
+ - test/lib/fastly_nsq/sample_message_processor_test.rb
194
+ - test/test_helper.rb
166
195
  homepage: https://github.com/fastly/fastly-nsq
167
196
  licenses:
168
197
  - MIT
@@ -187,4 +216,12 @@ rubygems_version: 2.5.1
187
216
  signing_key:
188
217
  specification_version: 4
189
218
  summary: Fastly NSQ Adapter
190
- test_files: []
219
+ test_files:
220
+ - test/lib/fastly_nsq/fake_message_queue_test.rb
221
+ - test/lib/fastly_nsq/fastly_nsq_test.rb
222
+ - test/lib/fastly_nsq/message_queue/consumer_test.rb
223
+ - test/lib/fastly_nsq/message_queue/listener_test.rb
224
+ - test/lib/fastly_nsq/message_queue/producer_test.rb
225
+ - test/lib/fastly_nsq/message_queue/strategy.rb
226
+ - test/lib/fastly_nsq/sample_message_processor_test.rb
227
+ - test/test_helper.rb