rest-core 3.5.4 → 3.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGES.md +6 -0
- data/Gemfile +1 -0
- data/README.md +64 -5
- data/TODO.md +5 -6
- data/lib/rest-core/builder.rb +1 -1
- data/lib/rest-core/engine.rb +1 -0
- data/lib/rest-core/engine/http-client.rb +1 -0
- data/lib/rest-core/middleware/json_response.rb +9 -4
- data/lib/rest-core/thread_pool.rb +32 -27
- data/lib/rest-core/util/json.rb +1 -0
- data/lib/rest-core/util/payload.rb +5 -1
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +4 -4
- data/task/gemgem.rb +6 -2
- data/test/test_builder.rb +1 -1
- data/test/test_default_payload.rb +12 -8
- data/test/test_error_handler.rb +3 -3
- data/test/test_httpclient.rb +72 -1
- data/test/test_thread_pool.rb +28 -4
- data/test/test_timeout.rb +12 -12
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02a017ca6ef776af782e4e7c575858b0cb8f3703
|
4
|
+
data.tar.gz: 8d29c4f87749dccb787c0134f6938a95fe57b733
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d6aad0bedad2f4b7a72a78ec984721515157508d20983425eb2f0354fad6cd092beaaa4d626ae4f1000339d248535d83b9b1da8568afe13adcdb5cf5064fe07
|
7
|
+
data.tar.gz: 2b75fccd0ba262c7f8915217cd142dbcc85f49497a2fe7b40b5d84b3818b74dea0b0982ba8ab601fa6a044c83e346054edd7beab24a56f67766a5c688ad61942
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -25,6 +25,7 @@ end
|
|
25
25
|
|
26
26
|
platforms :rbx do
|
27
27
|
gem 'rubysl-weakref' # used in rest-core
|
28
|
+
gem 'rubysl-socket' # used in test
|
28
29
|
gem 'rubysl-singleton' # used in rake
|
29
30
|
gem 'rubysl-rexml' # used in crack used in webmock
|
30
31
|
gem 'rubysl-bigdecimal' # used in crack used in webmock
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# rest-core [![Build Status](https://secure.travis-ci.org/godfat/rest-core.png?branch=master)](http://travis-ci.org/godfat/rest-core) [![Coverage Status](https://coveralls.io/repos/godfat/rest-core/badge.png)](https://coveralls.io/r/godfat/rest-core)
|
1
|
+
# rest-core [![Build Status](https://secure.travis-ci.org/godfat/rest-core.png?branch=master)](http://travis-ci.org/godfat/rest-core) [![Coverage Status](https://coveralls.io/repos/godfat/rest-core/badge.png)](https://coveralls.io/r/godfat/rest-core) [![Join the chat at https://gitter.im/godfat/rest-core](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/rest-core)
|
2
2
|
|
3
3
|
by Lin Jen-Shin ([godfat](http://godfat.org))
|
4
4
|
|
@@ -301,8 +301,9 @@ Not only JavaScript could receive server-sent events, any languages could.
|
|
301
301
|
Doing so would establish a keep-alive connection to the server, and receive
|
302
302
|
data periodically. We'll take Firebase as an example:
|
303
303
|
|
304
|
-
If you are using Firebase, please consider
|
305
|
-
|
304
|
+
If you are using Firebase, please consider [rest-firebase][] instead.
|
305
|
+
|
306
|
+
[rest-firebase]: https://github.com/CodementorIO/rest-firebase
|
306
307
|
|
307
308
|
``` ruby
|
308
309
|
require 'rest-core'
|
@@ -685,9 +686,67 @@ and complete.
|
|
685
686
|
|
686
687
|
[example/use-cases.rb]: example/use-cases.rb
|
687
688
|
|
689
|
+
## Configure the underlying HTTP engine
|
690
|
+
|
691
|
+
Occasionally we might want to configure the underlying HTTP engine, which
|
692
|
+
for now is [httpclient][]. For example, we might not want to decompress
|
693
|
+
gzip automatically, (rest-core configures httpclient to request and
|
694
|
+
decompress gzip automatically). or we might want to skip verifying SSL
|
695
|
+
in some situation. (e.g. making requests against a self-signed testing server)
|
696
|
+
|
697
|
+
In such cases, we could use `config_engine` option to configure the underlying
|
698
|
+
engine. This could be set with request based, client instance based, or
|
699
|
+
client class based. Please refer to:
|
700
|
+
[How We Pick the Default Value](#how-we-pick-the-default-value),
|
701
|
+
except that there's no middleware for `config_engine`.
|
702
|
+
|
703
|
+
Here are some examples:
|
704
|
+
|
705
|
+
``` ruby
|
706
|
+
require 'rest-core'
|
707
|
+
YourClient = RC::Builder.client
|
708
|
+
|
709
|
+
# class based:
|
710
|
+
def YourClient.default_config_engine
|
711
|
+
lambda do |engine|
|
712
|
+
# disable auto-gzip:
|
713
|
+
engine.transparent_gzip_decompression = false
|
714
|
+
|
715
|
+
# disable verifying SSL
|
716
|
+
engine.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
# instance based:
|
721
|
+
client = YourClient.new(:config_engine => lambda do |engine|
|
722
|
+
# disable auto-gzip:
|
723
|
+
engine.transparent_gzip_decompression = false
|
724
|
+
|
725
|
+
# disable verifying SSL
|
726
|
+
engine.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
727
|
+
end)
|
728
|
+
|
729
|
+
# request based:
|
730
|
+
client.get('http://example.com/', {}, :config_engine => lambda do |engine|
|
731
|
+
# disable auto-gzip:
|
732
|
+
engine.transparent_gzip_decompression = false
|
733
|
+
|
734
|
+
# disable verifying SSL
|
735
|
+
engine.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
736
|
+
end)
|
737
|
+
```
|
738
|
+
|
739
|
+
As we stated in
|
740
|
+
[How We Pick the Default Value](#how-we-pick-the-default-value),
|
741
|
+
the priority here is:
|
742
|
+
|
743
|
+
0. request based
|
744
|
+
0. instance based
|
745
|
+
0. class based
|
746
|
+
|
688
747
|
## rest-core users:
|
689
748
|
|
690
|
-
* [rest-firebase]
|
749
|
+
* [rest-firebase][]
|
691
750
|
* [rest-more][]
|
692
751
|
* [rest-more-yahoo_buy](https://github.com/GoodLife/rest-more-yahoo_buy)
|
693
752
|
* [s2sync](https://github.com/brucehsu/s2sync)
|
@@ -727,7 +786,7 @@ and complete.
|
|
727
786
|
|
728
787
|
Apache License 2.0
|
729
788
|
|
730
|
-
Copyright (c) 2011-
|
789
|
+
Copyright (c) 2011-2015, Lin Jen-Shin (godfat)
|
731
790
|
|
732
791
|
Licensed under the Apache License, Version 2.0 (the "License");
|
733
792
|
you may not use this file except in compliance with the License.
|
data/TODO.md
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
# TODO
|
2
2
|
|
3
|
-
|
4
|
-
* X-Method-Override
|
3
|
+
# NEAR FUTURE
|
5
4
|
|
6
|
-
|
5
|
+
* revisit error_callback (use middleware)
|
6
|
+
* ActiveRecord::ConnectionAdapters::ConnectionManagement
|
7
|
+
|
8
|
+
# FAR FUTURE
|
7
9
|
|
8
10
|
* middleware composer
|
9
11
|
* headers and payload logs for CommonLogger
|
10
|
-
|
11
|
-
# rest-request
|
12
|
-
|
13
12
|
* fix DRY by defining `prepare :: env -> env`
|
14
13
|
* FAIL and LOG need to be reimplemented as well.
|
data/lib/rest-core/builder.rb
CHANGED
data/lib/rest-core/engine.rb
CHANGED
@@ -9,6 +9,7 @@ class RestCore::HttpClient < RestCore::Engine
|
|
9
9
|
client.cookie_manager = nil
|
10
10
|
client.follow_redirect_count = 0
|
11
11
|
client.transparent_gzip_decompression = true
|
12
|
+
config = config_engine(env) and config.call(client)
|
12
13
|
payload, headers = payload_and_headers(env)
|
13
14
|
|
14
15
|
if env[HIJACK]
|
@@ -28,11 +28,16 @@ class RestCore::JsonResponse
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def process response
|
31
|
-
# StackExchange returns the problematic BOM! in UTF-8, so we need to
|
32
|
-
# strip it or it would break JSON parsers (i.e. yajl-ruby and json)
|
33
31
|
body = response[RESPONSE_BODY].to_s.sub(/\A\xEF\xBB\xBF/, '')
|
34
|
-
response
|
35
|
-
|
32
|
+
if response[HIJACK] && Json.respond_to?(:decode_from_io)
|
33
|
+
response.merge(
|
34
|
+
RESPONSE_SOCKET => Json.decode_from_io(response[RESPONSE_SOCKET]))
|
35
|
+
else
|
36
|
+
# StackExchange returns the problematic BOM! in UTF-8, so we need to
|
37
|
+
# strip it or it would break JSON parsers (i.e. yajl-ruby and json)
|
38
|
+
response.merge(RESPONSE_BODY => Json.decode("[#{body}]").first)
|
39
|
+
# [this].first is not needed for yajl-ruby
|
40
|
+
end
|
36
41
|
rescue Json.const_get(:ParseError) => error
|
37
42
|
fail(response, ParseError.new(error, body))
|
38
43
|
end
|
@@ -11,25 +11,24 @@ class RestCore::ThreadPool
|
|
11
11
|
class Queue
|
12
12
|
def initialize
|
13
13
|
@queue = []
|
14
|
-
@mutex = Mutex.new
|
15
14
|
@condv = ConditionVariable.new
|
16
15
|
end
|
17
16
|
|
17
|
+
def size
|
18
|
+
@queue.size
|
19
|
+
end
|
20
|
+
|
18
21
|
def << task
|
19
|
-
|
20
|
-
|
21
|
-
condv.signal
|
22
|
-
end
|
22
|
+
queue << task
|
23
|
+
condv.signal
|
23
24
|
end
|
24
25
|
|
25
|
-
def pop timeout=60
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
queue.shift
|
32
|
-
end
|
26
|
+
def pop mutex, timeout=60
|
27
|
+
if queue.empty?
|
28
|
+
condv.wait(mutex, timeout)
|
29
|
+
queue.shift || lambda{ |_| false } # shutdown idle workers
|
30
|
+
else
|
31
|
+
queue.shift
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
@@ -38,7 +37,7 @@ class RestCore::ThreadPool
|
|
38
37
|
end
|
39
38
|
|
40
39
|
protected
|
41
|
-
attr_reader :queue, :
|
40
|
+
attr_reader :queue, :condv
|
42
41
|
end
|
43
42
|
|
44
43
|
class Task < Struct.new(:job, :mutex, :thread, :cancelled)
|
@@ -61,7 +60,7 @@ class RestCore::ThreadPool
|
|
61
60
|
(@pools ||= {})[client_class] ||= new(client_class)
|
62
61
|
end
|
63
62
|
|
64
|
-
attr_reader :client_class
|
63
|
+
attr_reader :client_class, :workers
|
65
64
|
|
66
65
|
def initialize client_class
|
67
66
|
@client_class = client_class
|
@@ -87,37 +86,43 @@ class RestCore::ThreadPool
|
|
87
86
|
client_class.pool_idle_time
|
88
87
|
end
|
89
88
|
|
90
|
-
def defer
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
def defer promise_mutex, &job
|
90
|
+
mutex.synchronize do
|
91
|
+
task = Task.new(job, promise_mutex)
|
92
|
+
queue << task
|
93
|
+
spawn_worker if waiting < queue.size && workers.size < max_size
|
94
|
+
task
|
95
|
+
end
|
95
96
|
end
|
96
97
|
|
97
98
|
def trim force=false
|
98
|
-
|
99
|
+
mutex.synchronize do
|
100
|
+
queue << lambda{ |_| false } if force || waiting > 0
|
101
|
+
end
|
99
102
|
end
|
100
103
|
|
101
104
|
# Block on shutting down, and should not add more jobs while shutting down
|
102
105
|
def shutdown
|
103
106
|
workers.size.times{ trim(true) }
|
104
107
|
workers.first.join && trim(true) until workers.empty?
|
105
|
-
queue.clear
|
108
|
+
mutex.synchronize{ queue.clear }
|
106
109
|
end
|
107
110
|
|
108
111
|
protected
|
109
|
-
attr_reader :queue, :mutex, :condv, :
|
112
|
+
attr_reader :queue, :mutex, :condv, :waiting
|
110
113
|
|
111
114
|
private
|
112
115
|
def spawn_worker
|
113
116
|
workers << Thread.new{
|
114
|
-
Thread.current.abort_on_exception =
|
117
|
+
Thread.current.abort_on_exception = true
|
115
118
|
|
116
119
|
task = nil
|
117
120
|
begin
|
118
|
-
mutex.synchronize
|
119
|
-
|
120
|
-
|
121
|
+
mutex.synchronize do
|
122
|
+
@waiting += 1
|
123
|
+
task = queue.pop(mutex, idle_time)
|
124
|
+
@waiting -= 1
|
125
|
+
end
|
121
126
|
end while task.call(Thread.current)
|
122
127
|
|
123
128
|
mutex.synchronize{ workers.delete(Thread.current) }
|
data/lib/rest-core/util/json.rb
CHANGED
data/lib/rest-core/version.rb
CHANGED
data/rest-core.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: rest-core 3.5.
|
2
|
+
# stub: rest-core 3.5.5 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "rest-core"
|
6
|
-
s.version = "3.5.
|
6
|
+
s.version = "3.5.5"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Lin Jen-Shin (godfat)"]
|
11
|
-
s.date = "2015-
|
11
|
+
s.date = "2015-07-22"
|
12
12
|
s.description = "Modular Ruby clients interface for REST APIs.\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/godfat/rest-more"
|
13
13
|
s.email = ["godfat (XD) godfat.org"]
|
14
14
|
s.files = [
|
@@ -113,7 +113,7 @@ Gem::Specification.new do |s|
|
|
113
113
|
"test/test_universal.rb"]
|
114
114
|
s.homepage = "https://github.com/godfat/rest-core"
|
115
115
|
s.licenses = ["Apache License 2.0"]
|
116
|
-
s.rubygems_version = "2.4.
|
116
|
+
s.rubygems_version = "2.4.8"
|
117
117
|
s.summary = "Modular Ruby clients interface for REST APIs."
|
118
118
|
s.test_files = [
|
119
119
|
"test/test_auth_basic.rb",
|
data/task/gemgem.rb
CHANGED
@@ -100,8 +100,12 @@ module Gemgem
|
|
100
100
|
if ENV['COV'] || ENV['CI']
|
101
101
|
require 'simplecov'
|
102
102
|
if ENV['CI']
|
103
|
-
|
104
|
-
|
103
|
+
begin
|
104
|
+
require 'coveralls'
|
105
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
106
|
+
rescue LoadError => e
|
107
|
+
puts "Cannot load coveralls, skip: #{e}"
|
108
|
+
end
|
105
109
|
end
|
106
110
|
SimpleCov.start do
|
107
111
|
add_filter('test/')
|
data/test/test_builder.rb
CHANGED
@@ -25,7 +25,7 @@ describe RC::Builder do
|
|
25
25
|
would 'accept middleware without a member' do
|
26
26
|
RC::Builder.client{
|
27
27
|
use Class.new.send(:include, RC::Middleware)
|
28
|
-
}.members.should.eq []
|
28
|
+
}.members.should.eq [:config_engine]
|
29
29
|
end
|
30
30
|
|
31
31
|
would 'not have duplicated fields' do
|
@@ -5,6 +5,10 @@ describe RC::DefaultPayload do
|
|
5
5
|
app = RC::DefaultPayload.new(RC::Dry.new, {})
|
6
6
|
env = {RC::REQUEST_PAYLOAD => {}}
|
7
7
|
|
8
|
+
before do
|
9
|
+
app.instance_eval{@payload = {}}
|
10
|
+
end
|
11
|
+
|
8
12
|
would 'do nothing' do
|
9
13
|
app.call(env){ |r| r[RC::REQUEST_PAYLOAD].should.eq({}) }
|
10
14
|
end
|
@@ -16,9 +20,9 @@ describe RC::DefaultPayload do
|
|
16
20
|
{'pay' => 'load'}}) }
|
17
21
|
|
18
22
|
format = {'format' => 'json'}
|
19
|
-
|
23
|
+
e = {RC::REQUEST_PAYLOAD => format}
|
20
24
|
|
21
|
-
app.call(
|
25
|
+
app.call(e){ |r| r.should.eq({RC::REQUEST_PAYLOAD =>
|
22
26
|
{'pay' => 'load'}.merge(format)})}
|
23
27
|
end
|
24
28
|
|
@@ -32,15 +36,15 @@ describe RC::DefaultPayload do
|
|
32
36
|
|
33
37
|
would 'accept non-hash payload' do
|
34
38
|
u = RC::Universal.new(:log_method => false)
|
35
|
-
|
36
|
-
u.request_full(
|
39
|
+
e = {RC::REQUEST_PAYLOAD => 'payload'}
|
40
|
+
u.request_full(e, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
|
37
41
|
|
38
42
|
u.payload = 'default'
|
39
|
-
u.request_full(
|
40
|
-
u.request_full({}
|
43
|
+
u.request_full( e, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
|
44
|
+
u.request_full({}, u.dry)[RC::REQUEST_PAYLOAD].should.eq('default')
|
41
45
|
|
42
46
|
u = RC::Builder.client{use RC::DefaultPayload, 'maylord'}.new
|
43
|
-
u.request_full({}
|
44
|
-
u.request_full(
|
47
|
+
u.request_full({}, u.dry)[RC::REQUEST_PAYLOAD].should.eq('maylord')
|
48
|
+
u.request_full( e, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
|
45
49
|
end
|
46
50
|
end
|
data/test/test_error_handler.rb
CHANGED
@@ -44,17 +44,17 @@ describe RC::ErrorHandler do
|
|
44
44
|
|
45
45
|
would 'set full backtrace' do
|
46
46
|
url = 'http://example.com/'
|
47
|
-
|
47
|
+
c = RC::Builder.client do
|
48
48
|
use RC::ErrorHandler, lambda{ |env|
|
49
49
|
RuntimeError.new(env[RC::RESPONSE_BODY]) }
|
50
50
|
use RC::ErrorDetectorHttp
|
51
51
|
end.new
|
52
52
|
stub_request(:get, url).to_return(:status => 404, :body => 'nnf')
|
53
|
-
|
53
|
+
c.get(url) do |error|
|
54
54
|
error.message.should.eq 'nnf'
|
55
55
|
error.backtrace.grep(/^#{__FILE__}/).should.not.empty?
|
56
56
|
end
|
57
|
-
|
57
|
+
c.wait
|
58
58
|
end
|
59
59
|
|
60
60
|
would 'not call error_handler if there is already an exception' do
|
data/test/test_httpclient.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
|
+
require 'openssl'
|
5
|
+
require 'socket'
|
6
|
+
require 'zlib'
|
7
|
+
|
4
8
|
describe RC::HttpClient do
|
5
9
|
describe 'POST Payload' do
|
6
10
|
after do
|
@@ -8,7 +12,6 @@ describe RC::HttpClient do
|
|
8
12
|
end
|
9
13
|
|
10
14
|
client = RC::Builder.client
|
11
|
-
client.builder.run(RC::HttpClient)
|
12
15
|
path = 'http://example.com'
|
13
16
|
ok = 'OK'
|
14
17
|
c = client.new
|
@@ -43,5 +46,73 @@ describe RC::HttpClient do
|
|
43
46
|
c.request(RC::ASYNC => true).message.should.eq 'boom'
|
44
47
|
Muack.verify
|
45
48
|
end
|
49
|
+
|
50
|
+
def accept body
|
51
|
+
server = TCPServer.new(0)
|
52
|
+
t = Thread.new do
|
53
|
+
client = server.accept
|
54
|
+
client.write(<<-HTTP)
|
55
|
+
HTTP/1.0 200 OK\r
|
56
|
+
Connection: close\r
|
57
|
+
Content-Encoding: deflate\r
|
58
|
+
\r
|
59
|
+
#{body}\r
|
60
|
+
HTTP
|
61
|
+
client.close_write
|
62
|
+
end
|
63
|
+
|
64
|
+
yield("http://localhost:#{server.local_address.ip_port}")
|
65
|
+
|
66
|
+
t.join
|
67
|
+
end
|
68
|
+
|
69
|
+
would 'accept deflate' do
|
70
|
+
accept(Zlib::Deflate.deflate(ok)) do |site|
|
71
|
+
c.post(site, 'body').should.eq ok
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
config_engine = lambda do |engine|
|
76
|
+
engine.transparent_gzip_decompression = false
|
77
|
+
engine.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method(:define_default_config_engine) do |d|
|
81
|
+
d.singleton_class.module_eval do
|
82
|
+
define_method(:default_config_engine) do
|
83
|
+
config_engine
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
would 'disable auto-deflate' do
|
89
|
+
accept(ok) do |site|
|
90
|
+
c.post(site, 'body', {}, :config_engine => config_engine).
|
91
|
+
chomp.should.eq ok
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
would 'disable auto-deflate with class default_config_engine' do
|
96
|
+
accept(ok) do |site|
|
97
|
+
d = RC::Builder.client
|
98
|
+
define_default_config_engine(d)
|
99
|
+
d.new.post(site, 'body').chomp.should.eq ok
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
would 'disable auto-deflate with instance default_config_engine' do
|
104
|
+
accept(ok) do |site|
|
105
|
+
d = RC::Builder.client.new
|
106
|
+
define_default_config_engine(d)
|
107
|
+
d.post(site, 'body').chomp.should.eq ok
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
would 'disable auto-deflate with setting config_engine' do
|
112
|
+
accept(ok) do |site|
|
113
|
+
d = RC::Builder.client.new(:config_engine => config_engine)
|
114
|
+
d.post(site, 'body').chomp.should.eq ok
|
115
|
+
end
|
116
|
+
end
|
46
117
|
end
|
47
118
|
end
|
data/test/test_thread_pool.rb
CHANGED
@@ -2,9 +2,33 @@
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
4
|
describe RC::ThreadPool do
|
5
|
-
would 'have the same pool for the same client' do
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
# would 'have the same pool for the same client' do
|
6
|
+
# client = RC::Builder.client
|
7
|
+
# pool = RC::ThreadPool[client]
|
8
|
+
# RC::ThreadPool[client].object_id.should.eq pool.object_id
|
9
|
+
# end
|
10
|
+
|
11
|
+
would 'not waiting forever' do
|
12
|
+
mutex = Mutex.new
|
13
|
+
condv = ConditionVariable.new
|
14
|
+
klass = Struct.new(:pool_size, :pool_idle_time).new(2, 10)
|
15
|
+
pool = RC::ThreadPool[klass]
|
16
|
+
pool.defer(mutex){mutex.synchronize{ condv.signal }} # populate one worker
|
17
|
+
mutex.synchronize{ condv.wait(mutex) }
|
18
|
+
called = []
|
19
|
+
pool.defer(mutex) do
|
20
|
+
sleep 1
|
21
|
+
called << 0
|
22
|
+
end
|
23
|
+
pool.defer(mutex) do
|
24
|
+
sleep 1
|
25
|
+
called << 0
|
26
|
+
pool.defer(mutex) do
|
27
|
+
called << 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
sleep 5
|
31
|
+
p called
|
32
|
+
ok
|
9
33
|
end
|
10
34
|
end
|
data/test/test_timeout.rb
CHANGED
@@ -23,7 +23,7 @@ describe RC::Timeout do
|
|
23
23
|
|
24
24
|
would "not raise timeout error if there's already an error" do
|
25
25
|
env = {'timeout' => 0.01}
|
26
|
-
mock(app.app).call(
|
26
|
+
mock(app.app).call(having(env)){ raise "error" }
|
27
27
|
lambda{ app.call(env){} }.should .raise(RuntimeError)
|
28
28
|
lambda{ sleep 0.01 }.should.not.raise(Timeout::Error)
|
29
29
|
end
|
@@ -51,21 +51,21 @@ describe RC::Timeout do
|
|
51
51
|
|
52
52
|
would 'cancel the task if timing out for thread pool' do
|
53
53
|
timer = fake_timer
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
a = sleeping_app
|
55
|
+
a.pool_size = 1
|
56
|
+
a.new.request(RC::TIMER => timer, RC::ASYNC => true).
|
57
57
|
message.should.eq 'boom'
|
58
58
|
timer.timer.should.not.nil?
|
59
59
|
end
|
60
60
|
|
61
61
|
would 'still timeout if the task never processed for thread pool' do
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
a = sleeping_app
|
63
|
+
a.pool_size = 1
|
64
|
+
a.new.request(RC::TIMER => fake_timer, RC::ASYNC => true) do |e|
|
65
65
|
e.message.should.eq 'boom'
|
66
|
-
|
66
|
+
a.new.request(RC::TIMER => fake_timer, RC::ASYNC => true).tap{}
|
67
67
|
end
|
68
|
-
|
68
|
+
a.wait
|
69
69
|
end
|
70
70
|
|
71
71
|
would 'interrupt the task if timing out' do
|
@@ -85,7 +85,7 @@ describe RC::Timeout do
|
|
85
85
|
def timer ; @block; end
|
86
86
|
self
|
87
87
|
end
|
88
|
-
|
88
|
+
a = RC::Builder.client do
|
89
89
|
run Class.new(RC::Engine){
|
90
90
|
def request _, env
|
91
91
|
env['pipe'].puts
|
@@ -94,8 +94,8 @@ describe RC::Timeout do
|
|
94
94
|
}
|
95
95
|
end
|
96
96
|
(-1..1).each do |size|
|
97
|
-
|
98
|
-
|
97
|
+
a.pool_size = size
|
98
|
+
a.new.request(RC::TIMER => timer, RC::ASYNC => true, 'pipe' => wr).
|
99
99
|
message.should.eq 'boom'
|
100
100
|
end
|
101
101
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.5.
|
4
|
+
version: 3.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httpclient
|
@@ -188,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
188
|
version: '0'
|
189
189
|
requirements: []
|
190
190
|
rubyforge_project:
|
191
|
-
rubygems_version: 2.4.
|
191
|
+
rubygems_version: 2.4.8
|
192
192
|
signing_key:
|
193
193
|
specification_version: 4
|
194
194
|
summary: Modular Ruby clients interface for REST APIs.
|