ethon 0.5.12 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -1
- data/Guardfile +9 -0
- data/ethon.gemspec +26 -0
- data/lib/ethon/curl.rb +0 -12
- data/lib/ethon/curls/constants.rb +6 -22
- data/lib/ethon/curls/functions.rb +38 -41
- data/lib/ethon/curls/infos.rb +19 -0
- data/lib/ethon/curls/options.rb +416 -219
- data/lib/ethon/curls/settings.rb +1 -0
- data/lib/ethon/easy.rb +12 -18
- data/lib/ethon/easy/callbacks.rb +40 -6
- data/lib/ethon/easy/debug_info.rb +46 -0
- data/lib/ethon/easy/mirror.rb +39 -0
- data/lib/ethon/easy/options.rb +17 -1235
- data/lib/ethon/easy/queryable.rb +6 -8
- data/lib/ethon/easy/response_callbacks.rb +1 -1
- data/lib/ethon/version.rb +1 -1
- data/profile/benchmarks.rb +137 -0
- data/profile/memory_leaks.rb +113 -0
- data/profile/perf_spec_helper.rb +36 -0
- data/profile/support/memory_test_helpers.rb +75 -0
- data/profile/support/os_memory_leak_tracker.rb +47 -0
- data/profile/support/ruby_object_leak_tracker.rb +48 -0
- data/spec/ethon/curl_spec.rb +27 -0
- data/spec/ethon/easy/callbacks_spec.rb +31 -0
- data/spec/ethon/easy/debug_info_spec.rb +52 -0
- data/spec/ethon/easy/form_spec.rb +76 -0
- data/spec/ethon/easy/header_spec.rb +78 -0
- data/spec/ethon/easy/http/custom_spec.rb +176 -0
- data/spec/ethon/easy/http/delete_spec.rb +20 -0
- data/spec/ethon/easy/http/get_spec.rb +89 -0
- data/spec/ethon/easy/http/head_spec.rb +79 -0
- data/spec/ethon/easy/http/options_spec.rb +50 -0
- data/spec/ethon/easy/http/patch_spec.rb +50 -0
- data/spec/ethon/easy/http/post_spec.rb +220 -0
- data/spec/ethon/easy/http/put_spec.rb +124 -0
- data/spec/ethon/easy/http_spec.rb +44 -0
- data/spec/ethon/easy/informations_spec.rb +82 -0
- data/spec/ethon/easy/mirror_spec.rb +39 -0
- data/spec/ethon/easy/operations_spec.rb +251 -0
- data/spec/ethon/easy/options_spec.rb +135 -0
- data/spec/ethon/easy/queryable_spec.rb +188 -0
- data/spec/ethon/easy/response_callbacks_spec.rb +50 -0
- data/spec/ethon/easy/util_spec.rb +27 -0
- data/spec/ethon/easy_spec.rb +105 -0
- data/spec/ethon/libc_spec.rb +13 -0
- data/spec/ethon/loggable_spec.rb +21 -0
- data/spec/ethon/multi/operations_spec.rb +297 -0
- data/spec/ethon/multi/options_spec.rb +70 -0
- data/spec/ethon/multi/stack_spec.rb +79 -0
- data/spec/ethon/multi_spec.rb +21 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/localhost_server.rb +94 -0
- data/spec/support/server.rb +114 -0
- metadata +91 -31
- data/lib/ethon/curls/auth_types.rb +0 -25
- data/lib/ethon/curls/http_versions.rb +0 -22
- data/lib/ethon/curls/postredir.rb +0 -15
- data/lib/ethon/curls/protocols.rb +0 -36
- data/lib/ethon/curls/proxy_types.rb +0 -25
- data/lib/ethon/curls/ssl_versions.rb +0 -23
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ethon::Easy::Options do
|
4
|
+
let(:easy) { Ethon::Easy.new }
|
5
|
+
|
6
|
+
[
|
7
|
+
:accept_encoding, :cainfo, :capath, :connecttimeout, :connecttimeout_ms, :cookie,
|
8
|
+
:cookiejar, :cookiefile, :copypostfields, :customrequest, :dns_cache_timeout,
|
9
|
+
:followlocation, :forbid_reuse, :http_version, :httpauth, :httpget, :httppost,
|
10
|
+
:infilesize, :interface, :keypasswd, :maxredirs, :nobody, :nosignal,
|
11
|
+
:postfieldsize, :postredir, :protocols, :proxy, :proxyauth, :proxyport, :proxytype,
|
12
|
+
:proxyuserpwd, :readdata, :readfunction, :redir_protocols, :ssl_verifyhost,
|
13
|
+
:ssl_verifypeer, :sslcert, :sslcerttype, :sslkey, :sslkeytype, :sslversion,
|
14
|
+
:timeout, :timeout_ms, :unrestricted_auth, :upload, :url, :useragent,
|
15
|
+
:userpwd, :verbose
|
16
|
+
].each do |name|
|
17
|
+
describe "#{name}=" do
|
18
|
+
it "responds_to" do
|
19
|
+
expect(easy).to respond_to("#{name}=")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets option" do
|
23
|
+
Ethon::Easy.any_instance.should_receive(:set_callbacks)
|
24
|
+
Ethon::Curl.should_receive(:set_option).with do |option, _, _|
|
25
|
+
expect(option).to be(name)
|
26
|
+
end
|
27
|
+
value = case name
|
28
|
+
when :http_version
|
29
|
+
:httpv1_0
|
30
|
+
when :httpauth
|
31
|
+
:basic
|
32
|
+
when :protocols, :redir_protocols
|
33
|
+
:http
|
34
|
+
when :postredir
|
35
|
+
:post_301
|
36
|
+
when :proxytype
|
37
|
+
:http
|
38
|
+
when :sslversion
|
39
|
+
:default
|
40
|
+
when :httppost
|
41
|
+
FFI::Pointer::NULL
|
42
|
+
else
|
43
|
+
1
|
44
|
+
end
|
45
|
+
easy.method("#{name}=").call(value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#httppost=" do
|
51
|
+
it "raises unless given a FFI::Pointer" do
|
52
|
+
expect{ easy.httppost = 1 }.to raise_error(Ethon::Errors::InvalidValue)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when requesting" do
|
57
|
+
let(:url) { "localhost:3001" }
|
58
|
+
let(:timeout) { nil }
|
59
|
+
let(:timeout_ms) { nil }
|
60
|
+
let(:connecttimeout) { nil }
|
61
|
+
let(:connecttimeout_ms) { nil }
|
62
|
+
let(:userpwd) { nil }
|
63
|
+
|
64
|
+
before do
|
65
|
+
easy.url = url
|
66
|
+
easy.timeout = timeout
|
67
|
+
easy.timeout_ms = timeout_ms
|
68
|
+
easy.connecttimeout = connecttimeout
|
69
|
+
easy.connecttimeout_ms = connecttimeout_ms
|
70
|
+
easy.userpwd = userpwd
|
71
|
+
easy.perform
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when userpwd" do
|
75
|
+
context "when contains /" do
|
76
|
+
let(:url) { "localhost:3001/auth_basic/test/te%2Fst" }
|
77
|
+
let(:userpwd) { "test:te/st" }
|
78
|
+
|
79
|
+
it "works" do
|
80
|
+
expect(easy.response_code).to eq(200)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when timeout" do
|
86
|
+
let(:timeout) { 1 }
|
87
|
+
|
88
|
+
context "when request takes longer" do
|
89
|
+
let(:url) { "localhost:3001?delay=2" }
|
90
|
+
|
91
|
+
it "times out" do
|
92
|
+
expect(easy.return_code).to eq(:operation_timedout)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when connecttimeout" do
|
98
|
+
let(:connecttimeout) { 1 }
|
99
|
+
|
100
|
+
context "when cannot connect" do
|
101
|
+
let(:url) { "localhost:3002" }
|
102
|
+
|
103
|
+
it "times out" do
|
104
|
+
expect(easy.return_code).to eq(:couldnt_connect)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
if Ethon::Curl.version.match("c-ares")
|
110
|
+
context "when timeout_ms" do
|
111
|
+
let(:timeout_ms) { 900 }
|
112
|
+
|
113
|
+
context "when request takes longer" do
|
114
|
+
let(:url) { "localhost:3001?delay=1" }
|
115
|
+
|
116
|
+
it "times out" do
|
117
|
+
expect(easy.return_code).to eq(:operation_timedout)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "when connecttimeout_ms" do
|
123
|
+
let(:connecttimeout_ms) { 1 }
|
124
|
+
|
125
|
+
context "when cannot connect" do
|
126
|
+
let(:url) { "localhost:3002" }
|
127
|
+
|
128
|
+
it "times out" do
|
129
|
+
expect(easy.return_code).to eq(:couldnt_connect)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Ethon::Easy::Queryable do
|
5
|
+
let(:hash) { {} }
|
6
|
+
let!(:easy) { Ethon::Easy.new }
|
7
|
+
let(:params) { Ethon::Easy::Params.new(easy, hash) }
|
8
|
+
|
9
|
+
describe "#to_s" do
|
10
|
+
context "when query_pairs empty" do
|
11
|
+
before { params.instance_variable_set(:@query_pairs, []) }
|
12
|
+
|
13
|
+
it "returns empty string" do
|
14
|
+
expect(params.to_s).to eq("")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when query_pairs not empty" do
|
19
|
+
context "when escape" do
|
20
|
+
before do
|
21
|
+
params.escape = true
|
22
|
+
end
|
23
|
+
|
24
|
+
{
|
25
|
+
'!' => '%21', '*' => '%2A', "'" => '%27', '(' => '%28',
|
26
|
+
')' => '%29', ';' => '%3B', ':' => '%3A', '@' => '%40',
|
27
|
+
'&' => '%26', '=' => '%3D', '+' => '%2B', '$' => '%24',
|
28
|
+
',' => '%2C', '/' => '%2F', '?' => '%3F', '#' => '%23',
|
29
|
+
'[' => '%5B', ']' => '%5D',
|
30
|
+
|
31
|
+
'<' => '%3C', '>' => '%3E', '"' => '%22', '{' => '%7B',
|
32
|
+
'}' => '%7D', '|' => '%7C', '\\' => '%5C', '`' => '%60',
|
33
|
+
'^' => '%5E', '%' => '%25', ' ' => '%20', "\0" => '%00',
|
34
|
+
|
35
|
+
'まつもと' => '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8',
|
36
|
+
}.each do |value, percent|
|
37
|
+
it "turns #{value.inspect} into #{percent}" do
|
38
|
+
params.instance_variable_set(:@query_pairs, [[:a, value]])
|
39
|
+
expect(params.to_s).to eq("a=#{percent}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
{
|
44
|
+
'.' => '%2E', '-' => '%2D', '_' => '%5F', '~' => '%7E',
|
45
|
+
}.each do |value, percent|
|
46
|
+
it "leaves #{value.inspect} instead of turning into #{percent}" do
|
47
|
+
params.instance_variable_set(:@query_pairs, [[:a, value]])
|
48
|
+
expect(params.to_s).to eq("a=#{value}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when no escape" do
|
54
|
+
before { params.instance_variable_set(:@query_pairs, [[:a, 1], [:b, 2]]) }
|
55
|
+
|
56
|
+
it "returns concatenated query string" do
|
57
|
+
expect(params.to_s).to eq("a=1&b=2")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when query_pairs contains a string" do
|
63
|
+
before { params.instance_variable_set(:@query_pairs, ["{a: 1}"]) }
|
64
|
+
|
65
|
+
it "returns correct string" do
|
66
|
+
expect(params.to_s).to eq("{a: 1}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#build_query_pairs" do
|
72
|
+
let(:pairs) { params.method(:build_query_pairs).call(hash) }
|
73
|
+
|
74
|
+
context "when params is empty" do
|
75
|
+
it "returns empty array" do
|
76
|
+
expect(pairs).to eq([])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when params is string" do
|
81
|
+
let(:hash) { "{a: 1}" }
|
82
|
+
|
83
|
+
it "wraps it in an array" do
|
84
|
+
expect(pairs).to eq([hash])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when params is simple hash" do
|
89
|
+
let(:hash) { {:a => 1, :b => 2} }
|
90
|
+
|
91
|
+
it "transforms" do
|
92
|
+
expect(pairs).to include([:a, 1])
|
93
|
+
expect(pairs).to include([:b, 2])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when params is a nested hash" do
|
98
|
+
let(:hash) { {:a => 1, :b => {:c => 2}} }
|
99
|
+
|
100
|
+
it "transforms" do
|
101
|
+
expect(pairs).to include([:a, 1])
|
102
|
+
expect(pairs).to include(["b[c]", 2])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when params contains an array" do
|
107
|
+
let(:hash) { {:a => 1, :b => [2, 3]} }
|
108
|
+
|
109
|
+
it "transforms" do
|
110
|
+
expect(pairs).to include([:a, 1])
|
111
|
+
expect(pairs).to include(["b[0]", 2])
|
112
|
+
expect(pairs).to include(["b[1]", 3])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when params contains something nested in an array" do
|
117
|
+
context "when string" do
|
118
|
+
let(:hash) { {:a => {:b => ["hello", "world"]}} }
|
119
|
+
|
120
|
+
it "transforms" do
|
121
|
+
expect(pairs).to eq([["a[b][0]", "hello"], ["a[b][1]", "world"]])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when hash" do
|
126
|
+
let(:hash) { {:a => {:b => [{:c =>1}, {:d => 2}]}} }
|
127
|
+
|
128
|
+
it "transforms" do
|
129
|
+
expect(pairs).to eq([["a[b][0][c]", 1], ["a[b][1][d]", 2]])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when file" do
|
134
|
+
let(:file) { Tempfile.new("fubar") }
|
135
|
+
let(:file_info) { params.method(:file_info).call(file) }
|
136
|
+
let(:hash) { {:a => {:b => [file]}} }
|
137
|
+
|
138
|
+
it "transforms" do
|
139
|
+
expect(pairs).to eq([["a[b][0]", file_info]])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
context "when params contains file" do
|
146
|
+
let(:file) { Tempfile.new("fubar") }
|
147
|
+
let(:file_info) { params.method(:file_info).call(file) }
|
148
|
+
let(:hash) { {:a => 1, :b => file} }
|
149
|
+
|
150
|
+
it "transforms" do
|
151
|
+
expect(pairs).to include([:a, 1])
|
152
|
+
expect(pairs).to include([:b, file_info])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when params key contains a null byte" do
|
157
|
+
let(:hash) { {:a => "1\0" } }
|
158
|
+
|
159
|
+
it "preserves" do
|
160
|
+
expect(pairs).to eq([[:a, "1\0"]])
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "when params value contains a null byte" do
|
165
|
+
let(:hash) { {"a\0" => 1 } }
|
166
|
+
|
167
|
+
it "preserves" do
|
168
|
+
expect(pairs).to eq([["a\0", 1]])
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#empty?" do
|
174
|
+
context "when params empty" do
|
175
|
+
it "returns true" do
|
176
|
+
expect(params.empty?).to be_true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when params not empty" do
|
181
|
+
let(:hash) { {:a => 1} }
|
182
|
+
|
183
|
+
it "returns false" do
|
184
|
+
expect(params.empty?).to be_false
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ethon::Easy::ResponseCallbacks do
|
4
|
+
let(:easy) { Ethon::Easy.new }
|
5
|
+
|
6
|
+
describe "#on_complete" do
|
7
|
+
it "responds" do
|
8
|
+
expect(easy).to respond_to(:on_complete)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when no block given" do
|
12
|
+
it "returns @on_complete" do
|
13
|
+
expect(easy.on_complete).to eq([])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when block given" do
|
18
|
+
it "stores" do
|
19
|
+
easy.on_complete { p 1 }
|
20
|
+
expect(easy.instance_variable_get(:@on_complete)).to have(1).items
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when multiple blocks given" do
|
25
|
+
it "stores" do
|
26
|
+
easy.on_complete { p 1 }
|
27
|
+
easy.on_complete { p 2 }
|
28
|
+
expect(easy.instance_variable_get(:@on_complete)).to have(2).items
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#complete" do
|
34
|
+
before do
|
35
|
+
easy.on_complete {|r| String.new(r.url) }
|
36
|
+
end
|
37
|
+
|
38
|
+
it "executes blocks and passes self" do
|
39
|
+
String.should_receive(:new).with(easy.url)
|
40
|
+
easy.complete
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when @on_complete nil" do
|
44
|
+
it "doesn't raise" do
|
45
|
+
easy.instance_variable_set(:@on_complete, nil)
|
46
|
+
expect{ easy.complete }.to_not raise_error(NoMethodError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ethon::Easy::Util do
|
4
|
+
class Dummy
|
5
|
+
include Ethon::Easy::Util
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:klass) { Dummy.new }
|
9
|
+
|
10
|
+
describe "escape_zero_byte" do
|
11
|
+
context "when value has no zero byte" do
|
12
|
+
let(:value) { "hello world" }
|
13
|
+
|
14
|
+
it "returns same value" do
|
15
|
+
expect(klass.escape_zero_byte(value)).to be(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when value has zero byte" do
|
20
|
+
let(:value) { "hello \0world" }
|
21
|
+
|
22
|
+
it "returns escaped" do
|
23
|
+
expect(klass.escape_zero_byte(value)).to eq("hello \\0world")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ethon::Easy do
|
4
|
+
let(:easy) { Ethon::Easy.new }
|
5
|
+
|
6
|
+
describe ".new" do
|
7
|
+
it "inits curl" do
|
8
|
+
Ethon::Curl.should_receive(:init)
|
9
|
+
easy
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when options are empty" do
|
13
|
+
it "sets only callbacks" do
|
14
|
+
Ethon::Easy.any_instance.should_receive(:set_callbacks)
|
15
|
+
Ethon::Easy.should_receive(:set_option).never
|
16
|
+
easy
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when options not empty" do
|
21
|
+
context "when followlocation is set" do
|
22
|
+
let(:options) { { :followlocation => true } }
|
23
|
+
let(:easy) { Ethon::Easy.new(options) }
|
24
|
+
|
25
|
+
it "sets followlocation" do
|
26
|
+
Ethon::Easy.any_instance.should_receive(:set_callbacks)
|
27
|
+
Ethon::Curl.should_receive(:set_option).with do |option, value, _|
|
28
|
+
expect(option).to be(:followlocation)
|
29
|
+
expect(value).to be(true)
|
30
|
+
end
|
31
|
+
easy
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#set_attributes" do
|
38
|
+
context "when options are empty" do
|
39
|
+
it "sets only callbacks" do
|
40
|
+
Ethon::Easy.any_instance.should_receive(:set_callbacks)
|
41
|
+
Ethon::Easy.should_receive(:set_option).never
|
42
|
+
easy
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when options aren't empty" do
|
47
|
+
context "when valid key" do
|
48
|
+
it "sets" do
|
49
|
+
easy.should_receive(:verbose=).with(true)
|
50
|
+
easy.set_attributes({:verbose => true})
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when invalid key" do
|
55
|
+
it "raises invalid option error" do
|
56
|
+
expect{ easy.set_attributes({:fubar => 1}) }.to raise_error(Ethon::Errors::InvalidOption)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#reset" do
|
63
|
+
before { easy.url = "www.example.com" }
|
64
|
+
|
65
|
+
it "resets url" do
|
66
|
+
easy.reset
|
67
|
+
expect(easy.url).to be_nil
|
68
|
+
end
|
69
|
+
|
70
|
+
it "resets hash" do
|
71
|
+
easy.reset
|
72
|
+
expect(easy.instance_variable_get(:@hash)).to be_nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it "resets easy handle" do
|
76
|
+
Ethon::Curl.should_receive(:easy_reset)
|
77
|
+
easy.reset
|
78
|
+
end
|
79
|
+
|
80
|
+
it "resets on_complete" do
|
81
|
+
easy.on_complete { p 1 }
|
82
|
+
easy.reset
|
83
|
+
expect(easy.on_complete).to be_empty
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#mirror" do
|
88
|
+
it "returns a Mirror" do
|
89
|
+
expect(easy.mirror).to be_a(Ethon::Easy::Mirror)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "builds from easy" do
|
93
|
+
Ethon::Easy::Mirror.should_receive(:from_easy).with(easy)
|
94
|
+
easy.mirror
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#log_inspect" do
|
99
|
+
[ :url, :response_code, :return_code, :total_time ].each do |name|
|
100
|
+
it "contains #{name}" do
|
101
|
+
expect(easy.log_inspect).to match name.to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|