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