fastly_nsq 0.12.4 → 0.13.0

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