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 +4 -4
- data/.document +5 -0
- data/.gitignore +5 -0
- data/.rdoc_options +16 -0
- data/.travis.yml +17 -0
- data/ChangeLog.md +3 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +20 -0
- data/README.md +236 -0
- data/Rakefile +40 -0
- data/env_configuration_for_local_gem_tests.yml +6 -0
- data/examples/.sample.env +17 -0
- data/fastly_nsq.gemspec +34 -0
- data/lib/fastly_nsq.rb +3 -0
- data/lib/fastly_nsq/fake_message_queue.rb +59 -0
- data/lib/fastly_nsq/message_queue.rb +11 -0
- data/lib/fastly_nsq/message_queue/consumer.rb +30 -0
- data/lib/fastly_nsq/message_queue/listener.rb +27 -0
- data/lib/fastly_nsq/message_queue/producer.rb +28 -0
- data/lib/fastly_nsq/message_queue/strategy.rb +12 -0
- data/lib/fastly_nsq/sample_message_processor.rb +45 -0
- data/lib/fastly_nsq/version.rb +3 -0
- data/test/lib/fastly_nsq/fake_message_queue_test.rb +86 -0
- data/test/lib/fastly_nsq/fastly_nsq_test.rb +10 -0
- data/test/lib/fastly_nsq/message_queue/consumer_test.rb +59 -0
- data/test/lib/fastly_nsq/message_queue/listener_test.rb +45 -0
- data/test/lib/fastly_nsq/message_queue/producer_test.rb +54 -0
- data/test/lib/fastly_nsq/message_queue/strategy.rb +39 -0
- data/test/lib/fastly_nsq/sample_message_processor_test.rb +59 -0
- data/test/test_helper.rb +50 -0
- metadata +40 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed99890b9268655e4d1e7b151e53274bcbe147c9
|
4
|
+
data.tar.gz: 42d9dffa0b05e5a02be41dd92192c3a3f9834462
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b4855596f0aa86d2457ac2e1375e086999fb37b62be50b6f39d5895de51c34cf807b08355963697062423591dfa69e02567b7b2e1610b097e86caa33472cd2
|
7
|
+
data.tar.gz: b4e51dada6b9cb4b2ac0110911dd86a029be91ed4f3cf8f542095acb68333ba16a8c23f2879a26822b3fcd60cc2b3b4d8aae022e47e7a3438b7ff3c8ca81637b
|
data/.document
ADDED
data/.gitignore
ADDED
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
data/Gemfile
ADDED
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 [](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,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
|
data/fastly_nsq.gemspec
ADDED
@@ -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,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,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,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
|
data/test/test_helper.rb
ADDED
@@ -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.
|
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
|