dogtrainer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ require 'log4r'
2
+
3
+ module DogTrainer
4
+ # module to setup logging per-class throughout DogTrainer
5
+ module Logging
6
+ # Return the name of the class this logger is part of
7
+ #
8
+ # @return [String] logger class name
9
+ def logger_name
10
+ self.class.to_s
11
+ end
12
+
13
+ # Return a logger for the current class
14
+ #
15
+ # @return [Log4r::Logger]
16
+ def logger
17
+ if @logger.nil?
18
+ name = logger_name
19
+ if Log4r::Logger[name]
20
+ @logger = Log4r::Logger[name]
21
+ else
22
+ @logger = Log4r::Logger.new(name)
23
+ @logger.add(DogTrainer::Logging.outputter)
24
+ end
25
+ end
26
+ @logger
27
+ end
28
+
29
+ class << self
30
+ # Set the logger level and the output formatter
31
+ def level=(level)
32
+ outputter.level = level
33
+ @level = level
34
+
35
+ outputter.formatter = if level < Log4r::INFO
36
+ debug_formatter
37
+ else
38
+ default_formatter
39
+ end
40
+ end
41
+
42
+ # @!attribute [r] level
43
+ # @return [Integer] The current log level. Lower numbers correspond
44
+ # to more verbose log levels.
45
+ attr_reader :level
46
+
47
+ # @!attribute [r] formatter
48
+ # @api private
49
+ # @return [Log4r::Formatter]
50
+ attr_reader :formatter
51
+
52
+ # @!attribute [r] outputter
53
+ # @api private
54
+ # @return [Log4r::Outputter]
55
+ attr_reader :outputter
56
+
57
+ # Return a new log formatter with the default pattern
58
+ #
59
+ # @return [Log4r::PatternFormatter]
60
+ def default_formatter
61
+ Log4r::PatternFormatter.new(pattern: '%l\t -> %m')
62
+ end
63
+
64
+ # Return a new log formatter with the debug-level pattern
65
+ #
66
+ # @return [Log4r::PatternFormatter]
67
+ def debug_formatter
68
+ Log4r::PatternFormatter.new(pattern: '[%d - %C - %l] %m')
69
+ end
70
+
71
+ # Return the default log outputter (console)
72
+ #
73
+ # @return [Log4r::StderrOutputter]
74
+ def default_outputter
75
+ Log4r::StderrOutputter.new 'console'
76
+ end
77
+ end
78
+
79
+ Log4r::Logger.global.level = Log4r::ALL
80
+
81
+ @level = Log4r::INFO
82
+ @formatter = default_formatter
83
+ @outputter = default_outputter
84
+ end
85
+ end
@@ -0,0 +1,4 @@
1
+ module DogTrainer
2
+ # store the verson of the Gem/module; used in the gemspec and in messages
3
+ VERSION = '0.1.0'.freeze
4
+ end
@@ -0,0 +1,57 @@
1
+ require 'simplecov'
2
+ require 'simplecov-console'
3
+ require 'rspec_junit_formatter'
4
+
5
+ # for naming coverage and test results in CircleCI by ruby version tested
6
+ dir_suffix = ''
7
+ if ENV['GEM_HOME']
8
+ ver = File.basename(ENV['GEM_HOME'])
9
+ dir_suffix = "-#{ver}"
10
+ end
11
+
12
+ # for storing artifacts in the right place for CircleCI
13
+ if ENV['CIRCLE_ARTIFACTS']
14
+ dir = File.join(ENV['CIRCLE_ARTIFACTS'], "coverage#{dir_suffix}")
15
+ SimpleCov.coverage_dir(dir)
16
+ end
17
+
18
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
19
+ [SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::Console]
20
+ )
21
+
22
+ SimpleCov.start do
23
+ add_filter '/vendor/'
24
+ add_filter '/spec/'
25
+ end
26
+
27
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
28
+
29
+ RSpec.configure do |config|
30
+ # moved from .rspec to interpolate $CIRCLE_ARTIFACTS as output directory
31
+ # see: https://circleci.com/docs/build-artifacts and
32
+ # http://blog.circleci.com/build-artifacts/
33
+ # and also use CircleCI Junit parsing:
34
+ # http://blog.circleci.com/announcing-detailed-test-failure-reporting/
35
+ if ENV.key?('CIRCLE_ARTIFACTS')
36
+ junit_results_path = "#{ENV['CIRCLE_TEST_REPORTS']}/rspec/results"\
37
+ "#{dir_suffix}.xml"
38
+ html_results_path = "#{ENV['CIRCLE_TEST_REPORTS']}/rspec/results"\
39
+ "#{dir_suffix}.html"
40
+ else
41
+ junit_results_path = 'results/results.xml'
42
+ html_results_path = 'results/results.html'
43
+ end
44
+ config.color = true
45
+ config.order = :random
46
+ # documentation format
47
+ config.add_formatter(:documentation)
48
+ # HTML format
49
+ # @see https://github.com/rspec/rspec-core/blob/v2.14.8/lib/rspec/core/configuration.rb#L1086
50
+ config.add_formatter(:html, html_results_path)
51
+ # JUnit results
52
+ config.add_formatter('RspecJunitFormatter', junit_results_path)
53
+
54
+ config.before(:all) do
55
+ Log4r::Logger.global.level = Log4r::OFF
56
+ end
57
+ end
@@ -0,0 +1,1229 @@
1
+ require 'git'
2
+ require 'dogapi'
3
+ require 'dogtrainer'
4
+
5
+ describe DogTrainer::API do
6
+ subject do
7
+ allow(Dogapi::Client).to receive(:new).and_return(nil)
8
+ DogTrainer::API.new(
9
+ 'my_apikey', 'my_appkey', '@my-notify-to', 'my_repo_path'
10
+ )
11
+ end
12
+ describe '#initialize' do
13
+ it 'sets state variables to nil' do
14
+ expect(subject.instance_variable_get('@monitors')).to be_nil
15
+ expect(subject.instance_variable_get('@timeboards')).to be_nil
16
+ expect(subject.instance_variable_get('@screenboards')).to be_nil
17
+ end
18
+ it 'includes DogTrainer::Logging' do
19
+ expect(subject).to respond_to(:logger)
20
+ expect(subject).to respond_to(:logger_name)
21
+ end
22
+ it 'sets an instance variables for notify_to parameter' do
23
+ expect(subject.instance_variable_get('@notify_to')).to eq('@my-notify-to')
24
+ end
25
+ it 'instantiates Dogapi::Client' do
26
+ x = DogTrainer::API.new(
27
+ 'my_apikey', 'my_appkey', '@my-notify-to', 'my/path'
28
+ )
29
+ expect(x.instance_variable_get('@dog')).to be_a(Dogapi::Client)
30
+ expect(
31
+ x.instance_variable_get('@dog')
32
+ .instance_variable_get('@application_key')
33
+ ).to eq('my_appkey')
34
+ expect(
35
+ x.instance_variable_get('@dog')
36
+ .instance_variable_get('@api_key')
37
+ ).to eq('my_apikey')
38
+ end
39
+ it 'uses repo_path parameter as @repo_path if specified' do
40
+ allow_any_instance_of(DogTrainer::API).to receive(:get_repo_path)
41
+ .and_return('foo/bar')
42
+
43
+ expect_any_instance_of(DogTrainer::API).to_not receive(:get_repo_path)
44
+
45
+ x = DogTrainer::API.new(
46
+ 'my_apikey', 'my_appkey', '@my-notify-to', 'my/path'
47
+ )
48
+ expect(x.instance_variable_get('@repo_path')).to eq('my/path')
49
+ end
50
+ it 'uses #get_repo_path if repo_path parameter not specified' do
51
+ allow_any_instance_of(DogTrainer::API).to receive(:get_repo_path)
52
+ .and_return('foo/bar')
53
+
54
+ expect_any_instance_of(DogTrainer::API).to receive(:get_repo_path)
55
+ .and_return('foo/bar')
56
+
57
+ x = DogTrainer::API.new(
58
+ 'my_apikey', 'my_appkey', '@my-notify-to'
59
+ )
60
+ expect(x.instance_variable_get('@repo_path')).to eq('foo/bar')
61
+ end
62
+ end
63
+ describe '#get_repo_path' do
64
+ it 'calls #get_git_url_for_directory if ENV vars are not set' do
65
+ allow(ENV).to receive(:has_key?).with('GIT_URL').and_return(false)
66
+ allow(ENV).to receive(:has_key?).with('CIRCLE_REPOSITORY_URL')
67
+ .and_return(false)
68
+ allow(subject).to receive(:caller)
69
+ .and_return(['foo', 'my/path/Rakefile:123'])
70
+ allow(subject).to receive(:get_git_url_for_directory).with(any_args)
71
+ .and_return('my/repo/path')
72
+
73
+ expect(subject).to receive(:get_git_url_for_directory).with('my/path')
74
+ .once
75
+ expect(subject.get_repo_path).to eq('my/repo/path')
76
+ end
77
+ it 'raises an Exception if #get_git_url_for_directory returns nil' do
78
+ allow(ENV).to receive(:has_key?).with('GIT_URL').and_return(false)
79
+ allow(ENV).to receive(:has_key?).with('CIRCLE_REPOSITORY_URL')
80
+ .and_return(false)
81
+ allow(subject).to receive(:caller)
82
+ .and_return(['foo', 'my/path/Rakefile:123'])
83
+ allow(subject).to receive(:get_git_url_for_directory).with(any_args)
84
+ .and_return(nil)
85
+
86
+ expect(subject).to receive(:get_git_url_for_directory)
87
+ .with('my/path').once
88
+ expect { subject.get_repo_path }.to raise_error(
89
+ RuntimeError,
90
+ /Unable to determine source code path; please specify repo_path/
91
+ )
92
+ end
93
+ it 'returns GIT_URL if set' do
94
+ allow(ENV).to receive(:has_key?).with('GIT_URL').and_return(true)
95
+ allow(ENV).to receive(:has_key?).with('CIRCLE_REPOSITORY_URL')
96
+ .and_return(true)
97
+
98
+ allow(ENV).to receive(:[]).with('GIT_URL').and_return('my/git/url')
99
+ allow(ENV).to receive(:[]).with('CIRCLE_REPOSITORY_URL')
100
+ .and_return('my/circle/url')
101
+ allow(subject).to receive(:caller)
102
+ allow(subject).to receive(:get_git_url_for_directory)
103
+
104
+ expect(subject).to_not receive(:caller)
105
+ expect(subject).to_not receive(:get_git_url_for_directory)
106
+ expect(subject.get_repo_path).to eq('my/git/url')
107
+ end
108
+ end
109
+ describe '#get_git_url_for_directory' do
110
+ it 'returns nil if the command fails' do
111
+ allow(Dir).to receive(:chdir).with(any_args) { |&block| block.call }
112
+ expect(Dir).to receive(:chdir).once.with('/foo/bar')
113
+ allow(subject).to receive(:`).with(any_args).and_raise(Errno::ENOENT)
114
+ expect(subject).to receive(:`).once.with('git config --local -l')
115
+ expect(subject.get_git_url_for_directory('/foo/bar')).to be_nil
116
+ end
117
+ it 'returns nil if no matching remotes' do
118
+ allow(Dir).to receive(:chdir).with(any_args) { |&block| block.call }
119
+ expect(Dir).to receive(:chdir).once.with('/foo/bar')
120
+ allow(subject).to receive(:`).with(any_args).and_return('foobar')
121
+ expect(subject).to receive(:`).once.with('git config --local -l')
122
+ expect(subject.get_git_url_for_directory('/foo/bar')).to be_nil
123
+ end
124
+ it 'returns the first matching remote' do
125
+ expected = 'git@github.com:jantman/puppet.git'
126
+ output = [
127
+ 'core.repositoryformatversion=0',
128
+ 'core.filemode=true',
129
+ 'core.bare=false',
130
+ 'core.logallrefupdates=true',
131
+ 'remote.origin.url=git@github.com:jantman/puppet.git',
132
+ 'remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*',
133
+ 'remote.origin.fetch=+refs/pull/*/head:refs/pull/origin/*',
134
+ 'branch.master.remote=origin',
135
+ 'branch.master.merge=refs/heads/master',
136
+ 'credential.helper=store --file=.git/credentials',
137
+ 'branch.gh-pages.remote=origin',
138
+ 'branch.gh-pages.merge=refs/heads/gh-pages',
139
+ 'remote.upstream.url=git@github.com:puppetlabs/puppet.git',
140
+ 'remote.upstream.fetch=+refs/heads/*:refs/remotes/upstream/*',
141
+ 'remote.upstream.fetch=+refs/pull/*/head:refs/pull/upstream/*'
142
+ ].join("\n") + "\n"
143
+ allow(Dir).to receive(:chdir).with(any_args) { |&block| block.call }
144
+ expect(Dir).to receive(:chdir).once.with('/foo/bar')
145
+ allow(subject).to receive(:`).with(any_args).and_return(output)
146
+ expect(subject).to receive(:`).once.with('git config --local -l')
147
+ expect(subject.get_git_url_for_directory('/foo/bar')).to eq(expected)
148
+ end
149
+ end
150
+ describe '#generate_messages' do
151
+ it 'returns the appropriate message' do
152
+ expected = "{{#is_alert}}'mydesc' should be comp {{threshold}},"
153
+ expected += " but is {{value}}.{{/is_alert}}\n"
154
+ expected += "{{#is_recovery}}'mydesc' recovered (current value "
155
+ expected += '{{value}} is comp threshold of {{threshold}}).'
156
+ expected += "{{/is_recovery}}\n(monitor and threshold configuration "
157
+ expected += 'for this alert is managed by my_repo_path) @my-notify-to'
158
+ msg, = subject.generate_messages('mydesc', 'comp')
159
+ expect(msg).to eq(expected)
160
+ end
161
+ it 'returns the appropriate message' do
162
+ escalation = "'mydesc' is still in error state (current value {{value}}"
163
+ escalation += ' is comp threshold of {{threshold}})'
164
+ _, esc = subject.generate_messages('mydesc', 'comp')
165
+ expect(esc).to eq(escalation)
166
+ end
167
+ end
168
+ describe '#params_for_monitor' do
169
+ it 'returns the correct hash with default params' do
170
+ expected = {
171
+ 'name' => 'monname',
172
+ 'type' => 'metric alert',
173
+ 'query' => 'my_query',
174
+ 'message' => 'my_msg',
175
+ 'tags' => [],
176
+ 'options' => {
177
+ 'notify_audit' => false,
178
+ 'locked' => false,
179
+ 'timeout_h' => 0,
180
+ 'silenced' => {},
181
+ 'thresholds' => { 'critical' => 123.4 },
182
+ 'require_full_window' => false,
183
+ 'notify_no_data' => true,
184
+ 'renotify_interval' => 60,
185
+ 'no_data_timeframe' => 20
186
+ }
187
+ }
188
+ expect(subject.params_for_monitor(
189
+ 'monname',
190
+ 'my_msg',
191
+ 'my_query',
192
+ 123.4
193
+ )).to eq(expected)
194
+ end
195
+ it 'sets escalation_message if provided in options' do
196
+ expected = {
197
+ 'name' => 'monname',
198
+ 'type' => 'metric alert',
199
+ 'query' => 'my_query',
200
+ 'message' => 'my_msg',
201
+ 'tags' => [],
202
+ 'options' => {
203
+ 'notify_audit' => false,
204
+ 'locked' => false,
205
+ 'timeout_h' => 0,
206
+ 'silenced' => {},
207
+ 'thresholds' => { 'critical' => 123.4 },
208
+ 'require_full_window' => false,
209
+ 'notify_no_data' => true,
210
+ 'renotify_interval' => 60,
211
+ 'no_data_timeframe' => 20,
212
+ 'escalation_message' => 'myesc'
213
+ }
214
+ }
215
+ expect(subject.params_for_monitor(
216
+ 'monname',
217
+ 'my_msg',
218
+ 'my_query',
219
+ 123.4,
220
+ escalation_message: 'myesc'
221
+ )).to eq(expected)
222
+ end
223
+ it 'sets mon_type if provided in options' do
224
+ expected = {
225
+ 'name' => 'monname',
226
+ 'type' => 'foo',
227
+ 'query' => 'my_query',
228
+ 'message' => 'my_msg',
229
+ 'tags' => [],
230
+ 'options' => {
231
+ 'notify_audit' => false,
232
+ 'locked' => false,
233
+ 'timeout_h' => 0,
234
+ 'silenced' => {},
235
+ 'thresholds' => { 'critical' => 123.4 },
236
+ 'require_full_window' => false,
237
+ 'notify_no_data' => true,
238
+ 'renotify_interval' => 60,
239
+ 'no_data_timeframe' => 20
240
+ }
241
+ }
242
+ expect(subject.params_for_monitor(
243
+ 'monname',
244
+ 'my_msg',
245
+ 'my_query',
246
+ 123.4,
247
+ mon_type: 'foo'
248
+ )).to eq(expected)
249
+ end
250
+ it 'sets notify_no_data to false if provided in options' do
251
+ expected = {
252
+ 'name' => 'monname',
253
+ 'type' => 'metric alert',
254
+ 'query' => 'my_query',
255
+ 'message' => 'my_msg',
256
+ 'tags' => [],
257
+ 'options' => {
258
+ 'notify_audit' => false,
259
+ 'locked' => false,
260
+ 'timeout_h' => 0,
261
+ 'silenced' => {},
262
+ 'thresholds' => { 'critical' => 123.4 },
263
+ 'require_full_window' => false,
264
+ 'notify_no_data' => false,
265
+ 'renotify_interval' => 60,
266
+ 'no_data_timeframe' => 20
267
+ }
268
+ }
269
+ expect(subject.params_for_monitor(
270
+ 'monname',
271
+ 'my_msg',
272
+ 'my_query',
273
+ 123.4,
274
+ alert_no_data: false
275
+ )).to eq(expected)
276
+ end
277
+ it 'handles all options' do
278
+ expected = {
279
+ 'name' => 'monname',
280
+ 'type' => 'foo',
281
+ 'query' => 'my_query',
282
+ 'message' => 'my_msg',
283
+ 'tags' => [],
284
+ 'options' => {
285
+ 'notify_audit' => false,
286
+ 'locked' => false,
287
+ 'timeout_h' => 0,
288
+ 'silenced' => {},
289
+ 'thresholds' => { 'critical' => 123.4 },
290
+ 'require_full_window' => false,
291
+ 'notify_no_data' => false,
292
+ 'renotify_interval' => 60,
293
+ 'no_data_timeframe' => 20,
294
+ 'escalation_message' => 'myesc'
295
+ }
296
+ }
297
+ expect(subject.params_for_monitor(
298
+ 'monname',
299
+ 'my_msg',
300
+ 'my_query',
301
+ 123.4,
302
+ alert_no_data: false,
303
+ mon_type: 'foo',
304
+ escalation_message: 'myesc'
305
+ )).to eq(expected)
306
+ end
307
+ end
308
+ describe '#upsert_monitor' do
309
+ it 'creates the monitor if it doesnt exist' do
310
+ params = { 'foo' => 'bar', 'baz' => 'blam' }
311
+ dog = double(Dogapi::Client)
312
+ allow(dog).to receive(:update_monitor).with(any_args)
313
+ subject.instance_variable_set('@dog', dog)
314
+ allow(subject).to receive(:generate_messages).with(any_args)
315
+ .and_return(%w(msg esc))
316
+ allow(subject).to receive(:params_for_monitor).with(any_args)
317
+ .and_return(params)
318
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
319
+ .and_return(nil)
320
+ allow(subject).to receive(:create_monitor).with(any_args)
321
+ .and_return('12345')
322
+
323
+ expect(dog).to_not receive(:update_monitor)
324
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
325
+ expect(subject).to receive(:params_for_monitor).once
326
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
327
+ alert_no_data: true,
328
+ mon_type: 'metric alert')
329
+ expect(subject).to receive(:get_existing_monitor_by_name).once
330
+ .with('mname')
331
+ expect(subject).to receive(:create_monitor).once
332
+ .with('mname', params)
333
+
334
+ expect(subject.upsert_monitor(
335
+ 'mname',
336
+ 'my_query',
337
+ 123.4,
338
+ '>='
339
+ )).to eq('12345')
340
+ end
341
+ it 'does nothing if it already exists with the right params' do
342
+ params = { 'foo' => 'bar', 'baz' => 'blam' }
343
+ existing = { 'foo' => 'bar', 'baz' => 'blam', 'id' => 'monid' }
344
+ dog = double(Dogapi::Client)
345
+ allow(dog).to receive(:update_monitor).with(any_args)
346
+ subject.instance_variable_set('@dog', dog)
347
+ allow(subject).to receive(:generate_messages).with(any_args)
348
+ .and_return(%w(msg esc))
349
+ allow(subject).to receive(:params_for_monitor).with(any_args)
350
+ .and_return(params)
351
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
352
+ .and_return(existing)
353
+ allow(subject).to receive(:create_monitor).with(any_args)
354
+ .and_return('12345')
355
+
356
+ expect(dog).to_not receive(:update_monitor)
357
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
358
+ expect(subject).to receive(:params_for_monitor).once
359
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
360
+ alert_no_data: true,
361
+ mon_type: 'metric alert')
362
+ expect(subject).to receive(:get_existing_monitor_by_name).once
363
+ .with('mname')
364
+ expect(subject).to_not receive(:create_monitor)
365
+
366
+ expect(subject.upsert_monitor(
367
+ 'mname',
368
+ 'my_query',
369
+ 123.4,
370
+ '>='
371
+ )).to eq('monid')
372
+ end
373
+ it 'updates the monitor if missing parameters' do
374
+ params = {
375
+ 'foo' => 'bar',
376
+ 'baz' => 'blam',
377
+ 'blarg' => 'quux',
378
+ 'query' => 'my_query'
379
+ }
380
+ existing = {
381
+ 'foo' => 'bar',
382
+ 'baz' => 'blam',
383
+ 'query' => 'my_query',
384
+ 'id' => 'monid'
385
+ }
386
+ dog = double(Dogapi::Client)
387
+ allow(dog).to receive(:update_monitor).with(any_args)
388
+ .and_return(['200', {}])
389
+ subject.instance_variable_set('@dog', dog)
390
+ allow(subject).to receive(:generate_messages).with(any_args)
391
+ .and_return(%w(msg esc))
392
+ allow(subject).to receive(:params_for_monitor).with(any_args)
393
+ .and_return(params)
394
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
395
+ .and_return(existing)
396
+ allow(subject).to receive(:create_monitor).with(any_args)
397
+ .and_return('12345')
398
+
399
+ expect(dog).to receive(:update_monitor).once
400
+ .with('monid', 'my_query', params)
401
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
402
+ expect(subject).to receive(:params_for_monitor).once
403
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
404
+ alert_no_data: true,
405
+ mon_type: 'metric alert')
406
+ expect(subject).to receive(:get_existing_monitor_by_name).once
407
+ .with('mname')
408
+ expect(subject).to_not receive(:create_monitor)
409
+
410
+ expect(subject.upsert_monitor(
411
+ 'mname',
412
+ 'my_query',
413
+ 123.4,
414
+ '>='
415
+ )).to eq('monid')
416
+ end
417
+ it 'updates the monitor if parameters differ' do
418
+ params = { 'foo' => 'bar', 'baz' => 'blam', 'query' => 'my_query' }
419
+ existing = {
420
+ 'foo' => 'bar',
421
+ 'baz' => 'blarg',
422
+ 'query' => 'my_query',
423
+ 'id' => 'monid'
424
+ }
425
+ dog = double(Dogapi::Client)
426
+ allow(dog).to receive(:update_monitor).with(any_args)
427
+ .and_return(['200', {}])
428
+ subject.instance_variable_set('@dog', dog)
429
+ allow(subject).to receive(:generate_messages).with(any_args)
430
+ .and_return(%w(msg esc))
431
+ allow(subject).to receive(:params_for_monitor).with(any_args)
432
+ .and_return(params)
433
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
434
+ .and_return(existing)
435
+ allow(subject).to receive(:create_monitor).with(any_args)
436
+ .and_return('12345')
437
+
438
+ expect(dog).to receive(:update_monitor).once
439
+ .with('monid', 'my_query', params)
440
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
441
+ expect(subject).to receive(:params_for_monitor).once
442
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
443
+ alert_no_data: true,
444
+ mon_type: 'metric alert')
445
+ expect(subject).to receive(:get_existing_monitor_by_name).once
446
+ .with('mname')
447
+ expect(subject).to_not receive(:create_monitor)
448
+
449
+ expect(subject.upsert_monitor(
450
+ 'mname',
451
+ 'my_query',
452
+ 123.4,
453
+ '>='
454
+ )).to eq('monid')
455
+ end
456
+ it 'returns nil if the update failed' do
457
+ params = {
458
+ 'foo' => 'bar',
459
+ 'baz' => 'blam',
460
+ 'blarg' => 'quux',
461
+ 'query' => 'my_query'
462
+ }
463
+ existing = {
464
+ 'foo' => 'bar',
465
+ 'baz' => 'blam',
466
+ 'query' => 'my_query',
467
+ 'id' => 'monid'
468
+ }
469
+ res = ['404', {}]
470
+ dog = double(Dogapi::Client)
471
+ allow(dog).to receive(:update_monitor).with(any_args).and_return(res)
472
+ subject.instance_variable_set('@dog', dog)
473
+ allow(subject).to receive(:generate_messages).with(any_args)
474
+ .and_return(%w(msg esc))
475
+ allow(subject).to receive(:params_for_monitor).with(any_args)
476
+ .and_return(params)
477
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
478
+ .and_return(existing)
479
+ allow(subject).to receive(:create_monitor).with(any_args)
480
+ .and_return('12345')
481
+ allow(subject.logger).to receive(:debug).with(any_args)
482
+ allow(subject.logger).to receive(:info).with(any_args)
483
+ allow(subject.logger).to receive(:error).with(any_args)
484
+
485
+ expect(dog).to receive(:update_monitor).once
486
+ .with('monid', 'my_query', params)
487
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
488
+ expect(subject).to receive(:params_for_monitor).once
489
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
490
+ alert_no_data: true,
491
+ mon_type: 'metric alert')
492
+ expect(subject).to receive(:get_existing_monitor_by_name).once
493
+ .with('mname')
494
+ expect(subject).to_not receive(:create_monitor)
495
+ expect(subject.logger).to receive(:error).once
496
+ .with("\tError updating monitor monid: #{res}")
497
+
498
+ expect(subject.upsert_monitor(
499
+ 'mname',
500
+ 'my_query',
501
+ 123.4,
502
+ '>='
503
+ )).to be_nil
504
+ end
505
+ it 'handles sparse options, with only alert_no_data' do
506
+ params = { 'foo' => 'bar', 'baz' => 'blam' }
507
+ existing = { 'foo' => 'bar', 'baz' => 'blam', 'id' => 'monid' }
508
+ dog = double(Dogapi::Client)
509
+ allow(dog).to receive(:update_monitor).with(any_args)
510
+ subject.instance_variable_set('@dog', dog)
511
+ allow(subject).to receive(:generate_messages).with(any_args)
512
+ .and_return(%w(msg esc))
513
+ allow(subject).to receive(:params_for_monitor).with(any_args)
514
+ .and_return(params)
515
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
516
+ .and_return(existing)
517
+ allow(subject).to receive(:create_monitor).with(any_args)
518
+ .and_return('12345')
519
+
520
+ expect(dog).to_not receive(:update_monitor)
521
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
522
+ expect(subject).to receive(:params_for_monitor).once
523
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
524
+ alert_no_data: false,
525
+ mon_type: 'metric alert')
526
+ expect(subject).to receive(:get_existing_monitor_by_name).once
527
+ .with('mname')
528
+ expect(subject).to_not receive(:create_monitor)
529
+
530
+ expect(subject.upsert_monitor(
531
+ 'mname',
532
+ 'my_query',
533
+ 123.4,
534
+ '>=',
535
+ alert_no_data: false
536
+ )).to eq('monid')
537
+ end
538
+ it 'handles sparse options, with only mon_type' do
539
+ params = { 'foo' => 'bar', 'baz' => 'blam' }
540
+ existing = { 'foo' => 'bar', 'baz' => 'blam', 'id' => 'monid' }
541
+ dog = double(Dogapi::Client)
542
+ allow(dog).to receive(:update_monitor).with(any_args)
543
+ subject.instance_variable_set('@dog', dog)
544
+ allow(subject).to receive(:generate_messages).with(any_args)
545
+ .and_return(%w(msg esc))
546
+ allow(subject).to receive(:params_for_monitor).with(any_args)
547
+ .and_return(params)
548
+ allow(subject).to receive(:get_existing_monitor_by_name).with(any_args)
549
+ .and_return(existing)
550
+ allow(subject).to receive(:create_monitor).with(any_args)
551
+ .and_return('12345')
552
+
553
+ expect(dog).to_not receive(:update_monitor)
554
+ expect(subject).to receive(:generate_messages).once.with('mname', '>=')
555
+ expect(subject).to receive(:params_for_monitor).once
556
+ .with('mname', 'msg', 'my_query', 123.4, escalation_message: 'esc',
557
+ alert_no_data: true,
558
+ mon_type: 'foobar')
559
+ expect(subject).to receive(:get_existing_monitor_by_name).once
560
+ .with('mname')
561
+ expect(subject).to_not receive(:create_monitor)
562
+
563
+ expect(subject.upsert_monitor(
564
+ 'mname',
565
+ 'my_query',
566
+ 123.4,
567
+ '>=',
568
+ mon_type: 'foobar'
569
+ )).to eq('monid')
570
+ end
571
+ end
572
+ describe '#create_monitor' do
573
+ it 'returns the monitor id if created successfully' do
574
+ res = ['200', { 'foo' => 'bar', 'id' => 'monid' }]
575
+ params = { 'type' => 't', 'query' => 'q', 'foo' => 'bar' }
576
+ dog = double(Dogapi::Client)
577
+ allow(dog).to receive(:monitor).with(any_args).and_return(res)
578
+ subject.instance_variable_set('@dog', dog)
579
+ allow(subject.logger).to receive(:error).with(any_args)
580
+
581
+ expect(dog).to receive(:monitor).once
582
+ .with(params['type'], params['query'], params)
583
+ expect(subject.logger).to_not receive(:error)
584
+ expect(subject.create_monitor('foo', params)).to eq('monid')
585
+ end
586
+ it 'logs an error and returns nil if the create fails' do
587
+ res = ['404', {}]
588
+ params = { 'type' => 't', 'query' => 'q', 'foo' => 'bar' }
589
+ dog = double(Dogapi::Client)
590
+ allow(dog).to receive(:monitor).with(any_args).and_return(res)
591
+ subject.instance_variable_set('@dog', dog)
592
+ allow(subject.logger).to receive(:error).with(any_args)
593
+
594
+ expect(dog).to receive(:monitor).once
595
+ .with(params['type'], params['query'], params)
596
+ expect(subject.logger).to receive(:error).once
597
+ .with("\tError creating monitor: #{res}")
598
+ expect(subject.create_monitor('foo', params)).to be_nil
599
+ end
600
+ end
601
+ describe '#get_existing_monitor_by_name' do
602
+ it 'retrieves monitors if they are not cached' do
603
+ monitors = [
604
+ '200',
605
+ [
606
+ { 'name' => 'foo', 'foo' => 'bar' },
607
+ { 'name' => 'bar', 'foo' => 'baz' }
608
+ ]
609
+ ]
610
+ dog = double(Dogapi::Client)
611
+ allow(dog).to receive(:get_all_monitors).with(any_args)
612
+ .and_return(monitors)
613
+ subject.instance_variable_set('@dog', dog)
614
+
615
+ expect(dog).to receive(:get_all_monitors).once.with(group_states: 'all')
616
+ expect(subject.get_existing_monitor_by_name('bar'))
617
+ .to eq('name' => 'bar', 'foo' => 'baz')
618
+ expect(subject.instance_variable_get('@monitors')).to eq(monitors)
619
+ end
620
+ it 'does not retrieve monitors if they are cached' do
621
+ monitors = [
622
+ '200',
623
+ [
624
+ { 'name' => 'foo', 'foo' => 'bar' },
625
+ { 'name' => 'bar', 'foo' => 'baz' }
626
+ ]
627
+ ]
628
+ dog = double(Dogapi::Client)
629
+ allow(dog).to receive(:get_all_monitors).with(any_args)
630
+ .and_return(monitors)
631
+ subject.instance_variable_set('@dog', dog)
632
+ subject.instance_variable_set('@monitors', monitors)
633
+
634
+ expect(dog).to_not receive(:get_all_monitors)
635
+ expect(subject.get_existing_monitor_by_name('bar'))
636
+ .to eq('name' => 'bar', 'foo' => 'baz')
637
+ expect(subject.instance_variable_get('@monitors')).to eq(monitors)
638
+ end
639
+ it 'exits if no monitors can be found' do
640
+ monitors = ['200', []]
641
+ dog = double(Dogapi::Client)
642
+ allow(dog).to receive(:get_all_monitors).with(any_args)
643
+ .and_return(monitors)
644
+ subject.instance_variable_set('@dog', dog)
645
+ allow(subject.logger).to receive(:error).with(any_args)
646
+
647
+ expect(dog).to receive(:get_all_monitors).once
648
+ .with(group_states: 'all')
649
+ expect(subject.logger).to receive(:error).once
650
+ .with('ERROR: Docker API call returned no existing monitors. ' \
651
+ 'Something is wrong.')
652
+ expect { subject.get_existing_monitor_by_name('bar') }
653
+ .to raise_error(SystemExit)
654
+ end
655
+ end
656
+ describe '#graphdef' do
657
+ it 'generates a graphdef with sensible defaults' do
658
+ expected = {
659
+ 'definition' => {
660
+ 'viz' => 'timeseries',
661
+ 'requests' => [
662
+ {
663
+ 'q' => 'query1',
664
+ 'conditional_formats' => [],
665
+ 'type' => 'line'
666
+ }
667
+ ]
668
+ },
669
+ 'title' => 'gtitle'
670
+ }
671
+ expect(subject.graphdef('gtitle', 'query1')).to eq(expected)
672
+ end
673
+ it 'handles an array of queries' do
674
+ expected = {
675
+ 'definition' => {
676
+ 'viz' => 'timeseries',
677
+ 'requests' => [
678
+ {
679
+ 'q' => 'query1',
680
+ 'conditional_formats' => [],
681
+ 'type' => 'line'
682
+ },
683
+ {
684
+ 'q' => 'query2',
685
+ 'conditional_formats' => [],
686
+ 'type' => 'line'
687
+ },
688
+ {
689
+ 'q' => 'query3',
690
+ 'conditional_formats' => [],
691
+ 'type' => 'line'
692
+ }
693
+ ]
694
+ },
695
+ 'title' => 'gtitle'
696
+ }
697
+ expect(
698
+ subject.graphdef('gtitle', %w(query1 query2 query3))
699
+ ).to eq(expected)
700
+ end
701
+ it 'adds markers if specified' do
702
+ expected = {
703
+ 'definition' => {
704
+ 'viz' => 'timeseries',
705
+ 'requests' => [
706
+ {
707
+ 'q' => 'query1',
708
+ 'conditional_formats' => [],
709
+ 'type' => 'line'
710
+ }
711
+ ],
712
+ 'markers' => [
713
+ {
714
+ 'type' => 'error dashed',
715
+ 'val' => '2.3',
716
+ 'value' => 'y = 2.3',
717
+ 'label' => 'marker1==2.3'
718
+ },
719
+ {
720
+ 'type' => 'error dashed',
721
+ 'val' => '45',
722
+ 'value' => 'y = 45',
723
+ 'label' => 'm2==45'
724
+ }
725
+ ]
726
+ },
727
+ 'title' => 'gtitle'
728
+ }
729
+ expect(
730
+ subject.graphdef('gtitle', 'query1', 'marker1' => 2.3, 'm2' => 45)
731
+ ).to eq(expected)
732
+ end
733
+ end
734
+ describe '#upsert_timeboard' do
735
+ it 'creates the timeboard if it doesnt exist' do
736
+ res = [
737
+ '200',
738
+ {
739
+ 'foo' => 'bar',
740
+ 'dash' => {
741
+ 'id' => 'id1',
742
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
743
+ 'title' => 't',
744
+ 'graphs' => [1, 2]
745
+ }
746
+ }
747
+ ]
748
+ dog = double(Dogapi::Client)
749
+ allow(dog).to receive(:create_dashboard).with(any_args).and_return(res)
750
+ allow(dog).to receive(:update_dashboard).with(any_args)
751
+ subject.instance_variable_set('@dog', dog)
752
+ allow(subject).to receive(:get_existing_timeboard_by_name).with(any_args)
753
+ .and_return(nil)
754
+ allow(subject.logger).to receive(:info).with(any_args)
755
+
756
+ expect(subject).to receive(:get_existing_timeboard_by_name).once
757
+ .with('t')
758
+ expect(dog).to receive(:create_dashboard).once
759
+ .with(
760
+ 't',
761
+ 'created by DogTrainer RubyGem via my_repo_path',
762
+ [1, 2]
763
+ )
764
+ expect(dog).to_not receive(:update_dashboard)
765
+ expect(subject.logger).to receive(:info).with('Created timeboard id1')
766
+ subject.upsert_timeboard('t', [1, 2])
767
+ end
768
+ it 'does not update if params are current' do
769
+ res = [
770
+ '200',
771
+ {
772
+ 'foo' => 'bar',
773
+ 'dash' => {
774
+ 'id' => 'id1',
775
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
776
+ 'title' => 't',
777
+ 'graphs' => [1, 2]
778
+ }
779
+ }
780
+ ]
781
+ dog = double(Dogapi::Client)
782
+ allow(dog).to receive(:create_dashboard).with(any_args)
783
+ allow(dog).to receive(:update_dashboard).with(any_args)
784
+ subject.instance_variable_set('@dog', dog)
785
+ allow(subject).to receive(:get_existing_timeboard_by_name).with(any_args)
786
+ .and_return(res[1])
787
+ allow(subject.logger).to receive(:info).with(any_args)
788
+
789
+ expect(subject).to receive(:get_existing_timeboard_by_name).once
790
+ .with('t')
791
+ expect(dog).to_not receive(:create_dashboard)
792
+ expect(dog).to_not receive(:update_dashboard)
793
+ expect(subject.logger).to receive(:info).with("\tTimeboard is up-to-date")
794
+ subject.upsert_timeboard('t', [1, 2])
795
+ end
796
+ it 'updates if title changed' do
797
+ res = [
798
+ '200',
799
+ {
800
+ 'foo' => 'bar',
801
+ 'dash' => {
802
+ 'id' => 'id1',
803
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
804
+ 'title' => 'not_t',
805
+ 'graphs' => [1, 2]
806
+ }
807
+ }
808
+ ]
809
+ dog = double(Dogapi::Client)
810
+ allow(dog).to receive(:create_dashboard).with(any_args)
811
+ allow(dog).to receive(:update_dashboard).with(any_args)
812
+ subject.instance_variable_set('@dog', dog)
813
+ allow(subject).to receive(:get_existing_timeboard_by_name).with(any_args)
814
+ .and_return(res[1])
815
+ allow(subject.logger).to receive(:info).with(any_args)
816
+
817
+ expect(subject).to receive(:get_existing_timeboard_by_name).once
818
+ .with('t')
819
+ expect(dog).to_not receive(:create_dashboard)
820
+ expect(dog).to receive(:update_dashboard).once.with(
821
+ res[1]['dash']['id'],
822
+ 't',
823
+ res[1]['dash']['description'],
824
+ res[1]['dash']['graphs']
825
+ )
826
+ expect(subject.logger).to receive(:info).with("\tUpdating timeboard id1")
827
+ expect(subject.logger).to receive(:info).with("\tTimeboard updated.")
828
+ subject.upsert_timeboard('t', [1, 2])
829
+ end
830
+ it 'updates if repo_path changed' do
831
+ res = [
832
+ '200',
833
+ {
834
+ 'foo' => 'bar',
835
+ 'dash' => {
836
+ 'id' => 'id1',
837
+ 'description' => 'created by DogTrainer RubyGem via otherpath',
838
+ 'title' => 't',
839
+ 'graphs' => [1, 2]
840
+ }
841
+ }
842
+ ]
843
+ dog = double(Dogapi::Client)
844
+ allow(dog).to receive(:create_dashboard).with(any_args)
845
+ allow(dog).to receive(:update_dashboard).with(any_args)
846
+ subject.instance_variable_set('@dog', dog)
847
+ allow(subject).to receive(:get_existing_timeboard_by_name).with(any_args)
848
+ .and_return(res[1])
849
+ allow(subject.logger).to receive(:info).with(any_args)
850
+
851
+ expect(subject).to receive(:get_existing_timeboard_by_name).once
852
+ .with('t')
853
+ expect(dog).to_not receive(:create_dashboard)
854
+ expect(dog).to receive(:update_dashboard).once.with(
855
+ res[1]['dash']['id'],
856
+ res[1]['dash']['title'],
857
+ 'created by DogTrainer RubyGem via my_repo_path',
858
+ res[1]['dash']['graphs']
859
+ )
860
+ expect(subject.logger).to receive(:info).with("\tUpdating timeboard id1")
861
+ expect(subject.logger).to receive(:info).with("\tTimeboard updated.")
862
+ subject.upsert_timeboard('t', [1, 2])
863
+ end
864
+ it 'updates if graphs changed' do
865
+ res = [
866
+ '200',
867
+ {
868
+ 'foo' => 'bar',
869
+ 'dash' => {
870
+ 'id' => 'id1',
871
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
872
+ 'title' => 't',
873
+ 'graphs' => [1, 2]
874
+ }
875
+ }
876
+ ]
877
+ dog = double(Dogapi::Client)
878
+ allow(dog).to receive(:create_dashboard).with(any_args)
879
+ allow(dog).to receive(:update_dashboard).with(any_args)
880
+ subject.instance_variable_set('@dog', dog)
881
+ allow(subject).to receive(:get_existing_timeboard_by_name).with(any_args)
882
+ .and_return(res[1])
883
+ allow(subject.logger).to receive(:info).with(any_args)
884
+
885
+ expect(subject).to receive(:get_existing_timeboard_by_name).once
886
+ .with('t')
887
+ expect(dog).to_not receive(:create_dashboard)
888
+ expect(dog).to receive(:update_dashboard).once.with(
889
+ res[1]['dash']['id'],
890
+ res[1]['dash']['title'],
891
+ res[1]['dash']['description'],
892
+ [3, 4]
893
+ )
894
+ expect(subject.logger).to receive(:info).with("\tUpdating timeboard id1")
895
+ expect(subject.logger).to receive(:info).with("\tTimeboard updated.")
896
+ subject.upsert_timeboard('t', [3, 4])
897
+ end
898
+ end
899
+ describe '#upsert_screenboard' do
900
+ it 'creates the screenboard if it doesnt exist' do
901
+ res = [
902
+ '200',
903
+ {
904
+ 'id' => 'id1',
905
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
906
+ 'board_title' => 't',
907
+ 'widgets' => [1, 2]
908
+ }
909
+ ]
910
+ dog = double(Dogapi::Client)
911
+ allow(dog).to receive(:create_screenboard).with(any_args).and_return(res)
912
+ allow(dog).to receive(:update_screenboard).with(any_args)
913
+ subject.instance_variable_set('@dog', dog)
914
+ allow(subject).to receive(:get_existing_screenboard_by_name)
915
+ .with(any_args).and_return(nil)
916
+ allow(subject.logger).to receive(:info).with(any_args)
917
+
918
+ expect(subject).to receive(:get_existing_screenboard_by_name).once
919
+ .with('t')
920
+ expect(dog).to receive(:create_screenboard).once
921
+ .with(
922
+ board_title: 't',
923
+ description: 'created by DogTrainer RubyGem via my_repo_path',
924
+ widgets: [1, 2]
925
+ )
926
+ expect(dog).to_not receive(:update_screenboard)
927
+ expect(subject.logger).to receive(:info).with('Created screenboard id1')
928
+ subject.upsert_screenboard('t', [1, 2])
929
+ end
930
+ it 'does nothing if it is up to date' do
931
+ res = [
932
+ '200',
933
+ {
934
+ 'id' => 'id1',
935
+ 'description' => 'created by DogTrainer RubyGem via my_repo_path',
936
+ 'board_title' => 't',
937
+ 'widgets' => [1, 2]
938
+ }
939
+ ]
940
+ dog = double(Dogapi::Client)
941
+ allow(dog).to receive(:create_screenboard).with(any_args)
942
+ allow(dog).to receive(:update_screenboard).with(any_args)
943
+ subject.instance_variable_set('@dog', dog)
944
+ allow(subject).to receive(:get_existing_screenboard_by_name)
945
+ .with(any_args).and_return(res[1])
946
+ allow(subject.logger).to receive(:info).with(any_args)
947
+
948
+ expect(subject).to receive(:get_existing_screenboard_by_name).once
949
+ .with('t')
950
+ expect(dog).to_not receive(:create_screenboard)
951
+ expect(dog).to_not receive(:update_screenboard)
952
+ expect(subject.logger).to receive(:info)
953
+ .with("\tScreenboard is up-to-date")
954
+ subject.upsert_screenboard('t', [1, 2])
955
+ end
956
+ it 'updates if repo_path in description is different' do
957
+ res = [
958
+ '200',
959
+ {
960
+ 'id' => 'id1',
961
+ 'description' => 'created by DogTrainer RubyGem via foo',
962
+ 'board_title' => 't',
963
+ 'widgets' => [1, 2]
964
+ }
965
+ ]
966
+ dog = double(Dogapi::Client)
967
+ allow(dog).to receive(:create_screenboard).with(any_args)
968
+ allow(dog).to receive(:update_screenboard).with(any_args)
969
+ subject.instance_variable_set('@dog', dog)
970
+ allow(subject).to receive(:get_existing_screenboard_by_name)
971
+ .with(any_args).and_return(res[1])
972
+ allow(subject.logger).to receive(:info).with(any_args)
973
+
974
+ expect(subject).to receive(:get_existing_screenboard_by_name).once
975
+ .with('t')
976
+ expect(dog).to_not receive(:create_screenboard)
977
+ expect(dog).to_not receive(:update_screenboard).once
978
+ .with(
979
+ 'id1',
980
+ board_title: 't',
981
+ description: 'created by DogTrainer RubyGem via my_repo_path',
982
+ widgets: [1, 2]
983
+ )
984
+ subject.upsert_screenboard('t', [1, 2])
985
+ end
986
+ it 'updates if title is different' do
987
+ res = [
988
+ '200',
989
+ {
990
+ 'id' => 'id1',
991
+ 'description' => 'created by DogTrainer RubyGem via foo',
992
+ 'board_title' => 'not_t',
993
+ 'widgets' => [1, 2]
994
+ }
995
+ ]
996
+ dog = double(Dogapi::Client)
997
+ allow(dog).to receive(:create_screenboard).with(any_args)
998
+ allow(dog).to receive(:update_screenboard).with(any_args)
999
+ subject.instance_variable_set('@dog', dog)
1000
+ allow(subject).to receive(:get_existing_screenboard_by_name)
1001
+ .with(any_args).and_return(res[1])
1002
+ allow(subject.logger).to receive(:info).with(any_args)
1003
+
1004
+ expect(subject).to receive(:get_existing_screenboard_by_name).once
1005
+ .with('t')
1006
+ expect(dog).to_not receive(:create_screenboard)
1007
+ expect(dog).to_not receive(:update_screenboard).once
1008
+ .with(
1009
+ 'id1',
1010
+ board_title: 't',
1011
+ description: 'created by DogTrainer RubyGem via my_repo_path',
1012
+ widgets: [1, 2]
1013
+ )
1014
+ subject.upsert_screenboard('t', [1, 2])
1015
+ end
1016
+ it 'updates if widgets are different' do
1017
+ res = [
1018
+ '200',
1019
+ {
1020
+ 'id' => 'id1',
1021
+ 'description' => 'created by DogTrainer RubyGem via foo',
1022
+ 'board_title' => 't',
1023
+ 'widgets' => [3, 4]
1024
+ }
1025
+ ]
1026
+ dog = double(Dogapi::Client)
1027
+ allow(dog).to receive(:create_screenboard).with(any_args)
1028
+ allow(dog).to receive(:update_screenboard).with(any_args)
1029
+ subject.instance_variable_set('@dog', dog)
1030
+ allow(subject).to receive(:get_existing_screenboard_by_name)
1031
+ .with(any_args).and_return(res[1])
1032
+ allow(subject.logger).to receive(:info).with(any_args)
1033
+
1034
+ expect(subject).to receive(:get_existing_screenboard_by_name).once
1035
+ .with('t')
1036
+ expect(dog).to_not receive(:create_screenboard)
1037
+ expect(dog).to_not receive(:update_screenboard).once
1038
+ .with(
1039
+ 'id1',
1040
+ board_title: 't',
1041
+ description: 'created by DogTrainer RubyGem via my_repo_path',
1042
+ widgets: [1, 2]
1043
+ )
1044
+ subject.upsert_screenboard('t', [1, 2])
1045
+ end
1046
+ end
1047
+ describe '#get_existing_timeboard_by_name' do
1048
+ it 'retrieves timeboards if they are not cached' do
1049
+ boards = [
1050
+ '200',
1051
+ {
1052
+ 'dashes' => [
1053
+ { 'title' => 'foo', 'id' => 'dash1' },
1054
+ { 'title' => 'bar', 'id' => 'dash2' }
1055
+ ]
1056
+ }
1057
+ ]
1058
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1059
+ dog = double(Dogapi::Client)
1060
+ allow(dog).to receive(:get_dashboards).with(any_args)
1061
+ .and_return(boards)
1062
+ allow(dog).to receive(:get_dashboard).with(any_args).and_return(board)
1063
+ subject.instance_variable_set('@dog', dog)
1064
+
1065
+ expect(dog).to receive(:get_dashboards).once
1066
+ expect(dog).to receive(:get_dashboard).once.with('dash2')
1067
+ expect(subject.get_existing_timeboard_by_name('bar'))
1068
+ .to eq(board[1])
1069
+ expect(subject.instance_variable_get('@timeboards')).to eq(boards)
1070
+ end
1071
+ it 'does not retrieve boards if they are cached' do
1072
+ boards = [
1073
+ '200',
1074
+ {
1075
+ 'dashes' => [
1076
+ { 'title' => 'foo', 'id' => 'dash1' },
1077
+ { 'title' => 'bar', 'id' => 'dash2' }
1078
+ ]
1079
+ }
1080
+ ]
1081
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1082
+ dog = double(Dogapi::Client)
1083
+ allow(dog).to receive(:get_dashboards).with(any_args)
1084
+ .and_return(boards)
1085
+ allow(dog).to receive(:get_dashboard).with(any_args).and_return(board)
1086
+ subject.instance_variable_set('@dog', dog)
1087
+ subject.instance_variable_set('@timeboards', boards)
1088
+
1089
+ expect(dog).to_not receive(:get_dashboards)
1090
+ expect(dog).to receive(:get_dashboard).once.with('dash2')
1091
+ expect(subject.get_existing_timeboard_by_name('bar'))
1092
+ .to eq(board[1])
1093
+ expect(subject.instance_variable_get('@timeboards')).to eq(boards)
1094
+ end
1095
+ it 'returns nil if no matching board can be found' do
1096
+ boards = [
1097
+ '200',
1098
+ {
1099
+ 'dashes' => [
1100
+ { 'title' => 'foo', 'id' => 'dash1' },
1101
+ { 'title' => 'bar', 'id' => 'dash2' }
1102
+ ]
1103
+ }
1104
+ ]
1105
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1106
+ dog = double(Dogapi::Client)
1107
+ allow(dog).to receive(:get_dashboards).with(any_args)
1108
+ .and_return(boards)
1109
+ allow(dog).to receive(:get_dashboard).with(any_args).and_return(board)
1110
+ subject.instance_variable_set('@dog', dog)
1111
+ subject.instance_variable_set('@timeboards', boards)
1112
+
1113
+ expect(dog).to_not receive(:get_dashboards)
1114
+ expect(dog).to_not receive(:get_dashboard)
1115
+ expect(subject.get_existing_timeboard_by_name('blam'))
1116
+ .to be_nil
1117
+ expect(subject.instance_variable_get('@timeboards')).to eq(boards)
1118
+ end
1119
+ it 'exits if no boards can be found' do
1120
+ boards = [
1121
+ '200',
1122
+ {
1123
+ 'dashes' => []
1124
+ }
1125
+ ]
1126
+ dog = double(Dogapi::Client)
1127
+ allow(dog).to receive(:get_dashboards).with(any_args)
1128
+ .and_return(boards)
1129
+ allow(dog).to receive(:get_dashboard).with(any_args)
1130
+ subject.instance_variable_set('@dog', dog)
1131
+
1132
+ expect(dog).to receive(:get_dashboards).once
1133
+ expect(dog).to_not receive(:get_dashboard)
1134
+ expect { subject.get_existing_timeboard_by_name('blam') }
1135
+ .to raise_error(SystemExit)
1136
+ end
1137
+ end
1138
+ describe '#get_existing_screenboard_by_name' do
1139
+ it 'retrieves screenboards if they are not cached' do
1140
+ boards = [
1141
+ '200',
1142
+ {
1143
+ 'screenboards' => [
1144
+ { 'title' => 'foo', 'id' => 'screen1' },
1145
+ { 'title' => 'bar', 'id' => 'screen2' }
1146
+ ]
1147
+ }
1148
+ ]
1149
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1150
+ dog = double(Dogapi::Client)
1151
+ allow(dog).to receive(:get_all_screenboards).with(any_args)
1152
+ .and_return(boards)
1153
+ allow(dog).to receive(:get_screenboard).with(any_args).and_return(board)
1154
+ subject.instance_variable_set('@dog', dog)
1155
+
1156
+ expect(dog).to receive(:get_all_screenboards).once
1157
+ expect(dog).to receive(:get_screenboard).once.with('screen2')
1158
+ expect(subject.get_existing_screenboard_by_name('bar'))
1159
+ .to eq(board[1])
1160
+ expect(subject.instance_variable_get('@screenboards')).to eq(boards)
1161
+ end
1162
+ it 'does not retrieve boards if they are cached' do
1163
+ boards = [
1164
+ '200',
1165
+ {
1166
+ 'screenboards' => [
1167
+ { 'title' => 'foo', 'id' => 'screen1' },
1168
+ { 'title' => 'bar', 'id' => 'screen2' }
1169
+ ]
1170
+ }
1171
+ ]
1172
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1173
+ dog = double(Dogapi::Client)
1174
+ allow(dog).to receive(:get_all_screenboards).with(any_args)
1175
+ .and_return(boards)
1176
+ allow(dog).to receive(:get_screenboard).with(any_args).and_return(board)
1177
+ subject.instance_variable_set('@dog', dog)
1178
+ subject.instance_variable_set('@screenboards', boards)
1179
+
1180
+ expect(dog).to_not receive(:get_all_screenboards)
1181
+ expect(dog).to receive(:get_screenboard).once.with('screen2')
1182
+ expect(subject.get_existing_screenboard_by_name('bar'))
1183
+ .to eq(board[1])
1184
+ expect(subject.instance_variable_get('@screenboards')).to eq(boards)
1185
+ end
1186
+ it 'returns nil if no matching board can be found' do
1187
+ boards = [
1188
+ '200',
1189
+ {
1190
+ 'screenboards' => [
1191
+ { 'title' => 'foo', 'id' => 'screen1' },
1192
+ { 'title' => 'bar', 'id' => 'screen2' }
1193
+ ]
1194
+ }
1195
+ ]
1196
+ board = ['200', { 'foo' => 'bar', 'baz' => 'blam' }]
1197
+ dog = double(Dogapi::Client)
1198
+ allow(dog).to receive(:get_all_screenboards).with(any_args)
1199
+ .and_return(boards)
1200
+ allow(dog).to receive(:get_screenboard).with(any_args).and_return(board)
1201
+ subject.instance_variable_set('@dog', dog)
1202
+ subject.instance_variable_set('@screenboards', boards)
1203
+
1204
+ expect(dog).to_not receive(:get_all_screenboards)
1205
+ expect(dog).to_not receive(:get_screenboard)
1206
+ expect(subject.get_existing_screenboard_by_name('blam'))
1207
+ .to be_nil
1208
+ expect(subject.instance_variable_get('@screenboards')).to eq(boards)
1209
+ end
1210
+ it 'exits if no boards can be found' do
1211
+ boards = [
1212
+ '200',
1213
+ {
1214
+ 'screenboards' => []
1215
+ }
1216
+ ]
1217
+ dog = double(Dogapi::Client)
1218
+ allow(dog).to receive(:get_all_screenboards).with(any_args)
1219
+ .and_return(boards)
1220
+ allow(dog).to receive(:get_screenboard).with(any_args)
1221
+ subject.instance_variable_set('@dog', dog)
1222
+
1223
+ expect(dog).to receive(:get_all_screenboards).once
1224
+ expect(dog).to_not receive(:get_screenboard)
1225
+ expect { subject.get_existing_screenboard_by_name('blam') }
1226
+ .to raise_error(SystemExit)
1227
+ end
1228
+ end
1229
+ end