jomz-google-api-client 0.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 (63) hide show
  1. data/CHANGELOG.md +144 -0
  2. data/CONTRIBUTING.md +32 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE +202 -0
  5. data/README.md +192 -0
  6. data/Rakefile +46 -0
  7. data/lib/cacerts.pem +2183 -0
  8. data/lib/compat/multi_json.rb +16 -0
  9. data/lib/google/api_client.rb +672 -0
  10. data/lib/google/api_client/auth/compute_service_account.rb +28 -0
  11. data/lib/google/api_client/auth/file_storage.rb +87 -0
  12. data/lib/google/api_client/auth/installed_app.rb +122 -0
  13. data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
  14. data/lib/google/api_client/auth/key_utils.rb +93 -0
  15. data/lib/google/api_client/auth/pkcs12.rb +41 -0
  16. data/lib/google/api_client/batch.rb +323 -0
  17. data/lib/google/api_client/client_secrets.rb +176 -0
  18. data/lib/google/api_client/discovery.rb +19 -0
  19. data/lib/google/api_client/discovery/api.rb +300 -0
  20. data/lib/google/api_client/discovery/media.rb +77 -0
  21. data/lib/google/api_client/discovery/method.rb +363 -0
  22. data/lib/google/api_client/discovery/resource.rb +156 -0
  23. data/lib/google/api_client/discovery/schema.rb +121 -0
  24. data/lib/google/api_client/environment.rb +42 -0
  25. data/lib/google/api_client/errors.rb +60 -0
  26. data/lib/google/api_client/gzip.rb +28 -0
  27. data/lib/google/api_client/logging.rb +32 -0
  28. data/lib/google/api_client/media.rb +259 -0
  29. data/lib/google/api_client/railtie.rb +16 -0
  30. data/lib/google/api_client/reference.rb +27 -0
  31. data/lib/google/api_client/request.rb +351 -0
  32. data/lib/google/api_client/result.rb +253 -0
  33. data/lib/google/api_client/service.rb +233 -0
  34. data/lib/google/api_client/service/batch.rb +103 -0
  35. data/lib/google/api_client/service/request.rb +144 -0
  36. data/lib/google/api_client/service/resource.rb +40 -0
  37. data/lib/google/api_client/service/result.rb +162 -0
  38. data/lib/google/api_client/service/simple_file_store.rb +151 -0
  39. data/lib/google/api_client/service/stub_generator.rb +59 -0
  40. data/lib/google/api_client/service_account.rb +18 -0
  41. data/lib/google/api_client/version.rb +31 -0
  42. data/lib/google/inflection.rb +28 -0
  43. data/spec/fixtures/files/privatekey.p12 +0 -0
  44. data/spec/fixtures/files/sample.txt +33 -0
  45. data/spec/fixtures/files/secret.pem +19 -0
  46. data/spec/google/api_client/batch_spec.rb +249 -0
  47. data/spec/google/api_client/discovery_spec.rb +652 -0
  48. data/spec/google/api_client/gzip_spec.rb +86 -0
  49. data/spec/google/api_client/media_spec.rb +179 -0
  50. data/spec/google/api_client/request_spec.rb +30 -0
  51. data/spec/google/api_client/result_spec.rb +203 -0
  52. data/spec/google/api_client/service_account_spec.rb +164 -0
  53. data/spec/google/api_client/service_spec.rb +586 -0
  54. data/spec/google/api_client/simple_file_store_spec.rb +137 -0
  55. data/spec/google/api_client_spec.rb +253 -0
  56. data/spec/spec_helper.rb +56 -0
  57. data/tasks/gem.rake +97 -0
  58. data/tasks/git.rake +45 -0
  59. data/tasks/metrics.rake +22 -0
  60. data/tasks/spec.rake +57 -0
  61. data/tasks/wiki.rake +82 -0
  62. data/tasks/yard.rake +29 -0
  63. metadata +309 -0
@@ -0,0 +1,164 @@
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
+ describe Google::APIClient::KeyUtils do
22
+ it 'should read PKCS12 files from the filesystem' do
23
+ pending "Reading from PKCS12 not supported on jruby" if RUBY_PLATFORM == 'java'
24
+ path = File.expand_path('files/privatekey.p12', fixtures_path)
25
+ key = Google::APIClient::KeyUtils.load_from_pkcs12(path, 'notasecret')
26
+ key.should_not == nil
27
+ end
28
+
29
+ it 'should read PKCS12 files from loaded files' do
30
+ pending "Reading from PKCS12 not supported on jruby" if RUBY_PLATFORM == 'java'
31
+ path = File.expand_path('files/privatekey.p12', fixtures_path)
32
+ content = File.read(path)
33
+ key = Google::APIClient::KeyUtils.load_from_pkcs12(content, 'notasecret')
34
+ key.should_not == nil
35
+ end
36
+
37
+ it 'should read PEM files from the filesystem' do
38
+ path = File.expand_path('files/secret.pem', fixtures_path)
39
+ key = Google::APIClient::KeyUtils.load_from_pem(path, 'notasecret')
40
+ key.should_not == nil
41
+ end
42
+
43
+ it 'should read PEM files from loaded files' do
44
+ path = File.expand_path('files/secret.pem', fixtures_path)
45
+ content = File.read(path)
46
+ key = Google::APIClient::KeyUtils.load_from_pem(content, 'notasecret')
47
+ key.should_not == nil
48
+ end
49
+
50
+ end
51
+
52
+ describe Google::APIClient::JWTAsserter do
53
+ include ConnectionHelpers
54
+
55
+ before do
56
+ @key = OpenSSL::PKey::RSA.new 2048
57
+ end
58
+
59
+ it 'should generate valid JWTs' do
60
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
61
+ jwt = asserter.to_authorization.to_jwt
62
+ jwt.should_not == nil
63
+
64
+ claim = JWT.decode(jwt, @key.public_key, true)
65
+ claim["iss"].should == 'client1'
66
+ claim["scope"].should == 'scope1 scope2'
67
+ end
68
+
69
+ it 'should allow impersonation' do
70
+ conn = stub_connection do |stub|
71
+ stub.post('/o/oauth2/token') do |env|
72
+ params = Addressable::URI.form_unencode(env[:body])
73
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
74
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
75
+ [200, {}, '{
76
+ "access_token" : "1/abcdef1234567890",
77
+ "token_type" : "Bearer",
78
+ "expires_in" : 3600
79
+ }']
80
+ end
81
+ end
82
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
83
+ auth = asserter.authorize('user1@email.com', { :connection => conn })
84
+ auth.should_not == nil?
85
+ auth.person.should == 'user1@email.com'
86
+ conn.verify
87
+ end
88
+
89
+ it 'should send valid access token request' do
90
+ conn = stub_connection do |stub|
91
+ stub.post('/o/oauth2/token') do |env|
92
+ params = Addressable::URI.form_unencode(env[:body])
93
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
94
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
95
+ [200, {}, '{
96
+ "access_token" : "1/abcdef1234567890",
97
+ "token_type" : "Bearer",
98
+ "expires_in" : 3600
99
+ }']
100
+ end
101
+ end
102
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
103
+ auth = asserter.authorize(nil, { :connection => conn })
104
+ auth.should_not == nil?
105
+ auth.access_token.should == "1/abcdef1234567890"
106
+ conn.verify
107
+ end
108
+
109
+ it 'should be refreshable' do
110
+ conn = stub_connection do |stub|
111
+ stub.post('/o/oauth2/token') do |env|
112
+ params = Addressable::URI.form_unencode(env[:body])
113
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
114
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
115
+ [200, {}, '{
116
+ "access_token" : "1/abcdef1234567890",
117
+ "token_type" : "Bearer",
118
+ "expires_in" : 3600
119
+ }']
120
+ end
121
+ stub.post('/o/oauth2/token') do |env|
122
+ params = Addressable::URI.form_unencode(env[:body])
123
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
124
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
125
+ [200, {}, '{
126
+ "access_token" : "1/0987654321fedcba",
127
+ "token_type" : "Bearer",
128
+ "expires_in" : 3600
129
+ }']
130
+ end
131
+ end
132
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
133
+ auth = asserter.authorize(nil, { :connection => conn })
134
+ auth.should_not == nil?
135
+ auth.access_token.should == "1/abcdef1234567890"
136
+
137
+ auth.fetch_access_token!(:connection => conn)
138
+ auth.access_token.should == "1/0987654321fedcba"
139
+
140
+ conn.verify
141
+ end
142
+ end
143
+
144
+ describe Google::APIClient::ComputeServiceAccount do
145
+ include ConnectionHelpers
146
+
147
+ it 'should query metadata server' do
148
+ conn = stub_connection do |stub|
149
+ stub.get('/computeMetadata/v1beta1/instance/service-accounts/default/token') do |env|
150
+ env.url.host.should == 'metadata'
151
+ [200, {}, '{
152
+ "access_token" : "1/abcdef1234567890",
153
+ "token_type" : "Bearer",
154
+ "expires_in" : 3600
155
+ }']
156
+ end
157
+ end
158
+ service_account = Google::APIClient::ComputeServiceAccount.new
159
+ auth = service_account.fetch_access_token!({ :connection => conn })
160
+ auth.should_not == nil?
161
+ auth["access_token"].should == "1/abcdef1234567890"
162
+ conn.verify
163
+ end
164
+ end
@@ -0,0 +1,586 @@
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
+ 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
+ (lambda do
31
+ Google::APIClient::Service.new
32
+ end).should raise_error(ArgumentError)
33
+ end
34
+
35
+ it 'should error out when called without an API version' do
36
+ (lambda do
37
+ Google::APIClient::Service.new('foo')
38
+ end).should raise_error(ArgumentError)
39
+ end
40
+
41
+ it 'should error out when the options hash is not a hash' do
42
+ (lambda do
43
+ Google::APIClient::Service.new('foo', 'v1', 42)
44
+ end).should 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
+ @adsense.accounts.should be_a(Google::APIClient::Service::Resource)
116
+ end
117
+
118
+ it 'should throw an error when using an invalid resource name' do
119
+ (lambda do
120
+ @adsense.invalid_resource
121
+ end).should raise_error
122
+ end
123
+
124
+ it 'should return a request when using a valid method name' do
125
+ req = @adsense.adclients.list
126
+ req.should be_a(Google::APIClient::Service::Request)
127
+ req.method.id.should == 'adsense.adclients.list'
128
+ req.parameters.should be_nil
129
+ end
130
+
131
+ it 'should throw an error when using an invalid method name' do
132
+ (lambda do
133
+ @adsense.adclients.invalid_method
134
+ end).should raise_error
135
+ end
136
+
137
+ it 'should return a valid request with parameters' do
138
+ req = @adsense.adunits.list(:adClientId => '1')
139
+ req.should be_a(Google::APIClient::Service::Request)
140
+ req.method.id.should == 'adsense.adunits.list'
141
+ req.parameters.should_not be_nil
142
+ req.parameters[:adClientId].should == '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
+ env.body.should == '{"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
+ env.body.should == '{"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
+ req.should be_a(Google::APIClient::Service::Request)
200
+ req.method.id.should == 'prediction.trainedmodels.insert'
201
+ req.body.should == {'id' => '1'}
202
+ req.parameters.should_not be_nil
203
+ req.parameters[:project].should == '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
+ req.should be_a(Google::APIClient::Service::Request)
209
+ req.method.id.should == 'prediction.trainedmodels.insert'
210
+ req.training.should == {'id' => '1'}
211
+ req.parameters.should_not be_nil
212
+ req.parameters[:project].should == '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/v1/files?uploadType=multipart') do |env|
231
+ env.body.should be_a Faraday::CompositeReadIO
232
+ [200, {}, '{}']
233
+ end
234
+ end
235
+ drive = Google::APIClient::Service.new(
236
+ 'drive',
237
+ 'v1',
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', 'v1',
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
+ req.should be_a(Google::APIClient::Service::Request)
258
+ req.method.id.should == 'drive.files.insert'
259
+ req.body.should == @metadata
260
+ req.media.should == @media
261
+ req.parameters.should_not be_nil
262
+ req.parameters[:uploadType].should == '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
+ req.should be_a(Google::APIClient::Service::Request)
268
+ req.method.id.should == 'drive.files.insert'
269
+ req.file.should == @metadata
270
+ req.media.should == @media
271
+ req.parameters.should_not be_nil
272
+ req.parameters[:uploadType].should == '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
+ result.should_not be_nil
284
+ result.data.name.should == 'discovery'
285
+ result.data.version.should == 'v1'
286
+ end
287
+ end
288
+ end
289
+
290
+
291
+ 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
+ @response.stub(:status).and_return(200)
311
+ @response.stub(: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
+ @response.stub(: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
+ @result.error?.should be_false
345
+ end
346
+
347
+ it 'should return the correct next page token' do
348
+ @result.next_page_token.should == '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
+ next_page_request.parameters.should include('pageToken')
354
+ next_page_request.parameters['pageToken'].should == 'NEXT+PAGE+TOKEN'
355
+ @request.parameters.each_pair do |param, value|
356
+ next_page_request.parameters[param].should == value
357
+ end
358
+ end
359
+
360
+ it 'should return content type correctly' do
361
+ @result.media_type.should == 'application/json'
362
+ end
363
+
364
+ it 'should return the body correctly' do
365
+ @result.body.should == @body
366
+ end
367
+
368
+ it 'should return the result data correctly' do
369
+ @result.data?.should be_true
370
+ @result.data.class.to_s.should ==
371
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
372
+ @result.data.kind.should == 'plus#activityFeed'
373
+ @result.data.etag.should == 'FOO'
374
+ @result.data.nextPageToken.should == 'NEXT+PAGE+TOKEN'
375
+ @result.data.selfLink.should ==
376
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
377
+ @result.data.nextLink.should ==
378
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?' +
379
+ 'maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN'
380
+ @result.data.title.should == 'Plus Public Activity Feed for '
381
+ @result.data.id.should == "123456790"
382
+ @result.data.items.should be_empty
383
+ end
384
+ end
385
+
386
+ describe 'without a next page token' do
387
+ before do
388
+ @body = <<-END_OF_STRING
389
+ {
390
+ "kind": "plus#activityFeed",
391
+ "etag": "FOO",
392
+ "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
393
+ "title": "Plus Public Activity Feed for ",
394
+ "updated": "2012-04-23T00:00:00.000Z",
395
+ "id": "123456790",
396
+ "items": []
397
+ }
398
+ END_OF_STRING
399
+ @response.stub(:body).and_return(@body)
400
+ base_result = Google::APIClient::Result.new(@reference, @response)
401
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
402
+ end
403
+
404
+ it 'should not return a next page token' do
405
+ @result.next_page_token.should == nil
406
+ end
407
+
408
+ it 'should return content type correctly' do
409
+ @result.media_type.should == 'application/json'
410
+ end
411
+
412
+ it 'should return the body correctly' do
413
+ @result.body.should == @body
414
+ end
415
+
416
+ it 'should return the result data correctly' do
417
+ @result.data?.should be_true
418
+ @result.data.class.to_s.should ==
419
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
420
+ @result.data.kind.should == 'plus#activityFeed'
421
+ @result.data.etag.should == 'FOO'
422
+ @result.data.selfLink.should ==
423
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
424
+ @result.data.title.should == 'Plus Public Activity Feed for '
425
+ @result.data.id.should == "123456790"
426
+ @result.data.items.should be_empty
427
+ end
428
+ end
429
+
430
+ describe 'with JSON error response' do
431
+ before do
432
+ @body = <<-END_OF_STRING
433
+ {
434
+ "error": {
435
+ "errors": [
436
+ {
437
+ "domain": "global",
438
+ "reason": "parseError",
439
+ "message": "Parse Error"
440
+ }
441
+ ],
442
+ "code": 400,
443
+ "message": "Parse Error"
444
+ }
445
+ }
446
+ END_OF_STRING
447
+ @response.stub(:body).and_return(@body)
448
+ @response.stub(:status).and_return(400)
449
+ base_result = Google::APIClient::Result.new(@reference, @response)
450
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
451
+ end
452
+
453
+ it 'should return error status correctly' do
454
+ @result.error?.should be_true
455
+ end
456
+
457
+ it 'should return the correct error message' do
458
+ @result.error_message.should == 'Parse Error'
459
+ end
460
+
461
+ it 'should return the body correctly' do
462
+ @result.body.should == @body
463
+ end
464
+ end
465
+
466
+ describe 'with 204 No Content response' do
467
+ before do
468
+ @response.stub(:body).and_return('')
469
+ @response.stub(:status).and_return(204)
470
+ @response.stub(:headers).and_return({})
471
+ base_result = Google::APIClient::Result.new(@reference, @response)
472
+ @result = Google::APIClient::Service::Result.new(@request, base_result)
473
+ end
474
+
475
+ it 'should indicate no data is available' do
476
+ @result.data?.should be_false
477
+ end
478
+
479
+ it 'should return nil for data' do
480
+ @result.data.should == nil
481
+ end
482
+
483
+ it 'should return nil for media_type' do
484
+ @result.media_type.should == nil
485
+ end
486
+ end
487
+ end
488
+ end
489
+
490
+ describe Google::APIClient::Service::BatchRequest do
491
+ describe 'with the discovery API' do
492
+ before do
493
+ @discovery = Google::APIClient::Service.new('discovery', 'v1',
494
+ {:application_name => APPLICATION_NAME, :authorization => nil,
495
+ :cache_store => nil})
496
+ end
497
+
498
+ describe 'with two valid requests' do
499
+ before do
500
+ @calls = [
501
+ @discovery.apis.get_rest(:api => 'plus', :version => 'v1'),
502
+ @discovery.apis.get_rest(:api => 'discovery', :version => 'v1')
503
+ ]
504
+ end
505
+
506
+ it 'should execute both when using a global callback' do
507
+ block_called = 0
508
+ batch = @discovery.batch(@calls) do |result|
509
+ block_called += 1
510
+ result.status.should == 200
511
+ end
512
+
513
+ batch.execute
514
+ block_called.should == 2
515
+ end
516
+
517
+ it 'should execute both when using individual callbacks' do
518
+ call1_returned, call2_returned = false, false
519
+ batch = @discovery.batch
520
+
521
+ batch.add(@calls[0]) do |result|
522
+ call1_returned = true
523
+ result.status.should == 200
524
+ result.call_index.should == 0
525
+ end
526
+
527
+ batch.add(@calls[1]) do |result|
528
+ call2_returned = true
529
+ result.status.should == 200
530
+ result.call_index.should == 1
531
+ end
532
+
533
+ batch.execute
534
+ call1_returned.should == true
535
+ call2_returned.should == true
536
+ end
537
+ end
538
+
539
+ describe 'with a valid request and an invalid one' do
540
+ before do
541
+ @calls = [
542
+ @discovery.apis.get_rest(:api => 'plus', :version => 'v1'),
543
+ @discovery.apis.get_rest(:api => 'invalid', :version => 'invalid')
544
+ ]
545
+ end
546
+
547
+ it 'should execute both when using a global callback' do
548
+ block_called = 0
549
+ batch = @discovery.batch(@calls) do |result|
550
+ block_called += 1
551
+ if result.call_index == 0
552
+ result.status.should == 200
553
+ else
554
+ result.status.should >= 400
555
+ result.status.should < 500
556
+ end
557
+ end
558
+
559
+ batch.execute
560
+ block_called.should == 2
561
+ end
562
+
563
+ it 'should execute both when using individual callbacks' do
564
+ call1_returned, call2_returned = false, false
565
+ batch = @discovery.batch
566
+
567
+ batch.add(@calls[0]) do |result|
568
+ call1_returned = true
569
+ result.status.should == 200
570
+ result.call_index.should == 0
571
+ end
572
+
573
+ batch.add(@calls[1]) do |result|
574
+ call2_returned = true
575
+ result.status.should >= 400
576
+ result.status.should < 500
577
+ result.call_index.should == 1
578
+ end
579
+
580
+ batch.execute
581
+ call1_returned.should == true
582
+ call2_returned.should == true
583
+ end
584
+ end
585
+ end
586
+ end