garage_client 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +40 -0
  5. data/Gemfile +8 -0
  6. data/Guardfile +7 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +196 -0
  9. data/Rakefile +8 -0
  10. data/garage_client.gemspec +36 -0
  11. data/gemfiles/Gemfile.faraday-0.8.x +4 -0
  12. data/lib/garage_client.rb +33 -0
  13. data/lib/garage_client/cachers/base.rb +44 -0
  14. data/lib/garage_client/client.rb +93 -0
  15. data/lib/garage_client/configuration.rb +51 -0
  16. data/lib/garage_client/error.rb +37 -0
  17. data/lib/garage_client/request.rb +38 -0
  18. data/lib/garage_client/request/json_encoded.rb +59 -0
  19. data/lib/garage_client/resource.rb +63 -0
  20. data/lib/garage_client/response.rb +123 -0
  21. data/lib/garage_client/response/cacheable.rb +27 -0
  22. data/lib/garage_client/response/raise_http_exception.rb +34 -0
  23. data/lib/garage_client/version.rb +3 -0
  24. data/spec/features/configuration_spec.rb +46 -0
  25. data/spec/fixtures/example.yaml +56 -0
  26. data/spec/fixtures/examples.yaml +60 -0
  27. data/spec/fixtures/examples_dictionary.yaml +60 -0
  28. data/spec/fixtures/examples_without_pagination.yaml +58 -0
  29. data/spec/garage_client/cacher_spec.rb +55 -0
  30. data/spec/garage_client/client_spec.rb +228 -0
  31. data/spec/garage_client/configuration_spec.rb +106 -0
  32. data/spec/garage_client/error_spec.rb +37 -0
  33. data/spec/garage_client/request/json_encoded_spec.rb +66 -0
  34. data/spec/garage_client/resource_spec.rb +102 -0
  35. data/spec/garage_client/response_spec.rb +450 -0
  36. data/spec/garage_client_spec.rb +48 -0
  37. data/spec/spec_helper.rb +56 -0
  38. metadata +275 -0
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Configuration of GarageClient" do
4
+ let(:client) { GarageClient::Client.new(options) }
5
+ let(:options) { {} }
6
+
7
+ describe "header configuration" do
8
+ before do
9
+ options[:headers] = { "User-Agent" => "my agent" }
10
+ end
11
+
12
+ it "sends configured User-Agent" do
13
+ stub_request(:get, "https://garage.example.com/v1/me").
14
+ with(headers: { 'User-Agent'=>'my agent' }).
15
+ to_return(:status => 200, :body => "", :headers => {})
16
+
17
+ client.get('/v1/me')
18
+ end
19
+ end
20
+
21
+ describe "header configuration with global configuration" do
22
+ around do |example|
23
+ prev = GarageClient.configuration
24
+ GarageClient.instance_variable_set(
25
+ :@configuration,
26
+ GarageClient::Configuration.new(endpoint: "https://garage.example.com")
27
+ )
28
+
29
+ example.run
30
+
31
+ GarageClient.instance_variable_set(:@configuration, prev)
32
+ end
33
+
34
+ it "uses global configured User-Agent" do
35
+ GarageClient.configure do |c|
36
+ c.headers = { "User-Agent" => "my agent" }
37
+ end
38
+
39
+ stub_request(:get, "https://garage.example.com/v1/me").
40
+ with(headers: { 'User-Agent'=>'my agent' }).
41
+ to_return(:status => 200, :body => "", :headers => {})
42
+
43
+ client.get('/v1/me')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,56 @@
1
+ headers:
2
+ Content-Type: application/json; charset=utf-8
3
+ body: |
4
+ {
5
+ "id": 1,
6
+ "created": "2000-01-01T00:00:00+09:00",
7
+ "updated": "2000-01-01T00:00:00+09:00",
8
+ "name": "recipe title",
9
+ "url": "http://example.com/examples/1",
10
+ "user": {
11
+ "id": 2294,
12
+ "url": "http://example.com/kitchen/2294",
13
+ "name": "Fern1",
14
+ "_links": {
15
+ "self": {
16
+ "href": "/v1/users/2294"
17
+ },
18
+ "bookmarks": {
19
+ "href": "/v1/users/2294/bookmarks"
20
+ },
21
+ "bookmark_tags": {
22
+ "href": "/v1/users/2294/bookmark_tags"
23
+ },
24
+ "canonical": {
25
+ "href": "/v1/users/2294"
26
+ },
27
+ "diary_entries": {
28
+ "href": "/v1/users/2294/diary_entries"
29
+ },
30
+ "feedbacks": {
31
+ "href": "/v1/users/2294/feedbacks"
32
+ },
33
+ "recipes": {
34
+ "href": "/v1/users/2294/recipes"
35
+ }
36
+ }
37
+ },
38
+ "description": "this is my favorite recipe.",
39
+ "serving": null,
40
+ "published": "2000-01-01T00:00:00+09:00",
41
+ "edited": null,
42
+ "tier": "example.com:User",
43
+ "ingredients": [],
44
+ "steps": [],
45
+ "_links": {
46
+ "self": {
47
+ "href": "/examples/1"
48
+ },
49
+ "canonical": {
50
+ "href": "/examples/1"
51
+ },
52
+ "nested_examples": {
53
+ "href": "/examples/1/nested_examples"
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,60 @@
1
+ headers:
2
+ Content-Type: application/json; charset=utf-8
3
+ X-List-TotalCount: "1"
4
+ Link: </v1/examples?page=2&per_page=1>; rel="next"
5
+ body: |
6
+ [
7
+ {
8
+ "id": 1,
9
+ "created": "2000-01-01T00:00:00+09:00",
10
+ "updated": "2000-01-01T00:00:00+09:00",
11
+ "name": "recipe title",
12
+ "url": "http://example.com/examples/1",
13
+ "user": {
14
+ "id": 2294,
15
+ "url": "http://example.com/kitchen/2294",
16
+ "name": "Fern1",
17
+ "_links": {
18
+ "self": {
19
+ "href": "/v1/users/2294"
20
+ },
21
+ "bookmarks": {
22
+ "href": "/v1/users/2294/bookmarks"
23
+ },
24
+ "bookmark_tags": {
25
+ "href": "/v1/users/2294/bookmark_tags"
26
+ },
27
+ "canonical": {
28
+ "href": "/v1/users/2294"
29
+ },
30
+ "diary_entries": {
31
+ "href": "/v1/users/2294/diary_entries"
32
+ },
33
+ "feedbacks": {
34
+ "href": "/v1/users/2294/feedbacks"
35
+ },
36
+ "recipes": {
37
+ "href": "/v1/users/2294/recipes"
38
+ }
39
+ }
40
+ },
41
+ "descriptien": "this is my favorite recipe.",
42
+ "serving": null,
43
+ "published": "2000-01-01T00:00:00+09:00",
44
+ "edited": null,
45
+ "tier": "example.com:User",
46
+ "ingredients": [],
47
+ "steps": [],
48
+ "_links": {
49
+ "self": {
50
+ "href": "/examples/1"
51
+ },
52
+ "canonical": {
53
+ "href": "/examples/1"
54
+ },
55
+ "nested_examples": {
56
+ "href": "/examples/1/nested_examples"
57
+ }
58
+ }
59
+ }
60
+ ]
@@ -0,0 +1,60 @@
1
+ headers:
2
+ Content-Type: application/vnd.cookpad.dictionary+json; charset=utf-8
3
+ X-List-TotalCount: "1"
4
+ Link: </v1/examples?page=2&per_page=1>; rel="next"
5
+ body: |
6
+ {
7
+ "1": {
8
+ "id": 1,
9
+ "created": "2000-01-01T00:00:00+09:00",
10
+ "updated": "2000-01-01T00:00:00+09:00",
11
+ "name": "recipe title",
12
+ "url": "http://example.com/examples/1",
13
+ "user": {
14
+ "id": 2294,
15
+ "url": "http://example.com/kitchen/2294",
16
+ "name": "Fern1",
17
+ "_links": {
18
+ "self": {
19
+ "href": "/v1/users/2294"
20
+ },
21
+ "bookmarks": {
22
+ "href": "/v1/users/2294/bookmarks"
23
+ },
24
+ "bookmark_tags": {
25
+ "href": "/v1/users/2294/bookmark_tags"
26
+ },
27
+ "canonical": {
28
+ "href": "/v1/users/2294"
29
+ },
30
+ "diary_entries": {
31
+ "href": "/v1/users/2294/diary_entries"
32
+ },
33
+ "feedbacks": {
34
+ "href": "/v1/users/2294/feedbacks"
35
+ },
36
+ "recipes": {
37
+ "href": "/v1/users/2294/recipes"
38
+ }
39
+ }
40
+ },
41
+ "descriptien": "this is my favorite recipe.",
42
+ "serving": null,
43
+ "published": "2000-01-01T00:00:00+09:00",
44
+ "edited": null,
45
+ "tier": "cookpad.com:User",
46
+ "ingredients": [],
47
+ "steps": [],
48
+ "_links": {
49
+ "self": {
50
+ "href": "/examples/1"
51
+ },
52
+ "canonical": {
53
+ "href": "/examples/1"
54
+ },
55
+ "nested_examples": {
56
+ "href": "/examples/1/nested_examples"
57
+ }
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,58 @@
1
+ headers:
2
+ Content-Type: application/json; charset=utf-8
3
+ body: |
4
+ [
5
+ {
6
+ "id": 1,
7
+ "created": "2000-01-01T00:00:00+09:00",
8
+ "updated": "2000-01-01T00:00:00+09:00",
9
+ "name": "recipe title",
10
+ "url": "http://example.com/examples/1",
11
+ "user": {
12
+ "id": 2294,
13
+ "url": "http://example.com/kitchen/2294",
14
+ "name": "Fern1",
15
+ "_links": {
16
+ "self": {
17
+ "href": "/v1/users/2294"
18
+ },
19
+ "bookmarks": {
20
+ "href": "/v1/users/2294/bookmarks"
21
+ },
22
+ "bookmark_tags": {
23
+ "href": "/v1/users/2294/bookmark_tags"
24
+ },
25
+ "canonical": {
26
+ "href": "/v1/users/2294"
27
+ },
28
+ "diary_entries": {
29
+ "href": "/v1/users/2294/diary_entries"
30
+ },
31
+ "feedbacks": {
32
+ "href": "/v1/users/2294/feedbacks"
33
+ },
34
+ "recipes": {
35
+ "href": "/v1/users/2294/recipes"
36
+ }
37
+ }
38
+ },
39
+ "description": "this is my favorite recipe.",
40
+ "serving": null,
41
+ "published": "2000-01-01T00:00:00+09:00",
42
+ "edited": null,
43
+ "tier": "cookpad.com:User",
44
+ "ingredients": [],
45
+ "steps": [],
46
+ "_links": {
47
+ "self": {
48
+ "href": "/examples/1"
49
+ },
50
+ "canonical": {
51
+ "href": "/v1/examples/1"
52
+ },
53
+ "nested_examples": {
54
+ "href": "/examples/1/nested_examples"
55
+ }
56
+ }
57
+ }
58
+ ]
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+
3
+ describe GarageClient::Cachers::Base do
4
+ let(:client) do
5
+ GarageClient::Client.new(cacher: cacher_class)
6
+ end
7
+
8
+ let(:cacher_class) do
9
+ store = store
10
+ Class.new(GarageClient::Cachers::Base) do
11
+ private
12
+
13
+ def key
14
+ @env[:url].to_s
15
+ end
16
+
17
+ def read_from_cache?
18
+ true
19
+ end
20
+
21
+ def written_to_cache?
22
+ true
23
+ end
24
+
25
+ def store
26
+ Class.new do
27
+ def initialize
28
+ @table = {}
29
+ end
30
+
31
+ def read(key, options = {})
32
+ @table[key]
33
+ end
34
+
35
+ def write(key, value, options = {})
36
+ @table[key] = value
37
+ end
38
+ end.new
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "caching" do
44
+ context "with cache-enabled GarageClient::Client" do
45
+ it "caches response along passed cacher class" do
46
+ stub_get("/examples").to_return(fixture("examples.yaml")).times(1)
47
+ stub_get("/example").to_return(fixture("example.yaml")).times(1)
48
+ client.get("/examples").body.should be_a Array
49
+ client.get("/examples").body.should be_a Array
50
+ client.get("/example").body.should be_a GarageClient::Resource
51
+ client.get("/example").body.should be_a GarageClient::Resource
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,228 @@
1
+ require 'spec_helper'
2
+
3
+ describe GarageClient::Client do
4
+ let(:client) { GarageClient::Client.new(options) }
5
+ let(:options) { {} }
6
+
7
+ describe "#adapter" do
8
+ context "without :adapter option value" do
9
+ it "returns default value" do
10
+ client.adapter.should == GarageClient.configuration.adapter
11
+ end
12
+ end
13
+
14
+ context "with :adapter option value" do
15
+ before do
16
+ options[:adapter] = :test
17
+ end
18
+
19
+ it "returns it" do
20
+ client.adapter.should == :test
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#endpoint" do
26
+ context "without :endpoint option value" do
27
+ it "returns default value" do
28
+ client.endpoint.should == GarageClient.configuration.endpoint
29
+ end
30
+ end
31
+
32
+ context "with :endpoint option value" do
33
+ before do
34
+ options[:endpoint] = "http://example.com"
35
+ end
36
+
37
+ it "returns it" do
38
+ client.endpoint.should == "http://example.com"
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#path_prefix" do
44
+ context "without :path_prefix option value" do
45
+ it "returns default value" do
46
+ client.path_prefix.should == GarageClient.configuration.path_prefix
47
+ end
48
+ end
49
+
50
+ context "with :path_prefix option value" do
51
+ before do
52
+ options[:path_prefix] = "/v2"
53
+ end
54
+
55
+ it "returns it" do
56
+ client.path_prefix.should == "/v2"
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "#verbose" do
62
+ context "without :verbose option value" do
63
+ it "returns default value" do
64
+ client.verbose.should == GarageClient.configuration.verbose
65
+ end
66
+ end
67
+
68
+ context "with :verbose option value" do
69
+ before do
70
+ options[:verbose] = nil
71
+ end
72
+
73
+ it "returns it" do
74
+ client.verbose.should == nil
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#headers" do
80
+ context "without :headers option value" do
81
+ it "returns default value" do
82
+ client.headers.should == GarageClient.configuration.headers
83
+ end
84
+ end
85
+
86
+ context "with :headers option value" do
87
+ before do
88
+ options[:headers] = { "Content-Type" => "text/plain" }
89
+ end
90
+
91
+ it "returns headers merged with default values" do
92
+ client.headers.should == {
93
+ "Accept" => "application/json",
94
+ "Content-Type" => "text/plain",
95
+ "User-Agent" => "garage_client #{GarageClient::VERSION}"
96
+ }
97
+ end
98
+ end
99
+
100
+ context "with User-Agent header option" do
101
+ before do
102
+ options[:headers] = { "User-Agent" => "my agent" }
103
+ end
104
+
105
+ it "returns changed User-Agent" do
106
+ client.headers["User-Agent"].should eq "my agent"
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "authorization" do
112
+ before do
113
+ client.access_token = 'abc'
114
+ stub_get('/example').with(
115
+ headers: {
116
+ 'Accept' => 'application/json',
117
+ 'Accept-Encoding' => /.*/,
118
+ 'User-Agent' => /.*/,
119
+ 'Authorization' => 'Bearer abc'
120
+ }
121
+ ).to_return(fixture('example.yaml'))
122
+ end
123
+
124
+ it "requests with expected beaer authorization header" do
125
+ expect { client.get('/example') }.not_to raise_error
126
+ end
127
+ end
128
+
129
+ describe "#adapter=" do
130
+ it "overwrites it" do
131
+ client.adapter = :test
132
+ client.adapter.should == :test
133
+ end
134
+ end
135
+
136
+ describe "#endpoint=" do
137
+ it "overwrites it" do
138
+ client.adapter = "http://example.com"
139
+ client.adapter.should == "http://example.com"
140
+ end
141
+ end
142
+
143
+ describe "#headers=" do
144
+ it "updates merged headers" do
145
+ client.headers = { "Content-Type" => "text/plain" }
146
+ client.headers.should == { "Content-Type" => "text/plain" }
147
+ end
148
+ end
149
+
150
+ describe "#path_prefix=" do
151
+ it "overwrites it" do
152
+ client.adapter = "/v2"
153
+ client.adapter.should == "/v2"
154
+ end
155
+ end
156
+
157
+ describe "#verbose=" do
158
+ it "overwrites it" do
159
+ client.verbose = nil
160
+ client.verbose.should == nil
161
+ end
162
+ end
163
+
164
+ describe '#get' do
165
+ context 'with collection resource' do
166
+ before do
167
+ stub_get('/examples').to_return(fixture('examples.yaml'))
168
+ end
169
+
170
+ it 'returns response' do
171
+ response = client.get('/examples')
172
+ response.should be_kind_of(GarageClient::Response)
173
+ response.body.should be_kind_of(Array)
174
+ response.body.first.should be_kind_of(GarageClient::Resource)
175
+ end
176
+ end
177
+
178
+ context 'with single resource' do
179
+ before do
180
+ stub_get('/examples/1').to_return(fixture('example.yaml'))
181
+ end
182
+
183
+ it 'returns response' do
184
+ response = client.get('/examples/1')
185
+ response.should be_kind_of(GarageClient::Response)
186
+ response.body.should be_kind_of(GarageClient::Resource)
187
+ end
188
+ end
189
+ end
190
+
191
+ describe '#post' do
192
+ before do
193
+ stub_post('/examples').to_return(fixture('example.yaml'))
194
+ end
195
+
196
+ it 'returns created resource' do
197
+ response = client.post('/examples', :name => 'example name')
198
+ response.should be_kind_of(GarageClient::Response)
199
+ response.body.should be_kind_of(GarageClient::Resource)
200
+ end
201
+ end
202
+
203
+ describe '#me' do
204
+ before do
205
+ stub_get('/me').to_return(fixture('example.yaml'))
206
+ end
207
+
208
+ it 'returns response' do
209
+ response = client.me
210
+ response.should be_kind_of(GarageClient::Response)
211
+ response.body.should be_kind_of(GarageClient::Resource)
212
+ end
213
+ end
214
+
215
+ describe 'validation' do
216
+ context 'when endpoint configuration is missing' do
217
+ around do |example|
218
+ old, GarageClient.endpoint = GarageClient.endpoint, nil
219
+ example.run
220
+ GarageClient.endpoint = old
221
+ end
222
+
223
+ it 'raises RuntimeError' do
224
+ expect { client }.to raise_error(RuntimeError, /missing endpoint/)
225
+ end
226
+ end
227
+ end
228
+ end