restify 2.1.0 → 3.0.0.rc3
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/CHANGELOG.md +75 -0
- data/README.md +30 -5
- data/lib/restify/adapter/base.rb +10 -1
- data/lib/restify/adapter/ethon/easy.rb +147 -0
- data/lib/restify/adapter/ethon/event_loop.rb +255 -0
- data/lib/restify/adapter/ethon/options.rb +81 -0
- data/lib/restify/adapter/ethon/pool.rb +43 -0
- data/lib/restify/adapter/ethon.rb +211 -0
- data/lib/restify/adapter/loop_lock.rb +124 -0
- data/lib/restify/adapter/telemetry.rb +7 -5
- data/lib/restify/adapter/typhoeus.rb +52 -23
- data/lib/restify/context.rb +16 -6
- data/lib/restify/error.rb +13 -0
- data/lib/restify/global.rb +9 -30
- data/lib/restify/logging.rb +10 -4
- data/lib/restify/processors/base/parsing.rb +43 -26
- data/lib/restify/promise.rb +194 -42
- data/lib/restify/registry.rb +2 -2
- data/lib/restify/relation.rb +27 -13
- data/lib/restify/request.rb +2 -2
- data/lib/restify/resource.rb +20 -2
- data/lib/restify/response.rb +39 -3
- data/lib/restify/timeout.rb +23 -34
- data/lib/restify/version.rb +3 -3
- data/lib/restify/webmock.rb +126 -0
- data/lib/restify.rb +5 -2
- data/spec/restify/adapter/ethon/easy_spec.rb +111 -0
- data/spec/restify/adapter/ethon/event_loop_spec.rb +96 -0
- data/spec/restify/adapter/ethon/options_spec.rb +104 -0
- data/spec/restify/adapter/ethon/pool_spec.rb +81 -0
- data/spec/restify/adapter/ethon_spec.rb +307 -0
- data/spec/restify/adapter/loop_lock_spec.rb +144 -0
- data/spec/restify/adapter/telemetry_spec.rb +61 -0
- data/spec/restify/adapter/typhoeus_spec.rb +26 -0
- data/spec/restify/cache_spec.rb +1 -3
- data/spec/restify/context_spec.rb +69 -0
- data/spec/restify/features/opentelemetry_spec.rb +2 -0
- data/spec/restify/features/protocols_spec.rb +28 -0
- data/spec/restify/features/redirects_spec.rb +45 -0
- data/spec/restify/features/request_errors_spec.rb +1 -1
- data/spec/restify/features/response_bodies_spec.rb +45 -0
- data/spec/restify/features/response_encoding_spec.rb +82 -0
- data/spec/restify/features/response_errors_spec.rb +22 -1
- data/spec/restify/features/webmock_spec.rb +92 -1
- data/spec/restify/global_spec.rb +78 -10
- data/spec/restify/processors/json_spec.rb +103 -0
- data/spec/restify/processors/msgpack_spec.rb +36 -0
- data/spec/restify/promise_spec.rb +288 -9
- data/spec/restify/relation_spec.rb +25 -6
- data/spec/restify/request_spec.rb +26 -0
- data/spec/restify/timeout_spec.rb +43 -33
- data/spec/spec_helper.rb +10 -6
- data/spec/support/stub_server.rb +4 -4
- metadata +32 -221
- data/vendor/bundle/ruby/4.0.0/bundler/gems/my-rubocop-2b861962124a/LICENSE +0 -21
- data/vendor/bundle/ruby/4.0.0/bundler/gems/my-rubocop-2b861962124a/README.md +0 -23
- data/vendor/bundle/ruby/4.0.0/gems/activesupport-8.1.3/CHANGELOG.md +0 -561
- data/vendor/bundle/ruby/4.0.0/gems/activesupport-8.1.3/MIT-LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/activesupport-8.1.3/README.rdoc +0 -40
- data/vendor/bundle/ruby/4.0.0/gems/addressable-2.9.0/CHANGELOG.md +0 -326
- data/vendor/bundle/ruby/4.0.0/gems/addressable-2.9.0/LICENSE.txt +0 -202
- data/vendor/bundle/ruby/4.0.0/gems/addressable-2.9.0/README.md +0 -121
- data/vendor/bundle/ruby/4.0.0/gems/ast-2.4.3/LICENSE.MIT +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/ast-2.4.3/README.YARD.md +0 -12
- data/vendor/bundle/ruby/4.0.0/gems/base64-0.3.0/README.md +0 -48
- data/vendor/bundle/ruby/4.0.0/gems/bigdecimal-4.1.2/LICENSE +0 -56
- data/vendor/bundle/ruby/4.0.0/gems/concurrent-ruby-1.3.7/CHANGELOG.md +0 -615
- data/vendor/bundle/ruby/4.0.0/gems/concurrent-ruby-1.3.7/LICENSE.txt +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/concurrent-ruby-1.3.7/README.md +0 -409
- data/vendor/bundle/ruby/4.0.0/gems/connection_pool-3.0.2/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/connection_pool-3.0.2/README.md +0 -182
- data/vendor/bundle/ruby/4.0.0/gems/crack-1.0.1/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/crack-1.0.1/README.md +0 -43
- data/vendor/bundle/ruby/4.0.0/gems/diff-lcs-1.6.2/CHANGELOG.md +0 -518
- data/vendor/bundle/ruby/4.0.0/gems/diff-lcs-1.6.2/README.md +0 -92
- data/vendor/bundle/ruby/4.0.0/gems/docile-1.4.1/LICENSE +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/docile-1.4.1/README.md +0 -409
- data/vendor/bundle/ruby/4.0.0/gems/drb-2.2.3/LICENSE.txt +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/ethon-0.18.0/CHANGELOG.md +0 -417
- data/vendor/bundle/ruby/4.0.0/gems/ethon-0.18.0/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/ethon-0.18.0/README.md +0 -118
- data/vendor/bundle/ruby/4.0.0/gems/ffi-1.17.4-x86_64-linux-gnu/CHANGELOG.md +0 -507
- data/vendor/bundle/ruby/4.0.0/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE +0 -24
- data/vendor/bundle/ruby/4.0.0/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE.SPECS +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/ffi-1.17.4-x86_64-linux-gnu/README.md +0 -138
- data/vendor/bundle/ruby/4.0.0/gems/hashdiff-1.2.1/LICENSE +0 -19
- data/vendor/bundle/ruby/4.0.0/gems/hashdiff-1.2.1/README.md +0 -323
- data/vendor/bundle/ruby/4.0.0/gems/hashdiff-1.2.1/changelog.md +0 -127
- data/vendor/bundle/ruby/4.0.0/gems/hitimes-3.2.0/LICENSE.txt +0 -16
- data/vendor/bundle/ruby/4.0.0/gems/hitimes-3.2.0/README.md +0 -187
- data/vendor/bundle/ruby/4.0.0/gems/i18n-1.15.2/MIT-LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/i18n-1.15.2/README.md +0 -139
- data/vendor/bundle/ruby/4.0.0/gems/json-2.19.9/README.md +0 -310
- data/vendor/bundle/ruby/4.0.0/gems/language_server-protocol-3.17.0.5/LICENSE.txt +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/language_server-protocol-3.17.0.5/README.md +0 -88
- data/vendor/bundle/ruby/4.0.0/gems/lint_roller-1.1.0/CHANGELOG.md +0 -15
- data/vendor/bundle/ruby/4.0.0/gems/lint_roller-1.1.0/LICENSE.txt +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/lint_roller-1.1.0/README.md +0 -173
- data/vendor/bundle/ruby/4.0.0/gems/little-plugger-1.1.4/README.rdoc +0 -53
- data/vendor/bundle/ruby/4.0.0/gems/logger-1.7.0/README.md +0 -104
- data/vendor/bundle/ruby/4.0.0/gems/logging-2.4.0/LICENSE +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/logging-2.4.0/README.md +0 -140
- data/vendor/bundle/ruby/4.0.0/gems/minitest-6.0.6/README.rdoc +0 -763
- data/vendor/bundle/ruby/4.0.0/gems/msgpack-1.8.3/ChangeLog +0 -383
- data/vendor/bundle/ruby/4.0.0/gems/msgpack-1.8.3/LICENSE +0 -177
- data/vendor/bundle/ruby/4.0.0/gems/msgpack-1.8.3/README.md +0 -302
- data/vendor/bundle/ruby/4.0.0/gems/multi_json-1.21.1/LICENSE.md +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/multi_json-1.21.1/README.md +0 -281
- data/vendor/bundle/ruby/4.0.0/gems/nio4r-2.7.5/ext/libev/LICENSE +0 -37
- data/vendor/bundle/ruby/4.0.0/gems/nio4r-2.7.5/ext/libev/README +0 -59
- data/vendor/bundle/ruby/4.0.0/gems/nio4r-2.7.5/license.md +0 -80
- data/vendor/bundle/ruby/4.0.0/gems/nio4r-2.7.5/readme.md +0 -91
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-api-1.10.0/CHANGELOG.md +0 -219
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-api-1.10.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-api-1.10.0/README.md +0 -68
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-common-0.25.0/CHANGELOG.md +0 -110
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-common-0.25.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-common-0.25.0/README.md +0 -62
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-base-0.26.1/CHANGELOG.md +0 -97
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-base-0.26.1/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-base-0.26.1/README.md +0 -155
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-ethon-0.29.0/CHANGELOG.md +0 -192
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-ethon-0.29.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-instrumentation-ethon-0.29.0/README.md +0 -66
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-registry-0.6.0/CHANGELOG.md +0 -31
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-registry-0.6.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-registry-0.6.0/README.md +0 -40
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-sdk-1.12.0/CHANGELOG.md +0 -302
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-sdk-1.12.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-sdk-1.12.0/README.md +0 -101
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-semantic_conventions-1.41.0/CHANGELOG.md +0 -65
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-semantic_conventions-1.41.0/LICENSE +0 -201
- data/vendor/bundle/ruby/4.0.0/gems/opentelemetry-semantic_conventions-1.41.0/README.md +0 -115
- data/vendor/bundle/ruby/4.0.0/gems/parallel-2.1.0/MIT-LICENSE.txt +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/parser-3.3.11.1/LICENSE.txt +0 -26
- data/vendor/bundle/ruby/4.0.0/gems/prism-1.9.0/CHANGELOG.md +0 -786
- data/vendor/bundle/ruby/4.0.0/gems/prism-1.9.0/LICENSE.md +0 -7
- data/vendor/bundle/ruby/4.0.0/gems/prism-1.9.0/README.md +0 -143
- data/vendor/bundle/ruby/4.0.0/gems/public_suffix-7.0.5/CHANGELOG.md +0 -649
- data/vendor/bundle/ruby/4.0.0/gems/public_suffix-7.0.5/LICENSE.txt +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/public_suffix-7.0.5/README.md +0 -231
- data/vendor/bundle/ruby/4.0.0/gems/puma-8.0.2/LICENSE +0 -29
- data/vendor/bundle/ruby/4.0.0/gems/puma-8.0.2/README.md +0 -484
- data/vendor/bundle/ruby/4.0.0/gems/puma-8.0.2/docs/jungle/README.md +0 -9
- data/vendor/bundle/ruby/4.0.0/gems/puma-8.0.2/docs/jungle/rc.d/README.md +0 -74
- data/vendor/bundle/ruby/4.0.0/gems/racc-1.8.1/ChangeLog +0 -846
- data/vendor/bundle/ruby/4.0.0/gems/racc-1.8.1/README.ja.rdoc +0 -58
- data/vendor/bundle/ruby/4.0.0/gems/racc-1.8.1/README.rdoc +0 -60
- data/vendor/bundle/ruby/4.0.0/gems/rack-3.2.6/CHANGELOG.md +0 -1346
- data/vendor/bundle/ruby/4.0.0/gems/rack-3.2.6/MIT-LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/rack-3.2.6/README.md +0 -384
- data/vendor/bundle/ruby/4.0.0/gems/rainbow-3.1.1/Changelog.md +0 -101
- data/vendor/bundle/ruby/4.0.0/gems/rainbow-3.1.1/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/rainbow-3.1.1/README.markdown +0 -227
- data/vendor/bundle/ruby/4.0.0/gems/rake-13.4.2/MIT-LICENSE +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rake-13.4.2/README.rdoc +0 -155
- data/vendor/bundle/ruby/4.0.0/gems/rake-release-1.4.0/LICENSE +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rake-release-1.4.0/README.md +0 -107
- data/vendor/bundle/ruby/4.0.0/gems/regexp_parser-2.12.0/LICENSE +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/rexml-3.4.4/LICENSE.txt +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/rexml-3.4.4/README.md +0 -57
- data/vendor/bundle/ruby/4.0.0/gems/rspec-3.13.2/LICENSE.md +0 -27
- data/vendor/bundle/ruby/4.0.0/gems/rspec-3.13.2/README.md +0 -47
- data/vendor/bundle/ruby/4.0.0/gems/rspec-core-3.13.6/Changelog.md +0 -2447
- data/vendor/bundle/ruby/4.0.0/gems/rspec-core-3.13.6/LICENSE.md +0 -26
- data/vendor/bundle/ruby/4.0.0/gems/rspec-core-3.13.6/README.md +0 -389
- data/vendor/bundle/ruby/4.0.0/gems/rspec-expectations-3.13.5/Changelog.md +0 -1366
- data/vendor/bundle/ruby/4.0.0/gems/rspec-expectations-3.13.5/LICENSE.md +0 -25
- data/vendor/bundle/ruby/4.0.0/gems/rspec-expectations-3.13.5/README.md +0 -326
- data/vendor/bundle/ruby/4.0.0/gems/rspec-mocks-3.13.8/Changelog.md +0 -1351
- data/vendor/bundle/ruby/4.0.0/gems/rspec-mocks-3.13.8/LICENSE.md +0 -25
- data/vendor/bundle/ruby/4.0.0/gems/rspec-mocks-3.13.8/README.md +0 -465
- data/vendor/bundle/ruby/4.0.0/gems/rspec-support-3.13.7/Changelog.md +0 -444
- data/vendor/bundle/ruby/4.0.0/gems/rspec-support-3.13.7/LICENSE.md +0 -23
- data/vendor/bundle/ruby/4.0.0/gems/rspec-support-3.13.7/README.md +0 -40
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-1.88.0/LICENSE.txt +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-1.88.0/README.md +0 -255
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-ast-1.49.1/LICENSE.txt +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-ast-1.49.1/README.md +0 -54
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-capybara-2.23.0/CHANGELOG.md +0 -116
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-capybara-2.23.0/MIT-LICENSE.md +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-capybara-2.23.0/README.md +0 -91
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-factory_bot-2.28.0/CHANGELOG.md +0 -135
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-factory_bot-2.28.0/MIT-LICENSE.md +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-factory_bot-2.28.0/README.md +0 -91
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-performance-1.26.1/LICENSE.txt +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-performance-1.26.1/README.md +0 -100
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec-3.10.2/CHANGELOG.md +0 -1136
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec-3.10.2/MIT-LICENSE.md +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec-3.10.2/README.md +0 -112
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec_rails-2.32.0/CHANGELOG.md +0 -98
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec_rails-2.32.0/MIT-LICENSE.md +0 -21
- data/vendor/bundle/ruby/4.0.0/gems/rubocop-rspec_rails-2.32.0/README.md +0 -93
- data/vendor/bundle/ruby/4.0.0/gems/ruby-progressbar-1.13.0/LICENSE.txt +0 -19
- data/vendor/bundle/ruby/4.0.0/gems/ruby-progressbar-1.13.0/README.md +0 -131
- data/vendor/bundle/ruby/4.0.0/gems/securerandom-0.4.1/README.md +0 -72
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-0.22.0/CHANGELOG.md +0 -191
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-0.22.0/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-0.22.0/README.md +0 -974
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-cobertura-3.2.0/LICENSE +0 -202
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-cobertura-3.2.0/README.md +0 -65
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-html-0.13.2/CHANGELOG.md +0 -114
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-html-0.13.2/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/simplecov-html-0.13.2/README.md +0 -30
- data/vendor/bundle/ruby/4.0.0/gems/simplecov_json_formatter-0.1.4/CHANGELOG.md +0 -13
- data/vendor/bundle/ruby/4.0.0/gems/simplecov_json_formatter-0.1.4/README.md +0 -29
- data/vendor/bundle/ruby/4.0.0/gems/typhoeus-1.6.0/CHANGELOG.md +0 -465
- data/vendor/bundle/ruby/4.0.0/gems/typhoeus-1.6.0/LICENSE +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/typhoeus-1.6.0/README.md +0 -588
- data/vendor/bundle/ruby/4.0.0/gems/tzinfo-2.0.6/LICENSE +0 -19
- data/vendor/bundle/ruby/4.0.0/gems/tzinfo-2.0.6/README.md +0 -406
- data/vendor/bundle/ruby/4.0.0/gems/unicode-display_width-3.2.0/CHANGELOG.md +0 -299
- data/vendor/bundle/ruby/4.0.0/gems/unicode-display_width-3.2.0/MIT-LICENSE.txt +0 -22
- data/vendor/bundle/ruby/4.0.0/gems/unicode-display_width-3.2.0/README.md +0 -194
- data/vendor/bundle/ruby/4.0.0/gems/unicode-emoji-4.2.0/CHANGELOG.md +0 -202
- data/vendor/bundle/ruby/4.0.0/gems/unicode-emoji-4.2.0/MIT-LICENSE.txt +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/unicode-emoji-4.2.0/README.md +0 -205
- data/vendor/bundle/ruby/4.0.0/gems/uri-1.1.1/README.md +0 -55
- data/vendor/bundle/ruby/4.0.0/gems/webmock-3.26.2/CHANGELOG.md +0 -2148
- data/vendor/bundle/ruby/4.0.0/gems/webmock-3.26.2/LICENSE +0 -20
- data/vendor/bundle/ruby/4.0.0/gems/webmock-3.26.2/README.md +0 -1229
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Restify::Adapter::Ethon do
|
|
6
|
+
describe 'completed transfers' do
|
|
7
|
+
subject(:value) do
|
|
8
|
+
Restify::Promise.create do |writer|
|
|
9
|
+
described_class.new.send(:complete, easy, request, writer)
|
|
10
|
+
end.value!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
let(:request) { Restify::Request.new(uri: 'http://example.org/base') }
|
|
14
|
+
let(:easy) { instance_double(described_class::Easy, return_code: :ok, response_code: 200) }
|
|
15
|
+
|
|
16
|
+
it 'fulfills the promise with the response' do
|
|
17
|
+
response = instance_double(Restify::Response)
|
|
18
|
+
allow(easy).to receive(:response).with(request).and_return(response)
|
|
19
|
+
|
|
20
|
+
expect(value).to be response
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'rejects the promise on network errors' do
|
|
24
|
+
allow(easy).to receive(:response).and_raise(Restify::NetworkError.new(request, 'kaboom'))
|
|
25
|
+
|
|
26
|
+
expect { value }.to raise_error Restify::NetworkError, /kaboom/
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Unexpected errors must reject the promise too, as the caller would
|
|
30
|
+
# otherwise keep waiting for it until it times out.
|
|
31
|
+
it 'rejects the promise on unexpected errors' do
|
|
32
|
+
allow(easy).to receive(:response).and_raise('kaboom')
|
|
33
|
+
|
|
34
|
+
expect { value }.to raise_error 'kaboom'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe 'waiting on requests' do
|
|
39
|
+
let(:adapter) { described_class.new }
|
|
40
|
+
|
|
41
|
+
# Threads that completed a transfer, i.e. ran the event loop.
|
|
42
|
+
let(:completed_by) { Queue.new }
|
|
43
|
+
|
|
44
|
+
before do
|
|
45
|
+
stub_request(:get, 'http://stubserver/fast')
|
|
46
|
+
.to_return(status: 200, body: '{}')
|
|
47
|
+
stub_request(:get, 'http://stubserver/slow')
|
|
48
|
+
.to_return { sleep 0.5 and {status: 200, body: '{}'} }
|
|
49
|
+
|
|
50
|
+
allow(adapter).to receive(:complete).and_wrap_original do |m, *args|
|
|
51
|
+
completed_by << Thread.current
|
|
52
|
+
m.call(*args)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def request(path)
|
|
57
|
+
Restify::Request.new(uri: "http://localhost:9292/#{path}")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def completed_by_threads
|
|
61
|
+
Array.new(completed_by.size) { completed_by.pop }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'runs the event loop in the waiting thread' do
|
|
65
|
+
expect(adapter.call(request('fast')).value!.code).to eq 200
|
|
66
|
+
expect(completed_by_threads).to eq [Thread.current]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'completes requests nobody waits on in the background' do
|
|
70
|
+
adapter.call(request('fast'))
|
|
71
|
+
|
|
72
|
+
# Poll without waiting on the promise:
|
|
73
|
+
Timeout.timeout(1) { sleep 0.01 while completed_by.empty? }
|
|
74
|
+
|
|
75
|
+
expect(completed_by_threads).not_to include Thread.current
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'times out without blocking other requests' do
|
|
79
|
+
expect { adapter.call(request('slow')).value!(0.1) }.to raise_error Timeout::Error
|
|
80
|
+
expect(adapter.call(request('fast')).value!.code).to eq 200
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'can wait again after a timeout' do
|
|
84
|
+
promise = adapter.call(request('slow'))
|
|
85
|
+
|
|
86
|
+
expect { promise.value!(0.1) }.to raise_error Timeout::Error
|
|
87
|
+
expect(promise.value!(1).code).to eq 200
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'processes requests from many threads' do
|
|
91
|
+
threads = Array.new(8) do
|
|
92
|
+
Thread.new do
|
|
93
|
+
Array.new(5) { adapter.call(request('fast')).value!.code }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
expect(threads.flat_map(&:value)).to all eq 200
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Only the adapter's own promises are completed by whichever thread
|
|
101
|
+
# runs the event loop. Callbacks chained to them must still run in
|
|
102
|
+
# the thread waiting on them, and only when waiting on them.
|
|
103
|
+
describe 'chained callbacks' do
|
|
104
|
+
it 'does not run them before waiting on them' do
|
|
105
|
+
ran_in = Queue.new
|
|
106
|
+
promise = adapter.call(request('fast'))
|
|
107
|
+
chained = promise.then { ran_in << Thread.current }
|
|
108
|
+
|
|
109
|
+
promise.value!
|
|
110
|
+
expect(ran_in).to be_empty
|
|
111
|
+
|
|
112
|
+
chained.value!
|
|
113
|
+
expect(ran_in.pop(timeout: 1)).to eq Thread.current
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'runs them in the waiting thread when another thread runs the loop' do
|
|
117
|
+
# Keep the loop busy in another thread, until after the fast
|
|
118
|
+
# request completed.
|
|
119
|
+
driver = Thread.new { adapter.call(request('slow')).value! }
|
|
120
|
+
sleep 0.1
|
|
121
|
+
|
|
122
|
+
chained = adapter.call(request('fast')).then do |response|
|
|
123
|
+
[Thread.current, response.code]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
expect(chained.value!).to eq [Thread.current, 200]
|
|
127
|
+
expect(completed_by_threads.first).to eq driver
|
|
128
|
+
ensure
|
|
129
|
+
driver&.join
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context 'when waiting from within the event loop' do
|
|
134
|
+
it 'does not run the loop again' do
|
|
135
|
+
adapter.instance_variable_get(:@events).instance_variable_get(:@lock).acquire(0.1)
|
|
136
|
+
|
|
137
|
+
expect(adapter.drive(Restify::Promise.new, Restify::Timeout.new(0.1))).to be false
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe 'reusing easy handles' do
|
|
143
|
+
let(:adapter) { described_class.new }
|
|
144
|
+
let(:root) { Restify.new('http://localhost:9292/echo', adapter:) }
|
|
145
|
+
|
|
146
|
+
# Easy handles of completed transfers, in order.
|
|
147
|
+
let(:handles) { [] }
|
|
148
|
+
|
|
149
|
+
before do
|
|
150
|
+
allow(adapter).to receive(:complete).and_wrap_original do |m, easy, *args|
|
|
151
|
+
handles << easy
|
|
152
|
+
m.call(easy, *args)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def echo(method, *, **)
|
|
157
|
+
JSON.parse(root.send(method, *, **).value!.response.body)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'reuses the handle of a completed request' do
|
|
161
|
+
2.times { root.get.value! }
|
|
162
|
+
|
|
163
|
+
expect(handles[1]).to be handles[0]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'does not reuse handles of requests in progress' do
|
|
167
|
+
Restify::Promise.new(Array.new(2) { root.get }).value!
|
|
168
|
+
|
|
169
|
+
expect(handles[1]).not_to be handles[0]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Nothing must leak from one request into the next one.
|
|
173
|
+
describe 'subsequent requests' do
|
|
174
|
+
it 'use the method of each request' do
|
|
175
|
+
%i[post get head put patch delete get].each do |method|
|
|
176
|
+
response = root.send(method).value!.response
|
|
177
|
+
next if method == :head
|
|
178
|
+
|
|
179
|
+
expect(JSON.parse(response.body)).to include('REQUEST_METHOD' => method.to_s.upcase)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'do not send a previous body' do
|
|
184
|
+
root.post('payload').value!
|
|
185
|
+
|
|
186
|
+
expect(echo(:get)).not_to have_key('CONTENT_LENGTH')
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'do not send previous headers' do
|
|
190
|
+
root.get(headers: {'X-Custom' => 'yes'}).value!
|
|
191
|
+
|
|
192
|
+
expect(echo(:get)).not_to have_key('HTTP_X_CUSTOM')
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it 'receive a body after a HEAD request' do
|
|
196
|
+
root.head.value!
|
|
197
|
+
|
|
198
|
+
expect(root.get.value!.response.body).not_to be_empty
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
describe 'request bodies' do
|
|
203
|
+
before { stub_request(:any, 'http://stubserver/body') }
|
|
204
|
+
|
|
205
|
+
let(:root) { Restify.new('http://localhost:9292/body', adapter:) }
|
|
206
|
+
|
|
207
|
+
%i[post put patch].each do |method|
|
|
208
|
+
it "sends #{method.upcase} bodies" do
|
|
209
|
+
root.send(method, 'payload').value!
|
|
210
|
+
root.send(method, 'other').value!
|
|
211
|
+
|
|
212
|
+
expect(a_request(method, 'http://stubserver/body').with(body: 'payload')).to have_been_made.once
|
|
213
|
+
expect(a_request(method, 'http://stubserver/body').with(body: 'other')).to have_been_made.once
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
describe 'options' do
|
|
220
|
+
it 'raises on unknown options' do
|
|
221
|
+
expect { described_class.new(options: {unknown: 1}) }.to raise_error ArgumentError, /Unknown libcurl option/
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it 'sets options on each request' do
|
|
225
|
+
adapter = described_class.new(options: {useragent: 'restify-spec'})
|
|
226
|
+
root = Restify.new('http://localhost:9292/echo', adapter:)
|
|
227
|
+
|
|
228
|
+
2.times do
|
|
229
|
+
expect(JSON.parse(root.get.value!.response.body)).to include('HTTP_USER_AGENT' => 'restify-spec')
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
describe 'after fork' do
|
|
235
|
+
let(:adapter) { described_class.new }
|
|
236
|
+
let(:connects) { Queue.new }
|
|
237
|
+
|
|
238
|
+
before do
|
|
239
|
+
stub_request(:get, 'http://stubserver/fast')
|
|
240
|
+
.to_return(status: 200, body: '{}')
|
|
241
|
+
stub_request(:get, 'http://stubserver/slow')
|
|
242
|
+
.to_return { sleep 0.5 and {status: 200, body: '{}'} }
|
|
243
|
+
|
|
244
|
+
allow(adapter).to receive(:complete).and_wrap_original do |m, easy, *args|
|
|
245
|
+
connects << Ethon::Curl.get_info_long(:num_connects, easy.handle)
|
|
246
|
+
m.call(easy, *args)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def request(path)
|
|
251
|
+
Restify::Request.new(uri: "http://localhost:9292/#{path}")
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def in_child
|
|
255
|
+
reader, writer = IO.pipe
|
|
256
|
+
|
|
257
|
+
pid = fork do
|
|
258
|
+
reader.close
|
|
259
|
+
result = begin
|
|
260
|
+
yield
|
|
261
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
262
|
+
e
|
|
263
|
+
end
|
|
264
|
+
writer.write(Marshal.dump(result))
|
|
265
|
+
ensure
|
|
266
|
+
# Skip at exit handlers of the parent
|
|
267
|
+
exit!(0)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
writer.close
|
|
271
|
+
Marshal.load(reader.read) # rubocop:disable Security/MarshalLoad
|
|
272
|
+
ensure
|
|
273
|
+
reader&.close
|
|
274
|
+
Process.wait(pid) if pid
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it 'does not use connections of the parent process' do
|
|
278
|
+
# The parent process pools and reuses its connection.
|
|
279
|
+
2.times { adapter.call(request('fast')).value! }
|
|
280
|
+
expect(Array.new(2) { connects.pop(timeout: 1) }).to eq [1, 0]
|
|
281
|
+
|
|
282
|
+
result = in_child do
|
|
283
|
+
code = adapter.call(request('fast')).value!.code
|
|
284
|
+
[code, connects.pop(timeout: 1)]
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# A new connection, not the one pooled by the parent process
|
|
288
|
+
expect(result).to eq [200, 1]
|
|
289
|
+
|
|
290
|
+
# The parent process can still use its connections
|
|
291
|
+
expect(adapter.call(request('fast')).value!.code).to eq 200
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'rejects requests started before the fork in the child process' do
|
|
295
|
+
promise = adapter.call(request('slow'))
|
|
296
|
+
|
|
297
|
+
result = in_child do
|
|
298
|
+
promise.value!
|
|
299
|
+
rescue Restify::NetworkError => e
|
|
300
|
+
e.message
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
expect(result).to include 'before fork'
|
|
304
|
+
expect(promise.value!.code).to eq 200
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Restify::Adapter::LoopLock do
|
|
6
|
+
subject(:lock) { described_class.new { interrupts << Thread.current } }
|
|
7
|
+
|
|
8
|
+
let(:interrupts) { Queue.new }
|
|
9
|
+
let(:threads) { [] }
|
|
10
|
+
|
|
11
|
+
after { threads.each(&:kill).each(&:join) }
|
|
12
|
+
|
|
13
|
+
# Run the block in another thread, and wait until it has returned.
|
|
14
|
+
# The thread is kept alive until the example finished.
|
|
15
|
+
def other(&)
|
|
16
|
+
done = Queue.new
|
|
17
|
+
threads << Thread.new do
|
|
18
|
+
yield
|
|
19
|
+
done << true
|
|
20
|
+
sleep
|
|
21
|
+
end
|
|
22
|
+
expect(done.pop(timeout: 1)).to be true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def elapsed
|
|
26
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
27
|
+
yield
|
|
28
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#acquire' do
|
|
32
|
+
it 'acquires a free loop' do
|
|
33
|
+
expect(lock.acquire(1)).to be true
|
|
34
|
+
expect(lock).to be_owned
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'does not acquire the loop when done' do
|
|
38
|
+
expect(lock.acquire(1) { true }).to be false
|
|
39
|
+
expect(lock).not_to be_owned
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'times out while another thread holds the loop' do
|
|
43
|
+
other { lock.acquire(1) }
|
|
44
|
+
|
|
45
|
+
expect(elapsed { expect(lock.acquire(0.1)).to be false }).to be >= 0.1
|
|
46
|
+
expect(lock).not_to be_owned
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'waits for another thread to release the loop' do
|
|
50
|
+
acquired = Queue.new
|
|
51
|
+
released = false
|
|
52
|
+
threads << Thread.new do
|
|
53
|
+
lock.acquire(1)
|
|
54
|
+
acquired << true
|
|
55
|
+
sleep 0.1
|
|
56
|
+
released = true
|
|
57
|
+
lock.release
|
|
58
|
+
end
|
|
59
|
+
expect(acquired.pop(timeout: 1)).to be true
|
|
60
|
+
|
|
61
|
+
expect(lock.acquire(1)).to be true
|
|
62
|
+
expect(released).to be true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'stops waiting when done after being notified' do
|
|
66
|
+
done = false
|
|
67
|
+
other { lock.acquire(1) }
|
|
68
|
+
threads << Thread.new do
|
|
69
|
+
sleep 0.1
|
|
70
|
+
done = true
|
|
71
|
+
lock.notify
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
expect(elapsed { expect(lock.acquire(1) { done }).to be false }).to be < 0.5
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'treats a dead thread as not holding the loop' do
|
|
78
|
+
Thread.new { lock.acquire(1) }.join
|
|
79
|
+
|
|
80
|
+
expect(lock.acquire(0.1)).to be true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe '#release' do
|
|
85
|
+
it 'lets a waiting thread acquire the loop' do
|
|
86
|
+
lock.acquire(1)
|
|
87
|
+
waiter = Thread.new { lock.acquire(1) }
|
|
88
|
+
sleep 0.05
|
|
89
|
+
|
|
90
|
+
lock.release
|
|
91
|
+
|
|
92
|
+
expect(waiter.join(1)&.value).to be true
|
|
93
|
+
expect(lock).not_to be_owned
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe 'with a background thread' do
|
|
98
|
+
let(:background) { Queue.new }
|
|
99
|
+
|
|
100
|
+
# A background thread running the loop until interrupted, like an
|
|
101
|
+
# event loop waiting for sockets. Blocks on `interrupts` on purpose,
|
|
102
|
+
# and is killed after each example.
|
|
103
|
+
def start_background
|
|
104
|
+
threads << Thread.new do
|
|
105
|
+
loop do
|
|
106
|
+
lock.acquire_background
|
|
107
|
+
background << :acquired
|
|
108
|
+
interrupts.pop
|
|
109
|
+
lock.release
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
expect(background.pop(timeout: 1)).to eq :acquired
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'interrupts the background thread to release the loop' do
|
|
117
|
+
start_background
|
|
118
|
+
|
|
119
|
+
expect(lock.acquire(1)).to be true
|
|
120
|
+
expect(background).to be_empty
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'blocks the background thread while a thread holds the loop' do
|
|
124
|
+
start_background
|
|
125
|
+
lock.acquire(1)
|
|
126
|
+
|
|
127
|
+
sleep 0.1
|
|
128
|
+
expect(background).to be_empty
|
|
129
|
+
|
|
130
|
+
lock.release
|
|
131
|
+
expect(background.pop(timeout: 1)).to eq :acquired
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe '#reset!' do
|
|
136
|
+
it 'forgets threads holding the loop' do
|
|
137
|
+
other { lock.acquire(1) }
|
|
138
|
+
|
|
139
|
+
lock.reset!
|
|
140
|
+
|
|
141
|
+
expect(lock.acquire(0.1)).to be true
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Restify::Adapter::Telemetry do
|
|
6
|
+
subject(:call) { adapter.call(request).value! }
|
|
7
|
+
|
|
8
|
+
let(:adapter) do
|
|
9
|
+
Class.new(Restify::Adapter::Base) do
|
|
10
|
+
def call_native(request, writer)
|
|
11
|
+
writer.fulfill(Restify::Response.new(request, request.uri, 200, {}, ''))
|
|
12
|
+
end
|
|
13
|
+
end.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
let(:request) { Restify::Request.new(uri:) }
|
|
17
|
+
let(:span) { OTLE_EXPORTER.finished_spans.last }
|
|
18
|
+
|
|
19
|
+
before { call }
|
|
20
|
+
|
|
21
|
+
context 'with an explicit port' do
|
|
22
|
+
let(:uri) { Addressable::URI.parse('https://example.org:8443/resources') }
|
|
23
|
+
|
|
24
|
+
it 'records the given port' do
|
|
25
|
+
expect(span.name).to eq 'GET https://example.org:8443'
|
|
26
|
+
expect(span.attributes).to eq({
|
|
27
|
+
'http.request.method' => 'GET',
|
|
28
|
+
'http.response.status_code' => 200,
|
|
29
|
+
'server.address' => 'example.org',
|
|
30
|
+
'server.port' => 8443,
|
|
31
|
+
'url.full' => 'https://example.org:8443/resources',
|
|
32
|
+
'url.scheme' => 'https',
|
|
33
|
+
})
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'without a port' do
|
|
38
|
+
let(:uri) { Addressable::URI.parse('https://example.org/resources') }
|
|
39
|
+
|
|
40
|
+
it 'records the default port of the scheme' do
|
|
41
|
+
expect(span.name).to eq 'GET https://example.org:443'
|
|
42
|
+
expect(span.attributes).to include(
|
|
43
|
+
'server.port' => 443,
|
|
44
|
+
'url.full' => 'https://example.org/resources',
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'with a URI given as a string' do
|
|
50
|
+
let(:uri) { 'http://example.org/resources' }
|
|
51
|
+
|
|
52
|
+
it 'parses it' do
|
|
53
|
+
expect(span.name).to eq 'GET http://example.org:80'
|
|
54
|
+
expect(span.attributes).to include(
|
|
55
|
+
'server.address' => 'example.org',
|
|
56
|
+
'server.port' => 80,
|
|
57
|
+
'url.full' => 'http://example.org/resources',
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Restify::Adapter::Typhoeus do
|
|
6
|
+
let(:request) { Restify::Request.new(uri: 'http://localhost:9292/base') }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
stub_request(:get, 'http://stubserver/base').to_return(status: 200, body: '{}')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe 'sync' do
|
|
13
|
+
let(:adapter) { described_class.new(sync: true) }
|
|
14
|
+
|
|
15
|
+
it 'runs requests from many threads' do
|
|
16
|
+
threads = Array.new(4) do
|
|
17
|
+
Thread.new { Array.new(10) { adapter.call(request).value!.code } }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Do not hang the suite on a deadlock.
|
|
21
|
+
expect(threads.map {|thread| thread.join(5)&.value }).to all eq Array.new(10, 200)
|
|
22
|
+
ensure
|
|
23
|
+
threads&.each(&:kill)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/spec/restify/cache_spec.rb
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
|
-
require 'active_support'
|
|
5
|
-
require 'active_support/cache'
|
|
6
4
|
|
|
7
5
|
describe Restify::Cache do
|
|
8
6
|
subject(:cache) { described_class.new(store) }
|
|
9
7
|
|
|
10
|
-
let(:store) {
|
|
8
|
+
let(:store) { Object.new }
|
|
11
9
|
|
|
12
10
|
describe '#call' do
|
|
13
11
|
let(:request) { instance_double(Restify::Request) }
|
|
@@ -71,4 +71,73 @@ describe Restify::Context do
|
|
|
71
71
|
it_behaves_like 'serialization'
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
|
+
|
|
75
|
+
describe '#join' do
|
|
76
|
+
let(:uri) { 'http://localhost/base/' }
|
|
77
|
+
|
|
78
|
+
it 'resolves relative URIs' do
|
|
79
|
+
expect(context.join('../other').to_s).to eq 'http://localhost/other'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'returns absolute URIs as they are' do
|
|
83
|
+
absolute = Addressable::URI.parse('http://example.org/path')
|
|
84
|
+
|
|
85
|
+
expect(context.join(absolute)).to be absolute
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe '#request' do
|
|
90
|
+
subject(:request) { context.request(:get, '/').value! }
|
|
91
|
+
|
|
92
|
+
let(:adapter) do
|
|
93
|
+
response = Restify::Response.new(nil, Addressable::URI.parse(uri), 200, {}, 'body')
|
|
94
|
+
|
|
95
|
+
instance_double(Restify::Adapter::Base).tap do |adapter|
|
|
96
|
+
allow(adapter).to receive(:call).and_return(Restify::Promise.fulfilled(response))
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
let(:cache) do
|
|
101
|
+
Object.new.tap do |cache|
|
|
102
|
+
def cache.call(request)
|
|
103
|
+
yield(request)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
let(:kwargs) { {adapter:} }
|
|
109
|
+
|
|
110
|
+
it 'calls the adapter without a cache' do
|
|
111
|
+
expect(adapter).to receive(:call).with(Restify::Request)
|
|
112
|
+
|
|
113
|
+
request
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context 'with a cache' do
|
|
117
|
+
let(:kwargs) { {adapter:, cache:} }
|
|
118
|
+
|
|
119
|
+
it 'lets the cache call the adapter' do
|
|
120
|
+
expect(cache).to receive(:call).with(Restify::Request).and_call_original
|
|
121
|
+
expect(adapter).to receive(:call).with(Restify::Request)
|
|
122
|
+
|
|
123
|
+
request
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context 'with a global cache' do
|
|
128
|
+
around do |example|
|
|
129
|
+
Restify.cache = cache
|
|
130
|
+
example.run
|
|
131
|
+
ensure
|
|
132
|
+
Restify.cache = nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it 'lets the cache call the adapter' do
|
|
136
|
+
expect(cache).to receive(:call).with(Restify::Request).and_call_original
|
|
137
|
+
expect(adapter).to receive(:call).with(Restify::Request)
|
|
138
|
+
|
|
139
|
+
request
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
74
143
|
end
|
|
@@ -39,6 +39,8 @@ describe Restify do
|
|
|
39
39
|
# have the Restify span as a parent.
|
|
40
40
|
spans[0].tap do |span|
|
|
41
41
|
expect(span.instrumentation_scope.name).to include('Ethon')
|
|
42
|
+
expect(span.name).to eq 'GET'
|
|
43
|
+
expect(span.attributes).to include('http.request.method' => 'GET')
|
|
42
44
|
expect(span.parent_span_id).to eq spans[1].span_id
|
|
43
45
|
end
|
|
44
46
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Restify do
|
|
6
|
+
# Restify follows relations from URLs in server responses, and libcurl
|
|
7
|
+
# supports far more than HTTP. A server must therefore never be able
|
|
8
|
+
# to make it access e.g. a `file://` or `gopher://` URL.
|
|
9
|
+
describe 'Protocol restrictions' do
|
|
10
|
+
subject(:request) { Restify.new(uri).get.value! }
|
|
11
|
+
|
|
12
|
+
context 'with a file URI' do
|
|
13
|
+
let(:uri) { "file://#{File.expand_path(__FILE__)}" }
|
|
14
|
+
|
|
15
|
+
it 'refuses the request' do
|
|
16
|
+
expect { request }.to raise_error Restify::NetworkError, /protocol/i
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'with a gopher URI' do
|
|
21
|
+
let(:uri) { 'gopher://localhost:70/1' }
|
|
22
|
+
|
|
23
|
+
it 'refuses the request' do
|
|
24
|
+
expect { request }.to raise_error Restify::NetworkError, /protocol/i
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|