hutch 0.18.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.travis.yml +20 -8
- data/.yardopts +5 -0
- data/CHANGELOG.md +466 -2
- data/Gemfile +18 -4
- data/Guardfile +13 -4
- data/LICENSE +2 -1
- data/README.md +397 -32
- data/Rakefile +8 -1
- data/bin/ci/before_build.sh +20 -0
- data/bin/ci/install_on_debian.sh +46 -0
- data/hutch.gemspec +6 -7
- data/lib/hutch/acknowledgements/base.rb +16 -0
- data/lib/hutch/acknowledgements/nack_on_all_failures.rb +19 -0
- data/lib/hutch/adapters/march_hare.rb +1 -1
- data/lib/hutch/broker.rb +127 -103
- data/lib/hutch/cli.rb +66 -25
- data/lib/hutch/config.rb +230 -55
- data/lib/hutch/consumer.rb +42 -3
- data/lib/hutch/error_handlers/airbrake.rb +44 -16
- data/lib/hutch/error_handlers/base.rb +15 -0
- data/lib/hutch/error_handlers/bugsnag.rb +30 -0
- data/lib/hutch/error_handlers/honeybadger.rb +33 -18
- data/lib/hutch/error_handlers/logger.rb +12 -6
- data/lib/hutch/error_handlers/rollbar.rb +28 -0
- data/lib/hutch/error_handlers/sentry.rb +15 -12
- data/lib/hutch/error_handlers/sentry_raven.rb +31 -0
- data/lib/hutch/error_handlers.rb +3 -0
- data/lib/hutch/exceptions.rb +8 -1
- data/lib/hutch/logging.rb +5 -5
- data/lib/hutch/message.rb +2 -4
- data/lib/hutch/publisher.rb +75 -0
- data/lib/hutch/serializers/identity.rb +19 -0
- data/lib/hutch/serializers/json.rb +22 -0
- data/lib/hutch/tracers/datadog.rb +17 -0
- data/lib/hutch/tracers.rb +1 -0
- data/lib/hutch/version.rb +1 -2
- data/lib/hutch/waiter.rb +104 -0
- data/lib/hutch/worker.rb +81 -75
- data/lib/hutch.rb +15 -6
- data/lib/yard-settings/handler.rb +38 -0
- data/lib/yard-settings/yard-settings.rb +2 -0
- data/spec/hutch/broker_spec.rb +162 -77
- data/spec/hutch/cli_spec.rb +16 -3
- data/spec/hutch/config_spec.rb +121 -22
- data/spec/hutch/consumer_spec.rb +82 -4
- data/spec/hutch/error_handlers/airbrake_spec.rb +25 -10
- data/spec/hutch/error_handlers/bugsnag_spec.rb +55 -0
- data/spec/hutch/error_handlers/honeybadger_spec.rb +24 -2
- data/spec/hutch/error_handlers/logger_spec.rb +14 -1
- data/spec/hutch/error_handlers/rollbar_spec.rb +45 -0
- data/spec/hutch/error_handlers/sentry_raven_spec.rb +37 -0
- data/spec/hutch/error_handlers/sentry_spec.rb +21 -2
- data/spec/hutch/logger_spec.rb +12 -6
- data/spec/hutch/message_spec.rb +2 -2
- data/spec/hutch/serializers/json_spec.rb +17 -0
- data/spec/hutch/tracers/datadog_spec.rb +44 -0
- data/spec/hutch/waiter_spec.rb +51 -0
- data/spec/hutch/worker_spec.rb +89 -5
- data/spec/spec_helper.rb +7 -5
- data/templates/default/class/html/settings.erb +0 -0
- data/templates/default/class/setup.rb +4 -0
- data/templates/default/fulldoc/html/css/hutch.css +13 -0
- data/templates/default/layout/html/setup.rb +7 -0
- data/templates/default/method_details/html/settings.erb +5 -0
- data/templates/default/method_details/setup.rb +4 -0
- data/templates/default/method_details/text/settings.erb +0 -0
- data/templates/default/module/html/settings.erb +40 -0
- data/templates/default/module/setup.rb +4 -0
- metadata +62 -43
- data/circle.yml +0 -3
@@ -0,0 +1,38 @@
|
|
1
|
+
# :nodoc:
|
2
|
+
class SettingsHandlerBase < YARD::Handlers::Ruby::Base
|
3
|
+
handles method_call :string_setting
|
4
|
+
handles method_call :number_setting
|
5
|
+
handles method_call :boolean_setting
|
6
|
+
|
7
|
+
namespace_only
|
8
|
+
|
9
|
+
def process
|
10
|
+
name = statement.parameters.first.jump(:tstring_content, :ident).source
|
11
|
+
object = YARD::CodeObjects::MethodObject.new(namespace, name)
|
12
|
+
register(object)
|
13
|
+
|
14
|
+
# Modify the code object for the new instance method
|
15
|
+
object.dynamic = true
|
16
|
+
# Add custom metadata to the object
|
17
|
+
object['custom_field'] = '(Found using method_missing)'
|
18
|
+
|
19
|
+
# Module-level configuration notes
|
20
|
+
hutch_config = YARD::CodeObjects::ModuleObject.new(:root, "Hutch::Config")
|
21
|
+
collection_name = statement.first.first
|
22
|
+
default_value = statement.parameters[1].jump(:tstring_content, :ident).source
|
23
|
+
|
24
|
+
(hutch_config['setting_rows'] ||= []) << {
|
25
|
+
name: name,
|
26
|
+
default_value: default_value,
|
27
|
+
type: collection_name.sub('_setting', '').capitalize,
|
28
|
+
description: object.docstring,
|
29
|
+
first_line_of_description: first_line_of_description(object)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def first_line_of_description(object)
|
34
|
+
return '' if object.docstring.blank?
|
35
|
+
|
36
|
+
object.docstring.lines.first
|
37
|
+
end
|
38
|
+
end
|
data/spec/hutch/broker_spec.rb
CHANGED
@@ -2,8 +2,16 @@ require 'spec_helper'
|
|
2
2
|
require 'hutch/broker'
|
3
3
|
|
4
4
|
describe Hutch::Broker do
|
5
|
-
|
6
|
-
|
5
|
+
before do
|
6
|
+
Hutch::Config.initialize(client_logger: Hutch::Logging.logger)
|
7
|
+
@config = Hutch::Config.to_hash
|
8
|
+
end
|
9
|
+
let!(:config) { @config }
|
10
|
+
after do
|
11
|
+
Hutch::Config.instance_variable_set(:@config, nil)
|
12
|
+
Hutch::Config.initialize
|
13
|
+
end
|
14
|
+
let(:broker) { Hutch::Broker.new(config) }
|
7
15
|
|
8
16
|
describe '#connect' do
|
9
17
|
before { allow(broker).to receive(:set_up_amqp_connection) }
|
@@ -53,93 +61,183 @@ describe Hutch::Broker do
|
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
56
|
-
describe '#set_up_amqp_connection'
|
57
|
-
|
58
|
-
|
59
|
-
|
64
|
+
describe '#set_up_amqp_connection' do
|
65
|
+
it 'opens a connection, channel and declares an exchange' do
|
66
|
+
expect(broker).to receive(:open_connection!).ordered
|
67
|
+
expect(broker).to receive(:open_channel!).ordered
|
68
|
+
expect(broker).to receive(:declare_exchange!).ordered
|
60
69
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
70
|
+
broker.set_up_amqp_connection
|
71
|
+
end
|
72
|
+
end
|
65
73
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
74
|
+
describe '#open_connection', rabbitmq: true do
|
75
|
+
describe 'return value' do
|
76
|
+
subject { broker.open_connection }
|
77
|
+
after { subject.close }
|
70
78
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
79
|
+
it(nil, adapter: :bunny) { is_expected.to be_a Hutch::Adapters::BunnyAdapter }
|
80
|
+
it(nil, adapter: :march_hare) { is_expected.to be_a Hutch::Adapters::MarchHareAdapter }
|
81
|
+
end
|
75
82
|
|
76
|
-
|
77
|
-
|
78
|
-
|
83
|
+
context 'when given invalid details' do
|
84
|
+
before { config[:mq_host] = 'notarealhost' }
|
85
|
+
it { expect { broker.open_connection }.to raise_error(StandardError) }
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'does not set #connection' do
|
89
|
+
connection = broker.open_connection
|
90
|
+
|
91
|
+
expect(broker.connection).to be_nil
|
92
|
+
|
93
|
+
connection.close
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when configured with a URI' do
|
97
|
+
context 'which specifies the port' do
|
98
|
+
before { config[:uri] = 'amqp://guest:guest@127.0.0.1:5672/' }
|
99
|
+
|
100
|
+
it 'successfully connects' do
|
101
|
+
c = broker.open_connection
|
102
|
+
expect(c).to be_open
|
103
|
+
c.close
|
104
|
+
end
|
79
105
|
end
|
80
106
|
|
81
|
-
|
82
|
-
|
83
|
-
|
107
|
+
context 'which does not specify port and uses the amqp scheme' do
|
108
|
+
before { config[:uri] = 'amqp://guest:guest@127.0.0.1/' }
|
109
|
+
|
110
|
+
it 'successfully connects' do
|
111
|
+
c = broker.open_connection
|
112
|
+
expect(c).to be_open
|
113
|
+
c.close
|
114
|
+
end
|
84
115
|
end
|
85
116
|
|
86
|
-
|
87
|
-
|
88
|
-
|
117
|
+
context 'which specifies the amqps scheme' do
|
118
|
+
before { config[:uri] = 'amqps://guest:guest@127.0.0.1/' }
|
119
|
+
|
120
|
+
it 'utilises TLS' do
|
121
|
+
expect(Hutch::Adapter).to receive(:new).with(
|
122
|
+
hash_including(tls: true, port: 5671)
|
123
|
+
).and_return(instance_double('Hutch::Adapter', start: nil))
|
124
|
+
|
125
|
+
broker.open_connection
|
126
|
+
end
|
89
127
|
end
|
90
128
|
end
|
129
|
+
end
|
91
130
|
|
92
|
-
|
93
|
-
|
94
|
-
|
131
|
+
describe '#open_connection!' do
|
132
|
+
it 'sets the #connection to #open_connection' do
|
133
|
+
connection = double('connection').as_null_object
|
134
|
+
|
135
|
+
expect(broker).to receive(:open_connection).and_return(connection)
|
136
|
+
|
137
|
+
broker.open_connection!
|
95
138
|
|
96
|
-
|
139
|
+
expect(broker.connection).to eq(connection)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#open_channel', rabbitmq: true do
|
144
|
+
before { broker.open_connection! }
|
145
|
+
after { broker.disconnect }
|
146
|
+
|
147
|
+
describe 'return value' do
|
148
|
+
subject { broker.open_channel }
|
149
|
+
|
150
|
+
it(nil, adapter: :bunny) { is_expected.to be_a Bunny::Channel }
|
151
|
+
it(nil, adapter: :march_hare) { is_expected.to be_a MarchHare::Channel }
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'does not set #channel' do
|
155
|
+
broker.open_channel
|
156
|
+
expect(broker.channel).to be_nil
|
97
157
|
end
|
98
158
|
|
99
159
|
context 'with channel_prefetch set' do
|
100
160
|
let(:prefetch_value) { 1 }
|
101
161
|
before { config[:channel_prefetch] = prefetch_value }
|
102
|
-
after { broker.disconnect }
|
103
162
|
|
104
163
|
it "set's channel's prefetch", adapter: :bunny do
|
105
|
-
expect_any_instance_of(Bunny::Channel).
|
106
|
-
|
107
|
-
broker.set_up_amqp_connection
|
164
|
+
expect_any_instance_of(Bunny::Channel).to receive(:prefetch).with(prefetch_value)
|
165
|
+
broker.open_channel
|
108
166
|
end
|
109
167
|
|
110
168
|
it "set's channel's prefetch", adapter: :march_hare do
|
111
|
-
expect_any_instance_of(MarchHare::Channel).
|
112
|
-
|
113
|
-
broker.set_up_amqp_connection
|
169
|
+
expect_any_instance_of(MarchHare::Channel).to receive(:prefetch=).with(prefetch_value)
|
170
|
+
broker.open_channel
|
114
171
|
end
|
115
172
|
end
|
116
173
|
|
117
174
|
context 'with force_publisher_confirms set' do
|
118
175
|
let(:force_publisher_confirms_value) { true }
|
119
176
|
before { config[:force_publisher_confirms] = force_publisher_confirms_value }
|
120
|
-
after { broker.disconnect }
|
121
177
|
|
122
178
|
it 'waits for confirmation', adapter: :bunny do
|
123
|
-
expect_any_instance_of(Bunny::Channel).
|
124
|
-
|
125
|
-
broker.set_up_amqp_connection
|
179
|
+
expect_any_instance_of(Bunny::Channel).to receive(:confirm_select)
|
180
|
+
broker.open_channel
|
126
181
|
end
|
127
182
|
|
128
183
|
it 'waits for confirmation', adapter: :march_hare do
|
129
|
-
expect_any_instance_of(MarchHare::Channel).
|
130
|
-
|
131
|
-
broker.set_up_amqp_connection
|
184
|
+
expect_any_instance_of(MarchHare::Channel).to receive(:confirm_select)
|
185
|
+
broker.open_channel
|
132
186
|
end
|
133
187
|
end
|
134
188
|
end
|
135
189
|
|
190
|
+
describe '#open_channel!' do
|
191
|
+
it 'sets the #channel to #open_channel' do
|
192
|
+
channel = double('channel').as_null_object
|
193
|
+
|
194
|
+
expect(broker).to receive(:open_channel).and_return(channel)
|
195
|
+
|
196
|
+
broker.open_channel!
|
197
|
+
|
198
|
+
expect(broker.channel).to eq(channel)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#declare_exchange' do
|
203
|
+
before do
|
204
|
+
broker.open_connection!
|
205
|
+
broker.open_channel!
|
206
|
+
end
|
207
|
+
after { broker.disconnect }
|
208
|
+
|
209
|
+
describe 'return value' do
|
210
|
+
subject { broker.declare_exchange }
|
211
|
+
|
212
|
+
it(nil, adapter: :bunny) { is_expected.to be_a Bunny::Exchange }
|
213
|
+
it(nil, adapter: :march_hare) { is_expected.to be_a MarchHare::Exchange }
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'does not set #exchange' do
|
217
|
+
broker.declare_exchange
|
218
|
+
expect(broker.exchange).to be_nil
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe '#declare_exchange!' do
|
223
|
+
it 'sets the #exchange to #declare_exchange' do
|
224
|
+
exchange = double('exchange').as_null_object
|
225
|
+
|
226
|
+
expect(broker).to receive(:declare_exchange).and_return(exchange)
|
227
|
+
|
228
|
+
broker.declare_exchange!
|
229
|
+
|
230
|
+
expect(broker.exchange).to eq(exchange)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
136
234
|
describe '#set_up_api_connection', rabbitmq: true do
|
137
235
|
context 'with valid details' do
|
138
236
|
before { broker.set_up_api_connection }
|
139
237
|
after { broker.disconnect }
|
140
238
|
|
141
239
|
describe '#api_client' do
|
142
|
-
subject {
|
240
|
+
subject { broker.api_client }
|
143
241
|
it { is_expected.to be_a CarrotTop }
|
144
242
|
end
|
145
243
|
end
|
@@ -149,7 +247,7 @@ describe Hutch::Broker do
|
|
149
247
|
after { broker.disconnect }
|
150
248
|
let(:set_up_api_connection) { ->{ broker.set_up_api_connection } }
|
151
249
|
|
152
|
-
specify { expect(set_up_api_connection).to raise_error }
|
250
|
+
specify { expect(set_up_api_connection).to raise_error(StandardError) }
|
153
251
|
end
|
154
252
|
end
|
155
253
|
|
@@ -192,7 +290,7 @@ describe Hutch::Broker do
|
|
192
290
|
|
193
291
|
describe '#bind_queue' do
|
194
292
|
|
195
|
-
around { |example| broker.connect { example.run } }
|
293
|
+
around { |example| broker.connect(host: "127.0.0.1") { example.run } }
|
196
294
|
|
197
295
|
let(:routing_keys) { %w( a b c ) }
|
198
296
|
let(:queue) { double('Queue', bind: nil, unbind: nil, name: 'consumer') }
|
@@ -225,21 +323,6 @@ describe Hutch::Broker do
|
|
225
323
|
end
|
226
324
|
end
|
227
325
|
|
228
|
-
describe '#wait_on_threads' do
|
229
|
-
let(:thread) { double('Thread') }
|
230
|
-
before { allow(broker).to receive(:work_pool_threads).and_return(threads) }
|
231
|
-
|
232
|
-
context 'when all threads finish within the timeout' do
|
233
|
-
let(:threads) { [double(join: thread), double(join: thread)] }
|
234
|
-
specify { expect(broker.wait_on_threads(1)).to be_truthy }
|
235
|
-
end
|
236
|
-
|
237
|
-
context 'when timeout expires for one thread' do
|
238
|
-
let(:threads) { [double(join: thread), double(join: nil)] }
|
239
|
-
specify { expect(broker.wait_on_threads(1)).to be_falsey }
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
326
|
describe '#stop', adapter: :bunny do
|
244
327
|
let(:thread_1) { double('Thread') }
|
245
328
|
let(:thread_2) { double('Thread') }
|
@@ -280,12 +363,12 @@ describe Hutch::Broker do
|
|
280
363
|
|
281
364
|
it 'publishes to the exchange' do
|
282
365
|
expect(broker.exchange).to receive(:publish).once
|
283
|
-
broker.publish('test.key',
|
366
|
+
broker.publish('test.key', {key: "value"})
|
284
367
|
end
|
285
368
|
|
286
369
|
it 'sets default properties' do
|
287
370
|
expect(broker.exchange).to receive(:publish).with(
|
288
|
-
JSON.dump("
|
371
|
+
JSON.dump({key: "value"}),
|
289
372
|
hash_including(
|
290
373
|
persistent: true,
|
291
374
|
routing_key: 'test.key',
|
@@ -293,12 +376,12 @@ describe Hutch::Broker do
|
|
293
376
|
)
|
294
377
|
)
|
295
378
|
|
296
|
-
broker.publish('test.key',
|
379
|
+
broker.publish('test.key', {key: "value"})
|
297
380
|
end
|
298
381
|
|
299
382
|
it 'allows passing message properties' do
|
300
383
|
expect(broker.exchange).to receive(:publish).once
|
301
|
-
broker.publish('test.key',
|
384
|
+
broker.publish('test.key', {key: "value"}, {expiration: "2000", persistent: false})
|
302
385
|
end
|
303
386
|
|
304
387
|
context 'when there are global properties' do
|
@@ -309,8 +392,8 @@ describe Hutch::Broker do
|
|
309
392
|
|
310
393
|
it 'merges the properties' do
|
311
394
|
expect(broker.exchange).
|
312
|
-
to receive(:publish).with('"
|
313
|
-
broker.publish('test.key',
|
395
|
+
to receive(:publish).with('{"key":"value"}', hash_including(app_id: 'app'))
|
396
|
+
broker.publish('test.key', {key: "value"})
|
314
397
|
end
|
315
398
|
end
|
316
399
|
|
@@ -321,8 +404,8 @@ describe Hutch::Broker do
|
|
321
404
|
|
322
405
|
it 'calls the proc and merges the properties' do
|
323
406
|
expect(broker.exchange).
|
324
|
-
to receive(:publish).with('"
|
325
|
-
broker.publish('test.key',
|
407
|
+
to receive(:publish).with('{"key":"value"}', hash_including(app_id: 'app'))
|
408
|
+
broker.publish('test.key', {key: "value"})
|
326
409
|
end
|
327
410
|
end
|
328
411
|
end
|
@@ -331,13 +414,13 @@ describe Hutch::Broker do
|
|
331
414
|
it 'does not wait for confirms on the channel', adapter: :bunny do
|
332
415
|
expect_any_instance_of(Bunny::Channel).
|
333
416
|
to_not receive(:wait_for_confirms)
|
334
|
-
broker.publish('test.key',
|
417
|
+
broker.publish('test.key', {key: "value"})
|
335
418
|
end
|
336
419
|
|
337
420
|
it 'does not wait for confirms on the channel', adapter: :march_hare do
|
338
421
|
expect_any_instance_of(MarchHare::Channel).
|
339
422
|
to_not receive(:wait_for_confirms)
|
340
|
-
broker.publish('test.key',
|
423
|
+
broker.publish('test.key', {key: "value"})
|
341
424
|
end
|
342
425
|
end
|
343
426
|
|
@@ -351,26 +434,28 @@ describe Hutch::Broker do
|
|
351
434
|
it 'waits for confirms on the channel', adapter: :bunny do
|
352
435
|
expect_any_instance_of(Bunny::Channel).
|
353
436
|
to receive(:wait_for_confirms)
|
354
|
-
broker.publish('test.key',
|
437
|
+
broker.publish('test.key', {key: "value"})
|
355
438
|
end
|
356
439
|
|
357
440
|
it 'waits for confirms on the channel', adapter: :march_hare do
|
358
441
|
expect_any_instance_of(MarchHare::Channel).
|
359
442
|
to receive(:wait_for_confirms)
|
360
|
-
broker.publish('test.key',
|
443
|
+
broker.publish('test.key', {key: "value"})
|
361
444
|
end
|
362
445
|
end
|
363
446
|
end
|
364
447
|
|
365
448
|
context 'without a valid connection' do
|
449
|
+
before { broker.set_up_amqp_connection; broker.disconnect }
|
450
|
+
|
366
451
|
it 'raises an exception' do
|
367
|
-
expect { broker.publish('test.key',
|
452
|
+
expect { broker.publish('test.key', {key: "value"}) }.
|
368
453
|
to raise_exception(Hutch::PublishError)
|
369
454
|
end
|
370
455
|
|
371
456
|
it 'logs an error' do
|
372
457
|
expect(broker.logger).to receive(:error)
|
373
|
-
broker.publish('test.key',
|
458
|
+
broker.publish('test.key', {key: "value"}) rescue nil
|
374
459
|
end
|
375
460
|
end
|
376
461
|
end
|
data/spec/hutch/cli_spec.rb
CHANGED
@@ -4,6 +4,19 @@ require 'tempfile'
|
|
4
4
|
describe Hutch::CLI do
|
5
5
|
let(:cli) { Hutch::CLI.new }
|
6
6
|
|
7
|
+
describe "#start_work_loop" do
|
8
|
+
context "connection error during setup" do
|
9
|
+
let(:error) { Hutch::ConnectionError.new }
|
10
|
+
it "gets reported using error handlers" do
|
11
|
+
allow(Hutch).to receive(:connect).and_raise(error)
|
12
|
+
Hutch::Config[:error_handlers].each do |backend|
|
13
|
+
expect(backend).to receive(:handle_setup_exception).with(error)
|
14
|
+
end
|
15
|
+
cli.start_work_loop
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
describe "#parse_options" do
|
8
21
|
context "--config" do
|
9
22
|
context "when the config file does not exist" do
|
@@ -13,7 +26,7 @@ describe Hutch::CLI do
|
|
13
26
|
it "bails" do
|
14
27
|
expect {
|
15
28
|
cli.parse_options(["--config=#{file}"])
|
16
|
-
}.to raise_error SystemExit
|
29
|
+
}.to raise_error SystemExit, "Config file '/path/to/nonexistant/file' not found"
|
17
30
|
end
|
18
31
|
end
|
19
32
|
|
@@ -37,7 +50,7 @@ describe Hutch::CLI do
|
|
37
50
|
it "bails" do
|
38
51
|
expect {
|
39
52
|
cli.parse_options(["--mq-tls-key=#{file}"])
|
40
|
-
}.to raise_error SystemExit
|
53
|
+
}.to raise_error SystemExit, "Private key file '/path/to/nonexistant/file' not found"
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
@@ -61,7 +74,7 @@ describe Hutch::CLI do
|
|
61
74
|
it "bails" do
|
62
75
|
expect {
|
63
76
|
cli.parse_options(["--mq-tls-cert=#{file}"])
|
64
|
-
}.to raise_error SystemExit
|
77
|
+
}.to raise_error SystemExit, "Certificate file '/path/to/nonexistant/file' not found"
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
data/spec/hutch/config_spec.rb
CHANGED
@@ -4,23 +4,40 @@ require 'tempfile'
|
|
4
4
|
describe Hutch::Config do
|
5
5
|
let(:new_value) { 'not-localhost' }
|
6
6
|
|
7
|
+
before do
|
8
|
+
Hutch::Config.instance_variable_set(:@config, nil)
|
9
|
+
Hutch::Config.initialize
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Hutch::Config.instance_variable_set(:@config, nil)
|
14
|
+
end
|
15
|
+
|
7
16
|
describe '.get' do
|
8
17
|
context 'for valid attributes' do
|
9
18
|
subject { Hutch::Config.get(:mq_host) }
|
10
19
|
|
11
20
|
context 'with no overridden value' do
|
12
|
-
it { is_expected.to eq('
|
21
|
+
it { is_expected.to eq('127.0.0.1') }
|
13
22
|
end
|
14
23
|
|
15
24
|
context 'with an overridden value' do
|
16
|
-
before
|
25
|
+
before do
|
26
|
+
Hutch::Config.set(:mq_host, new_value)
|
27
|
+
end
|
28
|
+
|
17
29
|
it { is_expected.to eq(new_value) }
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
21
33
|
context 'for invalid attributes' do
|
22
|
-
let(:invalid_get)
|
23
|
-
|
34
|
+
let(:invalid_get) do
|
35
|
+
-> { Hutch::Config.get(:invalid_attr) }
|
36
|
+
end
|
37
|
+
|
38
|
+
specify do
|
39
|
+
expect(invalid_get).to raise_error Hutch::UnknownAttributeError
|
40
|
+
end
|
24
41
|
end
|
25
42
|
end
|
26
43
|
|
@@ -32,11 +49,54 @@ describe Hutch::Config do
|
|
32
49
|
context 'sets value in user config hash' do
|
33
50
|
it { is_expected.to eq(new_value) }
|
34
51
|
end
|
52
|
+
|
53
|
+
context 'type casting' do
|
54
|
+
context 'number attributes' do
|
55
|
+
before { Hutch::Config.set(:heartbeat, new_value) }
|
56
|
+
subject(:value) { Hutch::Config.user_config[:heartbeat] }
|
57
|
+
|
58
|
+
let(:new_value) { "0" }
|
59
|
+
|
60
|
+
|
61
|
+
specify 'casts values to integers' do
|
62
|
+
expect(value).to eq 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'boolean attributes' do
|
68
|
+
before { Hutch::Config.set(:autoload_rails, new_value) }
|
69
|
+
subject(:value) { Hutch::Config.user_config[:autoload_rails] }
|
70
|
+
|
71
|
+
let(:new_value) { "t" }
|
72
|
+
|
73
|
+
|
74
|
+
specify 'casts values to booleans' do
|
75
|
+
expect(value).to eq true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'string attributes' do
|
80
|
+
before { Hutch::Config.set(:mq_exchange_type, new_value) }
|
81
|
+
subject(:value) { Hutch::Config.user_config[:mq_exchange_type] }
|
82
|
+
|
83
|
+
let(:new_value) { 1 }
|
84
|
+
|
85
|
+
|
86
|
+
specify 'does not perform any typecasting' do
|
87
|
+
expect(value).to eq new_value
|
88
|
+
end
|
89
|
+
end
|
35
90
|
end
|
36
91
|
|
37
92
|
context 'for invalid attributes' do
|
38
|
-
let(:invalid_set)
|
39
|
-
|
93
|
+
let(:invalid_set) do
|
94
|
+
-> { Hutch::Config.set(:invalid_attr, new_value) }
|
95
|
+
end
|
96
|
+
|
97
|
+
specify do
|
98
|
+
expect(invalid_set).to raise_error Hutch::UnknownAttributeError
|
99
|
+
end
|
40
100
|
end
|
41
101
|
end
|
42
102
|
|
@@ -49,9 +109,33 @@ describe Hutch::Config do
|
|
49
109
|
end
|
50
110
|
|
51
111
|
context 'for an invalid attribute' do
|
52
|
-
let(:invalid_getter) { ->{ Hutch::Config.invalid_attr } }
|
112
|
+
let(:invalid_getter) { -> { Hutch::Config.invalid_attr } }
|
53
113
|
specify { expect(invalid_getter).to raise_error NoMethodError }
|
54
114
|
end
|
115
|
+
|
116
|
+
context 'for an ENV-overriden value attribute' do
|
117
|
+
around do |example|
|
118
|
+
ENV['HUTCH_MQ_HOST'] = 'example.com'
|
119
|
+
ENV['HUTCH_MQ_PORT'] = '10001'
|
120
|
+
ENV['HUTCH_MQ_TLS'] = 'true'
|
121
|
+
example.run
|
122
|
+
ENV.delete('HUTCH_MQ_HOST')
|
123
|
+
ENV.delete('HUTCH_MQ_PORT')
|
124
|
+
ENV.delete('HUTCH_MQ_TLS')
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns the override' do
|
128
|
+
expect(Hutch::Config.mq_host).to eq 'example.com'
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'returns the override for integers' do
|
132
|
+
expect(Hutch::Config.mq_port).to eq 10_001
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'returns the override for booleans' do
|
136
|
+
expect(Hutch::Config.mq_tls).to eq true
|
137
|
+
end
|
138
|
+
end
|
55
139
|
end
|
56
140
|
|
57
141
|
describe 'a magic setter' do
|
@@ -63,7 +147,7 @@ describe Hutch::Config do
|
|
63
147
|
end
|
64
148
|
|
65
149
|
context 'for an invalid attribute' do
|
66
|
-
let(:invalid_setter) { ->{ Hutch::Config.invalid_attr = new_value } }
|
150
|
+
let(:invalid_setter) { -> { Hutch::Config.invalid_attr = new_value } }
|
67
151
|
specify { expect(invalid_setter).to raise_error NoMethodError }
|
68
152
|
end
|
69
153
|
end
|
@@ -81,9 +165,9 @@ describe Hutch::Config do
|
|
81
165
|
context 'when an attribute is invalid' do
|
82
166
|
let(:config_data) { { random_attribute: 'socks' } }
|
83
167
|
it 'raises an error' do
|
84
|
-
expect
|
168
|
+
expect do
|
85
169
|
Hutch::Config.load_from_file(file)
|
86
|
-
|
170
|
+
end.to raise_error(NoMethodError)
|
87
171
|
end
|
88
172
|
end
|
89
173
|
|
@@ -96,26 +180,21 @@ describe Hutch::Config do
|
|
96
180
|
expect(Hutch::Config.mq_username).to eq username
|
97
181
|
end
|
98
182
|
end
|
99
|
-
end
|
100
183
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
184
|
+
context 'when using ERB' do
|
185
|
+
let(:host) { 'localhost' }
|
186
|
+
let(:file) do
|
187
|
+
Tempfile.new('configs.yaml').tap do |t|
|
188
|
+
t.write(config_contents)
|
189
|
+
t.rewind
|
190
|
+
end
|
108
191
|
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context 'when using ERb' do
|
112
192
|
let(:config_contents) do
|
113
193
|
<<-YAML
|
114
194
|
mq_host: 'localhost'
|
115
195
|
mq_username: '<%= "calvin" %>'
|
116
196
|
YAML
|
117
197
|
end
|
118
|
-
|
119
198
|
it 'loads in the config data' do
|
120
199
|
Hutch::Config.load_from_file(file)
|
121
200
|
expect(Hutch::Config.mq_host).to eq host
|
@@ -123,4 +202,24 @@ YAML
|
|
123
202
|
end
|
124
203
|
end
|
125
204
|
end
|
205
|
+
|
206
|
+
context 'developer ergonomics' do
|
207
|
+
it 'will accept strings and symbols as config keys' do
|
208
|
+
expect(Hutch::Config.get(:mq_host)).to eq '127.0.0.1'
|
209
|
+
expect(Hutch::Config.get('mq_host')).to eq '127.0.0.1'
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'it will not overwrite existing config' do
|
213
|
+
it 'with defaults' do
|
214
|
+
expect(Hutch::Config.get(:mq_host)).to eq '127.0.0.1'
|
215
|
+
Hutch::Config.initialize
|
216
|
+
|
217
|
+
Hutch::Config.set(:mq_host, 'example2.com')
|
218
|
+
|
219
|
+
expect(Hutch::Config.get(:mq_host)).to eq 'example2.com'
|
220
|
+
Hutch::Config.initialize
|
221
|
+
expect(Hutch::Config.get(:mq_host)).to eq 'example2.com'
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
126
225
|
end
|