wavefront-sdk 3.3.2 → 3.3.3

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +42 -35
  3. data/README.md +5 -5
  4. data/lib/wavefront-sdk/alert.rb +2 -0
  5. data/lib/wavefront-sdk/core/api_caller.rb +6 -3
  6. data/lib/wavefront-sdk/defs/version.rb +2 -2
  7. data/lib/wavefront-sdk/derivedmetric.rb +7 -0
  8. data/lib/wavefront-sdk/externallink.rb +2 -2
  9. data/lib/wavefront-sdk/maintenancewindow.rb +6 -2
  10. data/lib/wavefront-sdk/notificant.rb +7 -0
  11. data/lib/wavefront-sdk/paginator/base.rb +8 -0
  12. data/lib/wavefront-sdk/search.rb +11 -2
  13. data/lib/wavefront-sdk/user.rb +39 -8
  14. data/lib/wavefront-sdk/webhook.rb +1 -1
  15. data/spec/constants.rb +30 -0
  16. data/spec/spec_helper.rb +12 -237
  17. data/spec/support/bad_mocket.rb +15 -0
  18. data/spec/support/hash.rb +9 -0
  19. data/spec/support/minitest_assertions.rb +110 -0
  20. data/spec/support/mocket.rb +19 -0
  21. data/spec/test_mixins/acl.rb +78 -0
  22. data/spec/test_mixins/general.rb +120 -0
  23. data/spec/test_mixins/tag.rb +55 -0
  24. data/spec/test_mixins/update_keys.rb +11 -0
  25. data/spec/wavefront-sdk/alert_spec.rb +88 -136
  26. data/spec/wavefront-sdk/apitoken_spec.rb +26 -13
  27. data/spec/wavefront-sdk/cloudintegration_spec.rb +42 -44
  28. data/spec/wavefront-sdk/dashboard_spec.rb +53 -72
  29. data/spec/wavefront-sdk/derivedmetric_spec.rb +23 -49
  30. data/spec/wavefront-sdk/distribution_spec.rb +14 -14
  31. data/spec/wavefront-sdk/event_spec.rb +39 -48
  32. data/spec/wavefront-sdk/externallink_spec.rb +19 -50
  33. data/spec/wavefront-sdk/integration_spec.rb +33 -38
  34. data/spec/wavefront-sdk/maintenancewindow_spec.rb +18 -33
  35. data/spec/wavefront-sdk/message_spec.rb +19 -4
  36. data/spec/wavefront-sdk/metric_spec.rb +13 -9
  37. data/spec/wavefront-sdk/notificant_spec.rb +16 -15
  38. data/spec/wavefront-sdk/proxy_spec.rb +20 -25
  39. data/spec/wavefront-sdk/query_spec.rb +50 -24
  40. data/spec/wavefront-sdk/report_spec.rb +3 -6
  41. data/spec/wavefront-sdk/resources/user_responses/add_user_groups.json +1 -0
  42. data/spec/wavefront-sdk/resources/user_responses/create.json +28 -0
  43. data/spec/wavefront-sdk/resources/user_responses/delete_multiple.json +1 -0
  44. data/spec/wavefront-sdk/resources/user_responses/describe.json +1 -0
  45. data/spec/wavefront-sdk/resources/user_responses/grant.json +1 -0
  46. data/spec/wavefront-sdk/resources/user_responses/list.json +1 -0
  47. data/spec/wavefront-sdk/savedsearch_spec.rb +41 -35
  48. data/spec/wavefront-sdk/search_spec.rb +35 -29
  49. data/spec/wavefront-sdk/settings_spec.rb +18 -12
  50. data/spec/wavefront-sdk/source_spec.rb +29 -32
  51. data/spec/wavefront-sdk/user_spec.rb +101 -74
  52. data/spec/wavefront-sdk/usergroup_spec.rb +56 -67
  53. data/spec/wavefront-sdk/webhook_spec.rb +22 -34
  54. data/spec/wavefront-sdk/write_spec.rb +2 -0
  55. data/spec/wavefront-sdk/writers/core_spec.rb +2 -0
  56. data/spec/wavefront-sdk/writers/summary_spec.rb +2 -0
  57. data/wavefront-sdk.gemspec +5 -5
  58. metadata +44 -13
@@ -6,7 +6,7 @@ module Wavefront
6
6
  #
7
7
  class Webhook < CoreApi
8
8
  def update_keys
9
- %i[title description template title triggers recipient]
9
+ %i[id title description template title triggers recipient]
10
10
  end
11
11
 
12
12
  # GET /api/v2/webhook
@@ -0,0 +1,30 @@
1
+ # rubocop:disable Style/MutableConstant
2
+ CREDS = { endpoint: 'test.example.com',
3
+ token: '0123456789-ABCDEF' }
4
+ # rubocop:enable Style/MutableConstant
5
+
6
+ W_CREDS = { proxy: 'wavefront', port: 2878 }.freeze
7
+
8
+ POST_HEADERS = {
9
+ 'Content-Type': 'text/plain', Accept: 'application/json'
10
+ }.freeze
11
+
12
+ JSON_POST_HEADERS = {
13
+ 'Content-Type': 'application/json', Accept: 'application/json'
14
+ }.freeze
15
+
16
+ DUMMY_RESPONSE = '{"status":{"result":"OK","message":"","code":200},' \
17
+ '"response":{"items":[{"name":"test data"}],"offset":0,' \
18
+ '"limit":100,"totalItems":3,"moreItems":false}}'.freeze
19
+
20
+ RESOURCE_DIR = (Pathname.new(__FILE__).dirname +
21
+ 'wavefront-sdk' + 'resources').freeze
22
+
23
+ U_ACL_1 = 'someone@example.com'.freeze
24
+ U_ACL_2 = 'other@elsewhere.com'.freeze
25
+ GRP_ACL = 'f8dc0c14-91a0-4ca9-8a2a-7d47f4db4672'.freeze
26
+
27
+ DEFAULT_HEADERS = { 'Accept': /.*/,
28
+ 'Accept-Encoding': /.*/,
29
+ 'Authorization': 'Bearer 0123456789-ABCDEF',
30
+ 'User-Agent': /wavefront-sdk \d+\.\d+\.\d+/ }.freeze
@@ -1,258 +1,33 @@
1
- #
2
- # Stuff needed by multiple tests
3
- #
4
-
5
1
  require 'simplecov'
6
- SimpleCov.start do
7
- add_filter '/spec/'
8
- end
2
+ SimpleCov.start { add_filter '/spec/' }
9
3
  require 'minitest/autorun'
10
4
  require 'spy/integration'
11
5
  require 'webmock/minitest'
6
+ require_relative 'support/minitest_assertions'
7
+ require_relative 'constants'
12
8
 
13
- # rubocop:disable Style/MutableConstant
14
- CREDS = { endpoint: 'test.example.com',
15
- token: '0123456789-ABCDEF' }
16
- # rubocop:enable Style/MutableConstant
17
-
18
- W_CREDS = { proxy: 'wavefront', port: 2878 }.freeze
19
-
20
- POST_HEADERS = {
21
- 'Content-Type': 'text/plain', Accept: 'application/json'
22
- }.freeze
23
-
24
- JSON_POST_HEADERS = {
25
- 'Content-Type': 'application/json', Accept: 'application/json'
26
- }.freeze
27
-
28
- DUMMY_RESPONSE = '{"status":{"result":"OK","message":"","code":200},' \
29
- '"response":{"items":[{"name":"test data"}],"offset":0,' \
30
- '"limit":100,"totalItems":3,"moreItems":false}}'.freeze
31
-
32
- RESOURCE_DIR = (Pathname.new(__FILE__).dirname +
33
- 'wavefront-sdk' + 'resources').freeze
34
-
35
- U_ACL_1 = 'someone@example.com'.freeze
36
- U_ACL_2 = 'other@elsewhere.com'.freeze
37
- GRP_ACL = 'f8dc0c14-91a0-4ca9-8a2a-7d47f4db4672'.freeze
38
-
39
- # Common testing code
9
+ # Abstract class which sets up everything needed by the API tests
10
+ #
40
11
  class WavefrontTestBase < MiniTest::Test
41
- attr_reader :wf, :wf_noop, :headers
12
+ attr_reader :wf, :wf_noop, :headers, :invalid_id, :valid_id
42
13
 
43
14
  def initialize(args)
44
15
  require_relative "../lib/wavefront-sdk/#{class_basename.downcase}"
16
+ setup_fixtures if respond_to?(:setup_fixtures)
45
17
  super(args)
46
18
  end
47
19
 
48
- def class_basename
49
- self.class.name.match(/Wavefront(\w+)Test/)[1]
50
- end
51
-
52
- def api_base
53
- class_basename.downcase
54
- end
20
+ private
55
21
 
56
22
  def setup
57
- klass = Object.const_get('Wavefront').const_get(class_basename)
58
- @wf = klass.new(CREDS)
59
- @uri_base = uri_base
60
- @headers = { 'Authorization' => "Bearer #{CREDS[:token]}" }
23
+ @wf = Object.const_get("Wavefront::#{class_basename}").new(CREDS)
61
24
  end
62
25
 
63
- def uri_base
64
- "https://#{CREDS[:endpoint]}/api/v2/" + api_base
65
- end
66
-
67
- def target_uri(path)
68
- return "https://#{CREDS[:endpoint]}#{path}" if path.start_with?('/')
69
-
70
- [uri_base, path].join(path.start_with?('?') ? '' : '/')
71
- end
72
-
73
- # A shorthand method for very common tests.
74
- #
75
- # @param method [String] the method you wish to test
76
- # @args [String, Integer, Array] arguments with which to call method
77
- # @path [String] extra API path components (beyond /api/v2/class)
78
- # @call [Symbol] the type of API call (:get, :put etc.)
79
- # @more_headers [Hash] any additional headers which should be
80
- # sent. You will normally need to add these for :put and :post
81
- # requests.
82
- # @body [String] a JSON object you expect to be sent as part of
83
- # the request
84
- #
85
- # rubocop:disable Metrics/PerceivedComplexity
86
- # rubocop:disable Metrics/ParameterLists
87
- def should_work(method, args, path, call = :get, more_headers = {},
88
- body = nil, id = nil)
89
- path = Array(path)
90
- uri = target_uri(path.first).sub(%r{/$}, '')
91
-
92
- headers = { 'Accept': /.*/,
93
- 'Accept-Encoding': /.*/,
94
- 'Authorization': 'Bearer 0123456789-ABCDEF',
95
- 'User-Agent': "wavefront-sdk #{WF_SDK_VERSION}" }
96
- .merge(more_headers)
97
-
98
- if body
99
- stub_request(call, uri).with(body: body, headers: headers)
100
- .to_return(body: DUMMY_RESPONSE, status: 200)
101
- else
102
- stub_request(call, uri).to_return(body: DUMMY_RESPONSE, status: 200)
103
- end
104
-
105
- if args.is_a?(Hash)
106
- if id
107
- wf.send(method, id, args)
108
- else
109
- wf.send(method, args)
110
- end
111
- elsif id
112
- wf.send(method, id, *args)
113
- else
114
- wf.send(method, *args)
115
- end
116
-
117
- assert_requested(call, uri, headers: headers)
118
- WebMock.reset!
26
+ def class_basename
27
+ self.class.name.match(/Wavefront(\w+)Test/)[1]
119
28
  end
120
- # rubocop:enable Metrics/PerceivedComplexity
121
- # rubocop:enable Metrics/ParameterLists
122
29
 
123
30
  def standard_exception
124
- Object.const_get('Wavefront::Exception')
125
- .const_get("Invalid#{class_basename}Id")
126
- end
127
-
128
- def should_be_invalid(method, args = '!!invalid_val!!')
129
- assert_raises(standard_exception) { wf.send(method, *args) }
130
- end
131
-
132
- # Generic tag method testing.
133
- #
134
- def tag_tester(id)
135
- # Can we get tags? : tests #tags
136
- #
137
- should_work('tags', id, "#{id}/tag")
138
- should_be_invalid('tags')
139
-
140
- # Can we set tags? tests #tag_set
141
- #
142
- should_work('tag_set', [id, 'tag'],
143
- ["#{id}/tag", ['tag'].to_json], :post, JSON_POST_HEADERS)
144
- should_work('tag_set', [id, %w[tag1 tag2]],
145
- ["#{id}/tag", %w[tag1 tag2].to_json], :post,
146
- JSON_POST_HEADERS)
147
- should_fail_tags('tag_set', id)
148
-
149
- # Can we add tags? : tests #tag_add
150
- #
151
- should_work('tag_add', [id, 'tagval'],
152
- ["#{id}/tag/tagval", nil], :put, JSON_POST_HEADERS)
153
- should_fail_tags('tag_add', id)
154
-
155
- # Can we delete tags? : tests #tag_delete
156
- #
157
- should_work('tag_delete', [id, 'tagval'], "#{id}/tag/tagval", :delete)
158
- should_fail_tags('tag_delete', id)
159
- end
160
-
161
- def should_fail_tags(method, id)
162
- assert_raises(standard_exception) do
163
- wf.send(method, '!!invalid!!', 'tag1')
164
- end
165
-
166
- assert_raises(Wavefront::Exception::InvalidString) do
167
- wf.send(method, id, '<!!!>')
168
- end
169
- end
170
-
171
- def acl_tester(id)
172
- id2 = id.reverse
173
- should_work(:acls, [[id, id2]], "acl?id=#{id}&id=#{id2}")
174
-
175
- should_work(:acl_add, [id, [U_ACL_1, U_ACL_2], [GRP_ACL]],
176
- 'acl/add', :post, {}, acl_body(id,
177
- [U_ACL_1, U_ACL_2],
178
- [GRP_ACL]))
179
-
180
- should_work(:acl_add, [id, [U_ACL_1, U_ACL_2]],
181
- 'acl/add', :post, {}, acl_body(id,
182
- [U_ACL_1, U_ACL_2]))
183
- assert_raises(ArgumentError) { wf.acl_add(id, U_ACL_1) }
184
- assert_raises(ArgumentError) { wf.acl_add(id, [U_ACL_1], GRP_ACL) }
185
-
186
- should_work(:acl_delete, [id, [U_ACL_1, U_ACL_2], [GRP_ACL]],
187
- 'acl/remove', :post, {}, acl_body(id,
188
- [U_ACL_1, U_ACL_2],
189
- [GRP_ACL]))
190
-
191
- should_work(:acl_delete, [id, [U_ACL_1, U_ACL_2]],
192
- 'acl/remove', :post, {}, acl_body(id,
193
- [U_ACL_1, U_ACL_2]))
194
- assert_raises(ArgumentError) { wf.acl_delete(id, U_ACL_1) }
195
-
196
- should_work(:acl_set, [id, [U_ACL_1, U_ACL_2], [GRP_ACL]],
197
- 'acl/set', :put, {}, acl_body(id,
198
- [U_ACL_1, U_ACL_2],
199
- [GRP_ACL]))
200
-
201
- should_work(:acl_set, [id, [U_ACL_1, U_ACL_2]],
202
- 'acl/set', :put, {}, acl_body(id,
203
- [U_ACL_1, U_ACL_2]))
204
- assert_raises(ArgumentError) { wf.acl_set(id, U_ACL_1) }
205
- end
206
-
207
- # used by acl_tester
208
- #
209
- def acl_body(id, view = [], modify = [])
210
- [{ entityId: id, viewAcl: view, modifyAcl: modify }].to_json
211
- end
212
- end
213
-
214
- # Extensions to stdlib
215
- #
216
- class Hash
217
- # A quick way to deep-copy a hash.
218
- #
219
- def dup
220
- Marshal.load(Marshal.dump(self))
221
- end
222
- end
223
-
224
- # A mock socket
225
- #
226
- class Mocket
227
- def puts(socket); end
228
-
229
- def close; end
230
-
231
- def ok?
232
- true
233
- end
234
-
235
- def response
236
- { sent: 1, rejected: 0, unsent: 0 }
237
- end
238
-
239
- def status
240
- { result: 'OK', message: nil, code: nil }
241
- end
242
- end
243
-
244
- # A mock socket which says things went wrong.
245
- #
246
- class BadMocket < Mocket
247
- def ok?
248
- false
249
- end
250
-
251
- def status
252
- { result: 'ERROR', message: nil, code: nil }
253
- end
254
-
255
- def response
256
- { sent: 0, rejected: 1, unsent: 0 }
31
+ Object.const_get("Wavefront::Exception::Invalid#{class_basename}Id")
257
32
  end
258
33
  end
@@ -0,0 +1,15 @@
1
+ # A mock socket which says things went wrong.
2
+ #
3
+ class BadMocket < Mocket
4
+ def ok?
5
+ false
6
+ end
7
+
8
+ def status
9
+ { result: 'ERROR', message: nil, code: nil }
10
+ end
11
+
12
+ def response
13
+ { sent: 0, rejected: 1, unsent: 0 }
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # Extensions to stdlib
2
+ #
3
+ class Hash
4
+ # A quick way to deep-copy a hash.
5
+ #
6
+ def dup
7
+ Marshal.load(Marshal.dump(self))
8
+ end
9
+ end
@@ -0,0 +1,110 @@
1
+ module Minitest
2
+ #
3
+ # Some custom Minitest assertions to simplify testing
4
+ #
5
+ module Assertions
6
+ # Ensure the given call raises the correct InvalidId exception
7
+ # @param block [Proc] call to Wavefront SDK method
8
+ #
9
+ def assert_invalid_id(&block)
10
+ assert_raises(standard_exception) { yield block }
11
+ end
12
+
13
+ # Ensure that the correct API path is called by the given call
14
+ # @param api_path [String] full API path to be called
15
+ # @param block [Proc] call to SDK method
16
+ #
17
+ def assert_gets(api_path, &block)
18
+ headers = DEFAULT_HEADERS
19
+ stub_request(:get, uri(api_path))
20
+ .with(headers: headers)
21
+ .to_return(body: DUMMY_RESPONSE, status: 200)
22
+ yield block
23
+ assert_requested(:get, uri(api_path), headers: headers)
24
+ WebMock.reset!
25
+ end
26
+
27
+ # Ensure that the correct API path is hit by the given call, and
28
+ # that the correct HTTP payload is sent
29
+ # @param api_path [String] full API path to be called
30
+ # @param payload [Object] Ruby representation of payload we expect
31
+ # to see
32
+ # @param type [Symbol] override the content type
33
+ # @param block [Proc] call to SDK method
34
+ #
35
+ def assert_posts(api_path, payload = nil, type = nil, &block)
36
+ headers = DEFAULT_HEADERS.merge(extra_headers(payload, type))
37
+ payload = 'null' if payload.nil?
38
+ stub_request(:post, uri(api_path))
39
+ .with(body: payload, headers: headers)
40
+ .to_return(body: DUMMY_RESPONSE, status: 200)
41
+ yield block
42
+ assert_requested(:post, uri(api_path), headers: headers)
43
+ WebMock.reset!
44
+ end
45
+
46
+ # Ensure that the correct API path is hit by the given call, and
47
+ # that the correct HTTP payload is sent
48
+ # @param api_path [String] full API path to be called
49
+ # @param payload [Object] Ruby representation of payload we expect
50
+ # to see
51
+ # @param type [Symbol] override the content type
52
+ # @param block [Proc] call to SDK method
53
+ #
54
+ def assert_puts(api_path, payload = nil, type = nil, &block)
55
+ headers = DEFAULT_HEADERS.merge(extra_headers(payload, type))
56
+ payload = 'null' if payload.nil?
57
+ stub_request(:put, uri(api_path))
58
+ .with(body: payload, headers: headers)
59
+ .to_return(body: DUMMY_RESPONSE, status: 200)
60
+ yield block
61
+ assert_requested(:put, uri(api_path), headers: headers)
62
+ WebMock.reset!
63
+ end
64
+
65
+ # Ensure that the correct API path is called by the given call
66
+ # @param api_path [String] full API path to be called
67
+ # @param block [Proc] call to SDK method
68
+ #
69
+ def assert_deletes(api_path, &block)
70
+ headers = DEFAULT_HEADERS
71
+ stub_request(:delete, uri(api_path))
72
+ .with(headers: headers)
73
+ .to_return(body: DUMMY_RESPONSE, status: 200)
74
+ yield block
75
+ assert_requested(:delete, uri(api_path), headers: headers)
76
+ WebMock.reset!
77
+ end
78
+
79
+ private
80
+
81
+ def uri(api_path)
82
+ "https://#{CREDS[:endpoint]}#{api_path}"
83
+ end
84
+
85
+ def extra_headers(payload, type)
86
+ if payload.nil?
87
+ header_lookup(:plain)
88
+ elsif type.nil?
89
+ header_lookup(:json)
90
+ else
91
+ header_lookup(type)
92
+ end
93
+ end
94
+
95
+ def header_lookup(type)
96
+ ctype = case type
97
+ when :plain
98
+ 'text/plain'
99
+ when :json
100
+ 'application/json'
101
+ when :octet
102
+ 'application/octet-stream'
103
+ when :form
104
+ 'application/x-www-form-urlencoded'
105
+ end
106
+
107
+ { 'Content-Type': ctype, Accept: 'application/json' }
108
+ end
109
+ end
110
+ end