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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c924d022a2e6884c045b8d70ad7c1a30d86a5ca5
4
- data.tar.gz: 29232062eafc2a9f2dc6619da8470c79cf475dab
3
+ metadata.gz: 02a017ca6ef776af782e4e7c575858b0cb8f3703
4
+ data.tar.gz: 8d29c4f87749dccb787c0134f6938a95fe57b733
5
5
  SHA512:
6
- metadata.gz: b9b3a2c2fd0c54d3406988ded11b4954a7f620f3209a8fec4187e013a39b039be17a8ce68186365ed6c7d0a740130b177ab06f9323cea5b87bd88746235c3351
7
- data.tar.gz: 87b917cd53b4f80ed97d7ed172b5ad54063d5db868b525ca0501297f85c2f413d1c88d43ee80a8e59cda2179f5c0600156f4d36b0e85eca8169bfba210fe2d75
6
+ metadata.gz: 0d6aad0bedad2f4b7a72a78ec984721515157508d20983425eb2f0354fad6cd092beaaa4d626ae4f1000339d248535d83b9b1da8568afe13adcdb5cf5064fe07
7
+ data.tar.gz: 2b75fccd0ba262c7f8915217cd142dbcc85f49497a2fe7b40b5d84b3818b74dea0b0982ba8ab601fa6a044c83e346054edd7beab24a56f67766a5c688ad61942
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ rvm:
6
6
  - 2.2
7
7
  - rbx-2
8
8
  - jruby
9
- - jruby-head
10
9
 
11
10
  install: 'bundle install --retry=3'
12
11
  script: 'ruby -r bundler/setup -S rake test'
data/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 3.5.5 -- 2015-07-22
4
+
5
+ ### Bugs fixed
6
+
7
+ * Fixed a possible data race for thread pool when enqueuing very quickly.
8
+
3
9
  ## rest-core 3.5.4 -- 2015-01-17
4
10
 
5
11
  ### Bugs fixed
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 the pre-built client in
305
- [rest-more][] instead.
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](https://github.com/CodementorIO/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-2014, Lin Jen-Shin (godfat)
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
- * middleware revisit (how to initialize?)
4
- * X-Method-Override
3
+ # NEAR FUTURE
5
4
 
6
- # FEATURE
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.
@@ -54,7 +54,7 @@ class RestCore::Builder
54
54
  end
55
55
 
56
56
  def to_client *attrs
57
- fields = members + attrs
57
+ fields = (members + attrs + [:config_engine]).uniq
58
58
  struct = build_struct(fields)
59
59
  client = Class.new(struct)
60
60
  client.const_set('Struct', struct)
@@ -3,6 +3,7 @@ require 'rest-core/promise'
3
3
  require 'rest-core/middleware'
4
4
 
5
5
  class RestCore::Engine
6
+ def self.members; [:config_engine]; end
6
7
  include RestCore::Middleware
7
8
 
8
9
  def call env, &k
@@ -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.merge(RESPONSE_BODY => Json.decode("[#{body}]").first)
35
- # [this].first is not needed for yajl-ruby
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
- mutex.synchronize do
20
- queue << task
21
- condv.signal
22
- end
22
+ queue << task
23
+ condv.signal
23
24
  end
24
25
 
25
- def pop timeout=60
26
- mutex.synchronize do
27
- if queue.empty?
28
- condv.wait(mutex, timeout)
29
- queue.shift || lambda{ |_| false } # shutdown idle workers
30
- else
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, :mutex, :condv
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 mutex=nil, &job
91
- task = Task.new(job, mutex)
92
- queue << task
93
- spawn_worker if waiting == 0 && workers.size < max_size
94
- task
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
- queue << lambda{ |_| false } if force || waiting > 0
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, :workers, :waiting
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 = !!$DEBUG
117
+ Thread.current.abort_on_exception = true
115
118
 
116
119
  task = nil
117
120
  begin
118
- mutex.synchronize{ @waiting += 1 }
119
- task = queue.pop(idle_time)
120
- mutex.synchronize{ @waiting -= 1 }
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) }
@@ -23,6 +23,7 @@ module RestCore::Json
23
23
  def decode json
24
24
  Yajl::Parser.parse(json)
25
25
  end
26
+ alias_method :decode_from_io, :decode
26
27
  end
27
28
 
28
29
  module Json
@@ -3,7 +3,11 @@
3
3
 
4
4
  require 'rest-core/error'
5
5
 
6
- require 'mime/types'
6
+ begin
7
+ require 'mime/types/columnar'
8
+ rescue LoadError
9
+ require 'mime/types'
10
+ end
7
11
 
8
12
  require 'stringio'
9
13
  require 'tempfile'
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '3.5.4'
3
+ VERSION = '3.5.5'
4
4
  end
data/rest-core.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-core 3.5.4 ruby lib
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.4"
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-01-17"
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.5"
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
- require 'coveralls'
104
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
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
- env = {RC::REQUEST_PAYLOAD => format}
23
+ e = {RC::REQUEST_PAYLOAD => format}
20
24
 
21
- app.call(env){ |r| r.should.eq({RC::REQUEST_PAYLOAD =>
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
- env = {RC::REQUEST_PAYLOAD => 'payload'}
36
- u.request_full(env, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
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(env, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
40
- u.request_full({} , u.dry)[RC::REQUEST_PAYLOAD].should.eq('default')
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({} , u.dry)[RC::REQUEST_PAYLOAD].should.eq('maylord')
44
- u.request_full(env, u.dry)[RC::REQUEST_PAYLOAD].should.eq('payload')
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
@@ -44,17 +44,17 @@ describe RC::ErrorHandler do
44
44
 
45
45
  would 'set full backtrace' do
46
46
  url = 'http://example.com/'
47
- client = RC::Builder.client do
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
- client.get(url) do |error|
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
- client.wait
57
+ c.wait
58
58
  end
59
59
 
60
60
  would 'not call error_handler if there is already an exception' do
@@ -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
@@ -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
- client = RC::Builder.client
7
- pool = RC::ThreadPool[client]
8
- RC::ThreadPool[client].object_id.should.eq pool.object_id
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(hash_including(env)){ raise "error" }
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
- app = sleeping_app
55
- app.pool_size = 1
56
- app.new.request(RC::TIMER => timer, RC::ASYNC => true).
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
- app = sleeping_app
63
- app.pool_size = 1
64
- app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true) do |e|
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
- app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true).tap{}
66
+ a.new.request(RC::TIMER => fake_timer, RC::ASYNC => true).tap{}
67
67
  end
68
- app.wait
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
- app = RC::Builder.client do
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
- app.pool_size = size
98
- app.new.request(RC::TIMER => timer, RC::ASYNC => true, 'pipe' => wr).
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
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-01-17 00:00:00.000000000 Z
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.5
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.