wavefront-cli 4.2.1 → 4.3.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.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.rubocop.yml +1 -14
  4. data/.travis.yml +4 -4
  5. data/Gemfile +2 -0
  6. data/HISTORY.md +82 -60
  7. data/Rakefile +2 -0
  8. data/bin/wf +1 -0
  9. data/lib/wavefront-cli/alert.rb +13 -5
  10. data/lib/wavefront-cli/apitoken.rb +2 -0
  11. data/lib/wavefront-cli/base.rb +95 -47
  12. data/lib/wavefront-cli/cloudintegration.rb +6 -0
  13. data/lib/wavefront-cli/command_mixins/acl.rb +6 -1
  14. data/lib/wavefront-cli/command_mixins/tag.rb +2 -0
  15. data/lib/wavefront-cli/commands/.rubocop.yml +3 -4
  16. data/lib/wavefront-cli/commands/alert.rb +2 -1
  17. data/lib/wavefront-cli/commands/apitoken.rb +6 -0
  18. data/lib/wavefront-cli/commands/base.rb +30 -21
  19. data/lib/wavefront-cli/commands/cloudintegration.rb +2 -0
  20. data/lib/wavefront-cli/commands/config.rb +2 -0
  21. data/lib/wavefront-cli/commands/dashboard.rb +2 -0
  22. data/lib/wavefront-cli/commands/derivedmetric.rb +2 -0
  23. data/lib/wavefront-cli/commands/event.rb +3 -1
  24. data/lib/wavefront-cli/commands/integration.rb +2 -1
  25. data/lib/wavefront-cli/commands/link.rb +2 -0
  26. data/lib/wavefront-cli/commands/message.rb +2 -0
  27. data/lib/wavefront-cli/commands/metric.rb +2 -0
  28. data/lib/wavefront-cli/commands/notificant.rb +2 -0
  29. data/lib/wavefront-cli/commands/proxy.rb +2 -0
  30. data/lib/wavefront-cli/commands/query.rb +2 -0
  31. data/lib/wavefront-cli/commands/savedsearch.rb +2 -0
  32. data/lib/wavefront-cli/commands/serviceaccount.rb +58 -0
  33. data/lib/wavefront-cli/commands/settings.rb +2 -0
  34. data/lib/wavefront-cli/commands/source.rb +3 -1
  35. data/lib/wavefront-cli/commands/user.rb +4 -1
  36. data/lib/wavefront-cli/commands/usergroup.rb +3 -0
  37. data/lib/wavefront-cli/commands/webhook.rb +2 -0
  38. data/lib/wavefront-cli/commands/window.rb +2 -0
  39. data/lib/wavefront-cli/commands/write.rb +2 -0
  40. data/lib/wavefront-cli/config.rb +23 -12
  41. data/lib/wavefront-cli/constants.rb +10 -4
  42. data/lib/wavefront-cli/controller.rb +53 -22
  43. data/lib/wavefront-cli/dashboard.rb +3 -0
  44. data/lib/wavefront-cli/derivedmetric.rb +12 -11
  45. data/lib/wavefront-cli/display/alert.rb +7 -4
  46. data/lib/wavefront-cli/display/apitoken.rb +2 -0
  47. data/lib/wavefront-cli/display/base.rb +34 -8
  48. data/lib/wavefront-cli/display/cloudintegration.rb +4 -2
  49. data/lib/wavefront-cli/display/dashboard.rb +2 -0
  50. data/lib/wavefront-cli/display/derivedmetric.rb +2 -0
  51. data/lib/wavefront-cli/display/distribution.rb +2 -0
  52. data/lib/wavefront-cli/display/event.rb +2 -0
  53. data/lib/wavefront-cli/display/externallink.rb +2 -0
  54. data/lib/wavefront-cli/display/integration.rb +2 -0
  55. data/lib/wavefront-cli/display/maintenancewindow.rb +2 -0
  56. data/lib/wavefront-cli/display/message.rb +7 -3
  57. data/lib/wavefront-cli/display/metric.rb +3 -1
  58. data/lib/wavefront-cli/display/notificant.rb +3 -1
  59. data/lib/wavefront-cli/display/printer/long.rb +36 -11
  60. data/lib/wavefront-cli/display/printer/sparkline.rb +3 -0
  61. data/lib/wavefront-cli/display/printer/terse.rb +6 -1
  62. data/lib/wavefront-cli/display/proxy.rb +2 -0
  63. data/lib/wavefront-cli/display/query.rb +35 -24
  64. data/lib/wavefront-cli/display/savedsearch.rb +2 -0
  65. data/lib/wavefront-cli/display/serviceaccount.rb +60 -0
  66. data/lib/wavefront-cli/display/settings.rb +2 -0
  67. data/lib/wavefront-cli/display/source.rb +18 -4
  68. data/lib/wavefront-cli/display/user.rb +56 -10
  69. data/lib/wavefront-cli/display/usergroup.rb +25 -19
  70. data/lib/wavefront-cli/display/webhook.rb +2 -0
  71. data/lib/wavefront-cli/display/write.rb +6 -2
  72. data/lib/wavefront-cli/event.rb +83 -62
  73. data/lib/wavefront-cli/exception.rb +3 -0
  74. data/lib/wavefront-cli/externallink.rb +6 -4
  75. data/lib/wavefront-cli/integration.rb +2 -0
  76. data/lib/wavefront-cli/maintenancewindow.rb +28 -17
  77. data/lib/wavefront-cli/message.rb +4 -0
  78. data/lib/wavefront-cli/metric.rb +4 -1
  79. data/lib/wavefront-cli/notificant.rb +2 -0
  80. data/lib/wavefront-cli/opt_handler.rb +2 -0
  81. data/lib/wavefront-cli/output/base.rb +8 -3
  82. data/lib/wavefront-cli/output/csv.rb +2 -0
  83. data/lib/wavefront-cli/output/csv/base.rb +2 -0
  84. data/lib/wavefront-cli/output/csv/query.rb +14 -7
  85. data/lib/wavefront-cli/output/hcl.rb +2 -0
  86. data/lib/wavefront-cli/output/hcl/alert.rb +2 -0
  87. data/lib/wavefront-cli/output/hcl/base.rb +10 -4
  88. data/lib/wavefront-cli/output/hcl/dashboard.rb +17 -8
  89. data/lib/wavefront-cli/output/hcl/notificant.rb +2 -0
  90. data/lib/wavefront-cli/output/hcl/stdlib/array.rb +2 -0
  91. data/lib/wavefront-cli/output/hcl/stdlib/string.rb +2 -0
  92. data/lib/wavefront-cli/output/json.rb +2 -0
  93. data/lib/wavefront-cli/output/ruby.rb +2 -0
  94. data/lib/wavefront-cli/output/wavefront.rb +2 -0
  95. data/lib/wavefront-cli/output/wavefront/query.rb +7 -4
  96. data/lib/wavefront-cli/output/yaml.rb +2 -0
  97. data/lib/wavefront-cli/proxy.rb +15 -3
  98. data/lib/wavefront-cli/query.rb +14 -12
  99. data/lib/wavefront-cli/savedsearch.rb +2 -0
  100. data/lib/wavefront-cli/serviceaccount.rb +179 -0
  101. data/lib/wavefront-cli/settings.rb +2 -0
  102. data/lib/wavefront-cli/source.rb +2 -0
  103. data/lib/wavefront-cli/stdlib/array.rb +3 -0
  104. data/lib/wavefront-cli/stdlib/string.rb +17 -11
  105. data/lib/wavefront-cli/user.rb +10 -4
  106. data/lib/wavefront-cli/usergroup.rb +4 -2
  107. data/lib/wavefront-cli/version.rb +3 -1
  108. data/lib/wavefront-cli/webhook.rb +2 -0
  109. data/lib/wavefront-cli/write.rb +80 -46
  110. data/spec/.rubocop.yml +3 -16
  111. data/spec/constants.rb +21 -0
  112. data/spec/spec_helper.rb +8 -422
  113. data/spec/support/command_base.rb +82 -0
  114. data/spec/support/minitest_assertions.rb +262 -0
  115. data/spec/support/output_tester.rb +32 -0
  116. data/spec/support/supported_commands.rb +19 -0
  117. data/spec/test_mixins/acl.rb +169 -0
  118. data/spec/test_mixins/delete.rb +25 -0
  119. data/spec/test_mixins/deleteundelete.rb +106 -0
  120. data/spec/test_mixins/describe.rb +24 -0
  121. data/spec/test_mixins/dump.rb +43 -0
  122. data/spec/test_mixins/general.rb +11 -0
  123. data/spec/test_mixins/history.rb +35 -0
  124. data/spec/test_mixins/import.rb +65 -0
  125. data/spec/test_mixins/list.rb +29 -0
  126. data/spec/test_mixins/search.rb +98 -0
  127. data/spec/test_mixins/set.rb +47 -0
  128. data/spec/test_mixins/tag.rb +99 -0
  129. data/spec/wavefront-cli/alert_spec.rb +288 -111
  130. data/spec/wavefront-cli/apitoken_spec.rb +53 -24
  131. data/spec/wavefront-cli/base_spec.rb +9 -27
  132. data/spec/wavefront-cli/cloudintegration_spec.rb +65 -29
  133. data/spec/wavefront-cli/commands/alert_spec.rb +1 -0
  134. data/spec/wavefront-cli/commands/base_spec.rb +15 -13
  135. data/spec/wavefront-cli/commands/cloudintegration_spec.rb +1 -0
  136. data/spec/wavefront-cli/commands/config_spec.rb +3 -0
  137. data/spec/wavefront-cli/commands/dashboard_spec.rb +1 -0
  138. data/spec/wavefront-cli/commands/derivedmetric_spec.rb +1 -0
  139. data/spec/wavefront-cli/commands/event_spec.rb +1 -0
  140. data/spec/wavefront-cli/commands/link_spec.rb +1 -0
  141. data/spec/wavefront-cli/commands/message_spec.rb +1 -0
  142. data/spec/wavefront-cli/commands/metric_spec.rb +1 -0
  143. data/spec/wavefront-cli/commands/proxy_spec.rb +1 -0
  144. data/spec/wavefront-cli/commands/query_spec.rb +1 -0
  145. data/spec/wavefront-cli/commands/webhook_spec.rb +1 -0
  146. data/spec/wavefront-cli/commands/window_spec.rb +1 -0
  147. data/spec/wavefront-cli/commands/write_spec.rb +1 -0
  148. data/spec/wavefront-cli/config_spec.rb +25 -14
  149. data/spec/wavefront-cli/controller_spec.rb +13 -3
  150. data/spec/wavefront-cli/dashboard_spec.rb +125 -76
  151. data/spec/wavefront-cli/derivedmetric_spec.rb +83 -67
  152. data/spec/wavefront-cli/display/base_spec.rb +5 -7
  153. data/spec/wavefront-cli/display/printer/long_spec.rb +20 -16
  154. data/spec/wavefront-cli/display/printer/terse_spec.rb +5 -4
  155. data/spec/wavefront-cli/event_spec.rb +360 -18
  156. data/spec/wavefront-cli/externallink_spec.rb +92 -58
  157. data/spec/wavefront-cli/integration_spec.rb +129 -31
  158. data/spec/wavefront-cli/maintenancewindow_spec.rb +270 -32
  159. data/spec/wavefront-cli/message_spec.rb +73 -30
  160. data/spec/wavefront-cli/metric_spec.rb +60 -22
  161. data/spec/wavefront-cli/notificant_spec.rb +45 -32
  162. data/spec/wavefront-cli/opt_handler_spec.rb +4 -1
  163. data/spec/wavefront-cli/output/csv/query_spec.rb +21 -19
  164. data/spec/wavefront-cli/output/csv_spec.rb +5 -2
  165. data/spec/wavefront-cli/output/hcl_spec.rb +5 -2
  166. data/spec/wavefront-cli/output/helpers.rb +18 -0
  167. data/spec/wavefront-cli/output/json_spec.rb +3 -1
  168. data/spec/wavefront-cli/output/ruby_spec.rb +3 -1
  169. data/spec/wavefront-cli/output/wavefront/query_spec.rb +3 -1
  170. data/spec/wavefront-cli/output/wavefront_spec.rb +6 -4
  171. data/spec/wavefront-cli/output/yaml_spec.rb +3 -1
  172. data/spec/wavefront-cli/proxy_spec.rb +49 -27
  173. data/spec/wavefront-cli/query_spec.rb +174 -92
  174. data/spec/wavefront-cli/resources/responses/query.json +1 -0
  175. data/spec/wavefront-cli/resources/updates/alert.json +15 -0
  176. data/spec/wavefront-cli/resources/updates/dashboard.json +1 -0
  177. data/spec/wavefront-cli/savedsearch_spec.rb +35 -18
  178. data/spec/wavefront-cli/serviceaccount_spec.rb +399 -0
  179. data/spec/wavefront-cli/settings_spec.rb +42 -11
  180. data/spec/wavefront-cli/source_spec.rb +120 -23
  181. data/spec/wavefront-cli/stdlib/array_spec.rb +2 -1
  182. data/spec/wavefront-cli/stdlib/string_spec.rb +9 -6
  183. data/spec/wavefront-cli/user_spec.rb +278 -108
  184. data/spec/wavefront-cli/usergroup_spec.rb +152 -102
  185. data/spec/wavefront-cli/webhook_spec.rb +30 -15
  186. data/spec/wavefront-cli/write_spec.rb +25 -1
  187. data/wavefront-cli.gemspec +5 -3
  188. metadata +65 -21
  189. data/spec/wavefront-cli/commands/spec_helper.rb +0 -3
  190. data/spec/wavefront-cli/display/spec_helper.rb +0 -3
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../support/minitest_assertions'
5
+ require_relative '../test_mixins/general'
6
+ require_relative '../../lib/wavefront-cli/controller'
7
+
8
+ # An abstract class which facilitates "end-to-end" testing of
9
+ # commands.
10
+ #
11
+ class EndToEndTest < MiniTest::Test
12
+ attr_reader :wf
13
+
14
+ def setup
15
+ before_setup if respond_to?(:before_setup)
16
+ @wf = WavefrontCliController
17
+ end
18
+
19
+ def api_path
20
+ cmd_word
21
+ end
22
+
23
+ def search_api_path
24
+ api_path
25
+ end
26
+
27
+ def cmd_class
28
+ Object.const_get("WavefrontCli::#{sdk_class_name}")
29
+ end
30
+
31
+ def cmd_instance
32
+ cmd_class.new({})
33
+ end
34
+
35
+ def sdk_class_name
36
+ api_path.capitalize
37
+ end
38
+
39
+ # Fields which must not be in import objects
40
+ #
41
+ def blocked_import_fields
42
+ %i[id]
43
+ end
44
+
45
+ # the key to use when testing the 'set' command. The value is
46
+ # always 'new_value'
47
+ #
48
+ def set_key
49
+ 'name'
50
+ end
51
+
52
+ def friendly_name
53
+ cmd_word
54
+ end
55
+
56
+ def wall_time
57
+ half_an_hour_ago = TEE_ZERO - (30 * 60)
58
+ start_time = Time.at(half_an_hour_ago.to_i - half_an_hour_ago.sec)
59
+ [start_time, Time.at(start_time + (10 * 60))]
60
+ end
61
+
62
+ def epoch_time
63
+ wall_time.map { |t| parse_time(t, true) }
64
+ end
65
+
66
+ def start_and_end_opts
67
+ format('-s %<start_time>s -e %<end_time>s',
68
+ start_time: wall_time[0].strftime('%H:%M'),
69
+ end_time: wall_time[1].strftime('%H:%M'))
70
+ end
71
+
72
+ # Set this to true for things that use cursors rather than offsets
73
+ #
74
+ def cannot_handle_offsets
75
+ false
76
+ end
77
+
78
+ def dummy_response
79
+ { status: { result: 'OK', message: '', code: 200 },
80
+ items: [] }.to_json
81
+ end
82
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spy'
4
+ require 'webmock/minitest'
5
+ require_relative '../constants'
6
+
7
+ # rubocop:disable Metrics/ModuleLength
8
+ module Minitest
9
+ #
10
+ # Custom assertions to facilitate CLI command testing
11
+ #
12
+ module Assertions
13
+ def assert_gets(api_path, headers, response, &block)
14
+ stub = stub_request(:get, api_path)
15
+ .with(headers: headers)
16
+ .to_return(body: response, status: 200)
17
+ yield block
18
+ assert_requested(stub)
19
+ end
20
+
21
+ def assert_gets_with_params(api_path, params, headers, response, &block)
22
+ stub = stub_request(:get, api_path)
23
+ .with(query: hash_including(params),
24
+ headers: headers)
25
+ .to_return(body: response, status: 200)
26
+ yield block
27
+ assert_requested(stub)
28
+ end
29
+
30
+ def assert_posts(api_path, headers, payload, response, &block)
31
+ stub = stub_request(:post, api_path)
32
+ .with(body: payload, headers: headers)
33
+ .to_return(body: response, status: 200)
34
+ yield block
35
+ assert_requested(stub)
36
+ end
37
+
38
+ def assert_puts(api_path, headers, _payload, response, &block)
39
+ stub = stub_request(:put, api_path)
40
+ .with(headers: headers)
41
+ .to_return(body: response, status: 200)
42
+ yield block
43
+ assert_requested(stub)
44
+ end
45
+
46
+ def assert_deletes(api_path, headers, response, &block)
47
+ stub = stub_request(:delete, api_path)
48
+ .with(headers: headers)
49
+ .to_return(body: response, status: 200)
50
+ yield block
51
+ assert_requested(stub)
52
+ end
53
+
54
+ # Don't bother testing permutations for this
55
+ #
56
+ def assert_invalid_id(command)
57
+ out, err = capture_io do
58
+ assert_raises(SystemExit) { wf.new("#{cmd_word} #{command}".split) }
59
+ end
60
+
61
+ assert_empty(out)
62
+ assert_match(/is not a valid \w+ ID.$/, err)
63
+ end
64
+
65
+ def assert_usage(command)
66
+ out, err = capture_io do
67
+ assert_raises(SystemExit) { wf.new("#{cmd_word} #{command}".split) }
68
+ end
69
+
70
+ assert_empty(out)
71
+ assert_match(/^Usage:\n wf #{cmd_word}/, err)
72
+ end
73
+
74
+ def assert_abort_on_missing_creds(command)
75
+ out, err = capture_io do
76
+ assert_raises(SystemExit) do
77
+ wf.new("#{cmd_word} #{command} --config /nofile".split)
78
+ end
79
+ end
80
+
81
+ assert_empty(out)
82
+ assert_equal("Configuration file '/nofile' not found.\n", err)
83
+ end
84
+
85
+ def assert_exits_with(message, command)
86
+ out, err = capture_io do
87
+ assert_raises(SystemExit) do
88
+ wf.new("#{cmd_word} #{command} --config #{CF}".split)
89
+ end
90
+ end
91
+
92
+ assert_empty(out)
93
+ assert_equal(message, err.strip)
94
+ end
95
+
96
+ def assert_cannot_noop(command)
97
+ out, err = capture_io do
98
+ assert_raises(SystemExit) do
99
+ wf.new("#{cmd_word} #{command} --noop --config #{CF}".split)
100
+ end
101
+ end
102
+
103
+ assert_empty(out)
104
+ assert_equal('Multiple API call operations cannot be ' \
105
+ "performed as no-ops.\n", err)
106
+ end
107
+
108
+ def assert_repeated_output(msg)
109
+ begin
110
+ out, err = capture_io do
111
+ yield
112
+ end
113
+ rescue SystemExit => e
114
+ puts e.backtrace
115
+ p e
116
+ end
117
+
118
+ assert_empty(err)
119
+ out.each_line { |l| assert_equal(msg, l.rstrip) }
120
+ end
121
+
122
+ def assert_cmd_gets(command, api_path, response = dummy_response)
123
+ all_permutations do |p|
124
+ assert_gets(full_uri(p[:endpoint], api_path),
125
+ mk_headers(p[:token]), response) do
126
+ wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
127
+ end
128
+ end
129
+ end
130
+
131
+ def full_uri(host, api_path)
132
+ if api_path.is_a?(Regexp)
133
+ %r{^https://#{host}#{api_path.source}$}
134
+ else
135
+ "https://#{host}#{api_path}"
136
+ end
137
+ end
138
+
139
+ def assert_cmd_gets_with_params(command, api_path, params,
140
+ response = dummy_response)
141
+ all_permutations do |p|
142
+ assert_gets_with_params("https://#{p[:endpoint]}#{api_path}",
143
+ params,
144
+ mk_headers(p[:token]),
145
+ response) do
146
+ wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
147
+ end
148
+ end
149
+ end
150
+
151
+ def assert_cmd_posts(command, api_path, payload = 'null',
152
+ response = dummy_response)
153
+ all_permutations do |p|
154
+ assert_posts("https://#{p[:endpoint]}#{api_path}",
155
+ mk_headers(p[:token]), payload, response) do
156
+ wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
157
+ end
158
+ end
159
+ end
160
+
161
+ def assert_cmd_puts(command, api_path, payload, response = dummy_response)
162
+ all_permutations do |p|
163
+ assert_puts("https://#{p[:endpoint]}#{api_path}",
164
+ mk_headers(p[:token]), payload, response) do
165
+ wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
166
+ end
167
+ end
168
+ end
169
+
170
+ def assert_cmd_deletes(command, api_path, response = dummy_response)
171
+ permutations.each do |p|
172
+ assert_deletes("https://#{p[:endpoint]}#{api_path}",
173
+ mk_headers(p[:token]), response) do
174
+ wf.new("#{cmd_word} #{command} #{p[:cmdline]}".split)
175
+ end
176
+ end
177
+ end
178
+
179
+ def assert_noop(command, *expected)
180
+ out, err = capture_io do
181
+ assert_raises(SystemExit) do
182
+ wf.new("#{cmd_word} #{command} -c #{CF} --noop".split)
183
+ end
184
+ end
185
+
186
+ out.strip.split("\n").each.with_index do |l, i|
187
+ assert_equal("SDK INFO: #{expected[i]}", l)
188
+ end
189
+
190
+ assert_empty(err)
191
+ end
192
+
193
+ # Run tests with all available permutations. We'll always need
194
+ # to mock out display, unless we don't, when even if we do, it
195
+ # won't matter.
196
+ #
197
+ def all_permutations
198
+ perms = permutations
199
+ perms = [perms[2]]
200
+
201
+ perms.each do |p|
202
+ yield(p)
203
+ WebMock.reset!
204
+ end
205
+ end
206
+
207
+ # Helper to avoid dealing with our display methods
208
+ #
209
+ def quietly
210
+ d = Spy.on_instance_method(cmd_class, :display)
211
+ yield
212
+ assert d.has_been_called?
213
+ d.unhook
214
+ end
215
+
216
+ private
217
+
218
+ def mk_headers(token = nil)
219
+ { 'Accept': /.*/,
220
+ 'Accept-Encoding': /.*/,
221
+ 'Authorization': 'Bearer ' + (token || '0123456789-ABCDEF'),
222
+ 'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}" }
223
+ end
224
+
225
+ # Every command we simulate running is done under the following
226
+ # permutations
227
+ #
228
+ def permutations
229
+ [{ cmdline: "-t #{TOKEN} -E #{ENDPOINT}",
230
+ token: TOKEN,
231
+ endpoint: ENDPOINT },
232
+
233
+ { cmdline: "-c #{CF}",
234
+ token: CF_VAL['default']['token'],
235
+ endpoint: CF_VAL['default']['endpoint'] },
236
+
237
+ { cmdline: "-c #{CF} -P other",
238
+ token: CF_VAL['other']['token'],
239
+ endpoint: CF_VAL['other']['endpoint'] },
240
+
241
+ { cmdline: "-c #{CF} --profile other -t #{TOKEN}",
242
+ token: TOKEN,
243
+ endpoint: CF_VAL['other']['endpoint'] },
244
+
245
+ { cmdline: "--config #{CF} -E #{ENDPOINT}",
246
+ token: CF_VAL['default']['token'],
247
+ endpoint: ENDPOINT }]
248
+ end
249
+
250
+ # Drop this into bodies when you need to check a non-specific
251
+ # timestamp is there
252
+ #
253
+ def a_timestamp
254
+ proc { |t| t.to_s =~ /^\d{10}$/ }
255
+ end
256
+
257
+ def a_ms_timestamp
258
+ proc { |t| t.to_s =~ /^\d{13}$/ }
259
+ end
260
+ end
261
+ end
262
+ # rubocop:enable Metrics/ModuleLength
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative '../constants'
5
+
6
+ # We keep a bunch of Wavefront API responses as text files alongside
7
+ # canned responses in various formats. This class groups helpers for
8
+ # consuming those files.
9
+ #
10
+ class OutputTester
11
+ # @param file [String] filename to load
12
+ # @param only_items [Bool] true for the items hash, false for the
13
+ # whole loadedobject
14
+ # @return [Object] canned raw responses used to test outputs
15
+ #
16
+ def load_input(file, only_items = true)
17
+ ret = JSON.parse(IO.read(RES_DIR + 'display' + file),
18
+ symbolize_names: true)
19
+ only_items ? ret[:items] : ret
20
+ end
21
+
22
+ # @param file [String] file to load
23
+ # @return [String]
24
+ #
25
+ def load_expected(file)
26
+ IO.read(RES_DIR + 'display' + file)
27
+ end
28
+
29
+ def in_and_out(input, expected, only_items = true)
30
+ [load_input(input, only_items), load_expected(expected)]
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../constants'
4
+
5
+ class SupportedCommands
6
+ attr_reader :cmd_dir
7
+
8
+ def initialize
9
+ @cmd_dir = ROOT + 'lib' + 'wavefront-cli' + 'commands'
10
+ end
11
+
12
+ def all
13
+ files = cmd_dir.children.select do |f|
14
+ f.extname == '.rb' && f.basename.to_s != 'base.rb'
15
+ end
16
+
17
+ files.map { |f| f.basename.to_s.chomp('.rb') }
18
+ end
19
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/ModuleLength
4
+ module WavefrontCliTest
5
+ #
6
+ # Include this module to get full ACL tests
7
+ #
8
+ module Acl
9
+ def test_acl
10
+ assert_repeated_output('No data.') do
11
+ assert_cmd_gets("acls #{id}", "/api/v2/#{api_path}/acl?id=#{id}")
12
+ end
13
+
14
+ assert_noop("acls #{id}",
15
+ 'uri: GET https://default.wavefront.com/api/v2/' \
16
+ "#{api_path}/acl")
17
+
18
+ assert_invalid_id("acls #{invalid_id}")
19
+ assert_usage('acls')
20
+ assert_abort_on_missing_creds("acls #{id}")
21
+ end
22
+
23
+ def test_acl_clear
24
+ acl_stub = stub_do_acls
25
+ id_stub = stub_everyone_id
26
+
27
+ quietly do
28
+ assert_cmd_puts("acl clear #{id}",
29
+ "/api/v2/#{api_path}/acl/set",
30
+ [{ entityId: id,
31
+ viewAcl: [],
32
+ modifyAcl: [everyone_id] }].to_json)
33
+ end
34
+
35
+ assert_cannot_noop("acl clear #{id}")
36
+
37
+ assert_invalid_id("acl clear #{invalid_id}")
38
+ assert_usage('acl clear')
39
+ assert_abort_on_missing_creds("acl clear #{id}")
40
+ acl_stub.unhook
41
+ id_stub.unhook
42
+ end
43
+
44
+ def test_acl_grant_view_to_users
45
+ stub = stub_do_acls
46
+
47
+ quietly do
48
+ assert_cmd_posts("acl grant view on #{id} to #{user_acl_names}",
49
+ "/api/v2/#{api_path}/acl/add",
50
+ acl_body(id, user_acls, []))
51
+ end
52
+
53
+ assert_noop("acl grant view on #{id} to #{user_acl_names}",
54
+ 'uri: POST https://default.wavefront.com/api/v2/' \
55
+ "#{api_path}/acl/add",
56
+ "body: #{acl_body(id, user_acls, [])}")
57
+
58
+ assert_invalid_id("acl grant view on #{invalid_id} to user")
59
+ assert_usage("acl grant view on #{id}")
60
+ assert_abort_on_missing_creds(
61
+ "acl grant view on #{invalid_id} to user"
62
+ )
63
+ stub.unhook
64
+ end
65
+
66
+ def test_acl_grant_modify_to_group
67
+ stub = stub_do_acls
68
+
69
+ quietly do
70
+ assert_cmd_posts("acl grant modify on #{id} to #{group_acls.first}",
71
+ "/api/v2/#{api_path}/acl/add",
72
+ acl_body(id, [], group_acls))
73
+ end
74
+
75
+ assert_noop("acl grant modify on #{id} to #{group_acls.first}",
76
+ 'uri: POST https://default.wavefront.com/api/v2/' \
77
+ "#{api_path}/acl/add",
78
+ "body: #{acl_body(id, [], group_acls)}")
79
+
80
+ assert_invalid_id("acl grant modify on #{invalid_id} to user")
81
+ assert_usage("acl grant modify on #{id}")
82
+ assert_abort_on_missing_creds(
83
+ "acl grant modify on #{invalid_id} to user"
84
+ )
85
+ stub.unhook
86
+ end
87
+
88
+ def test_acl_revoke_view_from_group
89
+ stub = stub_do_acls
90
+
91
+ quietly do
92
+ assert_cmd_posts("acl revoke view on #{id} from #{group_acls.first}",
93
+ "/api/v2/#{api_path}/acl/remove",
94
+ acl_body(id, group_acls, []))
95
+ end
96
+
97
+ assert_noop("acl revoke view on #{id} from #{group_acls.first}",
98
+ 'uri: POST https://default.wavefront.com/api/v2/' \
99
+ "#{api_path}/acl/remove",
100
+ "body: #{acl_body(id, group_acls, [])}")
101
+
102
+ assert_invalid_id("acl revoke view on #{invalid_id} from user")
103
+ assert_usage("acl revoke view on #{id}")
104
+ assert_abort_on_missing_creds(
105
+ "acl revoke view on #{invalid_id} from user"
106
+ )
107
+ stub.unhook
108
+ end
109
+
110
+ def test_acl_revoke_modify_from_user
111
+ stub = stub_do_acls
112
+
113
+ quietly do
114
+ assert_cmd_posts("acl revoke modify on #{id} from #{user_acls.first}",
115
+ "/api/v2/#{api_path}/acl/remove",
116
+ acl_body(id, [], user_acls.take(1)))
117
+ end
118
+
119
+ assert_noop("acl revoke modify on #{id} from #{user_acls.first}",
120
+ 'uri: POST https://default.wavefront.com/api/v2/' \
121
+ "#{api_path}/acl/remove",
122
+ "body: #{acl_body(id, [], user_acls.take(1))}")
123
+
124
+ assert_invalid_id("acl revoke modify on #{invalid_id} from user")
125
+ assert_usage("acl revoke modify on #{id}")
126
+ assert_abort_on_missing_creds(
127
+ "acl revoke modify on #{invalid_id} from user"
128
+ )
129
+ stub.unhook
130
+ end
131
+
132
+ private
133
+
134
+ def stub_everyone_id
135
+ Spy.on_instance_method(cmd_class, :everyone_id)
136
+ .and_return(everyone_id)
137
+ end
138
+
139
+ def stub_do_acls
140
+ Spy.on_instance_method(cmd_class, :do_acls).and_return('')
141
+ end
142
+
143
+ def everyone_id
144
+ 'abcd-1234'
145
+ end
146
+
147
+ def user_acls
148
+ %w[someone@example.com other@elsewhere.com]
149
+ end
150
+
151
+ def user_acl_names
152
+ user_acls.join(' ')
153
+ end
154
+
155
+ # @return [Array[String]] list of group IDs for ACL testing
156
+ #
157
+ def group_acls
158
+ %w[f8dc0c14-91a0-4ca9-8a2a-7d47f4db4672]
159
+ end
160
+
161
+ # @return [String] JSON representation of an ACL request
162
+ # payload
163
+ #
164
+ def acl_body(id, view = [], modify = [])
165
+ [{ entityId: id, viewAcl: view, modifyAcl: modify }].to_json
166
+ end
167
+ end
168
+ end
169
+ # rubocop:enable Metrics/ModuleLength