wavefront-sdk 3.3.2 → 3.3.3

Sign up to get free protection for your applications and to get access to all the features.
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