cure-google-api-client 0.8.7.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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +178 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE +202 -0
  5. data/README.md +218 -0
  6. data/Rakefile +41 -0
  7. data/google-api-client.gemspec +43 -0
  8. data/lib/cacerts.pem +2183 -0
  9. data/lib/compat/multi_json.rb +19 -0
  10. data/lib/google/api_client.rb +750 -0
  11. data/lib/google/api_client/auth/compute_service_account.rb +28 -0
  12. data/lib/google/api_client/auth/file_storage.rb +59 -0
  13. data/lib/google/api_client/auth/installed_app.rb +126 -0
  14. data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
  15. data/lib/google/api_client/auth/key_utils.rb +93 -0
  16. data/lib/google/api_client/auth/pkcs12.rb +41 -0
  17. data/lib/google/api_client/auth/storage.rb +102 -0
  18. data/lib/google/api_client/auth/storages/file_store.rb +58 -0
  19. data/lib/google/api_client/auth/storages/redis_store.rb +54 -0
  20. data/lib/google/api_client/batch.rb +326 -0
  21. data/lib/google/api_client/charset.rb +33 -0
  22. data/lib/google/api_client/client_secrets.rb +179 -0
  23. data/lib/google/api_client/discovery.rb +19 -0
  24. data/lib/google/api_client/discovery/api.rb +310 -0
  25. data/lib/google/api_client/discovery/media.rb +77 -0
  26. data/lib/google/api_client/discovery/method.rb +363 -0
  27. data/lib/google/api_client/discovery/resource.rb +156 -0
  28. data/lib/google/api_client/discovery/schema.rb +117 -0
  29. data/lib/google/api_client/environment.rb +42 -0
  30. data/lib/google/api_client/errors.rb +65 -0
  31. data/lib/google/api_client/gzip.rb +28 -0
  32. data/lib/google/api_client/logging.rb +32 -0
  33. data/lib/google/api_client/media.rb +259 -0
  34. data/lib/google/api_client/railtie.rb +18 -0
  35. data/lib/google/api_client/reference.rb +27 -0
  36. data/lib/google/api_client/request.rb +350 -0
  37. data/lib/google/api_client/result.rb +255 -0
  38. data/lib/google/api_client/service.rb +233 -0
  39. data/lib/google/api_client/service/batch.rb +110 -0
  40. data/lib/google/api_client/service/request.rb +144 -0
  41. data/lib/google/api_client/service/resource.rb +40 -0
  42. data/lib/google/api_client/service/result.rb +162 -0
  43. data/lib/google/api_client/service/simple_file_store.rb +151 -0
  44. data/lib/google/api_client/service/stub_generator.rb +61 -0
  45. data/lib/google/api_client/service_account.rb +21 -0
  46. data/lib/google/api_client/version.rb +26 -0
  47. data/spec/google/api_client/auth/storage_spec.rb +122 -0
  48. data/spec/google/api_client/auth/storages/file_store_spec.rb +40 -0
  49. data/spec/google/api_client/auth/storages/redis_store_spec.rb +70 -0
  50. data/spec/google/api_client/batch_spec.rb +248 -0
  51. data/spec/google/api_client/client_secrets_spec.rb +53 -0
  52. data/spec/google/api_client/discovery_spec.rb +708 -0
  53. data/spec/google/api_client/gzip_spec.rb +98 -0
  54. data/spec/google/api_client/media_spec.rb +178 -0
  55. data/spec/google/api_client/request_spec.rb +29 -0
  56. data/spec/google/api_client/result_spec.rb +207 -0
  57. data/spec/google/api_client/service_account_spec.rb +169 -0
  58. data/spec/google/api_client/service_spec.rb +618 -0
  59. data/spec/google/api_client/simple_file_store_spec.rb +133 -0
  60. data/spec/google/api_client_spec.rb +352 -0
  61. data/spec/spec_helper.rb +66 -0
  62. metadata +339 -0
@@ -0,0 +1,169 @@
1
+ # Copyright 2012 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'google/api_client'
18
+
19
+ fixtures_path = File.expand_path('../../../fixtures', __FILE__)
20
+
21
+ RSpec.describe Google::APIClient::KeyUtils do
22
+ it 'should read PKCS12 files from the filesystem' do
23
+ if RUBY_PLATFORM == 'java' && RUBY_VERSION.start_with?('1.8')
24
+ pending "Reading from PKCS12 not supported on jruby 1.8.x"
25
+ end
26
+ path = File.expand_path('files/privatekey.p12', fixtures_path)
27
+ key = Google::APIClient::KeyUtils.load_from_pkcs12(path, 'notasecret')
28
+ expect(key).not_to eq(nil)
29
+ end
30
+
31
+ it 'should read PKCS12 files from loaded files' do
32
+ if RUBY_PLATFORM == 'java' && RUBY_VERSION.start_with?('1.8')
33
+ pending "Reading from PKCS12 not supported on jruby 1.8.x"
34
+ end
35
+ path = File.expand_path('files/privatekey.p12', fixtures_path)
36
+ content = File.read(path)
37
+ key = Google::APIClient::KeyUtils.load_from_pkcs12(content, 'notasecret')
38
+ expect(key).not_to eq(nil)
39
+ end
40
+
41
+ it 'should read PEM files from the filesystem' do
42
+ path = File.expand_path('files/secret.pem', fixtures_path)
43
+ key = Google::APIClient::KeyUtils.load_from_pem(path, 'notasecret')
44
+ expect(key).not_to eq(nil)
45
+ end
46
+
47
+ it 'should read PEM files from loaded files' do
48
+ path = File.expand_path('files/secret.pem', fixtures_path)
49
+ content = File.read(path)
50
+ key = Google::APIClient::KeyUtils.load_from_pem(content, 'notasecret')
51
+ expect(key).not_to eq(nil)
52
+ end
53
+
54
+ end
55
+
56
+ RSpec.describe Google::APIClient::JWTAsserter do
57
+ include ConnectionHelpers
58
+
59
+ before do
60
+ @key = OpenSSL::PKey::RSA.new 2048
61
+ end
62
+
63
+ it 'should generate valid JWTs' do
64
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
65
+ jwt = asserter.to_authorization.to_jwt
66
+ expect(jwt).not_to eq(nil)
67
+
68
+ claim = JWT.decode(jwt, @key.public_key, true)
69
+ claim = claim[0] if claim[0]
70
+ expect(claim["iss"]).to eq('client1')
71
+ expect(claim["scope"]).to eq('scope1 scope2')
72
+ end
73
+
74
+ it 'should allow impersonation' do
75
+ conn = stub_connection do |stub|
76
+ stub.post('/o/oauth2/token') do |env|
77
+ params = Addressable::URI.form_unencode(env[:body])
78
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
79
+ expect(params.assoc("grant_type")).to eq(['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer'])
80
+ [200, {'content-type' => 'application/json'}, '{
81
+ "access_token" : "1/abcdef1234567890",
82
+ "token_type" : "Bearer",
83
+ "expires_in" : 3600
84
+ }']
85
+ end
86
+ end
87
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
88
+ auth = asserter.authorize('user1@email.com', { :connection => conn })
89
+ expect(auth).not_to eq(nil?)
90
+ expect(auth.person).to eq('user1@email.com')
91
+ conn.verify
92
+ end
93
+
94
+ it 'should send valid access token request' do
95
+ conn = stub_connection do |stub|
96
+ stub.post('/o/oauth2/token') do |env|
97
+ params = Addressable::URI.form_unencode(env[:body])
98
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
99
+ expect(params.assoc("grant_type")).to eq(['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer'])
100
+ [200, {'content-type' => 'application/json'}, '{
101
+ "access_token" : "1/abcdef1234567890",
102
+ "token_type" : "Bearer",
103
+ "expires_in" : 3600
104
+ }']
105
+ end
106
+ end
107
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
108
+ auth = asserter.authorize(nil, { :connection => conn })
109
+ expect(auth).not_to eq(nil?)
110
+ expect(auth.access_token).to eq("1/abcdef1234567890")
111
+ conn.verify
112
+ end
113
+
114
+ it 'should be refreshable' do
115
+ conn = stub_connection do |stub|
116
+ stub.post('/o/oauth2/token') do |env|
117
+ params = Addressable::URI.form_unencode(env[:body])
118
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
119
+ expect(params.assoc("grant_type")).to eq(['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer'])
120
+ [200, {'content-type' => 'application/json'}, '{
121
+ "access_token" : "1/abcdef1234567890",
122
+ "token_type" : "Bearer",
123
+ "expires_in" : 3600
124
+ }']
125
+ end
126
+ stub.post('/o/oauth2/token') do |env|
127
+ params = Addressable::URI.form_unencode(env[:body])
128
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
129
+ expect(params.assoc("grant_type")).to eq(['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer'])
130
+ [200, {'content-type' => 'application/json'}, '{
131
+ "access_token" : "1/0987654321fedcba",
132
+ "token_type" : "Bearer",
133
+ "expires_in" : 3600
134
+ }']
135
+ end
136
+ end
137
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
138
+ auth = asserter.authorize(nil, { :connection => conn })
139
+ expect(auth).not_to eq(nil?)
140
+ expect(auth.access_token).to eq("1/abcdef1234567890")
141
+
142
+ auth.fetch_access_token!(:connection => conn)
143
+ expect(auth.access_token).to eq("1/0987654321fedcba")
144
+
145
+ conn.verify
146
+ end
147
+ end
148
+
149
+ RSpec.describe Google::APIClient::ComputeServiceAccount do
150
+ include ConnectionHelpers
151
+
152
+ it 'should query metadata server' do
153
+ conn = stub_connection do |stub|
154
+ stub.get('/computeMetadata/v1beta1/instance/service-accounts/default/token') do |env|
155
+ expect(env.url.host).to eq('metadata')
156
+ [200, {'content-type' => 'application/json'}, '{
157
+ "access_token" : "1/abcdef1234567890",
158
+ "token_type" : "Bearer",
159
+ "expires_in" : 3600
160
+ }']
161
+ end
162
+ end
163
+ service_account = Google::APIClient::ComputeServiceAccount.new
164
+ auth = service_account.fetch_access_token!({ :connection => conn })
165
+ expect(auth).not_to eq(nil?)
166
+ expect(auth["access_token"]).to eq("1/abcdef1234567890")
167
+ conn.verify
168
+ end
169
+ end
@@ -0,0 +1,618 @@
1
+ # encoding:utf-8
2
+
3
+ # Copyright 2013 Google Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'spec_helper'
18
+
19
+ require 'google/api_client'
20
+ require 'google/api_client/service'
21
+
22
+ fixtures_path = File.expand_path('../../../fixtures', __FILE__)
23
+
24
+ RSpec.describe Google::APIClient::Service do
25
+ include ConnectionHelpers
26
+
27
+ APPLICATION_NAME = 'API Client Tests'
28
+
29
+ it 'should error out when called without an API name or version' do
30
+ expect(lambda do
31
+ Google::APIClient::Service.new
32
+ end).to raise_error(ArgumentError)
33
+ end
34
+
35
+ it 'should error out when called without an API version' do
36
+ expect(lambda do
37
+ Google::APIClient::Service.new('foo')
38
+ end).to raise_error(ArgumentError)
39
+ end
40
+
41
+ it 'should error out when the options hash is not a hash' do
42
+ expect(lambda do
43
+ Google::APIClient::Service.new('foo', 'v1', 42)
44
+ end).to raise_error(ArgumentError)
45
+ end
46
+
47
+ describe 'with the AdSense Management API' do
48
+
49
+ it 'should make a valid call for a method with no parameters' do
50
+ conn = stub_connection do |stub|
51
+ stub.get('/adsense/v1.3/adclients') do |env|
52
+ [200, {}, '{}']
53
+ end
54
+ end
55
+ adsense = Google::APIClient::Service.new(
56
+ 'adsense',
57
+ 'v1.3',
58
+ {
59
+ :application_name => APPLICATION_NAME,
60
+ :authenticated => false,
61
+ :connection => conn,
62
+ :cache_store => nil
63
+ }
64
+ )
65
+
66
+ req = adsense.adclients.list.execute()
67
+ conn.verify
68
+ end
69
+
70
+ it 'should make a valid call for a method with parameters' do
71
+ conn = stub_connection do |stub|
72
+ stub.get('/adsense/v1.3/adclients/1/adunits') do |env|
73
+ [200, {}, '{}']
74
+ end
75
+ end
76
+ adsense = Google::APIClient::Service.new(
77
+ 'adsense',
78
+ 'v1.3',
79
+ {
80
+ :application_name => APPLICATION_NAME,
81
+ :authenticated => false,
82
+ :connection => conn,
83
+ :cache_store => nil
84
+ }
85
+ )
86
+ req = adsense.adunits.list(:adClientId => '1').execute()
87
+ end
88
+
89
+ it 'should make a valid call for a deep method' do
90
+ conn = stub_connection do |stub|
91
+ stub.get('/adsense/v1.3/accounts/1/adclients') do |env|
92
+ [200, {}, '{}']
93
+ end
94
+ end
95
+ adsense = Google::APIClient::Service.new(
96
+ 'adsense',
97
+ 'v1.3',
98
+ {
99
+ :application_name => APPLICATION_NAME,
100
+ :authenticated => false,
101
+ :connection => conn,
102
+ :cache_store => nil
103
+ }
104
+ )
105
+ req = adsense.accounts.adclients.list(:accountId => '1').execute()
106
+ end
107
+
108
+ describe 'with no connection' do
109
+ before do
110
+ @adsense = Google::APIClient::Service.new('adsense', 'v1.3',
111
+ {:application_name => APPLICATION_NAME, :cache_store => nil})
112
+ end
113
+
114
+ it 'should return a resource when using a valid resource name' do
115
+ expect(@adsense.accounts).to be_a(Google::APIClient::Service::Resource)
116
+ end
117
+
118
+ it 'should throw an error when using an invalid resource name' do
119
+ expect(lambda do
120
+ @adsense.invalid_resource
121
+ end).to raise_error
122
+ end
123
+
124
+ it 'should return a request when using a valid method name' do
125
+ req = @adsense.adclients.list
126
+ expect(req).to be_a(Google::APIClient::Service::Request)
127
+ expect(req.method.id).to eq('adsense.adclients.list')
128
+ expect(req.parameters).to be_nil
129
+ end
130
+
131
+ it 'should throw an error when using an invalid method name' do
132
+ expect(lambda do
133
+ @adsense.adclients.invalid_method
134
+ end).to raise_error
135
+ end
136
+
137
+ it 'should return a valid request with parameters' do
138
+ req = @adsense.adunits.list(:adClientId => '1')
139
+ expect(req).to be_a(Google::APIClient::Service::Request)
140
+ expect(req.method.id).to eq('adsense.adunits.list')
141
+ expect(req.parameters).not_to be_nil
142
+ expect(req.parameters[:adClientId]).to eq('1')
143
+ end
144
+ end
145
+ end
146
+
147
+ describe 'with the Prediction API' do
148
+
149
+ it 'should make a valid call with an object body' do
150
+ conn = stub_connection do |stub|
151
+ stub.post('/prediction/v1.5/trainedmodels?project=1') do |env|
152
+ expect(env.body).to eq('{"id":"1"}')
153
+ [200, {}, '{}']
154
+ end
155
+ end
156
+ prediction = Google::APIClient::Service.new(
157
+ 'prediction',
158
+ 'v1.5',
159
+ {
160
+ :application_name => APPLICATION_NAME,
161
+ :authenticated => false,
162
+ :connection => conn,
163
+ :cache_store => nil
164
+ }
165
+ )
166
+ req = prediction.trainedmodels.insert(:project => '1').body({'id' => '1'}).execute()
167
+ conn.verify
168
+ end
169
+
170
+ it 'should make a valid call with a text body' do
171
+ conn = stub_connection do |stub|
172
+ stub.post('/prediction/v1.5/trainedmodels?project=1') do |env|
173
+ expect(env.body).to eq('{"id":"1"}')
174
+ [200, {}, '{}']
175
+ end
176
+ end
177
+ prediction = Google::APIClient::Service.new(
178
+ 'prediction',
179
+ 'v1.5',
180
+ {
181
+ :application_name => APPLICATION_NAME,
182
+ :authenticated => false,
183
+ :connection => conn,
184
+ :cache_store => nil
185
+ }
186
+ )
187
+ req = prediction.trainedmodels.insert(:project => '1').body('{"id":"1"}').execute()
188
+ conn.verify
189
+ end
190
+
191
+ describe 'with no connection' do
192
+ before do
193
+ @prediction = Google::APIClient::Service.new('prediction', 'v1.5',
194
+ {:application_name => APPLICATION_NAME, :cache_store => nil})
195
+ end
196
+
197
+ it 'should return a valid request with a body' do
198
+ req = @prediction.trainedmodels.insert(:project => '1').body({'id' => '1'})
199
+ expect(req).to be_a(Google::APIClient::Service::Request)
200
+ expect(req.method.id).to eq('prediction.trainedmodels.insert')
201
+ expect(req.body).to eq({'id' => '1'})
202
+ expect(req.parameters).not_to be_nil
203
+ expect(req.parameters[:project]).to eq('1')
204
+ end
205
+
206
+ it 'should return a valid request with a body when using resource name' do
207
+ req = @prediction.trainedmodels.insert(:project => '1').training({'id' => '1'})
208
+ expect(req).to be_a(Google::APIClient::Service::Request)
209
+ expect(req.method.id).to eq('prediction.trainedmodels.insert')
210
+ expect(req.training).to eq({'id' => '1'})
211
+ expect(req.parameters).not_to be_nil
212
+ expect(req.parameters[:project]).to eq('1')
213
+ end
214
+ end
215
+ end
216
+
217
+ describe 'with the Drive API' do
218
+
219
+ before do
220
+ @metadata = {
221
+ 'title' => 'My movie',
222
+ 'description' => 'The best home movie ever made'
223
+ }
224
+ @file = File.expand_path('files/sample.txt', fixtures_path)
225
+ @media = Google::APIClient::UploadIO.new(@file, 'text/plain')
226
+ end
227
+
228
+ it 'should make a valid call with an object body and media upload' do
229
+ conn = stub_connection do |stub|
230
+ stub.post('/upload/drive/v2/files?uploadType=multipart') do |env|
231
+ expect(env.body).to be_a Faraday::CompositeReadIO
232
+ [200, {}, '{}']
233
+ end
234
+ end
235
+ drive = Google::APIClient::Service.new(
236
+ 'drive',
237
+ 'v2',
238
+ {
239
+ :application_name => APPLICATION_NAME,
240
+ :authenticated => false,
241
+ :connection => conn,
242
+ :cache_store => nil
243
+ }
244
+ )
245
+ req = drive.files.insert(:uploadType => 'multipart').body(@metadata).media(@media).execute()
246
+ conn.verify
247
+ end
248
+
249
+ describe 'with no connection' do
250
+ before do
251
+ @drive = Google::APIClient::Service.new('drive', 'v2',
252
+ {:application_name => APPLICATION_NAME, :cache_store => nil})
253
+ end
254
+
255
+ it 'should return a valid request with a body and media upload' do
256
+ req = @drive.files.insert(:uploadType => 'multipart').body(@metadata).media(@media)
257
+ expect(req).to be_a(Google::APIClient::Service::Request)
258
+ expect(req.method.id).to eq('drive.files.insert')
259
+ expect(req.body).to eq(@metadata)
260
+ expect(req.media).to eq(@media)
261
+ expect(req.parameters).not_to be_nil
262
+ expect(req.parameters[:uploadType]).to eq('multipart')
263
+ end
264
+
265
+ it 'should return a valid request with a body and media upload when using resource name' do
266
+ req = @drive.files.insert(:uploadType => 'multipart').file(@metadata).media(@media)
267
+ expect(req).to be_a(Google::APIClient::Service::Request)
268
+ expect(req.method.id).to eq('drive.files.insert')
269
+ expect(req.file).to eq(@metadata)
270
+ expect(req.media).to eq(@media)
271
+ expect(req.parameters).not_to be_nil
272
+ expect(req.parameters[:uploadType]).to eq('multipart')
273
+ end
274
+ end
275
+ end
276
+
277
+ describe 'with the Discovery API' do
278
+ it 'should make a valid end-to-end request' do
279
+ discovery = Google::APIClient::Service.new('discovery', 'v1',
280
+ {:application_name => APPLICATION_NAME, :authenticated => false,
281
+ :cache_store => nil})
282
+ result = discovery.apis.get_rest(:api => 'discovery', :version => 'v1').execute
283
+ expect(result).not_to be_nil
284
+ expect(result.data.name).to eq('discovery')
285
+ expect(result.data.version).to eq('v1')
286
+ end
287
+ end
288
+ end
289
+
290
+
291
+ RSpec.describe Google::APIClient::Service::Result do
292
+
293
+ describe 'with the plus API' do
294
+ before do
295
+ @plus = Google::APIClient::Service.new('plus', 'v1',
296
+ {:application_name => APPLICATION_NAME, :cache_store => nil})
297
+ @reference = Google::APIClient::Reference.new({
298
+ :api_method => @plus.activities.list.method,
299
+ :parameters => {
300
+ 'userId' => 'me',
301
+ 'collection' => 'public',
302
+ 'maxResults' => 20
303
+ }
304
+ })
305
+ @request = @plus.activities.list(:userId => 'me', :collection => 'public',
306
+ :maxResults => 20)
307
+
308
+ # Response double
309
+ @response = double("response")
310
+ allow(@response).to receive(:status).and_return(200)
311
+ allow(@response).to receive(:headers).and_return({
312
+ 'etag' => '12345',
313
+ 'x-google-apiary-auth-scopes' =>
314
+ 'https://www.googleapis.com/auth/plus.me',
315
+ 'content-type' => 'application/json; charset=UTF-8',
316
+ 'date' => 'Mon, 23 Apr 2012 00:00:00 GMT',
317
+ 'cache-control' => 'private, max-age=0, must-revalidate, no-transform',
318
+ 'server' => 'GSE',
319
+ 'connection' => 'close'
320
+ })
321
+ end
322
+
323
+ describe 'with a next page token' do
324
+ before do
325
+ @body = <<-END_OF_STRING
326
+ {
327
+ "kind": "plus#activityFeed",
328
+ "etag": "FOO",
329
+ "nextPageToken": "NEXT+PAGE+TOKEN",
330
+ "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
331
+ "nextLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN",
332
+ "title": "Plus Public Activity Feed for ",
333
+ "updated": "2012-04-23T00:00:00.000Z",
334
+ "id": "123456790",
335
+ "items": []
336
+ }
337
+ END_OF_STRING
338
+ allow(@response).to receive(:body).and_return(@body)
339
+ base_result = Google::APIClient::Result.new(@reference, @response)
340
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
341
+ end
342
+
343
+ it 'should indicate a successful response' do
344
+ expect(@result.error?).to be_falsey
345
+ end
346
+
347
+ it 'should return the correct next page token' do
348
+ expect(@result.next_page_token).to eq('NEXT+PAGE+TOKEN')
349
+ end
350
+
351
+ it 'generate a correct request when calling next_page' do
352
+ next_page_request = @result.next_page
353
+ expect(next_page_request.parameters).to include('pageToken')
354
+ expect(next_page_request.parameters['pageToken']).to eq('NEXT+PAGE+TOKEN')
355
+ @request.parameters.each_pair do |param, value|
356
+ expect(next_page_request.parameters[param]).to eq(value)
357
+ end
358
+ end
359
+
360
+ it 'should return content type correctly' do
361
+ expect(@result.media_type).to eq('application/json')
362
+ end
363
+
364
+ it 'should return the body correctly' do
365
+ expect(@result.body).to eq(@body)
366
+ end
367
+
368
+ it 'should return the result data correctly' do
369
+ expect(@result.data?).to be_truthy
370
+ expect(@result.data.class.to_s).to eq(
371
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
372
+ )
373
+ expect(@result.data.kind).to eq('plus#activityFeed')
374
+ expect(@result.data.etag).to eq('FOO')
375
+ expect(@result.data.nextPageToken).to eq('NEXT+PAGE+TOKEN')
376
+ expect(@result.data.selfLink).to eq(
377
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
378
+ )
379
+ expect(@result.data.nextLink).to eq(
380
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?' +
381
+ 'maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN'
382
+ )
383
+ expect(@result.data.title).to eq('Plus Public Activity Feed for ')
384
+ expect(@result.data.id).to eq("123456790")
385
+ expect(@result.data.items).to be_empty
386
+ end
387
+ end
388
+
389
+ describe 'without a next page token' do
390
+ before do
391
+ @body = <<-END_OF_STRING
392
+ {
393
+ "kind": "plus#activityFeed",
394
+ "etag": "FOO",
395
+ "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
396
+ "title": "Plus Public Activity Feed for ",
397
+ "updated": "2012-04-23T00:00:00.000Z",
398
+ "id": "123456790",
399
+ "items": []
400
+ }
401
+ END_OF_STRING
402
+ allow(@response).to receive(:body).and_return(@body)
403
+ base_result = Google::APIClient::Result.new(@reference, @response)
404
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
405
+ end
406
+
407
+ it 'should not return a next page token' do
408
+ expect(@result.next_page_token).to eq(nil)
409
+ end
410
+
411
+ it 'should return content type correctly' do
412
+ expect(@result.media_type).to eq('application/json')
413
+ end
414
+
415
+ it 'should return the body correctly' do
416
+ expect(@result.body).to eq(@body)
417
+ end
418
+
419
+ it 'should return the result data correctly' do
420
+ expect(@result.data?).to be_truthy
421
+ expect(@result.data.class.to_s).to eq(
422
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
423
+ )
424
+ expect(@result.data.kind).to eq('plus#activityFeed')
425
+ expect(@result.data.etag).to eq('FOO')
426
+ expect(@result.data.selfLink).to eq(
427
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
428
+ )
429
+ expect(@result.data.title).to eq('Plus Public Activity Feed for ')
430
+ expect(@result.data.id).to eq("123456790")
431
+ expect(@result.data.items).to be_empty
432
+ end
433
+ end
434
+
435
+ describe 'with JSON error response' do
436
+ before do
437
+ @body = <<-END_OF_STRING
438
+ {
439
+ "error": {
440
+ "errors": [
441
+ {
442
+ "domain": "global",
443
+ "reason": "parseError",
444
+ "message": "Parse Error"
445
+ }
446
+ ],
447
+ "code": 400,
448
+ "message": "Parse Error"
449
+ }
450
+ }
451
+ END_OF_STRING
452
+ allow(@response).to receive(:body).and_return(@body)
453
+ allow(@response).to receive(:status).and_return(400)
454
+ base_result = Google::APIClient::Result.new(@reference, @response)
455
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
456
+ end
457
+
458
+ it 'should return error status correctly' do
459
+ expect(@result.error?).to be_truthy
460
+ end
461
+
462
+ it 'should return the correct error message' do
463
+ expect(@result.error_message).to eq('Parse Error')
464
+ end
465
+
466
+ it 'should return the body correctly' do
467
+ expect(@result.body).to eq(@body)
468
+ end
469
+ end
470
+
471
+ describe 'with 204 No Content response' do
472
+ before do
473
+ allow(@response).to receive(:body).and_return('')
474
+ allow(@response).to receive(:status).and_return(204)
475
+ allow(@response).to receive(:headers).and_return({})
476
+ base_result = Google::APIClient::Result.new(@reference, @response)
477
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
478
+ end
479
+
480
+ it 'should indicate no data is available' do
481
+ expect(@result.data?).to be_falsey
482
+ end
483
+
484
+ it 'should return nil for data' do
485
+ expect(@result.data).to eq(nil)
486
+ end
487
+
488
+ it 'should return nil for media_type' do
489
+ expect(@result.media_type).to eq(nil)
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ RSpec.describe Google::APIClient::Service::BatchRequest do
496
+
497
+ include ConnectionHelpers
498
+
499
+ context 'with a service connection' do
500
+ before do
501
+ @conn = stub_connection do |stub|
502
+ stub.post('/batch') do |env|
503
+ [500, {'Content-Type' => 'application/json'}, '{}']
504
+ end
505
+ end
506
+ @discovery = Google::APIClient::Service.new('discovery', 'v1',
507
+ {:application_name => APPLICATION_NAME, :authorization => nil,
508
+ :cache_store => nil, :connection => @conn})
509
+ @calls = [
510
+ @discovery.apis.get_rest(:api => 'plus', :version => 'v1'),
511
+ @discovery.apis.get_rest(:api => 'discovery', :version => 'v1')
512
+ ]
513
+ end
514
+
515
+ it 'should use the service connection' do
516
+ batch = @discovery.batch(@calls) do
517
+ end
518
+ batch.execute
519
+ @conn.verify
520
+ end
521
+ end
522
+
523
+ describe 'with the discovery API' do
524
+ before do
525
+ @discovery = Google::APIClient::Service.new('discovery', 'v1',
526
+ {:application_name => APPLICATION_NAME, :authorization => nil,
527
+ :cache_store => nil})
528
+ end
529
+
530
+ describe 'with two valid requests' do
531
+ before do
532
+ @calls = [
533
+ @discovery.apis.get_rest(:api => 'plus', :version => 'v1'),
534
+ @discovery.apis.get_rest(:api => 'discovery', :version => 'v1')
535
+ ]
536
+ end
537
+
538
+ it 'should execute both when using a global callback' do
539
+ block_called = 0
540
+ batch = @discovery.batch(@calls) do |result|
541
+ block_called += 1
542
+ expect(result.status).to eq(200)
543
+ end
544
+
545
+ batch.execute
546
+ expect(block_called).to eq(2)
547
+ end
548
+
549
+ it 'should execute both when using individual callbacks' do
550
+ call1_returned, call2_returned = false, false
551
+ batch = @discovery.batch
552
+
553
+ batch.add(@calls[0]) do |result|
554
+ call1_returned = true
555
+ expect(result.status).to eq(200)
556
+ expect(result.call_index).to eq(0)
557
+ end
558
+
559
+ batch.add(@calls[1]) do |result|
560
+ call2_returned = true
561
+ expect(result.status).to eq(200)
562
+ expect(result.call_index).to eq(1)
563
+ end
564
+
565
+ batch.execute
566
+ expect(call1_returned).to eq(true)
567
+ expect(call2_returned).to eq(true)
568
+ end
569
+ end
570
+
571
+ describe 'with a valid request and an invalid one' do
572
+ before do
573
+ @calls = [
574
+ @discovery.apis.get_rest(:api => 'plus', :version => 'v1'),
575
+ @discovery.apis.get_rest(:api => 'invalid', :version => 'invalid')
576
+ ]
577
+ end
578
+
579
+ it 'should execute both when using a global callback' do
580
+ block_called = 0
581
+ batch = @discovery.batch(@calls) do |result|
582
+ block_called += 1
583
+ if result.call_index == 0
584
+ expect(result.status).to eq(200)
585
+ else
586
+ expect(result.status).to be >= 400
587
+ expect(result.status).to be < 500
588
+ end
589
+ end
590
+
591
+ batch.execute
592
+ expect(block_called).to eq(2)
593
+ end
594
+
595
+ it 'should execute both when using individual callbacks' do
596
+ call1_returned, call2_returned = false, false
597
+ batch = @discovery.batch
598
+
599
+ batch.add(@calls[0]) do |result|
600
+ call1_returned = true
601
+ expect(result.status).to eq(200)
602
+ expect(result.call_index).to eq(0)
603
+ end
604
+
605
+ batch.add(@calls[1]) do |result|
606
+ call2_returned = true
607
+ expect(result.status).to be >= 400
608
+ expect(result.status).to be < 500
609
+ expect(result.call_index).to eq(1)
610
+ end
611
+
612
+ batch.execute
613
+ expect(call1_returned).to eq(true)
614
+ expect(call2_returned).to eq(true)
615
+ end
616
+ end
617
+ end
618
+ end