google-api-client 0.4.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -71,68 +71,56 @@ describe Google::APIClient::ResumableUpload do
71
71
  @file = File.expand_path('files/sample.txt', fixtures_path)
72
72
  @media = Google::APIClient::UploadIO.new(@file, 'text/plain')
73
73
  @uploader = Google::APIClient::ResumableUpload.new(
74
- mock_result(308),
75
- @media,
76
- 'https://www.googleapis.com/upload/drive/v1/files/12345')
74
+ :media => @media,
75
+ :api_method => @drive.files.insert,
76
+ :uri => 'https://www.googleapis.com/upload/drive/v1/files/12345')
77
77
  end
78
78
 
79
79
  it 'should consider 20x status as complete' do
80
- api_client = stub('api', :execute => mock_result(200))
81
- @uploader.send_chunk(api_client)
80
+ request = @uploader.to_http_request
81
+ @uploader.process_http_response(mock_result(200))
82
82
  @uploader.complete?.should == true
83
83
  end
84
84
 
85
85
  it 'should consider 30x status as incomplete' do
86
- api_client = stub('api', :execute => mock_result(308))
87
- @uploader.send_chunk(api_client)
86
+ request = @uploader.to_http_request
87
+ @uploader.process_http_response(mock_result(308))
88
88
  @uploader.complete?.should == false
89
89
  @uploader.expired?.should == false
90
90
  end
91
91
 
92
92
  it 'should consider 40x status as fatal' do
93
- api_client = stub('api', :execute => mock_result(404))
94
- @uploader.send_chunk(api_client)
93
+ request = @uploader.to_http_request
94
+ @uploader.process_http_response(mock_result(404))
95
95
  @uploader.expired?.should == true
96
96
  end
97
97
 
98
98
  it 'should detect changes to location' do
99
- api_client = stub('api', :execute => mock_result(308, 'location' => 'https://www.googleapis.com/upload/drive/v1/files/abcdef'))
100
- @uploader.send_chunk(api_client)
101
- @uploader.location.should == 'https://www.googleapis.com/upload/drive/v1/files/abcdef'
99
+ request = @uploader.to_http_request
100
+ @uploader.process_http_response(mock_result(308, 'location' => 'https://www.googleapis.com/upload/drive/v1/files/abcdef'))
101
+ @uploader.uri.to_s.should == 'https://www.googleapis.com/upload/drive/v1/files/abcdef'
102
102
  end
103
103
 
104
- it 'should resume from the saved range reported by the server' do
105
- api_client = mock('api')
106
- api_client.should_receive(:execute).and_return(mock_result(308, 'range' => '0-99'))
107
- api_client.should_receive(:execute).with(
108
- hash_including(:headers => hash_including(
109
- "Content-Range" => "bytes 100-299/#{@media.length}",
110
- "Content-Length" => "200"
111
- ))).and_return(mock_result(308))
112
-
104
+ it 'should resume from the saved range reported by the server' do
113
105
  @uploader.chunk_size = 200
114
- @uploader.send_chunk(api_client) # Send bytes 0-199, only 0-99 saved
115
- @uploader.send_chunk(api_client) # Send bytes 100-299
106
+ @uploader.to_http_request # Send bytes 0-199, only 0-99 saved
107
+ @uploader.process_http_response(mock_result(308, 'range' => '0-99'))
108
+ method, url, headers, body = @uploader.to_http_request # Send bytes 100-299
109
+ headers['Content-Range'].should == "bytes 100-299/#{@media.length}"
110
+ headers['Content-length'].should == "200"
116
111
  end
117
112
 
118
113
  it 'should resync the offset after 5xx errors' do
119
- api_client = mock('api')
120
- api_client.should_receive(:execute).and_return(mock_result(500))
121
- api_client.should_receive(:execute).with(
122
- hash_including(:headers => hash_including(
123
- "Content-Range" => "bytes */#{@media.length}",
124
- "Content-Length" => "0"
125
- ))).and_return(mock_result(308, 'range' => '0-99'))
126
- api_client.should_receive(:execute).with(
127
- hash_including(:headers => hash_including(
128
- "Content-Range" => "bytes 100-299/#{@media.length}",
129
- "Content-Length" => "200"
130
- ))).and_return(mock_result(308))
131
-
132
114
  @uploader.chunk_size = 200
133
- @uploader.send_chunk(api_client) # 500, invalidate
134
- @uploader.send_chunk(api_client) # Just resyncs, doesn't actually upload
135
- @uploader.send_chunk(api_client) # Send next chunk at correct range
115
+ @uploader.to_http_request
116
+ @uploader.process_http_response(mock_result(500)) # Invalidates range
117
+ method, url, headers, body = @uploader.to_http_request # Resync
118
+ headers['Content-Range'].should == "bytes */#{@media.length}"
119
+ headers['Content-length'].should == "0"
120
+ @uploader.process_http_response(mock_result(308, 'range' => '0-99'))
121
+ method, url, headers, body = @uploader.to_http_request # Send next chunk at correct range
122
+ headers['Content-Range'].should == "bytes 100-299/#{@media.length}"
123
+ headers['Content-length'].should == "200"
136
124
  end
137
125
 
138
126
  def mock_result(status, headers = {})
@@ -32,7 +32,7 @@ describe Google::APIClient::Result do
32
32
  'maxResults' => 20
33
33
  }
34
34
  })
35
- @request = @reference.to_request
35
+ @request = @reference.to_http_request
36
36
 
37
37
  # Response stub
38
38
  @response = stub("response")
@@ -61,12 +61,12 @@ describe Google::APIClient::Result do
61
61
  "nextLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN",
62
62
  "title": "Plus Public Activity Feed for ",
63
63
  "updated": "2012-04-23T00:00:00.000Z",
64
- "id": "tag:google.com,2010:/plus/people/foo/activities/public",
64
+ "id": "123456790",
65
65
  "items": []
66
66
  }
67
67
  END_OF_STRING
68
68
  )
69
- @result = Google::APIClient::Result.new(@reference, @request, @response)
69
+ @result = Google::APIClient::Result.new(@reference, @response)
70
70
  end
71
71
 
72
72
  it 'should indicate a successful response' do
@@ -78,10 +78,11 @@ describe Google::APIClient::Result do
78
78
  end
79
79
 
80
80
  it 'should escape the next page token when calling next_page' do
81
+ pending("This is caused by Faraday's encoding of query parameters.")
81
82
  reference = @result.next_page
82
83
  Hash[reference.parameters].should include('pageToken')
83
84
  Hash[reference.parameters]['pageToken'].should == 'NEXT+PAGE+TOKEN'
84
- url = reference.to_request.to_env(Faraday.default_connection)[:url]
85
+ url = reference.to_env(Faraday.default_connection)[:url]
85
86
  url.to_s.should include('pageToken=NEXT%2BPAGE%2BTOKEN')
86
87
  end
87
88
 
@@ -102,8 +103,7 @@ describe Google::APIClient::Result do
102
103
  'https://www.googleapis.com/plus/v1/people/foo/activities/public?' +
103
104
  'maxResults=20&pageToken=NEXT%2BPAGE%2BTOKEN'
104
105
  @result.data.title.should == 'Plus Public Activity Feed for '
105
- @result.data.id.should ==
106
- 'tag:google.com,2010:/plus/people/foo/activities/public'
106
+ @result.data.id.should == "123456790"
107
107
  @result.data.items.should be_empty
108
108
  end
109
109
  end
@@ -118,12 +118,12 @@ describe Google::APIClient::Result do
118
118
  "selfLink": "https://www.googleapis.com/plus/v1/people/foo/activities/public?",
119
119
  "title": "Plus Public Activity Feed for ",
120
120
  "updated": "2012-04-23T00:00:00.000Z",
121
- "id": "tag:google.com,2010:/plus/people/foo/activities/public",
121
+ "id": "123456790",
122
122
  "items": []
123
123
  }
124
124
  END_OF_STRING
125
125
  )
126
- @result = Google::APIClient::Result.new(@reference, @request, @response)
126
+ @result = Google::APIClient::Result.new(@reference, @response)
127
127
  end
128
128
 
129
129
  it 'should not return a next page token' do
@@ -143,8 +143,7 @@ describe Google::APIClient::Result do
143
143
  @result.data.selfLink.should ==
144
144
  'https://www.googleapis.com/plus/v1/people/foo/activities/public?'
145
145
  @result.data.title.should == 'Plus Public Activity Feed for '
146
- @result.data.id.should ==
147
- 'tag:google.com,2010:/plus/people/foo/activities/public'
146
+ @result.data.id.should == "123456790"
148
147
  @result.data.items.should be_empty
149
148
  end
150
149
  end
@@ -169,7 +168,7 @@ describe Google::APIClient::Result do
169
168
  END_OF_STRING
170
169
  )
171
170
  @response.stub(:status).and_return(400)
172
- @result = Google::APIClient::Result.new(@reference, @request, @response)
171
+ @result = Google::APIClient::Result.new(@reference, @response)
173
172
  end
174
173
 
175
174
  it 'should return error status correctly' do
@@ -179,7 +178,27 @@ describe Google::APIClient::Result do
179
178
  it 'should return the correct error message' do
180
179
  @result.error_message.should == 'Parse Error'
181
180
  end
181
+ end
182
+
183
+ describe 'with 204 No Content response' do
184
+ before do
185
+ @response.stub(:body).and_return('')
186
+ @response.stub(:status).and_return(204)
187
+ @response.stub(:headers).and_return({})
188
+ @result = Google::APIClient::Result.new(@reference, @response)
189
+ end
182
190
 
191
+ it 'should indicate no data is available' do
192
+ @result.data?.should be_false
193
+ end
194
+
195
+ it 'should return nil for data' do
196
+ @result.data.should == nil
197
+ end
198
+
199
+ it 'should return nil for media_type' do
200
+ @result.media_type.should == nil
201
+ end
183
202
  end
184
203
  end
185
204
  end
@@ -17,6 +17,7 @@ require 'spec_helper'
17
17
  require 'google/api_client'
18
18
 
19
19
  describe Google::APIClient::JWTAsserter do
20
+ include ConnectionHelpers
20
21
 
21
22
  before do
22
23
  @key = OpenSSL::PKey::RSA.new 2048
@@ -33,7 +34,7 @@ describe Google::APIClient::JWTAsserter do
33
34
  end
34
35
 
35
36
  it 'should send valid access token request' do
36
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
37
+ conn = stub_connection do |stub|
37
38
  stub.post('/o/oauth2/token') do |env|
38
39
  params = Addressable::URI.form_unencode(env[:body])
39
40
  JWT.decode(params.assoc("assertion").last, @key.public_key)
@@ -45,14 +46,45 @@ describe Google::APIClient::JWTAsserter do
45
46
  }']
46
47
  end
47
48
  end
48
- connection = Faraday.new(:url => 'https://accounts.google.com') do |builder|
49
- builder.adapter(:test, stubs)
50
- end
51
-
52
49
  asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
53
- auth = asserter.authorize(nil, { :connection => connection})
50
+ auth = asserter.authorize(nil, { :connection => conn })
54
51
  auth.should_not == nil?
55
52
  auth.access_token.should == "1/abcdef1234567890"
53
+ conn.verify
56
54
  end
55
+
56
+ it 'should be refreshable' do
57
+ conn = stub_connection do |stub|
58
+ stub.post('/o/oauth2/token') do |env|
59
+ params = Addressable::URI.form_unencode(env[:body])
60
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
61
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
62
+ [200, {}, '{
63
+ "access_token" : "1/abcdef1234567890",
64
+ "token_type" : "Bearer",
65
+ "expires_in" : 3600
66
+ }']
67
+ end
68
+ stub.post('/o/oauth2/token') do |env|
69
+ params = Addressable::URI.form_unencode(env[:body])
70
+ JWT.decode(params.assoc("assertion").last, @key.public_key)
71
+ params.assoc("grant_type").should == ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
72
+ [200, {}, '{
73
+ "access_token" : "1/0987654321fedcba",
74
+ "token_type" : "Bearer",
75
+ "expires_in" : 3600
76
+ }']
77
+ end
78
+ end
79
+ asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
80
+ auth = asserter.authorize(nil, { :connection => conn })
81
+ auth.should_not == nil?
82
+ auth.access_token.should == "1/abcdef1234567890"
83
+
84
+ auth.fetch_access_token!(:connection => conn)
85
+ auth.access_token.should == "1/0987654321fedcba"
86
+
87
+ conn.verify
88
+ end
57
89
  end
58
90
 
@@ -14,17 +14,15 @@
14
14
 
15
15
  require 'spec_helper'
16
16
 
17
- gem 'faraday', '~> 0.8.1'
18
17
  require 'faraday'
19
18
  require 'faraday/utils'
20
-
21
- gem 'signet', '~> 0.4.0'
22
19
  require 'signet/oauth_1/client'
23
-
24
20
  require 'google/api_client'
25
21
  require 'google/api_client/version'
26
22
 
27
23
  shared_examples_for 'configurable user agent' do
24
+ include ConnectionHelpers
25
+
28
26
  it 'should allow the user agent to be modified' do
29
27
  client.user_agent = 'Custom User Agent/1.2.3'
30
28
  client.user_agent.should == 'Custom User Agent/1.2.3'
@@ -38,18 +36,14 @@ shared_examples_for 'configurable user agent' do
38
36
  it 'should not allow the user agent to be used with bogus values' do
39
37
  (lambda do
40
38
  client.user_agent = 42
41
- client.transmit(
42
- ['GET', 'http://www.google.com/', [], []]
43
- )
39
+ client.execute(:uri=>'http://www.google.com/')
44
40
  end).should raise_error(TypeError)
45
41
  end
46
42
 
47
43
  it 'should transmit a User-Agent header when sending requests' do
48
44
  client.user_agent = 'Custom User Agent/1.2.3'
49
- request = Faraday::Request.new(:get) do |req|
50
- req.url('http://www.google.com/')
51
- end
52
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
45
+
46
+ conn = stub_connection do |stub|
53
47
  stub.get('/') do |env|
54
48
  headers = env[:request_headers]
55
49
  headers.should have_key('User-Agent')
@@ -57,15 +51,14 @@ shared_examples_for 'configurable user agent' do
57
51
  [200, {}, ['']]
58
52
  end
59
53
  end
60
- connection = Faraday.new(:url => 'https://www.google.com') do |builder|
61
- builder.adapter(:test, stubs)
62
- end
63
- client.transmit(:request => request, :connection => connection)
64
- stubs.verify_stubbed_calls
54
+ client.execute(:uri=>'http://www.google.com/', :connection => conn)
55
+ conn.verify
65
56
  end
66
57
  end
67
58
 
68
59
  describe Google::APIClient do
60
+ include ConnectionHelpers
61
+
69
62
  let(:client) { Google::APIClient.new }
70
63
 
71
64
  it 'should make its version number available' do
@@ -76,11 +69,18 @@ describe Google::APIClient do
76
69
  Signet::OAuth2::Client.should === client.authorization
77
70
  end
78
71
 
79
- it_should_behave_like 'configurable user agent'
80
-
72
+ describe 'configure for no authentication' do
73
+ before do
74
+ client.authorization = nil
75
+ end
76
+ it_should_behave_like 'configurable user agent'
77
+ end
78
+
81
79
  describe 'configured for OAuth 1' do
82
80
  before do
83
81
  client.authorization = :oauth_1
82
+ client.authorization.token_credential_key = 'abc'
83
+ client.authorization.token_credential_secret = '123'
84
84
  end
85
85
 
86
86
  it 'should use the default OAuth1 client configuration' do
@@ -101,6 +101,7 @@ describe Google::APIClient do
101
101
  describe 'configured for OAuth 2' do
102
102
  before do
103
103
  client.authorization = :oauth_2
104
+ client.authorization.access_token = '12345'
104
105
  end
105
106
 
106
107
  # TODO
@@ -109,31 +110,46 @@ describe Google::APIClient do
109
110
 
110
111
  describe 'when executing requests' do
111
112
  before do
113
+ @prediction = client.discovered_api('prediction', 'v1.2')
112
114
  client.authorization = :oauth_2
113
- @connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder|
114
- stubs = Faraday::Adapter::Test::Stubs.new do |stub|
115
- stub.get('/test') do |env|
116
- env[:request_headers]['Authorization'].should == 'Bearer 12345'
117
- end
115
+ @connection = stub_connection do |stub|
116
+ stub.post('/prediction/v1.2/training?data=12345') do |env|
117
+ env[:request_headers]['Authorization'].should == 'Bearer 12345'
118
118
  end
119
- builder.adapter(:test, stubs)
120
119
  end
121
120
  end
122
-
121
+
122
+ after do
123
+ @connection.verify
124
+ end
125
+
123
126
  it 'should use default authorization' do
124
127
  client.authorization.access_token = "12345"
125
- client.execute(:http_method => :get,
126
- :uri => 'https://www.googleapis.com/test',
127
- :connection => @connection)
128
+ client.execute(
129
+ :api_method => @prediction.training.insert,
130
+ :parameters => {'data' => '12345'},
131
+ :connection => @connection
132
+ )
128
133
  end
129
134
 
130
135
  it 'should use request scoped authorization when provided' do
131
136
  client.authorization.access_token = "abcdef"
132
137
  new_auth = Signet::OAuth2::Client.new(:access_token => '12345')
133
- client.execute(:http_method => :get,
134
- :uri => 'https://www.googleapis.com/test',
135
- :connection => @connection,
136
- :authorization => new_auth)
138
+ client.execute(
139
+ :api_method => @prediction.training.insert,
140
+ :parameters => {'data' => '12345'},
141
+ :authorization => new_auth,
142
+ :connection => @connection
143
+ )
137
144
  end
145
+
146
+ it 'should accept options in array style execute' do
147
+ client.authorization.access_token = "abcdef"
148
+ new_auth = Signet::OAuth2::Client.new(:access_token => '12345')
149
+ client.execute(
150
+ @prediction.training.insert, {'data' => '12345'}, '', {},
151
+ { :authorization => new_auth, :connection => @connection }
152
+ )
153
+ end
138
154
  end
139
155
  end
@@ -2,6 +2,52 @@ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
2
  $LOAD_PATH.uniq!
3
3
 
4
4
  require 'rspec'
5
+ require 'faraday'
6
+
7
+ module Faraday
8
+ class Connection
9
+ def verify
10
+ if app.kind_of?(Faraday::Adapter::Test)
11
+ app.stubs.verify_stubbed_calls
12
+ else
13
+ raise TypeError, "Expected test adapter"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ module ConnectionHelpers
20
+ def stub_connection(&block)
21
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
22
+ block.call(stub)
23
+ end
24
+ connection = Faraday.new do |builder|
25
+ builder.adapter(:test, stubs)
26
+ end
27
+ end
28
+ end
29
+
30
+ module JSONMatchers
31
+ class EqualsJson
32
+ def initialize(expected)
33
+ @expected = JSON.parse(expected)
34
+ end
35
+ def matches?(target)
36
+ @target = JSON.parse(target)
37
+ @target.eql?(@expected)
38
+ end
39
+ def failure_message
40
+ "expected #{@target.inspect} to be #{@expected}"
41
+ end
42
+ def negative_failure_message
43
+ "expected #{@target.inspect} not to be #{@expected}"
44
+ end
45
+ end
46
+
47
+ def be_json(expected)
48
+ EqualsJson.new(expected)
49
+ end
50
+ end
5
51
 
6
52
  RSpec.configure do |config|
7
53
  end