excon-hypermedia 0.5.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|