wavefront-cli 8.5.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +37 -0
- data/.github/workflows/test.yml +23 -0
- data/.rubocop.yml +10 -9
- data/HISTORY.md +15 -0
- data/README.md +4 -2
- data/lib/wavefront-cli/base.rb +2 -2
- data/lib/wavefront-cli/commands/.rubocop.yml +2 -13
- data/lib/wavefront-cli/commands/base.rb +10 -9
- data/lib/wavefront-cli/commands/derivedmetric.rb +1 -1
- data/lib/wavefront-cli/commands/metric.rb +3 -3
- data/lib/wavefront-cli/commands/metricspolicy.rb +33 -0
- data/lib/wavefront-cli/commands/query.rb +5 -5
- data/lib/wavefront-cli/commands/write.rb +12 -12
- data/lib/wavefront-cli/config.rb +4 -4
- data/lib/wavefront-cli/constants.rb +2 -1
- data/lib/wavefront-cli/controller.rb +19 -15
- data/lib/wavefront-cli/display/base.rb +3 -2
- data/lib/wavefront-cli/display/metricspolicy.rb +15 -0
- data/lib/wavefront-cli/display/printer/long.rb +11 -13
- data/lib/wavefront-cli/display/printer/sparkline.rb +3 -3
- data/lib/wavefront-cli/display/query.rb +1 -1
- data/lib/wavefront-cli/display/write.rb +2 -1
- data/lib/wavefront-cli/event.rb +2 -2
- data/lib/wavefront-cli/event_store.rb +2 -2
- data/lib/wavefront-cli/exception.rb +21 -0
- data/lib/wavefront-cli/exception_handler.rb +8 -1
- data/lib/wavefront-cli/helpers/load_file.rb +2 -2
- data/lib/wavefront-cli/maintenancewindow.rb +1 -1
- data/lib/wavefront-cli/metricspolicy.rb +42 -0
- data/lib/wavefront-cli/opt_handler.rb +3 -4
- data/lib/wavefront-cli/output/csv/query.rb +2 -2
- data/lib/wavefront-cli/output/hcl/dashboard.rb +6 -6
- data/lib/wavefront-cli/output/hcl/stdlib/array.rb +1 -1
- data/lib/wavefront-cli/output/wavefront/query.rb +7 -7
- data/lib/wavefront-cli/query.rb +1 -1
- data/lib/wavefront-cli/settings.rb +3 -4
- data/lib/wavefront-cli/stdlib/string.rb +5 -5
- data/lib/wavefront-cli/usage.rb +1 -1
- data/lib/wavefront-cli/version.rb +1 -1
- data/lib/wavefront-cli/write.rb +14 -18
- data/spec/.rubocop.yml +2 -17
- data/spec/constants.rb +4 -5
- data/spec/support/command_base.rb +12 -0
- data/spec/support/minitest_assertions.rb +15 -11
- data/spec/support/output_tester.rb +2 -2
- data/spec/support/supported_commands.rb +3 -1
- data/spec/test_mixins/import.rb +2 -2
- data/spec/test_mixins/search.rb +9 -7
- data/spec/test_mixins/set.rb +1 -1
- data/spec/wavefront-cli/account_spec.rb +6 -4
- data/spec/wavefront-cli/alert_spec.rb +29 -6
- data/spec/wavefront-cli/commands/base_spec.rb +4 -4
- data/spec/wavefront-cli/commands/config_spec.rb +3 -3
- data/spec/wavefront-cli/config_spec.rb +3 -3
- data/spec/wavefront-cli/controller_spec.rb +4 -0
- data/spec/wavefront-cli/dashboard_spec.rb +1 -1
- data/spec/wavefront-cli/derivedmetric_spec.rb +9 -7
- data/spec/wavefront-cli/display/printer/long_spec.rb +5 -3
- data/spec/wavefront-cli/display/printer/terse_spec.rb +1 -1
- data/spec/wavefront-cli/event_spec.rb +14 -11
- data/spec/wavefront-cli/event_store_spec.rb +16 -12
- data/spec/wavefront-cli/externallink_spec.rb +5 -3
- data/spec/wavefront-cli/maintenancewindow_spec.rb +25 -19
- data/spec/wavefront-cli/message_spec.rb +3 -3
- data/spec/wavefront-cli/metricspolicy_spec.rb +30 -0
- data/spec/wavefront-cli/opt_handler_spec.rb +4 -4
- data/spec/wavefront-cli/output/helpers.rb +1 -1
- data/spec/wavefront-cli/proxy_spec.rb +1 -1
- data/spec/wavefront-cli/query_spec.rb +1 -1
- data/spec/wavefront-cli/role_spec.rb +4 -3
- data/spec/wavefront-cli/serviceaccount_spec.rb +7 -7
- data/spec/wavefront-cli/stdlib/string_spec.rb +3 -1
- data/spec/wavefront-cli/usage_spec.rb +1 -1
- data/spec/wavefront-cli/{write_spec.rb → write_class_spec.rb} +1 -14
- data/wavefront-cli.gemspec +13 -12
- metadata +72 -146
- data/.travis.yml +0 -20
- data/spec/spec_helper.rb +0 -113
data/lib/wavefront-cli/event.rb
CHANGED
@@ -38,7 +38,7 @@ module WavefrontCli
|
|
38
38
|
def do_show
|
39
39
|
events = state.list
|
40
40
|
|
41
|
-
if events.
|
41
|
+
if events.empty?
|
42
42
|
puts 'No open events.'
|
43
43
|
else
|
44
44
|
events.sort.reverse_each { |e| puts e.basename }
|
@@ -94,7 +94,7 @@ module WavefrontCli
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def window_start
|
97
|
-
parse_time((options[:start] || Time.now - 600), true)
|
97
|
+
parse_time((options[:start] || (Time.now - 600)), true)
|
98
98
|
end
|
99
99
|
|
100
100
|
def window_end
|
@@ -41,7 +41,7 @@ module WavefrontCli
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def event_file(id)
|
44
|
-
|
44
|
+
/^\d{13}:.+/.match?(id) ? dir + id : nil
|
45
45
|
end
|
46
46
|
|
47
47
|
# We can override the temp directory with the WF_EVENT_STATE_DIR env var.
|
@@ -70,7 +70,7 @@ module WavefrontCli
|
|
70
70
|
def event(id)
|
71
71
|
if !id
|
72
72
|
pop_event!
|
73
|
-
elsif
|
73
|
+
elsif /^\d{13}:.+:\d+/.match?(id)
|
74
74
|
id
|
75
75
|
else
|
76
76
|
pop_event!(id)
|
@@ -7,26 +7,47 @@ module WavefrontCli
|
|
7
7
|
#
|
8
8
|
class Exception
|
9
9
|
class CredentialError < RuntimeError; end
|
10
|
+
|
10
11
|
class MandatoryValue < RuntimeError; end
|
12
|
+
|
11
13
|
class ConfigFileNotFound < IOError; end
|
14
|
+
|
12
15
|
class FileNotFound < IOError; end
|
16
|
+
|
13
17
|
class ImpossibleSearch < RuntimeError; end
|
18
|
+
|
14
19
|
class InsufficientData < RuntimeError; end
|
20
|
+
|
15
21
|
class InvalidInput < RuntimeError; end
|
22
|
+
|
16
23
|
class InvalidQuery < RuntimeError; end
|
24
|
+
|
17
25
|
class InvalidValue < RuntimeError; end
|
26
|
+
|
18
27
|
class ProfileExists < RuntimeError; end
|
28
|
+
|
19
29
|
class ProfileNotFound < RuntimeError; end
|
30
|
+
|
20
31
|
class SystemError < RuntimeError; end
|
32
|
+
|
21
33
|
class UnhandledCommand < RuntimeError; end
|
34
|
+
|
22
35
|
class UnparseableInput < RuntimeError; end
|
36
|
+
|
23
37
|
class UnparseableResponse < RuntimeError; end
|
38
|
+
|
24
39
|
class UnparseableSearchPattern < RuntimeError; end
|
40
|
+
|
25
41
|
class UnsupportedFileFormat < RuntimeError; end
|
42
|
+
|
26
43
|
class UnsupportedNoop < RuntimeError; end
|
44
|
+
|
27
45
|
class UnsupportedOperation < RuntimeError; end
|
46
|
+
|
28
47
|
class UnsupportedOutput < RuntimeError; end
|
48
|
+
|
29
49
|
class UserGroupNotFound < RuntimeError; end
|
50
|
+
|
30
51
|
class UserError < RuntimeError; end
|
31
52
|
end
|
32
53
|
end
|
@@ -8,6 +8,7 @@ module WavefrontCli
|
|
8
8
|
# rubocop:disable Metrics/MethodLength
|
9
9
|
# rubocop:disable Metrics/AbcSize
|
10
10
|
# rubocop:disable Metrics/CyclomaticComplexity
|
11
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
11
12
|
def exception_handler(exception)
|
12
13
|
case exception
|
13
14
|
when WavefrontCli::Exception::UnhandledCommand
|
@@ -18,7 +19,8 @@ module WavefrontCli
|
|
18
19
|
abort "\nOperation aborted at user request."
|
19
20
|
when WavefrontCli::Exception::ConfigFileNotFound
|
20
21
|
abort "Configuration file #{exception}' not found."
|
21
|
-
when WavefrontCli::Exception::CredentialError
|
22
|
+
when WavefrontCli::Exception::CredentialError,
|
23
|
+
Wavefront::Exception::CredentialError
|
22
24
|
handle_missing_credentials(exception)
|
23
25
|
when WavefrontCli::Exception::MandatoryValue
|
24
26
|
abort 'A value must be supplied.'
|
@@ -26,6 +28,8 @@ module WavefrontCli
|
|
26
28
|
abort 'Connection timed out.'
|
27
29
|
when Wavefront::Exception::InvalidPermission
|
28
30
|
abort "'#{exception}' is not a valid Wavefront permission."
|
31
|
+
when Wavefront::Exception::InvalidTimestamp
|
32
|
+
abort "'#{exception}' is not a parseable time."
|
29
33
|
when Wavefront::Exception::InvalidUserGroupId
|
30
34
|
abort "'#{exception}' is not a valid user group ID."
|
31
35
|
when Wavefront::Exception::InvalidAccountId
|
@@ -38,6 +42,8 @@ module WavefrontCli
|
|
38
42
|
abort "'#{exception}' is not a valid API token ID."
|
39
43
|
when Wavefront::Exception::InvalidIngestionPolicyId
|
40
44
|
abort "'#{exception}' is not a valid ingestion policy ID."
|
45
|
+
when Wavefront::Exception::InvalidVersion
|
46
|
+
abort "'#{exception}' is not a valid version."
|
41
47
|
when WavefrontCli::Exception::InvalidValue
|
42
48
|
abort "Invalid value for #{exception}."
|
43
49
|
when WavefrontCli::Exception::ProfileExists
|
@@ -80,6 +86,7 @@ module WavefrontCli
|
|
80
86
|
abort
|
81
87
|
end
|
82
88
|
end
|
89
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
83
90
|
# rubocop:enable Metrics/MethodLength
|
84
91
|
# rubocop:enable Metrics/AbcSize
|
85
92
|
# rubocop:enable Metrics/CyclomaticComplexity
|
@@ -40,11 +40,11 @@ module WavefrontCli
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def load_json(file)
|
43
|
-
read_json(
|
43
|
+
read_json(File.read(file))
|
44
44
|
end
|
45
45
|
|
46
46
|
def load_yaml(file)
|
47
|
-
read_yaml(
|
47
|
+
read_yaml(File.read(file))
|
48
48
|
end
|
49
49
|
|
50
50
|
# Read STDIN and return a Ruby object, assuming that STDIN is
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'wavefront-sdk/support/mixins'
|
4
|
+
require_relative 'base'
|
5
|
+
require_relative 'helpers/load_file'
|
6
|
+
|
7
|
+
module WavefrontCli
|
8
|
+
#
|
9
|
+
# CLI coverage for the metricspolicy part of the v2 'usage' API.
|
10
|
+
#
|
11
|
+
class MetricsPolicy < WavefrontCli::Base
|
12
|
+
def do_describe
|
13
|
+
wf.describe(options[:version])
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_history
|
17
|
+
wf.history(options[:offset] || 0, options[:limit] || 100)
|
18
|
+
end
|
19
|
+
|
20
|
+
def do_revert
|
21
|
+
wf.revert(options[:'<version>'])
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_update
|
25
|
+
raw = WavefrontCli::Helper::LoadFile.new(options[:'<file>']).load
|
26
|
+
rules = process_update(raw)
|
27
|
+
wf.update(policyRules: rules)
|
28
|
+
end
|
29
|
+
|
30
|
+
# It looks like the API expects arrays of ID strings for accounts, groups,
|
31
|
+
# and roles, but when you export one, those fields are objects with name
|
32
|
+
# and ID.
|
33
|
+
#
|
34
|
+
def process_update(raw)
|
35
|
+
raw[:policyRules].tap do |rule|
|
36
|
+
rule[:accounts] = rule[:accounts].map { |r| r[:id] }
|
37
|
+
rule[:userGroups] = rule[:userGroups].map { |r| r[:id] }
|
38
|
+
rule[:roles] = rule[:roles].map { |r| r[:id] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -29,7 +29,7 @@ module WavefrontCli
|
|
29
29
|
|
30
30
|
def initialize(cli_opts = {})
|
31
31
|
cred_opts = setup_cred_opts(cli_opts)
|
32
|
-
cli_opts.
|
32
|
+
cli_opts.compact!
|
33
33
|
@opts = DEFAULT_OPTS.merge(load_profile(cred_opts)).merge(cli_opts)
|
34
34
|
rescue WavefrontCli::Exception::ConfigFileNotFound => e
|
35
35
|
abort "Configuration file '#{e}' not found."
|
@@ -43,11 +43,10 @@ module WavefrontCli
|
|
43
43
|
# constructor.
|
44
44
|
# @param cli_opts [Hash] options from docopt, which may include
|
45
45
|
# the location of the config file and the stanza within it
|
46
|
-
# @return [Hash] keys are none, one, or both of :file and
|
47
|
-
# :profile
|
46
|
+
# @return [Hash] keys are none, one, or both of :file and :profile
|
48
47
|
#
|
49
48
|
def setup_cred_opts(cli_opts)
|
50
|
-
cred_opts = { raise_on_no_profile: true }
|
49
|
+
cred_opts = cli_opts[:config] ? { raise_on_no_profile: true } : {}
|
51
50
|
|
52
51
|
if cli_opts[:config]
|
53
52
|
cred_opts[:file] = Pathname.new(cli_opts[:config])
|
@@ -32,7 +32,7 @@ module WavefrontCsvOutput
|
|
32
32
|
def raw_output
|
33
33
|
resp.each_with_object([]) do |point, a|
|
34
34
|
point[:points].each do |p|
|
35
|
-
a
|
35
|
+
a << csv_format(options[:'<metric>'],
|
36
36
|
p[:value],
|
37
37
|
p[:timestamp],
|
38
38
|
options[:host],
|
@@ -48,7 +48,7 @@ module WavefrontCsvOutput
|
|
48
48
|
|
49
49
|
resp[:timeseries].each_with_object([]) do |ts, a|
|
50
50
|
ts[:data].each do |point|
|
51
|
-
a
|
51
|
+
a << csv_format(ts[:label],
|
52
52
|
point[1],
|
53
53
|
point[0],
|
54
54
|
ts[:host],
|
@@ -32,19 +32,19 @@ module WavefrontHclOutput
|
|
32
32
|
# @return [String] HCL list of vals
|
33
33
|
#
|
34
34
|
def listmaker(vals, method)
|
35
|
-
vals.each_with_object([]) { |v, a| a
|
35
|
+
vals.each_with_object([]) { |v, a| a << send(method, v) }.to_hcl_list
|
36
36
|
end
|
37
37
|
|
38
38
|
def vhandle_sections(vals)
|
39
39
|
vals.each_with_object([]) do |section, a|
|
40
|
-
a
|
40
|
+
a << ("name = \"#{section[:name]}\"\n row = " +
|
41
41
|
handle_rows(section[:rows])).braced(4)
|
42
42
|
end.to_hcl_list
|
43
43
|
end
|
44
44
|
|
45
45
|
def handle_rows(rows)
|
46
46
|
rows.each_with_object([]) do |row, a|
|
47
|
-
a
|
47
|
+
a << "chart = #{handle_charts(row[:charts])}".braced(8)
|
48
48
|
end.to_hcl_list
|
49
49
|
end
|
50
50
|
|
@@ -58,10 +58,10 @@ module WavefrontHclOutput
|
|
58
58
|
lines = chart.each_with_object([]) do |(k, v), a|
|
59
59
|
next unless fields.include?(k)
|
60
60
|
|
61
|
-
a
|
61
|
+
a << format('%<key>s = %<value>s', key: k, value: quote_value(v))
|
62
62
|
end
|
63
63
|
|
64
|
-
lines
|
64
|
+
lines << "source = #{handle_sources(chart[:sources])}"
|
65
65
|
lines.to_hcl_obj(10)
|
66
66
|
end
|
67
67
|
|
@@ -75,7 +75,7 @@ module WavefrontHclOutput
|
|
75
75
|
|
76
76
|
k = 'queryBuilderEnabled' if k == 'querybuilderEnabled'
|
77
77
|
|
78
|
-
a
|
78
|
+
a << format('%<key>s = %<value>s',
|
79
79
|
key: k.to_snake,
|
80
80
|
value: quote_value(v))
|
81
81
|
end.to_hcl_obj(14)
|
@@ -20,11 +20,11 @@ module WavefrontWavefrontOutput
|
|
20
20
|
def raw_output
|
21
21
|
resp.each_with_object('') do |point, a|
|
22
22
|
point[:points].each do |p|
|
23
|
-
a
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
a << "#{wavefront_format(options[:'<metric>'],
|
24
|
+
p[:value],
|
25
|
+
p[:timestamp],
|
26
|
+
options[:host],
|
27
|
+
point[:tags])}\n"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -34,7 +34,7 @@ module WavefrontWavefrontOutput
|
|
34
34
|
|
35
35
|
resp[:timeseries].each_with_object([]) do |ts, a|
|
36
36
|
ts[:data].each do |point|
|
37
|
-
a
|
37
|
+
a << wavefront_format(ts[:label],
|
38
38
|
point[1],
|
39
39
|
point[0],
|
40
40
|
ts[:host],
|
@@ -46,7 +46,7 @@ module WavefrontWavefrontOutput
|
|
46
46
|
def wavefront_format(path, value, timestamp, source, tags = nil)
|
47
47
|
arr = [path, value, timestamp, format('source=%<source>s',
|
48
48
|
source: source)]
|
49
|
-
arr
|
49
|
+
arr << tags.to_wf_tag if tags && !tags.empty?
|
50
50
|
arr.join(' ')
|
51
51
|
end
|
52
52
|
end
|
data/lib/wavefront-cli/query.rb
CHANGED
@@ -7,6 +7,8 @@ module WavefrontCli
|
|
7
7
|
# CLI coverage for the v2 'settings' API.
|
8
8
|
#
|
9
9
|
class Settings < WavefrontCli::Base
|
10
|
+
JOBS = %w[invitePermissions defaultUserGroups].freeze
|
11
|
+
|
10
12
|
def do_list_permissions
|
11
13
|
wf.permissions
|
12
14
|
end
|
@@ -24,10 +26,7 @@ module WavefrontCli
|
|
24
26
|
k, v = o.split('=', 2)
|
25
27
|
next unless v && !v.empty?
|
26
28
|
|
27
|
-
|
28
|
-
v = v.include?(',') ? v.split(',') : [v]
|
29
|
-
end
|
30
|
-
|
29
|
+
v = v.include?(',') ? v.split(',') : [v] if JOBS.include?(k)
|
31
30
|
a[k] = v
|
32
31
|
end
|
33
32
|
|
@@ -10,7 +10,7 @@ class String
|
|
10
10
|
# @param indent [Integer] size of hanging indent, in chars
|
11
11
|
#
|
12
12
|
def cmd_fold(twidth = TW, indent = 10)
|
13
|
-
gsub(/(-\w) /, '\\1^').scan_line(twidth - 12).join("\n
|
13
|
+
gsub(/(-\w) /, '\\1^').scan_line(twidth - 12).join("\n#{' ' * indent}")
|
14
14
|
.restored
|
15
15
|
end
|
16
16
|
|
@@ -50,7 +50,7 @@ class String
|
|
50
50
|
# undesirable line breaking. This puts it back
|
51
51
|
#
|
52
52
|
def restored
|
53
|
-
tr('^', ' ').chomp
|
53
|
+
tr('^', ' ').chomp
|
54
54
|
end
|
55
55
|
|
56
56
|
# Fold long value lines in two-column output. The returned string
|
@@ -58,7 +58,7 @@ class String
|
|
58
58
|
#
|
59
59
|
def value_fold(indent = 0, twidth = TW)
|
60
60
|
max_line_length = twidth - indent - 4
|
61
|
-
scan_line(max_line_length).join("\n
|
61
|
+
scan_line(max_line_length).join("\n#{' ' * indent}")
|
62
62
|
end
|
63
63
|
|
64
64
|
# @param width [Integer] length of longest string (width of
|
@@ -94,7 +94,7 @@ class String
|
|
94
94
|
#
|
95
95
|
def to_snake
|
96
96
|
gsub(/(.)([A-Z])/) do
|
97
|
-
Regexp.last_match[1]
|
97
|
+
"#{Regexp.last_match[1]}_#{Regexp.last_match[2].downcase}"
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -102,7 +102,7 @@ class String
|
|
102
102
|
|
103
103
|
def indent_folded_lines(chunks, twidth, indent, prefix)
|
104
104
|
chunks.join(' ').scan_line(twidth - indent - 5).map do |line|
|
105
|
-
prefix
|
105
|
+
"#{prefix}#{' ' * indent}#{line}"
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
data/lib/wavefront-cli/usage.rb
CHANGED
data/lib/wavefront-cli/write.rb
CHANGED
@@ -74,8 +74,8 @@ module WavefrontCli
|
|
74
74
|
end
|
75
75
|
# rubocop:enable Metrics/AbcSize
|
76
76
|
|
77
|
-
# Turn our user's representation of a distribution into one
|
78
|
-
#
|
77
|
+
# Turn our user's representation of a distribution into one which suits
|
78
|
+
# Wavefront. The SDK can do this for us.
|
79
79
|
#
|
80
80
|
def mk_dist
|
81
81
|
xpanded = expand_dist(options[:'<val>'])
|
@@ -83,7 +83,11 @@ module WavefrontCli
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def extra_options
|
86
|
-
|
86
|
+
if options[:using]
|
87
|
+
{ writer: options[:using] }
|
88
|
+
else
|
89
|
+
{ writer: :http }
|
90
|
+
end
|
87
91
|
end
|
88
92
|
|
89
93
|
# I chose to prioritise UI consistency over internal elegance
|
@@ -108,6 +112,7 @@ module WavefrontCli
|
|
108
112
|
port: options[:port] || default_port,
|
109
113
|
socket: options[:socket],
|
110
114
|
endpoint: options[:endpoint],
|
115
|
+
agent: "wavefront-cli-#{WF_CLI_VERSION}",
|
111
116
|
token: options[:token] }
|
112
117
|
end
|
113
118
|
|
@@ -115,18 +120,9 @@ module WavefrontCli
|
|
115
120
|
distribution? ? 40_000 : 2878
|
116
121
|
end
|
117
122
|
|
123
|
+
# The SDK writer plugins validate the credentials they need
|
118
124
|
def validate_opts
|
119
125
|
validate_opts_file if options[:file]
|
120
|
-
|
121
|
-
if options[:using] == 'unix'
|
122
|
-
return true if options[:socket]
|
123
|
-
|
124
|
-
raise(WavefrontCli::Exception::CredentialError, 'No socket path.')
|
125
|
-
end
|
126
|
-
|
127
|
-
return true if options[:proxy]
|
128
|
-
|
129
|
-
raise(WavefrontCli::Exception::CredentialError, 'No proxy address.')
|
130
126
|
end
|
131
127
|
|
132
128
|
def validate_opts_file
|
@@ -167,7 +163,7 @@ module WavefrontCli
|
|
167
163
|
#
|
168
164
|
def process_input_file(data)
|
169
165
|
data.each_with_object([]) do |l, a|
|
170
|
-
a
|
166
|
+
a << process_line(l)
|
171
167
|
rescue WavefrontCli::Exception::UnparseableInput => e
|
172
168
|
puts "Bad input. #{e.message}."
|
173
169
|
next
|
@@ -375,7 +371,7 @@ module WavefrontCli
|
|
375
371
|
end
|
376
372
|
|
377
373
|
def format_string_is_all_valid_chars?(fmt)
|
378
|
-
return true if
|
374
|
+
return true if /^[dmstTv]+$/.match?(fmt)
|
379
375
|
|
380
376
|
raise(WavefrontCli::Exception::UnparseableInput,
|
381
377
|
'unsupported field in format string')
|
@@ -426,17 +422,17 @@ module WavefrontCli
|
|
426
422
|
#
|
427
423
|
def valid_timestamp?(timestamp)
|
428
424
|
(timestamp.is_a?(Integer) ||
|
429
|
-
timestamp.is_a?(String) && timestamp.match(/^\d+$/)) &&
|
425
|
+
(timestamp.is_a?(String) && timestamp.match(/^\d+$/))) &&
|
430
426
|
timestamp.to_i > 946_684_800 &&
|
431
427
|
timestamp.to_i < (Time.now.to_i + 31_557_600)
|
432
428
|
end
|
433
429
|
|
434
430
|
def setup_fmt(fmt)
|
435
|
-
@fmt = fmt.
|
431
|
+
@fmt = fmt.chars
|
436
432
|
end
|
437
433
|
|
438
434
|
def load_data(file)
|
439
|
-
|
435
|
+
File.read(file)
|
440
436
|
rescue StandardError
|
441
437
|
raise WavefrontCli::Exception::FileNotFound
|
442
438
|
end
|
data/spec/.rubocop.yml
CHANGED
@@ -1,23 +1,8 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
|
2
|
+
inherit_from:
|
3
|
+
- ../.rubocop.yml
|
4
4
|
|
5
5
|
Metrics/MethodLength:
|
6
6
|
Max: 30
|
7
|
-
|
8
7
|
Metrics/AbcSize:
|
9
8
|
Max: 45
|
10
|
-
|
11
|
-
Metrics/ClassLength:
|
12
|
-
Max: 300
|
13
|
-
|
14
|
-
# Is nothing sacred?
|
15
|
-
Layout/LineLength:
|
16
|
-
Max: 80
|
17
|
-
|
18
|
-
Style/IfUnlessModifier:
|
19
|
-
Enabled: false # because it wants to make lines >80 chars
|
20
|
-
Style/StringConcatenation:
|
21
|
-
Enabled: false
|
22
|
-
Style/OptionalBooleanParameter:
|
23
|
-
Enabled: false
|
data/spec/constants.rb
CHANGED
@@ -12,10 +12,9 @@ TW = 80
|
|
12
12
|
|
13
13
|
ENDPOINT = 'metrics.wavefront.com'
|
14
14
|
TOKEN = '0123456789-ABCDEF'
|
15
|
-
RES_DIR = ROOT
|
16
|
-
CF = RES_DIR
|
15
|
+
RES_DIR = ROOT.join('spec', 'wavefront-cli', 'resources')
|
16
|
+
CF = RES_DIR.join('wavefront.conf')
|
17
17
|
CF_VAL = IniFile.load(CF)
|
18
|
-
JSON_POST_HEADERS = {
|
19
|
-
|
20
|
-
}.freeze
|
18
|
+
JSON_POST_HEADERS = { 'Content-Type': 'application/json',
|
19
|
+
Accept: 'application/json' }.freeze
|
21
20
|
TEE_ZERO = Time.now.freeze
|
@@ -9,11 +9,13 @@ require_relative '../../lib/wavefront-cli/controller'
|
|
9
9
|
# commands.
|
10
10
|
#
|
11
11
|
class EndToEndTest < MiniTest::Test
|
12
|
+
attr_accessor :single_perm
|
12
13
|
attr_reader :wf
|
13
14
|
|
14
15
|
def setup
|
15
16
|
before_setup if respond_to?(:before_setup)
|
16
17
|
@wf = WavefrontCliController
|
18
|
+
@single_perm = false
|
17
19
|
end
|
18
20
|
|
19
21
|
def api_path
|
@@ -79,4 +81,14 @@ class EndToEndTest < MiniTest::Test
|
|
79
81
|
{ status: { result: 'OK', message: '', code: 200 },
|
80
82
|
items: [] }.to_json
|
81
83
|
end
|
84
|
+
|
85
|
+
def blank_envvars
|
86
|
+
%w[WAVEFRONT_ENDPOINT WAVEFRONT_PROXY WAVEFRONT_TOKEN].each do |v|
|
87
|
+
ENV[v] = nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def config?
|
92
|
+
Pathname.new(Dir.home).join('.wavefront').exist?
|
93
|
+
end
|
82
94
|
end
|
@@ -147,10 +147,13 @@ module Minitest
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def assert_cmd_posts(command, api_path, payload = 'null',
|
150
|
-
response =
|
150
|
+
response = nil, extra_headers = {})
|
151
|
+
response ||= dummy_response
|
151
152
|
all_permutations do |p|
|
152
153
|
assert_posts("https://#{p[:endpoint]}#{api_path}",
|
153
|
-
mk_headers(p[:token]
|
154
|
+
mk_headers(p[:token], extra_headers),
|
155
|
+
payload,
|
156
|
+
response) do
|
154
157
|
wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
|
155
158
|
end
|
156
159
|
end
|
@@ -166,7 +169,7 @@ module Minitest
|
|
166
169
|
end
|
167
170
|
|
168
171
|
def assert_cmd_deletes(command, api_path, response = dummy_response)
|
169
|
-
|
172
|
+
all_permutations do |p|
|
170
173
|
assert_deletes("https://#{p[:endpoint]}#{api_path}",
|
171
174
|
mk_headers(p[:token]), response) do
|
172
175
|
wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
|
@@ -188,13 +191,14 @@ module Minitest
|
|
188
191
|
assert_empty(err)
|
189
192
|
end
|
190
193
|
|
191
|
-
# Run tests with all available permutations
|
192
|
-
#
|
193
|
-
#
|
194
|
+
# Run tests with all available permutations, unless the single_perm class
|
195
|
+
# variable is set. This lets us run tests faster by running fewer (but
|
196
|
+
# still a good random selection) and lets us run tests which must only be
|
197
|
+
# run once, like tests which pop stuff off the event stack.
|
194
198
|
#
|
195
199
|
def all_permutations
|
196
200
|
perms = permutations
|
197
|
-
perms =
|
201
|
+
perms = perms.shuffle.take(1) if @single_perm || ENV['FAST_TESTS']
|
198
202
|
|
199
203
|
perms.each do |p|
|
200
204
|
yield(p)
|
@@ -213,11 +217,11 @@ module Minitest
|
|
213
217
|
|
214
218
|
private
|
215
219
|
|
216
|
-
def mk_headers(token = nil)
|
217
|
-
{
|
220
|
+
def mk_headers(token = nil, extra_headers = {})
|
221
|
+
{ Accept: /.*/,
|
218
222
|
'Accept-Encoding': /.*/,
|
219
|
-
|
220
|
-
'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}" }
|
223
|
+
Authorization: "Bearer #{token || '0123456789-ABCDEF'}",
|
224
|
+
'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}" }.merge(extra_headers)
|
221
225
|
end
|
222
226
|
|
223
227
|
# Every command we simulate running is done under the following
|
@@ -14,7 +14,7 @@ class OutputTester
|
|
14
14
|
# @return [Object] canned raw responses used to test outputs
|
15
15
|
#
|
16
16
|
def load_input(file, only_items = true)
|
17
|
-
ret = JSON.parse(
|
17
|
+
ret = JSON.parse(File.read(RES_DIR.join('display', file)),
|
18
18
|
symbolize_names: true)
|
19
19
|
only_items ? ret[:items] : ret
|
20
20
|
end
|
@@ -23,7 +23,7 @@ class OutputTester
|
|
23
23
|
# @return [String]
|
24
24
|
#
|
25
25
|
def load_expected(file)
|
26
|
-
|
26
|
+
File.read(RES_DIR.join('display', file))
|
27
27
|
end
|
28
28
|
|
29
29
|
def in_and_out(input, expected, only_items = true)
|