Fixed issues with recursive structures and external references.
[arvados.git] / spec / google / api_client / discovery_spec.rb
1 # Copyright 2010 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 'json'
18 require 'signet/oauth_1/client'
19 require 'httpadapter/adapters/net_http'
20
21 require 'google/api_client'
22 require 'google/api_client/version'
23 require 'google/api_client/parsers/json_parser'
24
25 describe Google::APIClient do
26   before do
27     @client = Google::APIClient.new
28   end
29
30   it 'should raise a type error for bogus authorization' do
31     (lambda do
32       Google::APIClient.new(:authorization => 42)
33     end).should raise_error(TypeError)
34   end
35
36   it 'should not be able to retrieve the discovery document for a bogus API' do
37     (lambda do
38       @client.discovery_document('bogus')
39     end).should raise_error(Google::APIClient::TransmissionError)
40     (lambda do
41       @client.discovered_api('bogus')
42     end).should raise_error(Google::APIClient::TransmissionError)
43   end
44
45   it 'should raise an error for bogus services' do
46     (lambda do
47       @client.discovered_api(42)
48     end).should raise_error(TypeError)
49   end
50
51   it 'should raise an error for bogus services' do
52     (lambda do
53       @client.preferred_version(42)
54     end).should raise_error(TypeError)
55   end
56
57   it 'should raise an error for bogus methods' do
58     (lambda do
59       @client.generate_request(42)
60     end).should raise_error(TypeError)
61   end
62
63   it 'should not return a preferred version for bogus service names' do
64     @client.preferred_version('bogus').should == nil
65   end
66
67   describe 'with the prediction API' do
68     before do
69       @client.authorization = nil
70       # The prediction API no longer exposes a v1, so we have to be
71       # careful about looking up the wrong API version.
72       @prediction = @client.discovered_api('prediction', 'v1.2')
73     end
74
75     it 'should correctly determine the discovery URI' do
76       @client.discovery_uri('prediction').should ===
77         'https://www.googleapis.com/discovery/v1/apis/prediction/v1/rest'
78     end
79
80     it 'should correctly determine the discovery URI if :user_ip is set' do
81       @client.user_ip = '127.0.0.1'
82       request = @client.generate_request(
83         :http_method => 'GET',
84         :uri => @client.discovery_uri('prediction', 'v1.2'),
85         :authenticated => false
86       )
87       http_method, uri, headers, body = request
88       uri.should === (
89         'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
90         '?userIp=127.0.0.1'
91       )
92     end
93
94     it 'should correctly determine the discovery URI if :key is set' do
95       @client.key = 'qwerty'
96       request = @client.generate_request(
97         :http_method => 'GET',
98         :uri => @client.discovery_uri('prediction', 'v1.2'),
99         :authenticated => false
100       )
101       http_method, uri, headers, body = request
102       uri.should === (
103         'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
104         '?key=qwerty'
105       )
106     end
107
108     it 'should correctly determine the discovery URI if both are set' do
109       @client.key = 'qwerty'
110       @client.user_ip = '127.0.0.1'
111       request = @client.generate_request(
112         :http_method => 'GET',
113         :uri => @client.discovery_uri('prediction', 'v1.2'),
114         :authenticated => false
115       )
116       http_method, uri, headers, body = request
117       uri.should === (
118         'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
119         '?key=qwerty&userIp=127.0.0.1'
120       )
121     end
122
123     it 'should correctly generate API objects' do
124       @client.discovered_api('prediction', 'v1.2').name.should == 'prediction'
125       @client.discovered_api('prediction', 'v1.2').version.should == 'v1.2'
126       @client.discovered_api(:prediction, 'v1.2').name.should == 'prediction'
127       @client.discovered_api(:prediction, 'v1.2').version.should == 'v1.2'
128     end
129
130     it 'should discover methods' do
131       @client.discovered_method(
132         'prediction.training.insert', 'prediction', 'v1.2'
133       ).name.should == 'insert'
134       @client.discovered_method(
135         :'prediction.training.insert', :prediction, 'v1.2'
136       ).name.should == 'insert'
137       @client.discovered_method(
138         'prediction.training.delete', 'prediction', 'v1.2'
139       ).name.should == 'delete'
140     end
141
142     it 'should not find methods that are not in the discovery document' do
143       @client.discovered_method(
144         'prediction.bogus', 'prediction', 'v1.2'
145       ).should == nil
146     end
147
148     it 'should raise an error for bogus methods' do
149       (lambda do
150         @client.discovered_method(42, 'prediction', 'v1.2')
151       end).should raise_error(TypeError)
152     end
153
154     it 'should raise an error for bogus methods' do
155       (lambda do
156         @client.generate_request(@client.discovered_api('prediction', 'v1.2'))
157       end).should raise_error(TypeError)
158     end
159
160     it 'should correctly determine the preferred version' do
161       @client.preferred_version('prediction').version.should_not == 'v1'
162       @client.preferred_version(:prediction).version.should_not == 'v1'
163     end
164
165     it 'should generate valid requests' do
166       request = @client.generate_request(
167         :api_method => @prediction.training.insert,
168         :parameters => {'data' => '12345', }
169       )
170       method, uri, headers, body = request
171       method.should == 'POST'
172       uri.should ==
173         'https://www.googleapis.com/prediction/v1.2/training?data=12345'
174       (headers.inject({}) { |h,(k,v)| h[k]=v; h }).should == {}
175       body.should respond_to(:each)
176     end
177
178     it 'should generate requests against the correct URIs' do
179       request = @client.generate_request(
180         :api_method => @prediction.training.insert,
181         :parameters => {'data' => '12345'}
182       )
183       method, uri, headers, body = request
184       uri.should ==
185         'https://www.googleapis.com/prediction/v1.2/training?data=12345'
186     end
187
188     it 'should generate requests against the correct URIs' do
189       request = @client.generate_request(
190         :api_method => @prediction.training.insert,
191         :parameters => {'data' => '12345'}
192       )
193       method, uri, headers, body = request
194       uri.should ==
195         'https://www.googleapis.com/prediction/v1.2/training?data=12345'
196     end
197
198     it 'should allow modification to the base URIs for testing purposes' do
199       prediction = @client.discovered_api('prediction', 'v1.2')
200       prediction.method_base =
201         'https://testing-domain.googleapis.com/prediction/v1.2/'
202       request = @client.generate_request(
203         :api_method => prediction.training.insert,
204         :parameters => {'data' => '123'}
205       )
206       method, uri, headers, body = request
207       uri.should == (
208         'https://testing-domain.googleapis.com/' +
209         'prediction/v1.2/training?data=123'
210       )
211     end
212
213     it 'should generate OAuth 1 requests' do
214       @client.authorization = :oauth_1
215       @client.authorization.token_credential_key = '12345'
216       @client.authorization.token_credential_secret = '12345'
217       request = @client.generate_request(
218         :api_method => @prediction.training.insert,
219         :parameters => {'data' => '12345'}
220       )
221       method, uri, headers, body = request
222       headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
223       headers.keys.should include('Authorization')
224       headers['Authorization'].should =~ /^OAuth/
225     end
226
227     it 'should generate OAuth 2 requests' do
228       @client.authorization = :oauth_2
229       @client.authorization.access_token = '12345'
230       request = @client.generate_request(
231         :api_method => @prediction.training.insert,
232         :parameters => {'data' => '12345'}
233       )
234       method, uri, headers, body = request
235       headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
236       headers.keys.should include('Authorization')
237       headers['Authorization'].should =~ /^OAuth/
238     end
239
240     it 'should not be able to execute improperly authorized requests' do
241       @client.authorization = :oauth_1
242       @client.authorization.token_credential_key = '12345'
243       @client.authorization.token_credential_secret = '12345'
244       result = @client.execute(
245         @prediction.training.insert,
246         {'data' => '12345'}
247       )
248       status, headers, body = result.response
249       status.should == 401
250     end
251
252     it 'should not be able to execute improperly authorized requests' do
253       @client.authorization = :oauth_2
254       @client.authorization.access_token = '12345'
255       result = @client.execute(
256         @prediction.training.insert,
257         {'data' => '12345'}
258       )
259       status, headers, body = result.response
260       status.should == 401
261     end
262
263     it 'should not be able to execute improperly authorized requests' do
264       (lambda do
265         @client.authorization = :oauth_1
266         @client.authorization.token_credential_key = '12345'
267         @client.authorization.token_credential_secret = '12345'
268         result = @client.execute!(
269           @prediction.training.insert,
270           {'data' => '12345'}
271         )
272       end).should raise_error(Google::APIClient::ClientError)
273     end
274
275     it 'should not be able to execute improperly authorized requests' do
276       (lambda do
277         @client.authorization = :oauth_2
278         @client.authorization.access_token = '12345'
279         result = @client.execute!(
280           @prediction.training.insert,
281           {'data' => '12345'}
282         )
283       end).should raise_error(Google::APIClient::ClientError)
284     end
285
286     it 'should correctly handle unnamed parameters' do
287       @client.authorization = :oauth_2
288       @client.authorization.access_token = '12345'
289       result = @client.execute(
290         @prediction.training.insert,
291         {},
292         JSON.generate({"id" => "bucket/object"}),
293         {'Content-Type' => 'application/json'}
294       )
295       method, uri, headers, body = result.request
296       Hash[headers]['Content-Type'].should == 'application/json'
297     end
298   end
299
300   describe 'with the buzz API' do
301     before do
302       @client.authorization = nil
303       @buzz = @client.discovered_api('buzz')
304     end
305
306     it 'should correctly determine the discovery URI' do
307       @client.discovery_uri('buzz').should ===
308         'https://www.googleapis.com/discovery/v1/apis/buzz/v1/rest'
309     end
310
311     it 'should find APIs that are in the discovery document' do
312       @client.discovered_api('buzz').name.should == 'buzz'
313       @client.discovered_api('buzz').version.should == 'v1'
314       @client.discovered_api(:buzz).name.should == 'buzz'
315       @client.discovered_api(:buzz).version.should == 'v1'
316     end
317
318     it 'should find methods that are in the discovery document' do
319       # TODO(bobaman) Fix this when the RPC names are correct
320       @client.discovered_method(
321         'chili.activities.list', 'buzz'
322       ).name.should == 'list'
323     end
324
325     it 'should not find methods that are not in the discovery document' do
326       @client.discovered_method('buzz.bogus', 'buzz').should == nil
327     end
328
329     it 'should fail for string RPC names that do not match API name' do
330       (lambda do
331         @client.generate_request(
332           :api_method => 'chili.activities.list',
333           :parameters => {'alt' => 'json'},
334           :authenticated => false
335         )
336       end).should raise_error(Google::APIClient::TransmissionError)
337     end
338
339     it 'should generate requests against the correct URIs' do
340       request = @client.generate_request(
341         :api_method => @buzz.activities.list,
342         :parameters => {'userId' => 'hikingfan', 'scope' => '@public'},
343         :authenticated => false
344       )
345       method, uri, headers, body = request
346       uri.should ==
347         'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
348     end
349
350     it 'should correctly validate parameters' do
351       (lambda do
352         @client.generate_request(
353           :api_method => @buzz.activities.list,
354           :parameters => {'alt' => 'json'},
355           :authenticated => false
356         )
357       end).should raise_error(ArgumentError)
358     end
359
360     it 'should correctly validate parameters' do
361       (lambda do
362         @client.generate_request(
363           :api_method => @buzz.activities.list,
364           :parameters => {'userId' => 'hikingfan', 'scope' => '@bogus'},
365           :authenticated => false
366         )
367       end).should raise_error(ArgumentError)
368     end
369
370     it 'should be able to execute requests without authorization' do
371       result = @client.execute(
372         @buzz.activities.list,
373         {'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
374         '',
375         [],
376         :authenticated => false
377       )
378       status, headers, body = result.response
379       status.should == 200
380     end
381
382     it 'should correctly handle nested schema objects' do
383       result = @client.execute(
384         @buzz.activities.list,
385         {'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
386         '',
387         [],
388         :authenticated => false
389       )
390       feed = result.data
391       puts feed.inspect
392     end
393
394     it 'should not be able to execute requests without authorization' do
395       result = @client.execute(
396         @buzz.activities.list,
397         'alt' => 'json', 'userId' => '@me', 'scope' => '@self'
398       )
399       status, headers, body = result.response
400       status.should == 401
401     end
402   end
403
404   describe 'with the latitude API' do
405     before do
406       @client.authorization = nil
407       @latitude = @client.discovered_api('latitude')
408     end
409
410     it 'should correctly determine the discovery URI' do
411       @client.discovery_uri('latitude').should ===
412         'https://www.googleapis.com/discovery/v1/apis/latitude/v1/rest'
413     end
414
415     it 'should find APIs that are in the discovery document' do
416       @client.discovered_api('latitude').name.should == 'latitude'
417       @client.discovered_api('latitude').version.should == 'v1'
418     end
419
420     it 'should find methods that are in the discovery document' do
421       @client.discovered_method(
422         'latitude.currentLocation.get', 'latitude'
423       ).name.should == 'get'
424     end
425
426     it 'should not find methods that are not in the discovery document' do
427       @client.discovered_method('latitude.bogus', 'latitude').should == nil
428     end
429
430     it 'should generate requests against the correct URIs' do
431       request = @client.generate_request(
432         :api_method => 'latitude.currentLocation.get',
433         :authenticated => false
434       )
435       method, uri, headers, body = request
436       uri.should ==
437         'https://www.googleapis.com/latitude/v1/currentLocation'
438     end
439
440     it 'should generate requests against the correct URIs' do
441       request = @client.generate_request(
442         :api_method => @latitude.current_location.get,
443         :authenticated => false
444       )
445       method, uri, headers, body = request
446       uri.should ==
447         'https://www.googleapis.com/latitude/v1/currentLocation'
448     end
449
450     it 'should not be able to execute requests without authorization' do
451       result = @client.execute(
452         :api_method => 'latitude.currentLocation.get',
453         :authenticated => false
454       )
455       status, headers, body = result.response
456       status.should == 401
457     end
458   end
459
460   describe 'with the moderator API' do
461     before do
462       @client.authorization = nil
463       @moderator = @client.discovered_api('moderator')
464     end
465
466     it 'should correctly determine the discovery URI' do
467       @client.discovery_uri('moderator').should ===
468         'https://www.googleapis.com/discovery/v1/apis/moderator/v1/rest'
469     end
470
471     it 'should find APIs that are in the discovery document' do
472       @client.discovered_api('moderator').name.should == 'moderator'
473       @client.discovered_api('moderator').version.should == 'v1'
474     end
475
476     it 'should find methods that are in the discovery document' do
477       @client.discovered_method(
478         'moderator.profiles.get', 'moderator'
479       ).name.should == 'get'
480     end
481
482     it 'should not find methods that are not in the discovery document' do
483       @client.discovered_method('moderator.bogus', 'moderator').should == nil
484     end
485
486     it 'should generate requests against the correct URIs' do
487       request = @client.generate_request(
488         :api_method => 'moderator.profiles.get',
489         :authenticated => false
490       )
491       method, uri, headers, body = request
492       uri.should ==
493         'https://www.googleapis.com/moderator/v1/profiles/@me'
494     end
495
496     it 'should generate requests against the correct URIs' do
497       request = @client.generate_request(
498         :api_method => @moderator.profiles.get,
499         :authenticated => false
500       )
501       method, uri, headers, body = request
502       uri.should ==
503         'https://www.googleapis.com/moderator/v1/profiles/@me'
504     end
505
506     it 'should not be able to execute requests without authorization' do
507       result = @client.execute(
508         'moderator.profiles.get',
509         {},
510         '',
511         [],
512         {:authenticated => false}
513       )
514       status, headers, body = result.response
515       status.should == 401
516     end
517   end
518 end