wavefront-cli 2.12.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d78c82e2fafc2ac41fd155095a99fbc63b33b377296aa67ee1f0ed1cb3252c46
4
- data.tar.gz: 2ef97b05806363fd93fc72068af3f662d1eb6c5828a2a319d429844f8e717e6e
3
+ metadata.gz: c9007cbf188f6962a31b04002c5b64c86e85bbc2ddad05e5299647706970ad65
4
+ data.tar.gz: 6b5daf8e04b6d5090837620f51dc9e1b5ce3c9d45227fe66d118a2adb94e758b
5
5
  SHA512:
6
- metadata.gz: f7646c92517c80068758780b69b01e385ff7de1bf62efb49003240a60a33af4b85a5c3d220a78f1573588bbe53e7d3236d7ef00741b17d3db033dc848f14f0cb
7
- data.tar.gz: 21566d131e3064522a1583c3ae44b57b38b277b521edb5336d8d58cfed606e673fe3b9f7d4036882a7a314db60a1726f4204aed08c1152dea181c00ac64d5837
6
+ metadata.gz: c224961d3690bed9d069d689d632c726262342ad4cc278b1942d4e70cc54a4263e0d89eda027b156cd93fde9184db04f831f75cbad3fe374f5a45f3eb7f30769
7
+ data.tar.gz: 2b20581ec22ae10242eea44ff07862b43eeb5bac057774b56aa6f3a363379298dbaca416859d1c274770edb376fe4bf3f85484876e16db23a475c457b850ac1b
data/HISTORY.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.13.0 (11/12/2018)
4
+ * Add CSV output for `query` command.
5
+ * Add multiple format outputs for all applicable `alert`
6
+ subcommands.
7
+ * Add `queries` subcommand for `alert` and `dashboard` subcommands,
8
+ to quickly see which queries (and therefore timeseries) are being
9
+ used.
10
+
3
11
  ## 2.12.0 (26/11/2018)
4
12
  * Support SDK's new `unix` writer, which lets you write points to a
5
13
  local Unix datagram socket. This requires `-u unix` and `-S
@@ -54,6 +54,12 @@ module WavefrontCli
54
54
  in_state(:firing)
55
55
  end
56
56
 
57
+ def do_queries
58
+ wf.list(0, :all).tap do |r|
59
+ r.response.items.map! { |a| { id: a.id, condition: a.condition } }
60
+ end
61
+ end
62
+
57
63
  # How many alerts are in the given state? If none, say so,
58
64
  # rather than just printing nothing.
59
65
  #
@@ -9,8 +9,8 @@ class WavefrontCommandAlert < WavefrontCommandBase
9
9
 
10
10
  def _commands
11
11
  ["list #{CMN} [-al] [-f format] [-o offset] [-L limit]",
12
- "firing #{CMN} [-o offset] [-L limit]",
13
- "snoozed #{CMN} [-o offset] [-L limit]",
12
+ "firing #{CMN} [-f format] [-o offset] [-L limit]",
13
+ "snoozed #{CMN} [-f format] [-o offset] [-L limit]",
14
14
  "describe #{CMN} [-f format] [-v version] <id>",
15
15
  "delete #{CMN} <id>",
16
16
  "undelete #{CMN} <id>",
@@ -25,8 +25,9 @@ class WavefrontCommandAlert < WavefrontCommandBase
25
25
  "tag clear #{CMN} <id>",
26
26
  "tag add #{CMN} <id> <tag>",
27
27
  "tag delete #{CMN} <id> <tag>",
28
- "currently #{CMN} <state>",
29
- "summary #{CMN} [-a]"]
28
+ "currently #{CMN} [-f format] <state>",
29
+ "queries #{CMN} [-f format] [-b]",
30
+ "summary #{CMN} [-f format] [-a]"]
30
31
  end
31
32
 
32
33
  def _options
@@ -37,6 +38,7 @@ class WavefrontCommandAlert < WavefrontCommandBase
37
38
  '-o, --offset=n start from nth alert',
38
39
  '-L, --limit=COUNT number of alerts to list',
39
40
  '-T, --time=SECONDS how long to snooze (default 3600)',
41
+ '-b, --brief do not show alert names',
40
42
  '-f, --format=STRING output format']
41
43
  end
42
44
  end
@@ -16,6 +16,7 @@ class WavefrontCommandDashboard < WavefrontCommandBase
16
16
  "undelete #{CMN} <id>",
17
17
  "history #{CMN} [-f format] [-o offset] [-L limit] <id>",
18
18
  "search #{CMN} [-al] [-f format] [-o offset] [-L limit] <condition>...",
19
+ "queries #{CMN} [-f format] [-b]",
19
20
  tag_commands]
20
21
  end
21
22
 
@@ -26,6 +27,7 @@ class WavefrontCommandDashboard < WavefrontCommandBase
26
27
  '-o, --offset=n start list from nth dashboard or revision',
27
28
  '-L, --limit=COUNT number of dashboards or revisions to list',
28
29
  '-v, --version=INTEGER version of dashboard',
30
+ '-b, --brief do not show dashboard names',
29
31
  '-f, --format=STRING output format']
30
32
  end
31
33
  end
@@ -10,10 +10,11 @@ class WavefrontCommandQuery < WavefrontCommandBase
10
10
  def _commands
11
11
  ['aliases [-DV] [-c file] [-P profile]',
12
12
  "#{CMN} [-g granularity] [-s time] [-e time] [-f format] " \
13
- '[-WikvO] [-S mode] [-N name] [-p points] <query>',
14
- "raw #{CMN} [-H host] [-s time] [-e time] [-f format] <metric>",
13
+ '[-WikvO] [-S mode] [-N name] [-p points] [-F options] <query>',
14
+ "raw #{CMN} [-H host] [-s time] [-e time] [-f format] " \
15
+ '[-F options] <metric>',
15
16
  "run #{CMN} [-g granularity] [-s time] [-e time] [-f format] " \
16
- '[-WkivO] [-S mode] [-N name] [-p points] <alias>']
17
+ '[-F options] [-WkivO] [-S mode] [-N name] [-p points] <alias>']
17
18
  end
18
19
 
19
20
  def _options
@@ -31,6 +32,8 @@ class WavefrontCommandQuery < WavefrontCommandBase
31
32
  '-O, --obsolete include metrics unreported for > 4 weeks',
32
33
  '-H, --host=STRING host or source to query on',
33
34
  '-f, --format=STRING output format',
35
+ '-F, --format-opts=STRING comma-separated options to pass to ' \
36
+ 'output formatter',
34
37
  '-k, --nospark do not show sparkline',
35
38
  '-W, --nowarn do not show API warning messages']
36
39
  end
@@ -38,6 +41,9 @@ class WavefrontCommandQuery < WavefrontCommandBase
38
41
  def postscript
39
42
  'The query command has an additional output format. Using ' \
40
43
  "'-f wavefront' produces output suitable for feeding back into a " \
41
- 'proxy.'.cmd_fold(TW, 0)
44
+ "proxy. Other output formats are 'yaml', 'json', 'ruby', "\
45
+ "and 'csv'. CSV format options are 'header' (print column headers); " \
46
+ "'tagkeys' (print tags as key=value rather than value); and 'quote' " \
47
+ '(force quoting of every CSV element).'.cmd_fold(TW, 0)
42
48
  end
43
49
  end
@@ -23,5 +23,36 @@ module WavefrontCli
23
23
  def do_history
24
24
  wf.history(options[:'<id>'])
25
25
  end
26
+
27
+ def do_queries
28
+ resp = wf.list(0, :all)
29
+
30
+ queries = resp.response.items.each_with_object({}) do |d, a|
31
+ a[d.id] = extract_values(d, 'query')
32
+ end
33
+
34
+ resp.tap { |r| r.response.items = queries }
35
+ end
36
+
37
+ # @param obj [Object] the thing to search
38
+ # @param key [String, Symbol] the key to search for
39
+ # @param aggr [Array] values of matched keys
40
+ # @return [Array]
41
+ #
42
+ def extract_values(obj, key, aggr = [])
43
+ if obj.is_a?(Hash)
44
+ obj.each_pair do |k, v|
45
+ if k == key && !v.to_s.empty?
46
+ aggr.<< v
47
+ else
48
+ extract_values(v, key, aggr)
49
+ end
50
+ end
51
+ elsif obj.is_a?(Array)
52
+ obj.each { |e| extract_values(e, key, aggr) }
53
+ end
54
+
55
+ aggr
56
+ end
26
57
  end
27
58
  end
@@ -55,5 +55,13 @@ module WavefrontDisplay
55
55
  data.sort.each { |k, v| puts format("%-#{kw}s%s", k, v) }
56
56
  end
57
57
  # rubocop:enable Metrics/AbcSize
58
+
59
+ def do_queries
60
+ if options[:brief]
61
+ multicolumn(:condition)
62
+ else
63
+ multicolumn(:id, :condition)
64
+ end
65
+ end
58
66
  end
59
67
  end
@@ -220,6 +220,14 @@ module WavefrontDisplay
220
220
  end
221
221
  end
222
222
 
223
+ def do_queries
224
+ if options[:brief]
225
+ multicolumn(:condition)
226
+ else
227
+ multicolumn(:id, :condition)
228
+ end
229
+ end
230
+
223
231
  # Modify, in-place, the data structure to remove fields which
224
232
  # we deem not of interest to the user.
225
233
  #
@@ -17,5 +17,14 @@ module WavefrontDisplay
17
17
  data[:sections] = data[:sections].map { |s| s[:name] }
18
18
  long_output
19
19
  end
20
+
21
+ def do_queries
22
+ if options[:brief]
23
+ @data = data.to_h.values.flatten.map { |q| { query: q } }
24
+ multicolumn(:query)
25
+ else
26
+ long_output
27
+ end
28
+ end
20
29
  end
21
30
  end
@@ -17,6 +17,7 @@ module WavefrontDisplayPrinter
17
17
  # @return [String] a Ruby format string for each line
18
18
  #
19
19
  def format_string
20
+ return '%s' if keys.length == 1
20
21
  lk = longest_keys
21
22
  keys.each_with_object('') { |k, out| out.<< "%-#{lk[k]}s " }
22
23
  end
@@ -0,0 +1,8 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontOutput
4
+ #
5
+ # Display query results in CSV format.
6
+ #
7
+ class Csv < Base; end
8
+ end
@@ -0,0 +1,18 @@
1
+ module WavefrontCsvOutput
2
+ #
3
+ # Standard output template
4
+ #
5
+ class Base
6
+ attr_reader :resp, :options
7
+
8
+ def initialize(resp, options)
9
+ @resp = resp
10
+ @options = options
11
+ post_initialize if respond_to?(:post_initialize)
12
+ end
13
+
14
+ def run
15
+ puts _run
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,117 @@
1
+ require 'set'
2
+ require_relative 'base'
3
+
4
+ module WavefrontCsvOutput
5
+ #
6
+ # Display query results in CSV format.
7
+ #
8
+ # The following options are supported:
9
+ # quote -- puts all values in soft quotes
10
+ # headers -- print CSV column headers
11
+ # tagkeys -- normally point tag keys go in the header and values in
12
+ # the CSV data. This option puts key=value in the CSV.
13
+ #
14
+ class Query < Base
15
+ attr_reader :columns, :formatopts, :headers, :data_map
16
+
17
+ def _run
18
+ csv_headers + csv_body
19
+ end
20
+
21
+ def post_initialize
22
+ @headers = []
23
+ @formatopts = extract_formatopts
24
+ @data_map = options[:raw] ? raw_output : query_output
25
+ @columns = all_keys.freeze
26
+ end
27
+
28
+ # @return [Array[Hash]] which goes in the @data_map
29
+ #
30
+ def raw_output
31
+ resp.each_with_object([]) do |point, a|
32
+ point[:points].each do |p|
33
+ a.<< csv_format(options[:'<metric>'],
34
+ p[:value],
35
+ p[:timestamp],
36
+ options[:host],
37
+ point[:tags])
38
+ end
39
+ end
40
+ end
41
+
42
+ # @return [Array[Hash]] which goes in the @data_map
43
+ #
44
+ def query_output
45
+ resp[:timeseries].each_with_object([]) do |ts, a|
46
+ ts[:data].each do |point|
47
+ a.<< csv_format(ts[:label],
48
+ point[1],
49
+ point[0],
50
+ ts[:host],
51
+ ts[:tags])
52
+ end
53
+ end
54
+ end
55
+
56
+ # @return [Array] unique list of all keys in an array of hashes
57
+ #
58
+ def all_keys(data = data_map)
59
+ data.each_with_object(Set.new) { |row, a| a.merge(row.keys) }.to_a
60
+ end
61
+
62
+ # @return [Array] single element of comma-separated CSV column
63
+ # headers if requested, otherwise []
64
+ #
65
+ def csv_headers
66
+ return [] unless formatopts.include?('headers')
67
+ [columns.map { |c| csv_value(c) }.join(',')]
68
+ end
69
+
70
+ def csv_body
71
+ data_map.map { |r| map_row_to_csv(r) }
72
+ end
73
+
74
+ def map_row_to_csv(row)
75
+ columns.map { |col| csv_value(row[col]) }.join(',')
76
+ end
77
+
78
+ # Do escaping and quoting
79
+ #
80
+ def csv_value(value)
81
+ if (formatopts.include?('quote') || value =~ /[,\s"]/) &&
82
+ !value.to_s.empty?
83
+ quote_value(value)
84
+ else
85
+ value
86
+ end
87
+ end
88
+
89
+ def quote_value(value)
90
+ format('"%s"', value.to_s.gsub(/"/, '\"'))
91
+ end
92
+
93
+ # Turn a string of output options into an easy-to-query array
94
+ #
95
+ def extract_formatopts
96
+ options[:formatopts].nil? ? [] : options[:formatopts].split(',')
97
+ end
98
+
99
+ # Take the data describing a point, and turn it into a CSV row.
100
+ # Tags have their keys removed.
101
+ #
102
+ def csv_format(path, value, timestamp, source, tags = nil)
103
+ ret = { path: path,
104
+ value: value,
105
+ timestamp: timestamp,
106
+ source: source }
107
+
108
+ ret.tap { |r| tags.each { |k, v| r[k.to_sym] = tag_val(k, v) } }
109
+ end
110
+
111
+ # We may be doing key=val or just val, depending on the formatter options
112
+ #
113
+ def tag_val(key, val)
114
+ formatopts.include?('tagkeys') ? format('%s=%s', key, val) : val
115
+ end
116
+ end
117
+ end
@@ -1 +1 @@
1
- WF_CLI_VERSION = '2.12.0'.freeze
1
+ WF_CLI_VERSION = '2.13.0'.freeze
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../../spec_helper'
4
+ require_relative '../../../../lib/wavefront-cli/output/csv/query'
5
+
6
+ # Test CSV output
7
+ #
8
+ class WavefrontOutputCsvTest < MiniTest::Test
9
+ attr_reader :wfq, :wfr, :wfqq, :wfh, :wft
10
+
11
+ def setup
12
+ @wfq = WavefrontCsvOutput::Query.new(load_query_response, {})
13
+ @wfr = WavefrontCsvOutput::Query.new(
14
+ load_raw_query_response,
15
+ raw: true,
16
+ host: 'www-blue',
17
+ '<metric>': 'solaris.network.obytes64'
18
+ )
19
+ @wfqq = WavefrontCsvOutput::Query.new(load_query_response,
20
+ formatopts: 'quote')
21
+ @wfh = WavefrontCsvOutput::Query.new(load_query_response,
22
+ formatopts: 'headers')
23
+ @wft = WavefrontCsvOutput::Query.new(load_query_response,
24
+ formatopts: 'tagkeys')
25
+ end
26
+
27
+ def test_all_keys
28
+ assert_equal(%i[a b c d e],
29
+ wfq.all_keys([{ a: 1, b: 2 }, { a: 3, c: 3 },
30
+ { d: 4, e: 5 }, { a: 1 }]))
31
+ end
32
+
33
+ def test_csv_value
34
+ assert_equal('word', wfq.csv_value('word'))
35
+ assert_equal('"word"', wfqq.csv_value('word'))
36
+ assert_equal('"7\" single"', wfq.quote_value('7" single'))
37
+ assert_equal('"7\" single"', wfqq.quote_value('7" single'))
38
+ assert_equal('"two words"', wfq.quote_value('two words'))
39
+ assert_equal('"two words"', wfqq.quote_value('two words'))
40
+ assert_equal('"a, b"', wfq.quote_value('a, b'))
41
+ assert_equal('"a, b"', wfqq.quote_value('a, b'))
42
+ end
43
+
44
+ def test_quote_value
45
+ assert_equal('"word"', wfq.quote_value('word'))
46
+ assert_equal('"1"', wfr.quote_value(1))
47
+ assert_equal('"two words"', wft.quote_value('two words'))
48
+ assert_equal('"7\" single"', wfh.quote_value('7" single'))
49
+ end
50
+
51
+ def test_csv_headers
52
+ assert_empty(wfq.csv_headers)
53
+ wfh = WavefrontCsvOutput::Query.new(load_query_response,
54
+ formatopts: 'headers')
55
+ assert_equal(['path,value,timestamp,source,colour,environment,' \
56
+ 'product,role,nic,platform,dc'], wfh.csv_headers)
57
+ end
58
+
59
+ def test_map_row_to_csv
60
+ assert_equal(',,,,,,,,,,', wfq.map_row_to_csv(merp: 1))
61
+ assert_equal('test.path,1,1544529523,testsource,,"unit test",,,,,',
62
+ wfq.map_row_to_csv(path: 'test.path',
63
+ value: 1,
64
+ timestamp: 1_544_529_523,
65
+ source: 'testsource',
66
+ environment: 'unit test'))
67
+ assert_equal('"test.path","1","1544529523","testsource",,"unit test",,,,,',
68
+ wfqq.map_row_to_csv(path: 'test.path',
69
+ value: 1,
70
+ timestamp: 1_544_529_523,
71
+ source: 'testsource',
72
+ environment: 'unit test'))
73
+ end
74
+
75
+ def test_csv_format
76
+ assert_equal({ path: 'test.path',
77
+ value: 1,
78
+ timestamp: 1_544_529_523,
79
+ source: 'testsource',
80
+ environment: 'test',
81
+ dc: 'travis' },
82
+ wfq.csv_format('test.path', 1, 1_544_529_523, 'testsource',
83
+ environment: 'test', dc: 'travis'))
84
+
85
+ assert_equal({ path: 'test.path',
86
+ value: 1,
87
+ timestamp: 1_544_529_523,
88
+ source: 'testsource',
89
+ environment: 'environment=test',
90
+ dc: 'dc=travis' },
91
+ wft.csv_format('test.path', 1, 1_544_529_523, 'testsource',
92
+ environment: 'test', dc: 'travis'))
93
+ end
94
+
95
+ def test_tag_val
96
+ assert_equal('value', wfq.tag_val('key', 'value'))
97
+ assert_equal('value', wfr.tag_val('key', 'value'))
98
+ assert_equal('key=value', wft.tag_val('key', 'value'))
99
+ assert_equal('key=value', wft.tag_val(:key, :value))
100
+ end
101
+
102
+ def test__run_query
103
+ out_q = wfq._run
104
+ assert_equal(
105
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
106
+ 'wavefront-blue,blue,production,websites,wavefront-proxy,net0,' \
107
+ 'JPC-triton,eu-ams-1', out_q.first
108
+ )
109
+ assert_equal(24, out_q.size)
110
+ check_csv_output(out_q)
111
+
112
+ out_h = wfh._run
113
+ assert_equal(
114
+ 'path,value,timestamp,source,colour,environment,product,role,' \
115
+ 'nic,platform,dc', out_h.first
116
+ )
117
+ assert_equal(
118
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
119
+ 'wavefront-blue,blue,production,websites,wavefront-proxy,net0,' \
120
+ 'JPC-triton,eu-ams-1', out_h[1]
121
+ )
122
+ assert_equal(25, out_h.size)
123
+
124
+ out_t = wft._run
125
+ assert_equal(
126
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
127
+ 'wavefront-blue,colour=blue,environment=production,product=websites,' \
128
+ 'role=wavefront-proxy,nic=net0,' \
129
+ 'platform=JPC-triton,dc=eu-ams-1', out_t.first
130
+ )
131
+ assert_equal(24, out_t.size)
132
+ check_csv_output(out_q)
133
+ end
134
+
135
+ def test__run_raw
136
+ check_csv_output(wfq._run)
137
+ end
138
+
139
+ def check_csv_output(out)
140
+ out.each do |l|
141
+ c = l.split(',', 5)
142
+ assert_equal(c[0], 'solaris.network.obytes64')
143
+ assert_match(/^[\d\.]+$/, c[1])
144
+ # query returns epoch s timestamp, raw returns epoch ms
145
+ assert_match(/^\d+$/, c[2])
146
+ assert(c[2].size == 10 || c[2].size == 13)
147
+ assert(c[3] =~ /.*blue$/)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../spec_helper'
4
+ require_relative '../../../lib/wavefront-cli/output/csv'
5
+
6
+ # Test the CSV instantiation of the base class
7
+ #
8
+ class CsvOutputBaseTest < MiniTest::Test
9
+ attr_reader :wfo
10
+
11
+ def setup
12
+ @wfo = WavefrontOutput::Csv.new(load_query_response, class: 'query')
13
+ end
14
+
15
+ def test_my_format
16
+ assert('csv', wfo.my_format)
17
+ end
18
+
19
+ def test_command_class_name
20
+ assert_equal('WavefrontCsvOutput::Query', wfo.command_class_name)
21
+ end
22
+
23
+ def test_command_file
24
+ assert_equal('csv/query', wfo.command_file)
25
+ end
26
+
27
+ def test_command_class
28
+ supported_commands = %w[query]
29
+
30
+ supported_commands.each do |cmd|
31
+ wfo = WavefrontOutput::Csv.new(load_query_response, class: cmd)
32
+ klass = wfo.command_class
33
+ assert_equal("WavefrontCsvOutput::#{cmd.capitalize}",
34
+ klass.class.name)
35
+ assert klass.respond_to?(:run)
36
+ end
37
+
38
+ (CMDS - supported_commands).each do |cmd|
39
+ wfo = WavefrontOutput::Csv.new(load_query_response, class: cmd)
40
+ assert_raises(LoadError) { wfo.command_class }
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefront-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Fisher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-05 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docopt
@@ -230,6 +230,9 @@ files:
230
230
  - lib/wavefront-cli/notificant.rb
231
231
  - lib/wavefront-cli/opt_handler.rb
232
232
  - lib/wavefront-cli/output/base.rb
233
+ - lib/wavefront-cli/output/csv.rb
234
+ - lib/wavefront-cli/output/csv/base.rb
235
+ - lib/wavefront-cli/output/csv/query.rb
233
236
  - lib/wavefront-cli/output/hcl.rb
234
237
  - lib/wavefront-cli/output/hcl/alert.rb
235
238
  - lib/wavefront-cli/output/hcl/base.rb
@@ -288,6 +291,8 @@ files:
288
291
  - spec/wavefront-cli/message_spec.rb
289
292
  - spec/wavefront-cli/metric_spec.rb
290
293
  - spec/wavefront-cli/opt_handler_spec.rb
294
+ - spec/wavefront-cli/output/csv/query_spec.rb
295
+ - spec/wavefront-cli/output/csv_spec.rb
291
296
  - spec/wavefront-cli/output/hcl_spec.rb
292
297
  - spec/wavefront-cli/output/json_spec.rb
293
298
  - spec/wavefront-cli/output/ruby_spec.rb
@@ -366,6 +371,8 @@ test_files:
366
371
  - spec/wavefront-cli/message_spec.rb
367
372
  - spec/wavefront-cli/metric_spec.rb
368
373
  - spec/wavefront-cli/opt_handler_spec.rb
374
+ - spec/wavefront-cli/output/csv/query_spec.rb
375
+ - spec/wavefront-cli/output/csv_spec.rb
369
376
  - spec/wavefront-cli/output/hcl_spec.rb
370
377
  - spec/wavefront-cli/output/json_spec.rb
371
378
  - spec/wavefront-cli/output/ruby_spec.rb