wavefront-cli 8.3.0 → 8.5.1

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +37 -0
  3. data/.github/workflows/test.yml +23 -0
  4. data/.rubocop.yml +10 -6
  5. data/HISTORY.md +21 -1
  6. data/lib/wavefront-cli/base.rb +3 -0
  7. data/lib/wavefront-cli/commands/.rubocop.yml +2 -13
  8. data/lib/wavefront-cli/commands/event.rb +8 -6
  9. data/lib/wavefront-cli/commands/serviceaccount.rb +6 -4
  10. data/lib/wavefront-cli/controller.rb +9 -0
  11. data/lib/wavefront-cli/display/base.rb +3 -2
  12. data/lib/wavefront-cli/display/printer/sparkline.rb +1 -1
  13. data/lib/wavefront-cli/display/serviceaccount.rb +12 -4
  14. data/lib/wavefront-cli/event.rb +50 -166
  15. data/lib/wavefront-cli/event_store.rb +177 -0
  16. data/lib/wavefront-cli/exception.rb +21 -0
  17. data/lib/wavefront-cli/exception_handler.rb +4 -0
  18. data/lib/wavefront-cli/opt_handler.rb +1 -1
  19. data/lib/wavefront-cli/query.rb +1 -1
  20. data/lib/wavefront-cli/serviceaccount.rb +16 -6
  21. data/lib/wavefront-cli/settings.rb +3 -4
  22. data/lib/wavefront-cli/stdlib/string.rb +1 -1
  23. data/lib/wavefront-cli/version.rb +1 -1
  24. data/lib/wavefront-cli/write.rb +1 -1
  25. data/spec/.rubocop.yml +2 -17
  26. data/spec/spec_helper.rb +0 -1
  27. data/spec/support/minitest_assertions.rb +2 -2
  28. data/spec/wavefront-cli/commands/base_spec.rb +2 -2
  29. data/spec/wavefront-cli/commands/config_spec.rb +1 -1
  30. data/spec/wavefront-cli/controller_spec.rb +14 -0
  31. data/spec/wavefront-cli/event_spec.rb +69 -109
  32. data/spec/wavefront-cli/event_store_spec.rb +186 -0
  33. data/spec/wavefront-cli/opt_handler_spec.rb +3 -3
  34. data/spec/wavefront-cli/serviceaccount_spec.rb +53 -21
  35. data/wavefront-cli.gemspec +5 -2
  36. metadata +62 -10
  37. data/.travis.yml +0 -20
@@ -22,6 +22,18 @@ class WavefrontCliHelpTest < MiniTest::Test
22
22
  assert_match(/^ \w+ --help$/, e.message)
23
23
  end
24
24
 
25
+ def test_commands_no_args
26
+ SupportedCommands.new.all.each do |cmd|
27
+ _test_command_no_args(cmd)
28
+ end
29
+ end
30
+
31
+ def _test_command_no_args(cmd)
32
+ capture_io { WavefrontCliController.new([cmd]) }
33
+ rescue SystemExit => e
34
+ assert e.message.end_with?("wf #{cmd} --help")
35
+ end
36
+
25
37
  def test_version
26
38
  capture_io { WavefrontCliController.new(%w[--version]) }
27
39
  rescue SystemExit => e
@@ -40,6 +52,7 @@ class WavefrontCliHelpTest < MiniTest::Test
40
52
  end
41
53
  end
42
54
 
55
+ # rubocop:disable Style/RedundantBegin
43
56
  def test_command_help
44
57
  SupportedCommands.new.all.each do |cmd|
45
58
  begin
@@ -54,6 +67,7 @@ class WavefrontCliHelpTest < MiniTest::Test
54
67
  end
55
68
  end
56
69
  end
70
+ # rubocop:enable Style/RedundantBegin
57
71
 
58
72
  def test_malformed_config
59
73
  capture_io do
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'tmpdir'
5
5
  require_relative '../support/command_base'
6
+ require_relative '../test_mixins/tag'
6
7
  require_relative '../../lib/wavefront-cli/event'
7
8
  require 'wavefront-sdk/support/mixins'
8
9
 
@@ -15,12 +16,11 @@ class EventEndToEndTest < EndToEndTest
15
16
  attr_reader :test_state_dir
16
17
 
17
18
  include Wavefront::Mixins
18
- include WavefrontCliTest::Describe
19
- include WavefrontCliTest::Delete
20
- # Ones above work, ones below don't
19
+ # include WavefrontCliTest::Describe
20
+ # include WavefrontCliTest::Delete
21
21
  # include WavefrontCliTest::Search
22
- # include WavefrontCliTest::Set
23
- # include WavefrontCliTest::Tags
22
+ # #include WavefrontCliTest::Set
23
+ # include WavefrontCliTest::Tag
24
24
 
25
25
  def before_setup
26
26
  @test_state_dir = Pathname.new(Dir.mktmpdir)
@@ -31,11 +31,6 @@ class EventEndToEndTest < EndToEndTest
31
31
  FileUtils.rm_r(test_state_dir)
32
32
  end
33
33
 
34
- def cmd_instance
35
- cmd_class.new(event_state_dir: TEST_EVENT_DIR)
36
- puts cmd_class
37
- end
38
-
39
34
  def test_list_no_options
40
35
  str = '/api/v2/event\?' \
41
36
  'earliestStartTimeEpochMillis=\d{13}+&' \
@@ -65,6 +60,22 @@ class EventEndToEndTest < EndToEndTest
65
60
  end
66
61
  end
67
62
 
63
+ def test_show_with_no_local_events
64
+ assert_exits_with('No locally recorded events.', 'show')
65
+ end
66
+
67
+ def test_show
68
+ setup_test_state_dir
69
+
70
+ out, err = capture_io do
71
+ assert_raises(SystemExit) { wf.new("event show -c #{CF}".split) }
72
+ end
73
+
74
+ assert_empty(err)
75
+ assert_equal("1568133440530:ev3:0\n1568133440520:ev2:0\n" \
76
+ "1568133440515:ev1:1\n1568133440510:ev1:0\n", out)
77
+ end
78
+
68
79
  def test_create
69
80
  mock_id = "#{start_time}:#{event_name}:1"
70
81
  state_file = state_dir + mock_id
@@ -100,8 +111,8 @@ class EventEndToEndTest < EndToEndTest
100
111
  refute state_file.exist?
101
112
 
102
113
  out, err = capture_io do
103
- assert_cmd_posts('create -d reason -H host1 -H host2 -g ' \
104
- "mytag #{event_name}",
114
+ assert_cmd_posts('create -d reason -H host1 -H host2 -g mytag ' \
115
+ "#{event_name}",
105
116
  '/api/v2/event',
106
117
  { name: event_name,
107
118
  startTime: a_ms_timestamp,
@@ -148,15 +159,6 @@ class EventEndToEndTest < EndToEndTest
148
159
  assert_match(/\ntags tag1\n tag2\n/, out)
149
160
  end
150
161
 
151
- def test_close_named_event
152
- quietly do
153
- assert_cmd_posts('close 1568133440520:ev2:0',
154
- '/api/v2/event/1568133440520:ev2:0/close')
155
- end
156
-
157
- assert_abort_on_missing_creds("close #{id}")
158
- end
159
-
160
162
  def test_close_with_no_local_events
161
163
  quietly { assert_cmd_posts("close #{id}", "/api/v2/event/#{id}/close") }
162
164
  assert_exits_with('No locally recorded events.', 'close')
@@ -212,26 +214,47 @@ class EventEndToEndTest < EndToEndTest
212
214
  end
213
215
  end
214
216
 
215
- def test_show
216
- setup_test_state_dir
217
+ def test_window_start
218
+ wfse = WavefrontCli::Event.new(start: wall_time[0], end: wall_time[1])
219
+ assert_kind_of(Numeric, wfse.window_start)
220
+ assert_equal(epoch_ms_time[0], wfse.window_start)
221
+ end
217
222
 
218
- out, err = capture_io do
219
- assert_raises(SystemExit) { wf.new("event show -c #{CF}".split) }
220
- end
223
+ def test_window_end
224
+ wfse = WavefrontCli::Event.new(start: wall_time[0], end: wall_time[1])
225
+ assert_kind_of(Numeric, wfse.window_end)
226
+ assert_equal(epoch_ms_time[1], wfse.window_end)
227
+ end
221
228
 
222
- assert_empty(err)
223
- assert_equal("1568133440530:ev3:0\n1568133440520:ev2:0\n" \
224
- "1568133440515:ev1:1\n1568133440510:ev1:0\n", out)
229
+ def test_list_args_defaults
230
+ wfe = WavefrontCli::Event.new({})
231
+ x = wfe.list_args
232
+ assert_instance_of(Array, x)
233
+ assert_equal(4, x.size)
234
+ assert_in_delta(((Time.now - 600).to_i * 1000), x[0], 1000)
235
+ assert_in_delta((Time.now.to_i * 1000), x[1], 1000)
236
+ assert_equal(100, x[2])
237
+ assert_nil(x[3])
238
+ end
239
+
240
+ def test_list_args_options
241
+ wfse = WavefrontCli::Event.new(limit: 55,
242
+ start: wall_time[0],
243
+ cursor: id,
244
+ end: wall_time[1])
245
+ x = wfse.list_args
246
+ assert_instance_of(Array, x)
247
+ assert_equal(4, x.size)
248
+ assert_equal(epoch_ms_time[0], x[0])
249
+ assert_equal(epoch_ms_time[1], x[1])
250
+ assert_equal(55, x[2])
251
+ assert_equal(id, x[3])
225
252
  end
226
253
 
227
254
  private
228
255
 
229
256
  def id
230
- '1481553823153:testev'
231
- end
232
-
233
- def event_name
234
- 'test_event'
257
+ '1481553823153:testev:0'
235
258
  end
236
259
 
237
260
  def invalid_id
@@ -242,18 +265,24 @@ class EventEndToEndTest < EndToEndTest
242
265
  'event'
243
266
  end
244
267
 
268
+ def event_name
269
+ 'test_event'
270
+ end
271
+
245
272
  def start_time
246
273
  1_481_553_823_153
247
274
  end
248
275
 
249
- def import_fields
250
- %i[method title creatorId triggers template]
276
+ def epoch_ms_time
277
+ wall_time.map { |t| (t.to_i * 1000) }
251
278
  end
252
279
 
253
280
  def state_dir
254
281
  test_state_dir + (Etc.getlogin || 'notty')
255
282
  end
256
283
 
284
+ # Puts some test events in the state directory
285
+ #
257
286
  def setup_test_state_dir
258
287
  FileUtils.mkdir_p(state_dir)
259
288
 
@@ -285,79 +314,10 @@ class EventEndToEndTest < EndToEndTest
285
314
  "https://#{perm[:endpoint]}/api/v2/event/#{mock_id}/close")
286
315
  .with(body: 'null')
287
316
  end
288
- end
289
-
290
- # Unit tests for class methods
291
- #
292
- class EventMethodTests < Minitest::Test
293
- attr_reader :wf, :wfse
294
-
295
- def setup
296
- @wf = WavefrontCli::Event.new({})
297
- @wfse = WavefrontCli::Event.new(start: wall_time[0],
298
- end: wall_time[1],
299
- limit: 55,
300
- cursor: '1481553823153:testev')
301
- end
302
-
303
- def test_create_dir_ok
304
- base = Pathname.new(Dir.mktmpdir)
305
- dir = base + 'testdir'
306
- refute dir.exist?
307
- wf.create_dir(dir)
308
- assert dir.exist?
309
- dir.unlink
310
- base.unlink
311
- end
312
-
313
- def test_create_dir_fail
314
- spy = Spy.on(FileUtils, :mkdir_p).and_return(false)
315
-
316
- assert_raises(WavefrontCli::Exception::SystemError) do
317
- wf.create_dir(Pathname.new('/any/old/directory'))
318
- end
319
-
320
- assert spy.has_been_called?
321
- spy.unhook
322
- end
323
-
324
- def test_list_args_defaults
325
- x = wf.list_args
326
- assert_instance_of(Array, x)
327
- assert_equal(4, x.size)
328
- assert_in_delta(((Time.now - 600).to_i * 1000), x[0], 1000)
329
- assert_in_delta((Time.now.to_i * 1000), x[1], 1000)
330
- assert_equal(100, x[2])
331
- assert_nil(x[3])
332
- end
333
-
334
- def test_list_args_options
335
- x = wfse.list_args
336
- assert_instance_of(Array, x)
337
- assert_equal(4, x.size)
338
- assert_equal(epoch_ms_time[0], x[0])
339
- assert_equal(epoch_ms_time[1], x[1])
340
- assert_equal(55, x[2])
341
- assert_equal('1481553823153:testev', x[3])
342
- end
343
-
344
- def test_window_start
345
- assert_kind_of(Numeric, wf.window_start)
346
- assert_equal(epoch_ms_time[0], wfse.window_start)
347
- end
348
-
349
- def test_window_end
350
- assert_kind_of(Numeric, wf.window_end)
351
- assert_equal(epoch_ms_time[1], wfse.window_end)
352
- end
353
317
 
354
- private
355
-
356
- def wall_time
357
- [Time.at(1_568_112_000), Time.at(1_568_112_999)]
358
- end
359
-
360
- def epoch_ms_time
361
- wall_time.map { |t| (t.to_i * 1000) }
318
+ # Event searching uses a cursor, not an offset
319
+ #
320
+ def cannot_handle_offsets
321
+ true
362
322
  end
363
323
  end
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'pathname'
5
+ require 'spy'
6
+ require 'minitest/autorun'
7
+ require_relative '../../lib/wavefront-cli/event_store'
8
+
9
+ TEST_EVENT_STORE_DIR = Pathname.new(Dir.mktmpdir)
10
+
11
+ # Tests for event store class. This is tested well via the interface of the
12
+ # events CLI class.
13
+ #
14
+ class Test < MiniTest::Test
15
+ attr_reader :wf
16
+
17
+ include WavefrontCli::Constants
18
+
19
+ def before_setup
20
+ FileUtils.mkdir_p(TEST_EVENT_STORE_DIR)
21
+ end
22
+
23
+ def setup
24
+ @wf = WavefrontCli::EventStore.new({}, TEST_EVENT_STORE_DIR)
25
+ end
26
+
27
+ def teardown
28
+ FileUtils.rm_r(TEST_EVENT_STORE_DIR)
29
+ end
30
+
31
+ def test_state_file_needed?
32
+ wf1 = WavefrontCli::EventStore.new({}, TEST_EVENT_STORE_DIR)
33
+ assert wf1.state_file_needed?
34
+
35
+ wf2 = WavefrontCli::EventStore.new({ nostate: true }, TEST_EVENT_STORE_DIR)
36
+ refute wf2.state_file_needed?
37
+
38
+ wf3 = WavefrontCli::EventStore.new({ instant: true }, TEST_EVENT_STORE_DIR)
39
+ refute wf3.state_file_needed?
40
+
41
+ wf4 = WavefrontCli::EventStore.new({ start: Time.now - 20, end: Time.now },
42
+ TEST_EVENT_STORE_DIR)
43
+ refute wf4.state_file_needed?
44
+ end
45
+
46
+ def test_event_file
47
+ x = wf.event_file(id)
48
+ assert_instance_of(Pathname, x)
49
+ assert_equal(wf.dir, x.dirname)
50
+ assert_equal(id, x.basename.to_s)
51
+
52
+ assert_nil(wf.event_file('not_a_valid_id'))
53
+ end
54
+
55
+ def test_create_dir_ok
56
+ dir = TEST_EVENT_STORE_DIR + 'testdir'
57
+ refute dir.exist?
58
+ wf.create_dir(dir)
59
+ assert dir.exist?
60
+ dir.unlink
61
+ end
62
+
63
+ def test_list
64
+ setup_test_state_dir
65
+
66
+ x = wf.list
67
+ assert(x.all? { |e| e.is_a?(Pathname) })
68
+ assert_equal(4, x.size)
69
+
70
+ empty_test_state_dir
71
+ end
72
+
73
+ def test_list_empty_stack
74
+ out, err = capture_io { assert_raises(SystemExit) { wf.list } }
75
+ assert_empty(out)
76
+ assert_equal("No locally recorded events.\n", err)
77
+ end
78
+
79
+ def test_pop_event
80
+ setup_test_state_dir
81
+
82
+ assert (wf.dir + '1568133440530:ev3:0').exist?
83
+ assert_equal('1568133440530:ev3:0', wf.pop_event!)
84
+ refute (wf.dir + '1568133440530:ev3:0').exist?
85
+
86
+ empty_test_state_dir
87
+ end
88
+
89
+ def test_pop_event_named
90
+ setup_test_state_dir
91
+
92
+ assert (wf.dir + '1568133440515:ev1:1').exist?
93
+ assert_equal('1568133440515:ev1:1', wf.pop_event!('ev1'))
94
+ refute (wf.dir + '1568133440515:ev1:1').exist?
95
+
96
+ empty_test_state_dir
97
+ end
98
+
99
+ def test_event_specific
100
+ setup_test_state_dir
101
+
102
+ assert (wf.dir + '1568133440515:ev1:1').exist?
103
+ assert_equal('1568133440515:ev1:1', wf.event('1568133440515:ev1:1'))
104
+ assert (wf.dir + '1568133440515:ev1:1').exist?
105
+
106
+ empty_test_state_dir
107
+ end
108
+
109
+ def test_pop_event_empty_stack
110
+ out, err = capture_io { assert_raises(SystemExit) { wf.pop_event! } }
111
+ assert_empty(out)
112
+ assert_equal("No locally recorded events.\n", err)
113
+ end
114
+
115
+ def test_event_state_dir
116
+ ENV['WF_EVENT_STATE_DIR'] = nil
117
+ assert_equal(EVENT_STATE_DIR, wf.event_state_dir)
118
+
119
+ ENV['WF_EVENT_STATE_DIR'] = '/tmp/tester'
120
+ assert_equal(Pathname.new('/tmp/tester'), wf.event_state_dir)
121
+ ENV['WF_EVENT_STATE_DIR'] = nil
122
+
123
+ assert_equal(Pathname.new('/tmp/mydir'), wf.event_state_dir('/tmp/mydir'))
124
+ end
125
+
126
+ def test_create_dir_fail
127
+ spy = Spy.on(FileUtils, :mkdir_p).and_return(false)
128
+
129
+ assert_raises(WavefrontCli::Exception::SystemError) do
130
+ wf.create_dir(Pathname.new('/any/old/directory'))
131
+ end
132
+
133
+ assert spy.has_been_called?
134
+ spy.unhook
135
+ end
136
+
137
+ def test_event_file_data
138
+ wf = WavefrontCli::EventStore.new({ desc: 'test event' },
139
+ TEST_EVENT_STORE_DIR)
140
+ x = wf.event_file_data
141
+ assert_instance_of(String, x)
142
+ y = JSON.parse(x, symbolize_names: true)
143
+ assert_equal('test event', y[:description])
144
+ assert_equal(%i[hosts description severity tags], y.keys)
145
+ assert_nil(y[:tags])
146
+ end
147
+
148
+ def test_create
149
+ refute (wf.dir + id).exist?
150
+ out, err = capture_io { wf.create!(id) }
151
+ assert_match(/Event state recorded at .*1481553823153:testev:0./, out)
152
+ assert_empty(err)
153
+ assert (wf.dir + id).exist?
154
+ end
155
+
156
+ def test_create_with_nostate
157
+ wf1 = WavefrontCli::EventStore.new(nostate: true)
158
+ assert_nil wf1.create!(id)
159
+ end
160
+
161
+ private
162
+
163
+ def id
164
+ '1481553823153:testev:0'
165
+ end
166
+
167
+ def dummy_event_files
168
+ %w[1568133440510:ev1:0
169
+ 1568133440515:ev1:1
170
+ 1568133440520:ev2:0
171
+ 1568133440530:ev3:0]
172
+ end
173
+
174
+ def setup_test_state_dir
175
+ dummy_event_files.each do |f|
176
+ File.open(wf.dir + f, 'w') { |fh| fh.puts('dummy_data') }
177
+ end
178
+ end
179
+
180
+ def empty_test_state_dir
181
+ dummy_event_files.each do |f|
182
+ file = wf.dir + f
183
+ FileUtils.rm(file) if file.exist?
184
+ end
185
+ end
186
+ end