Revision 1297:0a574315af3e .svn/pristine/55

View differences:

.svn/pristine/55/55001cf6d9a742aad4c5f507a1e501bdbbd4c606.svn-base
1
$('#related-issue-<%= @issue.id %>').remove();
.svn/pristine/55/55656b808ca026c38683e6dfc5a04c01603da464.svn-base
1
Installing gems for testing
2
===========================
3

  
4
Remove your .bundle/config if you've already installed Redmine without
5
the test dependencies. Then, run `bundle install`.
6

  
7
Running Tests
8
=============
9

  
10
Run `rake --tasks test` to see available tests.
11
Run `rake test` to run the entire test suite (except the tests for the
12
Apache perl module Redmine.pm, see below).
13

  
14
You can run `ruby test/unit/issue_test.rb` for running a single test case.
15

  
16
Before running tests, you need to configure both development
17
and test databases.
18

  
19
Creating test repositories
20
==========================
21

  
22
Redmine supports a wide array of different version control systems.
23
To test the support, a test repository needs to be created for each of those.
24

  
25
Run `rake --tasks test:scm:setup` for a list of available test-repositories or
26
run `rake test:scm:setup:all` to set up all of them. The repositories are
27
unpacked into {redmine_root}/tmp/test.
28

  
29
If the test repositories are not present, the tests that need them will be
30
skipped.
31

  
32
Creating a test ldap database
33
=============================
34

  
35
Redmine supports using LDAP for user authentications.  To test LDAP
36
with Redmine, load the LDAP export from test/fixtures/ldap/test-ldap.ldif
37
into a testing LDAP server. Make sure that the LDAP server can be accessed
38
at 127.0.0.1 on port 389.
39

  
40
Setting up the test LDAP server is beyond the scope of this documentation.
41
The OpenLDAP project provides a simple LDAP implementation that should work
42
good as a test server.
43

  
44
If the LDAP is not available, the tests that need it will be skipped.
45

  
46
Running Redmine.pm tests
47
========================
48

  
49
(work in progress)
50

  
51
Running the tests for the Redmine.pm perl module needs a bit more setup.
52
You need an Apache server with mod_perl, mod_dav_svn and Redmine.pm configured.
53
See: http://www.redmine.org/projects/redmine/wiki/Repositories_access_control_with_apache_mod_dav_svn_and_mod_perl
54

  
55
You need an empty repository accessible at http://127.0.0.1/svn/ecookbook
56
Then, you can run the tests with:
57
`ruby test\extra\redmine_pm\repository_subversion_test.rb`
58

  
59
If you svn server is not running on localhost, you can use the REDMINE_TEST_DAV_SERVER
60
environment variable to specify another host.
.svn/pristine/55/5599405356ee2efcb93c9803fa4189ef3dece11e.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
class Role < ActiveRecord::Base
19
  # Custom coder for the permissions attribute that should be an
20
  # array of symbols. Rails 3 uses Psych which can be *unbelievably*
21
  # slow on some platforms (eg. mingw32).
22
  class PermissionsAttributeCoder
23
    def self.load(str)
24
      str.to_s.scan(/:([a-z0-9_]+)/).flatten.map(&:to_sym)
25
    end
26

  
27
    def self.dump(value)
28
      YAML.dump(value)
29
    end
30
  end
31

  
32
  # Built-in roles
33
  BUILTIN_NON_MEMBER = 1
34
  BUILTIN_ANONYMOUS  = 2
35

  
36
  ISSUES_VISIBILITY_OPTIONS = [
37
    ['all', :label_issues_visibility_all],
38
    ['default', :label_issues_visibility_public],
39
    ['own', :label_issues_visibility_own]
40
  ]
41

  
42
  scope :sorted, order("#{table_name}.builtin ASC, #{table_name}.position ASC")
43
  scope :givable, order("#{table_name}.position ASC").where(:builtin => 0)
44
  scope :builtin, lambda { |*args|
45
    compare = (args.first == true ? 'not' : '')
46
    where("#{compare} builtin = 0")
47
  }
48

  
49
  before_destroy :check_deletable
50
  has_many :workflow_rules, :dependent => :delete_all do
51
    def copy(source_role)
52
      WorkflowRule.copy(nil, source_role, nil, proxy_association.owner)
53
    end
54
  end
55

  
56
  has_many :member_roles, :dependent => :destroy
57
  has_many :members, :through => :member_roles
58
  acts_as_list
59

  
60
  serialize :permissions, ::Role::PermissionsAttributeCoder
61
  attr_protected :builtin
62

  
63
  validates_presence_of :name
64
  validates_uniqueness_of :name
65
  validates_length_of :name, :maximum => 30
66
  validates_inclusion_of :issues_visibility,
67
    :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first),
68
    :if => lambda {|role| role.respond_to?(:issues_visibility)}
69

  
70
  # Copies attributes from another role, arg can be an id or a Role
71
  def copy_from(arg, options={})
72
    return unless arg.present?
73
    role = arg.is_a?(Role) ? arg : Role.find_by_id(arg.to_s)
74
    self.attributes = role.attributes.dup.except("id", "name", "position", "builtin", "permissions")
75
    self.permissions = role.permissions.dup
76
    self
77
  end
78

  
79
  def permissions=(perms)
80
    perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms
81
    write_attribute(:permissions, perms)
82
  end
83

  
84
  def add_permission!(*perms)
85
    self.permissions = [] unless permissions.is_a?(Array)
86

  
87
    permissions_will_change!
88
    perms.each do |p|
89
      p = p.to_sym
90
      permissions << p unless permissions.include?(p)
91
    end
92
    save!
93
  end
94

  
95
  def remove_permission!(*perms)
96
    return unless permissions.is_a?(Array)
97
    permissions_will_change!
98
    perms.each { |p| permissions.delete(p.to_sym) }
99
    save!
100
  end
101

  
102
  # Returns true if the role has the given permission
103
  def has_permission?(perm)
104
    !permissions.nil? && permissions.include?(perm.to_sym)
105
  end
106

  
107
  def <=>(role)
108
    if role
109
      if builtin == role.builtin
110
        position <=> role.position
111
      else
112
        builtin <=> role.builtin
113
      end
114
    else
115
      -1
116
    end
117
  end
118

  
119
  def to_s
120
    name
121
  end
122

  
123
  def name
124
    case builtin
125
    when 1; l(:label_role_non_member, :default => read_attribute(:name))
126
    when 2; l(:label_role_anonymous,  :default => read_attribute(:name))
127
    else; read_attribute(:name)
128
    end
129
  end
130

  
131
  # Return true if the role is a builtin role
132
  def builtin?
133
    self.builtin != 0
134
  end
135

  
136
  # Return true if the role is the anonymous role
137
  def anonymous?
138
    builtin == 2
139
  end
140
  
141
  # Return true if the role is a project member role
142
  def member?
143
    !self.builtin?
144
  end
145

  
146
  # Return true if role is allowed to do the specified action
147
  # action can be:
148
  # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
149
  # * a permission Symbol (eg. :edit_project)
150
  def allowed_to?(action)
151
    if action.is_a? Hash
152
      allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
153
    else
154
      allowed_permissions.include? action
155
    end
156
  end
157

  
158
  # Return all the permissions that can be given to the role
159
  def setable_permissions
160
    setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions
161
    setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER
162
    setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS
163
    setable_permissions
164
  end
165

  
166
  # Find all the roles that can be given to a project member
167
  def self.find_all_givable
168
    Role.givable.all
169
  end
170

  
171
  # Return the builtin 'non member' role.  If the role doesn't exist,
172
  # it will be created on the fly.
173
  def self.non_member
174
    find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member')
175
  end
176

  
177
  # Return the builtin 'anonymous' role.  If the role doesn't exist,
178
  # it will be created on the fly.
179
  def self.anonymous
180
    find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous')
181
  end
182

  
183
private
184

  
185
  def allowed_permissions
186
    @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}
187
  end
188

  
189
  def allowed_actions
190
    @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
191
  end
192

  
193
  def check_deletable
194
    raise "Can't delete role" if members.any?
195
    raise "Can't delete builtin role" if builtin?
196
  end
197

  
198
  def self.find_or_create_system_role(builtin, name)
199
    role = where(:builtin => builtin).first
200
    if role.nil?
201
      role = create(:name => name, :position => 0) do |r|
202
        r.builtin = builtin
203
      end
204
      raise "Unable to create the #{name} role." if role.new_record?
205
    end
206
    role
207
  end
208
end
.svn/pristine/55/55d19caa0b30cb24ce3fc09b9feabb1a8fe2c09a.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../test_helper', __FILE__)
19

  
20
class RepositoryBazaarTest < ActiveSupport::TestCase
21
  fixtures :projects
22

  
23
  include Redmine::I18n
24

  
25
  REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
26
  REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
27
  NUM_REV = 4
28

  
29
  REPOSITORY_PATH_NON_ASCII = Rails.root.join(REPOSITORY_PATH + '/' + 'non_ascii').to_s
30

  
31
  # Bazaar core does not support xml output such as Subversion and Mercurial.
32
  # "bzr" command output and command line parameter depend on locale.
33
  # So, non ASCII path tests cannot run independent locale.
34
  #
35
  # If you want to run Bazaar non ASCII path tests on Linux *Ruby 1.9*,
36
  # you need to set locale character set "ISO-8859-1".
37
  # E.g. "LANG=en_US.ISO-8859-1".
38
  # On Linux other platforms (e.g. Ruby 1.8, JRuby),
39
  # you need to set "RUN_LATIN1_OUTPUT_TEST = true" manually.
40
  #
41
  # On Windows, because it is too hard to change system locale,
42
  # you cannot run Bazaar non ASCII path tests.
43
  #
44
  RUN_LATIN1_OUTPUT_TEST = (RUBY_PLATFORM != 'java' &&
45
                             REPOSITORY_PATH.respond_to?(:force_encoding) &&
46
                             Encoding.locale_charmap == "ISO-8859-1")
47

  
48
  CHAR_1_UTF8_HEX   = "\xc3\x9c"
49
  CHAR_1_LATIN1_HEX = "\xdc"
50

  
51
  def setup
52
    @project = Project.find(3)
53
    @repository = Repository::Bazaar.create(
54
              :project => @project, :url => REPOSITORY_PATH_TRUNK,
55
              :log_encoding => 'UTF-8')
56
    assert @repository
57
    @char_1_utf8      = CHAR_1_UTF8_HEX.dup
58
    @char_1_ascii8bit = CHAR_1_LATIN1_HEX.dup
59
    if @char_1_utf8.respond_to?(:force_encoding)
60
      @char_1_utf8.force_encoding('UTF-8')
61
      @char_1_ascii8bit.force_encoding('ASCII-8BIT')
62
    end
63
  end
64

  
65
  def test_blank_path_to_repository_error_message
66
    set_language_if_valid 'en'
67
    repo = Repository::Bazaar.new(
68
                          :project      => @project,
69
                          :identifier   => 'test',
70
                          :log_encoding => 'UTF-8'
71
                        )
72
    assert !repo.save
73
    assert_include "Path to repository can't be blank",
74
                   repo.errors.full_messages
75
  end
76

  
77
  def test_blank_path_to_repository_error_message_fr
78
    set_language_if_valid 'fr'
79
    str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
80
    str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
81
    repo = Repository::Bazaar.new(
82
                          :project      => @project,
83
                          :url          => "",
84
                          :identifier   => 'test',
85
                          :log_encoding => 'UTF-8'
86
                        )
87
    assert !repo.save
88
    assert_include str, repo.errors.full_messages
89
  end
90

  
91
  if File.directory?(REPOSITORY_PATH_TRUNK)
92
    def test_fetch_changesets_from_scratch
93
      assert_equal 0, @repository.changesets.count
94
      @repository.fetch_changesets
95
      @project.reload
96

  
97
      assert_equal NUM_REV, @repository.changesets.count
98
      assert_equal 9, @repository.filechanges.count
99
      assert_equal 'Initial import', @repository.changesets.find_by_revision('1').comments
100
    end
101

  
102
    def test_fetch_changesets_incremental
103
      assert_equal 0, @repository.changesets.count
104
      @repository.fetch_changesets
105
      @project.reload
106
      assert_equal NUM_REV, @repository.changesets.count
107
      # Remove changesets with revision > 5
108
      @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2}
109
      @project.reload
110
      assert_equal 2, @repository.changesets.count
111

  
112
      @repository.fetch_changesets
113
      @project.reload
114
      assert_equal NUM_REV, @repository.changesets.count
115
    end
116

  
117
    def test_entries
118
      entries = @repository.entries
119
      assert_kind_of Redmine::Scm::Adapters::Entries, entries
120
      assert_equal 2, entries.size
121

  
122
      assert_equal 'dir', entries[0].kind
123
      assert_equal 'directory', entries[0].name
124
      assert_equal 'directory', entries[0].path
125

  
126
      assert_equal 'file', entries[1].kind
127
      assert_equal 'doc-mkdir.txt', entries[1].name
128
      assert_equal 'doc-mkdir.txt', entries[1].path
129
    end
130

  
131
    def test_entries_in_subdirectory
132
      entries = @repository.entries('directory')
133
      assert_equal 3, entries.size
134

  
135
      assert_equal 'file', entries.last.kind
136
      assert_equal 'edit.png', entries.last.name
137
      assert_equal 'directory/edit.png', entries.last.path
138
    end
139

  
140
    def test_previous
141
      assert_equal 0, @repository.changesets.count
142
      @repository.fetch_changesets
143
      @project.reload
144
      assert_equal NUM_REV, @repository.changesets.count
145
      changeset = @repository.find_changeset_by_name('3')
146
      assert_equal @repository.find_changeset_by_name('2'), changeset.previous
147
    end
148

  
149
    def test_previous_nil
150
      assert_equal 0, @repository.changesets.count
151
      @repository.fetch_changesets
152
      @project.reload
153
      assert_equal NUM_REV, @repository.changesets.count
154
      changeset = @repository.find_changeset_by_name('1')
155
      assert_nil changeset.previous
156
    end
157

  
158
    def test_next
159
      assert_equal 0, @repository.changesets.count
160
      @repository.fetch_changesets
161
      @project.reload
162
      assert_equal NUM_REV, @repository.changesets.count
163
      changeset = @repository.find_changeset_by_name('2')
164
      assert_equal @repository.find_changeset_by_name('3'), changeset.next
165
    end
166

  
167
    def test_next_nil
168
      assert_equal 0, @repository.changesets.count
169
      @repository.fetch_changesets
170
      @project.reload
171
      assert_equal NUM_REV, @repository.changesets.count
172
      changeset = @repository.find_changeset_by_name('4')
173
      assert_nil changeset.next
174
    end
175

  
176
    if File.directory?(REPOSITORY_PATH_NON_ASCII) && RUN_LATIN1_OUTPUT_TEST
177
      def test_cat_latin1_path
178
        latin1_repo = create_latin1_repo
179
        buf = latin1_repo.cat(
180
                 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", 2)
181
        assert buf
182
        lines = buf.split("\n")
183
        assert_equal 2, lines.length
184
        assert_equal 'It is written in Python.', lines[1]
185

  
186
        buf = latin1_repo.cat(
187
                 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2)
188
        assert buf
189
        lines = buf.split("\n")
190
        assert_equal 1, lines.length
191
        assert_equal "test-#{@char_1_ascii8bit}.txt", lines[0]
192
      end
193

  
194
      def test_annotate_latin1_path
195
        latin1_repo = create_latin1_repo
196
        ann1 = latin1_repo.annotate(
197
                   "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", 2)
198
        assert_equal 2, ann1.lines.size
199
        assert_equal '2', ann1.revisions[0].identifier
200
        assert_equal 'test00@', ann1.revisions[0].author
201
        assert_equal 'It is written in Python.', ann1.lines[1]
202
        ann2 = latin1_repo.annotate(
203
                   "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2)
204
        assert_equal 1, ann2.lines.size
205
        assert_equal '2', ann2.revisions[0].identifier
206
        assert_equal 'test00@', ann2.revisions[0].author
207
        assert_equal "test-#{@char_1_ascii8bit}.txt", ann2.lines[0]
208
      end
209

  
210
      def test_diff_latin1_path
211
        latin1_repo = create_latin1_repo
212
        diff1 = latin1_repo.diff(
213
                  "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2, 1)
214
        assert_equal 7, diff1.size
215
        buf =  diff1[5].gsub(/\r\n|\r|\n/, "")
216
        assert_equal "+test-#{@char_1_ascii8bit}.txt", buf
217
      end
218

  
219
      def test_entries_latin1_path
220
        latin1_repo = create_latin1_repo
221
        entries = latin1_repo.entries("test-#{@char_1_utf8}-dir", 2)
222
        assert_kind_of Redmine::Scm::Adapters::Entries, entries
223
        assert_equal 3, entries.size
224
        assert_equal 'file', entries[1].kind
225
        assert_equal "test-#{@char_1_utf8}-1.txt", entries[0].name
226
        assert_equal "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", entries[0].path
227
      end
228

  
229
      def test_entry_latin1_path
230
        latin1_repo = create_latin1_repo
231
        ["test-#{@char_1_utf8}-dir",
232
          "/test-#{@char_1_utf8}-dir",
233
          "/test-#{@char_1_utf8}-dir/"
234
        ].each do |path|
235
          entry = latin1_repo.entry(path, 2)
236
          assert_equal "test-#{@char_1_utf8}-dir", entry.path
237
          assert_equal "dir", entry.kind
238
        end
239
        ["test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt",
240
          "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt"
241
        ].each do |path|
242
          entry = latin1_repo.entry(path, 2)
243
          assert_equal "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt",
244
                       entry.path
245
          assert_equal "file", entry.kind
246
        end
247
      end
248

  
249
      def test_changeset_latin1_path
250
        latin1_repo = create_latin1_repo
251
        assert_equal 0, latin1_repo.changesets.count
252
        latin1_repo.fetch_changesets
253
        @project.reload
254
        assert_equal 3, latin1_repo.changesets.count
255

  
256
        cs2 = latin1_repo.changesets.find_by_revision('2')
257
        assert_not_nil cs2
258
        assert_equal "test-#{@char_1_utf8}", cs2.comments
259
        c2  = cs2.filechanges.sort_by(&:path)
260
        assert_equal 4, c2.size
261
        assert_equal 'A', c2[0].action
262
        assert_equal "/test-#{@char_1_utf8}-dir/", c2[0].path
263
        assert_equal 'A', c2[1].action
264
        assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", c2[1].path
265
        assert_equal 'A', c2[2].action
266
        assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", c2[2].path
267
        assert_equal 'A', c2[3].action
268
        assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}.txt", c2[3].path
269

  
270
        cs3 = latin1_repo.changesets.find_by_revision('3')
271
        assert_not_nil cs3
272
        assert_equal "modify, move and delete #{@char_1_utf8} files", cs3.comments
273
        c3  = cs3.filechanges.sort_by(&:path)
274
        assert_equal 3, c3.size
275
        assert_equal 'M', c3[0].action
276
        assert_equal "/test-#{@char_1_utf8}-1.txt", c3[0].path
277
        assert_equal 'D', c3[1].action
278
        assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", c3[1].path
279
        assert_equal 'M', c3[2].action
280
        assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}.txt", c3[2].path
281
      end
282
    else
283
      msg = "Bazaar non ASCII output test cannot run this environment." + "\n"
284
      if msg.respond_to?(:force_encoding)
285
        msg += "Encoding.locale_charmap: " + Encoding.locale_charmap + "\n"
286
      end
287
      puts msg
288
    end
289

  
290
    private
291

  
292
    def create_latin1_repo
293
      repo = Repository::Bazaar.create(
294
                            :project      => @project,
295
                            :identifier   => 'latin1',
296
                            :url => REPOSITORY_PATH_NON_ASCII,
297
                            :log_encoding => 'ISO-8859-1'
298
                        )
299
      assert repo
300
      repo
301
    end
302
  else
303
    puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!"
304
    def test_fake; assert true end
305
  end
306
end

Also available in: Unified diff