fake_dropbox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +8 -0
- data/README.md +97 -0
- data/Rakefile +1 -0
- data/bin/fake_dropbox +13 -0
- data/config.ru +3 -0
- data/fake_dropbox.gemspec +29 -0
- data/lib/fake_dropbox/glue.rb +33 -0
- data/lib/fake_dropbox/server.rb +83 -0
- data/lib/fake_dropbox/utils.rb +40 -0
- data/lib/fake_dropbox/version.rb +3 -0
- data/lib/fake_dropbox.rb +5 -0
- data/spec/fixtures/dummy.txt +1 -0
- data/spec/glue_spec.rb +72 -0
- data/spec/server_spec.rb +229 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/utils_spec.rb +57 -0
- metadata +138 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2011 Juliusz Gonera
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
|
+
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
fake_dropbox
|
2
|
+
============
|
3
|
+
|
4
|
+
fake_dropbox is a simple fake implementation of the Dropbox API written in Ruby
|
5
|
+
using the Sinatra framework. It can be used for developing and testing
|
6
|
+
applications that use Dropbox. There are no real authentication and users (you
|
7
|
+
are always authenticated), the server stores files on the local machine.
|
8
|
+
|
9
|
+
Can be used either as a standalone app listening on a port or intercept calls to
|
10
|
+
the real Dropbox in Ruby apps.
|
11
|
+
|
12
|
+
It partially implements [version 0](https://www.dropbox.com/developers/reference/oldapi)
|
13
|
+
of the Dropbox API which should be compatible with [version 1](https://www.dropbox.com/developers/reference/api).
|
14
|
+
If you find it useful and want to add support for more features, go ahead ;)
|
15
|
+
|
16
|
+
|
17
|
+
Installation
|
18
|
+
------------
|
19
|
+
|
20
|
+
Using RubyGems:
|
21
|
+
|
22
|
+
gem install fake_dropbox
|
23
|
+
|
24
|
+
To get the latest development version just clone the repository:
|
25
|
+
|
26
|
+
git clone git://github.com/jgonera/fake_dropbox.git
|
27
|
+
cd fake_dropbox
|
28
|
+
gem install bundler
|
29
|
+
bundle install
|
30
|
+
|
31
|
+
Then, if you want to install it as a gem:
|
32
|
+
|
33
|
+
rake install
|
34
|
+
|
35
|
+
|
36
|
+
How to use
|
37
|
+
----------
|
38
|
+
|
39
|
+
### Running the server
|
40
|
+
|
41
|
+
If you installed fake_dropbox as a gem, you should be able to run:
|
42
|
+
|
43
|
+
DROPBOX_DIR=/home/joe/somedir fake_dropbox [PORT]
|
44
|
+
|
45
|
+
You have to specify an environment variable `DROPBOX_DIR` which will point the
|
46
|
+
server to the directory on which the fake API should operate. Additionally, you
|
47
|
+
can specify a custom port (default is 4321).
|
48
|
+
|
49
|
+
### Intercepting requests in Ruby apps
|
50
|
+
|
51
|
+
You can also use this gem to intercept requests to Dropbox in your Ruby app,
|
52
|
+
without modifying any of its code or specifying a custom host or port. This
|
53
|
+
is achieved by using the [WebMock](https://github.com/bblimke/webmock) library.
|
54
|
+
|
55
|
+
The class responsible for this is `FakeDropbox::Glue`. To intercept requests to
|
56
|
+
the real Dropbox, just instantiate this class in your code:
|
57
|
+
|
58
|
+
fake_dropbox = FakeDropbox::Glue.new
|
59
|
+
|
60
|
+
You can provide an optional argument to the constructor, pointing to the
|
61
|
+
directory you want to use for your fake Dropbox:
|
62
|
+
|
63
|
+
fake_dropbox = FakeDropbox::Glue.new('/home/joe/somedir')
|
64
|
+
|
65
|
+
If you don't provide it, a temporary directory will be created in the system's
|
66
|
+
temporary path.
|
67
|
+
|
68
|
+
Moreover:
|
69
|
+
|
70
|
+
* `#dropbox_dir` returns the fake Dropbox directory.
|
71
|
+
* `#empty!` deletes everything in the `dropbox_dir` *recursively*.
|
72
|
+
Even though it should work only if the `dropbox_dir` resides inside the system's
|
73
|
+
temporary path, you should use it with caution.
|
74
|
+
|
75
|
+
A support file for Cucumber tests could look like this:
|
76
|
+
|
77
|
+
require 'fake_dropbox'
|
78
|
+
|
79
|
+
fake_dropbox = FakeDropbox::Glue.new
|
80
|
+
|
81
|
+
After do
|
82
|
+
fake_dropbox.empty!
|
83
|
+
end
|
84
|
+
|
85
|
+
### Using without installing as a gem
|
86
|
+
|
87
|
+
If you cloned the repository and you don't want to install fake_dropbox as a
|
88
|
+
gem, you can run it using `rackup` while in the fake_dropbox directory:
|
89
|
+
|
90
|
+
DROPBOX_DIR=/home/joe/somedir rackup
|
91
|
+
|
92
|
+
|
93
|
+
Copyright
|
94
|
+
---------
|
95
|
+
|
96
|
+
Copyright © 2011 Juliusz Gonera. fake_dropbox is released under the MIT license, see LICENSE for details.
|
97
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/fake_dropbox
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../lib'))
|
3
|
+
|
4
|
+
if not ENV.include? 'DROPBOX_DIR'
|
5
|
+
puts "You have to specify the DROPBOX_DIR in ENV, e.g."
|
6
|
+
puts "DROPBOX_DIR=/home/joe/somedir"
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rack'
|
11
|
+
require 'fake_dropbox/server'
|
12
|
+
|
13
|
+
Rack::Server.start(app: FakeDropbox::Server, Port: ARGV[0] || 4321)
|
data/config.ru
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require "fake_dropbox/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fake_dropbox"
|
7
|
+
s.version = FakeDropbox::VERSION
|
8
|
+
s.authors = ["Juliusz Gonera"]
|
9
|
+
s.email = ["jgonera@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/jgonera/fake_dropbox"
|
11
|
+
s.summary = %q{A simple fake implementation of the Dropbox API}
|
12
|
+
s.description = %q{Written in Ruby using the Sinatra framework. For development and testing purposes, no real authentication and users, stores files on the local machine. Can be used either as a standalone app listening on a port or intercept calls to the real Dropbox in Ruby apps.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "fake_dropbox"
|
15
|
+
s.extra_rdoc_files = ['README.md', 'LICENSE']
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'sinatra', '~> 1.2.6'
|
23
|
+
s.add_dependency 'json', '~> 1.6.1'
|
24
|
+
s.add_dependency 'rack', '~> 1.3.2'
|
25
|
+
s.add_dependency 'rack-test', '~> 0.6.1'
|
26
|
+
s.add_dependency 'webmock', '~> 1.7.7'
|
27
|
+
|
28
|
+
s.add_development_dependency 'rspec', '~> 2.7.0'
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'webmock'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'fake_dropbox/server'
|
5
|
+
|
6
|
+
module FakeDropbox
|
7
|
+
class Glue
|
8
|
+
attr_accessor :dropbox_dir
|
9
|
+
|
10
|
+
def initialize(dropbox_dir=ENV['DROPBOX_DIR'])
|
11
|
+
if dropbox_dir
|
12
|
+
raise "Directory #{dropbox_dir} doesn't exist!" unless File.exists? dropbox_dir
|
13
|
+
@dropbox_dir = dropbox_dir
|
14
|
+
else
|
15
|
+
@dropbox_dir = File.join(Dir.tmpdir, 'fake_dropbox')
|
16
|
+
Dir.mkdir(@dropbox_dir) unless File.exists? @dropbox_dir
|
17
|
+
end
|
18
|
+
|
19
|
+
ENV['DROPBOX_DIR'] = @dropbox_dir
|
20
|
+
WebMock.stub_request(:any, /.*dropbox.com.*/).to_rack(FakeDropbox::Server)
|
21
|
+
end
|
22
|
+
|
23
|
+
def empty!
|
24
|
+
if File.expand_path(@dropbox_dir).start_with? Dir.tmpdir
|
25
|
+
Dir.glob(File.join(@dropbox_dir, '*')).each do |entry|
|
26
|
+
FileUtils.remove_entry_secure entry
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise "Will not empty a directory which is outside of system's temporary path!"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'json'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'fake_dropbox/utils'
|
5
|
+
|
6
|
+
module FakeDropbox
|
7
|
+
class Server < Sinatra::Base
|
8
|
+
before do
|
9
|
+
if not request.path.start_with?('/__sinatra__')
|
10
|
+
@dropbox_dir = env['DROPBOX_DIR'] || ENV['DROPBOX_DIR']
|
11
|
+
raise 'no DROPBOX_DIR in ENV' if not @dropbox_dir
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
helpers FakeDropbox::Utils
|
16
|
+
|
17
|
+
not_found do
|
18
|
+
# only catch 404 not returned by the API
|
19
|
+
if request.env['sinatra.error'].class == Sinatra::NotFound
|
20
|
+
puts "[fake_dropbox] Unknown URI: #{request.request_method} #{request.path}"
|
21
|
+
"Unknown URI: #{request.request_method} #{request.path}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
post '/:version/oauth/request_token' do
|
26
|
+
'oauth_token_secret=fake&oauth_token=fake'
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/:version/oauth/access_token' do
|
30
|
+
'oauth_token_secret=fake&oauth_token=fake'
|
31
|
+
end
|
32
|
+
|
33
|
+
post '/:version/files/:mode*' do
|
34
|
+
dir = File.join(@dropbox_dir, params[:splat])
|
35
|
+
return status 404 unless File.exists?(dir) and File.directory?(dir)
|
36
|
+
|
37
|
+
tempfile = params[:file][:tempfile]
|
38
|
+
filename = params[:file][:filename]
|
39
|
+
file_path = File.join(params[:splat], filename)
|
40
|
+
FileUtils.cp(tempfile.path, File.join(@dropbox_dir, file_path))
|
41
|
+
File.delete(tempfile.path) if File.exists? tempfile.path
|
42
|
+
|
43
|
+
content_type :json
|
44
|
+
metadata(file_path).to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/:version/files/:mode*' do
|
48
|
+
file_path = File.join(@dropbox_dir, params[:splat])
|
49
|
+
return status 404 unless File.exists?(file_path)
|
50
|
+
|
51
|
+
IO.read(file_path)
|
52
|
+
end
|
53
|
+
|
54
|
+
get '/:version/metadata/:mode*' do
|
55
|
+
content_type :json
|
56
|
+
metadata(params[:splat][0], params['list'] == 'true').to_json
|
57
|
+
end
|
58
|
+
|
59
|
+
post '/:version/fileops/create_folder' do
|
60
|
+
dir = params[:path]
|
61
|
+
dir_path = File.join(@dropbox_dir, dir)
|
62
|
+
|
63
|
+
return status 400 unless ['dropbox', 'sandbox'].include? params[:root]
|
64
|
+
return status 403 if File.exists?(dir_path)
|
65
|
+
# seems that directories are created recursively (API docs wrong?)
|
66
|
+
#return status 404 unless File.exists?(File.dirname(dir_path))
|
67
|
+
|
68
|
+
FileUtils.mkdir_p dir_path
|
69
|
+
|
70
|
+
content_type :json
|
71
|
+
metadata(dir).to_json
|
72
|
+
end
|
73
|
+
|
74
|
+
post '/:version/fileops/delete' do
|
75
|
+
entry = safe_path(params[:path])
|
76
|
+
entry_path = File.join(@dropbox_dir, entry)
|
77
|
+
|
78
|
+
return status 404 unless File.exists?(entry_path)
|
79
|
+
|
80
|
+
FileUtils.remove_entry_secure entry_path
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module FakeDropbox
|
2
|
+
module Utils
|
3
|
+
DATE_FORMAT = '%a, %d %b %Y %H:%M:%S %z'
|
4
|
+
|
5
|
+
def metadata(path, list=false)
|
6
|
+
full_path = File.join(@dropbox_dir, path)
|
7
|
+
path.insert(0, '/') if path[0] != '/'
|
8
|
+
bytes = File.directory?(path) ? 0 : File.size(full_path)
|
9
|
+
|
10
|
+
metadata = {
|
11
|
+
thumb_exists: false,
|
12
|
+
bytes: bytes,
|
13
|
+
modified: File.mtime(full_path).strftime(DATE_FORMAT),
|
14
|
+
path: path,
|
15
|
+
is_dir: File.directory?(full_path),
|
16
|
+
size: "#{bytes} bytes",
|
17
|
+
root: "dropbox"
|
18
|
+
}
|
19
|
+
|
20
|
+
if File.directory?(full_path)
|
21
|
+
metadata[:icon] = "folder"
|
22
|
+
|
23
|
+
if list
|
24
|
+
entries = Dir.entries(full_path).reject { |x| ['.', '..'].include? x }
|
25
|
+
metadata[:contents] = entries.map do |entry|
|
26
|
+
metadata(File.join(path, entry))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
metadata[:icon] = "page_white"
|
31
|
+
end
|
32
|
+
|
33
|
+
metadata
|
34
|
+
end
|
35
|
+
|
36
|
+
def safe_path(path)
|
37
|
+
path.gsub(/(\.\.\/|\/\.\.)/, '')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/fake_dropbox.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Hello, I'm a test file
|
data/spec/glue_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "FakeDropbox::Glue" do
|
4
|
+
let(:stub_request) { double('stub_request').as_null_object }
|
5
|
+
|
6
|
+
before do
|
7
|
+
ENV.delete('DROPBOX_DIR')
|
8
|
+
Dir.stub(:tmpdir).and_return('/tmp')
|
9
|
+
File.stub(:exists?).and_return(true)
|
10
|
+
WebMock.stub(:stub_request).and_return(stub_request)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".new" do
|
14
|
+
it "stubs the Dropbox requests with WebMock" do
|
15
|
+
WebMock.should_receive(:stub_request)
|
16
|
+
stub_request.should_receive(:to_rack)
|
17
|
+
FakeDropbox::Glue.new('/tmp/somethingnonexistant')
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when invoked with an argument" do
|
21
|
+
it "sets the dropbox_dir" do
|
22
|
+
glue = FakeDropbox::Glue.new('/tmp/somethingnonexistant')
|
23
|
+
glue.dropbox_dir.should == '/tmp/somethingnonexistant'
|
24
|
+
ENV['DROPBOX_DIR'].should == glue.dropbox_dir
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when invoked with no arguments" do
|
29
|
+
it "creates dropbox_dir in system temp path" do
|
30
|
+
glue = FakeDropbox::Glue.new
|
31
|
+
glue.dropbox_dir.should == '/tmp/fake_dropbox'
|
32
|
+
ENV['DROPBOX_DIR'].should == glue.dropbox_dir
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#empty!" do
|
38
|
+
context "when dropbox_dir is in temp path" do
|
39
|
+
subject { FakeDropbox::Glue.new('/tmp/somethingnonexistant') }
|
40
|
+
|
41
|
+
it "deletes the dropbox_dir and all its contents" do
|
42
|
+
Dir.should_receive(:glob).with('/tmp/somethingnonexistant/*').and_return(['sth'])
|
43
|
+
FileUtils.should_receive(:remove_entry_secure).with('sth')
|
44
|
+
subject.empty!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples_for "dangerous" do
|
49
|
+
it "does not delete the dropbox_dir" do
|
50
|
+
FileUtils.should_not_receive(:remove_entry_secure)
|
51
|
+
begin
|
52
|
+
subject.empty!
|
53
|
+
rescue
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raises an exception" do
|
58
|
+
lambda { subject.empty! }.should raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when dropbox_dir is not in temp path" do
|
63
|
+
subject { FakeDropbox::Glue.new('/sth') }
|
64
|
+
it_behaves_like "dangerous"
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when dropbox_dir is not in temp path and is not absolute" do
|
68
|
+
subject { FakeDropbox::Glue.new('/tmp/../somethingnonexistant') }
|
69
|
+
it_behaves_like "dangerous"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'FakeDropbox::Server' do
|
4
|
+
before do
|
5
|
+
@tmpdir = Dir.mktmpdir 'fake_dropbox-test'
|
6
|
+
@env = { 'DROPBOX_DIR' => @tmpdir }
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
FileUtils.remove_entry_secure @tmpdir
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "POST /<version>/oauth/request_token" do
|
14
|
+
it "returns a fake OAuth request token" do
|
15
|
+
post "/0/oauth/request_token", {}, @env
|
16
|
+
#File.open('/home/julas/Desktop/aaa.html', 'w') {|f| f.write(last_response.body) }
|
17
|
+
last_response.should be_ok
|
18
|
+
last_response.body.should include 'oauth_token=', 'oauth_token_secret='
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "POST /<version>/oauth/access_token" do
|
23
|
+
it "returns a fake OAuth access token" do
|
24
|
+
post "/0/oauth/access_token", {}, @env
|
25
|
+
last_response.should be_ok
|
26
|
+
last_response.body.should include 'oauth_token=', 'oauth_token_secret='
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "POST /<version>/files/dropbox/<path>" do
|
31
|
+
let(:uploaded_file) { Rack::Test::UploadedFile.new(fixture_path('dummy.txt')) }
|
32
|
+
let(:params) { { file: uploaded_file } }
|
33
|
+
|
34
|
+
shared_examples_for "correct upload" do
|
35
|
+
it "saves the file in the directory" do
|
36
|
+
post "/0/files/dropbox" + path, params, @env
|
37
|
+
Dir.entries(dir).should include 'dummy.txt'
|
38
|
+
original_content = File.new(fixture_path('dummy.txt')).read
|
39
|
+
uploaded_content = File.new(File.join(dir, 'dummy.txt')).read
|
40
|
+
uploaded_content.should == original_content
|
41
|
+
end
|
42
|
+
|
43
|
+
it "deletes the temporary file (RackMultipart*)" do
|
44
|
+
post "/0/files/dropbox" + path, params, @env
|
45
|
+
tempfile = last_request.params['file'][:tempfile]
|
46
|
+
File.exists?(tempfile.path).should == false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns file metadata" do
|
50
|
+
post "/0/files/dropbox" + path, params, @env
|
51
|
+
last_response.should be_ok
|
52
|
+
metadata = JSON.parse(last_response.body)
|
53
|
+
metadata['path'].should == path + '/dummy.txt'
|
54
|
+
metadata['modified'].should include Time.new.strftime('%a, %d %b %Y %H:%M')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when the path is root" do
|
59
|
+
let (:path) { '' }
|
60
|
+
let (:dir) { @tmpdir }
|
61
|
+
|
62
|
+
it_behaves_like "correct upload"
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the path is not root" do
|
66
|
+
context "when the path exists" do
|
67
|
+
let (:path) { '/somedir' }
|
68
|
+
let (:dir) { File.join(@tmpdir, path) }
|
69
|
+
before { Dir.mkdir(dir) }
|
70
|
+
|
71
|
+
it_behaves_like "correct upload"
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when the path does not exist" do
|
75
|
+
it "returns error 404" do
|
76
|
+
post "/0/files/dropbox/incorrect", params, @env
|
77
|
+
last_response.status.should == 404
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "GET /<version>/files/dropbox/<path>" do
|
84
|
+
context "when the file exists" do
|
85
|
+
before do
|
86
|
+
File.open(File.join(@tmpdir, 'file.ext'), 'w') do |f|
|
87
|
+
f.write "This is a test."
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns file contents" do
|
92
|
+
get "/0/files/dropbox/file.ext", {}, @env
|
93
|
+
last_response.should be_ok
|
94
|
+
last_response.body.should == "This is a test."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when the file does not exist" do
|
99
|
+
it "returns error 404" do
|
100
|
+
get "/0/files/dropbox/none.ext", {}, @env
|
101
|
+
last_response.status.should == 404
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "GET /<version>/metadata/dropbox/<path>" do
|
107
|
+
it "returns metadata" do
|
108
|
+
File.open(File.join(@tmpdir, 'file.ext'), 'w')
|
109
|
+
get "/0/metadata/dropbox/file.ext", {}, @env
|
110
|
+
last_response.should be_ok
|
111
|
+
metadata = JSON.parse(last_response.body)
|
112
|
+
metadata['path'].should == '/file.ext'
|
113
|
+
metadata.should_not include 'contents'
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when the path is a directory and want a list" do
|
117
|
+
it "returns its children metadata too" do
|
118
|
+
FileUtils.cp(fixture_path('dummy.txt'), @tmpdir)
|
119
|
+
get "/0/metadata/dropbox", {list: 'true'}, @env
|
120
|
+
metadata = JSON.parse(last_response.body)
|
121
|
+
metadata.should include 'contents'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "POST /<version>/fileops/create_folder" do
|
127
|
+
shared_examples_for "creating folder" do
|
128
|
+
let(:params) { { path: path, root: 'dropbox' } }
|
129
|
+
|
130
|
+
it "creates a folder" do
|
131
|
+
post "/0/fileops/create_folder", params, @env
|
132
|
+
File.exists?(File.join(@tmpdir, path)).should == true
|
133
|
+
File.directory?(File.join(@tmpdir, path)).should == true
|
134
|
+
end
|
135
|
+
|
136
|
+
it "returns folder's metadata" do
|
137
|
+
metadata = post "/0/fileops/create_folder", params, @env
|
138
|
+
last_response.should be_ok
|
139
|
+
metadata = JSON.parse(last_response.body)
|
140
|
+
metadata['path'].should == path
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "when the path to the folder exists" do
|
145
|
+
let(:path) { '/somedir' }
|
146
|
+
|
147
|
+
it_behaves_like "creating folder"
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when the path to the folder does not exist" do
|
151
|
+
let(:path) { '/nonexistant/somedir' }
|
152
|
+
|
153
|
+
it_behaves_like "creating folder"
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when the root is neither 'dropbox' nor 'sandbox'" do
|
157
|
+
let(:params) { { path: '/somedir', root: 'wrong' } }
|
158
|
+
|
159
|
+
it "returns error 400" do
|
160
|
+
post "/0/fileops/create_folder", params, @env
|
161
|
+
last_response.status.should == 400
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# seems that directories are created recursively (API docs wrong?)
|
166
|
+
# context "when the path to the folder does not exist" do
|
167
|
+
# let(:params) { { path: '/nonexistant/somedir', root: 'dropbox' } }
|
168
|
+
#
|
169
|
+
# it "returns error 404" do
|
170
|
+
# post "/0/fileops/create_folder", params, @env
|
171
|
+
# last_response.status.should == 404
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
|
175
|
+
context "when the path already exists" do
|
176
|
+
let(:params) { { path: '/somedir', root: 'dropbox' } }
|
177
|
+
before { Dir.mkdir(File.join(@tmpdir, 'somedir')) }
|
178
|
+
|
179
|
+
it "returns error 403" do
|
180
|
+
post "/0/fileops/create_folder", params, @env
|
181
|
+
last_response.status.should == 403
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "POST /<version>/fileops/delete" do
|
187
|
+
let(:params) { { path: '/file.ext', root: 'dropbox' } }
|
188
|
+
|
189
|
+
context "when the path exists" do
|
190
|
+
|
191
|
+
shared_examples_for "deleting entry" do
|
192
|
+
it "removes the entry" do
|
193
|
+
post '/0/fileops/delete', params, @env
|
194
|
+
last_response.should be_ok
|
195
|
+
File.exists?(abs_path).should == false
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when it's a non-empty directory" do
|
200
|
+
let(:params) { { path: '/somedir', root: 'dropbox' } }
|
201
|
+
let(:abs_path) { File.join(@tmpdir, params[:path]) }
|
202
|
+
before do
|
203
|
+
Dir.mkdir(abs_path)
|
204
|
+
File.open(File.join(abs_path, 'file.ext'), 'w') { |f| f.write "Test file" }
|
205
|
+
end
|
206
|
+
|
207
|
+
it_behaves_like "deleting entry"
|
208
|
+
end
|
209
|
+
|
210
|
+
context "when it's not a non-empty directory" do
|
211
|
+
let(:params) { { path: '/file.ext', root: 'dropbox' } }
|
212
|
+
let(:abs_path) { File.join(@tmpdir, params[:path]) }
|
213
|
+
before { File.open(abs_path, 'w') { |f| f.write "Test file" } }
|
214
|
+
|
215
|
+
it_behaves_like "deleting entry"
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
context "when the path doesn't exist" do
|
221
|
+
let(:params) { { path: '/nonexistant.ext', root: 'dropbox' } }
|
222
|
+
|
223
|
+
it "returns error 404" do
|
224
|
+
post '/0/fileops/delete', params, @env
|
225
|
+
last_response.status.should == 404
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack/test'
|
4
|
+
require 'fake_dropbox'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
module TestHelpers
|
9
|
+
def fixture_path(filename='')
|
10
|
+
File.join(File.dirname(__FILE__), 'fixtures', filename)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.configure do |conf|
|
15
|
+
conf.include Rack::Test::Methods
|
16
|
+
conf.include TestHelpers
|
17
|
+
end
|
18
|
+
|
19
|
+
# ugly hack to show app errors when running rspec ;)
|
20
|
+
module FakeDropbox
|
21
|
+
class Server
|
22
|
+
configure :test do
|
23
|
+
disable :raise_errors
|
24
|
+
end
|
25
|
+
|
26
|
+
error do
|
27
|
+
e = env['sinatra.error']
|
28
|
+
puts e.to_s
|
29
|
+
puts e.backtrace.join("\n")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def app
|
35
|
+
FakeDropbox::Server
|
36
|
+
end
|
37
|
+
|
data/spec/utils_spec.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class DummyClass
|
4
|
+
include FakeDropbox::Utils
|
5
|
+
|
6
|
+
def initialize(dropbox_dir)
|
7
|
+
@dropbox_dir = dropbox_dir
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'FakeDropbox::Utils' do
|
12
|
+
subject { DummyClass.new(fixture_path) }
|
13
|
+
|
14
|
+
describe "#metadata" do
|
15
|
+
it "returns correct metadata" do
|
16
|
+
metadata = subject.metadata('/')
|
17
|
+
metadata.should include :thumb_exists, :bytes, :modified, :path,
|
18
|
+
:is_dir, :size, :root, :icon
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when path is a file" do
|
22
|
+
it "returns file metadata" do
|
23
|
+
file_path = fixture_path('dummy.txt')
|
24
|
+
metadata = subject.metadata('dummy.txt')
|
25
|
+
metadata.should_not include :contents
|
26
|
+
metadata[:is_dir].should == false
|
27
|
+
metadata[:bytes].should == File.size(file_path)
|
28
|
+
metadata[:path].should == '/dummy.txt'
|
29
|
+
metadata[:modified].should == File.mtime(file_path).strftime(FakeDropbox::Utils::DATE_FORMAT)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when path is a dir" do
|
34
|
+
it "returns dir metadata" do
|
35
|
+
metadata = subject.metadata('/')
|
36
|
+
metadata[:is_dir].should == true
|
37
|
+
metadata[:bytes].should == 0
|
38
|
+
metadata[:path].should == '/'
|
39
|
+
metadata[:modified].should == File.mtime(fixture_path).strftime(FakeDropbox::Utils::DATE_FORMAT)
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when list is true" do
|
43
|
+
it "returns the metadata of all its children too" do
|
44
|
+
metadata = subject.metadata('/', true)
|
45
|
+
metadata.should include :contents
|
46
|
+
metadata[:contents][0].should == subject.metadata('dummy.txt')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#safe_path" do
|
53
|
+
it "returns a safe path" do
|
54
|
+
subject.safe_path('../aa/../bb/..').should == 'aa/bb'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fake_dropbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Juliusz Gonera
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-27 00:00:00.000000000 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
requirement: &16756060 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.6
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *16756060
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: json
|
28
|
+
requirement: &16787980 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *16787980
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rack
|
39
|
+
requirement: &16787520 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.3.2
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *16787520
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rack-test
|
50
|
+
requirement: &16787060 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.6.1
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *16787060
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: webmock
|
61
|
+
requirement: &16786600 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ~>
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.7.7
|
67
|
+
type: :runtime
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *16786600
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: &16786140 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.7.0
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *16786140
|
81
|
+
description: Written in Ruby using the Sinatra framework. For development and testing
|
82
|
+
purposes, no real authentication and users, stores files on the local machine. Can
|
83
|
+
be used either as a standalone app listening on a port or intercept calls to the
|
84
|
+
real Dropbox in Ruby apps.
|
85
|
+
email:
|
86
|
+
- jgonera@gmail.com
|
87
|
+
executables:
|
88
|
+
- fake_dropbox
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files:
|
91
|
+
- README.md
|
92
|
+
- LICENSE
|
93
|
+
files:
|
94
|
+
- .gitignore
|
95
|
+
- .rspec
|
96
|
+
- Gemfile
|
97
|
+
- LICENSE
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- bin/fake_dropbox
|
101
|
+
- config.ru
|
102
|
+
- fake_dropbox.gemspec
|
103
|
+
- lib/fake_dropbox.rb
|
104
|
+
- lib/fake_dropbox/glue.rb
|
105
|
+
- lib/fake_dropbox/server.rb
|
106
|
+
- lib/fake_dropbox/utils.rb
|
107
|
+
- lib/fake_dropbox/version.rb
|
108
|
+
- spec/fixtures/dummy.txt
|
109
|
+
- spec/glue_spec.rb
|
110
|
+
- spec/server_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- spec/utils_spec.rb
|
113
|
+
has_rdoc: true
|
114
|
+
homepage: https://github.com/jgonera/fake_dropbox
|
115
|
+
licenses: []
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project: fake_dropbox
|
134
|
+
rubygems_version: 1.6.2
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: A simple fake implementation of the Dropbox API
|
138
|
+
test_files: []
|