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 +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +0 -1
- data/HISTORY.md +8 -0
- data/README.md +1 -1
- data/lib/wavefront-sdk/core/api_caller.rb +50 -7
- data/lib/wavefront-sdk/core/exception.rb +3 -0
- data/lib/wavefront-sdk/defs/version.rb +1 -3
- data/lib/wavefront-sdk/monitoredcluster.rb +93 -0
- data/lib/wavefront-sdk/stdlib/time.rb +13 -0
- data/lib/wavefront-sdk/unstable/README.md +4 -0
- data/lib/wavefront-sdk/unstable/chart.rb +90 -0
- data/lib/wavefront-sdk/unstable/spy.rb +134 -0
- data/lib/wavefront-sdk/unstable/unstable.rb +9 -0
- data/lib/wavefront-sdk/validators.rb +21 -0
- data/lib/wavefront-sdk/write.rb +9 -9
- data/spec/spec_helper.rb +4 -0
- data/spec/support/minitest_assertions.rb +4 -4
- data/spec/wavefront-sdk/core/api_caller_spec.rb +43 -0
- data/spec/wavefront-sdk/monitoredcluster_spec.rb +55 -0
- data/spec/wavefront-sdk/unstable/chart_spec.rb +39 -0
- data/spec/wavefront-sdk/unstable/spy_spec.rb +113 -0
- data/spec/wavefront-sdk/validators_spec.rb +15 -0
- data/wavefront-sdk.gemspec +2 -2
- metadata +17 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 578159c0ff0dac09b94caa4dac4e37f03436cb3e2b4cdda54886ce91b9ce4c9b
|
4
|
+
data.tar.gz: 93eac0630e97d53e3b26d222fd09df61f8cd7966c62e39520dbf27525982cb1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3f09ae6d818b0acc7e81e2e4da585c10a59efba18a4ab373679783d62b5a5ccc300e14435b7cbe8a0f2d64adec361e080c55f089732ffbb6c171f619524440e
|
7
|
+
data.tar.gz: d558a6d0eafe0d09120317113758ee70807cae035a7e9677a22cf643e537103ff66d671e7e6a031151cd03572f6b62a78e9aa92a86a2fb052f0cb31ba92c4f17
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
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.
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
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
|
@@ -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,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
|
@@ -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
|
data/lib/wavefront-sdk/write.rb
CHANGED
@@ -113,7 +113,7 @@ module Wavefront
|
|
113
113
|
# @return Wavefront::Response
|
114
114
|
#
|
115
115
|
def composite_response(responses)
|
116
|
-
result, code =
|
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
@@ -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:
|
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:
|
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:
|
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:
|
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
|
data/wavefront-sdk.gemspec
CHANGED
@@ -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', '~>
|
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.
|
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:
|
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-
|
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:
|
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:
|
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.
|
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
|