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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +37 -0
- data/.github/workflows/test.yml +23 -0
- data/.rubocop.yml +10 -6
- data/HISTORY.md +21 -1
- data/lib/wavefront-cli/base.rb +3 -0
- data/lib/wavefront-cli/commands/.rubocop.yml +2 -13
- data/lib/wavefront-cli/commands/event.rb +8 -6
- data/lib/wavefront-cli/commands/serviceaccount.rb +6 -4
- data/lib/wavefront-cli/controller.rb +9 -0
- data/lib/wavefront-cli/display/base.rb +3 -2
- data/lib/wavefront-cli/display/printer/sparkline.rb +1 -1
- data/lib/wavefront-cli/display/serviceaccount.rb +12 -4
- data/lib/wavefront-cli/event.rb +50 -166
- data/lib/wavefront-cli/event_store.rb +177 -0
- data/lib/wavefront-cli/exception.rb +21 -0
- data/lib/wavefront-cli/exception_handler.rb +4 -0
- data/lib/wavefront-cli/opt_handler.rb +1 -1
- data/lib/wavefront-cli/query.rb +1 -1
- data/lib/wavefront-cli/serviceaccount.rb +16 -6
- data/lib/wavefront-cli/settings.rb +3 -4
- data/lib/wavefront-cli/stdlib/string.rb +1 -1
- data/lib/wavefront-cli/version.rb +1 -1
- data/lib/wavefront-cli/write.rb +1 -1
- data/spec/.rubocop.yml +2 -17
- data/spec/spec_helper.rb +0 -1
- data/spec/support/minitest_assertions.rb +2 -2
- data/spec/wavefront-cli/commands/base_spec.rb +2 -2
- data/spec/wavefront-cli/commands/config_spec.rb +1 -1
- data/spec/wavefront-cli/controller_spec.rb +14 -0
- data/spec/wavefront-cli/event_spec.rb +69 -109
- data/spec/wavefront-cli/event_store_spec.rb +186 -0
- data/spec/wavefront-cli/opt_handler_spec.rb +3 -3
- data/spec/wavefront-cli/serviceaccount_spec.rb +53 -21
- data/wavefront-cli.gemspec +5 -2
- metadata +62 -10
- 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::
|
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
|
-
"
|
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
|
216
|
-
|
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
|
-
|
219
|
-
|
220
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
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
|
250
|
-
|
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
|
-
|
355
|
-
|
356
|
-
def
|
357
|
-
|
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
|