restify 1.9.0.rc1 → 1.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56819d6525aa39551a5d638f500585ca7c06ed931ceb0e272bed65cd823db3c8
4
- data.tar.gz: 803ddcde2d84ceb8b860f73a016844aa2aa08cceeeeec307aa6bc9fde87cf0bf
3
+ metadata.gz: e2b5dacc128de6cbfed604453544f51eaeffd16b9b6cb83f5353ecca66d24a8d
4
+ data.tar.gz: 5c3eba335362aea288f851327fa96262e5b464b9a747b092955241bb362e9c0d
5
5
  SHA512:
6
- metadata.gz: a5e62bcb309b29872ac78da6d4cb3ea489da01fd4501c7fadc6beaa299a4fc6d23e9428eef49d82032c055598bc763a006d3d91c4e102c2f98d22db4d9f7c5c0
7
- data.tar.gz: a5e4ade033f7f83fa5d195dd7d034399e96c561121a756dc995577f8e345a9e5aaac9272818902a4f3b9c742d1018c35ee7a39cee1292f2320eece3ce69810a6
6
+ metadata.gz: 32569c3544a1ac6734b3c81c1e2b6a46ea7dba324c1f71f5e85bd1df93b8b73bb70114a7cec37dd8e38e561a821e674e8c437c78757d78df75e1e51b1a5a79f8
7
+ data.tar.gz: 6f03d156fcc20e0dfba3d7fda0a5c7851ff5d9342fbb9b50c4d90d1f43bf65e92f0ecabb714c4023ce4ca8cfb95b231abd7ea5d1e05339e839ea046b17f3d1fe
@@ -1,82 +1,153 @@
1
1
  # Changelog
2
+ All notable changes to this project will be documented in this file.
2
3
 
3
- ## 1.8.0
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
6
 
5
- * Add HEAD request method (#16)
6
7
 
7
- ## 1.7.0
8
8
 
9
- * Introduce promise dependency timeouts (#15)
9
+ ## Unreleased
10
+ ---
10
11
 
11
- ## 1.6.0
12
+ ### New
12
13
 
13
- * Specify headers on restify clients and individual requests (#14)
14
+ ### Changes
14
15
 
15
- ## 1.5.0
16
+ ### Fixes
16
17
 
17
- * Tune typhoeus adapter to be more race-condition resilent
18
- * Add MessagePack processor enabled by default
18
+ ### Breaks
19
19
 
20
- ## 1.4.4
21
20
 
22
- * Fix race condition in typhoeus adapter
23
- * Add `#request` to `NetworkError` to ease debugging
21
+ ## 1.13.0 - (2020-06-12)
22
+ ---
24
23
 
25
- ## 1.4.3
24
+ ### New
25
+ * typhoeus: Support setting per-request libcurl options on adapter
26
+ * typhoeus: Enable short TCP keepalive probes by default (5s/5s)
26
27
 
27
- * Add advanced logging capabilities using logging gem
28
- * Improve compatibility with webmocks returning `nil` as headers
29
28
 
30
- ## 1.4.1
29
+ ## 1.12.0 - (2020-04-01)
30
+ ---
31
31
 
32
- * Fix possible deadlock issues
32
+ ### Added
33
+ * Explicit exception class for HTTP status code 410 (Gone)
33
34
 
34
- ## 1.4.0
35
+ ### Changed
35
36
 
36
- * Fix possible concurrency issue with typhoeus adapter
37
- * Add timeout option to requests (only supported by typhoeus adapter)
37
+ ### Fixed
38
+ * `GatewayError` exception classes introduced in v1.11.0 now properly inherit from `ServerError` (#30)
38
39
 
39
- ## 1.3.1
40
40
 
41
- * Improve typhoeus adapters initial request queuing
42
- * Disable default pipelining
41
+ ## 1.11.0 - (2019-07-11)
42
+ ### Added
43
+ * Explicit exception classes for HTTP status codes 500, 502, 503, 504
43
44
 
44
- ## 1.3.0
45
+ ## 1.10.0 - 2018-12-11
46
+ ### Changed
47
+ - Raise more specific error on a few status codes (#17)
48
+ - Complete promises with an empty list (but a list) of dependencies (#18)
45
49
 
46
- * Improve typhoeus adapter to better utilize concurrency
47
- * Default to new typhoeus adapter
50
+ ## 1.9.0 - 2018-11-13
51
+ ### Changed
52
+ - Do not raise error on 3XX responses but return responses
48
53
 
49
- ## 1.2.1
54
+ ## 1.8.0 - 2018-08-22
55
+ ### Added
56
+ - Add HEAD request method (#16)
50
57
 
51
- * Fix issue with Ruby 2.2 compatibility
58
+ ## 1.7.0 - 2018-08-15
59
+ ### Added
60
+ - Introduce promise dependency timeouts (#15)
52
61
 
53
- ## 1.2.0
62
+ ## 1.6.0 - 2018-08-09
63
+ ### Changed
64
+ - Specify headers on restify clients and individual requests (#14)
54
65
 
55
- * Add experimental PooledEM adapter (#10)
56
- * Improve marshalling of resources
66
+ ## 1.5.0 - 2018-07-31
67
+ ### Added
68
+ - Add MessagePack processor enabled by default
57
69
 
58
- ## 1.1.0
70
+ ### Changed
71
+ - Tune typhoeus adapter to be more race-condition resilent
59
72
 
60
- * Return response body if no processor matches (#7)
61
- * Add shortcuts for creating fulfilled / rejected promises (#6)
73
+ ## 1.4.4 - 2018-07-13
74
+ ### Added
75
+ - Add `#request` to `NetworkError` to ease debugging
62
76
 
63
- ## 1.0.0
77
+ ### Changed
78
+ - Fix race condition in typhoeus adapter
64
79
 
65
- * Experimental cache API doing nothing for now
66
- * Use `~> 1.0` of `concurrent-ruby`
80
+ ## 1.4.3 - 2017-11-15
81
+ ### Added
82
+ - Add advanced logging capabilities using logging gem
67
83
 
68
- ## 0.5.0
84
+ ### Changed
85
+ - Improve compatibility with webmocks returning `nil` as headers
69
86
 
70
- * Add `sync` option to typhoeus adapter
71
- * Add registry for storing entry points
72
- * Make eventmachine based adapter default
87
+ ## 1.4.1 - 2017-11-15
88
+ ### Changed
89
+ - Fix possible deadlock issues
73
90
 
74
- ## 0.4.0
91
+ ## 1.4.0 - 2017-11-10
92
+ ### Added
93
+ - Add timeout option to requests (only supported by typhoeus adapter)
75
94
 
76
- * Add method to explicit access resource data
77
- * Drop obligation in favor of simple Concurrent::IVar based promise class.
95
+ ### Changed
96
+ - Fix possible concurrency issue with typhoeus adapter
97
+
98
+ ## 1.3.1 - 2017-11-10
99
+ ### Changed
100
+ - Improve typhoeus adapters initial request queuing
101
+ - Disable default pipelining
102
+
103
+ ## 1.3.0 - 2017-11-08
104
+ ### Changed
105
+ - Improve typhoeus adapter to better utilize concurrency
106
+ - Default to new typhoeus adapter
107
+
108
+ ## 1.2.1 - 2017-10-30
109
+ ### Changed
110
+ - Fix issue with Ruby 2.2 compatibility
111
+
112
+ ## 1.2.0 - 2017-10-30
113
+ ### Added
114
+ - Add experimental PooledEM adapter (#10)
115
+
116
+ ### Changed
117
+ - Improve marshaling of resources
118
+
119
+ ## 1.1.0 - 2017-05-12
120
+ ### Added
121
+ - Add shortcuts for creating fulfilled / rejected promises (#6)
122
+
123
+ ### Changed
124
+ - Return response body if no processor matches (#7)
125
+
126
+ ## 1.0.0 - 2016-08-22
127
+ ### Added
128
+ - Experimental cache API doing nothing for now
129
+
130
+ ### Changed
131
+ - Use `~> 1.0` of `concurrent-ruby`
132
+
133
+ ## 0.5.0 - 2016-04-04
134
+ ### Added
135
+ - Add `sync` option to typhoeus adapter
136
+ - Add registry for storing entry points
137
+
138
+ ### Changed
139
+ - Make eventmachine based adapter default
140
+
141
+ ## 0.4.0 - 2016-02-24
142
+ ### Added
143
+ - Add method to explicit access resource data
144
+
145
+ ### Changed
146
+ - Use typhoeus as default adapter
147
+ - `Restify.new` returns relation now instead of resource
148
+
149
+ ### Removed
150
+ - Drop obligation in favor of simple Concurrent::IVar based promise class.
78
151
  Notable changes:
79
- - Returned object us of type `Restify::Promise` now.
80
- - `value` will not raise exception but return `nil` in case of failure. Use `value!` for old behavior.
81
- * Use typhoeus as default adapter
82
- * `Restify.new` returns relation now instead of resource
152
+ - Returned object us of type `Restify::Promise` now.
153
+ - `value` will not raise exception but return `nil` in case of failure. Use `value!` for old behavior.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Restify
2
2
 
3
3
  [![Build Status](https://travis-ci.org/jgraichen/restify.svg?branch=master)](https://travis-ci.org/jgraichen/restify)
4
+ [![Code Quality](https://codebeat.co/badges/18ffe6b7-8239-493a-b5b6-be329b9f275d)](https://codebeat.co/projects/github-com-jgraichen-restify-master)
4
5
 
5
6
  Restify is an hypermedia REST client that does parallel, concurrent and keep-alive requests by default.
6
7
 
@@ -14,20 +15,17 @@ Restify is build upon the following libraries:
14
15
  * [addressable](https://github.com/sporkmonger/addressable)
15
16
  * [typhoeus](https://github.com/typhoeus/typhoeus)
16
17
 
17
- It has optional HTTP adapters using:
18
-
19
- * [em-http-request](https://github.com/igrigorik/em-http-request)
20
-
21
18
  The HTTP adapters are mostly run in a background thread and may not survive mid-application forks.
22
19
 
23
- Included processors can handle:
20
+ Restify includes processors to parse responses and to extract links between resources. The following formats are can be parsed:
24
21
 
25
- * Plain JSON with GitHub-style relations
26
- * MessagePack with GitHub-style relations *(currently experimental)*
22
+ * JSON
23
+ * MessagePack
27
24
 
28
- (Beside HTTP Link header that's always supported)
25
+ Links are extracted from
29
26
 
30
- Restify requires Ruby 2.0+.
27
+ * HTTP Link header
28
+ * Github-style relations in payloads
31
29
 
32
30
  ### Planned features
33
31
 
@@ -105,9 +103,9 @@ commit = repo.rel(:commits).get.value.first
105
103
  And print it:
106
104
 
107
105
  ```ruby
108
- puts "Last commit: #{commit[:sha]}"
109
- puts "By #{commit[:commit][:author][:name]} <#{commit[:commit][:author][:email]}>"
110
- puts "#{commit[:commit][:message]}"
106
+ puts "Last commit: #{commit['sha']}"
107
+ puts "By #{commit['commit']['author']['name']} <#{commit['commit']['author']['email']}>"
108
+ puts "#{commit['commit']['message']}"
111
109
  ```
112
110
 
113
111
  See commented example in main spec [`spec/restify_spec.rb`](https://github.com/jgraichen/restify/blob/master/spec/restify_spec.rb#L100) or in the `examples` directory.
@@ -63,8 +63,8 @@ module Restify
63
63
  query: request.uri.normalized_query,
64
64
  body: request.body,
65
65
  head: request.headers
66
- rescue Exception => err # rubocop:disable RescueException
67
- writer.reject err
66
+ rescue Exception => e # rubocop:disable Lint/RescueException
67
+ writer.reject e
68
68
  requests.shift unless pipeline?
69
69
  return
70
70
  end
@@ -200,9 +200,9 @@ module Restify
200
200
  @pool = Pool.new(**kwargs)
201
201
  end
202
202
 
203
- # rubocop:disable MethodLength
204
- # rubocop:disable AbcSize
205
- # rubocop:disable BlockLength
203
+ # rubocop:disable Metrics/MethodLength
204
+ # rubocop:disable Metrics/AbcSize
205
+ # rubocop:disable Metrics/BlockLength
206
206
  def call_native(request, writer)
207
207
  next_tick do
208
208
  defer = @pool.get(request)
@@ -241,9 +241,9 @@ module Restify
241
241
  @pool.remove(conn)
242
242
  writer.reject(req.error)
243
243
  end
244
- rescue Exception => ex # rubocop:disable RescueException
244
+ rescue Exception => e # rubocop:disable Lint/RescueException
245
245
  @pool.remove(conn)
246
- writer.reject(ex)
246
+ writer.reject(e)
247
247
  end
248
248
  end
249
249
  end
@@ -16,19 +16,28 @@ module Restify
16
16
  'Transfer-Encoding' => ''
17
17
  }.freeze
18
18
 
19
- def initialize(sync: false, **options)
20
- @sync = sync
21
- @hydra = ::Typhoeus::Hydra.new(**options)
22
- @mutex = Mutex.new
23
- @signal = ConditionVariable.new
19
+ DEFAULT_OPTIONS = {
20
+ followlocation: true,
21
+ tcp_keepalive: true,
22
+ tcp_keepidle: 5,
23
+ tcp_keepintvl: 5
24
+ }.freeze
25
+
26
+ def initialize(sync: false, options: {}, **kwargs)
27
+ @sync = sync
28
+ @hydra = ::Typhoeus::Hydra.new(**kwargs)
29
+ @mutex = Mutex.new
30
+ @signal = ConditionVariable.new
31
+ @thread = nil
32
+ @options = DEFAULT_OPTIONS.merge(options)
24
33
  end
25
34
 
26
35
  def sync?
27
36
  @sync
28
37
  end
29
38
 
30
- # rubocop:disable AbcSize
31
- # rubocop:disable MethodLength
39
+ # rubocop:disable Metrics/AbcSize
40
+ # rubocop:disable Metrics/MethodLength
32
41
  def call_native(request, writer)
33
42
  req = convert(request, writer)
34
43
 
@@ -56,15 +65,15 @@ module Restify
56
65
 
57
66
  private
58
67
 
59
- # rubocop:disable AbcSize
60
- # rubocop:disable MethodLength
68
+ # rubocop:disable Metrics/AbcSize
69
+ # rubocop:disable Metrics/MethodLength
61
70
  def convert(request, writer)
62
71
  ::Typhoeus::Request.new(
63
72
  request.uri,
73
+ **@options,
64
74
  method: request.method,
65
75
  headers: DEFAULT_HEADERS.merge(request.headers),
66
76
  body: request.body,
67
- followlocation: true,
68
77
  timeout: request.timeout,
69
78
  connecttimeout: request.timeout
70
79
  ).tap do |req|
@@ -123,7 +132,7 @@ module Restify
123
132
  @hydra.queued_requests.any? || @hydra.multi.easy_handles.any?
124
133
  end
125
134
 
126
- # rubocop:disable MethodLength
135
+ # rubocop:disable Metrics/MethodLength
127
136
  def _run
128
137
  debug 'hydra:run'
129
138
  @hydra.run while _ongoing?
@@ -36,7 +36,7 @@ module Restify
36
36
 
37
37
  def inherit(uri, **kwargs)
38
38
  uri ||= self.uri
39
- Context.new uri, kwargs.merge(options)
39
+ Context.new(uri, **kwargs, **options)
40
40
  end
41
41
 
42
42
  def process(response)
@@ -62,7 +62,7 @@ module Restify
62
62
  if !response.errored?
63
63
  process response
64
64
  else
65
- Context.raise_response_error(response)
65
+ raise ResponseError.from_code(response)
66
66
  end
67
67
  end
68
68
  end
@@ -101,18 +101,5 @@ module Restify
101
101
  def default_headers
102
102
  options.fetch(:headers, {})
103
103
  end
104
-
105
- class << self
106
- def raise_response_error(response)
107
- case response.code
108
- when 400...500
109
- raise ClientError.new(response)
110
- when 500...600
111
- raise ServerError.new(response)
112
- else
113
- raise "Unknown response code: #{response.code}"
114
- end
115
- end
116
- end
117
104
  end
118
105
  end
@@ -20,6 +20,37 @@ module Restify
20
20
  class ResponseError < StandardError
21
21
  attr_reader :response
22
22
 
23
+ def self.from_code(response)
24
+ case response.code
25
+ when 400
26
+ BadRequest.new(response)
27
+ when 401
28
+ Unauthorized.new(response)
29
+ when 404
30
+ NotFound.new(response)
31
+ when 406
32
+ NotAcceptable.new(response)
33
+ when 410
34
+ Gone.new(response)
35
+ when 422
36
+ UnprocessableEntity.new(response)
37
+ when 400...500
38
+ ClientError.new(response)
39
+ when 500
40
+ InternalServerError.new(response)
41
+ when 502
42
+ BadGateway.new(response)
43
+ when 503
44
+ ServiceUnavailable.new(response)
45
+ when 504
46
+ GatewayTimeout.new(response)
47
+ when 500...600
48
+ ServerError.new(response)
49
+ else
50
+ raise "Unknown response code: #{response.code}"
51
+ end
52
+ end
53
+
23
54
  def initialize(response)
24
55
  @response = response
25
56
  super "#{response.message} (#{response.code}) for `#{response.uri}':\n" \
@@ -65,4 +96,29 @@ module Restify
65
96
  # A {ServerError} will be raised when a response has a
66
97
  # 5XX status code.
67
98
  class ServerError < ResponseError; end
99
+
100
+ # A {GatewayError} is the common base class for 502, 503 and 504
101
+ # response codes often used by load balancers when upstream servers are
102
+ # failing or not available.
103
+ #
104
+ # This can be used to catch "common" gateway responses.
105
+ class GatewayError < ServerError; end
106
+
107
+ ###
108
+ # CONCRETE SUBCLASSES FOR TYPICAL STATUS CODES
109
+ #
110
+ # This makes it easy to rescue specific expected error types.
111
+
112
+ class BadRequest < ClientError; end
113
+ class Unauthorized < ClientError; end
114
+ class NotFound < ClientError; end
115
+ class NotAcceptable < ClientError; end
116
+ class Gone < ClientError; end
117
+ class UnprocessableEntity < ClientError; end
118
+
119
+ class InternalServerError < ServerError; end
120
+
121
+ class BadGateway < GatewayError; end
122
+ class ServiceUnavailable < GatewayError; end
123
+ class GatewayTimeout < GatewayError; end
68
124
  end
@@ -39,9 +39,9 @@ module Restify
39
39
 
40
40
  def resolve_context(uri, **opts)
41
41
  if uri.is_a? Symbol
42
- Restify::Registry.fetch(uri).inherit(nil, opts)
42
+ Restify::Registry.fetch(uri).inherit(nil, **opts)
43
43
  else
44
- Context.new uri, opts
44
+ Context.new(uri, **opts)
45
45
  end
46
46
  end
47
47
  end
@@ -25,10 +25,10 @@ module Restify
25
25
  end
26
26
 
27
27
  class << self
28
- REGEXP_URI = /<[^>]*>\s*/
29
- REGEXP_PAR = /;\s*\w+\s*=\s*/i
30
- REGEXP_QUT = /"[^"]*"\s*/
31
- REGEXP_ARG = /\w+\s*/i
28
+ REGEXP_URI = /<[^>]*>\s*/.freeze
29
+ REGEXP_PAR = /;\s*\w+\s*=\s*/i.freeze
30
+ REGEXP_QUT = /"[^"]*"\s*/.freeze
31
+ REGEXP_ARG = /\w+\s*/i.freeze
32
32
 
33
33
  def parse(string)
34
34
  scanner = StringScanner.new(string.strip)
@@ -7,6 +7,13 @@ module Restify
7
7
  @dependencies = dependencies.flatten
8
8
 
9
9
  super(&nil)
10
+
11
+ # When dependencies were passed in, but none are left after flattening,
12
+ # then we don't have to wait for explicit dependencies or resolution
13
+ # through a writer.
14
+ if !@task && @dependencies.empty? && dependencies.any?
15
+ complete true, [], nil
16
+ end
10
17
  end
11
18
 
12
19
  def wait(timeout = nil)
@@ -16,6 +23,7 @@ module Restify
16
23
 
17
24
  super
18
25
  raise t if incomplete?
26
+
19
27
  self
20
28
  end
21
29
 
@@ -79,6 +79,7 @@ module Restify
79
79
 
80
80
  def convert_param(value)
81
81
  return value.to_param.to_s if value.respond_to?(:to_param)
82
+
82
83
  value
83
84
  end
84
85
 
@@ -61,6 +61,7 @@ module Restify
61
61
  class << self
62
62
  def new(timeout, *args)
63
63
  return timeout if timeout.is_a?(self)
64
+
64
65
  super
65
66
  end
66
67
  end
@@ -3,9 +3,9 @@
3
3
  module Restify
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 9
6
+ MINOR = 13
7
7
  PATCH = 0
8
- STAGE = :rc1
8
+ STAGE = nil
9
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.').freeze
10
10
 
11
11
  def self.to_s
@@ -47,7 +47,7 @@ describe Restify::Context do
47
47
 
48
48
  context 'YAML' do
49
49
  let(:dump) { YAML.dump(context) }
50
- let(:load) { YAML.load(dump) } # rubocop:disable YAMLLoad
50
+ let(:load) { YAML.load(dump) } # rubocop:disable Security/YAMLLoad
51
51
 
52
52
  subject { load }
53
53
 
@@ -56,7 +56,7 @@ describe Restify::Context do
56
56
 
57
57
  context 'Marshall' do
58
58
  let(:dump) { Marshal.dump(context) }
59
- let(:load) { Marshal.load(dump) } # rubocop:disable MarshalLoad
59
+ let(:load) { Marshal.load(dump) } # rubocop:disable Security/MarshalLoad
60
60
 
61
61
  subject { load }
62
62
 
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Restify::ResponseError do
6
+ let(:response) { double 'response' }
7
+ let(:message) { 'Error' }
8
+ let(:uri) { 'http://localhost' }
9
+
10
+ before do
11
+ allow(response).to receive(:uri).and_return(uri)
12
+ allow(response).to receive(:code).and_return(code)
13
+ allow(response).to receive(:message).and_return(message)
14
+ allow(response).to receive(:decoded_body).and_return({})
15
+ end
16
+
17
+ describe '.from_code' do
18
+ subject(:err) { described_class.from_code(response) }
19
+
20
+ context 'with 400 Bad Request' do
21
+ let(:code) { 400 }
22
+ it { is_expected.to be_a ::Restify::BadRequest }
23
+ end
24
+
25
+ context 'with 401 Unauthorized' do
26
+ let(:code) { 401 }
27
+ it { is_expected.to be_a ::Restify::Unauthorized }
28
+ end
29
+
30
+ context 'with 404 Unauthorized' do
31
+ let(:code) { 404 }
32
+ it { is_expected.to be_a ::Restify::NotFound }
33
+ end
34
+
35
+ context 'with 406 Not Acceptable' do
36
+ let(:code) { 406 }
37
+ it { is_expected.to be_a ::Restify::NotAcceptable }
38
+ end
39
+
40
+ context 'with 410 Gone' do
41
+ let(:code) { 410 }
42
+ it { is_expected.to be_a ::Restify::Gone }
43
+ end
44
+
45
+ context 'with 422 Unprocessable Entity' do
46
+ let(:code) { 422 }
47
+ it { is_expected.to be_a ::Restify::UnprocessableEntity }
48
+ end
49
+
50
+ context 'with 500 Internal Server Error' do
51
+ let(:code) { 500 }
52
+ it { is_expected.to be_a ::Restify::InternalServerError }
53
+ end
54
+
55
+ context 'with 502 Bad Gateway' do
56
+ let(:code) { 502 }
57
+ it { is_expected.to be_a ::Restify::BadGateway }
58
+ end
59
+
60
+ context 'with 503 Service Unavailable' do
61
+ let(:code) { 503 }
62
+ it { is_expected.to be_a ::Restify::ServiceUnavailable }
63
+ end
64
+
65
+ context 'with 504 Gateway Timeout' do
66
+ let(:code) { 504 }
67
+ it { is_expected.to be_a ::Restify::GatewayTimeout }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Restify do
6
+ let!(:request_stub) do
7
+ stub_request(:get, 'http://localhost/base')
8
+ .to_return do
9
+ <<-RESPONSE.gsub(/^ {8}/, '')
10
+ HTTP/1.1 #{http_status}
11
+ Content-Length: 333
12
+ Transfer-Encoding: chunked
13
+ Link: <http://localhost/other>; rel="neat"
14
+ RESPONSE
15
+ end
16
+ end
17
+
18
+ let(:http_status) { '200 OK' }
19
+
20
+ describe 'Error handling' do
21
+ subject(:request) { Restify.new('http://localhost/base').get.value! }
22
+
23
+ context 'for 400 status codes' do
24
+ let(:http_status) { '400 Bad Request' }
25
+
26
+ it 'throws a BadRequest exception' do
27
+ expect { request }.to raise_error Restify::BadRequest
28
+ end
29
+ end
30
+
31
+ context 'for 401 status codes' do
32
+ let(:http_status) { '401 Unauthorized' }
33
+
34
+ it 'throws an Unauthorized exception' do
35
+ expect { request }.to raise_error Restify::Unauthorized
36
+ end
37
+ end
38
+
39
+ context 'for 404 status codes' do
40
+ let(:http_status) { '404 Not Found' }
41
+
42
+ it 'throws a ClientError exception' do
43
+ expect { request }.to raise_error Restify::NotFoundError
44
+ end
45
+ end
46
+
47
+ context 'for 406 status codes' do
48
+ let(:http_status) { '406 Not Acceptable' }
49
+
50
+ it 'throws a NotAcceptable exception' do
51
+ expect { request }.to raise_error Restify::NotAcceptable
52
+ end
53
+ end
54
+
55
+ context 'for 422 status codes' do
56
+ let(:http_status) { '422 Unprocessable Entity' }
57
+
58
+ it 'throws a UnprocessableEntity exception' do
59
+ expect { request }.to raise_error Restify::UnprocessableEntity
60
+ end
61
+ end
62
+
63
+ context 'for any other 4xx status codes' do
64
+ let(:http_status) { '415 Unsupported Media Type' }
65
+
66
+ it 'throws a generic ClientError exception' do
67
+ expect { request }.to raise_error Restify::ClientError
68
+ end
69
+ end
70
+
71
+ context 'for any 5xx status codes' do
72
+ let(:http_status) { '500 Internal Server Error' }
73
+
74
+ it 'throws a generic ServerError exception' do
75
+ expect { request }.to raise_error Restify::ServerError
76
+ end
77
+ end
78
+ end
79
+ end
@@ -26,7 +26,7 @@ describe Restify::Global do
26
26
  let(:options) { {accept: 'application.vnd.github.v3+json'} }
27
27
  let(:context) { Restify::Context.new uri, **options }
28
28
 
29
- subject { global.new name, options }
29
+ subject { global.new(name, **options) }
30
30
 
31
31
  it 'returns relation for stored registry item' do
32
32
  Restify::Registry.store name, uri, options
@@ -163,6 +163,13 @@ describe Restify::Promise do
163
163
  expect(subject).to eq 17
164
164
  end
165
165
  end
166
+
167
+ # Nobody does this explicitly, but it can happen when the array of
168
+ # dependencies is built dynamically.
169
+ context 'with an empty array of dependencies and without task' do
170
+ subject { described_class.new([]).value! }
171
+ it { is_expected.to eq [] }
172
+ end
166
173
  end
167
174
 
168
175
  describe '#wait' do
@@ -134,7 +134,6 @@ describe Restify do
134
134
  # the result is here.
135
135
  expect { create_user_promise.value! }.to \
136
136
  raise_error(Restify::ClientError) do |e|
137
-
138
137
  # Because we forgot to send a "name" the server complains
139
138
  # with an error code that will lead to a raised error.
140
139
 
@@ -206,7 +205,6 @@ describe Restify do
206
205
 
207
206
  expect { create_user_promise.value! }.to \
208
207
  raise_error(Restify::ClientError) do |e|
209
-
210
208
  expect(e.status).to eq :unprocessable_entity
211
209
  expect(e.code).to eq 422
212
210
  expect(e.errors).to eq 'name' => ["can't be blank"]
@@ -3,11 +3,14 @@
3
3
  require 'rspec'
4
4
  require 'webmock/rspec'
5
5
 
6
- if ENV['CI'] || (defined?(:RUBY_ENGINE) && RUBY_ENGINE != 'rbx')
7
- require 'coveralls'
8
- Coveralls.wear! do
9
- add_filter 'spec'
10
- end
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_filter 'spec'
9
+ end
10
+
11
+ if ENV['CI']
12
+ require 'codecov'
13
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
11
14
  end
12
15
 
13
16
  require 'restify'
@@ -35,7 +38,7 @@ require 'webmock/rspec'
35
38
  require 'rspec/collection_matchers'
36
39
  require 'em-synchrony'
37
40
 
38
- Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f }
41
+ Dir[File.expand_path('spec/support/**/*.rb')].sort.each {|f| require f }
39
42
 
40
43
  RSpec.configure do |config|
41
44
  config.order = 'random'
@@ -51,6 +54,7 @@ RSpec.configure do |config|
51
54
  ::Logging.logger.root.add_appenders ::Logging.appenders.stdout
52
55
  end
53
56
 
57
+ config.warnings = true
54
58
  config.after(:suite) do
55
59
  EventMachine.stop if defined?(EventMachine) && EventMachine.reactor_running?
56
60
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restify
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0.rc1
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-16 00:00:00.000000000 Z
11
+ date: 2020-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -56,16 +56,22 @@ dependencies:
56
56
  name: hashie
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '3.3'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '5.0'
62
65
  type: :runtime
63
66
  prerelease: false
64
67
  version_requirements: !ruby/object:Gem::Requirement
65
68
  requirements:
66
- - - "~>"
69
+ - - ">="
67
70
  - !ruby/object:Gem::Version
68
71
  version: '3.3'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.0'
69
75
  - !ruby/object:Gem::Dependency
70
76
  name: rack
71
77
  requirement: !ruby/object:Gem::Requirement
@@ -140,16 +146,16 @@ dependencies:
140
146
  name: bundler
141
147
  requirement: !ruby/object:Gem::Requirement
142
148
  requirements:
143
- - - "~>"
149
+ - - ">="
144
150
  - !ruby/object:Gem::Version
145
- version: '1.5'
151
+ version: '0'
146
152
  type: :development
147
153
  prerelease: false
148
154
  version_requirements: !ruby/object:Gem::Requirement
149
155
  requirements:
150
- - - "~>"
156
+ - - ">="
151
157
  - !ruby/object:Gem::Version
152
- version: '1.5'
158
+ version: '0'
153
159
  description: An experimental hypermedia REST client that uses parallel, keep-alive
154
160
  and pipelined requests by default.
155
161
  email:
@@ -186,8 +192,10 @@ files:
186
192
  - lib/restify/version.rb
187
193
  - spec/restify/cache_spec.rb
188
194
  - spec/restify/context_spec.rb
195
+ - spec/restify/error_spec.rb
189
196
  - spec/restify/features/head_requests_spec.rb
190
197
  - spec/restify/features/request_headers_spec.rb
198
+ - spec/restify/features/response_errors.rb
191
199
  - spec/restify/global_spec.rb
192
200
  - spec/restify/link_spec.rb
193
201
  - spec/restify/processors/base_spec.rb
@@ -215,20 +223,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
215
223
  version: '0'
216
224
  required_rubygems_version: !ruby/object:Gem::Requirement
217
225
  requirements:
218
- - - ">"
226
+ - - ">="
219
227
  - !ruby/object:Gem::Version
220
- version: 1.3.1
228
+ version: '0'
221
229
  requirements: []
222
- rubyforge_project:
223
- rubygems_version: 2.7.7
230
+ rubygems_version: 3.1.2
224
231
  signing_key:
225
232
  specification_version: 4
226
233
  summary: An experimental hypermedia REST client.
227
234
  test_files:
228
235
  - spec/restify/cache_spec.rb
229
236
  - spec/restify/context_spec.rb
237
+ - spec/restify/error_spec.rb
230
238
  - spec/restify/features/head_requests_spec.rb
231
239
  - spec/restify/features/request_headers_spec.rb
240
+ - spec/restify/features/response_errors.rb
232
241
  - spec/restify/global_spec.rb
233
242
  - spec/restify/link_spec.rb
234
243
  - spec/restify/processors/base_spec.rb