fastly_nsq 0.12.4 → 0.13.0

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: a3a42709debb8a573f27df0efdb01b0ff2c30c01
4
- data.tar.gz: 4abd037e9a15eebb9c442a48fdc6c76a7fdd5536
3
+ metadata.gz: 160f5ed48ad6dba8fa1805abc9bd75d9f3c8b738
4
+ data.tar.gz: bd0ba1550ed27f8d9ced75e5b202fc16bf4d4af0
5
5
  SHA512:
6
- metadata.gz: 3059ee3d302f936190ba3f5992fde033f8854ba7b3bf5bdd79628db891e07fdb1bdb6afcb0c19645a4281b41891520db1a2fdcae12a23deeebcadac9498b0737
7
- data.tar.gz: 16f02d1c0238c80b7820761664d29125f6505175b4095ecd53f132711d8d3bc4b7a3006ffb84421b8f36f36fb93e5df4c50d8ae633ed00d99967eba148e85522
6
+ metadata.gz: 7870d124317e9ff43e3e40f766699565332d94fdea25741226a9d57613dac542da392cc51407db0a65c31fab4563dc0362a6e1f9d70f26cc26aa32a33c898b90
7
+ data.tar.gz: 9bbc2b875f8ec619a8ca0732e77c9ecc713a0d5762a61122a372f0fbbc4f52d52bcb04fe45b050ee06e0e27b9341e7caac1ae213265953cf0d32214cc414b344
data/README.md CHANGED
@@ -173,7 +173,7 @@ An example of using the cli:
173
173
  ./bin/fastly_nsq -r ./example_config_class.rb -L ./test.log -P ./fastly_nsq.pid -v -d -t 4
174
174
  ```
175
175
 
176
- ### FastlyNsq::Messgener
176
+ ### `FastlyNsq::Messenger`
177
177
 
178
178
  Wrapper around a producer for sending messages and persisting producer objects.
179
179
 
@@ -207,7 +207,39 @@ FastlyNsq::Messenger.terminate_producer(topic: 'hot_topic')
207
207
  FastlyNsq::Messenger.terminate_all_producers
208
208
  ```
209
209
 
210
- ### Real vs. Fake
210
+ ### `FastlyNsq::Http`
211
+
212
+ Wrappers around `nsqd` and `nsqlookupd` http api's described here:
213
+ * [NSQD API](http://nsq.io/components/nsqd.html)
214
+ * [NSQLOOKUPD API](http://nsq.io/components/nsqlookupd.html)
215
+
216
+ #### `Nsqd`
217
+
218
+ Implements most of the Nsqd api.
219
+
220
+ Example usage:
221
+ ```ruby
222
+ FastlyNsq::Http::Nsqd.ping
223
+ FastlyNsq::Http::Nsqd.create_channel(topic: 'foo', channel: 'bar')
224
+ FastlyNsq::Http::Nsqd.stats(topic: 'foo', format: '')
225
+ ```
226
+
227
+ TODO:
228
+ 1. Debug endpoints (`/debug/*`)
229
+ 2. Config PUT (`/config/nsqlookupd_tcp_address`)
230
+ 3. Correct Handling of `mpub` `binary` mode
231
+
232
+ #### `Nsqlookupd`
233
+
234
+ Implements all of the Nsqlookupd api.
235
+
236
+ Example usage:
237
+ ```ruby
238
+ FastlyNsq::Http::Nsqlookupd.nodes
239
+ FastlyNsq::Http::Nsqlookupd.lookup(topic: 'foo')
240
+ ```
241
+
242
+ ### `Real vs. Fake`
211
243
 
212
244
  The real strategy
213
245
  creates a connection
@@ -31,6 +31,7 @@ Gem::Specification.new do |gem|
31
31
  gem.add_development_dependency 'rspec', '~> 3.4.0'
32
32
  gem.add_development_dependency 'rubocop', '~> 0.39.0'
33
33
  gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
34
+ gem.add_development_dependency 'webmock'
34
35
 
35
36
  gem.add_dependency 'nsq-ruby', '~> 2.0', '>= 2.0.5'
36
37
  end
@@ -33,7 +33,10 @@ module FastlyNsq
33
33
  end
34
34
 
35
35
  class Producer
36
- def initialize(topic:, nsqlookupd: nil, tls_v1: nil, tls_options: nil)
36
+ attr_reader :topic
37
+
38
+ def initialize(topic:, **)
39
+ @topic = topic
37
40
  end
38
41
 
39
42
  def connected?
@@ -41,7 +44,7 @@ module FastlyNsq
41
44
  end
42
45
 
43
46
  def write(string)
44
- message = Message.new(string)
47
+ message = Message.new(string, topic: topic)
45
48
  queue.push(message)
46
49
  end
47
50
 
@@ -57,8 +60,7 @@ module FastlyNsq
57
60
  end
58
61
 
59
62
  class Consumer
60
- def initialize(nsqlookupd: nil, topic:, channel:, tls_v1: nil, tls_options: nil)
61
- end
63
+ def initialize(nsqlookupd: nil, topic:, channel:, tls_v1: nil, tls_options: nil); end
62
64
 
63
65
  def connected?
64
66
  true
@@ -99,14 +101,14 @@ module FastlyNsq
99
101
  end
100
102
 
101
103
  class Message
102
- attr_reader :body
104
+ attr_reader :topic, :body
103
105
 
104
- def initialize(body)
106
+ def initialize(body, topic: nil)
107
+ @topic = topic
105
108
  @body = body
106
109
  end
107
110
 
108
- def finish
109
- end
111
+ def finish; end
110
112
  end
111
113
  end
112
114
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/https'
4
+ require 'fastly_nsq/http/nsqd'
5
+ require 'fastly_nsq/http/nsqlookupd'
6
+
7
+ class FastlyNsq::Http
8
+ def initialize(uri:, cert_filename: ENV['NSQ_SSL_CERTIFICATE'], key_filename: ENV['NSQ_SSL_KEY'])
9
+ @uri = uri.is_a?(URI) ? uri : URI.parse(uri)
10
+ @cert_filename = cert_filename
11
+ @key_filename = key_filename
12
+ end
13
+
14
+ def get(data = nil)
15
+ if data
16
+ params = URI.encode_www_form(data)
17
+ uri.query = params
18
+ end
19
+ req = Net::HTTP::Get.new(uri.request_uri)
20
+ http.request(req)
21
+ end
22
+
23
+ def post(data, body = nil)
24
+ params = URI.encode_www_form(data)
25
+ uri.query = params
26
+ req = Net::HTTP::Post.new(uri.request_uri)
27
+ http.request(req, body)
28
+ end
29
+
30
+ def use_ssl
31
+ return unless can_use_ssl?
32
+ http.use_ssl = true
33
+ http.cert = cert
34
+ http.key = key
35
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :cert_filename, :key_filename, :uri
41
+
42
+ def http
43
+ @http ||= Net::HTTP.new(uri.host, uri.port)
44
+ end
45
+
46
+ def can_use_ssl?
47
+ !(cert_filename.nil? || key_filename.nil?)
48
+ end
49
+
50
+ def cert
51
+ @cert ||= OpenSSL::X509::Certificate.new(File.read(cert_filename))
52
+ end
53
+
54
+ def key
55
+ @key ||= OpenSSL::PKey::RSA.new(File.read(key_filename))
56
+ end
57
+ end
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fastly_nsq/http'
4
+
5
+ class FastlyNsq::Http
6
+ class Nsqd
7
+ extend Forwardable
8
+ def_delegator :client, :get
9
+ def_delegator :client, :post
10
+
11
+ BASE_NSQD_URL = ENV.fetch 'NSQD_URL', "https://#{ENV.fetch('NSQD_HTTPS_ADDRESS', '')}"
12
+ VALID_FORMATS = %w(text json).freeze
13
+
14
+ ##
15
+ # Monitoring endpoint, should return 200 OK. It returns an HTTP 500 if it is not healthy.
16
+ #
17
+ # NOTE: The only "unhealthy" state is if nsqd failed to write messages to disk when overflow occurred.
18
+ def self.ping(**args)
19
+ new(request_uri: '/ping', **args).get
20
+ end
21
+
22
+ ##
23
+ # NSQ version information
24
+ def self.info(**args)
25
+ new(request_uri: '/info', **args).get
26
+ end
27
+
28
+ ##
29
+ # Return Internal Statistics
30
+ #
31
+ # @param topic [String] filter to topic
32
+ # @param channel [String] filter to channel
33
+ # @param format [String] can be +text+ or +json+
34
+ #
35
+ # @raise [InvaildFormatError] provided format is not in list of valid formats
36
+ #
37
+ # @example Fetch Statistics for topic: 'foo', channel: 'bar' as text
38
+ # Nsqd.stats(topic: 'foo', channel: 'bar', format: 'text')
39
+ def self.stats(topic: nil, channel: nil, format: 'json', **args)
40
+ raise InvalidFormatError unless VALID_FORMATS.include?(format)
41
+ params = { format: format }
42
+ params[:topic] = topic if topic
43
+ params[:channel] = channel if channel
44
+ new(request_uri: '/stats', **args).get(params)
45
+ end
46
+
47
+ ##
48
+ # Publish a message
49
+ #
50
+ # @param topic [String] the topic to publish to
51
+ # @param defer [String] the time in ms to delay message delivery
52
+ # @param message the message body
53
+ def self.pub(topic:, message:, defer: nil, **args)
54
+ params = { topic: topic }
55
+ params[:defer] = defer if defer
56
+ new(request_uri: '/pub', **args).post(params, message)
57
+ end
58
+
59
+ ##
60
+ # Publish multiple messages in one roundtrip
61
+ #
62
+ # NOTE: by default +/mpub+ expects messages to be delimited by +\n+, use the
63
+ # +binary: true+ parameter to enable binary mode where message body
64
+ # is expected to be in the following format (the HTTP Content-Length
65
+ # header should be sent as the total size of the POST body):
66
+ # [ 4-byte num messages ]
67
+ # [ 4-byte message #1 size ][ N-byte binary data ]
68
+ # ... (repeated <num_messages> times)
69
+ #
70
+ # TODO: setup +Content-Legth+ header when binary is passed.
71
+ #
72
+ # @param topic [String] the topic to publish to
73
+ # @param binary [Boolean] enables binary mode
74
+ # @param message the messages to send with \n used to seperate messages
75
+ def self.mpub(topic:, binary: false, message:, **args)
76
+ binary_param = binary ? 'true' : 'false'
77
+ raise NotImplementedError, 'binary mode has yet to be implemented' if binary
78
+ params = { topic: topic, binary: binary_param }
79
+ new(request_uri: '/mpub', **args).post(params, message)
80
+ end
81
+
82
+ ##
83
+ # List of nsqlookupd TCP addresses
84
+ def self.config_nsqlookupd_tcp_addresses(**args)
85
+ new(request_uri: '/config/nsqlookupd_tcp_addresses', **args).get
86
+ end
87
+
88
+ ##
89
+ # Create a topic
90
+ #
91
+ # @param topic [String] the topic to create
92
+ def self.topic_create(topic:, **args)
93
+ new(request_uri: '/topic/create', **args).post(topic: topic)
94
+ end
95
+
96
+ ##
97
+ # Delete a topic (and all of its channels)
98
+ #
99
+ # @param topic [String] the existing topic to delete
100
+ def self.topic_delete(topic:, **args)
101
+ new(request_uri: '/topic/delete', **args).post(topic: topic)
102
+ end
103
+
104
+ ##
105
+ # Empty all the queued messages (in-memory and disk) for an existing topic
106
+ #
107
+ # @param topic [String] the existing topic to empty
108
+ def self.topic_empty(topic:, **args)
109
+ new(request_uri: '/topic/empty', **args).post(topic: topic)
110
+ end
111
+
112
+ ##
113
+ # Pause message flow to all channels on an existing topic
114
+ # (messages will queue at the *topic*)
115
+ #
116
+ # @param topic [String] the existing topic to pause
117
+ def self.topic_pause(topic:, **args)
118
+ new(request_uri: '/topic/pause', **args).post(topic: topic)
119
+ end
120
+
121
+ ##
122
+ # Unpause message flow to all channels of an existing, paused, topic
123
+ #
124
+ # @param topic [String] the existing, paused topic to unpause
125
+ def self.topic_unpause(topic:, **args)
126
+ new(request_uri: '/topic/unpause', **args).post(topic: topic)
127
+ end
128
+
129
+ ##
130
+ # Create a channel for an existing topic
131
+ #
132
+ # @param topic [String] the existing topic
133
+ # @param channel [String] the channel to create
134
+ def self.channel_create(topic:, channel:, **args)
135
+ new(request_uri: '/channel/create', **args).post(topic: topic, channel: channel)
136
+ end
137
+
138
+ ##
139
+ # Delete an existing channel for an existing topic
140
+ #
141
+ # @param topic [String] the existing topic
142
+ # @param channel [String] the channel to delete
143
+ def self.channel_delete(topic:, channel:, **args)
144
+ new(request_uri: '/channel/delete', **args).post(topic: topic, channel: channel)
145
+ end
146
+
147
+ ##
148
+ # Empty all queued messages (in-memory and disk) for an existing channel
149
+ #
150
+ # @param topic [String] the existing topic
151
+ # @param channel [String] the channel to empty
152
+ def self.channel_empty(topic:, channel:, **args)
153
+ new(request_uri: '/channel/empty', **args).post(topic: topic, channel: channel)
154
+ end
155
+
156
+ ##
157
+ # Pause message flow to consumers of an existing channel
158
+ # (messages will queue at the *channel*)
159
+ #
160
+ # @param topic [String] the existing topic
161
+ # @param channel [String] the channel to pause
162
+ def self.channel_pause(topic:, channel:, **args)
163
+ new(request_uri: '/channel/pause', **args).post(topic: topic, channel: channel)
164
+ end
165
+
166
+ ##
167
+ # Resume message flow to consumers of and existing, paused, channel
168
+ #
169
+ # @param topic [String] the existing topic
170
+ # @param channel [String] the existing, paused, channel to unpause
171
+ def self.channel_unpause(topic:, channel:, **args)
172
+ new(request_uri: '/channel/unpause', **args).post(topic: topic, channel: channel)
173
+ end
174
+
175
+ ##
176
+ # Nsqd http wrapper. Provides a simple interface to all NSQD http api's
177
+ # @see http://nsq.io/components/nsqd.html
178
+ #
179
+ # @attr [String] request_uri the request you would like to call ie: '/thing'
180
+ # @attr [String] base_uri the host, port, and protocol of your nsqd
181
+ # @attr [Object] adapter the http adapter you would like to use...
182
+ def initialize(request_uri:, base_uri: BASE_NSQD_URL, adapter: FastlyNsq::Http)
183
+ @base_uri = base_uri
184
+ @adapter = adapter
185
+ uri = URI.join(@base_uri, request_uri)
186
+
187
+ @client = @adapter.new(uri: uri)
188
+ @client.use_ssl
189
+ end
190
+
191
+ private
192
+
193
+ attr_accessor :client
194
+
195
+ class InvalidFormatError < StandardError; end
196
+ end
197
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fastly_nsq/http'
4
+
5
+ class FastlyNsq::Http
6
+ class Nsqlookupd
7
+ extend Forwardable
8
+ def_delegator :client, :get
9
+
10
+ BASE_NSQLOOKUPD_URL = "http://#{ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS', '').split(',')[0]}".freeze
11
+
12
+ ##
13
+ # List of producers for a given topic
14
+ #
15
+ # @param topic [String] the topic for which to list producers
16
+ def self.lookup(topic:, **args)
17
+ new(request_uri: '/lookup', **args).get(topic: topic)
18
+ end
19
+
20
+ ##
21
+ # List of all known topics
22
+ def self.topics(**args)
23
+ new(request_uri: '/topics', **args).get
24
+ end
25
+
26
+ ##
27
+ # List of channels for a given topic
28
+ #
29
+ # @param topic [String] the topic for which to list channels
30
+ def self.channels(topic:, **args)
31
+ new(request_uri: '/channels', **args).get(topic: topic)
32
+ end
33
+
34
+ ##
35
+ # List all known nsqd nodes
36
+ def self.nodes(**args)
37
+ new(request_uri: '/nodes', **args).get
38
+ end
39
+
40
+ ##
41
+ # Deletes an existing topic
42
+ #
43
+ # @param topic [String] the exsiting topic to delete
44
+ def self.delete_topic(topic:, **args)
45
+ new(request_uri: '/delete_topic', **args).get(topic: topic)
46
+ end
47
+
48
+ ##
49
+ # Deletes an existing channel of an existing topic
50
+ #
51
+ # @param topic [String] an exsiting topic
52
+ # @param channel [String] the exsiting channel to delete
53
+ def self.delete_channel(topic:, channel:, **args)
54
+ new(request_uri: '/delete_channel', **args).get(topic: topic, channel: channel)
55
+ end
56
+
57
+ ##
58
+ # Tombstones a specific producer of an existing topic
59
+ #
60
+ # @see http://nsq.io/components/nsqlookupd.html#deletion_tombstones
61
+ #
62
+ # @param topic [String] the existing topic
63
+ # @param node [String] the producer (nsqd) to tombstone (identified by <broadcast_address>:<http_port>)
64
+ def self.tombstone_topic_producer(topic:, node:, **args)
65
+ new(request_uri: '/tombstone_topic_producer', **args).get(topic: topic, node: node)
66
+ end
67
+
68
+ ##
69
+ # Monitoring endpoint, should return +OK+
70
+ def self.ping(**args)
71
+ new(request_uri: '/ping', **args).get
72
+ end
73
+
74
+ ##
75
+ # Returns nsqlookupd version information
76
+ def self.info(**args)
77
+ new(request_uri: '/info', **args).get
78
+ end
79
+
80
+ ##
81
+ # Nsqlookupd http wrapper. Provides a simple interface to all NSQlookupd http api's
82
+ # @see http://nsq.io/components/nsqlookupd.html
83
+ #
84
+ # @attr [String] request_uri the request you would like to call ie: '/thing'
85
+ # @attr [String] base_uri the host, port, and protocol of your nsqd
86
+ # @attr [Object] adapter the http adapter you would like to use...
87
+ def initialize(request_uri:, base_uri: BASE_NSQLOOKUPD_URL, adapter: FastlyNsq::Http)
88
+ @adapter = adapter
89
+ @base_uri = base_uri
90
+ uri = URI.join(@base_uri, request_uri)
91
+
92
+ @client = @adapter.new(uri: uri)
93
+ end
94
+
95
+ private
96
+
97
+ attr_accessor :client
98
+ end
99
+ end
@@ -1,3 +1,3 @@
1
1
  module FastlyNsq
2
- VERSION = '0.12.4'.freeze
2
+ VERSION = '0.13.0'.freeze
3
3
  end
@@ -41,9 +41,16 @@ RSpec.describe FastlyNsq::FakeBackend::Producer do
41
41
  let(:producer) { FastlyNsq::FakeBackend::Producer.new topic: topic }
42
42
 
43
43
  it 'adds a new message to the queue' do
44
- producer.write('hello')
44
+ body = 'hello'
45
45
 
46
- expect(FastlyNsq::FakeBackend.queue.size).to eq 1
46
+ expect do
47
+ producer.write(body)
48
+ end.to change { FastlyNsq::FakeBackend.queue.size }.by(1)
49
+
50
+ message = FastlyNsq::FakeBackend.queue.shift
51
+
52
+ expect(message.topic).to eq(topic)
53
+ expect(message.body).to eq(body)
47
54
  end
48
55
 
49
56
  it 'has a `terminate` method which is a noop' do
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fastly_nsq/http/nsqd'
5
+
6
+ RSpec.describe FastlyNsq::Http::Nsqd do
7
+ let(:base_uri) { 'http://example.com' }
8
+
9
+ it 'makes simple get requests' do
10
+ %w(ping info config/nsqlookupd_tcp_addresses).each do |api|
11
+ url = "#{base_uri}/#{api}"
12
+ stub_request(:get, url)
13
+ FastlyNsq::Http::Nsqd.send(api.tr('/', '_').to_sym, base_uri: base_uri)
14
+
15
+ expect(a_request(:get, url)).to have_been_requested
16
+ end
17
+ end
18
+
19
+ describe 'stats' do
20
+ it 'can fetch stats' do
21
+ url = "#{base_uri}/stats?topic=lol&channel=foo&format=json"
22
+ stub_request(:get, url)
23
+ data = { topic: 'lol', channel: 'foo', format: 'json' }
24
+
25
+ FastlyNsq::Http::Nsqd.stats(topic: 'lol', channel: 'foo', base_uri: base_uri)
26
+
27
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
28
+ end
29
+
30
+ it 'raises InvaildFormatError if provided format is not in list' do
31
+ expect do
32
+ FastlyNsq::Http::Nsqd.stats(format: 'foo')
33
+ end.to raise_error(FastlyNsq::Http::Nsqd::InvalidFormatError)
34
+ end
35
+ end
36
+
37
+ it 'can publish messages' do
38
+ url = "#{base_uri}/pub?topic=lol&defer=999"
39
+ stub_request(:post, url)
40
+ data = { topic: 'lol', defer: 999 }
41
+
42
+ FastlyNsq::Http::Nsqd.pub(topic: 'lol', defer: 999, message: 'SOMETHING', base_uri: base_uri)
43
+
44
+ expect(a_request(:post, url).with(query: data, body: 'SOMETHING')).to have_been_requested
45
+ end
46
+
47
+ it 'can publish multiple messages' do
48
+ url = "#{base_uri}/mpub?topic=lol&binary=false"
49
+ stub_request(:post, url)
50
+ data = { topic: 'lol' }
51
+ body = "ONE MESSAGE\nTWO MESSAGE\nRED MESSAGE\nBLUE MESSAGE"
52
+
53
+ FastlyNsq::Http::Nsqd.mpub(topic: 'lol', message: body, base_uri: base_uri)
54
+
55
+ expect(a_request(:post, url).with(query: data, body: body)).to have_been_requested
56
+ end
57
+
58
+ it 'can create, delete, empty, pause and unpause topics and channels' do
59
+ verbs = %w(create delete empty pause unpause)
60
+
61
+ verbs.each do |verb|
62
+ url = "#{base_uri}/topic/#{verb}?topic=lol"
63
+ stub_request(:post, url)
64
+ data = { topic: 'lol' }
65
+
66
+ FastlyNsq::Http::Nsqd.send("topic_#{verb}".to_sym, topic: 'lol', base_uri: base_uri)
67
+
68
+ expect(a_request(:post, url).with(query: data)).to have_been_requested
69
+
70
+ url = "#{base_uri}/channel/#{verb}?topic=lol&channel=foo"
71
+ stub_request(:post, url)
72
+ data = { topic: 'lol', channel: 'foo' }
73
+
74
+ FastlyNsq::Http::Nsqd.send("channel_#{verb}".to_sym, topic: 'lol', channel: 'foo', base_uri: base_uri)
75
+
76
+ expect(a_request(:post, url).with(query: data)).to have_been_requested
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fastly_nsq/http/nsqlookupd'
5
+
6
+ RSpec.describe FastlyNsq::Http::Nsqlookupd do
7
+ let(:base_uri) { 'http://example.com' }
8
+
9
+ it 'makes simple get requests' do
10
+ %w(topics nodes ping info).each do |api|
11
+ url = "#{base_uri}/#{api}"
12
+ stub_request(:get, url)
13
+ FastlyNsq::Http::Nsqlookupd.send(api.to_sym, base_uri: base_uri)
14
+
15
+ expect(a_request(:get, url)).to have_been_requested
16
+ end
17
+ end
18
+
19
+ it 'can lookup producers for a topic' do
20
+ url = "#{base_uri}/lookup?topic=lol"
21
+ stub_request(:get, url)
22
+ data = { topic: 'lol' }
23
+
24
+ FastlyNsq::Http::Nsqlookupd.lookup(topic: 'lol', base_uri: base_uri)
25
+
26
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
27
+ end
28
+
29
+ it 'can lookup channels for a topic' do
30
+ url = "#{base_uri}/channels?topic=lol"
31
+ stub_request(:get, url)
32
+ data = { topic: 'lol' }
33
+
34
+ FastlyNsq::Http::Nsqlookupd.channels(topic: 'lol', base_uri: base_uri)
35
+
36
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
37
+ end
38
+
39
+ it 'can delete a topic' do
40
+ url = "#{base_uri}/delete_topic?topic=lol"
41
+ stub_request(:get, url)
42
+ data = { topic: 'lol' }
43
+
44
+ FastlyNsq::Http::Nsqlookupd.delete_topic(topic: 'lol', base_uri: base_uri)
45
+
46
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
47
+ end
48
+
49
+ it 'can delete a channel' do
50
+ url = "#{base_uri}/delete_channel?topic=lol&channel=foo"
51
+ stub_request(:get, url)
52
+ data = { topic: 'lol', channel: 'foo' }
53
+
54
+ FastlyNsq::Http::Nsqlookupd.delete_channel(topic: 'lol', channel: 'foo', base_uri: base_uri)
55
+
56
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
57
+ end
58
+
59
+ it 'can tombstone a producer' do
60
+ url = "#{base_uri}/tombstone_topic_producer?topic=lol&node=localhost:8989"
61
+ stub_request(:get, url)
62
+ data = { topic: 'lol', node: 'localhost:8989' }
63
+
64
+ FastlyNsq::Http::Nsqlookupd.tombstone_topic_producer(topic: 'lol', node: 'localhost:8989', base_uri: base_uri)
65
+
66
+ expect(a_request(:get, url).with(query: data)).to have_been_requested
67
+ end
68
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+ require 'fastly_nsq/http'
3
+
4
+ RSpec.describe FastlyNsq::Http do
5
+ let(:base_url) { 'http://example.com' }
6
+ describe 'get' do
7
+ it 'can make simple requests' do
8
+ url = "#{base_url}/boop"
9
+ stub_request(:get, url)
10
+
11
+ FastlyNsq::Http.new(uri: URI.parse(url)).get
12
+ FastlyNsq::Http.new(uri: url).get
13
+
14
+ expect(a_request(:get, url)).to have_been_requested.twice
15
+ end
16
+
17
+ it 'can make requests with params' do
18
+ url = "#{base_url}/boop?sloop=noop"
19
+ data = { sloop: 'noop' }
20
+ stub_request(:get, url)
21
+
22
+ FastlyNsq::Http.new(uri: url).get(data)
23
+
24
+ expect(a_request(:get, url).with(query: data)).to have_been_made
25
+ end
26
+ end
27
+
28
+ describe 'post' do
29
+ it 'can make simple post requests' do
30
+ url = "#{base_url}/boop?sloop=noop"
31
+ stub_request(:post, url)
32
+ data = { sloop: 'noop' }
33
+
34
+ FastlyNsq::Http.new(uri: URI.parse(url)).post(data)
35
+ FastlyNsq::Http.new(uri: url).post(data)
36
+
37
+ expect(a_request(:post, url)).to have_been_requested.twice
38
+ end
39
+
40
+ it 'can make post requests with bodies' do
41
+ url = "#{base_url}/boop?sloop=noop"
42
+ stub_request(:post, url)
43
+ data = { sloop: 'noop' }
44
+ body = 'SOME MESSAGE'
45
+
46
+ FastlyNsq::Http.new(uri: url).post(data, body)
47
+
48
+ expect(a_request(:post, url).with(body: body)).to have_been_requested
49
+ end
50
+ end
51
+
52
+ describe 'SSL' do
53
+ it 'can be asked to use SSL' do
54
+ ssl_url = 'https://example.com:80/boop'
55
+ stub_request(:get, ssl_url)
56
+
57
+ cert_file = '/tmp/thing.cert'
58
+ key_file = '/tmp/thing.key'
59
+
60
+ allow(File).to receive(:read).with(cert_file).and_return('something')
61
+ allow(File).to receive(:read).with(key_file).and_return('something')
62
+ allow(OpenSSL::X509::Certificate).to receive(:new).with('something').and_return(true)
63
+ allow(OpenSSL::PKey::RSA).to receive(:new).with('something').and_return(true)
64
+
65
+ url = "#{base_url}/boop"
66
+ http = FastlyNsq::Http.new(uri: url, cert_filename: cert_file, key_filename: key_file)
67
+ http.use_ssl
68
+ http.get
69
+
70
+ expect(a_request(:get, ssl_url)).to have_been_requested
71
+ expect(File).to have_received(:read).twice
72
+ expect(OpenSSL::X509::Certificate).to have_received(:new)
73
+ expect(OpenSSL::PKey::RSA).to have_received(:new)
74
+ end
75
+ end
76
+ end
@@ -1,6 +1,7 @@
1
1
  require 'fastly_nsq'
2
2
  require 'awesome_print'
3
3
  require 'pry-byebug'
4
+ require 'webmock/rspec'
4
5
 
5
6
  require_relative 'support/env_helpers'
6
7
 
@@ -29,6 +30,7 @@ RSpec.configure do |config|
29
30
  config.before(:each) do
30
31
  load_sample_environment_variables
31
32
  FastlyNsq::FakeBackend.reset!
33
+ WebMock.reset!
32
34
  end
33
35
 
34
36
  config.around(:each, fake_queue: true) do |example|
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.12.4
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tommy O'Neil
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-11-02 00:00:00.000000000 Z
14
+ date: 2017-11-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: awesome_print
@@ -167,6 +167,20 @@ dependencies:
167
167
  - - "~>"
168
168
  - !ruby/object:Gem::Version
169
169
  version: '0.2'
170
+ - !ruby/object:Gem::Dependency
171
+ name: webmock
172
+ requirement: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ type: :development
178
+ prerelease: false
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
170
184
  - !ruby/object:Gem::Dependency
171
185
  name: nsq-ruby
172
186
  requirement: !ruby/object:Gem::Requirement
@@ -217,6 +231,9 @@ files:
217
231
  - lib/fastly_nsq/cli.rb
218
232
  - lib/fastly_nsq/consumer.rb
219
233
  - lib/fastly_nsq/fake_backend.rb
234
+ - lib/fastly_nsq/http.rb
235
+ - lib/fastly_nsq/http/nsqd.rb
236
+ - lib/fastly_nsq/http/nsqlookupd.rb
220
237
  - lib/fastly_nsq/launcher.rb
221
238
  - lib/fastly_nsq/listener.rb
222
239
  - lib/fastly_nsq/listener/config.rb
@@ -233,6 +250,9 @@ files:
233
250
  - spec/lib/fastly_nsq/consumer_spec.rb
234
251
  - spec/lib/fastly_nsq/fake_backend_spec.rb
235
252
  - spec/lib/fastly_nsq/fastly_nsq_spec.rb
253
+ - spec/lib/fastly_nsq/http/nsqd_spec.rb
254
+ - spec/lib/fastly_nsq/http/nsqlookupd_spec.rb
255
+ - spec/lib/fastly_nsq/http_spec.rb
236
256
  - spec/lib/fastly_nsq/launcher_spec.rb
237
257
  - spec/lib/fastly_nsq/listener_spec.rb
238
258
  - spec/lib/fastly_nsq/manager_spec.rb