excon-hypermedia 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/README.md +6 -3
- data/excon-hypermedia.gemspec +1 -0
- data/lib/excon/hypermedia/middleware.rb +7 -2
- data/lib/excon/hypermedia/middlewares/hypertext_cache_pattern.rb +49 -18
- data/lib/excon/hypermedia/response.rb +3 -7
- data/lib/excon/hypermedia/version.rb +1 -1
- data/test/excon/edgecase_test.rb +11 -37
- data/test/excon/hcp_test.rb +8 -7
- data/test/excon/integration_test.rb +5 -14
- data/test/excon/link_object_test.rb +3 -4
- data/test/excon/links_test.rb +2 -3
- data/test/excon/properties_test.rb +0 -1
- data/test/excon/resource_object_test.rb +1 -2
- data/test/excon/response_test.rb +1 -1
- data/test/support/responses.rb +142 -0
- data/test/support/server.rb +35 -0
- data/test/test_helper.rb +32 -144
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e498dada7c682834913fd4c4267edd45fe744d2
|
4
|
+
data.tar.gz: 7e399ffe806735ccbf5984ab2d74bcf49646fe68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 558647f962ced9141ee73e82a83e296d3c88f711cf1b3769f0814ae0b6cfd6cc92ce0814c202fa0f450cf1df1d06cf6e91439f3c765432d96cc20b31c12a60eb
|
7
|
+
data.tar.gz: cc3ad5802a30119dbaead138216298cd371bbf664c1679a1f6a6caaaf6939031cde9b3ea357191bb289d2adadaabccba653af3fa73d00f197556fff8620ca24d
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -280,9 +280,12 @@ pump.resource.weight # => '2kg'
|
|
280
280
|
```
|
281
281
|
|
282
282
|
This feature only works if you are sure the embedded resource is equal to the
|
283
|
-
resource returned by the link relation.
|
284
|
-
|
285
|
-
|
283
|
+
resource returned by the link relation. Also, the embedded resource needs to
|
284
|
+
have a `self` link in order to stub the correct endpoint.
|
285
|
+
|
286
|
+
Because of these requirement, the default configuration has `hcp` disabled, you
|
287
|
+
can either enable it per request (which also enables it for future requests in
|
288
|
+
the chain), or enable it globally:
|
286
289
|
|
287
290
|
```ruby
|
288
291
|
Excon.defaults[:hcp] = true
|
data/excon-hypermedia.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'rubocop', '~> 0.40'
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.10'
|
25
25
|
spec.add_development_dependency 'm', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'open4', '~> 1.3'
|
26
27
|
|
27
28
|
spec.add_dependency 'backport_dig' if RUBY_VERSION < '2.3'
|
28
29
|
spec.add_dependency 'excon', '~> 0.49'
|
@@ -17,8 +17,13 @@ module Excon
|
|
17
17
|
#
|
18
18
|
class Middleware < Excon::Middleware::Base
|
19
19
|
def request_call(datum)
|
20
|
-
|
21
|
-
|
20
|
+
# if `hcp` is enabled, insert the `HypertextCachePattern` middleware in
|
21
|
+
# the middleware stack right after this one.
|
22
|
+
if datum[:hcp]
|
23
|
+
orig_stack = @stack
|
24
|
+
@stack = Excon::HyperMedia::Middlewares::HypertextCachePattern.new(orig_stack)
|
25
|
+
end
|
26
|
+
|
22
27
|
super
|
23
28
|
end
|
24
29
|
|
@@ -15,37 +15,68 @@ module Excon
|
|
15
15
|
def request_call(datum)
|
16
16
|
@datum = datum
|
17
17
|
|
18
|
-
|
18
|
+
if stubs.any?
|
19
|
+
# We've created new stubs. The request should be marked as `mocked`
|
20
|
+
# to make sure the stubbed response is returned.
|
21
|
+
datum[:mock] = true
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# The requested resource might not be part of the embedded resources
|
24
|
+
# so we allow external requests.
|
25
|
+
# datum[:allow_unstubbed_requests] = true
|
26
|
+
|
27
|
+
# Make sure Excon's `Mock` middleware runs after this middleware, as
|
28
|
+
# it might have already triggered in the middleware chain.
|
29
|
+
orig_stack = @stack
|
30
|
+
@stack = Excon::Middleware::Mock.new(orig_stack)
|
31
|
+
end
|
32
|
+
|
33
|
+
super
|
34
|
+
rescue => e
|
35
|
+
raise unless e.class == Excon::Errors::StubNotFound
|
27
36
|
|
37
|
+
# If a request was made to a non-stubbed resource, don't use the Mock
|
38
|
+
# middleware, but simply send the request to the server.
|
39
|
+
@stack = orig_stack
|
28
40
|
super
|
29
41
|
end
|
30
42
|
|
31
|
-
|
43
|
+
def response_call(datum)
|
44
|
+
@datum = datum
|
32
45
|
|
33
|
-
|
34
|
-
|
46
|
+
# After the response is returned, remove any request-specific stubs
|
47
|
+
# from Excon, so they can't be accidentally re-used anymore.
|
48
|
+
embedded.each { |r| (match = matcher(r)) && Excon.unstub(match) }
|
49
|
+
|
50
|
+
super
|
35
51
|
end
|
36
52
|
|
37
|
-
|
38
|
-
|
53
|
+
private
|
54
|
+
|
55
|
+
def stubs
|
56
|
+
embedded.each { |r| (match = matcher(r)) && Excon.stub(match, response(r)) }.compact
|
39
57
|
end
|
40
58
|
|
41
|
-
def
|
42
|
-
|
59
|
+
def matcher(resource)
|
60
|
+
return unless (uri = ::Addressable::URI.parse(resource.dig('_links', 'self', 'href')))
|
61
|
+
|
62
|
+
{
|
63
|
+
scheme: uri.scheme,
|
64
|
+
host: uri.host,
|
65
|
+
path: uri.path,
|
66
|
+
query: uri.query
|
67
|
+
}
|
43
68
|
end
|
44
69
|
|
45
|
-
def
|
46
|
-
|
70
|
+
def response(resource)
|
71
|
+
{
|
72
|
+
body: resource.to_json,
|
73
|
+
hcp: true,
|
74
|
+
headers: { 'Content-Type' => 'application/hal+json', 'X-HCP' => 'true' }
|
75
|
+
}
|
76
|
+
end
|
47
77
|
|
48
|
-
|
78
|
+
def embedded
|
79
|
+
datum[:embedded].to_h.values.flatten
|
49
80
|
end
|
50
81
|
end
|
51
82
|
end
|
@@ -58,19 +58,15 @@ module Excon
|
|
58
58
|
raise UnknownRelationError, "unknown relation: #{name}"
|
59
59
|
end
|
60
60
|
|
61
|
-
options = rel_params(
|
61
|
+
options = rel_params(params.first.to_h)
|
62
62
|
|
63
63
|
link.respond_to?(:to_ary) ? link.map { |l| l.rel(options) } : link.rel(options)
|
64
64
|
end
|
65
65
|
|
66
|
-
def rel_params(
|
66
|
+
def rel_params(params)
|
67
67
|
params.merge(
|
68
68
|
hcp: (params[:hcp].nil? ? response.data[:hcp] : params[:hcp]),
|
69
|
-
|
70
|
-
content_type: response.headers['Content-Type'],
|
71
|
-
embedded: resource._embedded.to_h,
|
72
|
-
relation: name
|
73
|
-
},
|
69
|
+
embedded: resource._embedded.to_h,
|
74
70
|
hypermedia: true
|
75
71
|
)
|
76
72
|
end
|
data/test/excon/edgecase_test.rb
CHANGED
@@ -8,22 +8,8 @@ module Excon
|
|
8
8
|
# Validate edge cases (or: non-happy path)
|
9
9
|
#
|
10
10
|
class EdgeCaseTest < HyperMediaTest
|
11
|
-
def
|
12
|
-
|
13
|
-
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
14
|
-
|
15
|
-
response = { headers: { 'Content-Type' => 'application/hal+json' } }
|
16
|
-
Excon.stub({ path: '/api.json' }, response.merge(body: api_body))
|
17
|
-
Excon.stub({ path: '/empty_json' }, response.merge(body: '{}'))
|
18
|
-
end
|
19
|
-
|
20
|
-
def teardown
|
21
|
-
Excon.stubs.clear
|
22
|
-
Excon.defaults[:middlewares].delete(Excon::HyperMedia::Middleware)
|
23
|
-
end
|
24
|
-
|
25
|
-
def api
|
26
|
-
Excon.get('https://www.example.org/api.json')
|
11
|
+
def empty_json_resource
|
12
|
+
empty_json_response.resource
|
27
13
|
end
|
28
14
|
|
29
15
|
def test_missing_middleware
|
@@ -47,42 +33,30 @@ module Excon
|
|
47
33
|
end
|
48
34
|
|
49
35
|
def test_missing_links
|
50
|
-
|
51
|
-
|
52
|
-
assert_equal({}, resource._links.to_h)
|
36
|
+
assert_equal({}, empty_json_resource._links.to_h)
|
53
37
|
end
|
54
38
|
|
55
39
|
def test_missing_embedded
|
56
|
-
|
57
|
-
|
58
|
-
assert_equal({}, resource._embedded.to_h)
|
40
|
+
assert_equal({}, empty_json_resource._embedded.to_h)
|
59
41
|
end
|
60
42
|
|
61
43
|
def test_missing_properties
|
62
|
-
|
63
|
-
|
64
|
-
assert_equal({}, resource._properties.to_h)
|
44
|
+
assert_equal({}, empty_json_resource._properties.to_h)
|
65
45
|
end
|
66
46
|
|
67
47
|
def test_unknown_property
|
68
|
-
|
69
|
-
|
70
|
-
assert_equal nil, resource._properties.invalid
|
71
|
-
assert_equal nil, resource._properties['invalid']
|
48
|
+
assert_equal nil, api.resource._properties.invalid
|
49
|
+
assert_equal nil, api.resource._properties['invalid']
|
72
50
|
end
|
73
51
|
|
74
52
|
def test_unknown_link
|
75
|
-
|
76
|
-
|
77
|
-
assert_equal nil, resource._links.invalid
|
78
|
-
assert_equal nil, resource._links['invalid']
|
53
|
+
assert_equal nil, empty_json_resource._links.invalid
|
54
|
+
assert_equal nil, empty_json_resource._links['invalid']
|
79
55
|
end
|
80
56
|
|
81
57
|
def test_unknown_embed
|
82
|
-
|
83
|
-
|
84
|
-
assert_equal nil, resource._embedded.invalid
|
85
|
-
assert_equal nil, resource._embedded['invalid']
|
58
|
+
assert_equal nil, api.resource._embedded.invalid
|
59
|
+
assert_equal nil, api.resource._embedded['invalid']
|
86
60
|
end
|
87
61
|
end
|
88
62
|
end
|
data/test/excon/hcp_test.rb
CHANGED
@@ -9,7 +9,7 @@ module Excon
|
|
9
9
|
#
|
10
10
|
class HCPTest < HyperMediaTest
|
11
11
|
def response
|
12
|
-
|
12
|
+
bicycle
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_non_hcp_response
|
@@ -21,16 +21,21 @@ module Excon
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_hcp_response_without_existing_response
|
24
|
-
assert Excon.get('
|
24
|
+
assert Excon.get(url('/product/bicycle'), hcp: true)
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_hcp_response_with_missing_embedding
|
28
|
-
api = Excon.get('https://www.example.org/api.json')
|
29
28
|
response = api.rel('product', expand: { uid: 'bicycle' }, hcp: true).get
|
30
29
|
|
31
30
|
assert_equal nil, response[:hcp]
|
32
31
|
end
|
33
32
|
|
33
|
+
def test_hcp_response_with_embedding_but_missing_embed_for_request
|
34
|
+
handlebar = response.rel('handlebar', hcp: true).get
|
35
|
+
|
36
|
+
assert_equal nil, handlebar[:hcp]
|
37
|
+
end
|
38
|
+
|
34
39
|
def test_hcp_response_with_embedded_array
|
35
40
|
wheels = response.rel('wheels', hcp: true)
|
36
41
|
|
@@ -44,10 +49,6 @@ module Excon
|
|
44
49
|
assert response[:hcp]
|
45
50
|
end
|
46
51
|
|
47
|
-
def test_hcp_not_working_for_non_get_requests
|
48
|
-
assert_equal nil, response.rel('pump', hcp: true).post[:hcp]
|
49
|
-
end
|
50
|
-
|
51
52
|
def test_hcp_resource
|
52
53
|
resource = response.rel('pump', hcp: true).get.resource
|
53
54
|
|
@@ -10,20 +10,16 @@ module Excon
|
|
10
10
|
# Verifies the Excon connection consuming HyperMedia APIs.
|
11
11
|
#
|
12
12
|
class IntegrationTest < HyperMediaTest
|
13
|
-
def api
|
14
|
-
Excon.get('https://www.example.org/api.json')
|
15
|
-
end
|
16
|
-
|
17
13
|
def test_request
|
18
14
|
response = api.rel('product', expand: { uid: 'bicycle' }).get
|
19
15
|
|
20
|
-
assert response.body.include?('
|
16
|
+
assert response.body.include?('/product/bicycle')
|
21
17
|
end
|
22
18
|
|
23
19
|
def test_request_using_link_rel
|
24
20
|
response = api.resource._links.product.rel(expand: { uid: 'bicycle' }).get
|
25
21
|
|
26
|
-
assert response.body.include?('
|
22
|
+
assert response.body.include?('/product/bicycle')
|
27
23
|
end
|
28
24
|
|
29
25
|
def test_nested_request
|
@@ -45,7 +41,7 @@ module Excon
|
|
45
41
|
def test_expand_in_get
|
46
42
|
response = api.rel('product').get(expand: { uid: 'bicycle' })
|
47
43
|
|
48
|
-
assert response.body.include?('
|
44
|
+
assert response.body.include?('/product/bicycle')
|
49
45
|
end
|
50
46
|
|
51
47
|
def test_link
|
@@ -89,14 +85,9 @@ module Excon
|
|
89
85
|
end
|
90
86
|
|
91
87
|
def test_request_with_json_content_type
|
92
|
-
|
93
|
-
response = api.rel('product', expand: { uid: 'bicycle' }).get
|
94
|
-
|
95
|
-
assert response.body.include?('https://www.example.org/product/bicycle')
|
96
|
-
end
|
88
|
+
response = api_v2.rel('product', expand: { uid: 'bicycle' }).get
|
97
89
|
|
98
|
-
|
99
|
-
Excon.stubs.clear
|
90
|
+
assert response.body.include?('/product/bicycle')
|
100
91
|
end
|
101
92
|
end
|
102
93
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# rubocop:disable Metrics/MethodLength
|
3
2
|
|
4
3
|
require_relative '../test_helper'
|
5
4
|
|
@@ -10,17 +9,17 @@ module Excon
|
|
10
9
|
#
|
11
10
|
class LinkTest < Minitest::Test
|
12
11
|
def self
|
13
|
-
'{ "href": "https://
|
12
|
+
'{ "href": "https://example.org/hello" }'
|
14
13
|
end
|
15
14
|
|
16
15
|
def templated
|
17
|
-
'{ "href": "https://
|
16
|
+
'{ "href": "https://example.org/hello/{receiver}", "templated": "true" }'
|
18
17
|
end
|
19
18
|
|
20
19
|
def full
|
21
20
|
<<-EOF
|
22
21
|
{
|
23
|
-
"href": "https://
|
22
|
+
"href": "https://example.org/goodbye/{receiver}",
|
24
23
|
"templated": "true",
|
25
24
|
"type": "json",
|
26
25
|
"deprecation": true,
|
data/test/excon/links_test.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# rubocop:disable Metrics/MethodLength
|
3
2
|
|
4
3
|
require_relative '../test_helper'
|
5
4
|
|
@@ -14,10 +13,10 @@ module Excon
|
|
14
13
|
{
|
15
14
|
"_links": {
|
16
15
|
"self": {
|
17
|
-
"href": "https://
|
16
|
+
"href": "https://example.org/product/bicycle"
|
18
17
|
},
|
19
18
|
"parts": {
|
20
|
-
"href": "https://
|
19
|
+
"href": "https://example.org/product/bicycle/parts"
|
21
20
|
}
|
22
21
|
}
|
23
22
|
}
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# rubocop:disable Metrics/MethodLength
|
3
2
|
|
4
3
|
require_relative '../test_helper'
|
5
4
|
|
@@ -14,7 +13,7 @@ module Excon
|
|
14
13
|
{
|
15
14
|
"_links": {
|
16
15
|
"hello": {
|
17
|
-
"href": "
|
16
|
+
"href": "https://example.org/hello/{location}"
|
18
17
|
}
|
19
18
|
},
|
20
19
|
"uid": "universe",
|
data/test/excon/response_test.rb
CHANGED
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:disable Metrics/MethodLength
|
3
|
+
# rubocop:disable Metrics/ModuleLength
|
4
|
+
|
5
|
+
# :no-doc:
|
6
|
+
module Test
|
7
|
+
# :no-doc:
|
8
|
+
module Response
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def api_body
|
12
|
+
<<-EOF
|
13
|
+
{
|
14
|
+
"_links": {
|
15
|
+
"self": {
|
16
|
+
"href": "http://localhost:8000/api.json"
|
17
|
+
},
|
18
|
+
"product": {
|
19
|
+
"href": "http://localhost:8000/product/{uid}",
|
20
|
+
"templated": true
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
EOF
|
25
|
+
end
|
26
|
+
|
27
|
+
def bicycle_body
|
28
|
+
<<-EOF
|
29
|
+
{
|
30
|
+
"_links": {
|
31
|
+
"self": {
|
32
|
+
"href": "http://localhost:8000/product/bicycle"
|
33
|
+
},
|
34
|
+
"handlebar": {
|
35
|
+
"href": "http://localhost:8000/product/handlebar"
|
36
|
+
},
|
37
|
+
"object_id": {
|
38
|
+
"href": "http://localhost:8000/product/bicycle/object_id_as_text"
|
39
|
+
},
|
40
|
+
"pump": {
|
41
|
+
"href": "http://localhost:8000/product/pump"
|
42
|
+
},
|
43
|
+
"wheels": [
|
44
|
+
{ "href": "http://localhost:8000/product/bicycle/wheels/front" },
|
45
|
+
{ "href": "http://localhost:8000/product/bicycle/wheels/rear" }
|
46
|
+
]
|
47
|
+
},
|
48
|
+
"bike-type": "Mountain Bike",
|
49
|
+
"BMX": false,
|
50
|
+
"derailleurs": {
|
51
|
+
"back": 7,
|
52
|
+
"front": 3
|
53
|
+
},
|
54
|
+
"name": "bicycle",
|
55
|
+
"reflectors": true,
|
56
|
+
"_embedded": {
|
57
|
+
"pump": #{pump_body},
|
58
|
+
"wheels": [#{front_wheel_body}, #{rear_wheel_body}]
|
59
|
+
}
|
60
|
+
}
|
61
|
+
EOF
|
62
|
+
end
|
63
|
+
|
64
|
+
def handlebar_body
|
65
|
+
<<-EOF
|
66
|
+
{
|
67
|
+
"_links": {
|
68
|
+
"self": {
|
69
|
+
"href": "http://localhost:8000/product/handlebar"
|
70
|
+
}
|
71
|
+
},
|
72
|
+
"material": "Carbon fiber",
|
73
|
+
"reach": "75mm",
|
74
|
+
"bend": "compact"
|
75
|
+
}
|
76
|
+
EOF
|
77
|
+
end
|
78
|
+
|
79
|
+
def pump_body
|
80
|
+
<<-EOF
|
81
|
+
{
|
82
|
+
"_links": {
|
83
|
+
"self": {
|
84
|
+
"href": "http://localhost:8000/product/pump"
|
85
|
+
},
|
86
|
+
"parts": {
|
87
|
+
"href": "http://localhost:8000/product/pump/parts"
|
88
|
+
}
|
89
|
+
},
|
90
|
+
"weight": "2kg",
|
91
|
+
"type": "Floor Pump",
|
92
|
+
"valve-type": "Presta",
|
93
|
+
"_embedded": {
|
94
|
+
"parts": #{parts_body}
|
95
|
+
}
|
96
|
+
|
97
|
+
}
|
98
|
+
EOF
|
99
|
+
end
|
100
|
+
|
101
|
+
def parts_body
|
102
|
+
<<-EOF
|
103
|
+
{
|
104
|
+
"_links": {
|
105
|
+
"self": {
|
106
|
+
"href": "http://localhost:8000/product/pump/parts"
|
107
|
+
}
|
108
|
+
},
|
109
|
+
"count": 47
|
110
|
+
}
|
111
|
+
EOF
|
112
|
+
end
|
113
|
+
|
114
|
+
def rear_wheel_body
|
115
|
+
<<-EOF
|
116
|
+
{
|
117
|
+
"_links": {
|
118
|
+
"self": {
|
119
|
+
"href": "http://localhost:8000/product/bicycle/wheels/rear"
|
120
|
+
}
|
121
|
+
},
|
122
|
+
"position": "rear",
|
123
|
+
"lacing_pattern": "Radial"
|
124
|
+
}
|
125
|
+
EOF
|
126
|
+
end
|
127
|
+
|
128
|
+
def front_wheel_body
|
129
|
+
<<-EOF
|
130
|
+
{
|
131
|
+
"_links": {
|
132
|
+
"self": {
|
133
|
+
"href": "http://localhost:8000/product/bicycle/wheels/front"
|
134
|
+
}
|
135
|
+
},
|
136
|
+
"position": "front",
|
137
|
+
"lacing_pattern": "Radial/2-Cross"
|
138
|
+
}
|
139
|
+
EOF
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'webrick'
|
5
|
+
require 'logger'
|
6
|
+
require_relative 'responses'
|
7
|
+
|
8
|
+
server = WEBrick::HTTPServer.new(Port: 8000, Logger: Logger.new(STDERR))
|
9
|
+
|
10
|
+
def body(name)
|
11
|
+
Test::Response.send("#{name}_body")
|
12
|
+
end
|
13
|
+
|
14
|
+
endpoints = {
|
15
|
+
'/empty_json' => { body: '{}' },
|
16
|
+
'/api.json' => { body: body(:api) },
|
17
|
+
'/product/bicycle' => { body: body(:bicycle) },
|
18
|
+
'/product/bicycle/wheels/front' => { body: body(:front_wheel) },
|
19
|
+
'/product/bicycle/wheels/rear' => { body: body(:rear_wheel) },
|
20
|
+
'/product/pump' => { body: body(:pump) },
|
21
|
+
'/product/pump/parts' => { body: body(:parts) },
|
22
|
+
'/product/handlebar' => { body: body(:handlebar) },
|
23
|
+
'/api_v2.json' => { body: body(:api), headers: { 'Content-Type' => 'application/json' } }
|
24
|
+
}
|
25
|
+
|
26
|
+
endpoints.each do |path, params|
|
27
|
+
server.mount_proc(path) do |_, response|
|
28
|
+
response['Content-Type'] = 'application/hal+json'
|
29
|
+
params[:headers].to_h.each { |k, v| response[k] = v }
|
30
|
+
|
31
|
+
response.body = params[:body]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
server.start
|
data/test/test_helper.rb
CHANGED
@@ -1,171 +1,59 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# rubocop:disable Metrics/MethodLength
|
3
|
-
# rubocop:disable Metrics/LineLength
|
4
|
-
# rubocop:disable Metrics/ClassLength
|
5
|
-
# rubocop:disable Metrics/AbcSize
|
6
2
|
|
7
3
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
8
4
|
require 'excon/hypermedia'
|
9
5
|
require 'minitest/autorun'
|
6
|
+
require 'open4'
|
7
|
+
require_relative 'support/responses'
|
8
|
+
|
9
|
+
Excon.defaults.merge!(
|
10
|
+
connect_timeout: 1,
|
11
|
+
read_timeout: 1,
|
12
|
+
write_timeout: 1
|
13
|
+
)
|
14
|
+
|
15
|
+
@server_pid, _, _, e = Open4.popen4(File.expand_path('support/server.rb', __dir__))
|
16
|
+
until e.gets =~ /HTTPServer#start/; end
|
17
|
+
|
18
|
+
Minitest.after_run do
|
19
|
+
Process.kill(9, @server_pid)
|
20
|
+
Process.wait(@server_pid)
|
21
|
+
end
|
10
22
|
|
11
23
|
module Excon
|
12
24
|
# HyperMediaTest
|
13
25
|
#
|
14
26
|
class HyperMediaTest < Minitest::Test
|
15
|
-
def
|
16
|
-
Excon.
|
17
|
-
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
18
|
-
|
19
|
-
response = { headers: { 'Content-Type' => 'application/hal+json' } }
|
20
|
-
Excon.stub({ method: :get, path: '/api.json' }, response.merge(body: api_body))
|
21
|
-
Excon.stub({ method: :get, path: '/product/bicycle' }, response.merge(body: bicycle_body))
|
22
|
-
Excon.stub({ method: :get, path: '/product/bicycle/wheels/front' }, response.merge(body: front_wheel_body))
|
23
|
-
Excon.stub({ method: :get, path: '/product/bicycle/wheels/rear' }, response.merge(body: rear_wheel_body))
|
24
|
-
Excon.stub({ path: '/product/pump' }, response.merge(body: pump_body))
|
25
|
-
Excon.stub({ method: :get, path: '/product/pump/parts' }, response.merge(body: parts_body))
|
26
|
-
Excon.stub({ method: :get, path: '/product/handlebar' }, response.merge(body: handlebar_body))
|
27
|
-
Excon.stub({ method: :get, path: '/api_v2.json' }, body: api_body, headers: { 'Content-Type' => 'application/json' })
|
28
|
-
end
|
29
|
-
|
30
|
-
def teardown
|
31
|
-
Excon.stubs.clear
|
32
|
-
Excon.defaults[:middlewares].delete(Excon::HyperMedia::Middleware)
|
33
|
-
Excon.defaults[:mock] = true
|
27
|
+
def api
|
28
|
+
Excon.get('http://localhost:8000/api.json')
|
34
29
|
end
|
35
30
|
|
36
|
-
def
|
37
|
-
|
31
|
+
def api_v2
|
32
|
+
Excon.get('http://localhost:8000/api_v2.json', hypermedia: true)
|
38
33
|
end
|
39
34
|
|
40
|
-
def
|
41
|
-
|
42
|
-
{
|
43
|
-
"_links": {
|
44
|
-
"self": {
|
45
|
-
"href": "https://www.example.org/api.json"
|
46
|
-
},
|
47
|
-
"product": {
|
48
|
-
"href": "https://www.example.org/product/{uid}",
|
49
|
-
"templated": true
|
50
|
-
}
|
51
|
-
}
|
52
|
-
}
|
53
|
-
EOF
|
35
|
+
def empty_json_response
|
36
|
+
Excon.get('http://localhost:8000/empty_json')
|
54
37
|
end
|
55
38
|
|
56
|
-
def
|
57
|
-
|
58
|
-
{
|
59
|
-
"_links": {
|
60
|
-
"self": {
|
61
|
-
"href": "https://www.example.org/product/bicycle"
|
62
|
-
},
|
63
|
-
"handlebar": {
|
64
|
-
"href": "https://www.example.org/product/handlebar"
|
65
|
-
},
|
66
|
-
"object_id": {
|
67
|
-
"href": "https://www.example.org/product/bicycle/object_id_as_text"
|
68
|
-
},
|
69
|
-
"pump": {
|
70
|
-
"href": "https://www.example.org/product/pump"
|
71
|
-
},
|
72
|
-
"wheels": [
|
73
|
-
{ "href": "https://www.example.org/product/bicycle/wheels/front" },
|
74
|
-
{ "href": "https://www.example.org/product/bicycle/wheels/rear" }
|
75
|
-
]
|
76
|
-
},
|
77
|
-
"bike-type": "Mountain Bike",
|
78
|
-
"BMX": false,
|
79
|
-
"derailleurs": {
|
80
|
-
"back": 7,
|
81
|
-
"front": 3
|
82
|
-
},
|
83
|
-
"name": "bicycle",
|
84
|
-
"reflectors": true,
|
85
|
-
"_embedded": {
|
86
|
-
"pump": #{pump_body},
|
87
|
-
"wheels": [#{front_wheel_body}, #{rear_wheel_body}]
|
88
|
-
}
|
89
|
-
}
|
90
|
-
EOF
|
39
|
+
def bicycle
|
40
|
+
@bicycle ||= Excon.get('http://localhost:8000/product/bicycle')
|
91
41
|
end
|
92
42
|
|
93
|
-
def
|
94
|
-
|
95
|
-
{
|
96
|
-
"_links": {
|
97
|
-
"self": {
|
98
|
-
"href": "https://www.example.org/product/handlebar"
|
99
|
-
}
|
100
|
-
},
|
101
|
-
"material": "Carbon fiber",
|
102
|
-
"reach": "75mm",
|
103
|
-
"bend": "compact"
|
104
|
-
}
|
105
|
-
EOF
|
106
|
-
end
|
107
|
-
|
108
|
-
def pump_body
|
109
|
-
<<-EOF
|
110
|
-
{
|
111
|
-
"_links": {
|
112
|
-
"self": {
|
113
|
-
"href": "https://www.example.org/product/pump"
|
114
|
-
},
|
115
|
-
"parts": {
|
116
|
-
"href": "https://www.example.org/product/pump/parts"
|
117
|
-
}
|
118
|
-
},
|
119
|
-
"weight": "2kg",
|
120
|
-
"type": "Floor Pump",
|
121
|
-
"valve-type": "Presta",
|
122
|
-
"_embedded": {
|
123
|
-
"parts": #{parts_body}
|
124
|
-
}
|
125
|
-
|
126
|
-
}
|
127
|
-
EOF
|
43
|
+
def setup
|
44
|
+
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
128
45
|
end
|
129
46
|
|
130
|
-
def
|
131
|
-
|
132
|
-
{
|
133
|
-
"_links": {
|
134
|
-
"self": {
|
135
|
-
"href": "https://www.example.org/product/pump/parts"
|
136
|
-
}
|
137
|
-
},
|
138
|
-
"count": 47
|
139
|
-
}
|
140
|
-
EOF
|
47
|
+
def teardown
|
48
|
+
Excon.defaults[:middlewares].delete(Excon::HyperMedia::Middleware)
|
141
49
|
end
|
142
50
|
|
143
|
-
def
|
144
|
-
|
145
|
-
{
|
146
|
-
"_links": {
|
147
|
-
"self": {
|
148
|
-
"href": "https://www.example.org/product/bicycle/wheels/rear"
|
149
|
-
}
|
150
|
-
},
|
151
|
-
"position": "rear",
|
152
|
-
"lacing_pattern": "Radial"
|
153
|
-
}
|
154
|
-
EOF
|
51
|
+
def data(name)
|
52
|
+
JSON.parse(Test::Response.send("#{name}_body"))
|
155
53
|
end
|
156
54
|
|
157
|
-
def
|
158
|
-
|
159
|
-
{
|
160
|
-
"_links": {
|
161
|
-
"self": {
|
162
|
-
"href": "https://www.example.org/product/bicycle/wheels/front"
|
163
|
-
}
|
164
|
-
},
|
165
|
-
"position": "front",
|
166
|
-
"lacing_pattern": "Radial/2-Cross"
|
167
|
-
}
|
168
|
-
EOF
|
55
|
+
def url(path)
|
56
|
+
File.join('http://localhost:8000', path)
|
169
57
|
end
|
170
58
|
end
|
171
59
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excon-hypermedia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-05-
|
12
|
+
date: 2016-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -95,6 +95,20 @@ dependencies:
|
|
95
95
|
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '1.5'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: open4
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1.3'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '1.3'
|
98
112
|
- !ruby/object:Gem::Dependency
|
99
113
|
name: excon
|
100
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,6 +174,8 @@ files:
|
|
160
174
|
- test/excon/properties_test.rb
|
161
175
|
- test/excon/resource_object_test.rb
|
162
176
|
- test/excon/response_test.rb
|
177
|
+
- test/support/responses.rb
|
178
|
+
- test/support/server.rb
|
163
179
|
- test/test_helper.rb
|
164
180
|
homepage: https://github.com/JeanMertz/excon-hypermedia
|
165
181
|
licenses:
|