dropbox 0.0.10 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +23 -3
- data/LICENSE +20 -0
- data/README.rdoc +84 -17
- data/Rakefile +39 -20
- data/VERSION +1 -1
- data/lib/dropbox.rb +41 -12
- data/lib/dropbox/api.rb +530 -0
- data/lib/dropbox/entry.rb +96 -0
- data/lib/dropbox/event.rb +109 -0
- data/lib/dropbox/memoization.rb +98 -0
- data/lib/dropbox/revision.rb +197 -0
- data/lib/dropbox/session.rb +160 -0
- data/lib/extensions/array.rb +9 -0
- data/lib/extensions/hash.rb +61 -0
- data/lib/extensions/module.rb +22 -0
- data/lib/extensions/object.rb +5 -0
- data/lib/extensions/string.rb +9 -0
- data/lib/extensions/to_bool.rb +17 -0
- data/spec/dropbox/api_spec.rb +778 -0
- data/spec/dropbox/entry_spec.rb +144 -0
- data/spec/dropbox/event_spec.rb +122 -0
- data/spec/dropbox/revision_spec.rb +367 -0
- data/spec/dropbox/session_spec.rb +148 -0
- data/spec/dropbox_spec.rb +57 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +64 -27
- data/ChangeLog.rdoc +0 -17
- data/examples/dropbox_spec.rb +0 -99
- data/lib/dropbox/dropbox.rb +0 -213
@@ -0,0 +1,160 @@
|
|
1
|
+
# Defines the Dropbox::Session class.
|
2
|
+
|
3
|
+
require 'oauth'
|
4
|
+
|
5
|
+
module Dropbox
|
6
|
+
|
7
|
+
# This class is a portal to the Dropbox API and a façade over the Ruby OAuth
|
8
|
+
# gem allowing developers to authenticate their user's Dropbox accounts.
|
9
|
+
#
|
10
|
+
# == Authenticating a user
|
11
|
+
#
|
12
|
+
# You start by creating a new instance and providing your OAuth consumer key
|
13
|
+
# and secret. You then call the authorize_url method on your new instance to
|
14
|
+
# receive the authorization URL.
|
15
|
+
#
|
16
|
+
# Once your user visits the URL, it will complete the authorization process on
|
17
|
+
# the server side. You should call the authorize method:
|
18
|
+
#
|
19
|
+
# session = Dropbox::Session.new(my_key, my_secret)
|
20
|
+
# puts "Now visit #{session.authorize_url}. Hit enter when you have completed authorization."
|
21
|
+
# gets
|
22
|
+
# session.authorize
|
23
|
+
#
|
24
|
+
# The authorize method must be called on the same instance of Dropbox::Session
|
25
|
+
# that gave you the URL. If this is unfeasible (for instance, you are doing
|
26
|
+
# this in a stateless Rails application), you can serialize the Session for
|
27
|
+
# storage (e.g., in your Rails session):
|
28
|
+
#
|
29
|
+
# def authorize
|
30
|
+
# if params[:oauth_token] then
|
31
|
+
# dropbox_session = Dropbox::Session.deserialize(session[:dropbox_session])
|
32
|
+
# dropbox_session.authorize(params)
|
33
|
+
# session[:dropbox_session] = dropbox_session.serialize # re-serialize the authenticated session
|
34
|
+
#
|
35
|
+
# redirect_to :action => 'upload'
|
36
|
+
# else
|
37
|
+
# dropbox_session = Dropbox::Session.new('your_consumer_key', 'your_consumer_secret')
|
38
|
+
# session[:dropbox_session] = dropbox_session.serialize
|
39
|
+
# redirect_to dropbox_session.authorize_url(:oauth_callback => root_url)
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# == Working with the API
|
44
|
+
#
|
45
|
+
# This class includes the methods of the Dropbox::API module. See that module
|
46
|
+
# to learn how to continue using the API.
|
47
|
+
|
48
|
+
class Session
|
49
|
+
include API
|
50
|
+
|
51
|
+
# Begins the authorization process. Provide the OAuth key and secret of your
|
52
|
+
# API account, assigned by Dropbox. This is the first step in the
|
53
|
+
# authorization process.
|
54
|
+
#
|
55
|
+
# Options:
|
56
|
+
#
|
57
|
+
# +ssl+:: If true, uses SSL to connect to the Dropbox API server.
|
58
|
+
|
59
|
+
def initialize(oauth_key, oauth_secret, options={})
|
60
|
+
@ssl = options[:ssl].to_bool
|
61
|
+
@consumer = OAuth::Consumer.new(oauth_key, oauth_secret,
|
62
|
+
:site => (@ssl ? Dropbox::SSL_HOST : Dropbox::HOST),
|
63
|
+
:request_token_path => "/#{Dropbox::VERSION}/oauth/request_token",
|
64
|
+
:authorize_path => "/#{Dropbox::VERSION}/oauth/authorize",
|
65
|
+
:access_token_path => "/#{Dropbox::VERSION}/oauth/access_token")
|
66
|
+
@request_token = @consumer.get_request_token
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns a URL that is used to complete the authorization process. Visiting
|
70
|
+
# this URL is the second step in the authorization process, after creating
|
71
|
+
# the Session instance.
|
72
|
+
|
73
|
+
def authorize_url(*args)
|
74
|
+
if authorized? then
|
75
|
+
raise AlreadyAuthorizedError, "You have already been authorized; no need to get an authorization URL."
|
76
|
+
else
|
77
|
+
return @request_token.authorize_url(*args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Authorizes a user from the information returned by Dropbox. This is the
|
82
|
+
# third step in the authorization process, after sending the user to the
|
83
|
+
# authorize_url.
|
84
|
+
#
|
85
|
+
# You can pass to this method a hash containing the keys and values of the
|
86
|
+
# OAuth parameters returned by Dropbox. An example in Rails:
|
87
|
+
#
|
88
|
+
# session.authorize :oauth_verifier => params[:oauth_verifier]
|
89
|
+
#
|
90
|
+
# Returns a boolean indicating if authentication was successful.
|
91
|
+
|
92
|
+
def authorize(options={})
|
93
|
+
@access_token = @request_token.get_access_token(options)
|
94
|
+
@request_token = nil if @access_token
|
95
|
+
return @access_token.to_bool
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns true if this session has been authorized.
|
99
|
+
|
100
|
+
def authorized?
|
101
|
+
@access_token.to_bool
|
102
|
+
end
|
103
|
+
|
104
|
+
# Serializes this object into a string that can then be recreated with the
|
105
|
+
# Dropbox::Session.deserialize method.
|
106
|
+
|
107
|
+
def serialize
|
108
|
+
if authorized? then
|
109
|
+
[ @consumer.key, @consumer.secret, authorized?, @access_token.token, @access_token.secret ].to_yaml
|
110
|
+
else
|
111
|
+
[ @consumer.key, @consumer.secret, authorized?, @request_token.token, @request_token.secret ].to_yaml
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Deserializes an instance from a string created from the serialize method.
|
116
|
+
# Returns the recreated instance.
|
117
|
+
|
118
|
+
def self.deserialize(data)
|
119
|
+
consumer_key, consumer_secret, authorized, token, token_secret = YAML.load(StringIO.new(data))
|
120
|
+
raise ArgumentError, "Must provide a properly serialized #{self.to_s} instance" unless [ consumer_key, consumer_secret, token, token_secret ].all? and authorized == true or authorized == false
|
121
|
+
|
122
|
+
session = self.new(consumer_key, consumer_secret)
|
123
|
+
if authorized then
|
124
|
+
session.instance_variable_set :@access_token, OAuth::AccessToken.new(session.instance_variable_get(:@consumer), token, token_secret)
|
125
|
+
else
|
126
|
+
session.instance_variable_set :@request_token, OAuth::RequestToken.new(session.instance_variable_get(:@consumer), token, token_secret)
|
127
|
+
end
|
128
|
+
|
129
|
+
return session
|
130
|
+
end
|
131
|
+
|
132
|
+
def inspect # :nodoc:
|
133
|
+
"#<#{self.class.to_s} #{@consumer.key} (#{'un' unless authorized?}authorized)>"
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def access_token
|
139
|
+
@access_token || raise(UnauthorizedError, "You need to authorize the Dropbox user before you can call API methods")
|
140
|
+
end
|
141
|
+
|
142
|
+
def clone_with_host(host)
|
143
|
+
session = dup
|
144
|
+
consumer = OAuth::Consumer.new(@consumer.key, @consumer.secret, :site => host)
|
145
|
+
session.instance_variable_set :@consumer, consumer
|
146
|
+
session.instance_variable_set :@access_token, OAuth::AccessToken.new(consumer, @access_token.token, @access_token.secret)
|
147
|
+
return session
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Raised when trying to call Dropbox API methods without yet having completed
|
152
|
+
# the OAuth process.
|
153
|
+
|
154
|
+
class UnauthorizedError < StandardError; end
|
155
|
+
|
156
|
+
# Raised when trying to call Dropbox::Session#authorize_url on an already
|
157
|
+
# authorized session.
|
158
|
+
|
159
|
+
class AlreadyAuthorizedError < StandardError; end
|
160
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Hash # :nodoc:
|
2
|
+
def slice(*keys) #:nodoc:
|
3
|
+
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
4
|
+
hash = self.class.new
|
5
|
+
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
6
|
+
hash
|
7
|
+
end unless method_defined?(:slice)
|
8
|
+
|
9
|
+
def symbolize_keys # :nodoc:
|
10
|
+
inject({}) do |options, (key, value)|
|
11
|
+
options[(key.to_sym rescue key) || key] = value
|
12
|
+
options
|
13
|
+
end
|
14
|
+
end unless method_defined?(:symbolize_keys)
|
15
|
+
|
16
|
+
def symbolize_keys! # :nodoc:
|
17
|
+
self.replace(self.symbolize_keys)
|
18
|
+
end unless method_defined?(:symbolize_keys!)
|
19
|
+
|
20
|
+
def symbolize_keys_recursively # :nodoc:
|
21
|
+
hsh = symbolize_keys
|
22
|
+
hsh.each { |k, v| hsh[k] = v.symbolize_keys_recursively if v.kind_of?(Hash) }
|
23
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.symbolize_keys_recursively : i } if v.kind_of?(Array) }
|
24
|
+
return hsh
|
25
|
+
end
|
26
|
+
|
27
|
+
def stringify_keys # :nodoc:
|
28
|
+
inject({}) do |options, (key, value)|
|
29
|
+
options[(key.to_s rescue key) || key] = value
|
30
|
+
options
|
31
|
+
end
|
32
|
+
end unless method_defined?(:stringify_keys)
|
33
|
+
|
34
|
+
def stringify_keys! # :nodoc:
|
35
|
+
self.replace(self.stringify_keys)
|
36
|
+
end unless method_defined?(:stringify_keys!)
|
37
|
+
|
38
|
+
def stringify_keys_recursively # :nodoc:
|
39
|
+
hsh = stringify_keys
|
40
|
+
hsh.each { |k, v| hsh[k] = v.stringify_keys_recursively if v.kind_of?(Hash) }
|
41
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.stringify_keys_recursively : i } if v.kind_of?(Array) }
|
42
|
+
return hsh
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_struct # :nodoc:
|
46
|
+
struct = Struct.new(*keys).new(*values)
|
47
|
+
# attach methods for any predicate keys, since Struct.new doesn't seem to do that
|
48
|
+
pred_keys = slice(*(keys.select { |key| key.to_s.ends_with?('?') }))
|
49
|
+
pred_keys.each do |key, val|
|
50
|
+
struct.eigenclass.send(:define_method, key.to_sym) { return val }
|
51
|
+
end
|
52
|
+
return struct
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_struct_recursively # :nodoc:
|
56
|
+
hsh = dup
|
57
|
+
hsh.each { |k, v| hsh[k] = v.to_struct_recursively if v.kind_of?(Hash) }
|
58
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.to_struct_recursively : i } if v.kind_of?(Array) }
|
59
|
+
return hsh.to_struct
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Module # :nodoc:
|
2
|
+
def alias_method_chain(target, feature) # :nodoc:
|
3
|
+
# Strip out punctuation on predicates or bang methods since
|
4
|
+
# e.g. target?_without_feature is not a valid method name.
|
5
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
6
|
+
yield(aliased_target, punctuation) if block_given?
|
7
|
+
|
8
|
+
with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
|
9
|
+
|
10
|
+
alias_method without_method, target
|
11
|
+
alias_method target, with_method
|
12
|
+
|
13
|
+
case
|
14
|
+
when public_method_defined?(without_method)
|
15
|
+
public target
|
16
|
+
when protected_method_defined?(without_method)
|
17
|
+
protected target
|
18
|
+
when private_method_defined?(without_method)
|
19
|
+
private target
|
20
|
+
end
|
21
|
+
end unless method_defined?(:alias_method_chain)
|
22
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class String # :nodoc:
|
2
|
+
def starts_with?(prefix) # :nodoc:
|
3
|
+
self[0, prefix.length] == prefix
|
4
|
+
end unless method_defined?(:starts_with?)
|
5
|
+
|
6
|
+
def ends_with?(suffix) # :nodoc:
|
7
|
+
self[-suffix.length, suffix.length] == suffix
|
8
|
+
end unless method_defined?(:ends_with?)
|
9
|
+
end
|
@@ -0,0 +1,778 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
def url_args(url)
|
4
|
+
return {} unless url.include?('?')
|
5
|
+
_, back = url.split('?')
|
6
|
+
return {} unless back
|
7
|
+
back.split('&').map { |comp| comp.split('=') }.to_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def should_receive_api_method_with_arguments(object, method, api_method, arguments, response, path=nil, root=nil)
|
11
|
+
object.should_receive(method).once do |url|
|
12
|
+
front = url.split('?').first
|
13
|
+
front.should eql("#{Dropbox::ALTERNATE_HOSTS[api_method] || Dropbox::HOST}/#{Dropbox::VERSION}/#{api_method}#{'/' + root if root}#{'/' + path if path}")
|
14
|
+
|
15
|
+
query_params = url_args(url)
|
16
|
+
query_params.each { |key, val| val.should eql(arguments[key.to_sym]) }
|
17
|
+
arguments.each { |key, _| query_params.should include(key.to_s) }
|
18
|
+
response
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_for_upload_testing
|
23
|
+
@consumer_mock.stub!(:key).and_return("consumer key")
|
24
|
+
@consumer_mock.stub!(:secret).and_return("consumer secret")
|
25
|
+
@consumer_mock.stub!(:sign!).and_return { |req, _| req.stub!(:to_hash).and_return('authorization' => ["Oauth", "test"]) }
|
26
|
+
|
27
|
+
@token_mock.stub!(:token).and_return("access token")
|
28
|
+
@token_mock.stub!(:secret).and_return("access secret")
|
29
|
+
|
30
|
+
@response.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(true)
|
31
|
+
@response.stub!(:body).and_return('{"test":"val"}')
|
32
|
+
|
33
|
+
Net::HTTP.stub!(:start).and_return(@response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def response_acts_as(subclass)
|
37
|
+
@response.stub(:kind_of?).and_return(false)
|
38
|
+
@response.stub(:kind_of?).with(subclass).and_return(true) if subclass
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Dropbox::API do
|
42
|
+
before :each do
|
43
|
+
@consumer_mock = mock("OAuth::Consumer")
|
44
|
+
token_mock = mock("OAuth::RequestToken")
|
45
|
+
@token_mock = mock("OAuth::AccessToken")
|
46
|
+
token_mock.stub!(:get_access_token).and_return(@token_mock)
|
47
|
+
@consumer_mock.stub!(:get_request_token).and_return(token_mock)
|
48
|
+
OAuth::Consumer.stub!(:new).and_return(@consumer_mock)
|
49
|
+
|
50
|
+
@session = Dropbox::Session.new('foo', 'bar')
|
51
|
+
@session.authorize
|
52
|
+
|
53
|
+
@response = mock('Net::HTTPResponse')
|
54
|
+
@response.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(true)
|
55
|
+
@response.stub!(:code).and_return(200)
|
56
|
+
@response.stub!(:body).and_return("response body")
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#account" do
|
60
|
+
it "should call the /account/info API method" do
|
61
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
62
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'account/info', {}, @response
|
63
|
+
@session.account
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should convert the result into a struct" do
|
67
|
+
@response.stub!(:body).and_return( { :foo => :bar, :baz => { :hey => :you } }.to_json)
|
68
|
+
@token_mock.stub!(:get).and_return(@response)
|
69
|
+
result = @session.account
|
70
|
+
result.foo.should eql('bar')
|
71
|
+
result.baz.hey.should eql('you')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#download" do
|
76
|
+
it "should call the files API method" do
|
77
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'files', {}, @response, 'path/to/file', 'sandbox'
|
78
|
+
@session.download "path/to/file"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should strip a leading slash" do
|
82
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'files', {}, @response, 'path/to/file', 'sandbox'
|
83
|
+
@session.download "/path/to/file"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return the body of the response" do
|
87
|
+
@token_mock.stub!(:get).and_return(@response)
|
88
|
+
@session.download("path/to/file").should eql("response body")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should check the path" do
|
92
|
+
path = "test/path"
|
93
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
94
|
+
@token_mock.stub!(:get).and_return(@response)
|
95
|
+
|
96
|
+
@session.download(path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#copy" do
|
101
|
+
before :each do
|
102
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should call the fileops/copy API method" do
|
106
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/copy', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
107
|
+
@session.copy 'source/file', 'dest/file'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return the metadata as a struct" do
|
111
|
+
@response.stub!(:body).and_return( { :foo => :bar, :baz => { :hey => :you } }.to_json)
|
112
|
+
@token_mock.stub!(:post).and_return(@response)
|
113
|
+
|
114
|
+
result = @session.copy('a', 'b')
|
115
|
+
result.foo.should eql('bar')
|
116
|
+
result.baz.hey.should eql('you')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should strip a leading slash from source" do
|
120
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/copy', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
121
|
+
@session.copy '/source/file', 'dest/file'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should strip a leading slash from target" do
|
125
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/copy', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
126
|
+
@session.copy 'source/file', '/dest/file'
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should set the target file name to the source file name if the target is a directory path" do
|
130
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/copy', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
131
|
+
@session.copy 'source/file', 'dest/'
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should re-raise 404's as FileNotFoundErrors" do
|
135
|
+
response_acts_as Net::HTTPNotFound
|
136
|
+
@token_mock.stub!(:post).and_return(@response)
|
137
|
+
|
138
|
+
lambda { @session.copy('a', 'b') }.should raise_error(Dropbox::FileNotFoundError)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should re-raise 403's as FileExistsErrors" do
|
142
|
+
response_acts_as Net::HTTPForbidden
|
143
|
+
@token_mock.stub!(:post).and_return(@response)
|
144
|
+
|
145
|
+
lambda { @session.copy('a', 'b') }.should raise_error(Dropbox::FileExistsError)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should raise other errors unmodified" do
|
149
|
+
@response.stub(:kind_of?).and_return(false)
|
150
|
+
@token_mock.stub!(:post).and_return(@response)
|
151
|
+
|
152
|
+
lambda { @session.copy('a', 'b') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should check the source and destination paths" do
|
156
|
+
source_path = "source/path"
|
157
|
+
dest_path = "dest/path"
|
158
|
+
Dropbox.should_receive(:check_path).once.with(source_path).and_return(source_path)
|
159
|
+
Dropbox.should_receive(:check_path).once.with(dest_path).and_return(dest_path)
|
160
|
+
@token_mock.stub!(:post).and_return(@response)
|
161
|
+
|
162
|
+
@session.copy(source_path, dest_path)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#move" do
|
167
|
+
before :each do
|
168
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should call the fileops/move API method" do
|
172
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/move', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
173
|
+
@session.move 'source/file', 'dest/file'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should return the metadata as a struct" do
|
177
|
+
@response.stub!(:body).and_return( { :foo => :bar, :baz => { :hey => :you } }.to_json)
|
178
|
+
@token_mock.stub!(:post).and_return(@response)
|
179
|
+
|
180
|
+
result = @session.move('a', 'b')
|
181
|
+
result.foo.should eql('bar')
|
182
|
+
result.baz.hey.should eql('you')
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should strip a leading slash from source" do
|
186
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/move', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
187
|
+
@session.move '/source/file', 'dest/file'
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should strip a leading slash from target" do
|
191
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/move', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
192
|
+
@session.move 'source/file', '/dest/file'
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should set the target file name to the source file name if the target is a directory path" do
|
196
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/move', { :from_path => 'source%2Ffile', :to_path => 'dest%2Ffile', :root => 'sandbox' }, @response
|
197
|
+
@session.move 'source/file', 'dest/'
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should re-raise 404's as FileNotFoundErrors" do
|
201
|
+
response_acts_as Net::HTTPNotFound
|
202
|
+
@token_mock.stub!(:post).and_return(@response)
|
203
|
+
|
204
|
+
lambda { @session.move('a', 'b') }.should raise_error(Dropbox::FileNotFoundError)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should re-raise 403's as FileExistsErrors" do
|
208
|
+
response_acts_as Net::HTTPForbidden
|
209
|
+
@token_mock.stub!(:post).and_return(@response)
|
210
|
+
|
211
|
+
lambda { @session.move('a', 'b') }.should raise_error(Dropbox::FileExistsError)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should raise other errors unmodified" do
|
215
|
+
response_acts_as nil
|
216
|
+
@token_mock.stub!(:post).and_return(@response)
|
217
|
+
|
218
|
+
lambda { @session.move('a', 'b') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should check the source and destination paths" do
|
222
|
+
source_path = "source/path"
|
223
|
+
dest_path = "dest/path"
|
224
|
+
Dropbox.should_receive(:check_path).once.with(source_path).and_return(source_path)
|
225
|
+
Dropbox.should_receive(:check_path).once.with(dest_path).and_return(dest_path)
|
226
|
+
@token_mock.stub!(:post).and_return(@response)
|
227
|
+
|
228
|
+
@session.move(source_path, dest_path)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "#rename" do
|
233
|
+
it "should raise an error if the new name has a slash in it" do
|
234
|
+
lambda { @session.rename 'file', 'new/name' }.should raise_error(ArgumentError)
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should call move with the appropriate path and return the result of the call" do
|
238
|
+
@session.should_receive(:move).once.with('old/path/to/file', 'old/path/to/new_file', :mode => :sandbox).and_return(@response)
|
239
|
+
@session.rename('old/path/to/file', 'new_file', :mode => :sandbox).should eql(@response)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#create_folder" do
|
244
|
+
before :each do
|
245
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should call the fileops/create_folder API method" do
|
249
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/create_folder', { :path => 'new%2Ffolder', :root => 'sandbox' }, @response
|
250
|
+
@session.create_folder 'new/folder'
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should return the metadata as a struct" do
|
254
|
+
@response.stub!(:body).and_return( { :foo => :bar, :baz => { :hey => :you } }.to_json)
|
255
|
+
@token_mock.stub!(:post).and_return(@response)
|
256
|
+
|
257
|
+
result = @session.create_folder('a')
|
258
|
+
result.foo.should eql('bar')
|
259
|
+
result.baz.hey.should eql('you')
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should strip a leading slash from the path" do
|
263
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/create_folder', { :path => 'new%2Ffolder', :root => 'sandbox' }, @response
|
264
|
+
@session.create_folder '/new/folder'
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should strip a trailing slash from the path" do
|
268
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/create_folder', { :path => 'new%2Ffolder', :root => 'sandbox' }, @response
|
269
|
+
@session.create_folder 'new/folder/'
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should re-raise 403's as FileExistsErrors" do
|
273
|
+
response_acts_as Net::HTTPForbidden
|
274
|
+
@token_mock.stub!(:post).and_return(@response)
|
275
|
+
|
276
|
+
lambda { @session.create_folder('a') }.should raise_error(Dropbox::FileExistsError)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should raise other errors unmodified" do
|
280
|
+
response_acts_as nil
|
281
|
+
@token_mock.stub!(:post).and_return(@response)
|
282
|
+
|
283
|
+
lambda { @session.create_folder('a') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should check the path" do
|
287
|
+
path = "source/path"
|
288
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
289
|
+
@token_mock.stub!(:post).and_return(@response)
|
290
|
+
|
291
|
+
@session.create_folder(path)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "#delete" do
|
296
|
+
it "should call the API method fileops/delete" do
|
297
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/delete', { :path => 'some%2Ffile', :root => 'sandbox' }, @response
|
298
|
+
@session.delete 'some/file'
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should return true" do
|
302
|
+
@token_mock.stub!(:post).and_return(@response)
|
303
|
+
@session.delete('some/file').should be_true
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should strip a leading slash from the path" do
|
307
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/delete', { :path => 'some%2Ffile', :root => 'sandbox' }, @response
|
308
|
+
@session.delete '/some/file'
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should strip a trailing slash from the path" do
|
312
|
+
should_receive_api_method_with_arguments @token_mock, :post, 'fileops/delete', { :path => 'some%2Ffile', :root => 'sandbox' }, @response
|
313
|
+
@session.delete 'some/file/'
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should re-raise 404's as FileNotFoundErrors" do
|
317
|
+
response_acts_as Net::HTTPNotFound
|
318
|
+
@token_mock.stub!(:post).and_return(@response)
|
319
|
+
|
320
|
+
lambda { @session.delete('a') }.should raise_error(Dropbox::FileNotFoundError)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should raise other errors unmodified" do
|
324
|
+
response_acts_as nil
|
325
|
+
@token_mock.stub!(:post).and_return(@response)
|
326
|
+
|
327
|
+
lambda { @session.delete('a') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should check the path" do
|
331
|
+
path = "source/path"
|
332
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
333
|
+
@token_mock.stub!(:post).and_return(@response)
|
334
|
+
|
335
|
+
@session.delete(path)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "#link" do
|
340
|
+
before :each do
|
341
|
+
@response.stub!(:code).and_return(304)
|
342
|
+
response_acts_as Net::HTTPFound
|
343
|
+
@response.stub!(:[]).and_return("new location")
|
344
|
+
end
|
345
|
+
|
346
|
+
it "should call the API method links" do
|
347
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'links', {}, @response, 'some/file', 'sandbox'
|
348
|
+
@session.link 'some/file'
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should strip a leading slash" do
|
352
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'links', {}, @response, 'some/file', 'sandbox'
|
353
|
+
@session.link '/some/file'
|
354
|
+
end
|
355
|
+
|
356
|
+
it "should rescue 304's and return the Location header" do
|
357
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'links', {}, @response, 'some/file', 'sandbox'
|
358
|
+
lambda { @session.link('some/file').should eql("new location") }.should_not raise_error
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should re-raise other errors unmodified" do
|
362
|
+
response_acts_as nil
|
363
|
+
@token_mock.stub!(:get).and_return(@response)
|
364
|
+
lambda { @session.link('a') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should check the path" do
|
368
|
+
path = "source/path"
|
369
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
370
|
+
@token_mock.stub!(:get).and_return(@response)
|
371
|
+
|
372
|
+
@session.link(path)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe "#metadata" do
|
377
|
+
before :each do
|
378
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should call the API method metadata" do
|
382
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'metadata', { :list => 'true' }, @response, 'some/file', 'sandbox'
|
383
|
+
@session.metadata 'some/file'
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should strip a leading slash" do
|
387
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'metadata', { :list => 'true' }, @response, 'some/file', 'sandbox'
|
388
|
+
@session.metadata '/some/file'
|
389
|
+
end
|
390
|
+
|
391
|
+
it "should set file_limit if :limit is set" do
|
392
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'metadata', { :list => 'true', :file_limit => '123' }, @response, 'some/file', 'sandbox'
|
393
|
+
@session.metadata 'some/file', :limit => 123
|
394
|
+
end
|
395
|
+
|
396
|
+
it "should set list=false if :suppress_list is set" do
|
397
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'metadata', { :list => 'false' }, @response, 'some/file', 'sandbox'
|
398
|
+
@session.metadata 'some/file', :suppress_list => true
|
399
|
+
end
|
400
|
+
|
401
|
+
it "should rescue 406's and re-raise them as TooManyEntriesErrors" do
|
402
|
+
response_acts_as Net::HTTPNotAcceptable
|
403
|
+
@token_mock.stub!(:get).and_return(@response)
|
404
|
+
|
405
|
+
lambda { @session.metadata('a') }.should raise_error(Dropbox::TooManyEntriesError)
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should rescue 404's and re-raise them as FileNotFoundErrors" do
|
409
|
+
response_acts_as Net::HTTPNotFound
|
410
|
+
@token_mock.stub!(:get).and_return(@response)
|
411
|
+
|
412
|
+
lambda { @session.metadata('a') }.should raise_error(Dropbox::FileNotFoundError)
|
413
|
+
end
|
414
|
+
|
415
|
+
it "should re-raise other errors unmodified" do
|
416
|
+
response_acts_as nil
|
417
|
+
@token_mock.stub!(:get).and_return(@response)
|
418
|
+
|
419
|
+
lambda { @session.metadata('a') }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should check the path" do
|
423
|
+
path = "source/path"
|
424
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
425
|
+
@token_mock.stub!(:get).and_return(@response)
|
426
|
+
|
427
|
+
@session.metadata(path)
|
428
|
+
end
|
429
|
+
|
430
|
+
it "should recursively convert the modification date into a Time" do
|
431
|
+
time = Time.now
|
432
|
+
@response.stub!(:body).and_return({ :modified => time.to_s, :hsh => { :modified => time.to_s } }.to_json)
|
433
|
+
@token_mock.stub!(:get).and_return(@response)
|
434
|
+
|
435
|
+
response = @session.metadata('path')
|
436
|
+
|
437
|
+
response.modified.should be_kind_of(Time)
|
438
|
+
response.modified.to_i.should == time.to_i
|
439
|
+
response.hsh.modified.should be_kind_of(Time)
|
440
|
+
response.hsh.modified.to_i.should == time.to_i
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should add a directory? item recursively" do
|
444
|
+
@response.stub!(:body).and_return({ :is_dir => true, :hsh => { :is_dir => false } }.to_json)
|
445
|
+
@token_mock.stub!(:get).and_return(@response)
|
446
|
+
|
447
|
+
response = @session.metadata('path')
|
448
|
+
|
449
|
+
response.directory?.should be_true
|
450
|
+
response.hsh.directory?.should be_false
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
describe "#list" do
|
455
|
+
before :each do
|
456
|
+
@response = mock('metadata')
|
457
|
+
end
|
458
|
+
|
459
|
+
it "should call the metadata method and return the contents attribute" do
|
460
|
+
@response.should_receive(:contents).once.and_return([ 'contents' ])
|
461
|
+
@session.should_receive(:metadata).once.with('my/file', an_instance_of(Hash)).and_return(@response)
|
462
|
+
|
463
|
+
@session.list('my/file').should == [ 'contents' ]
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should not allow suppress_list to be set to true" do
|
467
|
+
@response.stub!(:contents)
|
468
|
+
@session.should_receive(:metadata).once.with('my/file', hash_including(:hash => true, :suppress_list => false)).and_return(@response)
|
469
|
+
|
470
|
+
@session.list('my/file', :suppress_list => true, :hash => true)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
describe "#upload" do
|
475
|
+
before :each do
|
476
|
+
stub_for_upload_testing
|
477
|
+
end
|
478
|
+
|
479
|
+
it "should check the path" do
|
480
|
+
path = "dest/path"
|
481
|
+
Dropbox.should_receive(:check_path).once.with(path).and_return(path)
|
482
|
+
@session.upload(__FILE__, path)
|
483
|
+
end
|
484
|
+
|
485
|
+
describe "parameters" do
|
486
|
+
describe "given a File object" do
|
487
|
+
before :each do
|
488
|
+
@file = File.open(__FILE__)
|
489
|
+
end
|
490
|
+
|
491
|
+
after :each do
|
492
|
+
@file.close
|
493
|
+
end
|
494
|
+
|
495
|
+
it "should use the File object as the stream" do
|
496
|
+
UploadIO.should_receive(:convert!).once.with(@file, anything, File.basename(__FILE__), __FILE__)
|
497
|
+
@session.upload @file, 'remote/'
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
describe "given a String object" do
|
502
|
+
before :each do
|
503
|
+
@string = __FILE__
|
504
|
+
@file = File.new(__FILE__)
|
505
|
+
File.should_receive(:new).once.with(@string).and_return(@file)
|
506
|
+
end
|
507
|
+
|
508
|
+
it "should use the file at that path as the stream" do
|
509
|
+
UploadIO.should_receive(:convert!).once.with(@file, anything, File.basename(__FILE__), __FILE__)
|
510
|
+
@session.upload @string, 'remote/'
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
it "should raise an error if given an unknown argument type" do
|
515
|
+
lambda { @session.upload 123, 'path' }.should raise_error(ArgumentError)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
describe "request" do
|
520
|
+
before :each do
|
521
|
+
@request = mock('Net::HTTPRequest')
|
522
|
+
@request.stub!(:[]=)
|
523
|
+
end
|
524
|
+
|
525
|
+
it "should strip a leading slash from the remote path" do
|
526
|
+
Net::HTTP::Post::Multipart.should_receive(:new).once do |*args|
|
527
|
+
args.first.should eql("/#{Dropbox::VERSION}/files/sandbox/path")
|
528
|
+
@request
|
529
|
+
end
|
530
|
+
|
531
|
+
@session.upload __FILE__, '/path'
|
532
|
+
end
|
533
|
+
|
534
|
+
it "should call the files API method" do
|
535
|
+
Net::HTTP::Post::Multipart.should_receive(:new).once do |*args|
|
536
|
+
args.first.should eql("/#{Dropbox::VERSION}/files/sandbox/path/to/file")
|
537
|
+
@request
|
538
|
+
end
|
539
|
+
|
540
|
+
@session.upload __FILE__, 'path/to/file'
|
541
|
+
end
|
542
|
+
|
543
|
+
it "should use the sandbox root if specified" do
|
544
|
+
Net::HTTP::Post::Multipart.should_receive(:new).once do |*args|
|
545
|
+
args.first.should eql("/#{Dropbox::VERSION}/files/sandbox/path/to/file")
|
546
|
+
@request
|
547
|
+
end
|
548
|
+
|
549
|
+
@session.upload __FILE__, 'path/to/file', :mode => :sandbox
|
550
|
+
end
|
551
|
+
|
552
|
+
it "should set the authorization content header to the signed OAuth request" do
|
553
|
+
Net::HTTP::Post::Multipart.stub!(:new).and_return(@request)
|
554
|
+
@request.should_receive(:[]=).once.with('authorization', 'Oauth, test')
|
555
|
+
|
556
|
+
@session.upload __FILE__, 'blah'
|
557
|
+
end
|
558
|
+
|
559
|
+
it "should create a multipart POST request with the 'file' parameter set to the file of type application/octet-stream" do
|
560
|
+
Net::HTTP::Post::Multipart.should_receive(:new).once.with("/#{Dropbox::VERSION}/files/sandbox/hello", hash_including('file' => an_instance_of(File))).and_return(@request)
|
561
|
+
|
562
|
+
@session.upload __FILE__, 'hello'
|
563
|
+
end
|
564
|
+
|
565
|
+
it "should send the request" do
|
566
|
+
uri = URI.parse(Dropbox::ALTERNATE_HOSTS['files'])
|
567
|
+
Net::HTTP.should_receive(:start).once.with(uri.host, uri.port).and_return(@response)
|
568
|
+
|
569
|
+
@session.upload __FILE__, 'test'
|
570
|
+
end
|
571
|
+
|
572
|
+
it "should send an SSL request" do
|
573
|
+
@session = Dropbox::Session.new('foo', 'bar', :ssl => true)
|
574
|
+
@session.authorize
|
575
|
+
|
576
|
+
uri = URI.parse(Dropbox::ALTERNATE_SSL_HOSTS['files'])
|
577
|
+
Net::HTTP.should_receive(:start).once.with(uri.host, uri.port).and_return(@response)
|
578
|
+
|
579
|
+
@session.upload __FILE__, 'test'
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
describe "#event_metadata" do
|
585
|
+
it "should call the API method event_metadata" do
|
586
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
587
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'event_metadata', { :root => 'sandbox', :target_events => 'event_json' }, @response
|
588
|
+
@session.event_metadata 'event_json'
|
589
|
+
end
|
590
|
+
|
591
|
+
it "should return the JSON-parsed response" do
|
592
|
+
resp = { :some => { :json => 123 } }
|
593
|
+
@response.stub!(:body).and_return(resp.to_json)
|
594
|
+
@token_mock.stub!(:get).and_return(@response)
|
595
|
+
@session.event_metadata('event_json').should == resp
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
describe "#event_content" do
|
600
|
+
it "should call the API method event_content" do
|
601
|
+
@response.stub!(:body).and_return('content')
|
602
|
+
@response.stub!(:header).and_return('X-Dropbox-Metadata' => '{"a":"b"}')
|
603
|
+
should_receive_api_method_with_arguments @token_mock, :get, 'event_content', { :root => 'sandbox', :target_event => '1%3A2%3A3' }, @response
|
604
|
+
@session.event_content '1:2:3'
|
605
|
+
end
|
606
|
+
|
607
|
+
it "should return the content body and the X-Dropbox-Metadata header JSON" do
|
608
|
+
resp = { 'some' => { 'json' => 123 } }
|
609
|
+
body = "Content here"
|
610
|
+
@response.stub!(:body).and_return(body)
|
611
|
+
@response.should_receive(:header).once.and_return('X-Dropbox-Metadata' => resp.to_json)
|
612
|
+
@token_mock.stub!(:get).and_return(@response)
|
613
|
+
|
614
|
+
@session.event_content('1:2:3').should == [ body, resp ]
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
{
|
619
|
+
:account => [ :get ],
|
620
|
+
:upload => [ :post, __FILE__, 'path/here' ],
|
621
|
+
:copy => [ :post, 'source/file', 'dest/file' ],
|
622
|
+
:move => [ :post, 'source/file', 'dest/file' ],
|
623
|
+
:create_folder => [ :post, 'new/folder' ],
|
624
|
+
:metadata => [ :get, 'some/file' ],
|
625
|
+
:event_metadata => [ :get, 'some_json' ]
|
626
|
+
}.each do |meth, args|
|
627
|
+
describe meth do
|
628
|
+
before :each do
|
629
|
+
stub_for_upload_testing
|
630
|
+
@token_mock.stub!(args.first).and_return(@response)
|
631
|
+
end
|
632
|
+
|
633
|
+
it "should parse the JSON response if successful" do
|
634
|
+
@response.stub!(:body).and_return('{"test":"json"}')
|
635
|
+
@session.send(meth, *(args[1..-1]))
|
636
|
+
end
|
637
|
+
|
638
|
+
it "should raise a ParseError if the JSON is invalid" do
|
639
|
+
@response.stub!(:body).and_return('sdgsdg')
|
640
|
+
lambda { @session.send(meth, *(args[1..-1])) }.should raise_error(Dropbox::ParseError)
|
641
|
+
end
|
642
|
+
|
643
|
+
it "should raise UnsuccessfulResponseError if unsuccessful" do
|
644
|
+
@response.stub!(:kind_of?).and_return(false)
|
645
|
+
lambda { @session.send(meth, *(args[1..-1])) }.should raise_error(Dropbox::UnsuccessfulResponseError)
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
describe "#mode" do
|
651
|
+
it "should return the correct mode" do
|
652
|
+
@session.mode = :dropbox
|
653
|
+
@session.mode.should eql(:dropbox)
|
654
|
+
|
655
|
+
@session.mode = :sandbox
|
656
|
+
@session.mode.should eql(:sandbox)
|
657
|
+
|
658
|
+
@session.mode = :metadata_only
|
659
|
+
@session.mode.should eql(:metadata_only)
|
660
|
+
end
|
661
|
+
|
662
|
+
it "should be :sandbox by default" do
|
663
|
+
@session.mode.should eql(:sandbox)
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
describe "#mode=" do
|
668
|
+
it "set the API root" do
|
669
|
+
@session.mode = :dropbox
|
670
|
+
@token_mock.should_receive(:get).once do |url, *rest|
|
671
|
+
url.should include('/dropbox')
|
672
|
+
url.should_not include('/sandbox')
|
673
|
+
@response
|
674
|
+
end
|
675
|
+
@session.download 'file'
|
676
|
+
|
677
|
+
@session.mode = :sandbox
|
678
|
+
@token_mock.should_receive(:get).once do |url, *rest|
|
679
|
+
url.should include('/sandbox')
|
680
|
+
url.should_not include('/dropbox')
|
681
|
+
@response
|
682
|
+
end
|
683
|
+
@session.download 'file'
|
684
|
+
|
685
|
+
@session.mode = :metadata_only
|
686
|
+
@token_mock.should_receive(:get).once do |url, *rest|
|
687
|
+
url.should include('/dropbox')
|
688
|
+
url.should_not include('/sandbox')
|
689
|
+
@response
|
690
|
+
end
|
691
|
+
@session.download 'file'
|
692
|
+
end
|
693
|
+
|
694
|
+
it "should raise for invalid modes" do
|
695
|
+
lambda { @session.mode = :foo }.should raise_error(ArgumentError)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
{
|
700
|
+
:account => [],
|
701
|
+
:copy => [ 'foo', 'bar' ],
|
702
|
+
:create_folder => [ 'foo' ],
|
703
|
+
:delete => [ 'foo' ],
|
704
|
+
:move => [ 'foo', 'bar' ],
|
705
|
+
:link => [ 'foo' ],
|
706
|
+
:metadata => [ 'foo'],
|
707
|
+
:download => [ 'foo' ],
|
708
|
+
:event_metadata => [ 'foo' ],
|
709
|
+
:event_content => [ 'foo' ]
|
710
|
+
}.each do |root_method, args|
|
711
|
+
describe ".#{root_method}" do
|
712
|
+
before :each do
|
713
|
+
@session = Dropbox::Session.new('foo', 'bar', :ssl => true)
|
714
|
+
@session.authorize
|
715
|
+
|
716
|
+
@token_mock.stub!(:get).and_return(@response)
|
717
|
+
@token_mock.stub!(:post).and_return(@response)
|
718
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
719
|
+
@response.stub!(:header).and_return('X-Dropbox-Metadata' => '{"a":"b"}')
|
720
|
+
end
|
721
|
+
|
722
|
+
it "should use the SSL host if :ssl => true is given to the constructor" do
|
723
|
+
Dropbox.should_receive(:api_url).once do |*args|
|
724
|
+
args.last[:ssl].should be_true
|
725
|
+
"http://www.example.com/test"
|
726
|
+
end
|
727
|
+
|
728
|
+
@session.send(root_method, *args)
|
729
|
+
end
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
{
|
734
|
+
:download => [ :get, 'path/to/file' ],
|
735
|
+
:copy => [ :post, 'source/file', 'dest/file' ],
|
736
|
+
:move => [ :post, 'source/file', 'dest/file' ],
|
737
|
+
:create_folder => [ :post, 'new/folder' ],
|
738
|
+
:delete => [ :post, 'some/file' ],
|
739
|
+
:link => [ :get, 'some/file' ],
|
740
|
+
:metadata => [ :get, 'some/file' ],
|
741
|
+
:event_metadata => [ :get, 'some_json' ],
|
742
|
+
:event_content => [ :get, '1:2:3' ]
|
743
|
+
}.each do |root_method, args|
|
744
|
+
describe ".#{root_method}" do
|
745
|
+
before :each do
|
746
|
+
@response.stub!(:body).and_return('{"a":"b"}')
|
747
|
+
@response.stub!(:header).and_return('X-Dropbox-Metadata' => '{"a":"b"}')
|
748
|
+
end
|
749
|
+
|
750
|
+
it "should use the dropbox root if in dropbox mode" do
|
751
|
+
@token_mock.should_receive(args.first).once do |url, *rest|
|
752
|
+
url.should_not include('sandbox')
|
753
|
+
@response
|
754
|
+
end
|
755
|
+
@session.mode = :dropbox
|
756
|
+
@session.send(root_method, *(args[1..-1]))
|
757
|
+
end
|
758
|
+
|
759
|
+
it "should use the sandbox root if in sandbox mode" do
|
760
|
+
@token_mock.should_receive(args.first).once do |url, *rest|
|
761
|
+
url.should include('sandbox')
|
762
|
+
@response
|
763
|
+
end
|
764
|
+
@session.mode = :sandbox
|
765
|
+
@session.send(root_method, *(args[1..-1]))
|
766
|
+
end
|
767
|
+
|
768
|
+
it "should use the dropbox root if in metadata mode" do
|
769
|
+
@token_mock.should_receive(args.first).once do |url, *rest|
|
770
|
+
url.should_not include('sandbox')
|
771
|
+
@response
|
772
|
+
end
|
773
|
+
@session.mode = :metadata_only
|
774
|
+
@session.send(root_method, *(args[1..-1]))
|
775
|
+
end
|
776
|
+
end
|
777
|
+
end
|
778
|
+
end
|