sumo-search 2.0.3 → 2.1.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 +4 -4
- data/lib/sumo/client.rb +42 -9
- data/lib/sumo/version.rb +2 -2
- data/spec/lib/sumo/client_spec.rb +113 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34911b9efb6c328c089cda2f45d3b6ddbe941c98
|
4
|
+
data.tar.gz: 9ff1594f807e696be3b703609f322289cff41c52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 367766f8515371162e4be5bdffffc4d2f805e363fae0265640e0e7f655ce96531e1e4312d46d3944e0683cf6f6cd90484474faa20a29d5913294f544695621d9
|
7
|
+
data.tar.gz: 6c812fc6cc43eb95156b825a51e4ea9a1f54c609a98ffa66c684d4c9e86af289973b2da77da52ddef3ac08366193dc1ee8973db912b3441e066ca55c12bf5d61
|
data/lib/sumo/client.rb
CHANGED
@@ -4,6 +4,8 @@ class Sumo::Client
|
|
4
4
|
|
5
5
|
attr_reader :email, :password, :cookie
|
6
6
|
|
7
|
+
REDIRECT_STATUSES = [301, 302, 303, 307, 308]
|
8
|
+
|
7
9
|
# The error message raised when the result can be parsed from Sumo.
|
8
10
|
DEFAULT_ERROR_MESSAGE = 'Error sending API request'
|
9
11
|
|
@@ -13,13 +15,25 @@ class Sumo::Client
|
|
13
15
|
@password = credentials['password'].freeze
|
14
16
|
end
|
15
17
|
|
16
|
-
# Send a
|
18
|
+
# Send a request to the API and retrieve processed data.
|
17
19
|
def request(hash, &block)
|
18
|
-
|
20
|
+
handle_request(hash, &block).body
|
21
|
+
end
|
22
|
+
|
23
|
+
# Send a HTTP request to the server, handling any errors that may occur.
|
24
|
+
def handle_request(hash, endpoint = nil, depth = 0, &block)
|
25
|
+
response = connection(endpoint).request(add_defaults(hash), &block)
|
26
|
+
|
27
|
+
if REDIRECT_STATUSES.include?(response.status) &&
|
28
|
+
response.headers['Location']
|
29
|
+
response = handle_redirect(response, hash, depth, &block)
|
30
|
+
end
|
31
|
+
|
19
32
|
handle_errors!(response)
|
20
33
|
set_cookie!(response)
|
21
|
-
response
|
34
|
+
response
|
22
35
|
end
|
36
|
+
private :handle_request
|
23
37
|
|
24
38
|
# Define methods for the HTTP methods used by the API (#get, #post, and
|
25
39
|
# #delete).
|
@@ -32,13 +46,27 @@ class Sumo::Client
|
|
32
46
|
# Private functions that operate on the request and response.
|
33
47
|
|
34
48
|
def add_defaults(hash)
|
35
|
-
hash.merge(
|
36
|
-
|
37
|
-
:path
|
38
|
-
|
49
|
+
hash[:headers] = default_headers.merge(hash[:headers] || {})
|
50
|
+
hash[:path] = "/api/v#{Sumo::API_VERSION}#{hash[:path]}" unless
|
51
|
+
hash[:path].index("/api/v#{Sumo::API_VERSION}") == 0
|
52
|
+
hash
|
39
53
|
end
|
40
54
|
private :add_defaults
|
41
55
|
|
56
|
+
# Recursively handle redirection up to 10 level depth
|
57
|
+
def handle_redirect(response, hash, depth, &block)
|
58
|
+
fail 'Too many redirections.' if depth > 9
|
59
|
+
|
60
|
+
endpoint = response.headers['Location']
|
61
|
+
.match(%r{^(https://.+\.[a-z]+)/}).to_a[1]
|
62
|
+
|
63
|
+
depth += 1
|
64
|
+
# I tried to blindly follow redirection path, but it omits the job ID.
|
65
|
+
# hash[:path] = path
|
66
|
+
handle_request(hash, endpoint, depth, &block)
|
67
|
+
end
|
68
|
+
private :handle_redirect
|
69
|
+
|
42
70
|
def handle_errors!(response)
|
43
71
|
case response.status
|
44
72
|
when 400..499 then raise ClientError, extract_error_message(response.body)
|
@@ -79,8 +107,13 @@ class Sumo::Client
|
|
79
107
|
end
|
80
108
|
private :creds
|
81
109
|
|
82
|
-
def connection
|
83
|
-
@
|
110
|
+
def connection(endpoint = nil)
|
111
|
+
@connections ||= {}
|
112
|
+
endpoint ||= 'https://api.sumologic.com'
|
113
|
+
|
114
|
+
fail 'Base url out of allowed domain.' unless
|
115
|
+
endpoint.match(%r{^https://.+\.sumologic\.com$})
|
116
|
+
@connections[endpoint] ||= Excon.new(endpoint)
|
84
117
|
end
|
85
118
|
private :connection
|
86
119
|
end
|
data/lib/sumo/version.rb
CHANGED
@@ -46,6 +46,7 @@ describe Sumo::Client do
|
|
46
46
|
subject.stub(:handle_errors!)
|
47
47
|
response.stub(:body)
|
48
48
|
response.stub(:headers).and_return({})
|
49
|
+
response.stub(:status).and_return(200)
|
49
50
|
connection.should_receive(:request)
|
50
51
|
.with(
|
51
52
|
:method => :get,
|
@@ -134,6 +135,118 @@ describe Sumo::Client do
|
|
134
135
|
end
|
135
136
|
end
|
136
137
|
end
|
138
|
+
|
139
|
+
context 'when a 3xx-level status code is returned by the API' do
|
140
|
+
let(:cookie) { 'oreo' }
|
141
|
+
let(:headers) { {'Set-Cookie' => cookie } }
|
142
|
+
let(:default_connection) { double(:default_connection) }
|
143
|
+
let(:redirect_connection) { double(:redirect_connection) }
|
144
|
+
|
145
|
+
before do
|
146
|
+
# Do not stub full connection method but only Excon.
|
147
|
+
subject.stub(:connection).and_call_original
|
148
|
+
default_connection.stub(:request).and_return(response)
|
149
|
+
allow(Excon).to receive(:new)
|
150
|
+
.with('https://api.sumologic.com').and_return default_connection
|
151
|
+
allow(Excon).to receive(:new)
|
152
|
+
.with('https://api.us2.sumologic.com').and_return redirect_connection
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'and the redirection url is within sumologic domain' do
|
156
|
+
let(:response) do
|
157
|
+
double(:response, :status => 301, :body => '', :headers => {
|
158
|
+
'Location' => 'https://api.us2.sumologic.com/api/v1/jobs'
|
159
|
+
})
|
160
|
+
end
|
161
|
+
let(:final_response) do
|
162
|
+
double(:response, :status => 200, :body => '', :headers => {})
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should follow it' do
|
166
|
+
expect(default_connection).to receive(:request)
|
167
|
+
.with(
|
168
|
+
:method => :get,
|
169
|
+
:path => '/api/v1/',
|
170
|
+
:headers => {
|
171
|
+
'Content-Type' => 'application/json',
|
172
|
+
'Accept' => 'application/json',
|
173
|
+
'Authorization' => "Basic #{encoded}" })
|
174
|
+
.and_return(response)
|
175
|
+
|
176
|
+
expect(redirect_connection).to receive(:request)
|
177
|
+
.with(
|
178
|
+
:method => :get,
|
179
|
+
:path => '/api/v1/',
|
180
|
+
:headers => {
|
181
|
+
'Content-Type' => 'application/json',
|
182
|
+
'Accept' => 'application/json',
|
183
|
+
'Authorization' => "Basic #{encoded}" })
|
184
|
+
.and_return(final_response)
|
185
|
+
subject.request(:method => :get, :path => '/')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'and the redirection url is outside of sumologic' do
|
190
|
+
let(:response) do
|
191
|
+
double(:response, :status => 301, :body => '', :headers => {
|
192
|
+
'Location' => 'https://donotfollow.me/api/v1/jobs'
|
193
|
+
})
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should not follow it' do
|
197
|
+
expect(default_connection).to receive(:request)
|
198
|
+
.with(
|
199
|
+
:method => :get,
|
200
|
+
:path => '/api/v1/',
|
201
|
+
:headers => {
|
202
|
+
'Content-Type' => 'application/json',
|
203
|
+
'Accept' => 'application/json',
|
204
|
+
'Authorization' => "Basic #{encoded}" })
|
205
|
+
.once
|
206
|
+
.and_return(response)
|
207
|
+
expect(Excon).not_to receive(:new)
|
208
|
+
.with('https://donotfollow.me')
|
209
|
+
expect do
|
210
|
+
subject.request(:method => :get, :path => '/')
|
211
|
+
end.to raise_error 'Base url out of allowed domain.'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'and there is a redirection loop' do
|
216
|
+
let(:response) do
|
217
|
+
double(:response, :status => 301, :body => '', :headers => {
|
218
|
+
'Location' => 'https://api.us2.sumologic.com/api/v1/jobs'
|
219
|
+
})
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should throw a too many redirections error' do
|
223
|
+
expect(default_connection).to receive(:request)
|
224
|
+
.with(
|
225
|
+
:method => :get,
|
226
|
+
:path => '/api/v1/',
|
227
|
+
:headers => {
|
228
|
+
'Content-Type' => 'application/json',
|
229
|
+
'Accept' => 'application/json',
|
230
|
+
'Authorization' => "Basic #{encoded}" })
|
231
|
+
.and_return(response)
|
232
|
+
|
233
|
+
expect(redirect_connection).to receive(:request)
|
234
|
+
.with(
|
235
|
+
:method => :get,
|
236
|
+
:path => '/api/v1/',
|
237
|
+
:headers => {
|
238
|
+
'Content-Type' => 'application/json',
|
239
|
+
'Accept' => 'application/json',
|
240
|
+
'Authorization' => "Basic #{encoded}" })
|
241
|
+
.exactly(10).times
|
242
|
+
.and_return(response)
|
243
|
+
|
244
|
+
expect do
|
245
|
+
subject.request(:method => :get, :path => '/')
|
246
|
+
end.to raise_error 'Too many redirections.'
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
137
250
|
end
|
138
251
|
|
139
252
|
[:get, :post, :delete].each do |http_method|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sumo-search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Swipely, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: excon
|