various UI improvements
[coquelicot.git] / spec / coquelicot / app_spec.rb
1 # -*- coding: UTF-8 -*-
2 # Coquelicot: "one-click" file sharing with a focus on users' privacy.
3 # Copyright © 2010-2012 potager.org <jardiniers@potager.org>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 require 'spec_helper'
19 require 'coquelicot/jyraphe_migrator'
20 require 'capybara/dsl'
21 require 'tempfile'
22
23 describe Coquelicot::Application do
24   include Rack::Test::Methods
25   include Capybara::DSL
26   Capybara.app = Coquelicot::Application
27
28   include_context 'with Coquelicot::Application'
29
30   def upload_password
31     'secret'
32   end
33
34   before(:each) do
35     app.set :authentication_method, :name => :simplepass,
36                                     :upload_password => Digest::SHA1.hexdigest(upload_password)
37   end
38
39   describe 'get /' do
40     context 'using the default language' do
41       it 'should display the maximum file size' do
42         visit '/'
43         find(:xpath, '//label[@for="file"]').
44             should have_content("max. size: #{Coquelicot.settings.max_file_size.as_size}")
45       end
46       context 'when I explicitly request french' do
47         it 'should display a page in french' do
48           visit '/'
49           click_link 'fr'
50           page.should have_content('Partager')
51         end
52         # will fail without ordered Hash, see:
53         # <https://github.com/jnicklas/capybara/issues/670>
54         context 'when I upload an empty file', :if => RUBY_VERSION >= '1.9' do
55           around do |example|
56             file = Tempfile.new('coquelicot')
57             begin
58               visit '/'
59               click_link 'fr'
60               fill_in 'upload_password', :with => upload_password
61               attach_file 'file', file.path
62               click_button 'submit'
63               example.run
64             ensure
65               file.close!
66             end
67           end
68           it 'should display an error in french' do
69             page.should have_content('Le fichier est vide')
70           end
71         end
72       end
73     end
74     context 'when my browser prefers french' do
75       around do |example|
76         begin
77           page.driver.header 'Accept-Language',  'fr-fr;q=1.0, en-gb;q=0.8, en;q=0.7'
78           example.run
79         ensure
80           page.driver.header 'Accept-Language', nil
81         end
82       end
83       context 'when I do nothing special' do
84         it 'should display a page in french' do
85           visit '/'
86           page.should have_content('Partager')
87         end
88         context 'when the max upload size is 1 KiB' do
89           around do |example|
90             begin
91               max_file_size = app.max_file_size
92               app.set :max_file_size, 1024
93               example.run
94             ensure
95               app.set :max_file_size, max_file_size
96             end
97           end
98           it 'should display "1 Kio" as the max upload size' do
99             visit '/'
100             page.should have_content('1 Kio')
101           end
102           # will fail without ordered Hash, see:
103           # <https://github.com/jnicklas/capybara/issues/670>
104           context 'when I upload something bigger', :if => RUBY_VERSION >= '1.9' do
105             before do
106               visit '/'
107               fill_in 'upload_password', :with => upload_password
108               attach_file 'file', __FILE__
109               click_button 'submit'
110             end
111             it 'should display an error in french' do
112               page.should have_content('plus gros que la taille maximale')
113             end
114           end
115         end
116         # will fail without ordered Hash, see:
117         # <https://github.com/jnicklas/capybara/issues/670>
118         context 'when I upload an empty file', :if => RUBY_VERSION >= '1.9' do
119           around do |example|
120             file = Tempfile.new('coquelicot')
121             begin
122               visit '/'
123               fill_in 'upload_password', :with => upload_password
124               attach_file 'file', file.path
125               click_button 'submit'
126               example.run
127             ensure
128               file.close!
129             end
130           end
131           it 'should display an error in french' do
132             page.should have_content('Le fichier est vide')
133           end
134         end
135       end
136       context 'when I explicitly request german' do
137         before do
138           visit '/'
139           click_link 'de'
140         end
141         it 'should display a page in german' do
142           page.should have_content('Verteile')
143         end
144         # will fail without ordered Hash, see:
145         # <https://github.com/jnicklas/capybara/issues/670>
146         context 'after an upload', :if => RUBY_VERSION >= '1.9' do
147           before do
148             fill_in 'upload_password', :with => upload_password
149             attach_file 'file', __FILE__
150             click_button 'submit'
151           end
152           it 'should display a page in german' do
153             page.should have_content('Verteile eine weitere Datei')
154           end
155         end
156       end
157     end
158   end
159
160   describe 'get /README' do
161     before do
162       visit '/README'
163     end
164     it 'should display the README file' do
165       title = File.open(File.expand_path('../../../README', __FILE__)) { |f| f.readline.strip }
166       find('h1').should have_content(title)
167     end
168   end
169
170   describe 'get /about-your-data' do
171     it 'should display some info about data retention' do
172       visit '/about-your-data'
173       find('h1').should have_content('About your data…')
174     end
175     context 'when using SSL' do
176       it 'should notice the connection is encrypted' do
177         visit 'https://example.com/about-your-data'
178         page.should have_content('Exchanges between your computer and example.com are encrypted.')
179       end
180     end
181     context 'when not using SSL' do
182       it 'should notice the connection is encrypted' do
183         visit 'http://example.com/about-your-data'
184         page.should_not have_content('Exchanges between your computer and example.org are encrypted.')
185       end
186     end
187   end
188
189   describe 'post /authenticate' do
190     context 'when given a request with too much input' do
191       before do
192         # README is bigger than 5 kiB
193         path = File.expand_path('../../../README', __FILE__)
194         post '/authenticate', :file => Rack::Test::UploadedFile.new(path, 'text/plain')
195       end
196       it 'should get status 413 (Request entity too large)' do
197         last_response.status.should == 413
198       end
199     end
200   end
201 end
202
203 describe Coquelicot, '.collect_garbage!' do
204   context 'when given no option' do
205     include_context 'with Coquelicot::Application'
206
207     it 'should use the default depot path' do
208       Coquelicot::Depot.should_receive(:new).
209         with(@depot_path).
210         and_return(double.as_null_object)
211       Coquelicot.collect_garbage!
212     end
213     it 'should call gc!' do
214       depot = double('Depot').as_null_object
215       depot.should_receive(:gc!)
216       Coquelicot::Depot.stub(:new).and_return(depot)
217       Coquelicot.collect_garbage!
218     end
219   end
220   context 'when using "-c <settings.yml>"' do
221     around(:each) do |example|
222       settings = Tempfile.new('coquelicot')
223       begin
224         settings.write(YAML.dump({ 'depot_path' => '/nonexistent' }))
225         settings.close
226         @settings_path = settings.path
227         example.run
228       ensure
229         settings.unlink
230       end
231     end
232     it 'should use the depot path defined in the given settings' do
233       Coquelicot::Depot.should_receive(:new).
234         with('/nonexistent').
235         and_return(double.as_null_object)
236       Coquelicot.collect_garbage! ['-c', @settings_path]
237     end
238     it 'should call gc!' do
239       depot = double('Depot').as_null_object
240       depot.should_receive(:gc!)
241       Coquelicot::Depot.stub(:new).and_return(depot)
242       Coquelicot.collect_garbage! ['-c', @settings_path]
243     end
244   end
245   context 'when using "-h"' do
246     it 'should display help and exit' do
247       stderr = capture(:stderr) do
248         expect { Coquelicot.collect_garbage! ['-h'] }.to raise_error(SystemExit)
249       end
250       stderr.should =~ /Usage:/
251     end
252     it 'should not call gc!' do
253       depot = double('Depot').as_null_object
254       depot.should_not_receive(:gc!)
255       Coquelicot::Depot.stub(:new).and_return(depot)
256       capture(:stderr) do
257         expect { Coquelicot.collect_garbage! ['-h'] }.to raise_error(SystemExit)
258       end
259     end
260   end
261 end
262
263 describe Coquelicot, '.migrate_jyraphe!' do
264   it 'should call the migrator' do
265     args = ['whatever']
266     Coquelicot::JyrapheMigrator.should_receive(:run!).with(args)
267     Coquelicot.migrate_jyraphe! args
268   end
269 end