excon-hypermedia 0.5.0 → 0.7.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 +5 -5
- data/.rubocop.yml +4 -1
- data/.wercker.yml +8 -0
- data/Gemfile +1 -0
- data/README.md +7 -4
- data/Rakefile +3 -2
- data/excon-hypermedia.gemspec +12 -10
- data/lib/excon/hypermedia/helpers/collection.rb +12 -1
- data/lib/excon/hypermedia/middleware.rb +18 -3
- data/lib/excon/hypermedia/middlewares/hypertext_cache_pattern.rb +49 -24
- data/lib/excon/hypermedia/resource_object.rb +6 -2
- data/lib/excon/hypermedia/response.rb +2 -5
- data/lib/excon/hypermedia/version.rb +1 -1
- data/test/excon/edgecase_test.rb +14 -36
- data/test/excon/hcp_test.rb +15 -10
- data/test/excon/integration_test.rb +9 -14
- data/test/excon/link_object_test.rb +5 -6
- data/test/excon/links_test.rb +5 -6
- data/test/excon/middleware_test.rb +58 -0
- data/test/excon/properties_test.rb +2 -3
- data/test/excon/resource_object_test.rb +13 -5
- data/test/excon/response_test.rb +1 -1
- data/test/support/responses.rb +144 -0
- data/test/support/server.rb +35 -0
- data/test/test_helper.rb +32 -144
- metadata +44 -28
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# rubocop:disable Metrics/AbcSize
|
3
4
|
# rubocop:disable Metrics/LineLength
|
4
5
|
|
@@ -10,20 +11,16 @@ module Excon
|
|
10
11
|
# Verifies the Excon connection consuming HyperMedia APIs.
|
11
12
|
#
|
12
13
|
class IntegrationTest < HyperMediaTest
|
13
|
-
def api
|
14
|
-
Excon.get('https://www.example.org/api.json')
|
15
|
-
end
|
16
|
-
|
17
14
|
def test_request
|
18
15
|
response = api.rel('product', expand: { uid: 'bicycle' }).get
|
19
16
|
|
20
|
-
assert response.body.include?('
|
17
|
+
assert response.body.include?('/product/bicycle')
|
21
18
|
end
|
22
19
|
|
23
20
|
def test_request_using_link_rel
|
24
21
|
response = api.resource._links.product.rel(expand: { uid: 'bicycle' }).get
|
25
22
|
|
26
|
-
assert response.body.include?('
|
23
|
+
assert response.body.include?('/product/bicycle')
|
27
24
|
end
|
28
25
|
|
29
26
|
def test_nested_request
|
@@ -45,7 +42,7 @@ module Excon
|
|
45
42
|
def test_expand_in_get
|
46
43
|
response = api.rel('product').get(expand: { uid: 'bicycle' })
|
47
44
|
|
48
|
-
assert response.body.include?('
|
45
|
+
assert response.body.include?('/product/bicycle')
|
49
46
|
end
|
50
47
|
|
51
48
|
def test_link
|
@@ -89,14 +86,12 @@ module Excon
|
|
89
86
|
end
|
90
87
|
|
91
88
|
def test_request_with_json_content_type
|
92
|
-
|
93
|
-
response = api.rel('product', expand: { uid: 'bicycle' }).get
|
89
|
+
response = api_v2.rel('product', expand: { uid: 'bicycle' }).get
|
94
90
|
|
95
|
-
assert response.body.include?('
|
96
|
-
end
|
97
|
-
|
98
|
-
def teardown
|
99
|
-
Excon.stubs.clear
|
91
|
+
assert response.body.include?('/product/bicycle')
|
100
92
|
end
|
101
93
|
end
|
102
94
|
end
|
95
|
+
|
96
|
+
# rubocop:enable Metrics/AbcSize
|
97
|
+
# rubocop:enable Metrics/LineLength
|
@@ -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
|
+
<<-JSON
|
22
21
|
{
|
23
|
-
"href": "https://
|
22
|
+
"href": "https://example.org/goodbye/{receiver}",
|
24
23
|
"templated": "true",
|
25
24
|
"type": "json",
|
26
25
|
"deprecation": true,
|
@@ -29,7 +28,7 @@ module Excon
|
|
29
28
|
"title": "Goodbye!",
|
30
29
|
"hreflang": "en-gb"
|
31
30
|
}
|
32
|
-
|
31
|
+
JSON
|
33
32
|
end
|
34
33
|
|
35
34
|
def data(name)
|
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
|
|
@@ -10,18 +9,18 @@ module Excon
|
|
10
9
|
#
|
11
10
|
class LinksTest < Minitest::Test
|
12
11
|
def body
|
13
|
-
<<-
|
12
|
+
<<-JSON
|
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
|
}
|
24
|
-
|
23
|
+
JSON
|
25
24
|
end
|
26
25
|
|
27
26
|
def data
|
@@ -37,7 +36,7 @@ module Excon
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def test_link_properties
|
40
|
-
assert_equal %w
|
39
|
+
assert_equal %w[self parts], links.to_h.keys
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/AbcSize
|
4
|
+
# rubocop:disable Metrics/LineLength
|
5
|
+
|
6
|
+
require_relative '../test_helper'
|
7
|
+
|
8
|
+
module Excon
|
9
|
+
class MiddlewareTest < Minitest::Test
|
10
|
+
def setup
|
11
|
+
Excon.defaults[:mock] = true
|
12
|
+
Excon.stub(
|
13
|
+
{ :path => '/lowercase-content-type' },
|
14
|
+
{
|
15
|
+
headers: { 'content-type' => 'application/hal+json' },
|
16
|
+
body: '{}',
|
17
|
+
status: 200
|
18
|
+
}
|
19
|
+
)
|
20
|
+
Excon.stub(
|
21
|
+
{ :path => '/uppercase-content-type' },
|
22
|
+
{
|
23
|
+
headers: { 'Content-Type' => 'application/hal+json' },
|
24
|
+
body: '{}',
|
25
|
+
status: 200
|
26
|
+
}
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_request_with_lowercase_content_type
|
31
|
+
test = Excon.get(
|
32
|
+
'http://example.com',
|
33
|
+
path: '/lowercase-content-type',
|
34
|
+
middlewares: Excon.defaults[:middlewares] + [Excon::HyperMedia::Middleware]
|
35
|
+
)
|
36
|
+
|
37
|
+
assert test.data[:hypermedia]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_request_with_uppercase_content_type
|
41
|
+
test = Excon.get(
|
42
|
+
'http://example.com',
|
43
|
+
path: '/uppercase-content-type',
|
44
|
+
middlewares: Excon.defaults[:middlewares] + [Excon::HyperMedia::Middleware]
|
45
|
+
)
|
46
|
+
|
47
|
+
assert test.data[:hypermedia]
|
48
|
+
end
|
49
|
+
|
50
|
+
def teardown
|
51
|
+
Excon.stubs.clear
|
52
|
+
Excon.defaults[:mock] = false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# rubocop:enable Metrics/AbcSize
|
58
|
+
# rubocop:enable Metrics/LineLength
|
@@ -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,7 +9,7 @@ module Excon
|
|
10
9
|
#
|
11
10
|
class PropertiesTest < Minitest::Test
|
12
11
|
def body
|
13
|
-
<<-
|
12
|
+
<<-JSON
|
14
13
|
{
|
15
14
|
"size": "49CM",
|
16
15
|
"bike-type": "Mountain Bike",
|
@@ -21,7 +20,7 @@ module Excon
|
|
21
20
|
"reflectors": true,
|
22
21
|
"BMX": false
|
23
22
|
}
|
24
|
-
|
23
|
+
JSON
|
25
24
|
end
|
26
25
|
|
27
26
|
def data
|
@@ -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 ResourceObjectTest < Minitest::Test
|
12
11
|
def body
|
13
|
-
<<-
|
12
|
+
<<-JSON
|
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",
|
21
20
|
"hello": "world"
|
22
21
|
}
|
23
|
-
|
22
|
+
JSON
|
24
23
|
end
|
25
24
|
|
26
25
|
def data
|
@@ -43,7 +42,16 @@ module Excon
|
|
43
42
|
assert_equal 'universe', resource.uid
|
44
43
|
assert_equal 'world', resource.hello
|
45
44
|
assert_equal 'world', resource['hello']
|
46
|
-
|
45
|
+
assert_nil resource['invalid']
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_correctly_raising_no_method_error
|
49
|
+
assert_raises(NoMethodError) { resource.invalid }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_correctly_respond_to
|
53
|
+
assert_equal true, resource.respond_to?(:hello)
|
54
|
+
assert_equal false, resource.respond_to?(:invalid)
|
47
55
|
end
|
48
56
|
end
|
49
57
|
end
|
data/test/excon/response_test.rb
CHANGED
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
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
|
+
<<-JSON
|
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
|
+
JSON
|
25
|
+
end
|
26
|
+
|
27
|
+
def bicycle_body
|
28
|
+
<<-JSON
|
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
|
+
JSON
|
62
|
+
end
|
63
|
+
|
64
|
+
def handlebar_body
|
65
|
+
<<-JSON
|
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
|
+
JSON
|
77
|
+
end
|
78
|
+
|
79
|
+
def pump_body
|
80
|
+
<<-JSON
|
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
|
+
JSON
|
99
|
+
end
|
100
|
+
|
101
|
+
def parts_body
|
102
|
+
<<-JSON
|
103
|
+
{
|
104
|
+
"_links": {
|
105
|
+
"self": {
|
106
|
+
"href": "http://localhost:8000/product/pump/parts"
|
107
|
+
}
|
108
|
+
},
|
109
|
+
"count": 47
|
110
|
+
}
|
111
|
+
JSON
|
112
|
+
end
|
113
|
+
|
114
|
+
def rear_wheel_body
|
115
|
+
<<-JSON
|
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
|
+
JSON
|
126
|
+
end
|
127
|
+
|
128
|
+
def front_wheel_body
|
129
|
+
<<-JSON
|
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
|
+
JSON
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# rubocop:enable Metrics/ModuleLength
|
@@ -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
|