google-api-client 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ # encoding:utf-8
2
+
1
3
  # Copyright 2010 Google Inc.
2
4
  #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,6 +14,7 @@
12
14
  # See the License for the specific language governing permissions and
13
15
  # limitations under the License.
14
16
 
17
+
15
18
  require 'spec_helper'
16
19
 
17
20
  gem 'faraday', '~> 0.7.0'
@@ -139,6 +142,12 @@ describe Google::APIClient do
139
142
  ).name.should == 'delete'
140
143
  end
141
144
 
145
+ it 'should define the origin API in discovered methods' do
146
+ @client.discovered_method(
147
+ 'prediction.training.insert', 'prediction', 'v1.2'
148
+ ).api.name.should == 'prediction'
149
+ end
150
+
142
151
  it 'should not find methods that are not in the discovery document' do
143
152
  @client.discovered_method(
144
153
  'prediction.bogus', 'prediction', 'v1.2'
@@ -162,6 +171,10 @@ describe Google::APIClient do
162
171
  @client.preferred_version(:prediction).version.should_not == 'v1'
163
172
  end
164
173
 
174
+ it 'should return a batch path' do
175
+ @client.discovered_api('prediction', 'v1.2').batch_path.should_not be_nil
176
+ end
177
+
165
178
  it 'should generate valid requests' do
166
179
  request = @client.generate_request(
167
180
  :api_method => @prediction.training.insert,
@@ -289,7 +302,7 @@ describe Google::APIClient do
289
302
  result = @client.execute(
290
303
  @prediction.training.insert,
291
304
  {},
292
- MultiJson.encode({"id" => "bucket/object"}),
305
+ MultiJson.dump({"id" => "bucket/object"}),
293
306
  {'Content-Type' => 'application/json'}
294
307
  )
295
308
  result.request.headers['Content-Type'].should == 'application/json'
@@ -321,6 +334,12 @@ describe Google::APIClient do
321
334
  ).name.should == 'list'
322
335
  end
323
336
 
337
+ it 'should define the origin API in discovered methods' do
338
+ @client.discovered_method(
339
+ 'plus.activities.list', 'plus'
340
+ ).api.name.should == 'plus'
341
+ end
342
+
324
343
  it 'should not find methods that are not in the discovery document' do
325
344
  @client.discovered_method('plus.bogus', 'plus').should == nil
326
345
  end
@@ -378,12 +397,22 @@ describe Google::APIClient do
378
397
  @client.discovered_api('latitude').version.should == 'v1'
379
398
  end
380
399
 
400
+ it 'should return a batch path' do
401
+ @client.discovered_api('latitude').batch_path.should_not be_nil
402
+ end
403
+
381
404
  it 'should find methods that are in the discovery document' do
382
405
  @client.discovered_method(
383
406
  'latitude.currentLocation.get', 'latitude'
384
407
  ).name.should == 'get'
385
408
  end
386
409
 
410
+ it 'should define the origin API in discovered methods' do
411
+ @client.discovered_method(
412
+ 'latitude.currentLocation.get', 'latitude'
413
+ ).api.name.should == 'latitude'
414
+ end
415
+
387
416
  it 'should not find methods that are not in the discovery document' do
388
417
  @client.discovered_method('latitude.bogus', 'latitude').should == nil
389
418
  end
@@ -437,10 +466,20 @@ describe Google::APIClient do
437
466
  ).name.should == 'get'
438
467
  end
439
468
 
469
+ it 'should define the origin API in discovered methods' do
470
+ @client.discovered_method(
471
+ 'moderator.profiles.get', 'moderator'
472
+ ).api.name.should == 'moderator'
473
+ end
474
+
440
475
  it 'should not find methods that are not in the discovery document' do
441
476
  @client.discovered_method('moderator.bogus', 'moderator').should == nil
442
477
  end
443
478
 
479
+ it 'should return a batch path' do
480
+ @client.discovered_api('moderator').batch_path.should_not be_nil
481
+ end
482
+
444
483
  it 'should generate requests against the correct URIs' do
445
484
  request = @client.generate_request(
446
485
  :api_method => 'moderator.profiles.get',
@@ -470,4 +509,153 @@ describe Google::APIClient do
470
509
  result.response.status.should == 401
471
510
  end
472
511
  end
512
+
513
+ describe 'with the adsense API' do
514
+ before do
515
+ @client.authorization = nil
516
+ @adsense = @client.discovered_api('adsense', 'v1')
517
+ end
518
+
519
+ it 'should correctly determine the discovery URI' do
520
+ @client.discovery_uri('adsense').should ===
521
+ 'https://www.googleapis.com/discovery/v1/apis/adsense/v1/rest'
522
+ end
523
+
524
+ it 'should find APIs that are in the discovery document' do
525
+ @client.discovered_api('adsense').name.should == 'adsense'
526
+ @client.discovered_api('adsense').version.should == 'v1'
527
+ end
528
+
529
+ it 'should return a batch path' do
530
+ @client.discovered_api('adsense').batch_path.should_not be_nil
531
+ end
532
+
533
+ it 'should find methods that are in the discovery document' do
534
+ @client.discovered_method(
535
+ 'adsense.reports.generate', 'adsense'
536
+ ).name.should == 'generate'
537
+ end
538
+
539
+ it 'should not find methods that are not in the discovery document' do
540
+ @client.discovered_method('adsense.bogus', 'adsense').should == nil
541
+ end
542
+
543
+ it 'should generate requests against the correct URIs' do
544
+ request = @client.generate_request(
545
+ :api_method => 'adsense.adclients.list',
546
+ :authenticated => false
547
+ )
548
+ request.to_env(Faraday.default_connection)[:url].should ===
549
+ 'https://www.googleapis.com/adsense/v1/adclients'
550
+ end
551
+
552
+ it 'should generate requests against the correct URIs' do
553
+ request = @client.generate_request(
554
+ :api_method => @adsense.adclients.list,
555
+ :authenticated => false
556
+ )
557
+ request.to_env(Faraday.default_connection)[:url].should ===
558
+ 'https://www.googleapis.com/adsense/v1/adclients'
559
+ end
560
+
561
+ it 'should not be able to execute requests without authorization' do
562
+ result = @client.execute(
563
+ :api_method => 'adsense.adclients.list',
564
+ :authenticated => false
565
+ )
566
+ result.response.status.should == 401
567
+ end
568
+
569
+ it 'should fail when validating missing required parameters' do
570
+ (lambda do
571
+ @client.generate_request(
572
+ :api_method => @adsense.reports.generate,
573
+ :authenticated => false
574
+ )
575
+ end).should raise_error(ArgumentError)
576
+ end
577
+
578
+ it 'should succeed when validating parameters in a correct call' do
579
+ (lambda do
580
+ @client.generate_request(
581
+ :api_method => @adsense.reports.generate,
582
+ :parameters => {
583
+ 'startDate' => '2000-01-01',
584
+ 'endDate' => '2010-01-01',
585
+ 'dimension' => 'DATE',
586
+ 'metric' => 'PAGE_VIEWS'
587
+ },
588
+ :authenticated => false
589
+ )
590
+ end).should_not raise_error
591
+ end
592
+
593
+ it 'should fail when validating parameters with invalid values' do
594
+ (lambda do
595
+ @client.generate_request(
596
+ :api_method => @adsense.reports.generate,
597
+ :parameters => {
598
+ 'startDate' => '2000-01-01',
599
+ 'endDate' => '2010-01-01',
600
+ 'dimension' => 'BAD_CHARACTERS=-&*(£&',
601
+ 'metric' => 'PAGE_VIEWS'
602
+ },
603
+ :authenticated => false
604
+ )
605
+ end).should raise_error(ArgumentError)
606
+ end
607
+
608
+ it 'should succeed when validating repeated parameters in a correct call' do
609
+ (lambda do
610
+ @client.generate_request(
611
+ :api_method => @adsense.reports.generate,
612
+ :parameters => {
613
+ 'startDate' => '2000-01-01',
614
+ 'endDate' => '2010-01-01',
615
+ 'dimension' => ['DATE', 'PRODUCT_CODE'],
616
+ 'metric' => ['PAGE_VIEWS', 'CLICKS']
617
+ },
618
+ :authenticated => false
619
+ )
620
+ end).should_not raise_error
621
+ end
622
+
623
+ it 'should fail when validating incorrect repeated parameters' do
624
+ (lambda do
625
+ @client.generate_request(
626
+ :api_method => @adsense.reports.generate,
627
+ :parameters => {
628
+ 'startDate' => '2000-01-01',
629
+ 'endDate' => '2010-01-01',
630
+ 'dimension' => ['DATE', 'BAD_CHARACTERS=-&*(£&'],
631
+ 'metric' => ['PAGE_VIEWS', 'CLICKS']
632
+ },
633
+ :authenticated => false
634
+ )
635
+ end).should raise_error(ArgumentError)
636
+ end
637
+ end
638
+
639
+ describe 'with the Drive API' do
640
+ before do
641
+ @client.authorization = nil
642
+ @drive = @client.discovered_api('drive', 'v1')
643
+ end
644
+
645
+ it 'should include media upload info methods' do
646
+ @drive.files.insert.media_upload.should_not == nil
647
+ end
648
+
649
+ it 'should include accepted media types' do
650
+ @drive.files.insert.media_upload.accepted_types.should_not be_empty
651
+ end
652
+
653
+ it 'should have an upload path' do
654
+ @drive.files.insert.media_upload.uri_template.should_not == nil
655
+ end
656
+
657
+ it 'should have a max file size' do
658
+ @drive.files.insert.media_upload.max_size.should_not == nil
659
+ end
660
+ end
473
661
  end
@@ -0,0 +1,136 @@
1
+ # Copyright 2012 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'google/api_client'
18
+ require 'google/api_client/version'
19
+
20
+ fixtures_path = File.expand_path('../../../fixtures', __FILE__)
21
+
22
+ describe Google::APIClient::UploadIO do
23
+ it 'should reject invalid file paths' do
24
+ (lambda do
25
+ media = Google::APIClient::UploadIO.new('doesnotexist', 'text/plain')
26
+ end).should raise_error
27
+ end
28
+
29
+ describe 'with a file' do
30
+ before do
31
+ @file = File.expand_path('files/sample.txt', fixtures_path)
32
+ @media = Google::APIClient::UploadIO.new(@file, 'text/plain')
33
+ end
34
+
35
+ it 'should report the correct file length' do
36
+ @media.length.should == File.size(@file)
37
+ end
38
+
39
+ it 'should have a mime type' do
40
+ @media.content_type.should == 'text/plain'
41
+ end
42
+ end
43
+
44
+ describe 'with StringIO' do
45
+ before do
46
+ @content = "hello world"
47
+ @media = Google::APIClient::UploadIO.new(StringIO.new(@content), 'text/plain', 'test.txt')
48
+ end
49
+
50
+ it 'should report the correct file length' do
51
+ @media.length.should == @content.length
52
+ end
53
+
54
+ it 'should have a mime type' do
55
+ @media.content_type.should == 'text/plain'
56
+ end
57
+ end
58
+ end
59
+
60
+ describe Google::APIClient::ResumableUpload do
61
+ before do
62
+ @client = Google::APIClient.new
63
+ @drive = @client.discovered_api('drive', 'v1')
64
+ @file = File.expand_path('files/sample.txt', fixtures_path)
65
+ @media = Google::APIClient::UploadIO.new(@file, 'text/plain')
66
+ @uploader = Google::APIClient::ResumableUpload.new(
67
+ mock_result(308),
68
+ @media,
69
+ 'https://www.googleapis.com/upload/drive/v1/files/12345')
70
+ end
71
+
72
+ it 'should consider 20x status as complete' do
73
+ api_client = stub('api', :execute => mock_result(200))
74
+ @uploader.send_chunk(api_client)
75
+ @uploader.complete?.should == true
76
+ end
77
+
78
+ it 'should consider 30x status as incomplete' do
79
+ api_client = stub('api', :execute => mock_result(308))
80
+ @uploader.send_chunk(api_client)
81
+ @uploader.complete?.should == false
82
+ @uploader.expired?.should == false
83
+ end
84
+
85
+ it 'should consider 40x status as fatal' do
86
+ api_client = stub('api', :execute => mock_result(404))
87
+ @uploader.send_chunk(api_client)
88
+ @uploader.expired?.should == true
89
+ end
90
+
91
+ it 'should detect changes to location' do
92
+ api_client = stub('api', :execute => mock_result(308, 'location' => 'https://www.googleapis.com/upload/drive/v1/files/abcdef'))
93
+ @uploader.send_chunk(api_client)
94
+ @uploader.location.should == 'https://www.googleapis.com/upload/drive/v1/files/abcdef'
95
+ end
96
+
97
+ it 'should resume from the saved range reported by the server' do
98
+ api_client = mock('api')
99
+ api_client.should_receive(:execute).and_return(mock_result(308, 'range' => '0-99'))
100
+ api_client.should_receive(:execute).with(
101
+ hash_including(:headers => hash_including(
102
+ "Content-Range" => "bytes 100-299/#{@media.length}",
103
+ "Content-Length" => "200"
104
+ ))).and_return(mock_result(308))
105
+
106
+ @uploader.chunk_size = 200
107
+ @uploader.send_chunk(api_client) # Send bytes 0-199, only 0-99 saved
108
+ @uploader.send_chunk(api_client) # Send bytes 100-299
109
+ end
110
+
111
+ it 'should resync the offset after 5xx errors' do
112
+ api_client = mock('api')
113
+ api_client.should_receive(:execute).and_return(mock_result(500))
114
+ api_client.should_receive(:execute).with(
115
+ hash_including(:headers => hash_including(
116
+ "Content-Range" => "bytes */#{@media.length}",
117
+ "Content-Length" => "0"
118
+ ))).and_return(mock_result(308, 'range' => '0-99'))
119
+ api_client.should_receive(:execute).with(
120
+ hash_including(:headers => hash_including(
121
+ "Content-Range" => "bytes 100-299/#{@media.length}",
122
+ "Content-Length" => "200"
123
+ ))).and_return(mock_result(308))
124
+
125
+ @uploader.chunk_size = 200
126
+ @uploader.send_chunk(api_client) # 500, invalidate
127
+ @uploader.send_chunk(api_client) # Just resyncs, doesn't actually upload
128
+ @uploader.send_chunk(api_client) # Send next chunk at correct range
129
+ end
130
+
131
+ def mock_result(status, headers = {})
132
+ reference = Google::APIClient::Reference.new(:api_method => @drive.files.insert)
133
+ stub('result', :status => status, :headers => headers, :reference => reference)
134
+ end
135
+
136
+ end
@@ -0,0 +1,150 @@
1
+ # Copyright 2012 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'google/api_client'
18
+ require 'google/api_client/version'
19
+
20
+ describe Google::APIClient::Result do
21
+ before do
22
+ @client = Google::APIClient.new
23
+ end
24
+
25
+ describe 'with the plus API' do
26
+ before do
27
+ @client.authorization = nil
28
+ @plus = @client.discovered_api('plus', 'v1')
29
+ @reference = Google::APIClient::Reference.new({
30
+ :api_method => @plus.activities.list,
31
+ :parameters => {
32
+ 'userId' => 'me',
33
+ 'collection' => 'public',
34
+ 'maxResults' => 20
35
+ }
36
+ })
37
+ @request = @reference.to_request
38
+
39
+ # Response stub
40
+ @response = stub("response")
41
+ @response.stub(:status).and_return(200)
42
+ @response.stub(:headers).and_return({
43
+ 'etag' => '12345',
44
+ 'x-google-apiary-auth-scopes' =>
45
+ 'https://www.googleapis.com/auth/plus.me',
46
+ 'content-type' => 'application/json; charset=UTF-8',
47
+ 'date' => 'Mon, 23 Apr 2012 00:00:00 GMT',
48
+ 'cache-control' => 'private, max-age=0, must-revalidate, no-transform',
49
+ 'server' => 'GSE',
50
+ 'connection' => 'close'
51
+ })
52
+ end
53
+
54
+ describe 'with a next page token' do
55
+ before do
56
+ @response.stub(:body).and_return(
57
+ <<-END_OF_STRING
58
+ {
59
+ "kind": "plus#activityFeed",
60
+ "etag": "FOO",
61
+ "nextPageToken": "NEXT+PAGE+TOKEN",
62
+ "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
63
+ "nextLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN",
64
+ "title": "Plus Public Activity Feed for ",
65
+ "updated": "2012-04-23T00:00:00.000Z",
66
+ "id": "tag:google.com,2010:/plus/people/foo/activities/public",
67
+ "items": []
68
+ }
69
+ END_OF_STRING
70
+ )
71
+ @result = Google::APIClient::Result.new(@reference, @request, @response)
72
+ end
73
+
74
+ it 'should return the correct next page token' do
75
+ @result.next_page_token.should == 'NEXT+PAGE+TOKEN'
76
+ end
77
+
78
+ it 'should escape the next page token when calling next_page' do
79
+ reference = @result.next_page
80
+ reference.parameters.should include('pageToken')
81
+ reference.parameters['pageToken'].should == 'NEXT+PAGE+TOKEN'
82
+ path = reference.to_request.path.to_s
83
+ path.should include 'pageToken=NEXT%2BPAGE%2BTOKEN'
84
+ end
85
+
86
+ it 'should return content type correctly' do
87
+ @result.media_type.should == 'application/json'
88
+ end
89
+
90
+ it 'should return the result data correctly' do
91
+ @result.data?.should be_true
92
+ @result.data.class.to_s.should ==
93
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
94
+ @result.data.kind.should == 'plus#activityFeed'
95
+ @result.data.etag.should == 'FOO'
96
+ @result.data.nextPageToken.should == 'NEXT+PAGE+TOKEN'
97
+ @result.data.selfLink.should ==
98
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
99
+ @result.data.nextLink.should ==
100
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?' +
101
+ 'maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN'
102
+ @result.data.title.should == 'Plus Public Activity Feed for '
103
+ @result.data.id.should ==
104
+ 'tag:google.com,2010:/plus/people/foo/activities/public'
105
+ @result.data.items.should be_empty
106
+ end
107
+ end
108
+
109
+ describe 'without a next page token' do
110
+ before do
111
+ @response.stub(:body).and_return(
112
+ <<-END_OF_STRING
113
+ {
114
+ "kind": "plus#activityFeed",
115
+ "etag": "FOO",
116
+ "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
117
+ "title": "Plus Public Activity Feed for ",
118
+ "updated": "2012-04-23T00:00:00.000Z",
119
+ "id": "tag:google.com,2010:/plus/people/foo/activities/public",
120
+ "items": []
121
+ }
122
+ END_OF_STRING
123
+ )
124
+ @result = Google::APIClient::Result.new(@reference, @request, @response)
125
+ end
126
+
127
+ it 'should not return a next page token' do
128
+ @result.next_page_token.should == nil
129
+ end
130
+
131
+ it 'should return content type correctly' do
132
+ @result.media_type.should == 'application/json'
133
+ end
134
+
135
+ it 'should return the result data correctly' do
136
+ @result.data?.should be_true
137
+ @result.data.class.to_s.should ==
138
+ 'Google::APIClient::Schema::Plus::V1::ActivityFeed'
139
+ @result.data.kind.should == 'plus#activityFeed'
140
+ @result.data.etag.should == 'FOO'
141
+ @result.data.selfLink.should ==
142
+ 'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
143
+ @result.data.title.should == 'Plus Public Activity Feed for '
144
+ @result.data.id.should ==
145
+ 'tag:google.com,2010:/plus/people/foo/activities/public'
146
+ @result.data.items.should be_empty
147
+ end
148
+ end
149
+ end
150
+ end