google-api-client 0.4.3 → 0.4.4

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.
@@ -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