wavefront-sdk 3.7.1 → 4.0.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.
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