Merge pull request #94 from programmiersportgruppe/master
[arvados.git] / spec / google / api_client / discovery_spec.rb
1 # encoding:utf-8
2
3 # Copyright 2010 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
18 require 'spec_helper'
19
20 require 'faraday'
21 require 'multi_json'
22 require 'compat/multi_json'
23 require 'signet/oauth_1/client'
24 require 'google/api_client'
25 require 'google/api_client/version'
26
27 describe Google::APIClient do
28   include ConnectionHelpers
29   CLIENT = Google::APIClient.new(:application_name => 'API Client Tests') unless defined?(CLIENT)
30
31   after do
32     # Reset client to not-quite-pristine state
33     CLIENT.key = nil
34     CLIENT.user_ip = nil
35   end
36
37   it 'should raise a type error for bogus authorization' do
38     expect(lambda do
39       Google::APIClient.new(:application_name => 'API Client Tests', :authorization => 42)
40     end).to raise_error(TypeError)
41   end
42
43   it 'should not be able to retrieve the discovery document for a bogus API' do
44     expect(lambda do
45       CLIENT.discovery_document('bogus')
46     end).to raise_error(Google::APIClient::TransmissionError)
47     expect(lambda do
48       CLIENT.discovered_api('bogus')
49     end).to raise_error(Google::APIClient::TransmissionError)
50   end
51
52   it 'should raise an error for bogus services' do
53     expect(lambda do
54       CLIENT.discovered_api(42)
55     end).to raise_error(TypeError)
56   end
57
58   it 'should raise an error for bogus services' do
59     expect(lambda do
60       CLIENT.preferred_version(42)
61     end).to raise_error(TypeError)
62   end
63
64   it 'should raise an error for bogus methods' do
65     expect(lambda do
66       CLIENT.execute(42)
67     end).to raise_error(TypeError)
68   end
69
70   it 'should not return a preferred version for bogus service names' do
71     expect(CLIENT.preferred_version('bogus')).to eq(nil)
72   end
73
74   describe 'with the prediction API' do
75     before do
76       CLIENT.authorization = nil
77       # The prediction API no longer exposes a v1, so we have to be
78       # careful about looking up the wrong API version.
79       @prediction = CLIENT.discovered_api('prediction', 'v1.2')
80     end
81
82     it 'should correctly determine the discovery URI' do
83       expect(CLIENT.discovery_uri('prediction')).to be ===
84         'https://www.googleapis.com/discovery/v1/apis/prediction/v1/rest'
85     end
86
87     it 'should correctly determine the discovery URI if :user_ip is set' do
88       CLIENT.user_ip = '127.0.0.1'
89
90       conn = stub_connection do |stub|
91         stub.get('/discovery/v1/apis/prediction/v1.2/rest?userIp=127.0.0.1') do |env|
92           [200, {}, '{}']
93         end
94       end
95       CLIENT.execute(
96         :http_method => 'GET',
97         :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
98         :authenticated => false,
99         :connection => conn
100       )
101       conn.verify
102     end
103
104     it 'should correctly determine the discovery URI if :key is set' do
105       CLIENT.key = 'qwerty'
106       conn = stub_connection do |stub|
107         stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty') do |env|
108           [200, {}, '{}']
109         end
110       end
111       request = CLIENT.execute(
112         :http_method => 'GET',
113         :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
114         :authenticated => false,
115         :connection => conn
116         )
117         conn.verify
118     end
119
120     it 'should correctly determine the discovery URI if both are set' do
121       CLIENT.key = 'qwerty'
122       CLIENT.user_ip = '127.0.0.1'
123       conn = stub_connection do |stub|
124         stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty&userIp=127.0.0.1') do |env|
125           [200, {}, '{}']
126         end
127       end
128       request = CLIENT.execute(
129         :http_method => 'GET',
130         :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
131         :authenticated => false,
132         :connection => conn
133         )
134         conn.verify
135     end
136
137     it 'should correctly generate API objects' do
138       expect(CLIENT.discovered_api('prediction', 'v1.2').name).to eq('prediction')
139       expect(CLIENT.discovered_api('prediction', 'v1.2').version).to eq('v1.2')
140       expect(CLIENT.discovered_api(:prediction, 'v1.2').name).to eq('prediction')
141       expect(CLIENT.discovered_api(:prediction, 'v1.2').version).to eq('v1.2')
142     end
143
144     it 'should discover methods' do
145       expect(CLIENT.discovered_method(
146         'prediction.training.insert', 'prediction', 'v1.2'
147       ).name).to eq('insert')
148       expect(CLIENT.discovered_method(
149         :'prediction.training.insert', :prediction, 'v1.2'
150       ).name).to eq('insert')
151       expect(CLIENT.discovered_method(
152         'prediction.training.delete', 'prediction', 'v1.2'
153       ).name).to eq('delete')
154     end
155
156     it 'should define the origin API in discovered methods' do
157       expect(CLIENT.discovered_method(
158         'prediction.training.insert', 'prediction', 'v1.2'
159       ).api.name).to eq('prediction')
160     end
161
162     it 'should not find methods that are not in the discovery document' do
163       expect(CLIENT.discovered_method(
164         'prediction.bogus', 'prediction', 'v1.2'
165       )).to eq(nil)
166     end
167
168     it 'should raise an error for bogus methods' do
169       expect(lambda do
170         CLIENT.discovered_method(42, 'prediction', 'v1.2')
171       end).to raise_error(TypeError)
172     end
173
174     it 'should raise an error for bogus methods' do
175       expect(lambda do
176         CLIENT.execute(:api_method => CLIENT.discovered_api('prediction', 'v1.2'))
177       end).to raise_error(TypeError)
178     end
179
180     it 'should correctly determine the preferred version' do
181       expect(CLIENT.preferred_version('prediction').version).not_to eq('v1')
182       expect(CLIENT.preferred_version(:prediction).version).not_to eq('v1')
183     end
184
185     it 'should return a batch path' do
186       expect(CLIENT.discovered_api('prediction', 'v1.2').batch_path).not_to be_nil
187     end
188
189     it 'should generate valid requests' do
190       conn = stub_connection do |stub|
191         stub.post('/prediction/v1.2/training?data=12345') do |env|
192           expect(env[:body]).to eq('')
193           [200, {}, '{}']
194         end
195       end
196       request = CLIENT.execute(
197         :api_method => @prediction.training.insert,
198         :parameters => {'data' => '12345'},
199         :connection => conn
200       )
201       conn.verify
202     end
203
204     it 'should generate valid requests when parameter value includes semicolon' do
205       conn = stub_connection do |stub|
206         # semicolon (;) in parameter value was being converted to
207         # bare ampersand (&) in 0.4.7. ensure that it gets converted
208         # to a CGI-escaped semicolon (%3B) instead.
209         stub.post('/prediction/v1.2/training?data=12345%3B67890') do |env|
210           expect(env[:body]).to eq('')
211           [200, {}, '{}']
212         end
213       end
214       request = CLIENT.execute(
215         :api_method => @prediction.training.insert,
216         :parameters => {'data' => '12345;67890'},
217         :connection => conn
218       )
219       conn.verify
220     end
221
222     it 'should generate valid requests when multivalued parameters are passed' do
223       conn = stub_connection do |stub|
224          stub.post('/prediction/v1.2/training?data=1&data=2') do |env|
225            expect(env.params['data']).to include('1', '2')
226           [200, {}, '{}']
227          end
228        end
229       request = CLIENT.execute(
230         :api_method => @prediction.training.insert,
231         :parameters => {'data' => ['1', '2']},
232         :connection => conn
233       )
234       conn.verify
235     end
236
237     it 'should generate requests against the correct URIs' do
238       conn = stub_connection do |stub|
239          stub.post('/prediction/v1.2/training?data=12345') do |env|
240           [200, {}, '{}']
241          end
242        end
243       request = CLIENT.execute(
244         :api_method => @prediction.training.insert,
245         :parameters => {'data' => '12345'},
246         :connection => conn
247       )
248       conn.verify
249     end
250
251     it 'should generate requests against the correct URIs' do
252       conn = stub_connection do |stub|
253         stub.post('/prediction/v1.2/training?data=12345') do |env|
254           [200, {}, '{}']
255         end
256       end
257       request = CLIENT.execute(
258         :api_method => @prediction.training.insert,
259         :parameters => {'data' => '12345'},
260         :connection => conn
261       )
262       conn.verify
263     end
264
265     it 'should allow modification to the base URIs for testing purposes' do
266       # Using a new client instance here to avoid caching rebased discovery doc
267       prediction_rebase =
268         Google::APIClient.new(:application_name => 'API Client Tests').discovered_api('prediction', 'v1.2')
269       prediction_rebase.method_base =
270         'https://testing-domain.example.com/prediction/v1.2/'
271
272       conn = stub_connection do |stub|
273         stub.post('/prediction/v1.2/training') do |env|
274           expect(env[:url].host).to eq('testing-domain.example.com')
275           [200, {}, '{}']          
276         end
277       end
278
279       request = CLIENT.execute(
280         :api_method => prediction_rebase.training.insert,
281         :parameters => {'data' => '123'},
282         :connection => conn
283       )
284       conn.verify
285     end
286
287     it 'should generate OAuth 1 requests' do
288       CLIENT.authorization = :oauth_1
289       CLIENT.authorization.token_credential_key = '12345'
290       CLIENT.authorization.token_credential_secret = '12345'
291
292       conn = stub_connection do |stub|
293         stub.post('/prediction/v1.2/training?data=12345') do |env|
294           expect(env[:request_headers]).to have_key('Authorization')
295           expect(env[:request_headers]['Authorization']).to match(/^OAuth/)
296           [200, {}, '{}']
297         end
298       end
299
300       request = CLIENT.execute(
301         :api_method => @prediction.training.insert,
302         :parameters => {'data' => '12345'},
303         :connection => conn
304       )
305       conn.verify
306     end
307
308     it 'should generate OAuth 2 requests' do
309       CLIENT.authorization = :oauth_2
310       CLIENT.authorization.access_token = '12345'
311
312       conn = stub_connection do |stub|
313         stub.post('/prediction/v1.2/training?data=12345') do |env|
314           expect(env[:request_headers]).to have_key('Authorization')
315           expect(env[:request_headers]['Authorization']).to match(/^Bearer/)
316           [200, {}, '{}']          
317         end
318       end
319
320       request = CLIENT.execute(
321         :api_method => @prediction.training.insert,
322         :parameters => {'data' => '12345'},
323         :connection => conn
324       )
325       conn.verify
326     end
327
328     it 'should not be able to execute improperly authorized requests' do
329       CLIENT.authorization = :oauth_1
330       CLIENT.authorization.token_credential_key = '12345'
331       CLIENT.authorization.token_credential_secret = '12345'
332       result = CLIENT.execute(
333         @prediction.training.insert,
334         {'data' => '12345'}
335       )
336       expect(result.response.status).to eq(401)
337     end
338
339     it 'should not be able to execute improperly authorized requests' do
340       CLIENT.authorization = :oauth_2
341       CLIENT.authorization.access_token = '12345'
342       result = CLIENT.execute(
343         @prediction.training.insert,
344         {'data' => '12345'}
345       )
346       expect(result.response.status).to eq(401)
347     end
348
349     it 'should not be able to execute improperly authorized requests' do
350       expect(lambda do
351         CLIENT.authorization = :oauth_1
352         CLIENT.authorization.token_credential_key = '12345'
353         CLIENT.authorization.token_credential_secret = '12345'
354         result = CLIENT.execute!(
355           @prediction.training.insert,
356           {'data' => '12345'}
357         )
358       end).to raise_error(Google::APIClient::ClientError)
359     end
360
361     it 'should not be able to execute improperly authorized requests' do
362       expect(lambda do
363         CLIENT.authorization = :oauth_2
364         CLIENT.authorization.access_token = '12345'
365         result = CLIENT.execute!(
366           @prediction.training.insert,
367           {'data' => '12345'}
368         )
369       end).to raise_error(Google::APIClient::ClientError)
370     end
371
372     it 'should correctly handle unnamed parameters' do
373       conn = stub_connection do |stub|
374         stub.post('/prediction/v1.2/training') do |env|
375           expect(env[:request_headers]).to have_key('Content-Type')
376           expect(env[:request_headers]['Content-Type']).to eq('application/json')
377           [200, {}, '{}']
378         end
379       end
380       CLIENT.authorization = :oauth_2
381       CLIENT.authorization.access_token = '12345'
382       CLIENT.execute(
383         :api_method => @prediction.training.insert,
384         :body => MultiJson.dump({"id" => "bucket/object"}),
385         :headers => {'Content-Type' => 'application/json'},
386         :connection => conn
387       )
388       conn.verify
389     end
390   end
391
392   describe 'with the plus API' do
393     before do
394       CLIENT.authorization = nil
395       @plus = CLIENT.discovered_api('plus')
396     end
397
398     it 'should correctly determine the discovery URI' do
399       expect(CLIENT.discovery_uri('plus')).to be ===
400         'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
401     end
402
403     it 'should find APIs that are in the discovery document' do
404       expect(CLIENT.discovered_api('plus').name).to eq('plus')
405       expect(CLIENT.discovered_api('plus').version).to eq('v1')
406       expect(CLIENT.discovered_api(:plus).name).to eq('plus')
407       expect(CLIENT.discovered_api(:plus).version).to eq('v1')
408     end
409
410     it 'should find methods that are in the discovery document' do
411       # TODO(bobaman) Fix this when the RPC names are correct
412       expect(CLIENT.discovered_method(
413         'plus.activities.list', 'plus'
414       ).name).to eq('list')
415     end
416
417     it 'should define the origin API in discovered methods' do
418       expect(CLIENT.discovered_method(
419         'plus.activities.list', 'plus'
420       ).api.name).to eq('plus')
421     end
422
423     it 'should not find methods that are not in the discovery document' do
424       expect(CLIENT.discovered_method('plus.bogus', 'plus')).to eq(nil)
425     end
426
427     it 'should generate requests against the correct URIs' do
428       conn = stub_connection do |stub|
429         stub.get('/plus/v1/people/107807692475771887386/activities/public') do |env|
430           [200, {}, '{}']
431         end
432       end
433
434       request = CLIENT.execute(
435         :api_method => @plus.activities.list,
436         :parameters => {
437           'userId' => '107807692475771887386', 'collection' => 'public'
438         },
439         :authenticated => false,
440         :connection => conn
441       )
442       conn.verify
443     end
444
445     it 'should correctly validate parameters' do
446       expect(lambda do
447         CLIENT.execute(
448           :api_method => @plus.activities.list,
449           :parameters => {'alt' => 'json'},
450           :authenticated => false
451         )
452       end).to raise_error(ArgumentError)
453     end
454
455     it 'should correctly validate parameters' do
456       expect(lambda do
457         CLIENT.execute(
458           :api_method => @plus.activities.list,
459           :parameters => {
460             'userId' => '107807692475771887386', 'collection' => 'bogus'
461           },
462           :authenticated => false
463         ).to_env(CLIENT.connection)
464       end).to raise_error(ArgumentError)
465     end
466   end
467
468   describe 'with the adsense API' do
469     before do
470       CLIENT.authorization = nil
471       @adsense = CLIENT.discovered_api('adsense', 'v1.3')
472     end
473
474     it 'should correctly determine the discovery URI' do
475       expect(CLIENT.discovery_uri('adsense', 'v1.3').to_s).to be ===
476         'https://www.googleapis.com/discovery/v1/apis/adsense/v1.3/rest'
477     end
478
479     it 'should find APIs that are in the discovery document' do
480       expect(CLIENT.discovered_api('adsense', 'v1.3').name).to eq('adsense')
481       expect(CLIENT.discovered_api('adsense', 'v1.3').version).to eq('v1.3')
482     end
483
484     it 'should return a batch path' do
485       expect(CLIENT.discovered_api('adsense', 'v1.3').batch_path).not_to be_nil
486     end
487
488     it 'should find methods that are in the discovery document' do
489       expect(CLIENT.discovered_method(
490         'adsense.reports.generate', 'adsense', 'v1.3'
491       ).name).to eq('generate')
492     end
493
494     it 'should not find methods that are not in the discovery document' do
495       expect(CLIENT.discovered_method('adsense.bogus', 'adsense', 'v1.3')).to eq(nil)
496     end
497
498     it 'should generate requests against the correct URIs' do
499       conn = stub_connection do |stub|
500         stub.get('/adsense/v1.3/adclients') do |env|
501           [200, {}, '{}']
502         end
503       end
504       request = CLIENT.execute(
505         :api_method => @adsense.adclients.list,
506         :authenticated => false,
507         :connection => conn
508       )
509       conn.verify
510     end
511
512     it 'should not be able to execute requests without authorization' do
513       result = CLIENT.execute(
514         :api_method => @adsense.adclients.list,
515         :authenticated => false
516       )
517       expect(result.response.status).to eq(401)
518     end
519
520     it 'should fail when validating missing required parameters' do
521       expect(lambda do
522         CLIENT.execute(
523           :api_method => @adsense.reports.generate,
524           :authenticated => false
525         )
526       end).to raise_error(ArgumentError)
527     end
528
529     it 'should succeed when validating parameters in a correct call' do
530       conn = stub_connection do |stub|
531         stub.get('/adsense/v1.3/reports?dimension=DATE&endDate=2010-01-01&metric=PAGE_VIEWS&startDate=2000-01-01') do |env|
532           [200, {}, '{}']
533         end
534       end
535       expect(lambda do
536         CLIENT.execute(
537           :api_method => @adsense.reports.generate,
538           :parameters => {
539             'startDate' => '2000-01-01',
540             'endDate' => '2010-01-01',
541             'dimension' => 'DATE',
542             'metric' => 'PAGE_VIEWS'
543           },
544           :authenticated => false,
545           :connection => conn
546         )
547       end).not_to raise_error
548       conn.verify
549     end
550
551     it 'should fail when validating parameters with invalid values' do
552       expect(lambda do
553         CLIENT.execute(
554           :api_method => @adsense.reports.generate,
555           :parameters => {
556             'startDate' => '2000-01-01',
557             'endDate' => '2010-01-01',
558             'dimension' => 'BAD_CHARACTERS=-&*(£&',
559             'metric' => 'PAGE_VIEWS'
560           },
561           :authenticated => false
562         )
563       end).to raise_error(ArgumentError)
564     end
565
566     it 'should succeed when validating repeated parameters in a correct call' do
567       conn = stub_connection do |stub|
568         stub.get('/adsense/v1.3/reports?dimension=DATE&dimension=PRODUCT_CODE'+
569                  '&endDate=2010-01-01&metric=CLICKS&metric=PAGE_VIEWS&'+
570                  'startDate=2000-01-01') do |env|
571           [200, {}, '{}']
572         end
573       end
574       expect(lambda do
575         CLIENT.execute(
576           :api_method => @adsense.reports.generate,
577           :parameters => {
578             'startDate' => '2000-01-01',
579             'endDate' => '2010-01-01',
580             'dimension' => ['DATE', 'PRODUCT_CODE'],
581             'metric' => ['PAGE_VIEWS', 'CLICKS']
582           },
583           :authenticated => false,
584           :connection => conn
585         )
586       end).not_to raise_error
587       conn.verify
588     end
589
590     it 'should fail when validating incorrect repeated parameters' do
591       expect(lambda do
592         CLIENT.execute(
593           :api_method => @adsense.reports.generate,
594           :parameters => {
595             'startDate' => '2000-01-01',
596             'endDate' => '2010-01-01',
597             'dimension' => ['DATE', 'BAD_CHARACTERS=-&*(£&'],
598             'metric' => ['PAGE_VIEWS', 'CLICKS']
599           },
600           :authenticated => false
601         )
602       end).to raise_error(ArgumentError)
603     end
604
605     it 'should generate valid requests when multivalued parameters are passed' do
606       conn = stub_connection do |stub|
607          stub.get('/adsense/v1.3/reports?dimension=DATE&dimension=PRODUCT_CODE'+
608                  '&endDate=2010-01-01&metric=CLICKS&metric=PAGE_VIEWS&'+
609                  'startDate=2000-01-01') do |env|
610            expect(env.params['dimension']).to include('DATE', 'PRODUCT_CODE')
611            expect(env.params['metric']).to include('CLICKS', 'PAGE_VIEWS')
612           [200, {}, '{}']
613          end
614        end
615       request = CLIENT.execute(
616         :api_method => @adsense.reports.generate,
617           :parameters => {
618             'startDate' => '2000-01-01',
619             'endDate' => '2010-01-01',
620             'dimension' => ['DATE', 'PRODUCT_CODE'],
621             'metric' => ['PAGE_VIEWS', 'CLICKS']
622           },
623           :authenticated => false,
624           :connection => conn
625       )
626       conn.verify
627     end
628   end
629
630   describe 'with the Drive API' do
631     before do
632       CLIENT.authorization = nil
633       @drive = CLIENT.discovered_api('drive', 'v1')
634     end
635
636     it 'should include media upload info methods' do
637       expect(@drive.files.insert.media_upload).not_to eq(nil)
638     end
639
640     it 'should include accepted media types' do
641       expect(@drive.files.insert.media_upload.accepted_types).not_to be_empty
642     end
643
644     it 'should have an upload path' do
645       expect(@drive.files.insert.media_upload.uri_template).not_to eq(nil)
646     end
647
648     it 'should have a max file size' do
649       expect(@drive.files.insert.media_upload.max_size).not_to eq(nil)
650     end
651   end
652 end