heroics 0.0.17 → 0.0.18
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 +4 -4
- data/.travis.yml +3 -5
- data/README.md +32 -1
- data/bin/heroics-generate +32 -11
- data/heroics.gemspec +4 -3
- data/lib/heroics.rb +7 -1
- data/lib/heroics/client_generator.rb +7 -14
- data/lib/heroics/configuration.rb +45 -0
- data/lib/heroics/link.rb +1 -1
- data/lib/heroics/version.rb +1 -1
- metadata +35 -30
- data/test/cli_test.rb +0 -237
- data/test/client_generator_test.rb +0 -35
- data/test/client_test.rb +0 -275
- data/test/command_test.rb +0 -215
- data/test/helper.rb +0 -221
- data/test/link_test.rb +0 -444
- data/test/naming_test.rb +0 -46
- data/test/resource_test.rb +0 -36
- data/test/schema_test.rb +0 -274
- data/test/version_test.rb +0 -10
data/test/helper.rb
DELETED
@@ -1,221 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'minitest/autorun'
|
3
|
-
require 'time'
|
4
|
-
|
5
|
-
require 'heroics'
|
6
|
-
|
7
|
-
module ExconHelper
|
8
|
-
def setup
|
9
|
-
super
|
10
|
-
Excon.stubs.clear
|
11
|
-
Excon.defaults[:mock] = true
|
12
|
-
end
|
13
|
-
|
14
|
-
def teardown
|
15
|
-
# FIXME This is a bit ugly, but Excon doesn't provide a builtin way to
|
16
|
-
# ensure that a request was invoked, so we have to do it ourselves.
|
17
|
-
# Without this, and the Excon.stubs.pop calls in the tests that use this
|
18
|
-
# helper, tests will pass if request logic is completely removed from
|
19
|
-
# application code. -jkakar
|
20
|
-
assert(Excon.stubs.empty?, 'Expected HTTP requests were not made.')
|
21
|
-
super
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# A simple JSON schema for testing purposes.
|
26
|
-
SAMPLE_SCHEMA = {
|
27
|
-
'description' => 'Sample schema for use in tests.',
|
28
|
-
'definitions' => {
|
29
|
-
'resource' => {
|
30
|
-
'description' => 'A sample resource to use in tests.',
|
31
|
-
'id' => 'schema/resource',
|
32
|
-
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
33
|
-
'title' => 'Sample resource title',
|
34
|
-
'type' => ['object'],
|
35
|
-
|
36
|
-
'definitions' => {
|
37
|
-
'date_field' => {
|
38
|
-
'description' => 'A sample date field',
|
39
|
-
'example' => '2013-10-19 22:10:29Z',
|
40
|
-
'format' => 'date-time',
|
41
|
-
'readOnly' => true,
|
42
|
-
'type' => ['string']
|
43
|
-
},
|
44
|
-
|
45
|
-
'string_field' => {
|
46
|
-
'description' => 'A sample string field',
|
47
|
-
'example' => 'Sample text.',
|
48
|
-
'readOnly' => true,
|
49
|
-
'type' => ['string']
|
50
|
-
},
|
51
|
-
|
52
|
-
'boolean_field' => {
|
53
|
-
'description' => 'A sample boolean field',
|
54
|
-
'example' => true,
|
55
|
-
'type' => ['boolean']
|
56
|
-
},
|
57
|
-
|
58
|
-
'uuid_field' => {
|
59
|
-
'description' => 'A sample UUID field',
|
60
|
-
'example' => '44724831-bf66-4bc2-865f-e2c4c2b14c78',
|
61
|
-
'format' => 'uuid',
|
62
|
-
'readOnly' => true,
|
63
|
-
'type' => ['string']
|
64
|
-
},
|
65
|
-
|
66
|
-
'email_field' => {
|
67
|
-
'description' => 'A sample email address field',
|
68
|
-
'example' => 'username@example.com',
|
69
|
-
'format' => 'email',
|
70
|
-
'readOnly' => true,
|
71
|
-
'type' => ['string']
|
72
|
-
},
|
73
|
-
|
74
|
-
'identity' => {
|
75
|
-
'oneOf' => [
|
76
|
-
{'$ref' => '#/definitions/resource/definitions/uuid_field'},
|
77
|
-
{'$ref' => '#/definitions/resource/definitions/email_field'}]
|
78
|
-
}
|
79
|
-
},
|
80
|
-
|
81
|
-
'properties' => {
|
82
|
-
'date_field' => {
|
83
|
-
'$ref' => '#/definitions/resource/definitions/date_field'},
|
84
|
-
'string_field' => {
|
85
|
-
'$ref' => '#/definitions/resource/definitions/string_field'},
|
86
|
-
'boolean_field' => {
|
87
|
-
'$ref' => '#/definitions/resource/definitions/boolean_field'},
|
88
|
-
'uuid_field' => {
|
89
|
-
'$ref' => '#/definitions/resource/definitions/uuid_field'},
|
90
|
-
'email_field' => {
|
91
|
-
'$ref' => '#/definitions/resource/definitions/email_field'},
|
92
|
-
},
|
93
|
-
|
94
|
-
'links' => [
|
95
|
-
{'description' => 'Show all sample resources',
|
96
|
-
'href' => '/resource',
|
97
|
-
'method' => 'GET',
|
98
|
-
'rel' => 'instances',
|
99
|
-
'title' => 'List'},
|
100
|
-
|
101
|
-
{'description' => 'Show a sample resource',
|
102
|
-
'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fuuid_field)}',
|
103
|
-
'method' => 'GET',
|
104
|
-
'rel' => 'self',
|
105
|
-
'title' => 'Info'},
|
106
|
-
|
107
|
-
{'description' => 'Show a sample resource',
|
108
|
-
'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fidentity)}',
|
109
|
-
'method' => 'GET',
|
110
|
-
'rel' => 'self',
|
111
|
-
'title' => 'Identify resource'},
|
112
|
-
|
113
|
-
{'description' => 'Create a sample resource',
|
114
|
-
'href' => '/resource',
|
115
|
-
'method' => 'POST',
|
116
|
-
'rel' => 'create',
|
117
|
-
'title' => 'Create',
|
118
|
-
'schema' => {
|
119
|
-
'properties' => {
|
120
|
-
'date_field' => {
|
121
|
-
'$ref' => '#/definitions/resource/definitions/date_field'},
|
122
|
-
'string_field' => {
|
123
|
-
'$ref' => '#/definitions/resource/definitions/string_field'},
|
124
|
-
'boolean_field' => {
|
125
|
-
'$ref' => '#/definitions/resource/definitions/boolean_field'},
|
126
|
-
'uuid_field' => {
|
127
|
-
'$ref' => '#/definitions/resource/definitions/uuid_field'},
|
128
|
-
'email_field' => {
|
129
|
-
'$ref' => '#/definitions/resource/definitions/email_field'}}}},
|
130
|
-
|
131
|
-
{'description' => 'Submit a sample resource as form data',
|
132
|
-
'encType' => 'application/x-www-form-urlencoded',
|
133
|
-
'href' => '/resource',
|
134
|
-
'method' => 'POST',
|
135
|
-
'rel' => 'submit',
|
136
|
-
'title' => 'Submit',
|
137
|
-
'schema' => {
|
138
|
-
'properties' => {
|
139
|
-
'date_field' => {
|
140
|
-
'$ref' => '#/definitions/resource/definitions/date_field'},
|
141
|
-
'string_field' => {
|
142
|
-
'$ref' => '#/definitions/resource/definitions/string_field'},
|
143
|
-
'boolean_field' => {
|
144
|
-
'$ref' => '#/definitions/resource/definitions/boolean_field'},
|
145
|
-
'uuid_field' => {
|
146
|
-
'$ref' => '#/definitions/resource/definitions/uuid_field'},
|
147
|
-
'email_field' => {
|
148
|
-
'$ref' => '#/definitions/resource/definitions/email_field'}}}},
|
149
|
-
|
150
|
-
{'description' => 'Update a sample resource',
|
151
|
-
'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fuuid_field)}',
|
152
|
-
'method' => 'PATCH',
|
153
|
-
'rel' => 'update',
|
154
|
-
'title' => 'Update',
|
155
|
-
'schema' => {
|
156
|
-
'properties' => {
|
157
|
-
'date_field' => {
|
158
|
-
'$ref' => '#/definitions/resource/definitions/date_field'},
|
159
|
-
'string_field' => {
|
160
|
-
'$ref' => '#/definitions/resource/definitions/string_field'},
|
161
|
-
'boolean_field' => {
|
162
|
-
'$ref' => '#/definitions/resource/definitions/boolean_field'},
|
163
|
-
'uuid_field' => {
|
164
|
-
'$ref' => '#/definitions/resource/definitions/uuid_field'},
|
165
|
-
'email_field' => {
|
166
|
-
'$ref' => '#/definitions/resource/definitions/email_field'}}}},
|
167
|
-
|
168
|
-
{'description' => 'Delete an existing sample resource at specific time',
|
169
|
-
'href' => '/resource/{(%23%2Fdefinitions%2Fresource%2Fdefinitions%2Fdate_field)}',
|
170
|
-
'method' => 'DELETE',
|
171
|
-
'rel' => 'destroy',
|
172
|
-
'title' => 'Delete'}
|
173
|
-
]
|
174
|
-
},
|
175
|
-
|
176
|
-
'another-resource' => {
|
177
|
-
'description' => 'Another sample resource to use in tests.',
|
178
|
-
'id' => 'schema/another-resource',
|
179
|
-
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
180
|
-
'title' => 'Another sample resource title',
|
181
|
-
'type' => ['object'],
|
182
|
-
|
183
|
-
'definitions' => {},
|
184
|
-
|
185
|
-
'properties' => {},
|
186
|
-
|
187
|
-
'links' => [
|
188
|
-
{'description' => 'Show all sample resources',
|
189
|
-
'href' => '/another-resource',
|
190
|
-
'method' => 'GET',
|
191
|
-
'rel' => 'instances',
|
192
|
-
'title' => 'List'}
|
193
|
-
]
|
194
|
-
},
|
195
|
-
|
196
|
-
'underscored_resource' => {
|
197
|
-
'description' => 'Underscores the importance of supporting underscored resources',
|
198
|
-
'id' => 'schema/underscored_resource',
|
199
|
-
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
200
|
-
'title' => 'Another underscored resource to use in tests',
|
201
|
-
'type' => ['object'],
|
202
|
-
|
203
|
-
'definitions' => {},
|
204
|
-
|
205
|
-
'properties' => {},
|
206
|
-
|
207
|
-
'links' => [
|
208
|
-
{'description' => 'Show all underscored resources',
|
209
|
-
'href' => '/underscored_resource',
|
210
|
-
'method' => 'GET',
|
211
|
-
'rel' => 'instances',
|
212
|
-
'title' => 'List'}
|
213
|
-
]
|
214
|
-
},
|
215
|
-
},
|
216
|
-
'properties' => {
|
217
|
-
'resource' => { '$ref' => '#/definitions/resource' },
|
218
|
-
'another-resource' => { '$ref' => '#/definitions/another-resource' },
|
219
|
-
'underscored_resource' => { '$ref' => '#/definitions/underscored_resource' }
|
220
|
-
}
|
221
|
-
}
|
data/test/link_test.rb
DELETED
@@ -1,444 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'helper'
|
3
|
-
|
4
|
-
class LinkTest < MiniTest::Unit::TestCase
|
5
|
-
include ExconHelper
|
6
|
-
|
7
|
-
# Link.run invokes a request against the service identified by the URL. The
|
8
|
-
# path is left unchanged when parameters aren't required and the username
|
9
|
-
# and password from the URL are passed using HTTP basic auth.
|
10
|
-
def test_run_without_parameters_and_with_empty_response
|
11
|
-
Excon.stub(method: :get) do |request|
|
12
|
-
assert_equal('Basic dXNlcm5hbWU6c2VjcmV0',
|
13
|
-
request[:headers]['Authorization'])
|
14
|
-
assert_equal('example.com', request[:host])
|
15
|
-
assert_equal(443, request[:port])
|
16
|
-
assert_equal('/resource', request[:path])
|
17
|
-
Excon.stubs.pop
|
18
|
-
{status: 200, body: ''}
|
19
|
-
end
|
20
|
-
|
21
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
22
|
-
link = Heroics::Link.new('https://username:secret@example.com',
|
23
|
-
schema.resource('resource').link('list'))
|
24
|
-
assert_equal(nil, link.run)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Link.run injects parameters into the path in the order they were received.
|
28
|
-
def test_run_with_parameters_and_empty_response
|
29
|
-
Excon.stub(method: :get) do |request|
|
30
|
-
assert_equal('/resource/44724831-bf66-4bc2-865f-e2c4c2b14c78',
|
31
|
-
request[:path])
|
32
|
-
Excon.stubs.pop
|
33
|
-
{status: 200, body: ''}
|
34
|
-
end
|
35
|
-
|
36
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
37
|
-
link = Heroics::Link.new('https://example.com',
|
38
|
-
schema.resource('resource').link('info'))
|
39
|
-
assert_equal(nil, link.run('44724831-bf66-4bc2-865f-e2c4c2b14c78'))
|
40
|
-
end
|
41
|
-
|
42
|
-
# Link.run URL-escapes special characters in parameters.
|
43
|
-
def test_run_with_parameters_needing_escaping
|
44
|
-
Excon.stub(method: :get) do |request|
|
45
|
-
assert_equal('/resource/foo%23bar', request[:path])
|
46
|
-
Excon.stubs.pop
|
47
|
-
{status: 200, body: ''}
|
48
|
-
end
|
49
|
-
|
50
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
51
|
-
link = Heroics::Link.new('https://example.com',
|
52
|
-
schema.resource('resource').link('info'))
|
53
|
-
assert_equal(nil, link.run('foo#bar'))
|
54
|
-
end
|
55
|
-
|
56
|
-
# Link.run converts Time parameters to UTC before sending them to the
|
57
|
-
# server.
|
58
|
-
def test_run_converts_time_parameters_to_utc
|
59
|
-
Excon.stub(method: :delete) do |request|
|
60
|
-
assert_equal("/resource/2013-01-01T08:00:00Z", request[:path])
|
61
|
-
Excon.stubs.pop
|
62
|
-
{status: 200, body: ''}
|
63
|
-
end
|
64
|
-
|
65
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
66
|
-
link = Heroics::Link.new('https://example.com',
|
67
|
-
schema.resource('resource').link('delete'))
|
68
|
-
assert_equal(nil, link.run(Time.parse('2013-01-01 00:00:00-0800')))
|
69
|
-
end
|
70
|
-
|
71
|
-
# Link.run optionally takes an extra parameter to send in the request body.
|
72
|
-
# It automatically converts the specified object to JSON and includes a
|
73
|
-
# Content-Type header in the request.
|
74
|
-
def test_run_without_parameters_and_with_request_body
|
75
|
-
body = {'Hello' => 'world!'}
|
76
|
-
Excon.stub(method: :post) do |request|
|
77
|
-
assert_equal('application/json', request[:headers]['Content-Type'])
|
78
|
-
assert_equal(body, MultiJson.load(request[:body]))
|
79
|
-
Excon.stubs.pop
|
80
|
-
{status: 200, body: ''}
|
81
|
-
end
|
82
|
-
|
83
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
84
|
-
link = Heroics::Link.new('https://example.com',
|
85
|
-
schema.resource('resource').link('create'))
|
86
|
-
assert_equal(nil, link.run(body))
|
87
|
-
end
|
88
|
-
|
89
|
-
# Link.run optionally takes an extra parameter to send in the request body.
|
90
|
-
# It automatically converts the specified object to the specified encoding
|
91
|
-
# type and includes a Content-Type header in the request
|
92
|
-
def test_run_without_parameters_and_with_non_json_request_body
|
93
|
-
body = {'Hello' => 'world!'}
|
94
|
-
Excon.stub(method: :post) do |request|
|
95
|
-
assert_equal('application/x-www-form-urlencoded', request[:headers]['Content-Type'])
|
96
|
-
assert_equal('Hello=world%21', request[:body])
|
97
|
-
Excon.stubs.pop
|
98
|
-
{status: 200, body: ''}
|
99
|
-
end
|
100
|
-
|
101
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
102
|
-
link = Heroics::Link.new('https://example.com',
|
103
|
-
schema.resource('resource').link('submit'))
|
104
|
-
assert_equal(nil, link.run(body))
|
105
|
-
end
|
106
|
-
|
107
|
-
|
108
|
-
# Link.run passes custom headers to the server when they've been provided.
|
109
|
-
def test_run_with_custom_request_headers
|
110
|
-
Excon.stub(method: :get) do |request|
|
111
|
-
assert_equal('application/vnd.heroku+json; version=3',
|
112
|
-
request[:headers]['Accept'])
|
113
|
-
Excon.stubs.pop
|
114
|
-
{status: 200}
|
115
|
-
end
|
116
|
-
|
117
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
118
|
-
link = Heroics::Link.new(
|
119
|
-
'https://example.com', schema.resource('resource').link('list'),
|
120
|
-
{default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}})
|
121
|
-
assert_equal(nil, link.run())
|
122
|
-
end
|
123
|
-
|
124
|
-
# Link.run passes custom headers to the server when they've been provided.
|
125
|
-
# It merges in the Content-Type when a body is included in the request.
|
126
|
-
def test_run_with_custom_request_headers_and_with_request_body
|
127
|
-
body = {'Hello' => 'world!'}
|
128
|
-
Excon.stub(method: :post) do |request|
|
129
|
-
assert_equal('application/json', request[:headers]['Content-Type'])
|
130
|
-
assert_equal('application/vnd.heroku+json; version=3',
|
131
|
-
request[:headers]['Accept'])
|
132
|
-
assert_equal(body, MultiJson.load(request[:body]))
|
133
|
-
Excon.stubs.pop
|
134
|
-
{status: 200}
|
135
|
-
end
|
136
|
-
|
137
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
138
|
-
link = Heroics::Link.new(
|
139
|
-
'https://example.com', schema.resource('resource').link('create'),
|
140
|
-
default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'})
|
141
|
-
assert_equal(nil, link.run(body))
|
142
|
-
end
|
143
|
-
|
144
|
-
# Link.run doesn't mutate the default headers.
|
145
|
-
def test_run_never_overwrites_default_headers
|
146
|
-
body = {'Hello' => 'world!'}
|
147
|
-
Excon.stub(method: :post) do |request|
|
148
|
-
assert_equal('application/json', request[:headers]['Content-Type'])
|
149
|
-
assert_equal('application/vnd.heroku+json; version=3',
|
150
|
-
request[:headers]['Accept'])
|
151
|
-
assert_equal(body, MultiJson.load(request[:body]))
|
152
|
-
Excon.stubs.pop
|
153
|
-
{status: 200}
|
154
|
-
end
|
155
|
-
|
156
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
157
|
-
link = Heroics::Link.new(
|
158
|
-
'https://example.com', schema.resource('resource').link('create'),
|
159
|
-
{default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}})
|
160
|
-
assert_equal(nil, link.run(body))
|
161
|
-
|
162
|
-
# The second time we use the link, without providing a request body, the
|
163
|
-
# Content-Type set during the first run is not present, as expected.
|
164
|
-
Excon.stub(method: :post) do |request|
|
165
|
-
assert_equal(nil, request[:headers]['Content-Type'])
|
166
|
-
assert_equal('application/vnd.heroku+json; version=3',
|
167
|
-
request[:headers]['Accept'])
|
168
|
-
Excon.stubs.pop
|
169
|
-
{status: 200}
|
170
|
-
end
|
171
|
-
assert_equal(nil, link.run)
|
172
|
-
end
|
173
|
-
|
174
|
-
# Link.run returns text responses sent by the server without processing them
|
175
|
-
# in any way.
|
176
|
-
def test_run_with_text_response
|
177
|
-
Excon.stub(method: :get) do |request|
|
178
|
-
assert_equal('/resource', request[:path])
|
179
|
-
Excon.stubs.pop
|
180
|
-
{status: 200, headers: {'Content-Type' => 'application/text'},
|
181
|
-
body: "Hello, world!\r\n"}
|
182
|
-
end
|
183
|
-
|
184
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
185
|
-
link = Heroics::Link.new('https://example.com',
|
186
|
-
schema.resource('resource').link('list'))
|
187
|
-
assert_equal("Hello, world!\r\n", link.run)
|
188
|
-
end
|
189
|
-
|
190
|
-
# Link.run automatically decodes JSON responses sent by the server into Ruby
|
191
|
-
# objects.
|
192
|
-
def test_run_with_json_response
|
193
|
-
body = {'Hello' => 'World!'}
|
194
|
-
Excon.stub(method: :post) do |request|
|
195
|
-
assert_equal('/resource', request[:path])
|
196
|
-
Excon.stubs.pop
|
197
|
-
{status: 201, headers: {'Content-Type' => 'application/json'},
|
198
|
-
body: MultiJson.dump(body)}
|
199
|
-
end
|
200
|
-
|
201
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
202
|
-
link = Heroics::Link.new('https://example.com',
|
203
|
-
schema.resource('resource').link('create'))
|
204
|
-
assert_equal(body, link.run)
|
205
|
-
end
|
206
|
-
|
207
|
-
# Link.run automatically decodes JSON responses with a complex Content-Type
|
208
|
-
# header sent by the server into Ruby objects.
|
209
|
-
def test_run_with_json_response_and_complex_content_type
|
210
|
-
body = {'Hello' => 'World!'}
|
211
|
-
Excon.stub(method: :get) do |request|
|
212
|
-
assert_equal('/resource', request[:path])
|
213
|
-
Excon.stubs.pop
|
214
|
-
{status: 200,
|
215
|
-
headers: {'Content-Type' => 'application/vnd.api+json;charset=utf-8'},
|
216
|
-
body: MultiJson.dump(body)}
|
217
|
-
end
|
218
|
-
|
219
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
220
|
-
link = Heroics::Link.new('https://example.com',
|
221
|
-
schema.resource('resource').link('list'))
|
222
|
-
assert_equal(body, link.run)
|
223
|
-
end
|
224
|
-
|
225
|
-
# Link.run considers HTTP 202 Accepted responses as successful.
|
226
|
-
def test_run_with_accepted_request
|
227
|
-
body = {'Hello' => 'World!'}
|
228
|
-
Excon.stub(method: :post) do |request|
|
229
|
-
assert_equal('/resource', request[:path])
|
230
|
-
Excon.stubs.pop
|
231
|
-
{status: 202, headers: {'Content-Type' => 'application/json'},
|
232
|
-
body: MultiJson.dump(body)}
|
233
|
-
end
|
234
|
-
|
235
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
236
|
-
link = Heroics::Link.new('https://example.com',
|
237
|
-
schema.resource('resource').link('create'))
|
238
|
-
assert_equal(body, link.run)
|
239
|
-
end
|
240
|
-
|
241
|
-
# Link.run considers HTTP 204 No Content responses as successful.
|
242
|
-
def test_run_with_no_content_response
|
243
|
-
Excon.stub(method: :delete) do |request|
|
244
|
-
assert_equal("/resource/2013-01-01T08:00:00Z", request[:path])
|
245
|
-
Excon.stubs.pop
|
246
|
-
{status: 204, body: ''}
|
247
|
-
end
|
248
|
-
|
249
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
250
|
-
link = Heroics::Link.new('https://example.com',
|
251
|
-
schema.resource('resource').link('delete'))
|
252
|
-
assert_equal(nil, link.run(Time.parse('2013-01-01 00:00:00-0800')))
|
253
|
-
end
|
254
|
-
|
255
|
-
# Link.run raises an Excon error if anything other than a 200 or 201 HTTP
|
256
|
-
# status code was returned by the server.
|
257
|
-
def test_run_with_failed_request
|
258
|
-
Excon.stub(method: :get) do |request|
|
259
|
-
assert_equal('/resource', request[:path])
|
260
|
-
Excon.stubs.pop
|
261
|
-
{status: 400}
|
262
|
-
end
|
263
|
-
|
264
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
265
|
-
link = Heroics::Link.new('https://example.com',
|
266
|
-
schema.resource('resource').link('list'))
|
267
|
-
assert_raises Excon::Errors::BadRequest do
|
268
|
-
link.run
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
# Link.run raises an ArgumentError if too few parameters are provided.
|
273
|
-
def test_run_with_missing_parameters
|
274
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
275
|
-
link = Heroics::Link.new('https://example.com',
|
276
|
-
schema.resource('resource').link('info'))
|
277
|
-
error = assert_raises ArgumentError do
|
278
|
-
link.run
|
279
|
-
end
|
280
|
-
assert_equal('wrong number of arguments (0 for 1)', error.message)
|
281
|
-
end
|
282
|
-
|
283
|
-
# Link.run raises an ArgumentError if too many parameters are provided.
|
284
|
-
def test_run_with_too_many_parameters
|
285
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
286
|
-
link = Heroics::Link.new('https://example.com',
|
287
|
-
schema.resource('resource').link('info'))
|
288
|
-
error = assert_raises ArgumentError do
|
289
|
-
link.run('too', 'many', 'parameters')
|
290
|
-
end
|
291
|
-
assert_equal('wrong number of arguments (3 for 1)', error.message)
|
292
|
-
end
|
293
|
-
|
294
|
-
# Link.run passes ETags from the cache to the server with GET requests.
|
295
|
-
def test_run_passes_cached_etags_in_get_requests
|
296
|
-
Excon.stub(method: :get) do |request|
|
297
|
-
assert_equal('etag-contents', request[:headers]['If-None-Match'])
|
298
|
-
Excon.stubs.pop
|
299
|
-
{status: 200}
|
300
|
-
end
|
301
|
-
|
302
|
-
headers = {}
|
303
|
-
cache = Moneta.new(:Memory)
|
304
|
-
cache["etag:/resource:#{headers.hash}"] = 'etag-contents'
|
305
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
306
|
-
link = Heroics::Link.new('https://example.com',
|
307
|
-
schema.resource('resource').link('list'),
|
308
|
-
cache: cache)
|
309
|
-
link.run
|
310
|
-
end
|
311
|
-
|
312
|
-
# Link.run will not pas ETags from the cache for non-GET requests.
|
313
|
-
def test_run_ignores_etags_for_non_get_requests
|
314
|
-
Excon.stub(method: :post) do |request|
|
315
|
-
assert_equal(nil, request[:headers]['If-None-Match'])
|
316
|
-
Excon.stubs.pop
|
317
|
-
{status: 201}
|
318
|
-
end
|
319
|
-
|
320
|
-
cache = Moneta.new(:Memory)
|
321
|
-
cache['etag:/resource:0'] = 'etag-contents'
|
322
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
323
|
-
link = Heroics::Link.new('https://example.com',
|
324
|
-
schema.resource('resource').link('create'),
|
325
|
-
cache: cache)
|
326
|
-
link.run({'Hello' => 'World'})
|
327
|
-
end
|
328
|
-
|
329
|
-
# Link.run returns JSON content loaded from the cache when a GET request
|
330
|
-
# with an ETag yields a 304 Not Modified response.
|
331
|
-
def test_run_returns_cached_json_content_for_not_modified_response
|
332
|
-
body = {'Hello' => 'World!'}
|
333
|
-
Excon.stub(method: :get) do |request|
|
334
|
-
assert_equal('etag-contents', request[:headers]['If-None-Match'])
|
335
|
-
Excon.stubs.pop
|
336
|
-
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
337
|
-
end
|
338
|
-
|
339
|
-
headers = {}
|
340
|
-
cache = Moneta.new(:Memory)
|
341
|
-
cache["etag:/resource:#{headers.hash}"] = 'etag-contents'
|
342
|
-
cache["data:/resource:#{headers.hash}"] = MultiJson.dump(body)
|
343
|
-
cache["status:/resource:#{headers.hash}"] = 200
|
344
|
-
cache["headers:/resource:#{headers.hash}"] = {'Content-Type' => 'application/json'}
|
345
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
346
|
-
link = Heroics::Link.new('https://example.com',
|
347
|
-
schema.resource('resource').link('list'),
|
348
|
-
cache: cache)
|
349
|
-
assert_equal(body, link.run)
|
350
|
-
end
|
351
|
-
|
352
|
-
# Link.run caches JSON content received from the server when an ETag is
|
353
|
-
# included in the response.
|
354
|
-
def test_run_caches_json_body_when_an_etag_is_received
|
355
|
-
body = {'Hello' => 'World!'}
|
356
|
-
Excon.stub(method: :get) do |request|
|
357
|
-
Excon.stubs.pop
|
358
|
-
{status: 200, headers: {'Content-Type' => 'application/json',
|
359
|
-
'ETag' => 'etag-contents'},
|
360
|
-
body: MultiJson.dump(body)}
|
361
|
-
end
|
362
|
-
|
363
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
364
|
-
link = Heroics::Link.new('https://example.com',
|
365
|
-
schema.resource('resource').link('list'),
|
366
|
-
cache: Moneta.new(:Memory))
|
367
|
-
assert_equal(body, link.run)
|
368
|
-
|
369
|
-
Excon.stub(method: :get) do |request|
|
370
|
-
assert_equal('etag-contents', request[:headers]['If-None-Match'])
|
371
|
-
Excon.stubs.pop
|
372
|
-
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
373
|
-
end
|
374
|
-
assert_equal(body, link.run)
|
375
|
-
end
|
376
|
-
|
377
|
-
# Link.run returns an enumerator when a 206 Partial Content status code and
|
378
|
-
# Content-Range header is included in a server response. The enumerator
|
379
|
-
# makes requests to fetch missing pages as its iterated.
|
380
|
-
def test_run_with_range_response
|
381
|
-
Excon.stub(method: :get) do |request|
|
382
|
-
Excon.stubs.shift
|
383
|
-
{status: 206, headers: {'Content-Type' => 'application/json',
|
384
|
-
'Content-Range' => 'id 1..2; max=200'},
|
385
|
-
body: MultiJson.dump([2])}
|
386
|
-
end
|
387
|
-
|
388
|
-
Excon.stub(method: :get) do |request|
|
389
|
-
Excon.stubs.shift
|
390
|
-
{status: 206, headers: {'Content-Type' => 'application/json',
|
391
|
-
'Content-Range' => 'id 0..1; max=200',
|
392
|
-
'Next-Range' => '201'},
|
393
|
-
body: MultiJson.dump([1])}
|
394
|
-
end
|
395
|
-
|
396
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
397
|
-
link = Heroics::Link.new('https://example.com',
|
398
|
-
schema.resource('resource').link('list'))
|
399
|
-
assert_equal([1, 2], link.run.to_a)
|
400
|
-
end
|
401
|
-
|
402
|
-
# Ensure that caching does not prevent pagination from working correctly.
|
403
|
-
# See https://github.com/heroku/platform-api/issues/16
|
404
|
-
def test_run_with_range_response_and_cache
|
405
|
-
Excon.stub(method: :get) do |request|
|
406
|
-
Excon.stubs.shift
|
407
|
-
{status: 206, headers: {'Content-Type' => 'application/json',
|
408
|
-
'Content-Range' => 'id 1..2; max=200',
|
409
|
-
'ETag' => 'second-page'},
|
410
|
-
body: MultiJson.dump([2])}
|
411
|
-
end
|
412
|
-
|
413
|
-
Excon.stub(method: :get) do |request|
|
414
|
-
Excon.stubs.shift
|
415
|
-
{status: 206, headers: {'Content-Type' => 'application/json',
|
416
|
-
'Content-Range' => 'id 0..1; max=200',
|
417
|
-
'Next-Range' => '201',
|
418
|
-
'ETag' => 'first-page'},
|
419
|
-
body: MultiJson.dump([1])}
|
420
|
-
end
|
421
|
-
|
422
|
-
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
423
|
-
link = Heroics::Link.new('https://example.com',
|
424
|
-
schema.resource('resource').link('list'),
|
425
|
-
cache: Moneta.new(:Memory))
|
426
|
-
assert_equal([1, 2], link.run.to_a)
|
427
|
-
|
428
|
-
Excon.stub(method: :get) do |request|
|
429
|
-
assert_equal('second-page', request[:headers]['If-None-Match'])
|
430
|
-
assert_equal('201', request[:headers]['Range'])
|
431
|
-
Excon.stubs.shift
|
432
|
-
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
433
|
-
end
|
434
|
-
|
435
|
-
Excon.stub(method: :get) do |request|
|
436
|
-
assert_equal('first-page', request[:headers]['If-None-Match'])
|
437
|
-
assert_equal(nil, request[:headers]['Range'])
|
438
|
-
Excon.stubs.shift
|
439
|
-
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
440
|
-
end
|
441
|
-
|
442
|
-
assert_equal([1, 2], link.run.to_a)
|
443
|
-
end
|
444
|
-
end
|