Refactor project membership and private repo functionality into generic protected...
[gitorious:mainline.git] / test / test_helper.rb
1 ENV["RAILS_ENV"] = "test"
2 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3 require 'test_help'
4 require 'ssl_requirement_macros'
5 require 'messaging_test_helper'
6
7 require "shoulda"
8 require "mocha"
9 begin
10   require "redgreen"
11 rescue LoadError
12 end
13
14 class ActiveSupport::TestCase
15   include AuthenticatedTestHelper
16   include Gitorious::Authorization
17
18   # Transactional fixtures accelerate your tests by wrapping each test method
19   # in a transaction that's rolled back on completion.  This ensures that the
20   # test database remains unchanged so your fixtures don't have to be reloaded
21   # between every test method.  Fewer database queries means faster tests.
22   #
23   # Read Mike Clark's excellent walkthrough at
24   #   http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
25   #
26   # Every Active Record database supports transactions except MyISAM tables
27   # in MySQL.  Turn off transactional fixtures in this case; however, if you
28   # don't care one way or the other, switching from MyISAM to InnoDB tables
29   # is recommended.
30   #
31   # The only drawback to using transactional fixtures is when you actually
32   # need to test transactions.  Since your test is bracketed by a transaction,
33   # any transactions started in your code will be automatically rolled back.
34   self.use_transactional_fixtures = true
35
36   # Instantiated fixtures are slow, but give you @david where otherwise you
37   # would need people(:david).  If you don't want to migrate your existing
38   # test cases which use the @david style and don't mind the speed hit (each
39   # instantiated fixtures translates to a database query per test method),
40   # then set this back to true.
41   self.use_instantiated_fixtures  = false
42
43   # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
44   #
45   # Note: You'll currently still have to declare fixtures explicitly in integration tests
46   # -- they do not yet inherit this setting
47   fixtures :all
48
49   NULL_SHA = "0" * 40 unless defined?(NULL_SHA)
50   SHA = "a" * 40 unless defined?(SHA)
51   OTHER_SHA = "f" * 40 unless defined?(OTHER_SHA)
52
53   # Add more helper methods to be used by all tests here...
54
55   def repo_path
56     File.join(File.dirname(__FILE__), "..", ".git")
57   end
58
59   def grit_test_repo(name)
60     File.join(RAILS_ROOT, "vendor/grit/test", name )
61   end
62
63   def assert_incremented_by(obj, meth, value)
64     value_before = obj.send(meth)
65     yield
66     value_after = obj.send(meth)
67     error_msg = (value_before == value_after) ? "unchanged" : "incremented by #{(value_after - value_before)}"
68     assert_equal(value, (value_after - value_before), "#{obj}##{meth} should be incremented by #{value} but was #{error_msg}")
69   end
70
71   def assert_includes(collection, object, message=nil)
72     assert(collection.include?(object),
73       (message || inclusion_failure(collection, object, true)))
74   end
75
76   def assert_not_includes(collection, object, message=nil)
77     assert(!collection.include?(object),
78       (message || inclusion_failure(collection, object, false)))
79   end
80
81   def inclusion_failure(collection, object, should_be_included)
82     not_message = should_be_included ? "" : " not"
83     "Expected collection (#{collection.count} items) #{not_message} to include #{object.class.name}"
84   end
85
86   def self.should_subscribe_to(queue_name)
87     should "Subscribe to message queue #{queue_name}" do
88       klass = self.class.name.sub(/Test$/, "").constantize
89
90       subscription = ActiveMessaging::Gateway.subscriptions.values.find do |s|
91         s.destination.name == queue_name && s.processor_class == klass
92       end
93
94       assert_not_nil subscription, "#{klass.name} does not subscribe to #{queue_name}"
95     end
96   end
97
98   def self.should_scope_pagination_to(action, klass, pluralized = nil, opt = {})
99     if Hash === pluralized
100       opt = pluralized
101       pluralized = nil
102     end
103
104     pluralized ||= klass.to_s.downcase.pluralize
105
106     should "redirect to action if page doesn't exist" do
107       params = @params || {}
108       get action, params.merge({ :page => 10 })
109
110       assert_response :redirect
111       assert_redirected_to params.dup.merge({ :action => action })
112     end
113
114     should "add flash message explaining that page doesn't exist" do
115       params = @params || {}
116       get action, params.merge({ :page => 10 })
117
118       assert_not_nil flash[:error]
119       assert_match /no #{pluralized}/, flash[:error]
120       assert_match /10/, flash[:error]
121     end
122
123     should "not redirect in a loop when there are no #{pluralized}" do
124       params = @params || {}
125       klass.delete_all if !opt.key?(:delete_all) || opt[:delete_all]
126
127       get action, params
128
129       assert_response :success
130     end
131
132     should "redirect to action if page is < 0" do
133       params = @params || {}
134       get action, params.merge({ :page => -1 })
135
136       assert_response :redirect
137       assert_redirected_to params.dup.merge({ :action => action })
138     end
139   end
140 end
141
142 class ActionController::TestCase
143   include Gitorious::Authorization
144
145   def setup_ssl_from_config
146     return unless GitoriousConfig["use_ssl"]
147
148     @request.env['HTTPS'] = 'on'
149     @request.env['SERVER_PORT'] = 443
150   end
151
152   def self.enforce_ssl
153     context "when enforcing ssl" do
154       setup do
155         @use_ssl = GitoriousConfig["use_ssl"]
156         GitoriousConfig["use_ssl"] = true
157         login_as(:johan)
158       end
159
160       teardown do
161         GitoriousConfig["use_ssl"] = @use_ssl
162       end
163
164       context "" do
165         yield
166       end
167     end
168   end
169
170   def self.disable_ssl
171     context "when not enforcing ssl" do
172       setup do
173         @use_ssl = GitoriousConfig["use_ssl"]
174         GitoriousConfig["use_ssl"] = false
175       end
176
177       teardown do
178         GitoriousConfig["use_ssl"] = @use_ssl
179       end
180
181       context "" do
182         yield
183       end
184     end
185   end
186
187   def self.should_enforce_ssl_for(method, action, params = {}, &block)
188     enforce_ssl do
189       without_ssl_context do
190         context "#{method.to_s.upcase} :#{action}" do
191           setup do
192             block.call unless block.nil?
193             self.send(method, action, params)
194           end
195
196           should_redirect_to_ssl
197         end
198       end
199     end
200
201     disable_ssl do
202       without_ssl_context do
203         context "#{method.to_s.upcase} :#{action}" do
204           should "not redirect to HTTPS" do
205             begin
206               self.send(method, action, params)
207             rescue NoMethodError
208               # Doesn't matter, this just means we hit the controller missing
209               # some parameters
210             end
211
212             assert_not_equal "https://" + @request.host + @request.request_uri, @response.location
213           end
214         end
215       end
216     end
217   end
218
219   def self.should_render_in_global_context(options = {})
220     should "Render in global context for actions" do
221       filter = @controller.class.filter_chain.find(:require_global_site_context)
222       assert_not_nil filter, ":require_global_site_context before_filter not set"
223       unless options[:except].blank?
224         assert_not_nil filter.options[:except], "no :except specified in controller"
225         assert_equal [*options[:except]].flatten.map(&:to_s).sort, filter.options[:except].sort
226       end
227       unless options[:only].blank?
228         assert_not_nil filter.options[:only], "no :only specified in controller"
229         assert_equal [*options[:only]].flatten.map(&:to_s).sort, filter.options[:only].sort
230       end
231     end
232   end
233
234   def self.should_render_in_site_specific_context(options = {})
235     should "Render in site specific context for actions" do
236       filter = @controller.class.filter_chain.find(:redirect_to_current_site_subdomain)
237       assert_not_nil filter, ":redirect_to_current_site_subdomain before_filter not set"
238       unless options[:except].blank?
239         assert_not_nil filter.options[:except], "no :except specified in controller"
240         assert_equal [*options[:except]].flatten.map(&:to_s).sort, filter.options[:except].sort
241       end
242       unless options[:only].blank?
243         assert_not_nil filter.options[:only], "no :only specified in controller"
244         assert_equal [*options[:only]].flatten.map(&:to_s).sort, filter.options[:only].sort
245       end
246     end
247   end
248
249   def self.should_verify_method(method, action, params = {})
250     should "only allow #{method} for #{action}" do
251       actions = ActionController::Routing::HTTP_METHODS - [method]
252
253       actions.each do |method|
254         send(method, action, params)
255
256         assert_response 400, "Should disallow #{method} for #{action}"
257       end
258     end
259   end
260
261   def options(action, parameters = nil, session = nil, flash = nil)
262     process(action, parameters, session, flash, "OPTIONS")
263   end
264
265   def enable_private_repositories
266     GitoriousConfig["enable_private_repositories"] = true
267     if defined?(@project)
268       @project.make_private
269     else
270       @repository.make_private
271     end
272   end
273 end