wavefront-sdk 3.7.1 → 4.0.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: f8a2c03d2fff24c9d9c986c89203a60dd5535d93c5df5018fc7fdb9fcd4a50a8
4
- data.tar.gz: 2957c881c681837d8e90f0c83b635a62e59d5806091f74f9861a4561f8422a83
3
+ metadata.gz: 578159c0ff0dac09b94caa4dac4e37f03436cb3e2b4cdda54886ce91b9ce4c9b
4
+ data.tar.gz: 93eac0630e97d53e3b26d222fd09df61f8cd7966c62e39520dbf27525982cb1b
5
5
  SHA512:
6
- metadata.gz: 80ffca53940c2d25cdaf6c5248fa0a5eddcbeeed7fc390d1f79405a2bf55fc9b1981624082891aa994e5e243238a37046ddb470829c5eb1140f37fef4dc6a520
7
- data.tar.gz: 4b68cae0043168eba7232296c15916a5d7e872cec758a217e8824e78a6a4945569d7d8d8e030a999b2cfb83aab2636617eb94fda12352c6985ce532a7206b416
6
+ metadata.gz: e3f09ae6d818b0acc7e81e2e4da585c10a59efba18a4ab373679783d62b5a5ccc300e14435b7cbe8a0f2d64adec361e080c55f089732ffbb6c171f619524440e
7
+ data.tar.gz: d558a6d0eafe0d09120317113758ee70807cae035a7e9677a22cf643e537103ff66d671e7e6a031151cd03572f6b62a78e9aa92a86a2fb052f0cb31ba92c4f17
data/.rubocop.yml CHANGED
@@ -4,4 +4,4 @@ AllCops:
4
4
  TargetRubyVersion: 2.3
5
5
 
6
6
  Metrics/ClassLength:
7
- Max: 124
7
+ Max: 150
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.3.8
5
4
  - 2.4.9
6
5
  - 2.5.7
7
6
  - 2.6.5
data/HISTORY.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0 (2020-02-17)
4
+ * Drop support for Ruby 2.3. (Breaking change.)
5
+ * Add `Wavefront::MonitoredCluster` class.
6
+ * Add `Wavefront::Unstable::Spy` class to speak to (undocumented) spy
7
+ interface.
8
+ * Add `Wavefront::Unstable::Chart` class to speak to (undocumented) chart
9
+ interface.
10
+
3
11
  ## 3.7.1 (2020-02-09)
4
12
  * `Response` object returned by `Wavefront::Write#write` includes a valid HTTP
5
13
  code, rather than `nil`.
data/README.md CHANGED
@@ -24,7 +24,7 @@ or to build locally,
24
24
  $ gem build wavefront-sdk.gemspec
25
25
  ```
26
26
 
27
- `wavefront-sdk` requires Ruby >= 2.3. All its dependencies are pure
27
+ `wavefront-sdk` requires Ruby >= 2.4. All its dependencies are pure
28
28
  Ruby, right the way down, so a compiler should never be required to
29
29
  install it.
30
30
 
@@ -6,6 +6,7 @@ require 'addressable'
6
6
  require_relative 'response'
7
7
  require_relative '../defs/version'
8
8
  require_relative '../support/mixins'
9
+ require_relative '../stdlib/time'
9
10
 
10
11
  module Wavefront
11
12
  #
@@ -78,14 +79,47 @@ module Wavefront
78
79
  # was cleaner to add this method. Parameters are same as #get.
79
80
  #
80
81
  def get_flat_params(path, query = {})
81
- conn = mk_conn(path,
82
- {},
83
- request: {
84
- params_encoder: Faraday::FlatParamsEncoder
85
- },
86
- params: query)
82
+ make_call(flat_param_conn(path, query), :get)
83
+ end
84
+
85
+ # This is used by the Wavefront::Unstable::Spy methods to stream data.
86
+ # It prints to standard out.
87
+ # @param path [String] path to be appended to the net[:api_base] path.
88
+ # @param query [Hash] optional key-value pairs with will be made into a
89
+ # query string
90
+ # @param opts [Hash] keys:
91
+ # timestamp_chunks -- prints a timestamp before each chunk of streamed
92
+ # data
93
+ # timeout -- after approximately this many seconds, return. It will be
94
+ # the first chunk *after* the given time
95
+ # @return
96
+ #
97
+ def get_stream(path, query = {}, opts = {})
98
+ conn = flat_param_conn(path, query)
99
+ verbosity(conn, :get, query)
100
+ stream_connection(conn, query, opts)
101
+ rescue Faraday::TimeoutError
102
+ raise Wavefront::Exception::NetworkTimeout
103
+ rescue StopIteration
104
+ nil
105
+ end
106
+
107
+ def stream_connection(conn, query, opts)
108
+ t_end = end_time(opts)
109
+
110
+ conn.get do |req|
111
+ req.params = query
112
+ req.options.on_data = proc do |chunk, _size|
113
+ raise StopIteration if t_end && Time.right_now >= t_end
87
114
 
88
- make_call(conn, :get)
115
+ puts Time.now if opts[:timestamp_chunks]
116
+ puts chunk
117
+ end
118
+ end
119
+ end
120
+
121
+ def end_time(opts)
122
+ Time.right_now + opts[:timeout] if opts[:timeout]&.positive?
89
123
  end
90
124
 
91
125
  # Make a POST call to the Wavefront API and return the result as
@@ -240,5 +274,14 @@ module Wavefront
240
274
  end
241
275
  end
242
276
  end
277
+
278
+ def flat_param_conn(path, query)
279
+ mk_conn(path,
280
+ {},
281
+ request: {
282
+ params_encoder: Faraday::FlatParamsEncoder
283
+ },
284
+ params: query)
285
+ end
243
286
  end
244
287
  end
@@ -28,6 +28,7 @@ module Wavefront
28
28
  class InvalidIntegrationId < RuntimeError; end
29
29
  class InvalidLinkTemplate < RuntimeError; end
30
30
  class InvalidMaintenanceWindowId < RuntimeError; end
31
+ class InvalidMonitoredClusterId < RuntimeError; end
31
32
  class InvalidMessageId < RuntimeError; end
32
33
  class InvalidMetricName < RuntimeError; end
33
34
  class InvalidMetricValue < RuntimeError; end
@@ -38,6 +39,7 @@ module Wavefront
38
39
  class InvalidPrefixLength < RuntimeError; end
39
40
  class InvalidProxyId < RuntimeError; end
40
41
  class InvalidRelativeTime < RuntimeError; end
42
+ class InvalidSamplingValue < RuntimeError; end
41
43
  class InvalidSavedSearchEntity < RuntimeError; end
42
44
  class InvalidSavedSearchId < RuntimeError; end
43
45
  class InvalidServiceAccountId < RuntimeError; end
@@ -51,6 +53,7 @@ module Wavefront
51
53
  class InvalidUserGroupId < RuntimeError; end
52
54
  class InvalidVersion < RuntimeError; end
53
55
  class InvalidWebhookId < RuntimeError; end
56
+ class NetworkTimeout < RuntimeError; end
54
57
  class NotImplemented < RuntimeError; end
55
58
  class SocketError < RuntimeError; end
56
59
  class UnparseableResponse < RuntimeError; end
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
- WF_SDK_VERSION = '3.7.1'
3
+ WF_SDK_VERSION = '4.0.0'
6
4
  WF_SDK_LOCATION = Pathname.new(__dir__).parent.parent.parent
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'core/api'
4
+ require_relative 'api_mixins/tag'
5
+
6
+ module Wavefront
7
+ #
8
+ # Manage and query Wavefront monitored clusters
9
+ #
10
+ class MonitoredCluster < CoreApi
11
+ include Wavefront::Mixin::Tag
12
+
13
+ def update_keys
14
+ %i[id]
15
+ end
16
+
17
+ # GET /api/v2/monitoredcluster
18
+ # Get all monitored clusters
19
+ # @param offset [Integer] cluster at which the list begins
20
+ # @param limit [Integer] the number of clusters to return
21
+ # @return [Wavefront::Response]
22
+ #
23
+ def list(offset = 0, limit = 100)
24
+ api.get('', offset: offset, limit: limit)
25
+ end
26
+
27
+ # POST /api/v2/monitoredcluster
28
+ # Create a specific cluster
29
+ # @param body [Hash] a hash of parameters describing the cluster.
30
+ # Please refer to the Wavefront Swagger docs for key:value
31
+ # information
32
+ # @return [Wavefront::Response]
33
+ #
34
+ def create(body)
35
+ raise ArgumentError unless body.is_a?(Hash)
36
+
37
+ api.post('', body, 'application/json')
38
+ end
39
+
40
+ # DELETE /api/v2/monitoredcluster/{id}
41
+ # Delete a specific cluster
42
+ # @param id [String, Integer] ID of the maintenance cluster
43
+ # @return [Wavefront::Response]
44
+ #
45
+ def delete(id)
46
+ wf_monitoredcluster_id?(id)
47
+ api.delete(id)
48
+ end
49
+
50
+ # GET /api/v2/monitoredcluster/{id}
51
+ # Get a specific cluster
52
+ # @param id [String, Integer] ID of the cluster
53
+ # @return [Wavefront::Response]
54
+ #
55
+ def describe(id)
56
+ wf_monitoredcluster_id?(id)
57
+ api.get(id)
58
+ end
59
+
60
+ # PUT /api/v2/monitoredcluster/{id}
61
+ # Update a specific cluster
62
+ # @return [Wavefront::Response]
63
+ #
64
+ def update(id, body, modify = true)
65
+ wf_monitoredcluster_id?(id)
66
+ raise ArgumentError unless body.is_a?(Hash)
67
+
68
+ return api.put(id, body, 'application/json') unless modify
69
+
70
+ api.put(id, hash_for_update(describe(id).response, body),
71
+ 'application/json')
72
+ end
73
+
74
+ # PUT /api/v2/monitoredcluster/merge/{id1}/{id2}
75
+ # Merge two monitored clusters. The first cluster will remain and the
76
+ # second cluster will be deleted, with its id added as an alias to the
77
+ # first cluster.
78
+ # @param id1 [String, Integer] ID of the target cluster
79
+ # @param id2 [String, Integer] ID of the other cluster
80
+ # @return [Wavefront::Response]
81
+ #
82
+ def merge(id1, id2)
83
+ wf_monitoredcluster_id?(id1)
84
+ wf_monitoredcluster_id?(id2)
85
+
86
+ api.put(['merge', id1, id2].uri_concat, nil, 'application/json')
87
+ end
88
+
89
+ def valid_id?(id)
90
+ wf_monitoredcluster_id?(id)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extensions to the stdlib Time class
4
+ #
5
+ class Time
6
+ #
7
+ # The real hi-res time. See
8
+ # https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/
9
+ #
10
+ def self.right_now
11
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ The classes in here use undocumented APIs. They are thus subject to
2
+ change or revocation at any time.
3
+
4
+ Use them at your own risk.
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../defs/constants'
4
+ require_relative '../core/api'
5
+
6
+ module Wavefront
7
+ module Unstable
8
+ #
9
+ # This is an unstable class. Please refer to README.md.
10
+ #
11
+ class Chart < CoreApi
12
+ def all_metrics
13
+ metrics_under('')
14
+ end
15
+
16
+ # Gets a list of metrics under the given path. This must be done via
17
+ # recursive calls to the API, so calls can take a while. If you ask for
18
+ # all your metrics, expect to be waiting some time.
19
+ #
20
+ # @return [Wavefront::Response]
21
+ #
22
+ # rubocop:disable Metrics/MethodLength
23
+ # rubocop:disable Metrics/AbcSize
24
+ def metrics_under(path, cursor = nil, limit = 100)
25
+ resp = api.get('metrics/all',
26
+ { trie: true, q: path, p: cursor, l: limit }.compact)
27
+
28
+ return resp unless resp.ok?
29
+
30
+ metrics = resp.response.items
31
+
32
+ metrics.each do |m|
33
+ if m.end_with?('.')
34
+ metrics += metrics_under(m).response.items
35
+ metrics.delete(m)
36
+ end
37
+ end
38
+
39
+ # resp.more_items? doesn't work: we don't get that from this API
40
+
41
+ if metrics.size == limit
42
+ metrics += metrics_under(path, metrics.last, limit).response.items
43
+ end
44
+
45
+ resp.response.items = metrics.sort
46
+ resp
47
+ end
48
+ # rubocop:enable Metrics/MethodLength
49
+ # rubocop:enable Metrics/AbcSize
50
+
51
+ def api_path
52
+ '/chart'
53
+ end
54
+
55
+ # We have to try to make the response we get from the API look
56
+ # like the one we get from the public API. To begin with, it's
57
+ # nothing like it.
58
+ #
59
+ # This method must be public because a #respond_to? looks for
60
+ # it.
61
+ #
62
+ def response_shim(resp, status)
63
+ { response: parse_response(resp),
64
+ status: { result: status == 200 ? 'OK' : 'ERROR',
65
+ message: extract_api_message(status, resp),
66
+ code: status } }.to_json
67
+ end
68
+
69
+ private
70
+
71
+ def parse_response(resp)
72
+ metrics = JSON.parse(resp, symbolize_names: true)[:metrics]
73
+
74
+ { items: metrics,
75
+ offset: 0,
76
+ limit: metrics.size,
77
+ totalItems: metrics.size,
78
+ moreItems: false }
79
+ rescue JSON::ParserError
80
+ nil
81
+ end
82
+
83
+ def extract_api_message(_status, resp)
84
+ resp.match(/^message='(.*)'/)[1]
85
+ rescue NoMethodError
86
+ ''
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../defs/constants'
4
+ require_relative '../core/api'
5
+
6
+ module Wavefront
7
+ module Unstable
8
+ #
9
+ # THIS IS AN UNSTABLE CLASS. PLEASE REFER TO README.md.
10
+ #
11
+ # Everything about this API is different from the public one. To make it
12
+ # appear similar we must change various things we normally take for
13
+ # granted.
14
+ #
15
+ # This class is built according to the documentation at
16
+ # https://docs.wavefront.com/wavefront_monitoring_spy.html
17
+ #
18
+ class Spy < CoreApi
19
+ # https://<cluster>.wavefront.com/api/spy/points
20
+ # Gets new metric data points that are added to existing time series.
21
+ # @param sampling [Float] the amount of points to sample, from 0
22
+ # (none) to 1 (all)
23
+ # @param filter [Hash] with the following keys:
24
+ # :prefix [String] only list points whose metric name begins with this
25
+ # case-sensitive string
26
+ # :host [Array] only list points if source name begins with this
27
+ # case-sensitive string
28
+ # :tag_key [String,Array[String]] only list points with one or more of
29
+ # the given points tags
30
+ # @param options [Hash] with the following keys
31
+ # :timestamp [Boolean] prefix each block of streamed data with a
32
+ # timestamp
33
+ # :timeout [Integer] how many seconds to run the spy. After this time
34
+ # the method returns
35
+ # @raise Wavefront::Exception::InvalidSamplingValue
36
+ # @return [Nil]
37
+ #
38
+ def points(sampling = 0.01, filters = {}, options = {})
39
+ wf_sampling_value?(sampling)
40
+ api.get_stream('points', points_filter(sampling, filters), options)
41
+ end
42
+
43
+ # Gets new histograms that are added to existing time series.
44
+ # @param sampling [Float] see #points
45
+ # @param filter [Hash] see #points
46
+ # @param options [Hash] see #points
47
+ # @raise Wavefront::Exception::InvalidSamplingValue
48
+ # @return [Nil]
49
+ #
50
+ def histograms(sampling = 0.01, filters = {}, options = {})
51
+ wf_sampling_value?(sampling)
52
+ api.get_stream('histograms',
53
+ histograms_filter(sampling, filters),
54
+ options)
55
+ end
56
+
57
+ # https://<cluster>.wavefront.com/api/spy/spans
58
+ # Gets new spans with existing source names and span tags.
59
+ # @param sampling [Float] see #points
60
+ # @param filter [Hash] see #points
61
+ # @param options [Hash] see #points
62
+ # @raise Wavefront::Exception::InvalidSamplingValue
63
+ # @return [Nil]
64
+ #
65
+ def spans(sampling = 0.01, filters = {}, options = {})
66
+ wf_sampling_value?(sampling)
67
+ api.get_stream('spans', spans_filter(sampling, filters), options)
68
+ end
69
+
70
+ # https://<cluster>.wavefront.com/api/spy/ids
71
+ # Gets newly allocated IDs that correspond to new metric names, source
72
+ # names, point tags, or span tags. A new ID generally indicates that a
73
+ # new time series has been introduced.
74
+ # @param sampling [Float] see #points
75
+ # @param filter [Hash] with keys:
76
+ # :prefix [String] only list assignments whose metric name begins with
77
+ # this case-sensitive string
78
+ # :type [String] one of METRIC, SPAN, HOST or STRING
79
+ # @param options [Hash] see #points
80
+ #
81
+ def ids(sampling = 0.01, filters = {}, options = {})
82
+ wf_sampling_value?(sampling)
83
+ api.get_stream('ids', ids_filter(sampling, filters), options)
84
+ end
85
+
86
+ def api_path
87
+ '/api/spy'
88
+ end
89
+
90
+ # We have to try to make the response we get from the API look
91
+ # like the one we get from the public API. To begin with, it's
92
+ # nothing like it.
93
+ #
94
+ # This method must be public because a #respond_to? looks for
95
+ # it.
96
+ #
97
+ def _response_shim(resp, status)
98
+ { response: parse_response(resp),
99
+ status: { result: status == 200 ? 'OK' : 'ERROR',
100
+ message: extract_api_message(status, resp),
101
+ code: status } }.to_json
102
+ end
103
+
104
+ private
105
+
106
+ def points_filter(sampling, filters)
107
+ { metric: filters.fetch(:prefix, nil),
108
+ host: filters.fetch(:host, nil),
109
+ sampling: sampling,
110
+ pointTagKey: filters.fetch(:tag_key, nil) }.compact
111
+ end
112
+
113
+ def histograms_filter(sampling, filters)
114
+ { histogram: filters.fetch(:prefix, nil),
115
+ host: filters.fetch(:host, nil),
116
+ sampling: sampling,
117
+ histogramTagKey: filters.fetch(:tag_key, nil) }.compact
118
+ end
119
+
120
+ def spans_filter(sampling, filters)
121
+ { name: filters.fetch(:prefix, nil),
122
+ host: filters.fetch(:host, nil),
123
+ sampling: sampling,
124
+ spanTagKey: filters.fetch(:tag_key, nil) }.compact
125
+ end
126
+
127
+ def ids_filter(sampling, filters)
128
+ { name: filters.fetch(:prefix, nil),
129
+ type: filters.fetch(:type, nil),
130
+ sampling: sampling }.compact
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wavefront
4
+ #
5
+ # Placeholder for unstable API classes
6
+ #
7
+ module Unstable
8
+ end
9
+ end
@@ -594,6 +594,27 @@ module Wavefront
594
594
  raise Wavefront::Exception::InvalidAccountId, id
595
595
  end
596
596
  end
597
+
598
+ # Ensure the given argument is a valid monitored cluster ID
599
+ # @param id [String]
600
+ # @raise Wavefront::Exception::InvalidMonitoredClusterId if the ID is not
601
+ # valid
602
+ #
603
+ def wf_monitoredcluster_id?(id)
604
+ return true if id.is_a?(String) && id.size < 256 && id =~ /^[a-z0-9\-_]+$/
605
+
606
+ raise Wavefront::Exception::InvalidMonitoredClusterId, id
607
+ end
608
+
609
+ # Ensure the given value is a valid sampling rate.
610
+ # @param rate [Float]
611
+ # @raise Wavefront::Exception::InvalidSamplingValue
612
+ #
613
+ def wf_sampling_value?(value)
614
+ return true if value.is_a?(Numeric) && value.between?(0, 0.05)
615
+
616
+ raise Wavefront::Exception::InvalidSamplingValue, value
617
+ end
597
618
  end
598
619
  # rubocop:enable Metrics/ModuleLength
599
620
  end
@@ -113,7 +113,7 @@ module Wavefront
113
113
  # @return Wavefront::Response
114
114
  #
115
115
  def composite_response(responses)
116
- result, code = response_codes(responses)
116
+ result, code = response_results(responses)
117
117
 
118
118
  summary = { sent: 0, rejected: 0, unsent: 0 }
119
119
 
@@ -127,6 +127,14 @@ module Wavefront
127
127
  )
128
128
  end
129
129
 
130
+ def response_results(responses)
131
+ if responses.all?(&:ok?)
132
+ ['OK', 200]
133
+ else
134
+ ['ERROR', 400]
135
+ end
136
+ end
137
+
130
138
  def manage_conn
131
139
  opts[:noauto] ? false : true
132
140
  end
@@ -248,13 +256,5 @@ module Wavefront
248
256
  rescue LoadError
249
257
  raise(Wavefront::Exception::UnsupportedWriter, writer)
250
258
  end
251
-
252
- def response_codes(responses)
253
- if responses.all?(&:ok?)
254
- ['OK', 200]
255
- else
256
- ['ERROR', 400]
257
- end
258
- end
259
259
  end
260
260
  end
data/spec/spec_helper.rb CHANGED
@@ -23,6 +23,10 @@ class WavefrontTestBase < MiniTest::Test
23
23
  "../lib/wavefront-sdk/#{class_basename.downcase}"
24
24
  end
25
25
 
26
+ def dummy_response
27
+ DUMMY_RESPONSE
28
+ end
29
+
26
30
  private
27
31
 
28
32
  def setup
@@ -20,7 +20,7 @@ module Minitest
20
20
  headers = DEFAULT_HEADERS
21
21
  stub_request(:get, uri(api_path))
22
22
  .with(headers: headers)
23
- .to_return(body: DUMMY_RESPONSE, status: 200)
23
+ .to_return(body: dummy_response, status: 200)
24
24
  yield block
25
25
  assert_requested(:get, uri(api_path), headers: headers)
26
26
  WebMock.reset!
@@ -39,7 +39,7 @@ module Minitest
39
39
  payload = 'null' if payload.nil?
40
40
  stub_request(:post, uri(api_path))
41
41
  .with(body: payload, headers: headers)
42
- .to_return(body: DUMMY_RESPONSE, status: 200)
42
+ .to_return(body: dummy_response, status: 200)
43
43
  yield block
44
44
  assert_requested(:post, uri(api_path), headers: headers)
45
45
  WebMock.reset!
@@ -58,7 +58,7 @@ module Minitest
58
58
  payload = 'null' if payload.nil?
59
59
  stub_request(:put, uri(api_path))
60
60
  .with(body: payload, headers: headers)
61
- .to_return(body: DUMMY_RESPONSE, status: 200)
61
+ .to_return(body: dummy_response, status: 200)
62
62
  yield block
63
63
  assert_requested(:put, uri(api_path), headers: headers)
64
64
  WebMock.reset!
@@ -72,7 +72,7 @@ module Minitest
72
72
  headers = DEFAULT_HEADERS
73
73
  stub_request(:delete, uri(api_path))
74
74
  .with(headers: headers)
75
- .to_return(body: DUMMY_RESPONSE, status: 200)
75
+ .to_return(body: dummy_response, status: 200)
76
76
  yield block
77
77
  assert_requested(:delete, uri(api_path), headers: headers)
78
78
  WebMock.reset!
@@ -37,6 +37,49 @@ class WavefrontApiCallerTest < MiniTest::Test
37
37
  assert_requested(:get, uri, headers: headers)
38
38
  end
39
39
 
40
+ def test_get_flat_params
41
+ query = { rkey: %w[val1 val2 val3], ukey: 36 }
42
+ uri = "#{uri_base}/path?rkey=val1&rkey=val2&rkey=val3&ukey=36"
43
+ stub_request(:get, uri).to_return(body: DUMMY_RESPONSE, status: 200)
44
+ wf.get_flat_params('/path', query)
45
+ assert_requested(:get, uri, headers: headers)
46
+ end
47
+
48
+ def test_get_stream
49
+ uri = "#{uri_base}/path?key1=val1"
50
+ stub_request(:get, uri).to_return(body: DUMMY_RESPONSE, status: 200)
51
+ out, err = capture_io { wf.get_stream('/path', key1: 'val1') }
52
+ assert_requested(:get, uri, headers: headers)
53
+ assert_equal(out.strip, DUMMY_RESPONSE)
54
+ assert_empty(err)
55
+ end
56
+
57
+ def test_get_stream_array_params
58
+ uri = "#{uri_base}/path?key=val1&key=val2"
59
+ stub_request(:get, uri).to_return(body: DUMMY_RESPONSE, status: 200)
60
+ out, err = capture_io { wf.get_stream('/path', key: %w[val1 val2]) }
61
+ assert_requested(:get, uri, headers: headers)
62
+ assert_equal(out.strip, DUMMY_RESPONSE)
63
+ assert_empty(err)
64
+ end
65
+
66
+ def test_get_stream_timestamp
67
+ uri = "#{uri_base}/path?key1=val1"
68
+ stub_request(:get, uri).to_return(body: DUMMY_RESPONSE, status: 200)
69
+
70
+ out, err = capture_io do
71
+ wf.get_stream('/path',
72
+ { key1: 'val1' },
73
+ timestamp_chunks: true)
74
+ end
75
+
76
+ assert_requested(:get, uri, headers: headers)
77
+ out_lines = out.split("\n")
78
+ assert_match(/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d \+\d{4}$/, out_lines[0])
79
+ assert_equal(out_lines[1], DUMMY_RESPONSE)
80
+ assert_empty(err)
81
+ end
82
+
40
83
  def test_post
41
84
  uri = "#{uri_base}/path"
42
85
  obj = { key: 'value' }
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../spec_helper'
5
+ require_relative '../test_mixins/general'
6
+ require_relative '../test_mixins/tag'
7
+
8
+ # Unit tests for MonitoredCluster class
9
+ #
10
+ class WavefrontMonitoredClusterTest < WavefrontTestBase
11
+ include WavefrontTest::Create
12
+ include WavefrontTest::Delete
13
+ include WavefrontTest::Describe
14
+ include WavefrontTest::List
15
+ include WavefrontTest::Update
16
+ include WavefrontTest::Tag
17
+
18
+ def test_merge
19
+ assert_puts("/api/v2/monitoredcluster/merge/#{id}/#{id2}", nil, :json) do
20
+ wf.merge(id, id2)
21
+ end
22
+
23
+ assert_invalid_id { wf.merge(id, invalid_id) }
24
+ end
25
+
26
+ private
27
+
28
+ def api_class
29
+ 'monitoredcluster'
30
+ end
31
+
32
+ def id
33
+ 'k8s-sample'
34
+ end
35
+
36
+ def id2
37
+ 'eks-cluster'
38
+ end
39
+
40
+ def invalid_id
41
+ '!!!!'
42
+ end
43
+
44
+ def payload
45
+ { id: 'k8s-sample',
46
+ name: 'Sample cluster',
47
+ platform: 'EKS',
48
+ version: '1.2',
49
+ additionalTags: {
50
+ region: 'us-west-2',
51
+ az: 'testing'
52
+ },
53
+ tags: %w[alertTag1] }
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../../spec_helper'
5
+ require_relative '../../../lib/wavefront-sdk/unstable/chart'
6
+
7
+ # Unit tests for Chart class
8
+ #
9
+ class WavefrontChartTest < MiniTest::Test
10
+ attr_reader :wf
11
+
12
+ def setup
13
+ @wf = Wavefront::Unstable::Chart.new(CREDS)
14
+ end
15
+
16
+ def test_all_metrics
17
+ assert_gets('/chart/metrics/all?l=100&q=&trie=true') do
18
+ wf.metrics_under('')
19
+ end
20
+ end
21
+
22
+ def test_metrics_under
23
+ assert_gets('/chart/metrics/all?l=100&q=test.path&trie=true') do
24
+ wf.metrics_under('test.path')
25
+ end
26
+
27
+ assert_gets('/chart/metrics/all?l=10&q=test.path&trie=true') do
28
+ wf.metrics_under('test.path', nil, 10)
29
+ end
30
+
31
+ assert_gets('/chart/metrics/all?l=100&p=last.one&q=test.path&trie=true') do
32
+ wf.metrics_under('test.path', 'last.one')
33
+ end
34
+ end
35
+
36
+ def dummy_response
37
+ { metrics: ['test data'] }.to_json
38
+ end
39
+ end
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../../spec_helper'
5
+ require_relative '../../../lib/wavefront-sdk/unstable/spy'
6
+
7
+ # Unit tests for Spy class
8
+ #
9
+ class WavefrontSpyTest < MiniTest::Test
10
+ attr_reader :wf
11
+
12
+ def setup
13
+ @wf = Wavefront::Unstable::Spy.new(CREDS)
14
+ end
15
+
16
+ def test_points
17
+ capture_io do
18
+ assert_gets('/api/spy/points?sampling=0.01') { wf.points }
19
+ assert_gets('/api/spy/points?sampling=0.05') { wf.points(0.05) }
20
+
21
+ assert_gets('/api/spy/points?sampling=0.05&metric=my_prefix') do
22
+ wf.points(0.05, prefix: 'my_prefix')
23
+ end
24
+
25
+ assert_gets('/api/spy/points?sampling=0.05&metric=my_prefix&host=h1') do
26
+ wf.points(0.05, prefix: 'my_prefix', host: 'h1')
27
+ end
28
+
29
+ assert_gets('/api/spy/points?sampling=0.02&metric=my_prefix&' \
30
+ 'pointTagKey=mytag') do
31
+ wf.points(0.02, prefix: 'my_prefix', tag_key: 'mytag')
32
+ end
33
+
34
+ assert_gets('/api/spy/points?sampling=0.02&metric=my_prefix&' \
35
+ 'pointTagKey=tag1&pointTagKey=tag2') do
36
+ wf.points(0.02, prefix: 'my_prefix', tag_key: %w[tag1 tag2])
37
+ end
38
+ end
39
+ end
40
+
41
+ def test_histograms
42
+ capture_io do
43
+ assert_gets('/api/spy/histograms?sampling=0.01') { wf.histograms }
44
+ assert_gets('/api/spy/histograms?sampling=0.05') { wf.histograms(0.05) }
45
+
46
+ assert_gets('/api/spy/histograms?sampling=0.05&histogram=my_prefix') do
47
+ wf.histograms(0.05, prefix: 'my_prefix')
48
+ end
49
+
50
+ assert_gets(
51
+ '/api/spy/histograms?sampling=0.05&histogram=my_prefix&host=h1'
52
+ ) do
53
+ wf.histograms(0.05, prefix: 'my_prefix', host: 'h1')
54
+ end
55
+
56
+ assert_gets('/api/spy/histograms?sampling=0.02&histogram=my_prefix&' \
57
+ 'histogramTagKey=the_tag') do
58
+ wf.histograms(0.02, prefix: 'my_prefix', tag_key: 'the_tag')
59
+ end
60
+
61
+ assert_gets('/api/spy/histograms?sampling=0.02&histogram=my_prefix&' \
62
+ 'histogramTagKey=tag1&histogramTagKey=tag2') do
63
+ wf.histograms(0.02, prefix: 'my_prefix', tag_key: %w[tag1 tag2])
64
+ end
65
+ end
66
+ end
67
+
68
+ def test_spans
69
+ capture_io do
70
+ assert_gets('/api/spy/spans?sampling=0.01') { wf.spans }
71
+ assert_gets('/api/spy/spans?sampling=0.05') { wf.spans(0.05) }
72
+
73
+ assert_gets('/api/spy/spans?sampling=0.05&name=my_prefix') do
74
+ wf.spans(0.05, prefix: 'my_prefix')
75
+ end
76
+
77
+ assert_gets(
78
+ '/api/spy/spans?sampling=0.05&name=my_prefix&host=h1'
79
+ ) do
80
+ wf.spans(0.05, prefix: 'my_prefix', host: 'h1')
81
+ end
82
+
83
+ assert_gets('/api/spy/spans?sampling=0.02&name=my_prefix&' \
84
+ 'spanTagKey=the_tag') do
85
+ wf.spans(0.02, prefix: 'my_prefix', tag_key: 'the_tag')
86
+ end
87
+
88
+ assert_gets('/api/spy/spans?sampling=0.02&name=my_prefix&' \
89
+ 'spanTagKey=tag1&spanTagKey=tag2') do
90
+ wf.spans(0.02, prefix: 'my_prefix', tag_key: %w[tag1 tag2])
91
+ end
92
+ end
93
+ end
94
+
95
+ def test_ids
96
+ capture_io do
97
+ assert_gets('/api/spy/ids?sampling=0.01') { wf.ids }
98
+ assert_gets('/api/spy/ids?sampling=0.05') { wf.ids(0.05) }
99
+
100
+ assert_gets('/api/spy/ids?sampling=0.05&type=METRIC') do
101
+ wf.ids(0.05, type: 'METRIC')
102
+ end
103
+
104
+ assert_gets('/api/spy/ids?sampling=0.05&type=SPAN&name=my_prefix') do
105
+ wf.ids(0.05, type: 'SPAN', prefix: 'my_prefix')
106
+ end
107
+ end
108
+ end
109
+
110
+ def dummy_response
111
+ DUMMY_RESPONSE
112
+ end
113
+ end
@@ -386,4 +386,19 @@ class WavefrontValidatorsTest < MiniTest::Test
386
386
  bad = ['', [], {}, 'a' * 1000]
387
387
  good_and_bad('wf_account_id?', 'InvalidAccountId', good, bad)
388
388
  end
389
+
390
+ def test_wf_managedcluster_id
391
+ good = %w[test-cluster other-cluster cluster]
392
+ bad = ['', [], {}, 'a' * 1000, '£"^WR"!']
393
+ good_and_bad('wf_monitoredcluster_id?',
394
+ 'InvalidMonitoredClusterId',
395
+ good,
396
+ bad)
397
+ end
398
+
399
+ def test_wf_sampling_value
400
+ good = [0, 0.01, 0.003, 0.05]
401
+ bad = ['a', 0.1, 0.99, 1, -1, 1.1]
402
+ good_and_bad('wf_sampling_value?', 'InvalidSamplingValue', good, bad)
403
+ end
389
404
  end
@@ -23,7 +23,7 @@ Gem::Specification.new do |gem|
23
23
  gem.bindir = 'bin'
24
24
 
25
25
  gem.add_dependency 'addressable', '~> 2.7'
26
- gem.add_dependency 'faraday', '~> 0.17.0'
26
+ gem.add_dependency 'faraday', '~> 1.0'
27
27
  gem.add_dependency 'inifile', '~> 3.0'
28
28
  gem.add_dependency 'map', '~> 6.6'
29
29
 
@@ -35,5 +35,5 @@ Gem::Specification.new do |gem|
35
35
  gem.add_development_dependency 'webmock', '~> 3.7'
36
36
  gem.add_development_dependency 'yard', '~> 0.9'
37
37
 
38
- gem.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
38
+ gem.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
39
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefront-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.1
4
+ version: 4.0.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: 2020-02-10 00:00:00.000000000 Z
11
+ date: 2020-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.17.0
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.17.0
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: inifile
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -205,6 +205,7 @@ files:
205
205
  - lib/wavefront-sdk/message.rb
206
206
  - lib/wavefront-sdk/metric.rb
207
207
  - lib/wavefront-sdk/metric_helper.rb
208
+ - lib/wavefront-sdk/monitoredcluster.rb
208
209
  - lib/wavefront-sdk/notificant.rb
209
210
  - lib/wavefront-sdk/paginator/base.rb
210
211
  - lib/wavefront-sdk/paginator/delete.rb
@@ -222,9 +223,14 @@ files:
222
223
  - lib/wavefront-sdk/stdlib/array.rb
223
224
  - lib/wavefront-sdk/stdlib/hash.rb
224
225
  - lib/wavefront-sdk/stdlib/string.rb
226
+ - lib/wavefront-sdk/stdlib/time.rb
225
227
  - lib/wavefront-sdk/support/mixins.rb
226
228
  - lib/wavefront-sdk/support/parse_time.rb
227
229
  - lib/wavefront-sdk/types/status.rb
230
+ - lib/wavefront-sdk/unstable/README.md
231
+ - lib/wavefront-sdk/unstable/chart.rb
232
+ - lib/wavefront-sdk/unstable/spy.rb
233
+ - lib/wavefront-sdk/unstable/unstable.rb
228
234
  - lib/wavefront-sdk/usage.rb
229
235
  - lib/wavefront-sdk/user.rb
230
236
  - lib/wavefront-sdk/usergroup.rb
@@ -270,6 +276,7 @@ files:
270
276
  - spec/wavefront-sdk/message_spec.rb
271
277
  - spec/wavefront-sdk/metric_helper_spec.rb
272
278
  - spec/wavefront-sdk/metric_spec.rb
279
+ - spec/wavefront-sdk/monitoredcluster_spec.rb
273
280
  - spec/wavefront-sdk/notificant_spec.rb
274
281
  - spec/wavefront-sdk/paginator/base_spec.rb
275
282
  - spec/wavefront-sdk/paginator/post_spec.rb
@@ -296,6 +303,8 @@ files:
296
303
  - spec/wavefront-sdk/stdlib/string_spec.rb
297
304
  - spec/wavefront-sdk/support/mixins_spec.rb
298
305
  - spec/wavefront-sdk/support/parse_time_spec.rb
306
+ - spec/wavefront-sdk/unstable/chart_spec.rb
307
+ - spec/wavefront-sdk/unstable/spy_spec.rb
299
308
  - spec/wavefront-sdk/usage_spec.rb
300
309
  - spec/wavefront-sdk/user_spec.rb
301
310
  - spec/wavefront-sdk/usergroup_spec.rb
@@ -320,7 +329,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
320
329
  requirements:
321
330
  - - ">="
322
331
  - !ruby/object:Gem::Version
323
- version: 2.3.0
332
+ version: 2.4.0
324
333
  required_rubygems_version: !ruby/object:Gem::Requirement
325
334
  requirements:
326
335
  - - ">="
@@ -365,6 +374,7 @@ test_files:
365
374
  - spec/wavefront-sdk/message_spec.rb
366
375
  - spec/wavefront-sdk/metric_helper_spec.rb
367
376
  - spec/wavefront-sdk/metric_spec.rb
377
+ - spec/wavefront-sdk/monitoredcluster_spec.rb
368
378
  - spec/wavefront-sdk/notificant_spec.rb
369
379
  - spec/wavefront-sdk/paginator/base_spec.rb
370
380
  - spec/wavefront-sdk/paginator/post_spec.rb
@@ -391,6 +401,8 @@ test_files:
391
401
  - spec/wavefront-sdk/stdlib/string_spec.rb
392
402
  - spec/wavefront-sdk/support/mixins_spec.rb
393
403
  - spec/wavefront-sdk/support/parse_time_spec.rb
404
+ - spec/wavefront-sdk/unstable/chart_spec.rb
405
+ - spec/wavefront-sdk/unstable/spy_spec.rb
394
406
  - spec/wavefront-sdk/usage_spec.rb
395
407
  - spec/wavefront-sdk/user_spec.rb
396
408
  - spec/wavefront-sdk/usergroup_spec.rb