dogtrainer 0.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.
@@ -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