ruby-requests 0.0.1.a1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.gitlab-ci.yml +37 -0
- data/.rubocop-disables.yml +96 -0
- data/.rubocop.yml +9 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/Makefile +17 -0
- data/README.md +151 -0
- data/lib/requests.rb +95 -0
- data/lib/requests/adapters.rb +124 -0
- data/lib/requests/cookies.rb +98 -0
- data/lib/requests/exceptions.rb +32 -0
- data/lib/requests/http_methods.rb +36 -0
- data/lib/requests/logger.rb +37 -0
- data/lib/requests/request.rb +94 -0
- data/lib/requests/response.rb +93 -0
- data/lib/requests/session.rb +120 -0
- data/lib/requests/utils.rb +162 -0
- data/lib/requests/version.rb +4 -0
- data/ruby-requests.gemspec +23 -0
- data/spec/docker-compose.yml +23 -0
- data/spec/docker_test_entrypoint.sh +12 -0
- data/spec/docker_tests.sh +6 -0
- data/spec/functional/proxies/proxies_spec.rb +84 -0
- data/spec/functional/proxies/squid_conf/passwords +2 -0
- data/spec/functional/proxies/squid_conf/squid.conf +11 -0
- data/spec/functional/requests_spec.rb +326 -0
- data/spec/functional/session_spec.rb +111 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/unit/api_spec.rb +42 -0
- data/spec/unit/utils_spec.rb +112 -0
- metadata +131 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
auth_param basic program /usr/lib/squid3/basic_ncsa_auth /etc/squid3/passwords
|
2
|
+
auth_param basic realm proxy
|
3
|
+
acl authenticated proxy_auth REQUIRED
|
4
|
+
http_access allow authenticated
|
5
|
+
|
6
|
+
http_port 3128
|
7
|
+
|
8
|
+
cache_dir ufs /var/spool/squid3 100 16 256
|
9
|
+
coredump_dir /var/spool/squid3
|
10
|
+
|
11
|
+
access_log stdio:/var/log/squid3/access.log squid
|
@@ -0,0 +1,326 @@
|
|
1
|
+
|
2
|
+
require 'rspec'
|
3
|
+
require 'base64'
|
4
|
+
require 'openssl'
|
5
|
+
require_relative '../spec_helper'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Requests do
|
9
|
+
reset_log
|
10
|
+
display_verbose_log
|
11
|
+
|
12
|
+
shared_examples "bad SSL certificates" do |method|
|
13
|
+
it "raises exception on self-signed cert" do
|
14
|
+
url = BADSSL_URLS['self-signed']
|
15
|
+
expect {
|
16
|
+
Requests.send(method, url)
|
17
|
+
}.to raise_error(OpenSSL::SSL::SSLError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "doesn't raise exception when verify: false" do
|
21
|
+
url = BADSSL_URLS['self-signed']
|
22
|
+
expect {
|
23
|
+
Requests.send(method, url, verify: false)
|
24
|
+
}.not_to raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_examples "redirects" do |method, protocol, httpbin|
|
29
|
+
it "#{protocol} follows redirect with allow_redirects: true" do
|
30
|
+
skip "Not implemented yet"
|
31
|
+
url = httpbin + '/redirect-to'
|
32
|
+
payload = {'url' => 'http://example.com'}
|
33
|
+
resp = Requests.send(method, url, params: payload,
|
34
|
+
allow_redirects: true)
|
35
|
+
expect(resp.status_code).to eq(200)
|
36
|
+
expect(resp.url).to eq('http://example.com')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "#{protocol} doesn't follow redirect with allow_redirects: false" do
|
40
|
+
url = httpbin + '/redirect-to'
|
41
|
+
payload = {'url' => 'http://example.com'}
|
42
|
+
resp = Requests.send(method, url, params: payload,
|
43
|
+
allow_redirects: false)
|
44
|
+
expect(resp.status_code).to eq(302)
|
45
|
+
full_url = url + '?' + URI.encode_www_form(payload)
|
46
|
+
expect(resp.url).to eq(full_url)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
shared_examples "all methods" do |method, protocol, httpbin|
|
51
|
+
it "#{protocol} sets url attribute on the response" do
|
52
|
+
url = httpbin + '/anything'
|
53
|
+
resp = Requests.send(method, url)
|
54
|
+
expect(resp.url).to eq(url)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "uses timeout" do
|
58
|
+
url = httpbin + '/anything'
|
59
|
+
expect {
|
60
|
+
Requests.send(method, url, timeout: [0.00001, 2])
|
61
|
+
}.to raise_error(Requests::ConnectionTimeout)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
shared_examples "methods with response body" do |method, protocol, httpbin|
|
66
|
+
let(:url) { httpbin + '/anything' }
|
67
|
+
|
68
|
+
it "#{protocol} makes request" do
|
69
|
+
resp = Requests.send(method, url)
|
70
|
+
received_headers = Requests::Utils::InsensitiveDict
|
71
|
+
.new(resp.json['headers'])
|
72
|
+
expect(resp.json['args']).to eq({})
|
73
|
+
user_agent = received_headers['User-Agent']
|
74
|
+
expect(user_agent).to eq(Requests::Utils.default_user_agent)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#{protocol} sends query string params" do
|
78
|
+
payload = {
|
79
|
+
'example_key' => 'example_value',
|
80
|
+
'other_key' => 'other_value',
|
81
|
+
'another_key' => ['this', 'is', 'an', 'array'],
|
82
|
+
}
|
83
|
+
resp = Requests.send(method, url, params: payload)
|
84
|
+
expect(resp.json['args']).to eq(payload)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "#{protocol} sends headers" do
|
88
|
+
headers = {
|
89
|
+
'Header-Name' => 'header value',
|
90
|
+
'Other-Header' => 'other value',
|
91
|
+
'lowercase-header' => 'should still match',
|
92
|
+
'User-Agent' => 'Mozilla whatever',
|
93
|
+
}
|
94
|
+
resp = Requests.send(method, url, headers: headers)
|
95
|
+
sent_headers = Requests::Utils::InsensitiveDict
|
96
|
+
.new(resp.json['headers'])
|
97
|
+
headers.each do |k, v|
|
98
|
+
expect(sent_headers[k]).to eq(v)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "#{protocol} sends cookies" do
|
103
|
+
cookies = {
|
104
|
+
'chocolate' => 'chip',
|
105
|
+
'oatmeal' => 'raisin hell',
|
106
|
+
}
|
107
|
+
resp = Requests.send(method, url, cookies: cookies)
|
108
|
+
sent_cookies = resp.json['headers']['Cookie']
|
109
|
+
expect(sent_cookies).to include('chocolate=chip')
|
110
|
+
expect(sent_cookies).to include('oatmeal="raisin hell"')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
shared_examples "GET method" do |protocol, httpbin|
|
115
|
+
it "#{protocol} sends basic auth" do
|
116
|
+
url = httpbin + '/basic-auth/testuser/testpassword'
|
117
|
+
resp = Requests.get(url, auth: ['testuser', 'testpassword'])
|
118
|
+
expect(resp.status_code).to eq(200)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "uses timeout" do
|
122
|
+
url = httpbin + '/delay/60'
|
123
|
+
expect {
|
124
|
+
Requests.get(url, timeout: 2)
|
125
|
+
}.to raise_error(Requests::TimeoutError)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "#{protocol} decodes gzip" do
|
129
|
+
url = httpbin + '/gzip'
|
130
|
+
resp = Requests.get(url, headers: {'Test-Header' => 'value'})
|
131
|
+
expect(resp.json['headers']['Test-Header']).to eq('value')
|
132
|
+
end
|
133
|
+
|
134
|
+
it "#{protocol} decodes deflate" do
|
135
|
+
url = httpbin + '/deflate'
|
136
|
+
resp = Requests.get(url, headers: {'Test-Header' => 'value'})
|
137
|
+
expect(resp.json['headers']['Test-Header']).to eq('value')
|
138
|
+
end
|
139
|
+
|
140
|
+
it "#{protocol} sets response cookies from Set-Cookie header" do
|
141
|
+
url = httpbin + '/cookies/set'
|
142
|
+
set_cookies = {
|
143
|
+
'macadamia' => 'nut',
|
144
|
+
'peanut' => 'butter',
|
145
|
+
}
|
146
|
+
resp = Requests.get(url, params: set_cookies,
|
147
|
+
allow_redirects: false)
|
148
|
+
expect(resp.cookies_hash).to eq(set_cookies)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "#{protocol} handles unicode" do
|
152
|
+
url = httpbin + '/encoding/utf8'
|
153
|
+
unicode_str = "Зарегистрируйтесь сейчас на"
|
154
|
+
r = Requests.get(url)
|
155
|
+
expect(r.text).to include(unicode_str)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
shared_examples "methods with request body" do |method, protocol, httpbin|
|
160
|
+
let(:url) { httpbin + '/anything' }
|
161
|
+
|
162
|
+
it "#{protocol} sends json object as body" do
|
163
|
+
json_payload = {
|
164
|
+
'some' => 'thing',
|
165
|
+
'that' => ['can', 'be', 'encoded'],
|
166
|
+
'as' => {'json' => true},
|
167
|
+
}
|
168
|
+
resp = Requests.send(method, url, json: json_payload)
|
169
|
+
expect(resp.json['json']).to eq(json_payload)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "#{protocol} sends json array as body" do
|
173
|
+
json_payload = ['some', 'list', 'of', 7, {'items' => [1, 42]}]
|
174
|
+
resp = Requests.send(method, url, json: json_payload)
|
175
|
+
expect(resp.json['json']).to eq(json_payload)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "#{protocol} sends data string as body" do
|
179
|
+
data = "Some sample data\nthat isn't JSON\n"
|
180
|
+
resp = Requests.send(method, url, data: data)
|
181
|
+
expect(resp.json['data']).to eq(data)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "#{protocol} sends data hash as form-urlencoded" do
|
185
|
+
data = {
|
186
|
+
"key a" => "value a",
|
187
|
+
"key b" => "value b",
|
188
|
+
}
|
189
|
+
resp = Requests.send(method, url, data: data)
|
190
|
+
expect(resp.json['form']).to eq(data)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "#{protocol} sends data array as form-urlencoded" do
|
194
|
+
data = [["key a", "value a"],
|
195
|
+
["key b", "value b"]]
|
196
|
+
expected = {
|
197
|
+
"key a" => "value a",
|
198
|
+
"key b" => "value b",
|
199
|
+
}
|
200
|
+
resp = Requests.send(method, url, data: data)
|
201
|
+
expect(resp.json['form']).to eq(expected)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "#{protocol} sends files" do
|
205
|
+
end
|
206
|
+
|
207
|
+
it "#{protocol} sends basic auth" do
|
208
|
+
url = httpbin + '/basic-auth/testuser/testpassword'
|
209
|
+
resp = Requests.send(method, url, auth: ['testuser',
|
210
|
+
'testpassword'])
|
211
|
+
|
212
|
+
# Can't check response status code here because httpbin.org
|
213
|
+
# only allows GET requests on /basic-auth:
|
214
|
+
auth_token = Base64.strict_encode64('testuser:testpassword')
|
215
|
+
encoded_auth = "Basic #{auth_token}"
|
216
|
+
auth_header = resp.request.headers['Authorization']
|
217
|
+
expect(auth_header).to eq(encoded_auth)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
shared_examples "HEAD method" do |protocol, httpbin|
|
222
|
+
let(:url) { httpbin + '/anything' }
|
223
|
+
|
224
|
+
it "#{protocol} makes request" do
|
225
|
+
resp = Requests.head(url)
|
226
|
+
expect(resp.status_code).to eq(200)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "#{protocol} body is empty" do
|
230
|
+
resp = Requests.head(url)
|
231
|
+
expect(resp.text).to eq('')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
shared_examples "OPTIONS method" do |protocol, httpbin|
|
236
|
+
let(:all_methods) {
|
237
|
+
['PUT', 'POST', 'OPTIONS', 'DELETE',
|
238
|
+
'HEAD', 'GET', 'TRACE', 'PATCH']
|
239
|
+
}
|
240
|
+
|
241
|
+
it "#{protocol} gets allow header in response /anything" do
|
242
|
+
url = httpbin + "/anything"
|
243
|
+
resp = Requests.options(url)
|
244
|
+
allowed = resp.headers['allow'].split(', ')
|
245
|
+
diff = (allowed - all_methods) + (all_methods - allowed)
|
246
|
+
expect(diff).to eq([])
|
247
|
+
end
|
248
|
+
|
249
|
+
it "#{protocol} gets allow header in response /delete" do
|
250
|
+
url = httpbin + "/delete"
|
251
|
+
resp = Requests.options(url)
|
252
|
+
allowed = resp.headers['allow'].split(', ')
|
253
|
+
methods = ['OPTIONS', 'DELETE']
|
254
|
+
diff = (allowed - methods) + (methods - allowed)
|
255
|
+
expect(diff).to eq([])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "GET" do
|
260
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
261
|
+
include_examples("all methods", "get", protocol, httpbin)
|
262
|
+
include_examples("redirects", "get", protocol, httpbin)
|
263
|
+
include_examples("methods with response body", "get", protocol,
|
264
|
+
httpbin)
|
265
|
+
include_examples("GET method", protocol, httpbin)
|
266
|
+
end
|
267
|
+
include_examples("bad SSL certificates", 'get')
|
268
|
+
end
|
269
|
+
|
270
|
+
describe "POST" do
|
271
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
272
|
+
include_examples("all methods", "post", protocol, httpbin)
|
273
|
+
include_examples("redirects", "post", protocol, httpbin)
|
274
|
+
include_examples("methods with response body", "post", protocol,
|
275
|
+
httpbin)
|
276
|
+
include_examples("methods with request body", "post", protocol,
|
277
|
+
httpbin)
|
278
|
+
end
|
279
|
+
include_examples("bad SSL certificates", 'post')
|
280
|
+
end
|
281
|
+
|
282
|
+
describe "PUT" do
|
283
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
284
|
+
include_examples("all methods", "put", protocol, httpbin)
|
285
|
+
include_examples("redirects", "put", protocol, httpbin)
|
286
|
+
include_examples("methods with response body", "put", protocol,
|
287
|
+
httpbin)
|
288
|
+
include_examples("methods with request body", "put", protocol,
|
289
|
+
httpbin)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe "PATCH" do
|
294
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
295
|
+
include_examples("all methods", "patch", protocol, httpbin)
|
296
|
+
include_examples("redirects", "patch", protocol, httpbin)
|
297
|
+
include_examples("methods with response body", "patch", protocol,
|
298
|
+
httpbin)
|
299
|
+
include_examples("methods with request body", "patch", protocol,
|
300
|
+
httpbin)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe "HEAD" do
|
305
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
306
|
+
include_examples("all methods", "head", protocol, httpbin)
|
307
|
+
include_examples("redirects", "head", protocol, httpbin)
|
308
|
+
include_examples("HEAD method", protocol, httpbin)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "DELETE" do
|
313
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
314
|
+
include_examples("all methods", "delete", protocol, httpbin)
|
315
|
+
include_examples("redirects", "delete", protocol, httpbin)
|
316
|
+
# include_examples("DELETE method", protocol, httpbin)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "OPTIONS" do
|
321
|
+
HTTPBIN_URLS.each do |protocol, httpbin|
|
322
|
+
include_examples("all methods", "options", protocol, httpbin)
|
323
|
+
include_examples("OPTIONS method", protocol, httpbin)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../spec_helper'
|
3
|
+
|
4
|
+
|
5
|
+
RSpec.describe Requests::Session do
|
6
|
+
let(:httpbin) {
|
7
|
+
HTTPBIN_URLS['HTTPS']
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:anything_url) {
|
11
|
+
httpbin + '/anything'
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@session = Requests::Session.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "headers" do
|
19
|
+
before(:each) do
|
20
|
+
@session_hdrs = {
|
21
|
+
'Test-Header' => 'test value',
|
22
|
+
'Other-Header' => 'other value',
|
23
|
+
}
|
24
|
+
@session.headers = @session_hdrs
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sends session headers with each request" do
|
28
|
+
r = @session.get(anything_url)
|
29
|
+
expect(r.json['headers']['Test-Header']).to(
|
30
|
+
eq(@session_hdrs['Test-Header'])
|
31
|
+
)
|
32
|
+
expect(r.json['headers']['Other-Header']).to(
|
33
|
+
eq(@session_hdrs['Other-Header'])
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "request headers take precedence over session headers" do
|
38
|
+
req_hdrs = {'Test-Header' => 'request-specific'}
|
39
|
+
r = @session.get(anything_url, headers: req_hdrs)
|
40
|
+
expect(r.json['headers']['Test-Header']).to(
|
41
|
+
eq(req_hdrs['Test-Header'])
|
42
|
+
)
|
43
|
+
expect(r.json['headers']['Other-Header']).to(
|
44
|
+
eq(@session_hdrs['Other-Header'])
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "session headers can be updated" do
|
49
|
+
@session.headers['New-Header'] = 'new value'
|
50
|
+
r = @session.put(anything_url)
|
51
|
+
expect(r.json['headers']['New-Header']).to eq('new value')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "cookies" do
|
56
|
+
let(:cookie_url) { httpbin + '/cookies' }
|
57
|
+
|
58
|
+
before(:each) do
|
59
|
+
@cookies = Requests::CookieJar.new
|
60
|
+
@cookies.add(
|
61
|
+
Requests::Cookie.new('chocolate', 'chip', domain: 'httpbin.org',
|
62
|
+
for_domain: true, path: '/')
|
63
|
+
)
|
64
|
+
@cookies.add(
|
65
|
+
Requests::Cookie.new('or', 'eo', domain: 'httpbin.org',
|
66
|
+
for_domain: true, path: '/')
|
67
|
+
)
|
68
|
+
@session.cookies = @cookies
|
69
|
+
end
|
70
|
+
|
71
|
+
it "sends session cookies with each request" do
|
72
|
+
r = @session.get(cookie_url)
|
73
|
+
expect(r.json['cookies']).to(
|
74
|
+
eq({'chocolate' => 'chip', 'or' => 'eo'})
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "request cookies take precedence over session cookies" do
|
79
|
+
r = @session.get(cookie_url, cookies: {'or' => 'something else'})
|
80
|
+
expect(r.json['cookies']).to(
|
81
|
+
eq({'chocolate' => 'chip',
|
82
|
+
'or' => 'something else'})
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "only sends cookies belonging to request uri" do
|
87
|
+
# this will set some cookies for github.com:
|
88
|
+
r = @session.get("https://github.com")
|
89
|
+
github_cookies = r.cookies.to_hash
|
90
|
+
|
91
|
+
r = @session.get(cookie_url)
|
92
|
+
github_cookies.each_key do |key|
|
93
|
+
expect(r.json['cookies']).not_to include(key)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "persists cookies set by requests" do
|
98
|
+
req_cookies = {'new-cookie' => 'new value',
|
99
|
+
'other-cookie' => 'other value'}
|
100
|
+
@session.get(cookie_url + '/set', params: req_cookies)
|
101
|
+
r = @session.get(cookie_url)
|
102
|
+
expect(r.json['cookies']).to(
|
103
|
+
eq({'chocolate' => 'chip',
|
104
|
+
'or' => 'eo'}.merge(req_cookies))
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# TODO: Write tests for proxies in a Session after figuring out
|
110
|
+
# a good automated way to test proxies
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.start { add_filter 'spec/' } unless ENV['COVERAGE'] == 'false'
|
4
|
+
|
5
|
+
require_relative '../lib/requests'
|
6
|
+
|
7
|
+
REQUESTS_VERBOSE = (ENV['REQUESTS_VERBOSE'] == 'true')
|
8
|
+
ENV['REQUESTS_HTTP_DEBUG'] = 'true' if REQUESTS_VERBOSE
|
9
|
+
|
10
|
+
HTTPBIN_URLS = {
|
11
|
+
'HTTP' => 'http://httpbin.org',
|
12
|
+
'HTTPS' => 'https://httpbin.org',
|
13
|
+
}
|
14
|
+
|
15
|
+
BADSSL_URLS = {
|
16
|
+
'self-signed' => 'https://self-signed.badssl.com/',
|
17
|
+
}
|
18
|
+
|
19
|
+
$log = StringIO.new
|
20
|
+
$logger = Requests::Logger.new($log, level: 'debug', enabled: true)
|
21
|
+
Requests.logger = $logger
|
22
|
+
|
23
|
+
|
24
|
+
def reset_log
|
25
|
+
before(:each) do
|
26
|
+
$log.seek(0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def display_verbose_log
|
31
|
+
after(:each) do
|
32
|
+
if REQUESTS_VERBOSE
|
33
|
+
$log.seek(0)
|
34
|
+
puts "\nCAPTURED LOG:"
|
35
|
+
puts "=" * 16
|
36
|
+
puts $log.read
|
37
|
+
puts "=" * 16 + "\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def running_in_docker
|
43
|
+
ENV['RUNNING_IN_DOCKER'] == 'true'
|
44
|
+
end
|