refactor tests
[coquelicot.git] / test_coquelicot.rb
1 $:.unshift File.join(File.dirname(__FILE__), '../rack-test/lib')
2 $:.unshift File.join(File.dirname(__FILE__), '../timecop/lib')
3
4 require 'sinatra'
5 require 'coquelicot'
6 require 'spec'
7 require 'rack/test'
8 require 'timecop'
9 require 'hpricot'
10 require 'tmpdir'
11
12 UPLOAD_PASSWORD = 'secret'
13
14 set :environment, :test
15 set :upload_password, Digest::SHA1.hexdigest(UPLOAD_PASSWORD)
16
17 describe 'Coquelicot' do
18   include Rack::Test::Methods
19
20   def app
21     Sinatra::Application
22   end
23
24   def upload(opts={})
25     opts = { :file => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
26              :upload_password => UPLOAD_PASSWORD
27            }.merge(opts)
28     post '/upload', opts
29     return nil unless last_response.redirect?
30     follow_redirect!
31     last_response.should be_ok
32     doc = Hpricot(last_response.body)
33     return (doc/'a').collect { |a| a.attributes['href'] }.
34              select { |h| h.start_with? "http://#{last_request.host}/" }[0]
35   end
36
37   before do
38     Depot.instance.path = Dir.mktmpdir('coquelicot') #"#{Time.now.to_f}"
39   end
40
41   after do
42     FileUtils.remove_entry_secure Depot.instance.path
43   end
44
45   it "should offer an upload form" do
46     get '/'
47     last_response.should be_ok
48     doc = Hpricot(last_response.body)
49     (doc/"form#upload").should have(1).items
50   end
51
52   it "should allow retrieval of an uploaded file" do
53     url = upload
54     get url
55     last_response.should be_ok
56     last_response['Content-Type'].should eql('text/x-script.ruby')
57     last_response.body.should eql(File.new(__FILE__).read)
58   end
59
60   it "should prevent upload without a password" do
61     url = upload :upload_password => ''
62     url.should be_nil
63     last_response.status.should eql(403)
64   end
65
66   it "should prevent upload with a wrong password" do
67     url = upload :upload_password => "bad"
68     url.should be_nil
69     last_response.status.should eql(403)
70   end
71
72   it "should not store an uploaded file in cleartext" do
73     upload
74     files = Dir.glob("#{Depot.instance.path}/*")
75     files.should have(1).items
76     File.new(files[0]).read().should_not include('should not store an uploaded file')
77   end
78
79   it "should generate a random URL to retrieve a file" do
80     url = upload
81     url.should_not include(File.basename(__FILE__))
82   end
83
84   it "should store files with a different name than then one in URL" do
85     url = upload
86     url_name = url.split('/')[-1]
87     files = Dir.glob("#{Depot.instance.path}/*")
88     files.should have(1).items
89     url_name.should_not eql(File.basename(files[0]))
90   end
91
92   it "should encode the encryption key in URL when no password has been specified" do
93     url = upload
94     url_name = url.split('/')[-1]
95     url_name.split('-').should have(2).items
96   end
97
98   it "should not encode the encryption key in URL when a password has been specified" do
99     url = upload :file_key => 'somethingSecret'
100     url_name = url.split('/')[-1]
101     url_name.split('-').should have(1).items
102   end
103
104   it "should allow retrieval of a password protected file" do
105     url = upload :file_key => 'somethingSecret'
106     get url
107     last_response.should be_ok
108     doc = Hpricot(last_response.body)
109     (doc/'input#file_key').should have(1).items
110     url = (doc/'form')[0].attributes['action']
111     post url, :file_key => 'somethingSecret'
112     last_response.should be_ok
113     last_response['Content-Type'].should eql('text/x-script.ruby')
114     last_response.body.should eql(File.new(__FILE__).read)
115   end
116
117   it "should not allow retrieval of a password protected file without the password" do
118     url = upload :file_key => 'somethingSecret'
119     get url
120     last_response.should be_ok
121     last_response['Content-Type'].should_not eql('text/x-script.ruby')
122     post url
123     last_response.status.should eql(403)
124   end
125
126   it "should not allow retrieval of a password protected file with a wrong password" do
127     url = upload :file_key => 'somethingSecret'
128     post url, :file_key => 'BAD'
129     last_response.status.should eql(403)
130   end
131
132   it "should not allow retrieval after the time limit has expired" do
133     url = upload :expire => 60 # 1 hour
134     # let's be tomorrow
135     Timecop.travel(Date.today + 1) do
136       get url
137       last_response.status.should eql(410)
138     end
139   end
140
141   it "should cleanup expired files" do
142     upload :expire => 60 # 1 hour
143     Dir.glob("#{Depot.instance.path}/*").should have(1).items
144     # let's be tomorrow
145     Timecop.travel(Date.today + 1) do
146       Depot.instance.gc!
147       Dir.glob("#{Depot.instance.path}/*").should have(0).items
148     end
149   end
150
151   it "should map extra base32 characters to filenames" do
152     url = upload :expire => 60 # 1 hour
153     splitted = url.split('/')
154     name = splitted[-1].upcase.gsub(/O/, '0').gsub(/L/, '1')
155     get "#{splitted[0..-2].join '/'}/#{name}"
156     last_response.should be_ok
157     last_response['Content-Type'].should eql('text/x-script.ruby')
158   end
159 end