garage_client 2.1.1
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 +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +8 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +196 -0
- data/Rakefile +8 -0
- data/garage_client.gemspec +36 -0
- data/gemfiles/Gemfile.faraday-0.8.x +4 -0
- data/lib/garage_client.rb +33 -0
- data/lib/garage_client/cachers/base.rb +44 -0
- data/lib/garage_client/client.rb +93 -0
- data/lib/garage_client/configuration.rb +51 -0
- data/lib/garage_client/error.rb +37 -0
- data/lib/garage_client/request.rb +38 -0
- data/lib/garage_client/request/json_encoded.rb +59 -0
- data/lib/garage_client/resource.rb +63 -0
- data/lib/garage_client/response.rb +123 -0
- data/lib/garage_client/response/cacheable.rb +27 -0
- data/lib/garage_client/response/raise_http_exception.rb +34 -0
- data/lib/garage_client/version.rb +3 -0
- data/spec/features/configuration_spec.rb +46 -0
- data/spec/fixtures/example.yaml +56 -0
- data/spec/fixtures/examples.yaml +60 -0
- data/spec/fixtures/examples_dictionary.yaml +60 -0
- data/spec/fixtures/examples_without_pagination.yaml +58 -0
- data/spec/garage_client/cacher_spec.rb +55 -0
- data/spec/garage_client/client_spec.rb +228 -0
- data/spec/garage_client/configuration_spec.rb +106 -0
- data/spec/garage_client/error_spec.rb +37 -0
- data/spec/garage_client/request/json_encoded_spec.rb +66 -0
- data/spec/garage_client/resource_spec.rb +102 -0
- data/spec/garage_client/response_spec.rb +450 -0
- data/spec/garage_client_spec.rb +48 -0
- data/spec/spec_helper.rb +56 -0
- metadata +275 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe GarageClient::Configuration do
|
4
|
+
let(:configuration) do
|
5
|
+
described_class.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#adapter" do
|
9
|
+
context "in default configuration" do
|
10
|
+
it "returns :net_http" do
|
11
|
+
configuration.adapter.should == :net_http
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "after configured" do
|
16
|
+
before do
|
17
|
+
configuration.adapter = :test
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns configured value" do
|
21
|
+
configuration.adapter.should == :test
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#endpoint" do
|
27
|
+
context "not configured" do
|
28
|
+
it "raises RuntimeError" do
|
29
|
+
expect { configuration.endpoint }.to raise_error(RuntimeError, /missing endpoint/)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "after configured" do
|
34
|
+
before do
|
35
|
+
configuration.endpoint = "http://example.com"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns configured value" do
|
39
|
+
configuration.endpoint.should == "http://example.com"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#headers" do
|
45
|
+
context "in default configuration" do
|
46
|
+
it "returns default headers as Hash" do
|
47
|
+
configuration.headers.should == {
|
48
|
+
"Accept" => "application/json",
|
49
|
+
"User-Agent" => "garage_client #{GarageClient::VERSION}",
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "after configured" do
|
55
|
+
before do
|
56
|
+
configuration.headers = { "HTTP_ACCEPT" => "application/json" }
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns configured value" do
|
60
|
+
configuration.headers.should == { "HTTP_ACCEPT" => "application/json" }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#default_headers" do
|
66
|
+
it "returns configuration.headers" do
|
67
|
+
configuration.default_headers.should == configuration.headers
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#path_prefix" do
|
72
|
+
context "in default configuration" do
|
73
|
+
it "returns /v1" do
|
74
|
+
configuration.path_prefix.should == "/v1"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "after configured" do
|
79
|
+
before do
|
80
|
+
configuration.path_prefix = "/v2"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns configured value" do
|
84
|
+
configuration.path_prefix.should == "/v2"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#verbose" do
|
90
|
+
context "in default configuration" do
|
91
|
+
it "returns false" do
|
92
|
+
configuration.verbose.should == false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "after configured" do
|
97
|
+
before do
|
98
|
+
configuration.verbose = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns configured value" do
|
102
|
+
configuration.verbose.should == nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GarageClient::Error do
|
4
|
+
context 'without argument' do
|
5
|
+
it 'raises GarageClient::Error' do
|
6
|
+
expect { raise GarageClient::Error }.to raise_error(GarageClient::Error, /GarageClient::Error/)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'with string' do
|
11
|
+
let(:message) do
|
12
|
+
'error_message'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises GarageClient::Error with error message' do
|
16
|
+
expect { raise GarageClient::Error, message }.to raise_error(GarageClient::Error, message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with Faraday::Response' do
|
21
|
+
let(:client) do
|
22
|
+
Faraday.new do |builder|
|
23
|
+
builder.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub|
|
24
|
+
stub.get('/example') { [404, {}, ''] }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:response) do
|
30
|
+
client.get('/example')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'raises GarageClient::Error with response summary' do
|
34
|
+
expect { raise GarageClient::Error, response.env }.to raise_error(GarageClient::Error, /GET .+ 404/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe GarageClient::Request::JsonEncoded do
|
4
|
+
let(:client) do
|
5
|
+
GarageClient::Client.new(headers: headers)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:headers) do
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:params) do
|
13
|
+
{ key: "value" }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with Content-Type: application/json" do
|
17
|
+
let(:headers) do
|
18
|
+
{ "Content-Type" => "application/json" }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "encodes request body to JSON" do
|
22
|
+
stub_post("/examples").with(body: params.to_json)
|
23
|
+
expect { client.post("/examples", params) }.not_to raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "without Content-Type" do
|
28
|
+
it "encodes request body to JSON" do
|
29
|
+
stub_post("/examples").with(body: params.to_json)
|
30
|
+
expect { client.post("/examples", params) }.not_to raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "without body" do
|
35
|
+
let(:params) do
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it "does nothing" do
|
40
|
+
stub_post("/examples").with(body: nil)
|
41
|
+
expect { client.post("/examples", params) }.not_to raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
context "with Content-Type: multipart/form-data" do
|
47
|
+
let(:headers) do
|
48
|
+
{ "Content-Type" => "multipart/form-data" }
|
49
|
+
end
|
50
|
+
|
51
|
+
it "does nothing" do
|
52
|
+
stub_post("/examples").with(
|
53
|
+
body: [
|
54
|
+
"-------------RubyMultipartPost",
|
55
|
+
"Content-Disposition: form-data; name=\"key\"",
|
56
|
+
"",
|
57
|
+
"value",
|
58
|
+
"-------------RubyMultipartPost--",
|
59
|
+
"",
|
60
|
+
"",
|
61
|
+
].join("\r\n")
|
62
|
+
)
|
63
|
+
expect { client.post("/examples", params) }.not_to raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GarageClient::Resource do
|
4
|
+
let(:client) { GarageClient::Client.new }
|
5
|
+
let(:response_body) { JSON.parse(fixture('example.yaml')['body']) }
|
6
|
+
let(:resource) { GarageClient::Resource.new(client, response_body) }
|
7
|
+
|
8
|
+
describe '#properties' do
|
9
|
+
it 'returns available properties' do
|
10
|
+
resource.properties.should include(
|
11
|
+
:id,
|
12
|
+
:created,
|
13
|
+
:updated,
|
14
|
+
:name,
|
15
|
+
:url,
|
16
|
+
:description,
|
17
|
+
:serving,
|
18
|
+
:published,
|
19
|
+
:edited,
|
20
|
+
:tier,
|
21
|
+
:ingredients,
|
22
|
+
:steps
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#links' do
|
28
|
+
it 'returns available links' do
|
29
|
+
resource.links.should include(:self, :canonical, :nested_examples)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#update' do
|
34
|
+
before do
|
35
|
+
stub_put('/examples/1').to_return(fixture('example.yaml'))
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns response with updated resource' do
|
39
|
+
response = resource.update(:name => 'new name')
|
40
|
+
response.should be_kind_of(GarageClient::Response)
|
41
|
+
response.body.should be_kind_of(GarageClient::Resource)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#destroy' do
|
46
|
+
before do
|
47
|
+
stub_delete('/examples/1').to_return(:status => 204, :body => '')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns response' do
|
51
|
+
response = resource.destroy
|
52
|
+
response.should be_kind_of(GarageClient::Response)
|
53
|
+
response.body.should be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'create nested resource' do
|
58
|
+
before do
|
59
|
+
stub_post('/examples/1/nested_examples').to_return(fixture('example.yaml'))
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns response' do
|
63
|
+
response = resource.create_nested_examples(:name => 'name')
|
64
|
+
response.should be_kind_of(GarageClient::Response)
|
65
|
+
response.body.should be_kind_of(GarageClient::Resource)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'property' do
|
70
|
+
context 'with non-existent property' do
|
71
|
+
it 'raise no method error' do
|
72
|
+
expect { resource.non_existent_field }.to raise_error(NoMethodError)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with primitive value' do
|
77
|
+
it 'returns value' do
|
78
|
+
resource.name.should == 'recipe title'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with resource value' do
|
83
|
+
it 'returns resource' do
|
84
|
+
resource.user.should be_kind_of(GarageClient::Resource)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'link' do
|
90
|
+
context 'with existent link' do
|
91
|
+
before do
|
92
|
+
stub_get('/examples/1/nested_examples').to_return(fixture('examples.yaml'))
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns response' do
|
96
|
+
response = resource.nested_examples
|
97
|
+
response.should be_kind_of(GarageClient::Response)
|
98
|
+
response.body.should be_kind_of(Array)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,450 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GarageClient::Response do
|
4
|
+
let(:response) do
|
5
|
+
described_class.new(client, raw_response)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:client) do
|
9
|
+
GarageClient::Client.new
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:raw_response) do
|
13
|
+
double(headers: headers, body: env.body, env: env)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:headers) do
|
17
|
+
{ 'Link' => link }
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:env) do
|
21
|
+
double(:env, body: body).tap do |e|
|
22
|
+
allow(e).to receive(:[]).with(:body).and_return(body)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:body) do
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:link) do
|
31
|
+
%w[
|
32
|
+
</v1/examples?page=1>; rel="first",
|
33
|
+
</v1/examples?page=2>; rel="prev",
|
34
|
+
</v1/examples?page=4>; rel="next",
|
35
|
+
</v1/examples?page=5>; rel="last"
|
36
|
+
].join(" ")
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#respond_to?" do
|
40
|
+
context "with same property" do
|
41
|
+
before do
|
42
|
+
body["name"] = "example"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns true" do
|
46
|
+
response.respond_to?(:name).should == true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with same method" do
|
51
|
+
it "returns true" do
|
52
|
+
response.respond_to?(:body).should == true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with neithor same property nor same method" do
|
57
|
+
it "returns false" do
|
58
|
+
response.respond_to?(:name).should == false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with private method name and no include_private option" do
|
63
|
+
it "returns false" do
|
64
|
+
response.respond_to?(:parsed_link_header).should == false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with private method name and include_private option" do
|
69
|
+
it "returns true" do
|
70
|
+
response.respond_to?(:parsed_link_header, true).should == true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#has_next_page?" do
|
76
|
+
context "without Link header" do
|
77
|
+
before do
|
78
|
+
headers.delete("Link")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "returns false" do
|
82
|
+
response.has_next_page?.should == false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "without next link" do
|
87
|
+
let(:link) do
|
88
|
+
""
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns false" do
|
92
|
+
response.has_next_page?.should == false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with next link" do
|
97
|
+
it "returns true" do
|
98
|
+
response.has_next_page?.should == true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#has_prev_page?" do
|
104
|
+
context "without Link header" do
|
105
|
+
before do
|
106
|
+
headers.delete("Link")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns false" do
|
110
|
+
response.has_prev_page?.should == false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "without prev link" do
|
115
|
+
let(:link) do
|
116
|
+
""
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns false" do
|
120
|
+
response.has_prev_page?.should == false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "with prev link" do
|
125
|
+
it "returns true" do
|
126
|
+
response.has_prev_page?.should == true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#has_first_page?" do
|
132
|
+
context "without Link header" do
|
133
|
+
before do
|
134
|
+
headers.delete("Link")
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns false" do
|
138
|
+
response.has_first_page?.should == false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "without first link" do
|
143
|
+
let(:link) do
|
144
|
+
""
|
145
|
+
end
|
146
|
+
|
147
|
+
it "returns false" do
|
148
|
+
response.has_first_page?.should == false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "with first link" do
|
153
|
+
it "returns true" do
|
154
|
+
response.has_first_page?.should == true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#has_last_page?" do
|
160
|
+
context "without Link header" do
|
161
|
+
before do
|
162
|
+
headers.delete("Link")
|
163
|
+
end
|
164
|
+
|
165
|
+
it "returns false" do
|
166
|
+
response.has_last_page?.should == false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "without last link" do
|
171
|
+
let(:link) do
|
172
|
+
""
|
173
|
+
end
|
174
|
+
|
175
|
+
it "returns false" do
|
176
|
+
response.has_last_page?.should == false
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "with last link" do
|
181
|
+
it "returns true" do
|
182
|
+
response.has_last_page?.should == true
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "#next_page_path" do
|
188
|
+
context "without Link header" do
|
189
|
+
before do
|
190
|
+
headers.delete("Link")
|
191
|
+
end
|
192
|
+
|
193
|
+
it "returns nil" do
|
194
|
+
response.next_page_path.should == nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "without next link" do
|
199
|
+
let(:link) do
|
200
|
+
""
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns nil" do
|
204
|
+
response.next_page_path.should == nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with next link" do
|
209
|
+
it "returns next page path" do
|
210
|
+
response.next_page_path.should == "/v1/examples?page=4"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#prev_page_path" do
|
216
|
+
context "without Link header" do
|
217
|
+
before do
|
218
|
+
headers.delete("Link")
|
219
|
+
end
|
220
|
+
|
221
|
+
it "returns nil" do
|
222
|
+
response.prev_page_path.should == nil
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "without prev link" do
|
227
|
+
let(:link) do
|
228
|
+
""
|
229
|
+
end
|
230
|
+
|
231
|
+
it "returns nil" do
|
232
|
+
response.prev_page_path.should == nil
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "with prev link" do
|
237
|
+
it "returns prev page path" do
|
238
|
+
response.prev_page_path.should == "/v1/examples?page=2"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#first_page_path" do
|
244
|
+
context "without Link header" do
|
245
|
+
before do
|
246
|
+
headers.delete("Link")
|
247
|
+
end
|
248
|
+
|
249
|
+
it "returns nil" do
|
250
|
+
response.first_page_path.should == nil
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context "without first link" do
|
255
|
+
let(:link) do
|
256
|
+
""
|
257
|
+
end
|
258
|
+
|
259
|
+
it "returns nil" do
|
260
|
+
response.first_page_path.should == nil
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context "with first link" do
|
265
|
+
it "returns first page path" do
|
266
|
+
response.first_page_path.should == "/v1/examples?page=1"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "#last_page_path" do
|
272
|
+
context "without Link header" do
|
273
|
+
before do
|
274
|
+
headers.delete("Link")
|
275
|
+
end
|
276
|
+
|
277
|
+
it "returns nil" do
|
278
|
+
response.last_page_path.should == nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
context "without last link" do
|
283
|
+
let(:link) do
|
284
|
+
""
|
285
|
+
end
|
286
|
+
|
287
|
+
it "returns nil" do
|
288
|
+
response.last_page_path.should == nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context "with last link" do
|
293
|
+
it "returns last page path" do
|
294
|
+
response.last_page_path.should == "/v1/examples?page=5"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe Faraday::Response do
|
301
|
+
let(:mime_dict) { 'application/vnd.cookpad.dictionary+json' }
|
302
|
+
let(:client) { GarageClient::Client.new }
|
303
|
+
let(:response) { client.get('/examples') }
|
304
|
+
|
305
|
+
describe '#link' do
|
306
|
+
context 'with resources collection' do
|
307
|
+
context 'without paginated resources' do
|
308
|
+
before do
|
309
|
+
stub_get('/examples').to_return(fixture('examples_without_pagination.yaml'))
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'returns link header' do
|
313
|
+
response.link.should be_nil
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'with paginated resources' do
|
318
|
+
before do
|
319
|
+
stub_get('/examples').to_return(fixture('examples.yaml'))
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'returns link header' do
|
323
|
+
response.link.should == %q{</v1/examples?page=2&per_page=1>; rel="next"}
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
describe '#total_count' do
|
330
|
+
context 'with resources collection' do
|
331
|
+
context 'without paginated resources' do
|
332
|
+
before do
|
333
|
+
stub_get('/examples').to_return(fixture('examples_without_pagination.yaml'))
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'returns nil' do
|
337
|
+
response.total_count.should be_nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context 'with paginated resources' do
|
342
|
+
before do
|
343
|
+
stub_get('/examples').to_return(fixture('examples.yaml'))
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'returns total count' do
|
347
|
+
response.total_count.should == 1
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe '#body' do
|
354
|
+
let(:single_response) { client.get('/examples/1') }
|
355
|
+
let(:array_response) { client.get('/examples') }
|
356
|
+
let(:dictionary_response) { client.get('/examples', nil, :headers => { 'Accept' => mime_dict }) }
|
357
|
+
|
358
|
+
context 'with single resource' do
|
359
|
+
let(:response) { single_response }
|
360
|
+
|
361
|
+
before do
|
362
|
+
stub_get('/examples/1').to_return(fixture('example.yaml'))
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns resource' do
|
366
|
+
response.body.should be_kind_of(GarageClient::Resource)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
context 'with resources collection' do
|
371
|
+
context 'with array response' do
|
372
|
+
let(:response) { array_response }
|
373
|
+
|
374
|
+
before do
|
375
|
+
stub_get('/examples').to_return(fixture('examples.yaml'))
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'returns resources array' do
|
379
|
+
response.body.should be_kind_of(Array)
|
380
|
+
response.body.first.should be_kind_of(GarageClient::Resource)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
context 'with dictionary response' do
|
385
|
+
let(:response) { dictionary_response }
|
386
|
+
|
387
|
+
before do
|
388
|
+
stub_get('/examples').to_return(fixture('examples_dictionary.yaml'))
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'returns resources array' do
|
392
|
+
response.body.should be_kind_of(Hash)
|
393
|
+
response.body['1'].should be_kind_of(GarageClient::Resource)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe 'delegation' do
|
400
|
+
before do
|
401
|
+
stub_get('/examples').to_return(fixture('examples.yaml'))
|
402
|
+
end
|
403
|
+
|
404
|
+
it 'delegates undefined method call to resource' do
|
405
|
+
response.size.should == 1
|
406
|
+
response.first.should be_kind_of(GarageClient::Resource)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe 'http errors' do
|
411
|
+
{
|
412
|
+
401 => GarageClient::Unauthorized,
|
413
|
+
403 => GarageClient::Forbidden,
|
414
|
+
404 => GarageClient::NotFound,
|
415
|
+
406 => GarageClient::NotAcceptable,
|
416
|
+
409 => GarageClient::Conflict,
|
417
|
+
415 => GarageClient::UnsupportedMediaType,
|
418
|
+
422 => GarageClient::UnprocessableEntity,
|
419
|
+
500 => GarageClient::InternalServerError,
|
420
|
+
503 => GarageClient::ServiceUnavailable,
|
421
|
+
}.each do |status, exception|
|
422
|
+
context "when HTTP status is #{status}" do
|
423
|
+
before do
|
424
|
+
stub_get('/examples/xyz').to_return(:status => status)
|
425
|
+
end
|
426
|
+
|
427
|
+
it "should raise #{exception.name} error" do
|
428
|
+
expect {
|
429
|
+
client.get('/examples/xyz')
|
430
|
+
}.to raise_error(exception) { |e|
|
431
|
+
e.should be_a_kind_of(GarageClient::Error)
|
432
|
+
e.response.should be_respond_to(:[])
|
433
|
+
}
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
describe 'response type error' do
|
440
|
+
before do
|
441
|
+
stub_get('/examples').to_return(body: 'error')
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'raises error' do
|
445
|
+
expect { client.get('/examples') }.to raise_error(GarageClient::InvalidResponseType) {|e|
|
446
|
+
e.should be_a_kind_of(GarageClient::Error)
|
447
|
+
}
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|