hutch 0.18.0 → 1.1.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 +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
|