ethon 0.5.12 → 0.6.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.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +11 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +1 -1
  7. data/Guardfile +9 -0
  8. data/ethon.gemspec +26 -0
  9. data/lib/ethon/curl.rb +0 -12
  10. data/lib/ethon/curls/constants.rb +6 -22
  11. data/lib/ethon/curls/functions.rb +38 -41
  12. data/lib/ethon/curls/infos.rb +19 -0
  13. data/lib/ethon/curls/options.rb +416 -219
  14. data/lib/ethon/curls/settings.rb +1 -0
  15. data/lib/ethon/easy.rb +12 -18
  16. data/lib/ethon/easy/callbacks.rb +40 -6
  17. data/lib/ethon/easy/debug_info.rb +46 -0
  18. data/lib/ethon/easy/mirror.rb +39 -0
  19. data/lib/ethon/easy/options.rb +17 -1235
  20. data/lib/ethon/easy/queryable.rb +6 -8
  21. data/lib/ethon/easy/response_callbacks.rb +1 -1
  22. data/lib/ethon/version.rb +1 -1
  23. data/profile/benchmarks.rb +137 -0
  24. data/profile/memory_leaks.rb +113 -0
  25. data/profile/perf_spec_helper.rb +36 -0
  26. data/profile/support/memory_test_helpers.rb +75 -0
  27. data/profile/support/os_memory_leak_tracker.rb +47 -0
  28. data/profile/support/ruby_object_leak_tracker.rb +48 -0
  29. data/spec/ethon/curl_spec.rb +27 -0
  30. data/spec/ethon/easy/callbacks_spec.rb +31 -0
  31. data/spec/ethon/easy/debug_info_spec.rb +52 -0
  32. data/spec/ethon/easy/form_spec.rb +76 -0
  33. data/spec/ethon/easy/header_spec.rb +78 -0
  34. data/spec/ethon/easy/http/custom_spec.rb +176 -0
  35. data/spec/ethon/easy/http/delete_spec.rb +20 -0
  36. data/spec/ethon/easy/http/get_spec.rb +89 -0
  37. data/spec/ethon/easy/http/head_spec.rb +79 -0
  38. data/spec/ethon/easy/http/options_spec.rb +50 -0
  39. data/spec/ethon/easy/http/patch_spec.rb +50 -0
  40. data/spec/ethon/easy/http/post_spec.rb +220 -0
  41. data/spec/ethon/easy/http/put_spec.rb +124 -0
  42. data/spec/ethon/easy/http_spec.rb +44 -0
  43. data/spec/ethon/easy/informations_spec.rb +82 -0
  44. data/spec/ethon/easy/mirror_spec.rb +39 -0
  45. data/spec/ethon/easy/operations_spec.rb +251 -0
  46. data/spec/ethon/easy/options_spec.rb +135 -0
  47. data/spec/ethon/easy/queryable_spec.rb +188 -0
  48. data/spec/ethon/easy/response_callbacks_spec.rb +50 -0
  49. data/spec/ethon/easy/util_spec.rb +27 -0
  50. data/spec/ethon/easy_spec.rb +105 -0
  51. data/spec/ethon/libc_spec.rb +13 -0
  52. data/spec/ethon/loggable_spec.rb +21 -0
  53. data/spec/ethon/multi/operations_spec.rb +297 -0
  54. data/spec/ethon/multi/options_spec.rb +70 -0
  55. data/spec/ethon/multi/stack_spec.rb +79 -0
  56. data/spec/ethon/multi_spec.rb +21 -0
  57. data/spec/spec_helper.rb +27 -0
  58. data/spec/support/localhost_server.rb +94 -0
  59. data/spec/support/server.rb +114 -0
  60. metadata +91 -31
  61. data/lib/ethon/curls/auth_types.rb +0 -25
  62. data/lib/ethon/curls/http_versions.rb +0 -22
  63. data/lib/ethon/curls/postredir.rb +0 -15
  64. data/lib/ethon/curls/protocols.rb +0 -36
  65. data/lib/ethon/curls/proxy_types.rb +0 -25
  66. data/lib/ethon/curls/ssl_versions.rb +0 -23
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Libc do
4
+ describe "#getdtablesize" do
5
+ it "returns an integer" do
6
+ expect(Ethon::Libc.getdtablesize).to be_a(Integer)
7
+ end
8
+
9
+ it "returns bigger zero" do
10
+ expect(Ethon::Libc.getdtablesize).to_not be_zero
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe Ethon::Loggable do
4
+
5
+ describe "#logger=" do
6
+
7
+ let(:logger) do
8
+ Logger.new($stdout).tap do |log|
9
+ log.level = Logger::INFO
10
+ end
11
+ end
12
+
13
+ before do
14
+ Ethon.logger = logger
15
+ end
16
+
17
+ it "sets the logger" do
18
+ expect(Ethon.logger).to eq(logger)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,297 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Multi::Operations do
4
+ let(:multi) { Ethon::Multi.new }
5
+ let(:easy) { Ethon::Easy.new }
6
+ let(:pointer) { FFI::MemoryPointer.new(:int) }
7
+
8
+ describe "#handle" do
9
+ it "returns a pointer" do
10
+ expect(multi.handle).to be_a(FFI::Pointer)
11
+ end
12
+ end
13
+
14
+ describe "#running_count" do
15
+ context "when hydra has no easy" do
16
+ it "returns nil" do
17
+ expect(multi.send(:running_count)).to be_nil
18
+ end
19
+ end
20
+
21
+ context "when hydra has easy" do
22
+ before do
23
+ easy.url = "http://localhost:3001/"
24
+ multi.add(easy)
25
+ multi.send(:trigger, pointer)
26
+ end
27
+
28
+ it "returns 1" do
29
+ expect(multi.send(:running_count)).to eq(1)
30
+ end
31
+ end
32
+
33
+ context "when hydra has more easys" do
34
+ let(:another_easy) { Ethon::Easy.new }
35
+
36
+ before do
37
+ easy.url = "http://localhost:3001/"
38
+ another_easy.url = "http://localhost:3001/"
39
+ multi.add(easy)
40
+ multi.add(another_easy)
41
+ multi.send(:trigger, pointer)
42
+ end
43
+
44
+ it "returns 2" do
45
+ expect(multi.send(:running_count)).to eq(2)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "#get_timeout" do
51
+ context "when code ok" do
52
+ let(:timeout) { 1 }
53
+
54
+ before do
55
+ Ethon::Curl.should_receive(:multi_timeout).and_return(:ok)
56
+ multi.instance_variable_set(:@timeout, double(:read_long => timeout))
57
+ end
58
+
59
+ it "doesn't raise" do
60
+ expect{ multi.send(:get_timeout) }.to_not raise_error
61
+ end
62
+
63
+ context "when timeout smaller zero" do
64
+ let(:timeout) { -1 }
65
+
66
+ it "returns 1" do
67
+ expect(multi.send(:get_timeout)).to eq(1)
68
+ end
69
+ end
70
+
71
+ context "when timeout bigger or equal zero" do
72
+ let(:timeout) { 2 }
73
+
74
+ it "returns timeout" do
75
+ expect(multi.send(:get_timeout)).to eq(timeout)
76
+ end
77
+ end
78
+ end
79
+
80
+ context "when code not ok" do
81
+ before { Ethon::Curl.should_receive(:multi_timeout).and_return(:not_ok) }
82
+
83
+ it "raises MultiTimeout error" do
84
+ expect{ multi.send(:get_timeout) }.to raise_error(Ethon::Errors::MultiTimeout)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#set_fds" do
90
+ let(:timeout) { 1 }
91
+ let(:max_fd) { 1 }
92
+
93
+ context "when code ok" do
94
+ before { Ethon::Curl.should_receive(:multi_fdset).and_return(:ok) }
95
+
96
+ it "doesn't raise" do
97
+ expect{ multi.method(:set_fds).call(timeout) }.to_not raise_error(Ethon::Errors::MultiFdset)
98
+ end
99
+
100
+ context "when max_fd -1" do
101
+ let(:max_fd) { -1 }
102
+
103
+ before do
104
+ multi.instance_variable_set(:@max_fd, double(:read_int => max_fd))
105
+ multi.should_receive(:sleep).with(0.001)
106
+ end
107
+
108
+ it "waits 100ms" do
109
+ multi.method(:set_fds).call(timeout)
110
+ end
111
+ end
112
+
113
+ context "when max_fd not -1" do
114
+ context "when code smaller zero" do
115
+ before { Ethon::Curl.should_receive(:select).and_return(-1) }
116
+
117
+ it "raises Select error" do
118
+ expect{ multi.method(:set_fds).call(timeout) }.to raise_error(Ethon::Errors::Select)
119
+ end
120
+ end
121
+
122
+ context "when code bigger or equal zero" do
123
+ before { Ethon::Curl.should_receive(:select).and_return(0) }
124
+
125
+ it "doesn't raise" do
126
+ expect{ multi.method(:set_fds).call(timeout) }.to_not raise_error(Ethon::Errors::Select)
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ context "when code not ok" do
133
+ before { Ethon::Curl.should_receive(:multi_fdset).and_return(:not_ok) }
134
+
135
+ it "raises MultiFdset error" do
136
+ expect{ multi.method(:set_fds).call(timeout) }.to raise_error(Ethon::Errors::MultiFdset)
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "#perform" do
142
+ context "when no easy handles" do
143
+ it "returns nil" do
144
+ expect(multi.perform).to be_nil
145
+ end
146
+
147
+ it "logs" do
148
+ Ethon.logger.should_receive(:debug).twice
149
+ multi.perform
150
+ end
151
+ end
152
+
153
+ context "when easy handle" do
154
+ before do
155
+ easy.url = "http://localhost:3001/"
156
+ multi.add(easy)
157
+ end
158
+
159
+ it "requests" do
160
+ multi.perform
161
+ end
162
+
163
+ it "sets easy" do
164
+ multi.perform
165
+ expect(easy.response_code).to eq(200)
166
+ end
167
+ end
168
+
169
+ context "when four easy handles" do
170
+ let(:easies) do
171
+ ary = []
172
+ 4.times do
173
+ ary << another_easy = Ethon::Easy.new
174
+ another_easy.url = "http://localhost:3001/"
175
+ end
176
+ ary
177
+ end
178
+
179
+ before do
180
+ easies.each { |e| multi.add(e) }
181
+ multi.perform
182
+ end
183
+
184
+ it "sets response codes" do
185
+ expect(easies.all?{ |e| e.response_code == 200 }).to be_true
186
+ end
187
+ end
188
+ end
189
+
190
+ describe "#ongoing?" do
191
+ context "when easy_handles" do
192
+ before { multi.easy_handles << 1 }
193
+
194
+ context "when running_count not greater 0" do
195
+ before { multi.instance_variable_set(:@running_count, 0) }
196
+
197
+ it "returns true" do
198
+ expect(multi.method(:ongoing?).call).to be_true
199
+ end
200
+ end
201
+
202
+ context "when running_count greater 0" do
203
+ before { multi.instance_variable_set(:@running_count, 1) }
204
+
205
+ it "returns true" do
206
+ expect(multi.method(:ongoing?).call).to be_true
207
+ end
208
+ end
209
+ end
210
+
211
+ context "when no easy_handles" do
212
+ context "when running_count not greater 0" do
213
+ before { multi.instance_variable_set(:@running_count, 0) }
214
+
215
+ it "returns false" do
216
+ expect(multi.method(:ongoing?).call).to be_false
217
+ end
218
+ end
219
+
220
+ context "when running_count greater 0" do
221
+ before { multi.instance_variable_set(:@running_count, 1) }
222
+
223
+ it "returns true" do
224
+ expect(multi.method(:ongoing?).call).to be_true
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ describe "#init_vars" do
231
+ it "sets @timeout" do
232
+ expect(multi.instance_variable_get(:@timeout)).to be_a(FFI::MemoryPointer)
233
+ end
234
+
235
+ it "sets @timeval" do
236
+ expect(multi.instance_variable_get(:@timeval)).to be_a(Ethon::Curl::Timeval)
237
+ end
238
+
239
+ it "sets @fd_read" do
240
+ expect(multi.instance_variable_get(:@fd_read)).to be_a(Ethon::Curl::FDSet)
241
+ end
242
+
243
+ it "sets @fd_write" do
244
+ expect(multi.instance_variable_get(:@fd_write)).to be_a(Ethon::Curl::FDSet)
245
+ end
246
+
247
+ it "sets @fd_excep" do
248
+ expect(multi.instance_variable_get(:@fd_excep)).to be_a(Ethon::Curl::FDSet)
249
+ end
250
+
251
+ it "sets @max_fd" do
252
+ expect(multi.instance_variable_get(:@max_fd)).to be_a(FFI::MemoryPointer)
253
+ end
254
+ end
255
+
256
+ describe "#reset_fds" do
257
+ after { multi.method(:reset_fds).call }
258
+
259
+ it "resets @fd_read" do
260
+ multi.instance_variable_get(:@fd_read).should_receive(:clear)
261
+ end
262
+
263
+ it "resets @fd_write" do
264
+ multi.instance_variable_get(:@fd_write).should_receive(:clear)
265
+ end
266
+
267
+ it "resets @fd_excep" do
268
+ multi.instance_variable_get(:@fd_excep).should_receive(:clear)
269
+ end
270
+ end
271
+
272
+ describe "#check" do
273
+ it { pending("untested") }
274
+ end
275
+
276
+ describe "#run" do
277
+ it { pending("untested") }
278
+ end
279
+
280
+ describe "#trigger" do
281
+ it "calls multi perform" do
282
+ Ethon::Curl.should_receive(:multi_perform)
283
+ multi.send(:trigger, pointer)
284
+ end
285
+
286
+ it "sets running count" do
287
+ multi.instance_variable_set(:@running_count, nil)
288
+ multi.send(:trigger, pointer)
289
+ expect(multi.instance_variable_get(:@running_count)).to_not be_nil
290
+ end
291
+
292
+ it "returns multi perform code" do
293
+ Ethon::Curl.should_receive(:multi_perform).and_return(:ok)
294
+ expect(multi.send(:trigger, pointer)).to eq(:ok)
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Multi::Options do
4
+ let(:multi) { Ethon::Multi.new }
5
+
6
+ [
7
+ :maxconnects, :pipelining, :socketdata, :socketfunction,
8
+ :timerdata, :timerfunction
9
+ ].each do |name|
10
+ describe "#{name}=" do
11
+ it "responds_to" do
12
+ expect(multi).to respond_to("#{name}=")
13
+ end
14
+
15
+ it "sets option" do
16
+ Ethon::Curl.should_receive(:set_option).with do |option, _, _|
17
+ expect(option).to be(name)
18
+ end
19
+ multi.method("#{name}=").call(1)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#value_for" do
25
+ context "when option in bool" do
26
+ context "when value true" do
27
+ let(:value) { true }
28
+
29
+ it "returns 1" do
30
+ expect(multi.method(:value_for).call(value, :bool)).to eq(1)
31
+ end
32
+ end
33
+
34
+ context "when value false" do
35
+ let(:value) { false }
36
+
37
+ it "returns 0" do
38
+ expect(multi.method(:value_for).call(value, :bool)).to eq(0)
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+ context "when value in int" do
45
+ let(:value) { "2" }
46
+
47
+ it "returns value casted to int" do
48
+ expect(multi.method(:value_for).call(value, :int)).to eq(2)
49
+ end
50
+ end
51
+
52
+ context "when value in unspecific_options" do
53
+ context "when value a string" do
54
+ let(:value) { "www.example.\0com" }
55
+
56
+ it "returns zero byte escaped string" do
57
+ expect(multi.method(:value_for).call(value, nil)).to eq("www.example.\\0com")
58
+ end
59
+ end
60
+
61
+ context "when value not a string" do
62
+ let(:value) { 1 }
63
+
64
+ it "returns value" do
65
+ expect(multi.method(:value_for).call(value, nil)).to eq(1)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Multi::Stack do
4
+ let(:multi) { Ethon::Multi.new }
5
+ let(:easy) { Ethon::Easy.new }
6
+
7
+ describe "#add" do
8
+ context "when easy already added" do
9
+ before { multi.add(easy) }
10
+
11
+ it "returns nil" do
12
+ expect(multi.add(easy)).to be_nil
13
+ end
14
+ end
15
+
16
+ context "when easy new" do
17
+ it "adds easy to multi" do
18
+ Ethon::Curl.should_receive(:multi_add_handle).and_return(:ok)
19
+ multi.add(easy)
20
+ end
21
+
22
+ it "adds easy to easy_handles" do
23
+ multi.add(easy)
24
+ expect(multi.easy_handles).to include(easy)
25
+ end
26
+ end
27
+
28
+ context "when multi_add_handle fails" do
29
+ it "raises multi add error" do
30
+ Ethon::Curl.should_receive(:multi_add_handle).and_return(:bad_easy_handle)
31
+ expect{ multi.add(easy) }.to raise_error(Ethon::Errors::MultiAdd)
32
+ end
33
+ end
34
+
35
+ context "when multi cleaned up before" do
36
+ it "raises multi add error" do
37
+ Ethon::Curl.multi_cleanup(multi.handle)
38
+ expect{ multi.add(easy) }.to raise_error(Ethon::Errors::MultiAdd)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#delete" do
44
+ context "when easy in easy_handles" do
45
+ before { multi.add(easy) }
46
+
47
+ it "deletes easy from multi" do
48
+ Ethon::Curl.should_receive(:multi_remove_handle).and_return(:ok)
49
+ multi.delete(easy)
50
+ end
51
+
52
+ it "deletes easy from easy_handles" do
53
+ multi.delete(easy)
54
+ expect(multi.easy_handles).to_not include(easy)
55
+ end
56
+ end
57
+
58
+ context "when easy is not in easy_handles" do
59
+ it "does nothing" do
60
+ Ethon::Curl.should_receive(:multi_add_handle).and_return(:ok)
61
+ multi.add(easy)
62
+ end
63
+
64
+ it "adds easy to easy_handles" do
65
+ multi.add(easy)
66
+ expect(multi.easy_handles).to include(easy)
67
+ end
68
+ end
69
+
70
+ context "when multi_remove_handle fails" do
71
+ before { multi.add(easy) }
72
+
73
+ it "raises multi remove error" do
74
+ Ethon::Curl.should_receive(:multi_remove_handle).and_return(:bad_easy_handle)
75
+ expect{ multi.delete(easy) }.to raise_error(Ethon::Errors::MultiRemove)
76
+ end
77
+ end
78
+ end
79
+ end