##// END OF EJS Templates
Merged r14156 and r14161 (#19400)....
Jean-Philippe Lang -
r13815:d904292635b1
parent child
Show More
@@ -1,509 +1,514
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class ScmFetchError < Exception; end
18 class ScmFetchError < Exception; end
19
19
20 class Repository < ActiveRecord::Base
20 class Repository < ActiveRecord::Base
21 include Redmine::Ciphering
21 include Redmine::Ciphering
22 include Redmine::SafeAttributes
22 include Redmine::SafeAttributes
23
23
24 # Maximum length for repository identifiers
24 # Maximum length for repository identifiers
25 IDENTIFIER_MAX_LENGTH = 255
25 IDENTIFIER_MAX_LENGTH = 255
26
26
27 belongs_to :project
27 belongs_to :project
28 has_many :changesets, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
28 has_many :changesets, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
30
30
31 serialize :extra_info
31 serialize :extra_info
32
32
33 before_validation :normalize_identifier
33 before_save :check_default
34 before_save :check_default
34
35
35 # Raw SQL to delete changesets and changes in the database
36 # Raw SQL to delete changesets and changes in the database
36 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 # has_many :changesets, :dependent => :destroy is too slow for big repositories
37 before_destroy :clear_changesets
38 before_destroy :clear_changesets
38
39
39 validates_length_of :password, :maximum => 255, :allow_nil => true
40 validates_length_of :password, :maximum => 255, :allow_nil => true
40 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true
41 validates_uniqueness_of :identifier, :scope => :project_id
42 validates_uniqueness_of :identifier, :scope => :project_id
42 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
43 validates_exclusion_of :identifier, :in => %w(browse show entry raw changes annotate diff statistics graph revisions revision)
43 # donwcase letters, digits, dashes, underscores but not digits only
44 # donwcase letters, digits, dashes, underscores but not digits only
44 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
45 # Checks if the SCM is enabled when creating a repository
46 # Checks if the SCM is enabled when creating a repository
46 validate :repo_create_validation, :on => :create
47 validate :repo_create_validation, :on => :create
47 validate :validate_repository_path
48 validate :validate_repository_path
48 attr_protected :id
49 attr_protected :id
49
50
50 safe_attributes 'identifier',
51 safe_attributes 'identifier',
51 'login',
52 'login',
52 'password',
53 'password',
53 'path_encoding',
54 'path_encoding',
54 'log_encoding',
55 'log_encoding',
55 'is_default'
56 'is_default'
56
57
57 safe_attributes 'url',
58 safe_attributes 'url',
58 :if => lambda {|repository, user| repository.new_record?}
59 :if => lambda {|repository, user| repository.new_record?}
59
60
60 def repo_create_validation
61 def repo_create_validation
61 unless Setting.enabled_scm.include?(self.class.name.demodulize)
62 unless Setting.enabled_scm.include?(self.class.name.demodulize)
62 errors.add(:type, :invalid)
63 errors.add(:type, :invalid)
63 end
64 end
64 end
65 end
65
66
66 def self.human_attribute_name(attribute_key_name, *args)
67 def self.human_attribute_name(attribute_key_name, *args)
67 attr_name = attribute_key_name.to_s
68 attr_name = attribute_key_name.to_s
68 if attr_name == "log_encoding"
69 if attr_name == "log_encoding"
69 attr_name = "commit_logs_encoding"
70 attr_name = "commit_logs_encoding"
70 end
71 end
71 super(attr_name, *args)
72 super(attr_name, *args)
72 end
73 end
73
74
74 # Removes leading and trailing whitespace
75 # Removes leading and trailing whitespace
75 def url=(arg)
76 def url=(arg)
76 write_attribute(:url, arg ? arg.to_s.strip : nil)
77 write_attribute(:url, arg ? arg.to_s.strip : nil)
77 end
78 end
78
79
79 # Removes leading and trailing whitespace
80 # Removes leading and trailing whitespace
80 def root_url=(arg)
81 def root_url=(arg)
81 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
82 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
82 end
83 end
83
84
84 def password
85 def password
85 read_ciphered_attribute(:password)
86 read_ciphered_attribute(:password)
86 end
87 end
87
88
88 def password=(arg)
89 def password=(arg)
89 write_ciphered_attribute(:password, arg)
90 write_ciphered_attribute(:password, arg)
90 end
91 end
91
92
92 def scm_adapter
93 def scm_adapter
93 self.class.scm_adapter_class
94 self.class.scm_adapter_class
94 end
95 end
95
96
96 def scm
97 def scm
97 unless @scm
98 unless @scm
98 @scm = self.scm_adapter.new(url, root_url,
99 @scm = self.scm_adapter.new(url, root_url,
99 login, password, path_encoding)
100 login, password, path_encoding)
100 if root_url.blank? && @scm.root_url.present?
101 if root_url.blank? && @scm.root_url.present?
101 update_attribute(:root_url, @scm.root_url)
102 update_attribute(:root_url, @scm.root_url)
102 end
103 end
103 end
104 end
104 @scm
105 @scm
105 end
106 end
106
107
107 def scm_name
108 def scm_name
108 self.class.scm_name
109 self.class.scm_name
109 end
110 end
110
111
111 def name
112 def name
112 if identifier.present?
113 if identifier.present?
113 identifier
114 identifier
114 elsif is_default?
115 elsif is_default?
115 l(:field_repository_is_default)
116 l(:field_repository_is_default)
116 else
117 else
117 scm_name
118 scm_name
118 end
119 end
119 end
120 end
120
121
121 def identifier=(identifier)
122 def identifier=(identifier)
122 super unless identifier_frozen?
123 super unless identifier_frozen?
123 end
124 end
124
125
125 def identifier_frozen?
126 def identifier_frozen?
126 errors[:identifier].blank? && !(new_record? || identifier.blank?)
127 errors[:identifier].blank? && !(new_record? || identifier.blank?)
127 end
128 end
128
129
129 def identifier_param
130 def identifier_param
130 if is_default?
131 if is_default?
131 nil
132 nil
132 elsif identifier.present?
133 elsif identifier.present?
133 identifier
134 identifier
134 else
135 else
135 id.to_s
136 id.to_s
136 end
137 end
137 end
138 end
138
139
139 def <=>(repository)
140 def <=>(repository)
140 if is_default?
141 if is_default?
141 -1
142 -1
142 elsif repository.is_default?
143 elsif repository.is_default?
143 1
144 1
144 else
145 else
145 identifier.to_s <=> repository.identifier.to_s
146 identifier.to_s <=> repository.identifier.to_s
146 end
147 end
147 end
148 end
148
149
149 def self.find_by_identifier_param(param)
150 def self.find_by_identifier_param(param)
150 if param.to_s =~ /^\d+$/
151 if param.to_s =~ /^\d+$/
151 find_by_id(param)
152 find_by_id(param)
152 else
153 else
153 find_by_identifier(param)
154 find_by_identifier(param)
154 end
155 end
155 end
156 end
156
157
157 # TODO: should return an empty hash instead of nil to avoid many ||{}
158 # TODO: should return an empty hash instead of nil to avoid many ||{}
158 def extra_info
159 def extra_info
159 h = read_attribute(:extra_info)
160 h = read_attribute(:extra_info)
160 h.is_a?(Hash) ? h : nil
161 h.is_a?(Hash) ? h : nil
161 end
162 end
162
163
163 def merge_extra_info(arg)
164 def merge_extra_info(arg)
164 h = extra_info || {}
165 h = extra_info || {}
165 return h if arg.nil?
166 return h if arg.nil?
166 h.merge!(arg)
167 h.merge!(arg)
167 write_attribute(:extra_info, h)
168 write_attribute(:extra_info, h)
168 end
169 end
169
170
170 def report_last_commit
171 def report_last_commit
171 true
172 true
172 end
173 end
173
174
174 def supports_cat?
175 def supports_cat?
175 scm.supports_cat?
176 scm.supports_cat?
176 end
177 end
177
178
178 def supports_annotate?
179 def supports_annotate?
179 scm.supports_annotate?
180 scm.supports_annotate?
180 end
181 end
181
182
182 def supports_all_revisions?
183 def supports_all_revisions?
183 true
184 true
184 end
185 end
185
186
186 def supports_directory_revisions?
187 def supports_directory_revisions?
187 false
188 false
188 end
189 end
189
190
190 def supports_revision_graph?
191 def supports_revision_graph?
191 false
192 false
192 end
193 end
193
194
194 def entry(path=nil, identifier=nil)
195 def entry(path=nil, identifier=nil)
195 scm.entry(path, identifier)
196 scm.entry(path, identifier)
196 end
197 end
197
198
198 def scm_entries(path=nil, identifier=nil)
199 def scm_entries(path=nil, identifier=nil)
199 scm.entries(path, identifier)
200 scm.entries(path, identifier)
200 end
201 end
201 protected :scm_entries
202 protected :scm_entries
202
203
203 def entries(path=nil, identifier=nil)
204 def entries(path=nil, identifier=nil)
204 entries = scm_entries(path, identifier)
205 entries = scm_entries(path, identifier)
205 load_entries_changesets(entries)
206 load_entries_changesets(entries)
206 entries
207 entries
207 end
208 end
208
209
209 def branches
210 def branches
210 scm.branches
211 scm.branches
211 end
212 end
212
213
213 def tags
214 def tags
214 scm.tags
215 scm.tags
215 end
216 end
216
217
217 def default_branch
218 def default_branch
218 nil
219 nil
219 end
220 end
220
221
221 def properties(path, identifier=nil)
222 def properties(path, identifier=nil)
222 scm.properties(path, identifier)
223 scm.properties(path, identifier)
223 end
224 end
224
225
225 def cat(path, identifier=nil)
226 def cat(path, identifier=nil)
226 scm.cat(path, identifier)
227 scm.cat(path, identifier)
227 end
228 end
228
229
229 def diff(path, rev, rev_to)
230 def diff(path, rev, rev_to)
230 scm.diff(path, rev, rev_to)
231 scm.diff(path, rev, rev_to)
231 end
232 end
232
233
233 def diff_format_revisions(cs, cs_to, sep=':')
234 def diff_format_revisions(cs, cs_to, sep=':')
234 text = ""
235 text = ""
235 text << cs_to.format_identifier + sep if cs_to
236 text << cs_to.format_identifier + sep if cs_to
236 text << cs.format_identifier if cs
237 text << cs.format_identifier if cs
237 text
238 text
238 end
239 end
239
240
240 # Returns a path relative to the url of the repository
241 # Returns a path relative to the url of the repository
241 def relative_path(path)
242 def relative_path(path)
242 path
243 path
243 end
244 end
244
245
245 # Finds and returns a revision with a number or the beginning of a hash
246 # Finds and returns a revision with a number or the beginning of a hash
246 def find_changeset_by_name(name)
247 def find_changeset_by_name(name)
247 return nil if name.blank?
248 return nil if name.blank?
248 s = name.to_s
249 s = name.to_s
249 if s.match(/^\d*$/)
250 if s.match(/^\d*$/)
250 changesets.where("revision = ?", s).first
251 changesets.where("revision = ?", s).first
251 else
252 else
252 changesets.where("revision LIKE ?", s + '%').first
253 changesets.where("revision LIKE ?", s + '%').first
253 end
254 end
254 end
255 end
255
256
256 def latest_changeset
257 def latest_changeset
257 @latest_changeset ||= changesets.first
258 @latest_changeset ||= changesets.first
258 end
259 end
259
260
260 # Returns the latest changesets for +path+
261 # Returns the latest changesets for +path+
261 # Default behaviour is to search in cached changesets
262 # Default behaviour is to search in cached changesets
262 def latest_changesets(path, rev, limit=10)
263 def latest_changesets(path, rev, limit=10)
263 if path.blank?
264 if path.blank?
264 changesets.
265 changesets.
265 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
266 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
266 limit(limit).
267 limit(limit).
267 preload(:user).
268 preload(:user).
268 to_a
269 to_a
269 else
270 else
270 filechanges.
271 filechanges.
271 where("path = ?", path.with_leading_slash).
272 where("path = ?", path.with_leading_slash).
272 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
273 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
273 limit(limit).
274 limit(limit).
274 preload(:changeset => :user).
275 preload(:changeset => :user).
275 collect(&:changeset)
276 collect(&:changeset)
276 end
277 end
277 end
278 end
278
279
279 def scan_changesets_for_issue_ids
280 def scan_changesets_for_issue_ids
280 self.changesets.each(&:scan_comment_for_issue_ids)
281 self.changesets.each(&:scan_comment_for_issue_ids)
281 end
282 end
282
283
283 # Returns an array of committers usernames and associated user_id
284 # Returns an array of committers usernames and associated user_id
284 def committers
285 def committers
285 @committers ||= Changeset.where(:repository_id => id).uniq.pluck(:committer, :user_id)
286 @committers ||= Changeset.where(:repository_id => id).uniq.pluck(:committer, :user_id)
286 end
287 end
287
288
288 # Maps committers username to a user ids
289 # Maps committers username to a user ids
289 def committer_ids=(h)
290 def committer_ids=(h)
290 if h.is_a?(Hash)
291 if h.is_a?(Hash)
291 committers.each do |committer, user_id|
292 committers.each do |committer, user_id|
292 new_user_id = h[committer]
293 new_user_id = h[committer]
293 if new_user_id && (new_user_id.to_i != user_id.to_i)
294 if new_user_id && (new_user_id.to_i != user_id.to_i)
294 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
295 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
295 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
296 Changeset.where(["repository_id = ? AND committer = ?", id, committer]).
296 update_all("user_id = #{new_user_id.nil? ? 'NULL' : new_user_id}")
297 update_all("user_id = #{new_user_id.nil? ? 'NULL' : new_user_id}")
297 end
298 end
298 end
299 end
299 @committers = nil
300 @committers = nil
300 @found_committer_users = nil
301 @found_committer_users = nil
301 true
302 true
302 else
303 else
303 false
304 false
304 end
305 end
305 end
306 end
306
307
307 # Returns the Redmine User corresponding to the given +committer+
308 # Returns the Redmine User corresponding to the given +committer+
308 # It will return nil if the committer is not yet mapped and if no User
309 # It will return nil if the committer is not yet mapped and if no User
309 # with the same username or email was found
310 # with the same username or email was found
310 def find_committer_user(committer)
311 def find_committer_user(committer)
311 unless committer.blank?
312 unless committer.blank?
312 @found_committer_users ||= {}
313 @found_committer_users ||= {}
313 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
314 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
314
315
315 user = nil
316 user = nil
316 c = changesets.where(:committer => committer).
317 c = changesets.where(:committer => committer).
317 includes(:user).references(:user).first
318 includes(:user).references(:user).first
318 if c && c.user
319 if c && c.user
319 user = c.user
320 user = c.user
320 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
321 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
321 username, email = $1.strip, $3
322 username, email = $1.strip, $3
322 u = User.find_by_login(username)
323 u = User.find_by_login(username)
323 u ||= User.find_by_mail(email) unless email.blank?
324 u ||= User.find_by_mail(email) unless email.blank?
324 user = u
325 user = u
325 end
326 end
326 @found_committer_users[committer] = user
327 @found_committer_users[committer] = user
327 user
328 user
328 end
329 end
329 end
330 end
330
331
331 def repo_log_encoding
332 def repo_log_encoding
332 encoding = log_encoding.to_s.strip
333 encoding = log_encoding.to_s.strip
333 encoding.blank? ? 'UTF-8' : encoding
334 encoding.blank? ? 'UTF-8' : encoding
334 end
335 end
335
336
336 # Fetches new changesets for all repositories of active projects
337 # Fetches new changesets for all repositories of active projects
337 # Can be called periodically by an external script
338 # Can be called periodically by an external script
338 # eg. ruby script/runner "Repository.fetch_changesets"
339 # eg. ruby script/runner "Repository.fetch_changesets"
339 def self.fetch_changesets
340 def self.fetch_changesets
340 Project.active.has_module(:repository).all.each do |project|
341 Project.active.has_module(:repository).all.each do |project|
341 project.repositories.each do |repository|
342 project.repositories.each do |repository|
342 begin
343 begin
343 repository.fetch_changesets
344 repository.fetch_changesets
344 rescue Redmine::Scm::Adapters::CommandFailed => e
345 rescue Redmine::Scm::Adapters::CommandFailed => e
345 logger.error "scm: error during fetching changesets: #{e.message}"
346 logger.error "scm: error during fetching changesets: #{e.message}"
346 end
347 end
347 end
348 end
348 end
349 end
349 end
350 end
350
351
351 # scan changeset comments to find related and fixed issues for all repositories
352 # scan changeset comments to find related and fixed issues for all repositories
352 def self.scan_changesets_for_issue_ids
353 def self.scan_changesets_for_issue_ids
353 all.each(&:scan_changesets_for_issue_ids)
354 all.each(&:scan_changesets_for_issue_ids)
354 end
355 end
355
356
356 def self.scm_name
357 def self.scm_name
357 'Abstract'
358 'Abstract'
358 end
359 end
359
360
360 def self.available_scm
361 def self.available_scm
361 subclasses.collect {|klass| [klass.scm_name, klass.name]}
362 subclasses.collect {|klass| [klass.scm_name, klass.name]}
362 end
363 end
363
364
364 def self.factory(klass_name, *args)
365 def self.factory(klass_name, *args)
365 klass = "Repository::#{klass_name}".constantize
366 klass = "Repository::#{klass_name}".constantize
366 klass.new(*args)
367 klass.new(*args)
367 rescue
368 rescue
368 nil
369 nil
369 end
370 end
370
371
371 def self.scm_adapter_class
372 def self.scm_adapter_class
372 nil
373 nil
373 end
374 end
374
375
375 def self.scm_command
376 def self.scm_command
376 ret = ""
377 ret = ""
377 begin
378 begin
378 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
379 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
379 rescue Exception => e
380 rescue Exception => e
380 logger.error "scm: error during get command: #{e.message}"
381 logger.error "scm: error during get command: #{e.message}"
381 end
382 end
382 ret
383 ret
383 end
384 end
384
385
385 def self.scm_version_string
386 def self.scm_version_string
386 ret = ""
387 ret = ""
387 begin
388 begin
388 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
389 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
389 rescue Exception => e
390 rescue Exception => e
390 logger.error "scm: error during get version string: #{e.message}"
391 logger.error "scm: error during get version string: #{e.message}"
391 end
392 end
392 ret
393 ret
393 end
394 end
394
395
395 def self.scm_available
396 def self.scm_available
396 ret = false
397 ret = false
397 begin
398 begin
398 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
399 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
399 rescue Exception => e
400 rescue Exception => e
400 logger.error "scm: error during get scm available: #{e.message}"
401 logger.error "scm: error during get scm available: #{e.message}"
401 end
402 end
402 ret
403 ret
403 end
404 end
404
405
405 def set_as_default?
406 def set_as_default?
406 new_record? && project && Repository.where(:project_id => project.id).empty?
407 new_record? && project && Repository.where(:project_id => project.id).empty?
407 end
408 end
408
409
409 # Returns a hash with statistics by author in the following form:
410 # Returns a hash with statistics by author in the following form:
410 # {
411 # {
411 # "John Smith" => { :commits => 45, :changes => 324 },
412 # "John Smith" => { :commits => 45, :changes => 324 },
412 # "Bob" => { ... }
413 # "Bob" => { ... }
413 # }
414 # }
414 #
415 #
415 # Notes:
416 # Notes:
416 # - this hash honnors the users mapping defined for the repository
417 # - this hash honnors the users mapping defined for the repository
417 def stats_by_author
418 def stats_by_author
418 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
419 commits = Changeset.where("repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
419
420
420 #TODO: restore ordering ; this line probably never worked
421 #TODO: restore ordering ; this line probably never worked
421 #commits.to_a.sort! {|x, y| x.last <=> y.last}
422 #commits.to_a.sort! {|x, y| x.last <=> y.last}
422
423
423 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
424 changes = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", id).select("committer, user_id, count(*) as count").group("committer, user_id")
424
425
425 user_ids = changesets.map(&:user_id).compact.uniq
426 user_ids = changesets.map(&:user_id).compact.uniq
426 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
427 authors_names = User.where(:id => user_ids).inject({}) do |memo, user|
427 memo[user.id] = user.to_s
428 memo[user.id] = user.to_s
428 memo
429 memo
429 end
430 end
430
431
431 (commits + changes).inject({}) do |hash, element|
432 (commits + changes).inject({}) do |hash, element|
432 mapped_name = element.committer
433 mapped_name = element.committer
433 if username = authors_names[element.user_id.to_i]
434 if username = authors_names[element.user_id.to_i]
434 mapped_name = username
435 mapped_name = username
435 end
436 end
436 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
437 hash[mapped_name] ||= { :commits_count => 0, :changes_count => 0 }
437 if element.is_a?(Changeset)
438 if element.is_a?(Changeset)
438 hash[mapped_name][:commits_count] += element.count.to_i
439 hash[mapped_name][:commits_count] += element.count.to_i
439 else
440 else
440 hash[mapped_name][:changes_count] += element.count.to_i
441 hash[mapped_name][:changes_count] += element.count.to_i
441 end
442 end
442 hash
443 hash
443 end
444 end
444 end
445 end
445
446
446 # Returns a scope of changesets that come from the same commit as the given changeset
447 # Returns a scope of changesets that come from the same commit as the given changeset
447 # in different repositories that point to the same backend
448 # in different repositories that point to the same backend
448 def same_commits_in_scope(scope, changeset)
449 def same_commits_in_scope(scope, changeset)
449 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
450 scope = scope.joins(:repository).where(:repositories => {:url => url, :root_url => root_url, :type => type})
450 if changeset.scmid.present?
451 if changeset.scmid.present?
451 scope = scope.where(:scmid => changeset.scmid)
452 scope = scope.where(:scmid => changeset.scmid)
452 else
453 else
453 scope = scope.where(:revision => changeset.revision)
454 scope = scope.where(:revision => changeset.revision)
454 end
455 end
455 scope
456 scope
456 end
457 end
457
458
458 protected
459 protected
459
460
460 # Validates repository url based against an optional regular expression
461 # Validates repository url based against an optional regular expression
461 # that can be set in the Redmine configuration file.
462 # that can be set in the Redmine configuration file.
462 def validate_repository_path(attribute=:url)
463 def validate_repository_path(attribute=:url)
463 regexp = Redmine::Configuration["scm_#{scm_name.to_s.downcase}_path_regexp"]
464 regexp = Redmine::Configuration["scm_#{scm_name.to_s.downcase}_path_regexp"]
464 if changes[attribute] && regexp.present?
465 if changes[attribute] && regexp.present?
465 regexp = regexp.to_s.strip.gsub('%project%') {Regexp.escape(project.try(:identifier).to_s)}
466 regexp = regexp.to_s.strip.gsub('%project%') {Regexp.escape(project.try(:identifier).to_s)}
466 unless send(attribute).to_s.match(Regexp.new("\\A#{regexp}\\z"))
467 unless send(attribute).to_s.match(Regexp.new("\\A#{regexp}\\z"))
467 errors.add(attribute, :invalid)
468 errors.add(attribute, :invalid)
468 end
469 end
469 end
470 end
470 end
471 end
471
472
473 def normalize_identifier
474 self.identifier = identifier.to_s.strip
475 end
476
472 def check_default
477 def check_default
473 if !is_default? && set_as_default?
478 if !is_default? && set_as_default?
474 self.is_default = true
479 self.is_default = true
475 end
480 end
476 if is_default? && is_default_changed?
481 if is_default? && is_default_changed?
477 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
482 Repository.where(["project_id = ?", project_id]).update_all(["is_default = ?", false])
478 end
483 end
479 end
484 end
480
485
481 def load_entries_changesets(entries)
486 def load_entries_changesets(entries)
482 if entries
487 if entries
483 entries.each do |entry|
488 entries.each do |entry|
484 if entry.lastrev && entry.lastrev.identifier
489 if entry.lastrev && entry.lastrev.identifier
485 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
490 entry.changeset = find_changeset_by_name(entry.lastrev.identifier)
486 end
491 end
487 end
492 end
488 end
493 end
489 end
494 end
490
495
491 private
496 private
492
497
493 # Deletes repository data
498 # Deletes repository data
494 def clear_changesets
499 def clear_changesets
495 cs = Changeset.table_name
500 cs = Changeset.table_name
496 ch = Change.table_name
501 ch = Change.table_name
497 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
502 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
498 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
503 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
499
504
500 self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
505 self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
501 self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
506 self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
502 self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
507 self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
503 self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
508 self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
504 clear_extra_info_of_changesets
509 clear_extra_info_of_changesets
505 end
510 end
506
511
507 def clear_extra_info_of_changesets
512 def clear_extra_info_of_changesets
508 end
513 end
509 end
514 end
@@ -1,606 +1,606
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoriesGitControllerTest < ActionController::TestCase
20 class RepositoriesGitControllerTest < ActionController::TestCase
21 tests RepositoriesController
21 tests RepositoriesController
22
22
23 fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
23 fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
24 :repositories, :enabled_modules
24 :repositories, :enabled_modules
25
25
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
28 PRJ_ID = 3
28 PRJ_ID = 3
29 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
29 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
30 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
30 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
31 NUM_REV = 28
31 NUM_REV = 28
32
32
33 ## Git, Mercurial and CVS path encodings are binary.
33 ## Git, Mercurial and CVS path encodings are binary.
34 ## Subversion supports URL encoding for path.
34 ## Subversion supports URL encoding for path.
35 ## Redmine Mercurial adapter and extension use URL encoding.
35 ## Redmine Mercurial adapter and extension use URL encoding.
36 ## Git accepts only binary path in command line parameter.
36 ## Git accepts only binary path in command line parameter.
37 ## So, there is no way to use binary command line parameter in JRuby.
37 ## So, there is no way to use binary command line parameter in JRuby.
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40
40
41 def setup
41 def setup
42 @ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
42 @ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
43
43
44 User.current = nil
44 User.current = nil
45 @project = Project.find(PRJ_ID)
45 @project = Project.find(PRJ_ID)
46 @repository = Repository::Git.create(
46 @repository = Repository::Git.create(
47 :project => @project,
47 :project => @project,
48 :url => REPOSITORY_PATH,
48 :url => REPOSITORY_PATH,
49 :path_encoding => 'ISO-8859-1'
49 :path_encoding => 'ISO-8859-1'
50 )
50 )
51 assert @repository
51 assert @repository
52 end
52 end
53
53
54 def test_create_and_update
54 def test_create_and_update
55 @request.session[:user_id] = 1
55 @request.session[:user_id] = 1
56 assert_difference 'Repository.count' do
56 assert_difference 'Repository.count' do
57 post :create, :project_id => 'subproject1',
57 post :create, :project_id => 'subproject1',
58 :repository_scm => 'Git',
58 :repository_scm => 'Git',
59 :repository => {
59 :repository => {
60 :url => '/test',
60 :url => '/test',
61 :is_default => '0',
61 :is_default => '0',
62 :identifier => 'test-create',
62 :identifier => 'test-create',
63 :extra_report_last_commit => '1',
63 :extra_report_last_commit => '1',
64 }
64 }
65 end
65 end
66 assert_response 302
66 assert_response 302
67 repository = Repository.order('id DESC').first
67 repository = Repository.order('id DESC').first
68 assert_kind_of Repository::Git, repository
68 assert_kind_of Repository::Git, repository
69 assert_equal '/test', repository.url
69 assert_equal '/test', repository.url
70 assert_equal true, repository.extra_report_last_commit
70 assert_equal true, repository.extra_report_last_commit
71
71
72 put :update, :id => repository.id,
72 put :update, :id => repository.id,
73 :repository => {
73 :repository => {
74 :extra_report_last_commit => '0'
74 :extra_report_last_commit => '0'
75 }
75 }
76 assert_response 302
76 assert_response 302
77 repo2 = Repository.find(repository.id)
77 repo2 = Repository.find(repository.id)
78 assert_equal false, repo2.extra_report_last_commit
78 assert_equal false, repo2.extra_report_last_commit
79 end
79 end
80
80
81 if File.directory?(REPOSITORY_PATH)
81 if File.directory?(REPOSITORY_PATH)
82 ## Ruby uses ANSI api to fork a process on Windows.
82 ## Ruby uses ANSI api to fork a process on Windows.
83 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
83 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
84 ## and these are incompatible with ASCII.
84 ## and these are incompatible with ASCII.
85 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
85 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
86 ## http://code.google.com/p/msysgit/issues/detail?id=80
86 ## http://code.google.com/p/msysgit/issues/detail?id=80
87 ## So, Latin-1 path tests fail on Japanese Windows
87 ## So, Latin-1 path tests fail on Japanese Windows
88 WINDOWS_PASS = (Redmine::Platform.mswin? &&
88 WINDOWS_PASS = (Redmine::Platform.mswin? &&
89 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
89 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
90 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
90 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
91
91
92 def test_get_new
92 def test_get_new
93 @request.session[:user_id] = 1
93 @request.session[:user_id] = 1
94 @project.repository.destroy
94 @project.repository.destroy
95 get :new, :project_id => 'subproject1', :repository_scm => 'Git'
95 get :new, :project_id => 'subproject1', :repository_scm => 'Git'
96 assert_response :success
96 assert_response :success
97 assert_template 'new'
97 assert_template 'new'
98 assert_kind_of Repository::Git, assigns(:repository)
98 assert_kind_of Repository::Git, assigns(:repository)
99 assert assigns(:repository).new_record?
99 assert assigns(:repository).new_record?
100 end
100 end
101
101
102 def test_browse_root
102 def test_browse_root
103 assert_equal 0, @repository.changesets.count
103 assert_equal 0, @repository.changesets.count
104 @repository.fetch_changesets
104 @repository.fetch_changesets
105 @project.reload
105 @project.reload
106 assert_equal NUM_REV, @repository.changesets.count
106 assert_equal NUM_REV, @repository.changesets.count
107
107
108 get :show, :id => PRJ_ID
108 get :show, :id => PRJ_ID
109 assert_response :success
109 assert_response :success
110 assert_template 'show'
110 assert_template 'show'
111 assert_not_nil assigns(:entries)
111 assert_not_nil assigns(:entries)
112 assert_equal 9, assigns(:entries).size
112 assert_equal 9, assigns(:entries).size
113 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
113 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
114 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
114 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
115 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
115 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
116 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
116 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
117 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
117 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
118 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
118 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
119 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
119 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
120 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
120 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
121 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
121 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
122 assert_not_nil assigns(:changesets)
122 assert_not_nil assigns(:changesets)
123 assert assigns(:changesets).size > 0
123 assert assigns(:changesets).size > 0
124 end
124 end
125
125
126 def test_browse_branch
126 def test_browse_branch
127 assert_equal 0, @repository.changesets.count
127 assert_equal 0, @repository.changesets.count
128 @repository.fetch_changesets
128 @repository.fetch_changesets
129 @project.reload
129 @project.reload
130 assert_equal NUM_REV, @repository.changesets.count
130 assert_equal NUM_REV, @repository.changesets.count
131 get :show, :id => PRJ_ID, :rev => 'test_branch'
131 get :show, :id => PRJ_ID, :rev => 'test_branch'
132 assert_response :success
132 assert_response :success
133 assert_template 'show'
133 assert_template 'show'
134 assert_not_nil assigns(:entries)
134 assert_not_nil assigns(:entries)
135 assert_equal 4, assigns(:entries).size
135 assert_equal 4, assigns(:entries).size
136 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
136 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
137 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
137 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
138 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
138 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
139 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
139 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
140 assert_not_nil assigns(:changesets)
140 assert_not_nil assigns(:changesets)
141 assert assigns(:changesets).size > 0
141 assert assigns(:changesets).size > 0
142 end
142 end
143
143
144 def test_browse_tag
144 def test_browse_tag
145 assert_equal 0, @repository.changesets.count
145 assert_equal 0, @repository.changesets.count
146 @repository.fetch_changesets
146 @repository.fetch_changesets
147 @project.reload
147 @project.reload
148 assert_equal NUM_REV, @repository.changesets.count
148 assert_equal NUM_REV, @repository.changesets.count
149 [
149 [
150 "tag00.lightweight",
150 "tag00.lightweight",
151 "tag01.annotated",
151 "tag01.annotated",
152 ].each do |t1|
152 ].each do |t1|
153 get :show, :id => PRJ_ID, :rev => t1
153 get :show, :id => PRJ_ID, :rev => t1
154 assert_response :success
154 assert_response :success
155 assert_template 'show'
155 assert_template 'show'
156 assert_not_nil assigns(:entries)
156 assert_not_nil assigns(:entries)
157 assert assigns(:entries).size > 0
157 assert assigns(:entries).size > 0
158 assert_not_nil assigns(:changesets)
158 assert_not_nil assigns(:changesets)
159 assert assigns(:changesets).size > 0
159 assert assigns(:changesets).size > 0
160 end
160 end
161 end
161 end
162
162
163 def test_browse_directory
163 def test_browse_directory
164 assert_equal 0, @repository.changesets.count
164 assert_equal 0, @repository.changesets.count
165 @repository.fetch_changesets
165 @repository.fetch_changesets
166 @project.reload
166 @project.reload
167 assert_equal NUM_REV, @repository.changesets.count
167 assert_equal NUM_REV, @repository.changesets.count
168 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
168 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
169 assert_response :success
169 assert_response :success
170 assert_template 'show'
170 assert_template 'show'
171 assert_not_nil assigns(:entries)
171 assert_not_nil assigns(:entries)
172 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
172 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
173 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
173 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
174 assert_not_nil entry
174 assert_not_nil entry
175 assert_equal 'file', entry.kind
175 assert_equal 'file', entry.kind
176 assert_equal 'images/edit.png', entry.path
176 assert_equal 'images/edit.png', entry.path
177 assert_not_nil assigns(:changesets)
177 assert_not_nil assigns(:changesets)
178 assert assigns(:changesets).size > 0
178 assert assigns(:changesets).size > 0
179 end
179 end
180
180
181 def test_browse_at_given_revision
181 def test_browse_at_given_revision
182 assert_equal 0, @repository.changesets.count
182 assert_equal 0, @repository.changesets.count
183 @repository.fetch_changesets
183 @repository.fetch_changesets
184 @project.reload
184 @project.reload
185 assert_equal NUM_REV, @repository.changesets.count
185 assert_equal NUM_REV, @repository.changesets.count
186 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
186 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
187 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
187 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
188 assert_response :success
188 assert_response :success
189 assert_template 'show'
189 assert_template 'show'
190 assert_not_nil assigns(:entries)
190 assert_not_nil assigns(:entries)
191 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
191 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
192 assert_not_nil assigns(:changesets)
192 assert_not_nil assigns(:changesets)
193 assert assigns(:changesets).size > 0
193 assert assigns(:changesets).size > 0
194 end
194 end
195
195
196 def test_changes
196 def test_changes
197 get :changes, :id => PRJ_ID,
197 get :changes, :id => PRJ_ID,
198 :path => repository_path_hash(['images', 'edit.png'])[:param]
198 :path => repository_path_hash(['images', 'edit.png'])[:param]
199 assert_response :success
199 assert_response :success
200 assert_template 'changes'
200 assert_template 'changes'
201 assert_select 'h2', :text => /edit.png/
201 assert_select 'h2', :text => /edit.png/
202 end
202 end
203
203
204 def test_entry_show
204 def test_entry_show
205 get :entry, :id => PRJ_ID,
205 get :entry, :id => PRJ_ID,
206 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
206 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
207 assert_response :success
207 assert_response :success
208 assert_template 'entry'
208 assert_template 'entry'
209 # Line 11
209 # Line 11
210 assert_select 'tr#L11 td.line-code', :text => /WITHOUT ANY WARRANTY/
210 assert_select 'tr#L11 td.line-code', :text => /WITHOUT ANY WARRANTY/
211 end
211 end
212
212
213 def test_entry_show_latin_1
213 def test_entry_show_latin_1
214 if @ruby19_non_utf8_pass
214 if @ruby19_non_utf8_pass
215 puts_ruby19_non_utf8_pass()
215 puts_ruby19_non_utf8_pass()
216 elsif WINDOWS_PASS
216 elsif WINDOWS_PASS
217 puts WINDOWS_SKIP_STR
217 puts WINDOWS_SKIP_STR
218 elsif JRUBY_SKIP
218 elsif JRUBY_SKIP
219 puts JRUBY_SKIP_STR
219 puts JRUBY_SKIP_STR
220 else
220 else
221 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
221 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
222 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
222 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
223 get :entry, :id => PRJ_ID,
223 get :entry, :id => PRJ_ID,
224 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
224 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
225 :rev => r1
225 :rev => r1
226 assert_response :success
226 assert_response :success
227 assert_template 'entry'
227 assert_template 'entry'
228 assert_select 'tr#L1 td.line-code', :text => /test-#{CHAR_1_HEX}.txt/
228 assert_select 'tr#L1 td.line-code', :text => /test-#{CHAR_1_HEX}.txt/
229 end
229 end
230 end
230 end
231 end
231 end
232 end
232 end
233
233
234 def test_entry_download
234 def test_entry_download
235 get :entry, :id => PRJ_ID,
235 get :entry, :id => PRJ_ID,
236 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
236 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
237 :format => 'raw'
237 :format => 'raw'
238 assert_response :success
238 assert_response :success
239 # File content
239 # File content
240 assert @response.body.include?('WITHOUT ANY WARRANTY')
240 assert @response.body.include?('WITHOUT ANY WARRANTY')
241 end
241 end
242
242
243 def test_directory_entry
243 def test_directory_entry
244 get :entry, :id => PRJ_ID,
244 get :entry, :id => PRJ_ID,
245 :path => repository_path_hash(['sources'])[:param]
245 :path => repository_path_hash(['sources'])[:param]
246 assert_response :success
246 assert_response :success
247 assert_template 'show'
247 assert_template 'show'
248 assert_not_nil assigns(:entry)
248 assert_not_nil assigns(:entry)
249 assert_equal 'sources', assigns(:entry).name
249 assert_equal 'sources', assigns(:entry).name
250 end
250 end
251
251
252 def test_diff
252 def test_diff
253 assert_equal true, @repository.is_default
253 assert_equal true, @repository.is_default
254 assert_nil @repository.identifier
254 assert @repository.identifier.blank?
255 assert_equal 0, @repository.changesets.count
255 assert_equal 0, @repository.changesets.count
256 @repository.fetch_changesets
256 @repository.fetch_changesets
257 @project.reload
257 @project.reload
258 assert_equal NUM_REV, @repository.changesets.count
258 assert_equal NUM_REV, @repository.changesets.count
259 # Full diff of changeset 2f9c0091
259 # Full diff of changeset 2f9c0091
260 ['inline', 'sbs'].each do |dt|
260 ['inline', 'sbs'].each do |dt|
261 get :diff,
261 get :diff,
262 :id => PRJ_ID,
262 :id => PRJ_ID,
263 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
263 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
264 :type => dt
264 :type => dt
265 assert_response :success
265 assert_response :success
266 assert_template 'diff'
266 assert_template 'diff'
267 # Line 22 removed
267 # Line 22 removed
268 assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
268 assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
269 assert_select 'h2', :text => /2f9c0091/
269 assert_select 'h2', :text => /2f9c0091/
270 end
270 end
271 end
271 end
272
272
273 def test_diff_with_rev_and_path
273 def test_diff_with_rev_and_path
274 assert_equal 0, @repository.changesets.count
274 assert_equal 0, @repository.changesets.count
275 @repository.fetch_changesets
275 @repository.fetch_changesets
276 @project.reload
276 @project.reload
277 assert_equal NUM_REV, @repository.changesets.count
277 assert_equal NUM_REV, @repository.changesets.count
278 with_settings :diff_max_lines_displayed => 1000 do
278 with_settings :diff_max_lines_displayed => 1000 do
279 # Full diff of changeset 2f9c0091
279 # Full diff of changeset 2f9c0091
280 ['inline', 'sbs'].each do |dt|
280 ['inline', 'sbs'].each do |dt|
281 get :diff,
281 get :diff,
282 :id => PRJ_ID,
282 :id => PRJ_ID,
283 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
283 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
284 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
284 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
285 :type => dt
285 :type => dt
286 assert_response :success
286 assert_response :success
287 assert_template 'diff'
287 assert_template 'diff'
288 # Line 22 removed
288 # Line 22 removed
289 assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
289 assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
290 assert_select 'h2', :text => /2f9c0091/
290 assert_select 'h2', :text => /2f9c0091/
291 end
291 end
292 end
292 end
293 end
293 end
294
294
295 def test_diff_truncated
295 def test_diff_truncated
296 assert_equal 0, @repository.changesets.count
296 assert_equal 0, @repository.changesets.count
297 @repository.fetch_changesets
297 @repository.fetch_changesets
298 @project.reload
298 @project.reload
299 assert_equal NUM_REV, @repository.changesets.count
299 assert_equal NUM_REV, @repository.changesets.count
300
300
301 with_settings :diff_max_lines_displayed => 5 do
301 with_settings :diff_max_lines_displayed => 5 do
302 # Truncated diff of changeset 2f9c0091
302 # Truncated diff of changeset 2f9c0091
303 with_cache do
303 with_cache do
304 with_settings :default_language => 'en' do
304 with_settings :default_language => 'en' do
305 get :diff, :id => PRJ_ID, :type => 'inline',
305 get :diff, :id => PRJ_ID, :type => 'inline',
306 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
306 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
307 assert_response :success
307 assert_response :success
308 assert @response.body.include?("... This diff was truncated")
308 assert @response.body.include?("... This diff was truncated")
309 end
309 end
310 with_settings :default_language => 'fr' do
310 with_settings :default_language => 'fr' do
311 get :diff, :id => PRJ_ID, :type => 'inline',
311 get :diff, :id => PRJ_ID, :type => 'inline',
312 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
312 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
313 assert_response :success
313 assert_response :success
314 assert ! @response.body.include?("... This diff was truncated")
314 assert ! @response.body.include?("... This diff was truncated")
315 assert @response.body.include?("... Ce diff")
315 assert @response.body.include?("... Ce diff")
316 end
316 end
317 end
317 end
318 end
318 end
319 end
319 end
320
320
321 def test_diff_two_revs
321 def test_diff_two_revs
322 assert_equal 0, @repository.changesets.count
322 assert_equal 0, @repository.changesets.count
323 @repository.fetch_changesets
323 @repository.fetch_changesets
324 @project.reload
324 @project.reload
325 assert_equal NUM_REV, @repository.changesets.count
325 assert_equal NUM_REV, @repository.changesets.count
326 ['inline', 'sbs'].each do |dt|
326 ['inline', 'sbs'].each do |dt|
327 get :diff,
327 get :diff,
328 :id => PRJ_ID,
328 :id => PRJ_ID,
329 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
329 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
330 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
330 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
331 :type => dt
331 :type => dt
332 assert_response :success
332 assert_response :success
333 assert_template 'diff'
333 assert_template 'diff'
334 diff = assigns(:diff)
334 diff = assigns(:diff)
335 assert_not_nil diff
335 assert_not_nil diff
336 assert_select 'h2', :text => /2f9c0091:61b685fb/
336 assert_select 'h2', :text => /2f9c0091:61b685fb/
337 assert_select 'form[action=?]', '/projects/subproject1/repository/revisions/61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff'
337 assert_select 'form[action=?]', '/projects/subproject1/repository/revisions/61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff'
338 assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
338 assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
339 end
339 end
340 end
340 end
341
341
342 def test_diff_path_in_subrepo
342 def test_diff_path_in_subrepo
343 repo = Repository::Git.create(
343 repo = Repository::Git.create(
344 :project => @project,
344 :project => @project,
345 :url => REPOSITORY_PATH,
345 :url => REPOSITORY_PATH,
346 :identifier => 'test-diff-path',
346 :identifier => 'test-diff-path',
347 :path_encoding => 'ISO-8859-1'
347 :path_encoding => 'ISO-8859-1'
348 )
348 )
349 assert repo
349 assert repo
350 assert_equal false, repo.is_default
350 assert_equal false, repo.is_default
351 assert_equal 'test-diff-path', repo.identifier
351 assert_equal 'test-diff-path', repo.identifier
352 get :diff,
352 get :diff,
353 :id => PRJ_ID,
353 :id => PRJ_ID,
354 :repository_id => 'test-diff-path',
354 :repository_id => 'test-diff-path',
355 :rev => '61b685fbe55ab05b',
355 :rev => '61b685fbe55ab05b',
356 :rev_to => '2f9c0091c754a91a',
356 :rev_to => '2f9c0091c754a91a',
357 :type => 'inline'
357 :type => 'inline'
358 assert_response :success
358 assert_response :success
359 assert_template 'diff'
359 assert_template 'diff'
360 diff = assigns(:diff)
360 diff = assigns(:diff)
361 assert_not_nil diff
361 assert_not_nil diff
362 assert_select 'form[action=?]', '/projects/subproject1/repository/test-diff-path/revisions/61b685fbe55ab05b/diff'
362 assert_select 'form[action=?]', '/projects/subproject1/repository/test-diff-path/revisions/61b685fbe55ab05b/diff'
363 assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91a'
363 assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91a'
364 end
364 end
365
365
366 def test_diff_latin_1
366 def test_diff_latin_1
367 if @ruby19_non_utf8_pass
367 if @ruby19_non_utf8_pass
368 puts_ruby19_non_utf8_pass()
368 puts_ruby19_non_utf8_pass()
369 else
369 else
370 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
370 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
371 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
371 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
372 ['inline', 'sbs'].each do |dt|
372 ['inline', 'sbs'].each do |dt|
373 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
373 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
374 assert_response :success
374 assert_response :success
375 assert_template 'diff'
375 assert_template 'diff'
376 assert_select 'table' do
376 assert_select 'table' do
377 assert_select 'thead th.filename', :text => /latin-1-dir\/test-#{CHAR_1_HEX}.txt/
377 assert_select 'thead th.filename', :text => /latin-1-dir\/test-#{CHAR_1_HEX}.txt/
378 assert_select 'tbody td.diff_in', :text => /test-#{CHAR_1_HEX}.txt/
378 assert_select 'tbody td.diff_in', :text => /test-#{CHAR_1_HEX}.txt/
379 end
379 end
380 end
380 end
381 end
381 end
382 end
382 end
383 end
383 end
384 end
384 end
385
385
386 def test_diff_should_show_filenames
386 def test_diff_should_show_filenames
387 get :diff, :id => PRJ_ID, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3', :type => 'inline'
387 get :diff, :id => PRJ_ID, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3', :type => 'inline'
388 assert_response :success
388 assert_response :success
389 assert_template 'diff'
389 assert_template 'diff'
390 # modified file
390 # modified file
391 assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
391 assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
392 # deleted file
392 # deleted file
393 assert_select 'th.filename', :text => 'test.txt'
393 assert_select 'th.filename', :text => 'test.txt'
394 end
394 end
395
395
396 def test_save_diff_type
396 def test_save_diff_type
397 user1 = User.find(1)
397 user1 = User.find(1)
398 user1.pref[:diff_type] = nil
398 user1.pref[:diff_type] = nil
399 user1.preference.save
399 user1.preference.save
400 user = User.find(1)
400 user = User.find(1)
401 assert_nil user.pref[:diff_type]
401 assert_nil user.pref[:diff_type]
402
402
403 @request.session[:user_id] = 1 # admin
403 @request.session[:user_id] = 1 # admin
404 get :diff,
404 get :diff,
405 :id => PRJ_ID,
405 :id => PRJ_ID,
406 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
406 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
407 assert_response :success
407 assert_response :success
408 assert_template 'diff'
408 assert_template 'diff'
409 user.reload
409 user.reload
410 assert_equal "inline", user.pref[:diff_type]
410 assert_equal "inline", user.pref[:diff_type]
411 get :diff,
411 get :diff,
412 :id => PRJ_ID,
412 :id => PRJ_ID,
413 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
413 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
414 :type => 'sbs'
414 :type => 'sbs'
415 assert_response :success
415 assert_response :success
416 assert_template 'diff'
416 assert_template 'diff'
417 user.reload
417 user.reload
418 assert_equal "sbs", user.pref[:diff_type]
418 assert_equal "sbs", user.pref[:diff_type]
419 end
419 end
420
420
421 def test_annotate
421 def test_annotate
422 get :annotate, :id => PRJ_ID,
422 get :annotate, :id => PRJ_ID,
423 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
423 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
424 assert_response :success
424 assert_response :success
425 assert_template 'annotate'
425 assert_template 'annotate'
426
426
427 # Line 23, changeset 2f9c0091
427 # Line 23, changeset 2f9c0091
428 assert_select 'tr' do
428 assert_select 'tr' do
429 assert_select 'th.line-num', :text => '23'
429 assert_select 'th.line-num', :text => '23'
430 assert_select 'td.revision', :text => /2f9c0091/
430 assert_select 'td.revision', :text => /2f9c0091/
431 assert_select 'td.author', :text => 'jsmith'
431 assert_select 'td.author', :text => 'jsmith'
432 assert_select 'td', :text => /remove_watcher/
432 assert_select 'td', :text => /remove_watcher/
433 end
433 end
434 end
434 end
435
435
436 def test_annotate_at_given_revision
436 def test_annotate_at_given_revision
437 assert_equal 0, @repository.changesets.count
437 assert_equal 0, @repository.changesets.count
438 @repository.fetch_changesets
438 @repository.fetch_changesets
439 @project.reload
439 @project.reload
440 assert_equal NUM_REV, @repository.changesets.count
440 assert_equal NUM_REV, @repository.changesets.count
441 get :annotate, :id => PRJ_ID, :rev => 'deff7',
441 get :annotate, :id => PRJ_ID, :rev => 'deff7',
442 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
442 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
443 assert_response :success
443 assert_response :success
444 assert_template 'annotate'
444 assert_template 'annotate'
445 assert_select 'h2', :text => /@ deff712f/
445 assert_select 'h2', :text => /@ deff712f/
446 end
446 end
447
447
448 def test_annotate_binary_file
448 def test_annotate_binary_file
449 with_settings :default_language => 'en' do
449 with_settings :default_language => 'en' do
450 get :annotate, :id => PRJ_ID,
450 get :annotate, :id => PRJ_ID,
451 :path => repository_path_hash(['images', 'edit.png'])[:param]
451 :path => repository_path_hash(['images', 'edit.png'])[:param]
452 assert_response 500
452 assert_response 500
453 assert_select 'p#errorExplanation', :text => /cannot be annotated/
453 assert_select 'p#errorExplanation', :text => /cannot be annotated/
454 end
454 end
455 end
455 end
456
456
457 def test_annotate_error_when_too_big
457 def test_annotate_error_when_too_big
458 with_settings :file_max_size_displayed => 1 do
458 with_settings :file_max_size_displayed => 1 do
459 get :annotate, :id => PRJ_ID,
459 get :annotate, :id => PRJ_ID,
460 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
460 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
461 :rev => 'deff712f'
461 :rev => 'deff712f'
462 assert_response 500
462 assert_response 500
463 assert_select 'p#errorExplanation', :text => /exceeds the maximum text file size/
463 assert_select 'p#errorExplanation', :text => /exceeds the maximum text file size/
464
464
465 get :annotate, :id => PRJ_ID,
465 get :annotate, :id => PRJ_ID,
466 :path => repository_path_hash(['README'])[:param],
466 :path => repository_path_hash(['README'])[:param],
467 :rev => '7234cb2'
467 :rev => '7234cb2'
468 assert_response :success
468 assert_response :success
469 assert_template 'annotate'
469 assert_template 'annotate'
470 end
470 end
471 end
471 end
472
472
473 def test_annotate_latin_1
473 def test_annotate_latin_1
474 if @ruby19_non_utf8_pass
474 if @ruby19_non_utf8_pass
475 puts_ruby19_non_utf8_pass()
475 puts_ruby19_non_utf8_pass()
476 elsif WINDOWS_PASS
476 elsif WINDOWS_PASS
477 puts WINDOWS_SKIP_STR
477 puts WINDOWS_SKIP_STR
478 elsif JRUBY_SKIP
478 elsif JRUBY_SKIP
479 puts JRUBY_SKIP_STR
479 puts JRUBY_SKIP_STR
480 else
480 else
481 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
481 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
482 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
482 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
483 get :annotate, :id => PRJ_ID,
483 get :annotate, :id => PRJ_ID,
484 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
484 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
485 :rev => r1
485 :rev => r1
486 assert_select "th.line-num", :text => '1' do
486 assert_select "th.line-num", :text => '1' do
487 assert_select "+ td.revision" do
487 assert_select "+ td.revision" do
488 assert_select "a", :text => '57ca437c'
488 assert_select "a", :text => '57ca437c'
489 assert_select "+ td.author", :text => "jsmith" do
489 assert_select "+ td.author", :text => "jsmith" do
490 assert_select "+ td",
490 assert_select "+ td",
491 :text => "test-#{CHAR_1_HEX}.txt"
491 :text => "test-#{CHAR_1_HEX}.txt"
492 end
492 end
493 end
493 end
494 end
494 end
495 end
495 end
496 end
496 end
497 end
497 end
498 end
498 end
499
499
500 def test_annotate_latin_1_author
500 def test_annotate_latin_1_author
501 ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
501 ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
502 get :annotate, :id => PRJ_ID,
502 get :annotate, :id => PRJ_ID,
503 :path => repository_path_hash([" filename with a leading space.txt "])[:param],
503 :path => repository_path_hash([" filename with a leading space.txt "])[:param],
504 :rev => r1
504 :rev => r1
505 assert_select "th.line-num", :text => '1' do
505 assert_select "th.line-num", :text => '1' do
506 assert_select "+ td.revision" do
506 assert_select "+ td.revision" do
507 assert_select "a", :text => '83ca5fd5'
507 assert_select "a", :text => '83ca5fd5'
508 assert_select "+ td.author", :text => FELIX_HEX do
508 assert_select "+ td.author", :text => FELIX_HEX do
509 assert_select "+ td",
509 assert_select "+ td",
510 :text => "And this is a file with a leading and trailing space..."
510 :text => "And this is a file with a leading and trailing space..."
511 end
511 end
512 end
512 end
513 end
513 end
514 end
514 end
515 end
515 end
516
516
517 def test_revisions
517 def test_revisions
518 assert_equal 0, @repository.changesets.count
518 assert_equal 0, @repository.changesets.count
519 @repository.fetch_changesets
519 @repository.fetch_changesets
520 @project.reload
520 @project.reload
521 assert_equal NUM_REV, @repository.changesets.count
521 assert_equal NUM_REV, @repository.changesets.count
522 get :revisions, :id => PRJ_ID
522 get :revisions, :id => PRJ_ID
523 assert_response :success
523 assert_response :success
524 assert_template 'revisions'
524 assert_template 'revisions'
525 assert_select 'form[method=get][action=?]', '/projects/subproject1/repository/revision'
525 assert_select 'form[method=get][action=?]', '/projects/subproject1/repository/revision'
526 end
526 end
527
527
528 def test_revision
528 def test_revision
529 assert_equal 0, @repository.changesets.count
529 assert_equal 0, @repository.changesets.count
530 @repository.fetch_changesets
530 @repository.fetch_changesets
531 @project.reload
531 @project.reload
532 assert_equal NUM_REV, @repository.changesets.count
532 assert_equal NUM_REV, @repository.changesets.count
533 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
533 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
534 get :revision, :id => PRJ_ID, :rev => r
534 get :revision, :id => PRJ_ID, :rev => r
535 assert_response :success
535 assert_response :success
536 assert_template 'revision'
536 assert_template 'revision'
537 end
537 end
538 end
538 end
539
539
540 def test_empty_revision
540 def test_empty_revision
541 assert_equal 0, @repository.changesets.count
541 assert_equal 0, @repository.changesets.count
542 @repository.fetch_changesets
542 @repository.fetch_changesets
543 @project.reload
543 @project.reload
544 assert_equal NUM_REV, @repository.changesets.count
544 assert_equal NUM_REV, @repository.changesets.count
545 ['', ' ', nil].each do |r|
545 ['', ' ', nil].each do |r|
546 get :revision, :id => PRJ_ID, :rev => r
546 get :revision, :id => PRJ_ID, :rev => r
547 assert_response 404
547 assert_response 404
548 assert_select_error /was not found/
548 assert_select_error /was not found/
549 end
549 end
550 end
550 end
551
551
552 def test_destroy_valid_repository
552 def test_destroy_valid_repository
553 @request.session[:user_id] = 1 # admin
553 @request.session[:user_id] = 1 # admin
554 assert_equal 0, @repository.changesets.count
554 assert_equal 0, @repository.changesets.count
555 @repository.fetch_changesets
555 @repository.fetch_changesets
556 @project.reload
556 @project.reload
557 assert_equal NUM_REV, @repository.changesets.count
557 assert_equal NUM_REV, @repository.changesets.count
558
558
559 assert_difference 'Repository.count', -1 do
559 assert_difference 'Repository.count', -1 do
560 delete :destroy, :id => @repository.id
560 delete :destroy, :id => @repository.id
561 end
561 end
562 assert_response 302
562 assert_response 302
563 @project.reload
563 @project.reload
564 assert_nil @project.repository
564 assert_nil @project.repository
565 end
565 end
566
566
567 def test_destroy_invalid_repository
567 def test_destroy_invalid_repository
568 @request.session[:user_id] = 1 # admin
568 @request.session[:user_id] = 1 # admin
569 @project.repository.destroy
569 @project.repository.destroy
570 @repository = Repository::Git.create!(
570 @repository = Repository::Git.create!(
571 :project => @project,
571 :project => @project,
572 :url => "/invalid",
572 :url => "/invalid",
573 :path_encoding => 'ISO-8859-1'
573 :path_encoding => 'ISO-8859-1'
574 )
574 )
575 @repository.fetch_changesets
575 @repository.fetch_changesets
576 @repository.reload
576 @repository.reload
577 assert_equal 0, @repository.changesets.count
577 assert_equal 0, @repository.changesets.count
578
578
579 assert_difference 'Repository.count', -1 do
579 assert_difference 'Repository.count', -1 do
580 delete :destroy, :id => @repository.id
580 delete :destroy, :id => @repository.id
581 end
581 end
582 assert_response 302
582 assert_response 302
583 @project.reload
583 @project.reload
584 assert_nil @project.repository
584 assert_nil @project.repository
585 end
585 end
586
586
587 private
587 private
588
588
589 def puts_ruby19_non_utf8_pass
589 def puts_ruby19_non_utf8_pass
590 puts "TODO: This test fails " +
590 puts "TODO: This test fails " +
591 "when Encoding.default_external is not UTF-8. " +
591 "when Encoding.default_external is not UTF-8. " +
592 "Current value is '#{Encoding.default_external.to_s}'"
592 "Current value is '#{Encoding.default_external.to_s}'"
593 end
593 end
594 else
594 else
595 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
595 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
596 def test_fake; assert true end
596 def test_fake; assert true end
597 end
597 end
598
598
599 private
599 private
600 def with_cache(&block)
600 def with_cache(&block)
601 before = ActionController::Base.perform_caching
601 before = ActionController::Base.perform_caching
602 ActionController::Base.perform_caching = true
602 ActionController::Base.perform_caching = true
603 block.call
603 block.call
604 ActionController::Base.perform_caching = before
604 ActionController::Base.perform_caching = before
605 end
605 end
606 end
606 end
@@ -1,621 +1,623
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryGitTest < ActiveSupport::TestCase
20 class RepositoryGitTest < ActiveSupport::TestCase
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
21 fixtures :projects, :repositories, :enabled_modules, :users, :roles
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27
27
28 NUM_REV = 28
28 NUM_REV = 28
29 NUM_HEAD = 6
29 NUM_HEAD = 6
30
30
31 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
31 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
32 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
32 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
33
33
34 ## Git, Mercurial and CVS path encodings are binary.
34 ## Git, Mercurial and CVS path encodings are binary.
35 ## Subversion supports URL encoding for path.
35 ## Subversion supports URL encoding for path.
36 ## Redmine Mercurial adapter and extension use URL encoding.
36 ## Redmine Mercurial adapter and extension use URL encoding.
37 ## Git accepts only binary path in command line parameter.
37 ## Git accepts only binary path in command line parameter.
38 ## So, there is no way to use binary command line parameter in JRuby.
38 ## So, there is no way to use binary command line parameter in JRuby.
39 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
39 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
40 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
41
41
42 def setup
42 def setup
43 @project = Project.find(3)
43 @project = Project.find(3)
44 @repository = Repository::Git.create(
44 @repository = Repository::Git.create(
45 :project => @project,
45 :project => @project,
46 :url => REPOSITORY_PATH,
46 :url => REPOSITORY_PATH,
47 :path_encoding => 'ISO-8859-1'
47 :path_encoding => 'ISO-8859-1'
48 )
48 )
49 assert @repository
49 assert @repository
50 end
50 end
51
51
52 def test_nondefault_repo_with_blank_identifier_destruction
52 def test_nondefault_repo_with_blank_identifier_destruction
53 Repository.delete_all
54
53 repo1 = Repository::Git.new(
55 repo1 = Repository::Git.new(
54 :project => @project,
56 :project => @project,
55 :url => REPOSITORY_PATH,
57 :url => REPOSITORY_PATH,
56 :identifier => '',
58 :identifier => '',
57 :is_default => true
59 :is_default => true
58 )
60 )
59 assert repo1.save
61 assert repo1.save
60 repo1.fetch_changesets
62 repo1.fetch_changesets
61
63
62 repo2 = Repository::Git.new(
64 repo2 = Repository::Git.new(
63 :project => @project,
65 :project => @project,
64 :url => REPOSITORY_PATH,
66 :url => REPOSITORY_PATH,
65 :identifier => 'repo2',
67 :identifier => 'repo2',
66 :is_default => true
68 :is_default => true
67 )
69 )
68 assert repo2.save
70 assert repo2.save
69 repo2.fetch_changesets
71 repo2.fetch_changesets
70
72
71 repo1.reload
73 repo1.reload
72 repo2.reload
74 repo2.reload
73 assert !repo1.is_default?
75 assert !repo1.is_default?
74 assert repo2.is_default?
76 assert repo2.is_default?
75
77
76 assert_difference 'Repository.count', -1 do
78 assert_difference 'Repository.count', -1 do
77 repo1.destroy
79 repo1.destroy
78 end
80 end
79 end
81 end
80
82
81 def test_blank_path_to_repository_error_message
83 def test_blank_path_to_repository_error_message
82 set_language_if_valid 'en'
84 set_language_if_valid 'en'
83 repo = Repository::Git.new(
85 repo = Repository::Git.new(
84 :project => @project,
86 :project => @project,
85 :identifier => 'test'
87 :identifier => 'test'
86 )
88 )
87 assert !repo.save
89 assert !repo.save
88 assert_include "Path to repository cannot be blank",
90 assert_include "Path to repository cannot be blank",
89 repo.errors.full_messages
91 repo.errors.full_messages
90 end
92 end
91
93
92 def test_blank_path_to_repository_error_message_fr
94 def test_blank_path_to_repository_error_message_fr
93 set_language_if_valid 'fr'
95 set_language_if_valid 'fr'
94 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
96 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
95 repo = Repository::Git.new(
97 repo = Repository::Git.new(
96 :project => @project,
98 :project => @project,
97 :url => "",
99 :url => "",
98 :identifier => 'test',
100 :identifier => 'test',
99 :path_encoding => ''
101 :path_encoding => ''
100 )
102 )
101 assert !repo.save
103 assert !repo.save
102 assert_include str, repo.errors.full_messages
104 assert_include str, repo.errors.full_messages
103 end
105 end
104
106
105 if File.directory?(REPOSITORY_PATH)
107 if File.directory?(REPOSITORY_PATH)
106 ## Ruby uses ANSI api to fork a process on Windows.
108 ## Ruby uses ANSI api to fork a process on Windows.
107 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
109 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
108 ## and these are incompatible with ASCII.
110 ## and these are incompatible with ASCII.
109 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
111 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
110 ## http://code.google.com/p/msysgit/issues/detail?id=80
112 ## http://code.google.com/p/msysgit/issues/detail?id=80
111 ## So, Latin-1 path tests fail on Japanese Windows
113 ## So, Latin-1 path tests fail on Japanese Windows
112 WINDOWS_PASS = (Redmine::Platform.mswin? &&
114 WINDOWS_PASS = (Redmine::Platform.mswin? &&
113 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
115 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
114 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
116 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
115
117
116 def test_scm_available
118 def test_scm_available
117 klass = Repository::Git
119 klass = Repository::Git
118 assert_equal "Git", klass.scm_name
120 assert_equal "Git", klass.scm_name
119 assert klass.scm_adapter_class
121 assert klass.scm_adapter_class
120 assert_not_equal "", klass.scm_command
122 assert_not_equal "", klass.scm_command
121 assert_equal true, klass.scm_available
123 assert_equal true, klass.scm_available
122 end
124 end
123
125
124 def test_entries
126 def test_entries
125 entries = @repository.entries
127 entries = @repository.entries
126 assert_kind_of Redmine::Scm::Adapters::Entries, entries
128 assert_kind_of Redmine::Scm::Adapters::Entries, entries
127 end
129 end
128
130
129 def test_fetch_changesets_from_scratch
131 def test_fetch_changesets_from_scratch
130 assert_nil @repository.extra_info
132 assert_nil @repository.extra_info
131
133
132 assert_equal 0, @repository.changesets.count
134 assert_equal 0, @repository.changesets.count
133 @repository.fetch_changesets
135 @repository.fetch_changesets
134 @project.reload
136 @project.reload
135
137
136 assert_equal NUM_REV, @repository.changesets.count
138 assert_equal NUM_REV, @repository.changesets.count
137 assert_equal 39, @repository.filechanges.count
139 assert_equal 39, @repository.filechanges.count
138
140
139 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
141 commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
140 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
142 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
141 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
143 assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments
142 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
144 assert_equal "jsmith <jsmith@foo.bar>", commit.committer
143 assert_equal User.find_by_login('jsmith'), commit.user
145 assert_equal User.find_by_login('jsmith'), commit.user
144 # TODO: add a commit with commit time <> author time to the test repository
146 # TODO: add a commit with commit time <> author time to the test repository
145 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
147 assert_equal Time.gm(2007, 12, 14, 9, 22, 52), commit.committed_on
146 assert_equal "2007-12-14".to_date, commit.commit_date
148 assert_equal "2007-12-14".to_date, commit.commit_date
147 assert_equal 3, commit.filechanges.count
149 assert_equal 3, commit.filechanges.count
148 change = commit.filechanges.sort_by(&:path).first
150 change = commit.filechanges.sort_by(&:path).first
149 assert_equal "README", change.path
151 assert_equal "README", change.path
150 assert_equal nil, change.from_path
152 assert_equal nil, change.from_path
151 assert_equal "A", change.action
153 assert_equal "A", change.action
152
154
153 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
155 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
154 end
156 end
155
157
156 def test_fetch_changesets_incremental
158 def test_fetch_changesets_incremental
157 assert_equal 0, @repository.changesets.count
159 assert_equal 0, @repository.changesets.count
158 @repository.fetch_changesets
160 @repository.fetch_changesets
159 @project.reload
161 @project.reload
160 assert_equal NUM_REV, @repository.changesets.count
162 assert_equal NUM_REV, @repository.changesets.count
161 extra_info_heads = @repository.extra_info["heads"].dup
163 extra_info_heads = @repository.extra_info["heads"].dup
162 assert_equal NUM_HEAD, extra_info_heads.size
164 assert_equal NUM_HEAD, extra_info_heads.size
163 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
165 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
164 assert_equal 4, extra_info_heads.size
166 assert_equal 4, extra_info_heads.size
165
167
166 del_revs = [
168 del_revs = [
167 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
169 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
168 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
170 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
169 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
171 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
170 "deff712f05a90d96edbd70facc47d944be5897e3",
172 "deff712f05a90d96edbd70facc47d944be5897e3",
171 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
173 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
172 "7e61ac704deecde634b51e59daa8110435dcb3da",
174 "7e61ac704deecde634b51e59daa8110435dcb3da",
173 ]
175 ]
174 @repository.changesets.each do |rev|
176 @repository.changesets.each do |rev|
175 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
177 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
176 end
178 end
177 @project.reload
179 @project.reload
178 cs1 = @repository.changesets
180 cs1 = @repository.changesets
179 assert_equal NUM_REV - 6, cs1.count
181 assert_equal NUM_REV - 6, cs1.count
180 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
182 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
181 h = {}
183 h = {}
182 h["heads"] = extra_info_heads
184 h["heads"] = extra_info_heads
183 @repository.merge_extra_info(h)
185 @repository.merge_extra_info(h)
184 @repository.save
186 @repository.save
185 @project.reload
187 @project.reload
186 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
188 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
187 @repository.fetch_changesets
189 @repository.fetch_changesets
188 @project.reload
190 @project.reload
189 assert_equal NUM_REV, @repository.changesets.count
191 assert_equal NUM_REV, @repository.changesets.count
190 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
192 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
191 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
193 assert @repository.extra_info["heads"].index("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c")
192 end
194 end
193
195
194 def test_fetch_changesets_history_editing
196 def test_fetch_changesets_history_editing
195 assert_equal 0, @repository.changesets.count
197 assert_equal 0, @repository.changesets.count
196 @repository.fetch_changesets
198 @repository.fetch_changesets
197 @project.reload
199 @project.reload
198 assert_equal NUM_REV, @repository.changesets.count
200 assert_equal NUM_REV, @repository.changesets.count
199 extra_info_heads = @repository.extra_info["heads"].dup
201 extra_info_heads = @repository.extra_info["heads"].dup
200 assert_equal NUM_HEAD, extra_info_heads.size
202 assert_equal NUM_HEAD, extra_info_heads.size
201 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
203 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
202 assert_equal 4, extra_info_heads.size
204 assert_equal 4, extra_info_heads.size
203
205
204 del_revs = [
206 del_revs = [
205 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
207 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
206 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
208 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
207 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
209 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
208 "deff712f05a90d96edbd70facc47d944be5897e3",
210 "deff712f05a90d96edbd70facc47d944be5897e3",
209 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
211 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
210 "7e61ac704deecde634b51e59daa8110435dcb3da",
212 "7e61ac704deecde634b51e59daa8110435dcb3da",
211 ]
213 ]
212 @repository.changesets.each do |rev|
214 @repository.changesets.each do |rev|
213 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
215 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
214 end
216 end
215 @project.reload
217 @project.reload
216 assert_equal NUM_REV - 6, @repository.changesets.count
218 assert_equal NUM_REV - 6, @repository.changesets.count
217
219
218 c = Changeset.new(:repository => @repository,
220 c = Changeset.new(:repository => @repository,
219 :committed_on => Time.now,
221 :committed_on => Time.now,
220 :revision => "abcd1234efgh",
222 :revision => "abcd1234efgh",
221 :scmid => "abcd1234efgh",
223 :scmid => "abcd1234efgh",
222 :comments => 'test')
224 :comments => 'test')
223 assert c.save
225 assert c.save
224 @project.reload
226 @project.reload
225 assert_equal NUM_REV - 5, @repository.changesets.count
227 assert_equal NUM_REV - 5, @repository.changesets.count
226
228
227 extra_info_heads << "1234abcd5678"
229 extra_info_heads << "1234abcd5678"
228 h = {}
230 h = {}
229 h["heads"] = extra_info_heads
231 h["heads"] = extra_info_heads
230 @repository.merge_extra_info(h)
232 @repository.merge_extra_info(h)
231 @repository.save
233 @repository.save
232 @project.reload
234 @project.reload
233 h1 = @repository.extra_info["heads"].dup
235 h1 = @repository.extra_info["heads"].dup
234 assert h1.index("1234abcd5678")
236 assert h1.index("1234abcd5678")
235 assert_equal 5, h1.size
237 assert_equal 5, h1.size
236
238
237 @repository.fetch_changesets
239 @repository.fetch_changesets
238 @project.reload
240 @project.reload
239 assert_equal NUM_REV - 5, @repository.changesets.count
241 assert_equal NUM_REV - 5, @repository.changesets.count
240 h2 = @repository.extra_info["heads"].dup
242 h2 = @repository.extra_info["heads"].dup
241 assert_equal h1, h2
243 assert_equal h1, h2
242 end
244 end
243
245
244 def test_keep_extra_report_last_commit_in_clear_changesets
246 def test_keep_extra_report_last_commit_in_clear_changesets
245 assert_nil @repository.extra_info
247 assert_nil @repository.extra_info
246 h = {}
248 h = {}
247 h["extra_report_last_commit"] = "1"
249 h["extra_report_last_commit"] = "1"
248 @repository.merge_extra_info(h)
250 @repository.merge_extra_info(h)
249 @repository.save
251 @repository.save
250 @project.reload
252 @project.reload
251
253
252 assert_equal 0, @repository.changesets.count
254 assert_equal 0, @repository.changesets.count
253 @repository.fetch_changesets
255 @repository.fetch_changesets
254 @project.reload
256 @project.reload
255
257
256 assert_equal NUM_REV, @repository.changesets.count
258 assert_equal NUM_REV, @repository.changesets.count
257 @repository.send(:clear_changesets)
259 @repository.send(:clear_changesets)
258 assert_equal 1, @repository.extra_info.size
260 assert_equal 1, @repository.extra_info.size
259 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
261 assert_equal "1", @repository.extra_info["extra_report_last_commit"]
260 end
262 end
261
263
262 def test_refetch_after_clear_changesets
264 def test_refetch_after_clear_changesets
263 assert_nil @repository.extra_info
265 assert_nil @repository.extra_info
264 assert_equal 0, @repository.changesets.count
266 assert_equal 0, @repository.changesets.count
265 @repository.fetch_changesets
267 @repository.fetch_changesets
266 @project.reload
268 @project.reload
267 assert_equal NUM_REV, @repository.changesets.count
269 assert_equal NUM_REV, @repository.changesets.count
268
270
269 @repository.send(:clear_changesets)
271 @repository.send(:clear_changesets)
270 @project.reload
272 @project.reload
271 assert_equal 0, @repository.changesets.count
273 assert_equal 0, @repository.changesets.count
272
274
273 @repository.fetch_changesets
275 @repository.fetch_changesets
274 @project.reload
276 @project.reload
275 assert_equal NUM_REV, @repository.changesets.count
277 assert_equal NUM_REV, @repository.changesets.count
276 end
278 end
277
279
278 def test_parents
280 def test_parents
279 assert_equal 0, @repository.changesets.count
281 assert_equal 0, @repository.changesets.count
280 @repository.fetch_changesets
282 @repository.fetch_changesets
281 @project.reload
283 @project.reload
282 assert_equal NUM_REV, @repository.changesets.count
284 assert_equal NUM_REV, @repository.changesets.count
283 r1 = @repository.find_changeset_by_name("7234cb2750b63")
285 r1 = @repository.find_changeset_by_name("7234cb2750b63")
284 assert_equal [], r1.parents
286 assert_equal [], r1.parents
285 r2 = @repository.find_changeset_by_name("899a15dba03a3")
287 r2 = @repository.find_changeset_by_name("899a15dba03a3")
286 assert_equal 1, r2.parents.length
288 assert_equal 1, r2.parents.length
287 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
289 assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
288 r2.parents[0].identifier
290 r2.parents[0].identifier
289 r3 = @repository.find_changeset_by_name("32ae898b720c2")
291 r3 = @repository.find_changeset_by_name("32ae898b720c2")
290 assert_equal 2, r3.parents.length
292 assert_equal 2, r3.parents.length
291 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
293 r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort
292 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
294 assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0]
293 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
295 assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1]
294 end
296 end
295
297
296 def test_db_consistent_ordering_init
298 def test_db_consistent_ordering_init
297 assert_nil @repository.extra_info
299 assert_nil @repository.extra_info
298 assert_equal 0, @repository.changesets.count
300 assert_equal 0, @repository.changesets.count
299 @repository.fetch_changesets
301 @repository.fetch_changesets
300 @project.reload
302 @project.reload
301 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
303 assert_equal 1, @repository.extra_info["db_consistent"]["ordering"]
302 end
304 end
303
305
304 def test_db_consistent_ordering_before_1_2
306 def test_db_consistent_ordering_before_1_2
305 assert_nil @repository.extra_info
307 assert_nil @repository.extra_info
306 assert_equal 0, @repository.changesets.count
308 assert_equal 0, @repository.changesets.count
307 @repository.fetch_changesets
309 @repository.fetch_changesets
308 @project.reload
310 @project.reload
309 assert_equal NUM_REV, @repository.changesets.count
311 assert_equal NUM_REV, @repository.changesets.count
310 assert_not_nil @repository.extra_info
312 assert_not_nil @repository.extra_info
311 h = {}
313 h = {}
312 h["heads"] = []
314 h["heads"] = []
313 h["branches"] = {}
315 h["branches"] = {}
314 h["db_consistent"] = {}
316 h["db_consistent"] = {}
315 @repository.merge_extra_info(h)
317 @repository.merge_extra_info(h)
316 @repository.save
318 @repository.save
317 assert_equal NUM_REV, @repository.changesets.count
319 assert_equal NUM_REV, @repository.changesets.count
318 @repository.fetch_changesets
320 @repository.fetch_changesets
319 @project.reload
321 @project.reload
320 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
322 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
321
323
322 extra_info_heads = @repository.extra_info["heads"].dup
324 extra_info_heads = @repository.extra_info["heads"].dup
323 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
325 extra_info_heads.delete_if { |x| x == "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c" }
324 del_revs = [
326 del_revs = [
325 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
327 "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
326 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
328 "ed5bb786bbda2dee66a2d50faf51429dbc043a7b",
327 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
329 "4f26664364207fa8b1af9f8722647ab2d4ac5d43",
328 "deff712f05a90d96edbd70facc47d944be5897e3",
330 "deff712f05a90d96edbd70facc47d944be5897e3",
329 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
331 "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
330 "7e61ac704deecde634b51e59daa8110435dcb3da",
332 "7e61ac704deecde634b51e59daa8110435dcb3da",
331 ]
333 ]
332 @repository.changesets.each do |rev|
334 @repository.changesets.each do |rev|
333 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
335 rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s }
334 end
336 end
335 @project.reload
337 @project.reload
336 cs1 = @repository.changesets
338 cs1 = @repository.changesets
337 assert_equal NUM_REV - 6, cs1.count
339 assert_equal NUM_REV - 6, cs1.count
338 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
340 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
339
341
340 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
342 extra_info_heads << "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8"
341 h = {}
343 h = {}
342 h["heads"] = extra_info_heads
344 h["heads"] = extra_info_heads
343 @repository.merge_extra_info(h)
345 @repository.merge_extra_info(h)
344 @repository.save
346 @repository.save
345 @project.reload
347 @project.reload
346 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
348 assert @repository.extra_info["heads"].index("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8")
347 @repository.fetch_changesets
349 @repository.fetch_changesets
348 @project.reload
350 @project.reload
349 assert_equal NUM_REV, @repository.changesets.count
351 assert_equal NUM_REV, @repository.changesets.count
350 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
352 assert_equal NUM_HEAD, @repository.extra_info["heads"].size
351
353
352 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
354 assert_equal 0, @repository.extra_info["db_consistent"]["ordering"]
353 end
355 end
354
356
355 def test_heads_from_branches_hash
357 def test_heads_from_branches_hash
356 assert_nil @repository.extra_info
358 assert_nil @repository.extra_info
357 assert_equal 0, @repository.changesets.count
359 assert_equal 0, @repository.changesets.count
358 assert_equal [], @repository.heads_from_branches_hash
360 assert_equal [], @repository.heads_from_branches_hash
359 h = {}
361 h = {}
360 h["branches"] = {}
362 h["branches"] = {}
361 h["branches"]["test1"] = {}
363 h["branches"]["test1"] = {}
362 h["branches"]["test1"]["last_scmid"] = "1234abcd"
364 h["branches"]["test1"]["last_scmid"] = "1234abcd"
363 h["branches"]["test2"] = {}
365 h["branches"]["test2"] = {}
364 h["branches"]["test2"]["last_scmid"] = "abcd1234"
366 h["branches"]["test2"]["last_scmid"] = "abcd1234"
365 @repository.merge_extra_info(h)
367 @repository.merge_extra_info(h)
366 @repository.save
368 @repository.save
367 @project.reload
369 @project.reload
368 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
370 assert_equal ["1234abcd", "abcd1234"], @repository.heads_from_branches_hash.sort
369 end
371 end
370
372
371 def test_latest_changesets
373 def test_latest_changesets
372 assert_equal 0, @repository.changesets.count
374 assert_equal 0, @repository.changesets.count
373 @repository.fetch_changesets
375 @repository.fetch_changesets
374 @project.reload
376 @project.reload
375 assert_equal NUM_REV, @repository.changesets.count
377 assert_equal NUM_REV, @repository.changesets.count
376 # with limit
378 # with limit
377 changesets = @repository.latest_changesets('', 'master', 2)
379 changesets = @repository.latest_changesets('', 'master', 2)
378 assert_equal 2, changesets.size
380 assert_equal 2, changesets.size
379
381
380 # with path
382 # with path
381 changesets = @repository.latest_changesets('images', 'master')
383 changesets = @repository.latest_changesets('images', 'master')
382 assert_equal [
384 assert_equal [
383 'deff712f05a90d96edbd70facc47d944be5897e3',
385 'deff712f05a90d96edbd70facc47d944be5897e3',
384 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
386 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
385 '7234cb2750b63f47bff735edc50a1c0a433c2518',
387 '7234cb2750b63f47bff735edc50a1c0a433c2518',
386 ], changesets.collect(&:revision)
388 ], changesets.collect(&:revision)
387
389
388 changesets = @repository.latest_changesets('README', nil)
390 changesets = @repository.latest_changesets('README', nil)
389 assert_equal [
391 assert_equal [
390 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
392 '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf',
391 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
393 '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8',
392 '713f4944648826f558cf548222f813dabe7cbb04',
394 '713f4944648826f558cf548222f813dabe7cbb04',
393 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
395 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
394 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
396 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
395 '7234cb2750b63f47bff735edc50a1c0a433c2518',
397 '7234cb2750b63f47bff735edc50a1c0a433c2518',
396 ], changesets.collect(&:revision)
398 ], changesets.collect(&:revision)
397
399
398 # with path, revision and limit
400 # with path, revision and limit
399 changesets = @repository.latest_changesets('images', '899a15dba')
401 changesets = @repository.latest_changesets('images', '899a15dba')
400 assert_equal [
402 assert_equal [
401 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
403 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
402 '7234cb2750b63f47bff735edc50a1c0a433c2518',
404 '7234cb2750b63f47bff735edc50a1c0a433c2518',
403 ], changesets.collect(&:revision)
405 ], changesets.collect(&:revision)
404
406
405 changesets = @repository.latest_changesets('images', '899a15dba', 1)
407 changesets = @repository.latest_changesets('images', '899a15dba', 1)
406 assert_equal [
408 assert_equal [
407 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
409 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
408 ], changesets.collect(&:revision)
410 ], changesets.collect(&:revision)
409
411
410 changesets = @repository.latest_changesets('README', '899a15dba')
412 changesets = @repository.latest_changesets('README', '899a15dba')
411 assert_equal [
413 assert_equal [
412 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
414 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
413 '7234cb2750b63f47bff735edc50a1c0a433c2518',
415 '7234cb2750b63f47bff735edc50a1c0a433c2518',
414 ], changesets.collect(&:revision)
416 ], changesets.collect(&:revision)
415
417
416 changesets = @repository.latest_changesets('README', '899a15dba', 1)
418 changesets = @repository.latest_changesets('README', '899a15dba', 1)
417 assert_equal [
419 assert_equal [
418 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
420 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
419 ], changesets.collect(&:revision)
421 ], changesets.collect(&:revision)
420
422
421 # with path, tag and limit
423 # with path, tag and limit
422 changesets = @repository.latest_changesets('images', 'tag01.annotated')
424 changesets = @repository.latest_changesets('images', 'tag01.annotated')
423 assert_equal [
425 assert_equal [
424 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
426 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
425 '7234cb2750b63f47bff735edc50a1c0a433c2518',
427 '7234cb2750b63f47bff735edc50a1c0a433c2518',
426 ], changesets.collect(&:revision)
428 ], changesets.collect(&:revision)
427
429
428 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
430 changesets = @repository.latest_changesets('images', 'tag01.annotated', 1)
429 assert_equal [
431 assert_equal [
430 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
432 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
431 ], changesets.collect(&:revision)
433 ], changesets.collect(&:revision)
432
434
433 changesets = @repository.latest_changesets('README', 'tag01.annotated')
435 changesets = @repository.latest_changesets('README', 'tag01.annotated')
434 assert_equal [
436 assert_equal [
435 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
437 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
436 '7234cb2750b63f47bff735edc50a1c0a433c2518',
438 '7234cb2750b63f47bff735edc50a1c0a433c2518',
437 ], changesets.collect(&:revision)
439 ], changesets.collect(&:revision)
438
440
439 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
441 changesets = @repository.latest_changesets('README', 'tag01.annotated', 1)
440 assert_equal [
442 assert_equal [
441 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
443 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
442 ], changesets.collect(&:revision)
444 ], changesets.collect(&:revision)
443
445
444 # with path, branch and limit
446 # with path, branch and limit
445 changesets = @repository.latest_changesets('images', 'test_branch')
447 changesets = @repository.latest_changesets('images', 'test_branch')
446 assert_equal [
448 assert_equal [
447 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
449 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
448 '7234cb2750b63f47bff735edc50a1c0a433c2518',
450 '7234cb2750b63f47bff735edc50a1c0a433c2518',
449 ], changesets.collect(&:revision)
451 ], changesets.collect(&:revision)
450
452
451 changesets = @repository.latest_changesets('images', 'test_branch', 1)
453 changesets = @repository.latest_changesets('images', 'test_branch', 1)
452 assert_equal [
454 assert_equal [
453 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
455 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
454 ], changesets.collect(&:revision)
456 ], changesets.collect(&:revision)
455
457
456 changesets = @repository.latest_changesets('README', 'test_branch')
458 changesets = @repository.latest_changesets('README', 'test_branch')
457 assert_equal [
459 assert_equal [
458 '713f4944648826f558cf548222f813dabe7cbb04',
460 '713f4944648826f558cf548222f813dabe7cbb04',
459 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
461 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
460 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
462 '899a15dba03a3b350b89c3f537e4bbe02a03cdc9',
461 '7234cb2750b63f47bff735edc50a1c0a433c2518',
463 '7234cb2750b63f47bff735edc50a1c0a433c2518',
462 ], changesets.collect(&:revision)
464 ], changesets.collect(&:revision)
463
465
464 changesets = @repository.latest_changesets('README', 'test_branch', 2)
466 changesets = @repository.latest_changesets('README', 'test_branch', 2)
465 assert_equal [
467 assert_equal [
466 '713f4944648826f558cf548222f813dabe7cbb04',
468 '713f4944648826f558cf548222f813dabe7cbb04',
467 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
469 '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
468 ], changesets.collect(&:revision)
470 ], changesets.collect(&:revision)
469
471
470 if WINDOWS_PASS
472 if WINDOWS_PASS
471 puts WINDOWS_SKIP_STR
473 puts WINDOWS_SKIP_STR
472 elsif JRUBY_SKIP
474 elsif JRUBY_SKIP
473 puts JRUBY_SKIP_STR
475 puts JRUBY_SKIP_STR
474 else
476 else
475 # latin-1 encoding path
477 # latin-1 encoding path
476 changesets = @repository.latest_changesets(
478 changesets = @repository.latest_changesets(
477 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89')
479 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89')
478 assert_equal [
480 assert_equal [
479 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
481 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
480 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
482 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
481 ], changesets.collect(&:revision)
483 ], changesets.collect(&:revision)
482
484
483 changesets = @repository.latest_changesets(
485 changesets = @repository.latest_changesets(
484 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89', 1)
486 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89', 1)
485 assert_equal [
487 assert_equal [
486 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
488 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
487 ], changesets.collect(&:revision)
489 ], changesets.collect(&:revision)
488 end
490 end
489 end
491 end
490
492
491 def test_latest_changesets_latin_1_dir
493 def test_latest_changesets_latin_1_dir
492 if WINDOWS_PASS
494 if WINDOWS_PASS
493 puts WINDOWS_SKIP_STR
495 puts WINDOWS_SKIP_STR
494 elsif JRUBY_SKIP
496 elsif JRUBY_SKIP
495 puts JRUBY_SKIP_STR
497 puts JRUBY_SKIP_STR
496 else
498 else
497 assert_equal 0, @repository.changesets.count
499 assert_equal 0, @repository.changesets.count
498 @repository.fetch_changesets
500 @repository.fetch_changesets
499 @project.reload
501 @project.reload
500 assert_equal NUM_REV, @repository.changesets.count
502 assert_equal NUM_REV, @repository.changesets.count
501 changesets = @repository.latest_changesets(
503 changesets = @repository.latest_changesets(
502 "latin-1-dir/test-#{CHAR_1_HEX}-subdir", '1ca7f5ed')
504 "latin-1-dir/test-#{CHAR_1_HEX}-subdir", '1ca7f5ed')
503 assert_equal [
505 assert_equal [
504 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
506 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
505 ], changesets.collect(&:revision)
507 ], changesets.collect(&:revision)
506 end
508 end
507 end
509 end
508
510
509 def test_find_changeset_by_name
511 def test_find_changeset_by_name
510 assert_equal 0, @repository.changesets.count
512 assert_equal 0, @repository.changesets.count
511 @repository.fetch_changesets
513 @repository.fetch_changesets
512 @project.reload
514 @project.reload
513 assert_equal NUM_REV, @repository.changesets.count
515 assert_equal NUM_REV, @repository.changesets.count
514 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
516 ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r|
515 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
517 assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518',
516 @repository.find_changeset_by_name(r).revision
518 @repository.find_changeset_by_name(r).revision
517 end
519 end
518 end
520 end
519
521
520 def test_find_changeset_by_empty_name
522 def test_find_changeset_by_empty_name
521 assert_equal 0, @repository.changesets.count
523 assert_equal 0, @repository.changesets.count
522 @repository.fetch_changesets
524 @repository.fetch_changesets
523 @project.reload
525 @project.reload
524 assert_equal NUM_REV, @repository.changesets.count
526 assert_equal NUM_REV, @repository.changesets.count
525 ['', ' ', nil].each do |r|
527 ['', ' ', nil].each do |r|
526 assert_nil @repository.find_changeset_by_name(r)
528 assert_nil @repository.find_changeset_by_name(r)
527 end
529 end
528 end
530 end
529
531
530 def test_identifier
532 def test_identifier
531 assert_equal 0, @repository.changesets.count
533 assert_equal 0, @repository.changesets.count
532 @repository.fetch_changesets
534 @repository.fetch_changesets
533 @project.reload
535 @project.reload
534 assert_equal NUM_REV, @repository.changesets.count
536 assert_equal NUM_REV, @repository.changesets.count
535 c = @repository.changesets.find_by_revision(
537 c = @repository.changesets.find_by_revision(
536 '7234cb2750b63f47bff735edc50a1c0a433c2518')
538 '7234cb2750b63f47bff735edc50a1c0a433c2518')
537 assert_equal c.scmid, c.identifier
539 assert_equal c.scmid, c.identifier
538 end
540 end
539
541
540 def test_format_identifier
542 def test_format_identifier
541 assert_equal 0, @repository.changesets.count
543 assert_equal 0, @repository.changesets.count
542 @repository.fetch_changesets
544 @repository.fetch_changesets
543 @project.reload
545 @project.reload
544 assert_equal NUM_REV, @repository.changesets.count
546 assert_equal NUM_REV, @repository.changesets.count
545 c = @repository.changesets.find_by_revision(
547 c = @repository.changesets.find_by_revision(
546 '7234cb2750b63f47bff735edc50a1c0a433c2518')
548 '7234cb2750b63f47bff735edc50a1c0a433c2518')
547 assert_equal '7234cb27', c.format_identifier
549 assert_equal '7234cb27', c.format_identifier
548 end
550 end
549
551
550 def test_activities
552 def test_activities
551 c = Changeset.new(:repository => @repository,
553 c = Changeset.new(:repository => @repository,
552 :committed_on => Time.now,
554 :committed_on => Time.now,
553 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
555 :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
554 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
556 :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2',
555 :comments => 'test')
557 :comments => 'test')
556 assert c.event_title.include?('abc7234c:')
558 assert c.event_title.include?('abc7234c:')
557 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
559 assert_equal 'abc7234cb2750b63f47bff735edc50a1c0a433c2', c.event_url[:rev]
558 end
560 end
559
561
560 def test_log_utf8
562 def test_log_utf8
561 assert_equal 0, @repository.changesets.count
563 assert_equal 0, @repository.changesets.count
562 @repository.fetch_changesets
564 @repository.fetch_changesets
563 @project.reload
565 @project.reload
564 assert_equal NUM_REV, @repository.changesets.count
566 assert_equal NUM_REV, @repository.changesets.count
565 c = @repository.changesets.find_by_revision(
567 c = @repository.changesets.find_by_revision(
566 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
568 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
567 assert_equal "#{FELIX_HEX} <felix@fachschaften.org>", c.committer
569 assert_equal "#{FELIX_HEX} <felix@fachschaften.org>", c.committer
568 end
570 end
569
571
570 def test_previous
572 def test_previous
571 assert_equal 0, @repository.changesets.count
573 assert_equal 0, @repository.changesets.count
572 @repository.fetch_changesets
574 @repository.fetch_changesets
573 @project.reload
575 @project.reload
574 assert_equal NUM_REV, @repository.changesets.count
576 assert_equal NUM_REV, @repository.changesets.count
575 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
577 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
576 changeset = @repository.find_changeset_by_name(r1)
578 changeset = @repository.find_changeset_by_name(r1)
577 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
579 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
578 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
580 assert_equal @repository.find_changeset_by_name(r2), changeset.previous
579 end
581 end
580 end
582 end
581 end
583 end
582
584
583 def test_previous_nil
585 def test_previous_nil
584 assert_equal 0, @repository.changesets.count
586 assert_equal 0, @repository.changesets.count
585 @repository.fetch_changesets
587 @repository.fetch_changesets
586 @project.reload
588 @project.reload
587 assert_equal NUM_REV, @repository.changesets.count
589 assert_equal NUM_REV, @repository.changesets.count
588 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
590 %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb275|.each do |r1|
589 changeset = @repository.find_changeset_by_name(r1)
591 changeset = @repository.find_changeset_by_name(r1)
590 assert_nil changeset.previous
592 assert_nil changeset.previous
591 end
593 end
592 end
594 end
593
595
594 def test_next
596 def test_next
595 assert_equal 0, @repository.changesets.count
597 assert_equal 0, @repository.changesets.count
596 @repository.fetch_changesets
598 @repository.fetch_changesets
597 @project.reload
599 @project.reload
598 assert_equal NUM_REV, @repository.changesets.count
600 assert_equal NUM_REV, @repository.changesets.count
599 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
601 %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2|
600 changeset = @repository.find_changeset_by_name(r2)
602 changeset = @repository.find_changeset_by_name(r2)
601 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
603 %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1|
602 assert_equal @repository.find_changeset_by_name(r1), changeset.next
604 assert_equal @repository.find_changeset_by_name(r1), changeset.next
603 end
605 end
604 end
606 end
605 end
607 end
606
608
607 def test_next_nil
609 def test_next_nil
608 assert_equal 0, @repository.changesets.count
610 assert_equal 0, @repository.changesets.count
609 @repository.fetch_changesets
611 @repository.fetch_changesets
610 @project.reload
612 @project.reload
611 assert_equal NUM_REV, @repository.changesets.count
613 assert_equal NUM_REV, @repository.changesets.count
612 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
614 %w|2a682156a3b6e77a8bf9cd4590e8db757f3c6c78 2a682156a3b6e77a|.each do |r1|
613 changeset = @repository.find_changeset_by_name(r1)
615 changeset = @repository.find_changeset_by_name(r1)
614 assert_nil changeset.next
616 assert_nil changeset.next
615 end
617 end
616 end
618 end
617 else
619 else
618 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
620 puts "Git test repository NOT FOUND. Skipping unit tests !!!"
619 def test_fake; assert true end
621 def test_fake; assert true end
620 end
622 end
621 end
623 end
@@ -1,487 +1,499
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoryTest < ActiveSupport::TestCase
20 class RepositoryTest < ActiveSupport::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :trackers,
22 :trackers,
23 :projects_trackers,
23 :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :repositories,
25 :repositories,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_categories,
28 :issue_categories,
29 :changesets,
29 :changesets,
30 :changes,
30 :changes,
31 :users,
31 :users,
32 :email_addresses,
32 :email_addresses,
33 :members,
33 :members,
34 :member_roles,
34 :member_roles,
35 :roles,
35 :roles,
36 :enumerations
36 :enumerations
37
37
38 include Redmine::I18n
38 include Redmine::I18n
39
39
40 def setup
40 def setup
41 @repository = Project.find(1).repository
41 @repository = Project.find(1).repository
42 end
42 end
43
43
44 def test_blank_log_encoding_error_message
44 def test_blank_log_encoding_error_message
45 set_language_if_valid 'en'
45 set_language_if_valid 'en'
46 repo = Repository::Bazaar.new(
46 repo = Repository::Bazaar.new(
47 :project => Project.find(3),
47 :project => Project.find(3),
48 :url => "/test",
48 :url => "/test",
49 :log_encoding => ''
49 :log_encoding => ''
50 )
50 )
51 assert !repo.save
51 assert !repo.save
52 assert_include "Commit messages encoding cannot be blank",
52 assert_include "Commit messages encoding cannot be blank",
53 repo.errors.full_messages
53 repo.errors.full_messages
54 end
54 end
55
55
56 def test_blank_log_encoding_error_message_fr
56 def test_blank_log_encoding_error_message_fr
57 set_language_if_valid 'fr'
57 set_language_if_valid 'fr'
58 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
58 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
59 repo = Repository::Bazaar.new(
59 repo = Repository::Bazaar.new(
60 :project => Project.find(3),
60 :project => Project.find(3),
61 :url => "/test"
61 :url => "/test"
62 )
62 )
63 assert !repo.save
63 assert !repo.save
64 assert_include str, repo.errors.full_messages
64 assert_include str, repo.errors.full_messages
65 end
65 end
66
66
67 def test_create
67 def test_create
68 repository = Repository::Subversion.new(:project => Project.find(3))
68 repository = Repository::Subversion.new(:project => Project.find(3))
69 assert !repository.save
69 assert !repository.save
70
70
71 repository.url = "svn://localhost"
71 repository.url = "svn://localhost"
72 assert repository.save
72 assert repository.save
73 repository.reload
73 repository.reload
74
74
75 project = Project.find(3)
75 project = Project.find(3)
76 assert_equal repository, project.repository
76 assert_equal repository, project.repository
77 end
77 end
78
78
79 def test_2_repositories_with_same_identifier_in_different_projects_should_be_valid
79 def test_2_repositories_with_same_identifier_in_different_projects_should_be_valid
80 Repository::Subversion.create!(:project_id => 2, :identifier => 'foo', :url => 'file:///foo')
80 Repository::Subversion.create!(:project_id => 2, :identifier => 'foo', :url => 'file:///foo')
81 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
81 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
82 assert r.save
82 assert r.save
83 end
83 end
84
84
85 def test_2_repositories_with_same_identifier_should_not_be_valid
85 def test_2_repositories_with_same_identifier_should_not_be_valid
86 Repository::Subversion.create!(:project_id => 3, :identifier => 'foo', :url => 'file:///foo')
86 Repository::Subversion.create!(:project_id => 3, :identifier => 'foo', :url => 'file:///foo')
87 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
87 r = Repository::Subversion.new(:project_id => 3, :identifier => 'foo', :url => 'file:///bar')
88 assert !r.save
88 assert !r.save
89 end
89 end
90
90
91 def test_2_repositories_with_blank_identifier_should_not_be_valid
91 def test_2_repositories_with_blank_identifier_should_not_be_valid
92 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo')
92 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo')
93 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
93 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
94 assert !r.save
94 assert !r.save
95 end
95 end
96
96
97 def test_2_repositories_with_blank_identifier_and_one_as_default_should_not_be_valid
98 Repository::Subversion.create!(:project_id => 3, :identifier => '', :url => 'file:///foo', :is_default => true)
99 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
100 assert !r.save
101 end
102
103 def test_2_repositories_with_blank_and_nil_identifier_should_not_be_valid
104 Repository::Subversion.create!(:project_id => 3, :identifier => nil, :url => 'file:///foo')
105 r = Repository::Subversion.new(:project_id => 3, :identifier => '', :url => 'file:///bar')
106 assert !r.save
107 end
108
97 def test_first_repository_should_be_set_as_default
109 def test_first_repository_should_be_set_as_default
98 repository1 = Repository::Subversion.new(
110 repository1 = Repository::Subversion.new(
99 :project => Project.find(3),
111 :project => Project.find(3),
100 :identifier => 'svn1',
112 :identifier => 'svn1',
101 :url => 'file:///svn1'
113 :url => 'file:///svn1'
102 )
114 )
103 assert repository1.save
115 assert repository1.save
104 assert repository1.is_default?
116 assert repository1.is_default?
105
117
106 repository2 = Repository::Subversion.new(
118 repository2 = Repository::Subversion.new(
107 :project => Project.find(3),
119 :project => Project.find(3),
108 :identifier => 'svn2',
120 :identifier => 'svn2',
109 :url => 'file:///svn2'
121 :url => 'file:///svn2'
110 )
122 )
111 assert repository2.save
123 assert repository2.save
112 assert !repository2.is_default?
124 assert !repository2.is_default?
113
125
114 assert_equal repository1, Project.find(3).repository
126 assert_equal repository1, Project.find(3).repository
115 assert_equal [repository1, repository2], Project.find(3).repositories.sort
127 assert_equal [repository1, repository2], Project.find(3).repositories.sort
116 end
128 end
117
129
118 def test_default_repository_should_be_one
130 def test_default_repository_should_be_one
119 assert_equal 0, Project.find(3).repositories.count
131 assert_equal 0, Project.find(3).repositories.count
120 repository1 = Repository::Subversion.new(
132 repository1 = Repository::Subversion.new(
121 :project => Project.find(3),
133 :project => Project.find(3),
122 :identifier => 'svn1',
134 :identifier => 'svn1',
123 :url => 'file:///svn1'
135 :url => 'file:///svn1'
124 )
136 )
125 assert repository1.save
137 assert repository1.save
126 assert repository1.is_default?
138 assert repository1.is_default?
127
139
128 repository2 = Repository::Subversion.new(
140 repository2 = Repository::Subversion.new(
129 :project => Project.find(3),
141 :project => Project.find(3),
130 :identifier => 'svn2',
142 :identifier => 'svn2',
131 :url => 'file:///svn2',
143 :url => 'file:///svn2',
132 :is_default => true
144 :is_default => true
133 )
145 )
134 assert repository2.save
146 assert repository2.save
135 assert repository2.is_default?
147 assert repository2.is_default?
136 repository1.reload
148 repository1.reload
137 assert !repository1.is_default?
149 assert !repository1.is_default?
138
150
139 assert_equal repository2, Project.find(3).repository
151 assert_equal repository2, Project.find(3).repository
140 assert_equal [repository2, repository1], Project.find(3).repositories.sort
152 assert_equal [repository2, repository1], Project.find(3).repositories.sort
141 end
153 end
142
154
143 def test_identifier_should_accept_letters_digits_dashes_and_underscores
155 def test_identifier_should_accept_letters_digits_dashes_and_underscores
144 r = Repository::Subversion.new(
156 r = Repository::Subversion.new(
145 :project_id => 3,
157 :project_id => 3,
146 :identifier => 'svn-123_45',
158 :identifier => 'svn-123_45',
147 :url => 'file:///svn'
159 :url => 'file:///svn'
148 )
160 )
149 assert r.save
161 assert r.save
150 end
162 end
151
163
152 def test_identifier_should_not_be_frozen_for_a_new_repository
164 def test_identifier_should_not_be_frozen_for_a_new_repository
153 assert_equal false, Repository.new.identifier_frozen?
165 assert_equal false, Repository.new.identifier_frozen?
154 end
166 end
155
167
156 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
168 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
157 Repository.where(:id => 10).update_all(["identifier = ''"])
169 Repository.where(:id => 10).update_all(["identifier = ''"])
158 assert_equal false, Repository.find(10).identifier_frozen?
170 assert_equal false, Repository.find(10).identifier_frozen?
159 end
171 end
160
172
161 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
173 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
162 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
174 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
163 assert_equal true, Repository.find(10).identifier_frozen?
175 assert_equal true, Repository.find(10).identifier_frozen?
164 end
176 end
165
177
166 def test_identifier_should_not_accept_change_if_frozen
178 def test_identifier_should_not_accept_change_if_frozen
167 r = Repository.new(:identifier => 'foo')
179 r = Repository.new(:identifier => 'foo')
168 r.stubs(:identifier_frozen?).returns(true)
180 r.stubs(:identifier_frozen?).returns(true)
169
181
170 r.identifier = 'bar'
182 r.identifier = 'bar'
171 assert_equal 'foo', r.identifier
183 assert_equal 'foo', r.identifier
172 end
184 end
173
185
174 def test_identifier_should_accept_change_if_not_frozen
186 def test_identifier_should_accept_change_if_not_frozen
175 r = Repository.new(:identifier => 'foo')
187 r = Repository.new(:identifier => 'foo')
176 r.stubs(:identifier_frozen?).returns(false)
188 r.stubs(:identifier_frozen?).returns(false)
177
189
178 r.identifier = 'bar'
190 r.identifier = 'bar'
179 assert_equal 'bar', r.identifier
191 assert_equal 'bar', r.identifier
180 end
192 end
181
193
182 def test_destroy
194 def test_destroy
183 repository = Repository.find(10)
195 repository = Repository.find(10)
184 changesets = repository.changesets.count
196 changesets = repository.changesets.count
185 changes = repository.filechanges.count
197 changes = repository.filechanges.count
186
198
187 assert_difference 'Changeset.count', -changesets do
199 assert_difference 'Changeset.count', -changesets do
188 assert_difference 'Change.count', -changes do
200 assert_difference 'Change.count', -changes do
189 Repository.find(10).destroy
201 Repository.find(10).destroy
190 end
202 end
191 end
203 end
192 end
204 end
193
205
194 def test_destroy_should_delete_parents_associations
206 def test_destroy_should_delete_parents_associations
195 changeset = Changeset.find(102)
207 changeset = Changeset.find(102)
196 changeset.parents = Changeset.where(:id => [100, 101]).to_a
208 changeset.parents = Changeset.where(:id => [100, 101]).to_a
197 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
209 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
198 Repository.find(10).destroy
210 Repository.find(10).destroy
199 end
211 end
200 end
212 end
201
213
202 def test_destroy_should_delete_issues_associations
214 def test_destroy_should_delete_issues_associations
203 changeset = Changeset.find(102)
215 changeset = Changeset.find(102)
204 changeset.issues = Issue.where(:id => [1, 2]).to_a
216 changeset.issues = Issue.where(:id => [1, 2]).to_a
205 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
217 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
206 Repository.find(10).destroy
218 Repository.find(10).destroy
207 end
219 end
208 end
220 end
209
221
210 def test_should_not_create_with_disabled_scm
222 def test_should_not_create_with_disabled_scm
211 # disable Subversion
223 # disable Subversion
212 with_settings :enabled_scm => ['Darcs', 'Git'] do
224 with_settings :enabled_scm => ['Darcs', 'Git'] do
213 repository = Repository::Subversion.new(
225 repository = Repository::Subversion.new(
214 :project => Project.find(3), :url => "svn://localhost")
226 :project => Project.find(3), :url => "svn://localhost")
215 assert !repository.save
227 assert !repository.save
216 assert_include I18n.translate('activerecord.errors.messages.invalid'),
228 assert_include I18n.translate('activerecord.errors.messages.invalid'),
217 repository.errors[:type]
229 repository.errors[:type]
218 end
230 end
219 end
231 end
220
232
221 def test_scan_changesets_for_issue_ids
233 def test_scan_changesets_for_issue_ids
222 Setting.default_language = 'en'
234 Setting.default_language = 'en'
223 Setting.commit_ref_keywords = 'refs , references, IssueID'
235 Setting.commit_ref_keywords = 'refs , references, IssueID'
224 Setting.commit_update_keywords = [
236 Setting.commit_update_keywords = [
225 {'keywords' => 'fixes , closes',
237 {'keywords' => 'fixes , closes',
226 'status_id' => IssueStatus.where(:is_closed => true).first.id,
238 'status_id' => IssueStatus.where(:is_closed => true).first.id,
227 'done_ratio' => '90'}
239 'done_ratio' => '90'}
228 ]
240 ]
229 Setting.default_language = 'en'
241 Setting.default_language = 'en'
230 ActionMailer::Base.deliveries.clear
242 ActionMailer::Base.deliveries.clear
231
243
232 # make sure issue 1 is not already closed
244 # make sure issue 1 is not already closed
233 fixed_issue = Issue.find(1)
245 fixed_issue = Issue.find(1)
234 assert !fixed_issue.closed?
246 assert !fixed_issue.closed?
235 old_status = fixed_issue.status
247 old_status = fixed_issue.status
236
248
237 with_settings :notified_events => %w(issue_added issue_updated) do
249 with_settings :notified_events => %w(issue_added issue_updated) do
238 Repository.scan_changesets_for_issue_ids
250 Repository.scan_changesets_for_issue_ids
239 end
251 end
240 assert_equal [101, 102], Issue.find(3).changeset_ids
252 assert_equal [101, 102], Issue.find(3).changeset_ids
241
253
242 # fixed issues
254 # fixed issues
243 fixed_issue.reload
255 fixed_issue.reload
244 assert fixed_issue.closed?
256 assert fixed_issue.closed?
245 assert_equal 90, fixed_issue.done_ratio
257 assert_equal 90, fixed_issue.done_ratio
246 assert_equal [101], fixed_issue.changeset_ids
258 assert_equal [101], fixed_issue.changeset_ids
247
259
248 # issue change
260 # issue change
249 journal = fixed_issue.journals.reorder('created_on desc').first
261 journal = fixed_issue.journals.reorder('created_on desc').first
250 assert_equal User.find_by_login('dlopper'), journal.user
262 assert_equal User.find_by_login('dlopper'), journal.user
251 assert_equal 'Applied in changeset r2.', journal.notes
263 assert_equal 'Applied in changeset r2.', journal.notes
252
264
253 # 2 email notifications
265 # 2 email notifications
254 assert_equal 2, ActionMailer::Base.deliveries.size
266 assert_equal 2, ActionMailer::Base.deliveries.size
255 mail = ActionMailer::Base.deliveries.first
267 mail = ActionMailer::Base.deliveries.first
256 assert_not_nil mail
268 assert_not_nil mail
257 assert mail.subject.starts_with?(
269 assert mail.subject.starts_with?(
258 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
270 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
259 assert_mail_body_match(
271 assert_mail_body_match(
260 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
272 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
261
273
262 # ignoring commits referencing an issue of another project
274 # ignoring commits referencing an issue of another project
263 assert_equal [], Issue.find(4).changesets
275 assert_equal [], Issue.find(4).changesets
264 end
276 end
265
277
266 def test_for_changeset_comments_strip
278 def test_for_changeset_comments_strip
267 repository = Repository::Mercurial.create(
279 repository = Repository::Mercurial.create(
268 :project => Project.find( 4 ),
280 :project => Project.find( 4 ),
269 :url => '/foo/bar/baz' )
281 :url => '/foo/bar/baz' )
270 comment = <<-COMMENT
282 comment = <<-COMMENT
271 This is a loooooooooooooooooooooooooooong comment
283 This is a loooooooooooooooooooooooooooong comment
272
284
273
285
274 COMMENT
286 COMMENT
275 changeset = Changeset.new(
287 changeset = Changeset.new(
276 :comments => comment, :commit_date => Time.now,
288 :comments => comment, :commit_date => Time.now,
277 :revision => 0, :scmid => 'f39b7922fb3c',
289 :revision => 0, :scmid => 'f39b7922fb3c',
278 :committer => 'foo <foo@example.com>',
290 :committer => 'foo <foo@example.com>',
279 :committed_on => Time.now, :repository => repository )
291 :committed_on => Time.now, :repository => repository )
280 assert( changeset.save )
292 assert( changeset.save )
281 assert_not_equal( comment, changeset.comments )
293 assert_not_equal( comment, changeset.comments )
282 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
294 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
283 changeset.comments )
295 changeset.comments )
284 end
296 end
285
297
286 def test_for_urls_strip_cvs
298 def test_for_urls_strip_cvs
287 repository = Repository::Cvs.create(
299 repository = Repository::Cvs.create(
288 :project => Project.find(4),
300 :project => Project.find(4),
289 :url => ' :pserver:login:password@host:/path/to/the/repository',
301 :url => ' :pserver:login:password@host:/path/to/the/repository',
290 :root_url => 'foo ',
302 :root_url => 'foo ',
291 :log_encoding => 'UTF-8')
303 :log_encoding => 'UTF-8')
292 assert repository.save
304 assert repository.save
293 repository.reload
305 repository.reload
294 assert_equal ':pserver:login:password@host:/path/to/the/repository',
306 assert_equal ':pserver:login:password@host:/path/to/the/repository',
295 repository.url
307 repository.url
296 assert_equal 'foo', repository.root_url
308 assert_equal 'foo', repository.root_url
297 end
309 end
298
310
299 def test_for_urls_strip_subversion
311 def test_for_urls_strip_subversion
300 repository = Repository::Subversion.create(
312 repository = Repository::Subversion.create(
301 :project => Project.find(4),
313 :project => Project.find(4),
302 :url => ' file:///dummy ')
314 :url => ' file:///dummy ')
303 assert repository.save
315 assert repository.save
304 repository.reload
316 repository.reload
305 assert_equal 'file:///dummy', repository.url
317 assert_equal 'file:///dummy', repository.url
306 end
318 end
307
319
308 def test_for_urls_strip_git
320 def test_for_urls_strip_git
309 repository = Repository::Git.create(
321 repository = Repository::Git.create(
310 :project => Project.find(4),
322 :project => Project.find(4),
311 :url => ' c:\dummy ')
323 :url => ' c:\dummy ')
312 assert repository.save
324 assert repository.save
313 repository.reload
325 repository.reload
314 assert_equal 'c:\dummy', repository.url
326 assert_equal 'c:\dummy', repository.url
315 end
327 end
316
328
317 def test_manual_user_mapping
329 def test_manual_user_mapping
318 assert_no_difference "Changeset.where('user_id <> 2').count" do
330 assert_no_difference "Changeset.where('user_id <> 2').count" do
319 c = Changeset.create!(
331 c = Changeset.create!(
320 :repository => @repository,
332 :repository => @repository,
321 :committer => 'foo',
333 :committer => 'foo',
322 :committed_on => Time.now,
334 :committed_on => Time.now,
323 :revision => 100,
335 :revision => 100,
324 :comments => 'Committed by foo.'
336 :comments => 'Committed by foo.'
325 )
337 )
326 assert_nil c.user
338 assert_nil c.user
327 @repository.committer_ids = {'foo' => '2'}
339 @repository.committer_ids = {'foo' => '2'}
328 assert_equal User.find(2), c.reload.user
340 assert_equal User.find(2), c.reload.user
329 # committer is now mapped
341 # committer is now mapped
330 c = Changeset.create!(
342 c = Changeset.create!(
331 :repository => @repository,
343 :repository => @repository,
332 :committer => 'foo',
344 :committer => 'foo',
333 :committed_on => Time.now,
345 :committed_on => Time.now,
334 :revision => 101,
346 :revision => 101,
335 :comments => 'Another commit by foo.'
347 :comments => 'Another commit by foo.'
336 )
348 )
337 assert_equal User.find(2), c.user
349 assert_equal User.find(2), c.user
338 end
350 end
339 end
351 end
340
352
341 def test_auto_user_mapping_by_username
353 def test_auto_user_mapping_by_username
342 c = Changeset.create!(
354 c = Changeset.create!(
343 :repository => @repository,
355 :repository => @repository,
344 :committer => 'jsmith',
356 :committer => 'jsmith',
345 :committed_on => Time.now,
357 :committed_on => Time.now,
346 :revision => 100,
358 :revision => 100,
347 :comments => 'Committed by john.'
359 :comments => 'Committed by john.'
348 )
360 )
349 assert_equal User.find(2), c.user
361 assert_equal User.find(2), c.user
350 end
362 end
351
363
352 def test_auto_user_mapping_by_email
364 def test_auto_user_mapping_by_email
353 c = Changeset.create!(
365 c = Changeset.create!(
354 :repository => @repository,
366 :repository => @repository,
355 :committer => 'john <jsmith@somenet.foo>',
367 :committer => 'john <jsmith@somenet.foo>',
356 :committed_on => Time.now,
368 :committed_on => Time.now,
357 :revision => 100,
369 :revision => 100,
358 :comments => 'Committed by john.'
370 :comments => 'Committed by john.'
359 )
371 )
360 assert_equal User.find(2), c.user
372 assert_equal User.find(2), c.user
361 end
373 end
362
374
363 def test_filesystem_avaialbe
375 def test_filesystem_avaialbe
364 klass = Repository::Filesystem
376 klass = Repository::Filesystem
365 assert klass.scm_adapter_class
377 assert klass.scm_adapter_class
366 assert_equal true, klass.scm_available
378 assert_equal true, klass.scm_available
367 end
379 end
368
380
369 def test_extra_info_should_not_return_non_hash_value
381 def test_extra_info_should_not_return_non_hash_value
370 repo = Repository.new
382 repo = Repository.new
371 repo.extra_info = "foo"
383 repo.extra_info = "foo"
372 assert_nil repo.extra_info
384 assert_nil repo.extra_info
373 end
385 end
374
386
375 def test_merge_extra_info
387 def test_merge_extra_info
376 repo = Repository::Subversion.new(:project => Project.find(3))
388 repo = Repository::Subversion.new(:project => Project.find(3))
377 assert !repo.save
389 assert !repo.save
378 repo.url = "svn://localhost"
390 repo.url = "svn://localhost"
379 assert repo.save
391 assert repo.save
380 repo.reload
392 repo.reload
381 project = Project.find(3)
393 project = Project.find(3)
382 assert_equal repo, project.repository
394 assert_equal repo, project.repository
383 assert_nil repo.extra_info
395 assert_nil repo.extra_info
384 h1 = {"test_1" => {"test_11" => "test_value_11"}}
396 h1 = {"test_1" => {"test_11" => "test_value_11"}}
385 repo.merge_extra_info(h1)
397 repo.merge_extra_info(h1)
386 assert_equal h1, repo.extra_info
398 assert_equal h1, repo.extra_info
387 h2 = {"test_2" => {
399 h2 = {"test_2" => {
388 "test_21" => "test_value_21",
400 "test_21" => "test_value_21",
389 "test_22" => "test_value_22",
401 "test_22" => "test_value_22",
390 }}
402 }}
391 repo.merge_extra_info(h2)
403 repo.merge_extra_info(h2)
392 assert_equal (h = {"test_11" => "test_value_11"}),
404 assert_equal (h = {"test_11" => "test_value_11"}),
393 repo.extra_info["test_1"]
405 repo.extra_info["test_1"]
394 assert_equal "test_value_21",
406 assert_equal "test_value_21",
395 repo.extra_info["test_2"]["test_21"]
407 repo.extra_info["test_2"]["test_21"]
396 h3 = {"test_2" => {
408 h3 = {"test_2" => {
397 "test_23" => "test_value_23",
409 "test_23" => "test_value_23",
398 "test_24" => "test_value_24",
410 "test_24" => "test_value_24",
399 }}
411 }}
400 repo.merge_extra_info(h3)
412 repo.merge_extra_info(h3)
401 assert_equal (h = {"test_11" => "test_value_11"}),
413 assert_equal (h = {"test_11" => "test_value_11"}),
402 repo.extra_info["test_1"]
414 repo.extra_info["test_1"]
403 assert_nil repo.extra_info["test_2"]["test_21"]
415 assert_nil repo.extra_info["test_2"]["test_21"]
404 assert_equal "test_value_23",
416 assert_equal "test_value_23",
405 repo.extra_info["test_2"]["test_23"]
417 repo.extra_info["test_2"]["test_23"]
406 end
418 end
407
419
408 def test_sort_should_not_raise_an_error_with_nil_identifiers
420 def test_sort_should_not_raise_an_error_with_nil_identifiers
409 r1 = Repository.new
421 r1 = Repository.new
410 r2 = Repository.new
422 r2 = Repository.new
411
423
412 assert_nothing_raised do
424 assert_nothing_raised do
413 [r1, r2].sort
425 [r1, r2].sort
414 end
426 end
415 end
427 end
416
428
417 def test_stats_by_author_reflect_changesets_and_changes
429 def test_stats_by_author_reflect_changesets_and_changes
418 repository = Repository.find(10)
430 repository = Repository.find(10)
419
431
420 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
432 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
421 assert_equal expected, repository.stats_by_author
433 assert_equal expected, repository.stats_by_author
422
434
423 set = Changeset.create!(
435 set = Changeset.create!(
424 :repository => repository,
436 :repository => repository,
425 :committer => 'dlopper',
437 :committer => 'dlopper',
426 :committed_on => Time.now,
438 :committed_on => Time.now,
427 :revision => 101,
439 :revision => 101,
428 :comments => 'Another commit by foo.'
440 :comments => 'Another commit by foo.'
429 )
441 )
430 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
442 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
431 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
443 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
432 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
444 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
433 assert_equal expected, repository.stats_by_author
445 assert_equal expected, repository.stats_by_author
434 end
446 end
435
447
436 def test_stats_by_author_honnor_committers
448 def test_stats_by_author_honnor_committers
437 # in fact it is really tested above, but let's have a dedicated test
449 # in fact it is really tested above, but let's have a dedicated test
438 # to ensure things are dynamically linked to Users
450 # to ensure things are dynamically linked to Users
439 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
451 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
440 repository = Repository.find(10)
452 repository = Repository.find(10)
441 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
453 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
442 assert_equal expected, repository.stats_by_author
454 assert_equal expected, repository.stats_by_author
443 end
455 end
444
456
445 def test_stats_by_author_doesnt_drop_unmapped_users
457 def test_stats_by_author_doesnt_drop_unmapped_users
446 repository = Repository.find(10)
458 repository = Repository.find(10)
447 Changeset.create!(
459 Changeset.create!(
448 :repository => repository,
460 :repository => repository,
449 :committer => 'unnamed <foo@bar.net>',
461 :committer => 'unnamed <foo@bar.net>',
450 :committed_on => Time.now,
462 :committed_on => Time.now,
451 :revision => 101,
463 :revision => 101,
452 :comments => 'Another commit by foo.'
464 :comments => 'Another commit by foo.'
453 )
465 )
454
466
455 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
467 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
456 end
468 end
457
469
458 def test_stats_by_author_merge_correctly
470 def test_stats_by_author_merge_correctly
459 # as we honnor users->committer map and it's not injective,
471 # as we honnor users->committer map and it's not injective,
460 # we must be sure merges happen correctly and stats are not
472 # we must be sure merges happen correctly and stats are not
461 # wiped out when two source counts map to the same user.
473 # wiped out when two source counts map to the same user.
462 #
474 #
463 # Here we have Changeset's with committer="dlopper" and others
475 # Here we have Changeset's with committer="dlopper" and others
464 # with committer="dlopper <dlopper@somefoo.net>"
476 # with committer="dlopper <dlopper@somefoo.net>"
465 repository = Repository.find(10)
477 repository = Repository.find(10)
466
478
467 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
479 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
468 assert_equal expected, repository.stats_by_author
480 assert_equal expected, repository.stats_by_author
469
481
470 set = Changeset.create!(
482 set = Changeset.create!(
471 :repository => repository,
483 :repository => repository,
472 :committer => 'dlopper <dlopper@somefoo.net>',
484 :committer => 'dlopper <dlopper@somefoo.net>',
473 :committed_on => Time.now,
485 :committed_on => Time.now,
474 :revision => 101,
486 :revision => 101,
475 :comments => 'Another commit by foo.'
487 :comments => 'Another commit by foo.'
476 )
488 )
477
489
478 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
490 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
479 assert_equal expected, repository.stats_by_author
491 assert_equal expected, repository.stats_by_author
480 end
492 end
481
493
482 def test_fetch_changesets
494 def test_fetch_changesets
483 # 2 repositories in fixtures
495 # 2 repositories in fixtures
484 Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
496 Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
485 Repository.fetch_changesets
497 Repository.fetch_changesets
486 end
498 end
487 end
499 end
General Comments 0
You need to be logged in to leave comments. Login now