dropbox 0.0.10 → 1.0.0
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.
- 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
|