google-api-client 0.7.0.rc2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -2
- data/Gemfile +10 -1
- data/README.md +11 -1
- data/Rakefile +1 -1
- data/lib/google/api_client.rb +54 -33
- data/lib/google/api_client/errors.rb +11 -0
- data/lib/google/api_client/request.rb +1 -0
- data/lib/google/api_client/service.rb +233 -0
- data/lib/google/api_client/service/batch.rb +103 -0
- data/lib/google/api_client/service/request.rb +144 -0
- data/lib/google/api_client/service/resource.rb +40 -0
- data/lib/google/api_client/service/result.rb +162 -0
- data/lib/google/api_client/service/simple_file_store.rb +151 -0
- data/lib/google/api_client/service/stub_generator.rb +59 -0
- data/lib/google/api_client/version.rb +1 -1
- data/spec/google/api_client/batch_spec.rb +3 -3
- data/spec/google/api_client/discovery_spec.rb +24 -7
- data/spec/google/api_client/service_spec.rb +586 -0
- data/spec/google/api_client/simple_file_store_spec.rb +137 -0
- data/spec/google/api_client_spec.rb +84 -0
- data/tasks/gem.rake +1 -2
- metadata +17 -10
- data/bin/google-api +0 -390
@@ -0,0 +1,151 @@
|
|
1
|
+
# Copyright 2013 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
|
+
module Google
|
16
|
+
class APIClient
|
17
|
+
class Service
|
18
|
+
|
19
|
+
# Simple file store to be used in the event no ActiveSupport cache store
|
20
|
+
# is provided. This is not thread-safe, and does not support a number of
|
21
|
+
# features (such as expiration), but it's useful for the simple purpose of
|
22
|
+
# caching discovery documents to disk.
|
23
|
+
# Implements the basic cache methods of ActiveSupport::Cache::Store in a
|
24
|
+
# limited fashion.
|
25
|
+
class SimpleFileStore
|
26
|
+
|
27
|
+
# Creates a new SimpleFileStore.
|
28
|
+
#
|
29
|
+
# @param [String] file_path
|
30
|
+
# The path to the cache file on disk.
|
31
|
+
# @param [Object] options
|
32
|
+
# The options to be used with this SimpleFileStore. Not implemented.
|
33
|
+
def initialize(file_path, options = nil)
|
34
|
+
@file_path = file_path.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns true if a key exists in the cache.
|
38
|
+
#
|
39
|
+
# @param [String] name
|
40
|
+
# The name of the key. Will always be converted to a string.
|
41
|
+
# @param [Object] options
|
42
|
+
# The options to be used with this query. Not implemented.
|
43
|
+
def exist?(name, options = nil)
|
44
|
+
read_file
|
45
|
+
@cache.nil? ? nil : @cache.include?(name.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fetches data from the cache and returns it, using the given key.
|
49
|
+
# If the key is missing and no block is passed, returns nil.
|
50
|
+
# If the key is missing and a block is passed, executes the block, sets
|
51
|
+
# the key to its value, and returns it.
|
52
|
+
#
|
53
|
+
# @param [String] name
|
54
|
+
# The name of the key. Will always be converted to a string.
|
55
|
+
# @param [Object] options
|
56
|
+
# The options to be used with this query. Not implemented.
|
57
|
+
# @yield [String]
|
58
|
+
# optional block with the default value if the key is missing
|
59
|
+
def fetch(name, options = nil)
|
60
|
+
read_file
|
61
|
+
if block_given?
|
62
|
+
entry = read(name.to_s, options)
|
63
|
+
if entry.nil?
|
64
|
+
value = yield name.to_s
|
65
|
+
write(name.to_s, value)
|
66
|
+
return value
|
67
|
+
else
|
68
|
+
return entry
|
69
|
+
end
|
70
|
+
else
|
71
|
+
return read(name.to_s, options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Fetches data from the cache, using the given key.
|
76
|
+
# Returns nil if the key is missing.
|
77
|
+
#
|
78
|
+
# @param [String] name
|
79
|
+
# The name of the key. Will always be converted to a string.
|
80
|
+
# @param [Object] options
|
81
|
+
# The options to be used with this query. Not implemented.
|
82
|
+
def read(name, options = nil)
|
83
|
+
read_file
|
84
|
+
@cache.nil? ? nil : @cache[name.to_s]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Writes the value to the cache, with the key.
|
88
|
+
#
|
89
|
+
# @param [String] name
|
90
|
+
# The name of the key. Will always be converted to a string.
|
91
|
+
# @param [Object] value
|
92
|
+
# The value to be written.
|
93
|
+
# @param [Object] options
|
94
|
+
# The options to be used with this query. Not implemented.
|
95
|
+
def write(name, value, options = nil)
|
96
|
+
read_file
|
97
|
+
@cache = {} if @cache.nil?
|
98
|
+
@cache[name.to_s] = value
|
99
|
+
write_file
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
# Deletes an entry in the cache.
|
104
|
+
# Returns true if an entry is deleted.
|
105
|
+
#
|
106
|
+
# @param [String] name
|
107
|
+
# The name of the key. Will always be converted to a string.
|
108
|
+
# @param [Object] options
|
109
|
+
# The options to be used with this query. Not implemented.
|
110
|
+
def delete(name, options = nil)
|
111
|
+
read_file
|
112
|
+
return nil if @cache.nil?
|
113
|
+
if @cache.include? name.to_s
|
114
|
+
@cache.delete name.to_s
|
115
|
+
write_file
|
116
|
+
return true
|
117
|
+
else
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
# Read the entire cache file from disk.
|
125
|
+
# Will avoid reading if there have been no changes.
|
126
|
+
def read_file
|
127
|
+
if !File.exists? @file_path
|
128
|
+
@cache = nil
|
129
|
+
else
|
130
|
+
# Check for changes after our last read or write.
|
131
|
+
if @last_change.nil? || File.mtime(@file_path) > @last_change
|
132
|
+
File.open(@file_path) do |file|
|
133
|
+
@cache = Marshal.load(file)
|
134
|
+
@last_change = file.mtime
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
return @cache
|
139
|
+
end
|
140
|
+
|
141
|
+
# Write the entire cache contents to disk.
|
142
|
+
def write_file
|
143
|
+
File.open(@file_path, 'w') do |file|
|
144
|
+
Marshal.dump(@cache, file)
|
145
|
+
end
|
146
|
+
@last_change = File.mtime(@file_path)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright 2013 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
|
+
module Google
|
16
|
+
class APIClient
|
17
|
+
class Service
|
18
|
+
##
|
19
|
+
# Auxiliary mixin to generate resource and method stubs.
|
20
|
+
# Used by the Service and Service::Resource classes to generate both
|
21
|
+
# top-level and nested resources and methods.
|
22
|
+
module StubGenerator
|
23
|
+
def generate_call_stubs(service, root)
|
24
|
+
metaclass = (class << self; self; end)
|
25
|
+
|
26
|
+
# Handle resources.
|
27
|
+
root.discovered_resources.each do |resource|
|
28
|
+
method_name = Google::INFLECTOR.underscore(resource.name).to_sym
|
29
|
+
if !self.respond_to?(method_name)
|
30
|
+
metaclass.send(:define_method, method_name) do
|
31
|
+
Google::APIClient::Service::Resource.new(service, resource)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Handle methods.
|
37
|
+
root.discovered_methods.each do |method|
|
38
|
+
method_name = Google::INFLECTOR.underscore(method.name).to_sym
|
39
|
+
if !self.respond_to?(method_name)
|
40
|
+
metaclass.send(:define_method, method_name) do |*args|
|
41
|
+
if args.length > 1
|
42
|
+
raise ArgumentError,
|
43
|
+
"wrong number of arguments (#{args.length} for 1)"
|
44
|
+
elsif !args.first.respond_to?(:to_hash) && !args.first.nil?
|
45
|
+
raise ArgumentError,
|
46
|
+
"expected parameter Hash, got #{args.first.class}"
|
47
|
+
else
|
48
|
+
return Google::APIClient::Service::Request.new(
|
49
|
+
service, method, args.first
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -53,7 +53,7 @@ describe Google::APIClient::BatchRequest do
|
|
53
53
|
@call1 = {
|
54
54
|
:api_method => @discovery.apis.get_rest,
|
55
55
|
:parameters => {
|
56
|
-
'api' => '
|
56
|
+
'api' => 'plus',
|
57
57
|
'version' => 'v1'
|
58
58
|
}
|
59
59
|
}
|
@@ -118,7 +118,7 @@ describe Google::APIClient::BatchRequest do
|
|
118
118
|
@call1 = {
|
119
119
|
:api_method => @discovery.apis.get_rest,
|
120
120
|
:parameters => {
|
121
|
-
'api' => '
|
121
|
+
'api' => 'plus',
|
122
122
|
'version' => 'v1'
|
123
123
|
}
|
124
124
|
}
|
@@ -244,6 +244,6 @@ describe Google::APIClient::BatchRequest do
|
|
244
244
|
#request[:body].read.gsub("\r", "").should =~ expected_body
|
245
245
|
end
|
246
246
|
end
|
247
|
-
|
247
|
+
|
248
248
|
end
|
249
249
|
end
|
@@ -86,9 +86,10 @@ describe Google::APIClient do
|
|
86
86
|
|
87
87
|
it 'should correctly determine the discovery URI if :user_ip is set' do
|
88
88
|
CLIENT.user_ip = '127.0.0.1'
|
89
|
-
|
89
|
+
|
90
90
|
conn = stub_connection do |stub|
|
91
91
|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?userIp=127.0.0.1') do |env|
|
92
|
+
[200, {}, '{}']
|
92
93
|
end
|
93
94
|
end
|
94
95
|
CLIENT.execute(
|
@@ -104,6 +105,7 @@ describe Google::APIClient do
|
|
104
105
|
CLIENT.key = 'qwerty'
|
105
106
|
conn = stub_connection do |stub|
|
106
107
|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty') do |env|
|
108
|
+
[200, {}, '{}']
|
107
109
|
end
|
108
110
|
end
|
109
111
|
request = CLIENT.execute(
|
@@ -120,6 +122,7 @@ describe Google::APIClient do
|
|
120
122
|
CLIENT.user_ip = '127.0.0.1'
|
121
123
|
conn = stub_connection do |stub|
|
122
124
|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty&userIp=127.0.0.1') do |env|
|
125
|
+
[200, {}, '{}']
|
123
126
|
end
|
124
127
|
end
|
125
128
|
request = CLIENT.execute(
|
@@ -187,6 +190,7 @@ describe Google::APIClient do
|
|
187
190
|
conn = stub_connection do |stub|
|
188
191
|
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
189
192
|
env[:body].should == ''
|
193
|
+
[200, {}, '{}']
|
190
194
|
end
|
191
195
|
end
|
192
196
|
request = CLIENT.execute(
|
@@ -199,11 +203,12 @@ describe Google::APIClient do
|
|
199
203
|
|
200
204
|
it 'should generate valid requests when parameter value includes semicolon' do
|
201
205
|
conn = stub_connection do |stub|
|
202
|
-
# semicolon (;) in parameter value was being converted to
|
203
|
-
# bare ampersand (&) in 0.4.7. ensure that it gets converted
|
206
|
+
# semicolon (;) in parameter value was being converted to
|
207
|
+
# bare ampersand (&) in 0.4.7. ensure that it gets converted
|
204
208
|
# to a CGI-escaped semicolon (%3B) instead.
|
205
209
|
stub.post('/prediction/v1.2/training?data=12345%3B67890') do |env|
|
206
210
|
env[:body].should == ''
|
211
|
+
[200, {}, '{}']
|
207
212
|
end
|
208
213
|
end
|
209
214
|
request = CLIENT.execute(
|
@@ -218,6 +223,7 @@ describe Google::APIClient do
|
|
218
223
|
conn = stub_connection do |stub|
|
219
224
|
stub.post('/prediction/v1.2/training?data=1&data=2') do |env|
|
220
225
|
env.params['data'].should include('1', '2')
|
226
|
+
[200, {}, '{}']
|
221
227
|
end
|
222
228
|
end
|
223
229
|
request = CLIENT.execute(
|
@@ -231,6 +237,7 @@ describe Google::APIClient do
|
|
231
237
|
it 'should generate requests against the correct URIs' do
|
232
238
|
conn = stub_connection do |stub|
|
233
239
|
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
240
|
+
[200, {}, '{}']
|
234
241
|
end
|
235
242
|
end
|
236
243
|
request = CLIENT.execute(
|
@@ -244,6 +251,7 @@ describe Google::APIClient do
|
|
244
251
|
it 'should generate requests against the correct URIs' do
|
245
252
|
conn = stub_connection do |stub|
|
246
253
|
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
254
|
+
[200, {}, '{}']
|
247
255
|
end
|
248
256
|
end
|
249
257
|
request = CLIENT.execute(
|
@@ -264,9 +272,10 @@ describe Google::APIClient do
|
|
264
272
|
conn = stub_connection do |stub|
|
265
273
|
stub.post('/prediction/v1.2/training') do |env|
|
266
274
|
env[:url].host.should == 'testing-domain.example.com'
|
275
|
+
[200, {}, '{}']
|
267
276
|
end
|
268
277
|
end
|
269
|
-
|
278
|
+
|
270
279
|
request = CLIENT.execute(
|
271
280
|
:api_method => prediction_rebase.training.insert,
|
272
281
|
:parameters => {'data' => '123'},
|
@@ -284,6 +293,7 @@ describe Google::APIClient do
|
|
284
293
|
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
285
294
|
env[:request_headers].should have_key('Authorization')
|
286
295
|
env[:request_headers]['Authorization'].should =~ /^OAuth/
|
296
|
+
[200, {}, '{}']
|
287
297
|
end
|
288
298
|
end
|
289
299
|
|
@@ -303,6 +313,7 @@ describe Google::APIClient do
|
|
303
313
|
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
304
314
|
env[:request_headers].should have_key('Authorization')
|
305
315
|
env[:request_headers]['Authorization'].should =~ /^Bearer/
|
316
|
+
[200, {}, '{}']
|
306
317
|
end
|
307
318
|
end
|
308
319
|
|
@@ -363,6 +374,7 @@ describe Google::APIClient do
|
|
363
374
|
stub.post('/prediction/v1.2/training') do |env|
|
364
375
|
env[:request_headers].should have_key('Content-Type')
|
365
376
|
env[:request_headers]['Content-Type'].should == 'application/json'
|
377
|
+
[200, {}, '{}']
|
366
378
|
end
|
367
379
|
end
|
368
380
|
CLIENT.authorization = :oauth_2
|
@@ -415,9 +427,10 @@ describe Google::APIClient do
|
|
415
427
|
it 'should generate requests against the correct URIs' do
|
416
428
|
conn = stub_connection do |stub|
|
417
429
|
stub.get('/plus/v1/people/107807692475771887386/activities/public') do |env|
|
430
|
+
[200, {}, '{}']
|
418
431
|
end
|
419
432
|
end
|
420
|
-
|
433
|
+
|
421
434
|
request = CLIENT.execute(
|
422
435
|
:api_method => @plus.activities.list,
|
423
436
|
:parameters => {
|
@@ -474,17 +487,18 @@ describe Google::APIClient do
|
|
474
487
|
|
475
488
|
it 'should find methods that are in the discovery document' do
|
476
489
|
CLIENT.discovered_method(
|
477
|
-
'adsense.reports.generate', 'adsense'
|
490
|
+
'adsense.reports.generate', 'adsense', 'v1.3'
|
478
491
|
).name.should == 'generate'
|
479
492
|
end
|
480
493
|
|
481
494
|
it 'should not find methods that are not in the discovery document' do
|
482
|
-
CLIENT.discovered_method('adsense.bogus', 'adsense').should == nil
|
495
|
+
CLIENT.discovered_method('adsense.bogus', 'adsense', 'v1.3').should == nil
|
483
496
|
end
|
484
497
|
|
485
498
|
it 'should generate requests against the correct URIs' do
|
486
499
|
conn = stub_connection do |stub|
|
487
500
|
stub.get('/adsense/v1.3/adclients') do |env|
|
501
|
+
[200, {}, '{}']
|
488
502
|
end
|
489
503
|
end
|
490
504
|
request = CLIENT.execute(
|
@@ -515,6 +529,7 @@ describe Google::APIClient do
|
|
515
529
|
it 'should succeed when validating parameters in a correct call' do
|
516
530
|
conn = stub_connection do |stub|
|
517
531
|
stub.get('/adsense/v1.3/reports?dimension=DATE&endDate=2010-01-01&metric=PAGE_VIEWS&startDate=2000-01-01') do |env|
|
532
|
+
[200, {}, '{}']
|
518
533
|
end
|
519
534
|
end
|
520
535
|
(lambda do
|
@@ -553,6 +568,7 @@ describe Google::APIClient do
|
|
553
568
|
stub.get('/adsense/v1.3/reports?dimension=DATE&dimension=PRODUCT_CODE'+
|
554
569
|
'&endDate=2010-01-01&metric=CLICKS&metric=PAGE_VIEWS&'+
|
555
570
|
'startDate=2000-01-01') do |env|
|
571
|
+
[200, {}, '{}']
|
556
572
|
end
|
557
573
|
end
|
558
574
|
(lambda do
|
@@ -593,6 +609,7 @@ describe Google::APIClient do
|
|
593
609
|
'startDate=2000-01-01') do |env|
|
594
610
|
env.params['dimension'].should include('DATE', 'PRODUCT_CODE')
|
595
611
|
env.params['metric'].should include('CLICKS', 'PAGE_VIEWS')
|
612
|
+
[200, {}, '{}']
|
596
613
|
end
|
597
614
|
end
|
598
615
|
request = CLIENT.execute(
|
@@ -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
|