dogapi 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/.tailor +106 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +7 -0
- data/README.rdoc +4 -1
- data/Rakefile +31 -2
- data/lib/capistrano/datadog.rb +6 -10
- data/lib/dogapi/common.rb +1 -1
- data/lib/dogapi/event.rb +6 -6
- data/lib/dogapi/facade.rb +34 -45
- data/lib/dogapi/v1/alert.rb +1 -1
- data/lib/dogapi/v1/comment.rb +3 -3
- data/lib/dogapi/v1/dash.rb +1 -2
- data/lib/dogapi/v1/event.rb +1 -1
- data/lib/dogapi/v1/metric.rb +3 -3
- data/lib/dogapi/v1/user.rb +1 -1
- data/lib/dogapi/version.rb +1 -1
- data/spec/alerts_spec.rb +33 -0
- data/spec/common_spec.rb +16 -0
- data/spec/facade_spec.rb +122 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/cassettes/Alerts/create/returns_HTTP_code_201.yml +90 -0
- data/spec/support/cassettes/Alerts/create/returns_a_valid_event_ID.yml +90 -0
- data/spec/support/cassettes/Alerts/create/returns_the_same_query_as_sent.yml +90 -0
- data/spec/support/cassettes/Facade/Client/emit_point_can_pass_nil_host.yml +32 -0
- data/spec/support/cassettes/Facade/Client/emit_point_passes_data.yml +32 -0
- data/spec/support/cassettes/Facade/Client/emit_point_uses_localhost_default.yml +32 -0
- data/spec/support/cassettes/Facade/Client/emits_point_with_localhost.yml +32 -0
- data/spec/support/cassettes/Facade/Events/emits_aggregate_events.yml +131 -0
- data/spec/support/cassettes/Facade/Events/emits_events_and_retrieves_them.yml +67 -0
- data/spec/support/cassettes/Facade/Events/emits_events_with_specified_priority.yml +67 -0
- data/spec/support/cassettes/Facade/Tags/adds_updates_and_detaches_tags.yml +352 -0
- data/tests/test_alerts.rb +3 -3
- data/tests/test_client.rb +0 -114
- data/tests/test_dashes.rb +3 -2
- metadata +38 -7
data/lib/dogapi/v1/alert.rb
CHANGED
data/lib/dogapi/v1/comment.rb
CHANGED
@@ -8,7 +8,7 @@ module Dogapi
|
|
8
8
|
API_VERSION = "v1"
|
9
9
|
|
10
10
|
# Submit a comment.
|
11
|
-
def comment(message, options={})
|
11
|
+
def comment(message, options = {})
|
12
12
|
begin
|
13
13
|
params = {
|
14
14
|
:api_key => @api_key,
|
@@ -16,7 +16,7 @@ module Dogapi
|
|
16
16
|
}
|
17
17
|
|
18
18
|
body = {
|
19
|
-
|
19
|
+
'message' => message,
|
20
20
|
}.merge options
|
21
21
|
|
22
22
|
request(Net::HTTP::Post, "/api/#{API_VERSION}/comments", params, body, true)
|
@@ -26,7 +26,7 @@ module Dogapi
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Update a comment.
|
29
|
-
def update_comment(comment_id, options={})
|
29
|
+
def update_comment(comment_id, options = {})
|
30
30
|
begin
|
31
31
|
params = {
|
32
32
|
:api_key => @api_key,
|
data/lib/dogapi/v1/dash.rb
CHANGED
@@ -7,7 +7,7 @@ module Dogapi
|
|
7
7
|
|
8
8
|
API_VERSION = "v1"
|
9
9
|
|
10
|
-
def create_dashboard(title, description, graphs, template_variables=nil)
|
10
|
+
def create_dashboard(title, description, graphs, template_variables = nil)
|
11
11
|
|
12
12
|
begin
|
13
13
|
params = {
|
@@ -75,7 +75,6 @@ module Dogapi
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
78
|
def delete_dashboard(dash_id)
|
80
79
|
begin
|
81
80
|
params = {
|
data/lib/dogapi/v1/event.rb
CHANGED
data/lib/dogapi/v1/metric.rb
CHANGED
@@ -9,7 +9,7 @@ module Dogapi
|
|
9
9
|
API_VERSION = "v1"
|
10
10
|
|
11
11
|
# Records an Event with no duration
|
12
|
-
def submit(metric, points, scope, options={})
|
12
|
+
def submit(metric, points, scope, options = {})
|
13
13
|
begin
|
14
14
|
params = {
|
15
15
|
:api_key => @api_key
|
@@ -20,7 +20,8 @@ module Dogapi
|
|
20
20
|
raise ArgumentError, "metric type must be gauge or counter"
|
21
21
|
end
|
22
22
|
|
23
|
-
body = {
|
23
|
+
body = {
|
24
|
+
:series => [
|
24
25
|
{
|
25
26
|
:metric => metric,
|
26
27
|
:points => points,
|
@@ -31,7 +32,6 @@ module Dogapi
|
|
31
32
|
]
|
32
33
|
}
|
33
34
|
|
34
|
-
|
35
35
|
# Add tags if there are any
|
36
36
|
if not options[:tags].nil?
|
37
37
|
body[:series][0][:tags] = options[:tags]
|
data/lib/dogapi/v1/user.rb
CHANGED
data/lib/dogapi/version.rb
CHANGED
data/spec/alerts_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Alerts", :vcr => true do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@api_key = ENV["DATADOG_API_KEY"]
|
7
|
+
@app_key = ENV["DATADOG_APP_KEY"]
|
8
|
+
@dog = Dogapi::Client.new(@api_key, @app_key)
|
9
|
+
@query = 'avg(last_10m):avg:test.metric.metric{host:test.metric.host} > 5'
|
10
|
+
end
|
11
|
+
|
12
|
+
context "create" do
|
13
|
+
before(:each) do
|
14
|
+
@new_alert = @dog.alert(@query)
|
15
|
+
end
|
16
|
+
after(:each) do
|
17
|
+
@dog.delete_alert(@new_alert[1]['id'])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns HTTP code 201" do
|
21
|
+
expect(@new_alert[0]).to eq '201'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns a valid event ID" do
|
25
|
+
expect(@new_alert[1]['id']).to be_a(Fixnum)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns the same query as sent" do
|
29
|
+
expect(@new_alert[1]['query']).to eq @query
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/common_spec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Common" do
|
4
|
+
|
5
|
+
context "Scope" do
|
6
|
+
|
7
|
+
it "validates the Scope class" do
|
8
|
+
obj = Dogapi::Scope.new("somehost", "somedevice")
|
9
|
+
|
10
|
+
expect(obj.host).to eq "somehost"
|
11
|
+
expect(obj.device).to eq "somedevice"
|
12
|
+
end
|
13
|
+
|
14
|
+
end # end Scope
|
15
|
+
|
16
|
+
end # end Common
|
data/spec/facade_spec.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Facade", :vcr => true do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@api_key = ENV["DATADOG_API_KEY"]
|
7
|
+
@app_key = ENV["DATADOG_APP_KEY"]
|
8
|
+
@job_number = ENV['TRAVIS_JOB_NUMBER'] || '1'
|
9
|
+
@dog = Dogapi::Client.new(@api_key, @app_key)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Client" do
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@dogmock = Dogapi::Client.new(@api_key, @app_key)
|
16
|
+
@metric_svc = double
|
17
|
+
@dogmock.instance_variable_set("@metric_svc", @metric_svc)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "emit_point passes data" do
|
21
|
+
expect(@metric_svc).to receive(:submit) do |metric, points, scope, options|
|
22
|
+
expect(metric).to eq "metric.name"
|
23
|
+
expect(points[0][1]).to eq 0
|
24
|
+
expect(scope.host).to eq "myhost"
|
25
|
+
end
|
26
|
+
@dogmock.emit_point("metric.name", 0, :host => "myhost")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "emit_point uses localhost default" do
|
30
|
+
expect(@metric_svc).to receive(:submit) do |metric, points, scope, options|
|
31
|
+
expect(scope.host).to eq Dogapi.find_localhost
|
32
|
+
end
|
33
|
+
@dogmock.emit_point("metric.name", 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "emit_point can pass nil host" do
|
37
|
+
expect(@metric_svc).to receive(:submit) do |metric, points, scope, options|
|
38
|
+
expect(scope.host).to be_nil
|
39
|
+
end
|
40
|
+
@dogmock.emit_point("metric.name", 0, :host => nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "Events" do
|
46
|
+
|
47
|
+
it "emits events and retrieves them" do
|
48
|
+
now = Time.now()
|
49
|
+
|
50
|
+
# Tag the events with the build number, because Travis parallel testing
|
51
|
+
# can cause problems with the event stream
|
52
|
+
tags = ["test-run:#{@job_number}"]
|
53
|
+
|
54
|
+
now_ts = now
|
55
|
+
now_title = 'dogapi-rb end test title ' + now_ts.to_i.to_s
|
56
|
+
now_message = 'test message'
|
57
|
+
|
58
|
+
|
59
|
+
event = Dogapi::Event.new(now_message, :msg_title => now_title,
|
60
|
+
:date_happened => now_ts, :tags => tags)
|
61
|
+
|
62
|
+
code, resp = @dog.emit_event(event)
|
63
|
+
now_event_id = resp["event"]["id"]
|
64
|
+
|
65
|
+
code, resp = @dog.get_event(now_event_id)
|
66
|
+
expect(resp['event']).not_to be_nil
|
67
|
+
expect(resp['event']['text']).to eq(now_message)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "emits events with specified priority" do
|
71
|
+
event = Dogapi::Event.new('test message', :msg_title => 'title', :date_happened => Time.now(), :priority => "low")
|
72
|
+
code, resp = @dog.emit_event(event)
|
73
|
+
low_event_id = resp["event"]["id"]
|
74
|
+
|
75
|
+
code, resp = @dog.get_event(low_event_id)
|
76
|
+
expect(resp['event']).not_to be_nil
|
77
|
+
low_event = resp['event']
|
78
|
+
expect(low_event['priority']).to eq("low")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "emits aggregate events" do
|
82
|
+
now = Time.now()
|
83
|
+
code, resp = @dog.emit_event(Dogapi::Event.new("Testing Aggregation (first)", :aggregation_key => now.to_i))
|
84
|
+
first = resp["event"]["id"]
|
85
|
+
code, resp = @dog.emit_event(Dogapi::Event.new("Testing Aggregation (second)", :aggregation_key => now.to_i))
|
86
|
+
second = resp["event"]["id"]
|
87
|
+
|
88
|
+
code, resp = @dog.get_event(first)
|
89
|
+
expect(resp["event"]).not_to be_nil
|
90
|
+
code, resp = @dog.get_event(second)
|
91
|
+
expect(resp["event"]).not_to be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context "Tags" do
|
97
|
+
it "adds, updates and detaches tags" do
|
98
|
+
hostname = "test.tag.host"
|
99
|
+
|
100
|
+
@dog.emit_point('test.tag.metric', 1, :host => hostname)
|
101
|
+
|
102
|
+
@dog.detach_tags(hostname)
|
103
|
+
code, resp = @dog.host_tags(hostname)
|
104
|
+
expect(resp["tags"]).to be_empty
|
105
|
+
|
106
|
+
@dog.add_tags(hostname, ['test.tag.1', 'test.tag.2'])
|
107
|
+
code, resp = @dog.host_tags(hostname)
|
108
|
+
new_tags = resp["tags"]
|
109
|
+
expect(new_tags).to match_array(['test.tag.1', 'test.tag.2'])
|
110
|
+
|
111
|
+
@dog.add_tags(hostname, ['test.tag.3'])
|
112
|
+
code, resp = @dog.host_tags(hostname)
|
113
|
+
new_tags = resp["tags"]
|
114
|
+
expect(new_tags).to match_array(['test.tag.1', 'test.tag.2', 'test.tag.3'])
|
115
|
+
|
116
|
+
@dog.detach_tags(hostname)
|
117
|
+
code, resp = @dog.host_tags(hostname)
|
118
|
+
expect(resp["tags"]).to be_empty
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'vcr'
|
3
|
+
|
4
|
+
# include our code and methods
|
5
|
+
require 'dogapi'
|
6
|
+
|
7
|
+
# Load any custom matchers
|
8
|
+
Dir[File.join(File.dirname(__FILE__), "/support/**/*.rb")].each { |f| require f }
|
9
|
+
|
10
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
config.filter_run :focus
|
15
|
+
|
16
|
+
# Run specs in random order to surface order dependencies. If you find an
|
17
|
+
# order dependency and want to debug it, you can fix the order by providing
|
18
|
+
# the seed, which is printed after each run.
|
19
|
+
# --seed 1234
|
20
|
+
config.order = 'random'
|
21
|
+
end
|
22
|
+
|
23
|
+
VCR.configure do |c|
|
24
|
+
c.cassette_library_dir = 'spec/support/cassettes'
|
25
|
+
c.configure_rspec_metadata!
|
26
|
+
c.default_cassette_options = { :record => :new_episodes, :re_record_interval => 2592000 } # 30 days, in seconds
|
27
|
+
c.hook_into :webmock
|
28
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://app.datadoghq.com/api/v1/alert?api_key=9775a026f1ca7d1c6c5af9d94d9595a4&application_key=87ce4a24b5553d2e482ea8a8500e71b8ad4554ff
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: ! '{"query":"avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
9
|
+
> 5"}'
|
10
|
+
headers:
|
11
|
+
Accept:
|
12
|
+
- ! '*/*'
|
13
|
+
User-Agent:
|
14
|
+
- Ruby
|
15
|
+
Content-Type:
|
16
|
+
- application/json
|
17
|
+
response:
|
18
|
+
status:
|
19
|
+
code: 201
|
20
|
+
message: Created
|
21
|
+
headers:
|
22
|
+
Cache-Control:
|
23
|
+
- no-cache
|
24
|
+
Content-Type:
|
25
|
+
- application/json
|
26
|
+
Date:
|
27
|
+
- Tue, 27 Aug 2013 16:13:42 GMT
|
28
|
+
Pragma:
|
29
|
+
- no-cache
|
30
|
+
Server:
|
31
|
+
- gunicorn/0.17.4
|
32
|
+
Set-Cookie:
|
33
|
+
- user={"org":{"id":1499},"_type":"User","id":3658}; Path=/
|
34
|
+
X-Dd-Version:
|
35
|
+
- 31.153-293-3859d5c
|
36
|
+
Content-Length:
|
37
|
+
- '328'
|
38
|
+
Connection:
|
39
|
+
- keep-alive
|
40
|
+
body:
|
41
|
+
encoding: US-ASCII
|
42
|
+
string: ! '{"notify_no_data": false, "event_object": "6bc5a22ffc9d267c3cd6eb3ad79623e0",
|
43
|
+
"state": "OK", "name": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
44
|
+
> 5", "silenced": false, "query": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
45
|
+
> 5", "message": null, "creator": 3658, "id": 37498, "timeout_h": null}'
|
46
|
+
http_version:
|
47
|
+
recorded_at: Tue, 27 Aug 2013 16:13:42 GMT
|
48
|
+
- request:
|
49
|
+
method: delete
|
50
|
+
uri: https://app.datadoghq.com/api/v1/alert/37498?api_key=9775a026f1ca7d1c6c5af9d94d9595a4&application_key=87ce4a24b5553d2e482ea8a8500e71b8ad4554ff
|
51
|
+
body:
|
52
|
+
encoding: US-ASCII
|
53
|
+
string: ''
|
54
|
+
headers:
|
55
|
+
Accept:
|
56
|
+
- ! '*/*'
|
57
|
+
User-Agent:
|
58
|
+
- Ruby
|
59
|
+
response:
|
60
|
+
status:
|
61
|
+
code: 200
|
62
|
+
message: OK
|
63
|
+
headers:
|
64
|
+
Cache-Control:
|
65
|
+
- no-cache
|
66
|
+
Content-Type:
|
67
|
+
- application/json
|
68
|
+
Date:
|
69
|
+
- Tue, 27 Aug 2013 16:13:42 GMT
|
70
|
+
Pragma:
|
71
|
+
- no-cache
|
72
|
+
Server:
|
73
|
+
- gunicorn/0.17.4
|
74
|
+
Set-Cookie:
|
75
|
+
- user={"org":{"id":1499},"_type":"User","id":3658}; Path=/
|
76
|
+
X-Dd-Version:
|
77
|
+
- 31.153-293-3859d5c
|
78
|
+
Content-Length:
|
79
|
+
- '315'
|
80
|
+
Connection:
|
81
|
+
- keep-alive
|
82
|
+
body:
|
83
|
+
encoding: US-ASCII
|
84
|
+
string: ! '{"notify_no_data": false, "event_object": "6bc5a22ffc9d267c3cd6eb3ad79623e0",
|
85
|
+
"state": "OK", "name": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
86
|
+
> 5", "silenced": false, "query": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
87
|
+
> 5", "message": null, "creator": 3658, "timeout_h": null}'
|
88
|
+
http_version:
|
89
|
+
recorded_at: Tue, 27 Aug 2013 16:13:42 GMT
|
90
|
+
recorded_with: VCR 2.5.0
|
@@ -0,0 +1,90 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://app.datadoghq.com/api/v1/alert?api_key=9775a026f1ca7d1c6c5af9d94d9595a4&application_key=87ce4a24b5553d2e482ea8a8500e71b8ad4554ff
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: ! '{"query":"avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
9
|
+
> 5"}'
|
10
|
+
headers:
|
11
|
+
Accept:
|
12
|
+
- ! '*/*'
|
13
|
+
User-Agent:
|
14
|
+
- Ruby
|
15
|
+
Content-Type:
|
16
|
+
- application/json
|
17
|
+
response:
|
18
|
+
status:
|
19
|
+
code: 201
|
20
|
+
message: Created
|
21
|
+
headers:
|
22
|
+
Cache-Control:
|
23
|
+
- no-cache
|
24
|
+
Content-Type:
|
25
|
+
- application/json
|
26
|
+
Date:
|
27
|
+
- Tue, 27 Aug 2013 16:13:42 GMT
|
28
|
+
Pragma:
|
29
|
+
- no-cache
|
30
|
+
Server:
|
31
|
+
- gunicorn/0.17.4
|
32
|
+
Set-Cookie:
|
33
|
+
- user={"org":{"id":1499},"_type":"User","id":3658}; Path=/
|
34
|
+
X-Dd-Version:
|
35
|
+
- 31.153-293-3859d5c
|
36
|
+
Content-Length:
|
37
|
+
- '328'
|
38
|
+
Connection:
|
39
|
+
- keep-alive
|
40
|
+
body:
|
41
|
+
encoding: US-ASCII
|
42
|
+
string: ! '{"notify_no_data": false, "event_object": "6bc5a22ffc9d267c3cd6eb3ad79623e0",
|
43
|
+
"state": "OK", "name": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
44
|
+
> 5", "silenced": false, "query": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
45
|
+
> 5", "message": null, "creator": 3658, "id": 37497, "timeout_h": null}'
|
46
|
+
http_version:
|
47
|
+
recorded_at: Tue, 27 Aug 2013 16:13:41 GMT
|
48
|
+
- request:
|
49
|
+
method: delete
|
50
|
+
uri: https://app.datadoghq.com/api/v1/alert/37497?api_key=9775a026f1ca7d1c6c5af9d94d9595a4&application_key=87ce4a24b5553d2e482ea8a8500e71b8ad4554ff
|
51
|
+
body:
|
52
|
+
encoding: US-ASCII
|
53
|
+
string: ''
|
54
|
+
headers:
|
55
|
+
Accept:
|
56
|
+
- ! '*/*'
|
57
|
+
User-Agent:
|
58
|
+
- Ruby
|
59
|
+
response:
|
60
|
+
status:
|
61
|
+
code: 200
|
62
|
+
message: OK
|
63
|
+
headers:
|
64
|
+
Cache-Control:
|
65
|
+
- no-cache
|
66
|
+
Content-Type:
|
67
|
+
- application/json
|
68
|
+
Date:
|
69
|
+
- Tue, 27 Aug 2013 16:13:42 GMT
|
70
|
+
Pragma:
|
71
|
+
- no-cache
|
72
|
+
Server:
|
73
|
+
- gunicorn/0.17.4
|
74
|
+
Set-Cookie:
|
75
|
+
- user={"org":{"id":1499},"_type":"User","id":3658}; Path=/
|
76
|
+
X-Dd-Version:
|
77
|
+
- 31.153-293-3859d5c
|
78
|
+
Content-Length:
|
79
|
+
- '315'
|
80
|
+
Connection:
|
81
|
+
- keep-alive
|
82
|
+
body:
|
83
|
+
encoding: US-ASCII
|
84
|
+
string: ! '{"notify_no_data": false, "event_object": "6bc5a22ffc9d267c3cd6eb3ad79623e0",
|
85
|
+
"state": "OK", "name": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
86
|
+
> 5", "silenced": false, "query": "avg(last_10m):avg:test.metric.metric{host:test.metric.host}
|
87
|
+
> 5", "message": null, "creator": 3658, "timeout_h": null}'
|
88
|
+
http_version:
|
89
|
+
recorded_at: Tue, 27 Aug 2013 16:13:42 GMT
|
90
|
+
recorded_with: VCR 2.5.0
|