fastly_nsq 0.1.2 → 0.1.3

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
  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