You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by rj...@apache.org on 2014/02/13 06:08:08 UTC
svn commit: r1567849 [10/17] - in /bloodhound/vendor/trac: 1.0-stable/
current/ current/contrib/ current/contrib/cgi-bin/
current/contrib/workflow/ current/doc/ current/doc/utils/
current/sample-plugins/ current/sample-plugins/permissions/ current/samp...
Modified: bloodhound/vendor/trac/current/trac/ticket/tests/functional.py
URL: http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/tests/functional.py?rev=1567849&r1=1567848&r2=1567849&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/tests/functional.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/tests/functional.py Thu Feb 13 05:08:02 2014
@@ -1,24 +1,89 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
import os
import re
from datetime import datetime, timedelta
+from trac.admin.tests.functional import AuthorizationTestCaseSetup
from trac.test import locale_en
from trac.tests.functional import *
-from trac.util.datefmt import utc, localtz, format_date, format_datetime
+from trac.util.datefmt import utc, localtz, format_date, format_datetime, \
+ pretty_timedelta
+from trac.util.text import to_utf8
+
+try:
+ from configobj import ConfigObj
+except ImportError:
+ ConfigObj = None
class TestTickets(FunctionalTwillTestCaseSetup):
def runTest(self):
- """Create a ticket, comment on it, and attach a file"""
+ """Create a ticket and comment on it."""
# TODO: this should be split into multiple tests
- summary = random_sentence(5)
- ticketid = self._tester.create_ticket(summary)
- self._tester.create_ticket()
- self._tester.add_comment(ticketid)
- self._tester.attach_file_to_ticket(ticketid)
+ id = self._tester.create_ticket()
+ self._tester.add_comment(id)
+
+
+class TestTicketMaxSummarySize(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Test `[ticket] max_summary_size` option.
+ http://trac.edgewall.org/ticket/11472"""
+ prev_max_summary_size = \
+ self._testenv.get_config('ticket', 'max_summary_size')
+ short_summary = "abcdefghijklmnopqrstuvwxyz"
+ long_summary = short_summary + "."
+ max_summary_size = len(short_summary)
+ warning_message = r"Ticket summary is too long \(must be less " \
+ r"than %s characters\)" % max_summary_size
+ self._testenv.set_config('ticket', 'max_summary_size',
+ str(max_summary_size))
+ try:
+ self._tester.create_ticket(short_summary)
+ tc.find(short_summary)
+ tc.notfind(warning_message)
+ self._tester.go_to_front()
+ tc.follow(r"\bNew Ticket\b")
+ tc.notfind(internal_error)
+ tc.url(self._tester.url + '/newticket')
+ tc.formvalue('propertyform', 'field_summary', long_summary)
+ tc.submit('submit')
+ tc.url(self._tester.url + '/newticket')
+ tc.find(warning_message)
+ finally:
+ self._testenv.set_config('ticket', 'max_summary_size',
+ prev_max_summary_size)
+
+
+class TestTicketAddAttachment(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Add attachment to a ticket. Test that the attachment button
+ reads 'Attach file' when no files have been attached, and 'Attach
+ another file' when there are existing attachments.
+ Feature added in http://trac.edgewall.org/ticket/10281"""
+ id = self._tester.create_ticket()
+ tc.find("Attach file")
+ filename = self._tester.attach_file_to_ticket(id)
+
+ self._tester.go_to_ticket(id)
+ tc.find("Attach another file")
+ tc.find('Attachments <span class="trac-count">\(1\)</span>')
+ tc.find(filename)
+ tc.find('Download all attachments as:\s+<a rel="nofollow" '
+ 'href="/zip-attachment/ticket/%s/">.zip</a>' % id)
class TestTicketPreview(FunctionalTwillTestCaseSetup):
@@ -55,23 +120,21 @@ class TestTicketAltFormats(FunctionalTes
def runTest(self):
"""Download ticket in alternative formats"""
summary = random_sentence(5)
- ticketid = self._tester.create_ticket(summary)
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(summary)
for format in ['Comma-delimited Text', 'Tab-delimited Text',
'RSS Feed']:
tc.follow(format)
content = b.get_html()
if content.find(summary) < 0:
- raise AssertionError('Summary missing from %s format' % format)
+ raise AssertionError('Summary missing from %s format'
+ % format)
tc.back()
class TestTicketCSVFormat(FunctionalTestCaseSetup):
def runTest(self):
"""Download ticket in CSV format"""
- summary = random_sentence(5)
- ticketid = self._tester.create_ticket(summary)
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket()
tc.follow('Comma-delimited Text')
csv = b.get_html()
if not csv.startswith('\xef\xbb\xbfid,summary,'): # BOM
@@ -80,24 +143,20 @@ class TestTicketCSVFormat(FunctionalTest
class TestTicketTabFormat(FunctionalTestCaseSetup):
def runTest(self):
- """Download ticket in Tab-delimitted format"""
- summary = random_sentence(5)
- ticketid = self._tester.create_ticket(summary)
- self._tester.go_to_ticket(ticketid)
+ """Download ticket in Tab-delimited format"""
+ self._tester.create_ticket()
tc.follow('Tab-delimited Text')
tab = b.get_html()
if not tab.startswith('\xef\xbb\xbfid\tsummary\t'): # BOM
- raise AssertionError('Bad tab delimitted format')
+ raise AssertionError('Bad tab delimited format')
class TestTicketRSSFormat(FunctionalTestCaseSetup):
def runTest(self):
"""Download ticket in RSS format"""
summary = random_sentence(5)
- ticketid = self._tester.create_ticket(summary)
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(summary)
# Make a number of changes to exercise all of the RSS feed code
- self._tester.go_to_ticket(ticketid)
tc.formvalue('propertyform', 'comment', random_sentence(3))
tc.formvalue('propertyform', 'field-type', 'task')
tc.formvalue('propertyform', 'description', summary + '\n\n' +
@@ -119,7 +178,7 @@ class TestTicketSearch(FunctionalTwillTe
def runTest(self):
"""Test ticket search"""
summary = random_sentence(4)
- ticketid = self._tester.create_ticket(summary)
+ self._tester.create_ticket(summary)
self._tester.go_to_front()
tc.follow('Search')
tc.formvalue('fullsearch', 'ticket', True)
@@ -135,7 +194,7 @@ class TestNonTicketSearch(FunctionalTwil
# Create a summary containing only unique words
summary = ' '.join([random_word() + '_TestNonTicketSearch'
for i in range(5)])
- ticketid = self._tester.create_ticket(summary)
+ self._tester.create_ticket(summary)
self._tester.go_to_front()
tc.follow('Search')
tc.formvalue('fullsearch', 'ticket', False)
@@ -150,9 +209,14 @@ class TestTicketHistory(FunctionalTwillT
"""Test ticket history"""
summary = random_sentence(5)
ticketid = self._tester.create_ticket(summary)
- comment = random_sentence(5)
- self._tester.add_comment(ticketid, comment=comment)
+ comment = self._tester.add_comment(ticketid)
self._tester.go_to_ticket(ticketid)
+ tc.find(r'<a [^>]+>\bModify\b</a>')
+ tc.find(r"\bAttach file\b")
+ tc.find(r"\bAdd Comment\b")
+ tc.find(r"\bModify Ticket\b")
+ tc.find(r"\bPreview\b")
+ tc.find(r"\bSubmit changes\b")
url = b.get_url()
tc.go(url + '?version=0')
tc.find('at <[^>]*>*Initial Version')
@@ -162,19 +226,23 @@ class TestTicketHistory(FunctionalTwillT
tc.find('at <[^>]*>*Version 1')
tc.find(summary)
tc.find(comment)
+ tc.notfind(r'<a [^>]+>\bModify\b</a>')
+ tc.notfind(r"\bAttach file\b")
+ tc.notfind(r"\bAdd Comment\b")
+ tc.notfind(r"\bModify Ticket\b")
+ tc.notfind(r"\bPreview\b")
+ tc.notfind(r"\bSubmit changes\b")
class TestTicketHistoryDiff(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test ticket history (diff)"""
- name = 'TestTicketHistoryDiff'
- ticketid = self._tester.create_ticket(name)
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket()
tc.formvalue('propertyform', 'description', random_sentence(6))
tc.submit('submit')
tc.find('Description<[^>]*>\\s*modified \\(<[^>]*>diff', 's')
tc.follow('diff')
- tc.find('Changes\\s*between\\s*<[^>]*>Initial Version<[^>]*>\\s*and' \
+ tc.find('Changes\\s*between\\s*<[^>]*>Initial Version<[^>]*>\\s*and'
'\\s*<[^>]*>Version 1<[^>]*>\\s*of\\s*<[^>]*>Ticket #' , 's')
@@ -214,14 +282,63 @@ class TestTicketQueryLinks(FunctionalTwi
tc.find('class="missing">Next Ticket →')
+class TestTicketQueryLinksQueryModuleDisabled(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Ticket query links should not be present when the QueryModule
+ is disabled."""
+ def enable_query_module(enable):
+ self._tester.go_to_admin('Plugins')
+ tc.formvalue('edit-plugin-trac', 'component',
+ 'trac.ticket.query.QueryModule')
+ tc.formvalue('edit-plugin-trac', 'enable',
+ '%strac.ticket.query.QueryModule'
+ % ('+' if enable else '-'))
+ tc.submit()
+ tc.find("The following component has been %s:"
+ ".*QueryModule.*\(trac\.ticket\.query\.\*\)"
+ % ("enabled" if enable else "disabled"))
+ props = {'cc': 'user1, user2',
+ 'component': 'component1',
+ 'keywords': 'kw1, kw2',
+ 'milestone': 'milestone1',
+ 'owner': 'user',
+ 'priority': 'major',
+ 'reporter': 'admin',
+ 'version': '2.0'}
+ tid = self._tester.create_ticket(info=props)
+ milestone_cell = \
+ r'<td headers="h_milestone">\s*' \
+ r'<a class="milestone" href="/milestone/%(milestone)s" ' \
+ r'title=".*">\s*%(milestone)s\s*</a>\s*</td>'\
+ % {'milestone': props['milestone']}
+ try:
+ for field, value in props.iteritems():
+ if field != 'milestone':
+ links = r', '.join(r'<a href="/query.*>%s</a>'
+ % v.strip() for v in value.split(','))
+ tc.find(r'<td headers="h_%s"( class="searchable")?>'
+ r'\s*%s\s*</td>' % (field, links))
+ else:
+ tc.find(milestone_cell)
+ enable_query_module(False)
+ self._tester.go_to_ticket(tid)
+ for field, value in props.iteritems():
+ if field != 'milestone':
+ tc.find(r'<td headers="h_%s"( class="searchable")?>'
+ r'\s*%s\s*</td>' % (field, value))
+ else:
+ tc.find(milestone_cell)
+ finally:
+ enable_query_module(True)
+
+
class TestTicketQueryOrClause(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test ticket query with an or clauses"""
count = 3
- ticket_ids = [self._tester.create_ticket(
- summary='TestTicketQueryOrClause%s' % i,
- info={'keywords': str(i)})
- for i in range(count)]
+ [self._tester.create_ticket(summary='TestTicketQueryOrClause%s' % i,
+ info={'keywords': str(i)})
+ for i in range(count)]
self._tester.go_to_query()
tc.formvalue('query', '0_owner', '')
tc.submit('rm_filter_0_owner_0')
@@ -233,7 +350,7 @@ class TestTicketQueryOrClause(Functional
tc.formvalue('query', '1_keywords', '2')
tc.submit('update')
tc.notfind('TestTicketQueryOrClause0')
- for i in [1, 2]:
+ for i in (1, 2):
tc.find('TestTicketQueryOrClause%s' % i)
@@ -249,11 +366,8 @@ class TestTicketCustomFieldTextNoFormat(
env.config.set('ticket-custom', 'newfield.format', '')
env.config.save()
- self._testenv.restart()
val = "%s %s" % (random_unique_camel(), random_word())
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % val)
@@ -269,11 +383,8 @@ class TestTicketCustomFieldTextAreaNoFor
env.config.set('ticket-custom', 'newfield.format', '')
env.config.save()
- self._testenv.restart()
val = "%s %s" % (random_unique_camel(), random_word())
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % val)
@@ -290,13 +401,10 @@ class TestTicketCustomFieldTextWikiForma
env.config.set('ticket-custom', 'newfield.format', 'wiki')
env.config.save()
- self._testenv.restart()
word1 = random_unique_camel()
word2 = random_word()
val = "%s %s" % (word1, word2)
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
wiki = '<a [^>]*>%s\??</a> %s' % (word1, word2)
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % wiki)
@@ -313,13 +421,10 @@ class TestTicketCustomFieldTextAreaWikiF
env.config.set('ticket-custom', 'newfield.format', 'wiki')
env.config.save()
- self._testenv.restart()
word1 = random_unique_camel()
word2 = random_word()
val = "%s %s" % (word1, word2)
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
wiki = '<p>\s*<a [^>]*>%s\??</a> %s<br />\s*</p>' % (word1, word2)
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % wiki)
@@ -338,13 +443,10 @@ class TestTicketCustomFieldTextReference
env.config.set('ticket-custom', 'newfield.format', 'reference')
env.config.save()
- self._testenv.restart()
word1 = random_unique_camel()
word2 = random_word()
val = "%s %s" % (word1, word2)
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
query = 'status=!closed&newfield=%s\+%s' % (word1, word2)
querylink = '<a href="/query\?%s">%s</a>' % (query, val)
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % querylink)
@@ -364,13 +466,10 @@ class TestTicketCustomFieldTextListForma
env.config.set('ticket-custom', 'newfield.format', 'list')
env.config.save()
- self._testenv.restart()
word1 = random_unique_camel()
word2 = random_word()
val = "%s %s" % (word1, word2)
- ticketid = self._tester.create_ticket(summary=random_sentence(3),
- info={'newfield': val})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket(info={'newfield': val})
query1 = 'status=!closed&newfield=~%s' % word1
query2 = 'status=!closed&newfield=~%s' % word2
querylink1 = '<a href="/query\?%s">%s</a>' % (query1, word1)
@@ -392,9 +491,7 @@ class RegressionTestTicket10828(Function
env.config.set('ticket-custom', 'newfield.format', 'list')
env.config.save()
- self._testenv.restart()
- ticketid = self._tester.create_ticket(summary=random_sentence(3))
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket()
word1 = random_unique_camel()
word2 = random_word()
@@ -431,7 +528,7 @@ class RegressionTestTicket10828(Function
tc.find('<td headers="h_newfield"[^>]*>\s*%s\s*</td>' % querylinks)
-class TestTimelineTicketDetails(FunctionalTwillTestCaseSetup):
+class TestTicketTimeline(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test ticket details on timeline"""
env = self._testenv.get_trac_environment()
@@ -439,14 +536,18 @@ class TestTimelineTicketDetails(Function
env.config.save()
summary = random_sentence(5)
ticketid = self._tester.create_ticket(summary)
- self._tester.go_to_ticket(ticketid)
self._tester.add_comment(ticketid)
+
self._tester.go_to_timeline()
+ tc.formvalue('prefs', 'ticket', True)
+ tc.submit()
+ tc.find('Ticket.*#%s.*created' % ticketid)
tc.formvalue('prefs', 'ticket_details', True)
tc.submit()
htmltags = '(<[^>]*>)*'
- tc.find('Ticket ' + htmltags + '#' + str(ticketid) + htmltags + ' \\(' +
- summary + '\\) updated\\s+by\\s+' + htmltags + 'admin', 's')
+ tc.find('Ticket ' + htmltags + '#' + str(ticketid) + htmltags +
+ ' \\(' + summary.split()[0] +
+ ' [^\\)]+\\) updated\\s+by\\s+' + htmltags + 'admin', 's')
class TestAdminComponent(FunctionalTwillTestCaseSetup):
@@ -455,10 +556,17 @@ class TestAdminComponent(FunctionalTwill
self._tester.create_component()
+class TestAdminComponentAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Components
+ panel."""
+ self.test_authorization('/admin/ticket/components', 'TICKET_ADMIN',
+ "Manage Components")
+
class TestAdminComponentDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate component"""
- name = "DuplicateMilestone"
+ name = "DuplicateComponent"
self._tester.create_component(name)
component_url = self._tester.url + "/admin/ticket/components"
tc.go(component_url)
@@ -521,12 +629,44 @@ class TestAdminComponentDetail(Functiona
tc.notfind(desc)
+class TestAdminComponentNoneDefined(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """The table should be hidden and help text shown when there are no
+ components defined (#11103)."""
+ from trac.ticket import model
+ env = self._testenv.get_trac_environment()
+ components = list(model.Component.select(env))
+ self._tester.go_to_admin()
+ tc.follow(r"\bComponents\b")
+
+ try:
+ for comp in components:
+ tc.formvalue('component_table', 'sel', comp.name)
+ tc.submit('remove')
+ tc.notfind('<table class="listing" id="complist">')
+ tc.find("As long as you don't add any items to the list, this "
+ "field[ \t\n]*will remain completely hidden from the "
+ "user interface.")
+ finally:
+ for comp in components:
+ self._tester.create_component(comp.name, comp.owner,
+ comp.description)
+
+
class TestAdminMilestone(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create milestone"""
self._tester.create_milestone()
+class TestAdminMilestoneAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Milestone
+ panel."""
+ self.test_authorization('/admin/ticket/milestones', 'TICKET_ADMIN',
+ "Manage Milestones")
+
+
class TestAdminMilestoneSpace(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create milestone with a space"""
@@ -590,7 +730,8 @@ class TestAdminMilestoneDue(FunctionalTw
"""Admin milestone duedate"""
name = "DueMilestone"
duedate = datetime.now(tz=utc)
- duedate_string = format_datetime(duedate, tzinfo=utc, locale=locale_en)
+ duedate_string = format_datetime(duedate, tzinfo=utc,
+ locale=locale_en)
self._tester.create_milestone(name, due=duedate_string)
tc.find(duedate_string)
@@ -609,13 +750,40 @@ class TestAdminMilestoneDetailDue(Functi
tc.follow(name)
tc.url(milestone_url + '/' + name)
duedate = datetime.now(tz=utc)
- duedate_string = format_datetime(duedate, tzinfo=utc, locale=locale_en)
+ duedate_string = format_datetime(duedate, tzinfo=utc,
+ locale=locale_en)
tc.formvalue('modifymilestone', 'due', duedate_string)
tc.submit('save')
tc.url(milestone_url + '$')
tc.find(name + '(<[^>]*>|\\s)*'+ duedate_string, 's')
+class TestAdminMilestoneDetailRename(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Admin rename milestone"""
+ name1 = self._tester.create_milestone()
+ name2 = random_unique_camel()
+ tid = self._tester.create_ticket(info={'milestone': name1})
+ milestone_url = self._tester.url + '/admin/ticket/milestones'
+
+ self._tester.go_to_url(milestone_url)
+ tc.follow(name1)
+ tc.url(milestone_url + '/' + name1)
+ tc.formvalue('modifymilestone', 'name', name2)
+ tc.submit('save')
+
+ tc.find(r"Your changes have been saved\.")
+ tc.find(r"\b%s\b" % name2)
+ tc.notfind(r"\b%s\b" % name1)
+ self._tester.go_to_ticket(tid)
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="No date set">%(name)s</a>' % {'name': name2})
+ tc.find('<strong class="trac-field-milestone">Milestone</strong>'
+ '[ \t\n]+changed from <em>%s</em> to <em>%s</em>'
+ % (name1, name2))
+ tc.find("Milestone renamed")
+
+
class TestAdminMilestoneCompleted(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin milestone completed"""
@@ -642,7 +810,7 @@ class TestAdminMilestoneCompletedFuture(
tc.follow(name)
tc.url(milestone_url + '/' + name)
tc.formvalue('modifymilestone', 'completed', True)
- cdate = datetime.now(tz=utc) + timedelta(days=1)
+ cdate = datetime.now(tz=utc) + timedelta(days=2)
cdate_string = format_date(cdate, tzinfo=localtz, locale=locale_en)
tc.formvalue('modifymilestone', 'completeddate', cdate_string)
tc.submit('save')
@@ -657,12 +825,22 @@ class TestAdminMilestoneRemove(Functiona
"""Admin remove milestone"""
name = "MilestoneRemove"
self._tester.create_milestone(name)
- milestone_url = self._tester.url + "/admin/ticket/milestones"
+ tid = self._tester.create_ticket(info={'milestone': name})
+ milestone_url = self._tester.url + '/admin/ticket/milestones'
+
tc.go(milestone_url)
tc.formvalue('milestone_table', 'sel', name)
tc.submit('remove')
+
tc.url(milestone_url + '$')
tc.notfind(name)
+ self._tester.go_to_ticket(tid)
+ tc.find('<th id="h_milestone" class="missing">'
+ '[ \t\n]*Milestone:[ \t\n]*</th>')
+ tc.find('<strong class="trac-field-milestone">Milestone'
+ '</strong>[ \t\n]*<em>%s</em>[ \t\n]*deleted'
+ % name)
+ tc.find("Milestone deleted")
class TestAdminMilestoneRemoveMulti(FunctionalTwillTestCaseSetup):
@@ -717,6 +895,14 @@ class TestAdminPriority(FunctionalTwillT
self._tester.create_priority()
+class TestAdminPriorityAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Priority
+ panel."""
+ self.test_authorization('/admin/ticket/priority', 'TICKET_ADMIN',
+ "Manage Priorities")
+
+
class TestAdminPriorityDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate priority"""
@@ -846,8 +1032,10 @@ class TestAdminPriorityRenumber(Function
tc.url(priority_url + '$')
tc.find(name + '1')
tc.find(name + '2')
- tc.formvalue('enumtable', 'value_%s' % (max_priority + 1), str(max_priority + 2))
- tc.formvalue('enumtable', 'value_%s' % (max_priority + 2), str(max_priority + 1))
+ tc.formvalue('enumtable',
+ 'value_%s' % (max_priority + 1), str(max_priority + 2))
+ tc.formvalue('enumtable',
+ 'value_%s' % (max_priority + 2), str(max_priority + 1))
tc.submit('apply')
tc.url(priority_url + '$')
# Verify that their order has changed.
@@ -873,6 +1061,14 @@ class TestAdminResolution(FunctionalTwil
self._tester.create_resolution()
+class TestAdminResolutionAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Resolutions
+ panel."""
+ self.test_authorization('/admin/ticket/resolution', 'TICKET_ADMIN',
+ "Manage Resolutions")
+
+
class TestAdminResolutionDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate resolution"""
@@ -888,6 +1084,14 @@ class TestAdminSeverity(FunctionalTwillT
self._tester.create_severity()
+class TestAdminSeverityAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Severities
+ panel."""
+ self.test_authorization('/admin/ticket/severity', 'TICKET_ADMIN',
+ "Manage Severities")
+
+
class TestAdminSeverityDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate severity"""
@@ -903,6 +1107,14 @@ class TestAdminType(FunctionalTwillTestC
self._tester.create_type()
+class TestAdminTypeAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Ticket Types
+ panel."""
+ self.test_authorization('/admin/ticket/type', 'TICKET_ADMIN',
+ "Manage Ticket Types")
+
+
class TestAdminTypeDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate type"""
@@ -918,6 +1130,13 @@ class TestAdminVersion(FunctionalTwillTe
self._tester.create_version()
+class TestAdminVersionAuthorization(AuthorizationTestCaseSetup):
+ def runTest(self):
+ """Check permissions required to access the Versions panel."""
+ self.test_authorization('/admin/ticket/versions', 'TICKET_ADMIN',
+ "Manage Versions")
+
+
class TestAdminVersionDuplicates(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create duplicate version"""
@@ -965,7 +1184,8 @@ class TestAdminVersionDetailTime(Functio
tc.formvalue('modifyversion', 'time', '')
tc.submit('save')
tc.url(version_admin + '$')
- tc.find(name + '(<[^>]*>|\\s)*<[^>]* name="default" value="%s"' % name, 's')
+ tc.find(name + '(<[^>]*>|\\s)*<[^>]* name="default" value="%s"'
+ % name, 's')
class TestAdminVersionDetailCancel(FunctionalTwillTestCaseSetup):
@@ -1114,6 +1334,191 @@ UNION ALL SELECT 'attachment', 'file.ext
'file[.]ext [(]WikiStart[)]</a>')
+class TestMilestone(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Create a milestone."""
+ self._tester.go_to_roadmap()
+ tc.submit(formname='add')
+ tc.url(self._tester.url + '/milestone\?action=new')
+ name = random_unique_camel()
+ due = format_datetime(datetime.now(tz=utc) + timedelta(hours=1),
+ tzinfo=localtz, locale=locale_en)
+ tc.formvalue('edit', 'name', name)
+ tc.formvalue('edit', 'due', True)
+ tc.formvalue('edit', 'duedate', due)
+ tc.submit('add')
+ tc.url(self._tester.url + '/milestone/' + name + '$')
+ tc.find(r'<h1>Milestone %s</h1>' % name)
+ tc.find(due)
+ self._tester.create_ticket(info={'milestone': name})
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="Due in .+ (.+)">%(name)s</a>'
+ % {'name': name})
+
+
+class TestMilestoneAddAttachment(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Add attachment to a milestone. Test that the attachment
+ button reads 'Attach file' when no files have been attached, and
+ 'Attach another file' when there are existing attachments.
+ Feature added in http://trac.edgewall.org/ticket/10281."""
+ name = self._tester.create_milestone()
+ self._tester.go_to_milestone(name)
+ tc.find("Attach file")
+ filename = self._tester.attach_file_to_milestone(name)
+
+ self._tester.go_to_milestone(name)
+ tc.find("Attach another file")
+ tc.find('Attachments <span class="trac-count">\(1\)</span>')
+ tc.find(filename)
+ tc.find('Download all attachments as:\s+<a rel="nofollow" '
+ 'href="/zip-attachment/milestone/%s/">.zip</a>' % name)
+
+
+class TestMilestoneClose(FunctionalTwillTestCaseSetup):
+ """Close a milestone and verify that tickets are retargeted
+ to the selected milestone"""
+ def runTest(self):
+ name = self._tester.create_milestone()
+ retarget_to = self._tester.create_milestone()
+ tid1 = self._tester.create_ticket(info={'milestone': name})
+ tid2 = self._tester.create_ticket(info={'milestone': name})
+ tc.formvalue('propertyform', 'action', 'resolve')
+ tc.formvalue('propertyform',
+ 'action_resolve_resolve_resolution', 'fixed')
+ tc.submit('submit')
+
+ self._tester.go_to_milestone(name)
+ completed = format_datetime(datetime.now(tz=utc) - timedelta(hours=1),
+ tzinfo=localtz, locale=locale_en)
+ tc.submit(formname='editmilestone')
+ tc.formvalue('edit', 'completed', True)
+ tc.formvalue('edit', 'completeddate', completed)
+ tc.formvalue('edit', 'target', retarget_to)
+ tc.submit('save')
+
+ tc.url(self._tester.url + '/milestone/%s$' % name)
+ tc.find('The open tickets associated with milestone "%s" '
+ 'have been retargeted to milestone "%s".'
+ % (name, retarget_to))
+ tc.find("Completed")
+ self._tester.go_to_ticket(tid1)
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="No date set">%(name)s</a>' % {'name': retarget_to})
+ tc.find('changed from <em>%s</em> to <em>%s</em>'
+ % (name, retarget_to))
+ tc.find("Ticket retargeted after milestone closed")
+ self._tester.go_to_ticket(tid2)
+ tc.find('<a class="closed milestone" href="/milestone/%(name)s" '
+ 'title="Completed .+ ago (.+)">%(name)s</a>'
+ % {'name': name})
+ tc.notfind('changed from <em>%s</em> to <em>%s</em>'
+ % (name, retarget_to))
+ tc.notfind("Ticket retargeted after milestone closed")
+
+
+class TestMilestoneDelete(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Delete a milestone and verify that tickets are retargeted
+ to the selected milestone."""
+ def delete_milestone(name, retarget_to=None, tid=None):
+ self._tester.go_to_milestone(name)
+ tc.submit(formname='deletemilestone')
+ if retarget_to is not None:
+ tc.formvalue('edit', 'target', retarget_to)
+ tc.submit('delete', formname='edit')
+
+ tc.url(self._tester.url + '/roadmap')
+ tc.find('The milestone "%s" has been deleted.' % name)
+ tc.notfind('Milestone:.*%s' % name)
+ if retarget_to is not None:
+ tc.find('Milestone:.*%s' % retarget_to)
+ retarget_notice = 'The tickets associated with milestone "%s" ' \
+ 'have been retargeted to milestone "%s".' \
+ % (name, str(retarget_to))
+ if tid is not None:
+ tc.find(retarget_notice)
+ self._tester.go_to_ticket(tid)
+ tc.find('Changed[ \t\n]+<a .*>\d+ seconds? ago</a>'
+ '[ \t\n]+by admin')
+ if retarget_to is not None:
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="No date set">%(name)s</a>'
+ % {'name': retarget_to})
+ tc.find('<strong class="trac-field-milestone">Milestone'
+ '</strong>[ \t\n]+changed from <em>%s</em> to '
+ '<em>%s</em>' % (name, retarget_to))
+ else:
+ tc.find('<th id="h_milestone" class="missing">'
+ '[ \t\n]*Milestone:[ \t\n]*</th>')
+ tc.find('<strong class="trac-field-milestone">Milestone'
+ '</strong>[ \t\n]*<em>%s</em>[ \t\n]*deleted'
+ % name)
+ tc.find("Ticket retargeted after milestone deleted")
+ else:
+ tc.notfind(retarget_notice)
+
+ # No tickets associated with milestone to be retargeted
+ name = self._tester.create_milestone()
+ delete_milestone(name)
+
+ # Don't select a milestone to retarget to
+ name = self._tester.create_milestone()
+ tid = self._tester.create_ticket(info={'milestone': name})
+ delete_milestone(name, tid=tid)
+
+ # Select a milestone to retarget to
+ name = self._tester.create_milestone()
+ retarget_to = self._tester.create_milestone()
+ tid = self._tester.create_ticket(info={'milestone': name})
+ delete_milestone(name, retarget_to, tid)
+
+ # Just navigate to the page and select cancel
+ name = self._tester.create_milestone()
+ tid = self._tester.create_ticket(info={'milestone': name})
+
+ self._tester.go_to_milestone(name)
+ tc.submit(formname='deletemilestone')
+ tc.submit('cancel', formname='edit')
+
+ tc.url(self._tester.url + '/milestone/%s' % name)
+ tc.notfind('The milestone "%s" has been deleted.' % name)
+ tc.notfind('The tickets associated with milestone "%s" '
+ 'have been retargeted to milestone' % name)
+ self._tester.go_to_ticket(tid)
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="No date set">%(name)s</a>' % {'name': name})
+ tc.notfind('<strong class="trac-field-milestone">Milestone</strong>'
+ '[ \t\n]*<em>%s</em>[ \t\n]*deleted' % name)
+ tc.notfind("Ticket retargeted after milestone deleted<br />")
+
+
+class TestMilestoneRename(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Rename a milestone and verify that the rename is shown in the
+ change history for the associated tickets."""
+ name = self._tester.create_milestone()
+ new_name = random_unique_camel()
+ tid = self._tester.create_ticket(info={'milestone': name})
+
+ self._tester.go_to_milestone(name)
+ tc.submit(formname='editmilestone')
+ tc.formvalue('edit', 'name', new_name)
+ tc.submit('save')
+
+ tc.url(self._tester.url + '/milestone/' + new_name)
+ tc.find("Your changes have been saved.")
+ tc.find(r"<h1>Milestone %s</h1>" % new_name)
+ self._tester.go_to_ticket(tid)
+ tc.find('Changed[ \t\n]+<a .*>\d+ seconds? ago</a>[ \t\n]+by admin')
+ tc.find('<a class="milestone" href="/milestone/%(name)s" '
+ 'title="No date set">%(name)s</a>' % {'name': new_name})
+ tc.find('<strong class="trac-field-milestone">Milestone</strong>'
+ '[ \t\n]+changed from <em>%s</em> to <em>%s</em>'
+ % (name, new_name))
+ tc.find("Milestone renamed")
+
+
class RegressionTestRev5665(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Admin create version without release time (r5665)"""
@@ -1128,7 +1533,6 @@ class RegressionTestRev5994(FunctionalTw
env.config.set('ticket-custom', 'custfield.label', 'Custom Field')
env.config.save()
try:
- self._testenv.restart()
self._tester.go_to_query()
tc.find('<label>( |\\n)*<input[^<]*value="custfield"'
'[^<]*/>( |\\n)*Custom Field( |\\n)*</label>', 's')
@@ -1136,23 +1540,21 @@ class RegressionTestRev5994(FunctionalTw
pass
#env.config.set('ticket', 'restrict_owner', 'no')
#env.config.save()
- #self._testenv.restart()
class RegressionTestTicket4447(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/4447"""
- ticketid = self._tester.create_ticket(summary="Hello World")
-
env = self._testenv.get_trac_environment()
env.config.set('ticket-custom', 'newfield', 'text')
env.config.set('ticket-custom', 'newfield.label',
'Another Custom Field')
env.config.save()
- self._testenv.restart()
- self._tester.go_to_ticket(ticketid)
+
+ ticketid = self._tester.create_ticket(summary="Hello World")
self._tester.add_comment(ticketid)
- tc.notfind('deleted')
+ tc.notfind('<strong class="trac-field-newfield">Another Custom Field'
+ '</strong>[ \t\n]+<em></em>[ \t\n]+deleted')
tc.notfind('set to')
@@ -1163,25 +1565,27 @@ class RegressionTestTicket4630a(Function
env.config.set('ticket', 'restrict_owner', 'yes')
env.config.save()
try:
- self._testenv.restart()
# Make sure 'user' has logged in.
self._tester.go_to_front()
self._tester.logout()
self._tester.login('user')
+ self._tester.go_to_front()
+ self._tester.logout()
+ self._tester.login('joe')
+ self._tester.go_to_front()
self._tester.logout()
self._tester.login('admin')
- ticket_id = self._tester.create_ticket()
- self._tester.go_to_ticket(ticket_id)
+ self._tester.create_ticket()
tc.formvalue('propertyform', 'action', 'reassign')
tc.find('reassign_reassign_owner')
- tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'user')
+ tc.formvalue('propertyform', 'action_reassign_reassign_owner',
+ 'user')
tc.submit('submit')
finally:
# Undo the config change for now since this (failing)
# regression test causes problems for later tests.
env.config.set('ticket', 'restrict_owner', 'no')
env.config.save()
- self._testenv.restart()
class RegressionTestTicket4630b(FunctionalTestCaseSetup):
@@ -1195,7 +1599,7 @@ class RegressionTestTicket4630b(Function
users = perm.get_users_with_permission('TRAC_ADMIN')
self.assertEqual(users, ['admin'])
users = perm.get_users_with_permission('TICKET_MODIFY')
- self.assertEqual(users, ['admin', 'user'])
+ self.assertEqual(sorted(users), ['admin', 'joe', 'user'])
class RegressionTestTicket5022(FunctionalTwillTestCaseSetup):
@@ -1217,14 +1621,13 @@ class RegressionTestTicket5394a(Function
env = self._testenv.get_trac_environment()
env.config.set('ticket', 'restrict_owner', 'yes')
env.config.save()
- self._testenv.restart()
self._tester.go_to_front()
self._tester.logout()
test_users = ['alice', 'bob', 'jane', 'john', 'charlie', 'alan',
'zorro']
- # Apprently it takes a sec for the new user to be recognized by the
+ # Apparently it takes a sec for the new user to be recognized by the
# environment. So we add all the users, then log in as the users
# in a second loop. This should be faster than adding a sleep(1)
# between the .adduser and .login steps.
@@ -1232,17 +1635,17 @@ class RegressionTestTicket5394a(Function
self._testenv.adduser(user)
for user in test_users:
self._tester.login(user)
+ self._tester.go_to_front()
self._tester.logout()
self._tester.login('admin')
- ticketid = self._tester.create_ticket("regression test 5394a")
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket("regression test 5394a")
options = 'id="action_reassign_reassign_owner">' + \
''.join(['<option[^>]*>%s</option>' % user for user in
- sorted(test_users + ['admin', 'user'])])
- tc.find(options, 's')
+ sorted(test_users + ['admin', 'joe', 'user'])])
+ tc.find(to_utf8(options), 's')
# We don't have a good way to fully delete a user from the Trac db.
# Once we do, we may want to cleanup our list of users here.
@@ -1285,8 +1688,7 @@ class RegressionTestTicket5497a(Function
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/5497 a
Open ticket, component changed, owner not changed"""
- ticketid = self._tester.create_ticket("regression test 5497a")
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket("regression test 5497a")
tc.formvalue('propertyform', 'field-component', 'regression5497')
tc.submit('submit')
tc.find(regex_owned_by('user'))
@@ -1295,11 +1697,11 @@ class RegressionTestTicket5497b(Function
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/5497 b
Open ticket, component changed, owner changed"""
- ticketid = self._tester.create_ticket("regression test 5497b")
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket("regression test 5497b")
tc.formvalue('propertyform', 'field-component', 'regression5497')
tc.formvalue('propertyform', 'action', 'reassign')
- tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'admin')
+ tc.formvalue('propertyform', 'action_reassign_reassign_owner',
+ 'admin')
tc.submit('submit')
tc.notfind(regex_owned_by('user'))
tc.find(regex_owned_by('admin'))
@@ -1308,18 +1710,17 @@ class RegressionTestTicket5497c(Function
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/5497 c
New ticket, component changed, owner not changed"""
- ticketid = self._tester.create_ticket("regression test 5497c",
- {'component':'regression5497'})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket("regression test 5497c",
+ {'component':'regression5497'})
tc.find(regex_owned_by('user'))
class RegressionTestTicket5497d(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/5497 d
New ticket, component changed, owner changed"""
- ticketid = self._tester.create_ticket("regression test 5497d",
- {'component':'regression5497', 'owner':'admin'})
- self._tester.go_to_ticket(ticketid)
+ self._tester.create_ticket("regression test 5497d",
+ {'component':'regression5497',
+ 'owner':'admin'})
tc.find(regex_owned_by('admin'))
@@ -1328,15 +1729,16 @@ class RegressionTestTicket5602(Functiona
"""Test for regression of http://trac.edgewall.org/ticket/5602"""
# Create a set of tickets, and assign them all to a milestone
milestone = self._tester.create_milestone()
- ids = [self._tester.create_ticket() for x in range(5)]
- [self._tester.ticket_set_milestone(x, milestone) for x in ids]
+ ids = [self._tester.create_ticket(info={'milestone': milestone})
+ for x in range(5)]
# Need a ticket in each state: new, assigned, accepted, closed,
# reopened
# leave ids[0] as new
# make ids[1] be assigned
self._tester.go_to_ticket(ids[1])
tc.formvalue('propertyform', 'action', 'reassign')
- tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'admin')
+ tc.formvalue('propertyform', 'action_reassign_reassign_owner',
+ 'admin')
tc.submit('submit')
# make ids[2] be accepted
self._tester.go_to_ticket(ids[2])
@@ -1345,12 +1747,14 @@ class RegressionTestTicket5602(Functiona
# make ids[3] be closed
self._tester.go_to_ticket(ids[3])
tc.formvalue('propertyform', 'action', 'resolve')
- tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
+ tc.formvalue('propertyform', 'action_resolve_resolve_resolution',
+ 'fixed')
tc.submit('submit')
# make ids[4] be reopened
self._tester.go_to_ticket(ids[4])
tc.formvalue('propertyform', 'action', 'resolve')
- tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
+ tc.formvalue('propertyform', 'action_resolve_resolve_resolution',
+ 'fixed')
tc.submit('submit')
# FIXME: we have to wait a second to avoid "IntegrityError: columns
# ticket, time, field are not unique"
@@ -1380,9 +1784,10 @@ class RegressionTestTicket5602(Functiona
class RegressionTestTicket5687(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/5687"""
+ self._tester.go_to_front()
self._tester.logout()
self._tester.login('user')
- ticketid = self._tester.create_ticket()
+ self._tester.create_ticket()
self._tester.logout()
self._tester.login('admin')
@@ -1406,10 +1811,11 @@ class RegressionTestTicket6048(Functiona
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/6048"""
# Setup the DeleteTicket plugin
- plugin = open(os.path.join(self._testenv.command_cwd, 'sample-plugins',
- 'workflow', 'DeleteTicket.py')).read()
- open(os.path.join(self._testenv.tracdir, 'plugins', 'DeleteTicket.py'),
- 'w').write(plugin)
+ plugin = open(os.path.join(self._testenv.command_cwd,
+ 'sample-plugins', 'workflow',
+ 'DeleteTicket.py')).read()
+ open(os.path.join(self._testenv.tracdir, 'plugins',
+ 'DeleteTicket.py'), 'w').write(plugin)
env = self._testenv.get_trac_environment()
prevconfig = env.config.get('ticket', 'workflow')
env.config.set('ticket', 'workflow',
@@ -1418,8 +1824,7 @@ class RegressionTestTicket6048(Functiona
env = self._testenv.get_trac_environment() # reload environment
# Create a ticket and delete it
- ticket_id = self._tester.create_ticket(
- summary='RegressionTestTicket6048')
+ ticket_id = self._tester.create_ticket('RegressionTestTicket6048')
# (Create a second ticket so that the ticket id does not get reused
# and confuse the tester object.)
self._tester.create_ticket(summary='RegressionTestTicket6048b')
@@ -1454,10 +1859,7 @@ class RegressionTestTicket6747(Functiona
env.config.save()
try:
- self._testenv.restart()
-
- ticket_id = self._tester.create_ticket("RegressionTestTicket6747")
- self._tester.go_to_ticket(ticket_id)
+ self._tester.create_ticket("RegressionTestTicket6747")
tc.find("a_specified_owner")
tc.notfind("a_specified_owneras")
@@ -1468,7 +1870,6 @@ class RegressionTestTicket6747(Functiona
'set_resolution')
env.config.remove('ticket-workflow', 'resolve.set_owner')
env.config.save()
- self._testenv.restart()
class RegressionTestTicket6879a(FunctionalTwillTestCaseSetup):
@@ -1479,10 +1880,10 @@ class RegressionTestTicket6879a(Function
be those for the close status.
"""
# create a ticket, then preview resolving the ticket twice
- ticket_id = self._tester.create_ticket("RegressionTestTicket6879 a")
- self._tester.go_to_ticket(ticket_id)
+ self._tester.create_ticket("RegressionTestTicket6879 a")
tc.formvalue('propertyform', 'action', 'resolve')
- tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
+ tc.formvalue('propertyform', 'action_resolve_resolve_resolution',
+ 'fixed')
tc.submit('preview')
tc.formvalue('propertyform', 'action', 'resolve')
tc.submit('preview')
@@ -1496,10 +1897,10 @@ class RegressionTestTicket6879b(Function
be those for the close status.
"""
# create a ticket, then preview resolving the ticket twice
- ticket_id = self._tester.create_ticket("RegressionTestTicket6879 b")
- self._tester.go_to_ticket(ticket_id)
+ self._tester.create_ticket("RegressionTestTicket6879 b")
tc.formvalue('propertyform', 'action', 'resolve')
- tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
+ tc.formvalue('propertyform', 'action_resolve_resolve_resolution',
+ 'fixed')
tc.submit('preview')
tc.formvalue('propertyform', 'action', 'resolve')
tc.submit('submit')
@@ -1510,7 +1911,7 @@ class RegressionTestTicket6912a(Function
"""Test for regression of http://trac.edgewall.org/ticket/6912 a"""
try:
self._tester.create_component(name='RegressionTestTicket6912a',
- user='')
+ owner='')
except twill.utils.ClientForm.ItemNotFoundError, e:
raise twill.errors.TwillAssertionError(e)
@@ -1519,7 +1920,7 @@ class RegressionTestTicket6912b(Function
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/6912 b"""
self._tester.create_component(name='RegressionTestTicket6912b',
- user='admin')
+ owner='admin')
tc.follow('RegressionTestTicket6912b')
try:
tc.formvalue('modcomp', 'owner', '')
@@ -1532,7 +1933,8 @@ class RegressionTestTicket6912b(Function
class RegressionTestTicket7821group(FunctionalTwillTestCaseSetup):
def runTest(self):
- """Test for regression of http://trac.edgewall.org/ticket/7821 group"""
+ """Test for regression of http://trac.edgewall.org/ticket/7821 group.
+ """
env = self._testenv.get_trac_environment()
saved_default_query = env.config.get('query', 'default_query')
default_query = 'status!=closed&order=status&group=status&max=42' \
@@ -1541,7 +1943,6 @@ class RegressionTestTicket7821group(Func
env.config.set('query', 'default_query', default_query)
env.config.save()
try:
- self._testenv.restart()
self._tester.create_ticket('RegressionTestTicket7821 group')
self._tester.go_to_query()
# $USER
@@ -1573,7 +1974,6 @@ class RegressionTestTicket7821group(Func
finally:
env.config.set('query', 'default_query', saved_default_query)
env.config.save()
- self._testenv.restart()
class RegressionTestTicket7821var(FunctionalTwillTestCaseSetup):
@@ -1587,7 +1987,6 @@ class RegressionTestTicket7821var(Functi
env.config.set('ticket', 'restrict_owner', 'no')
env.config.save()
try:
- self._testenv.restart()
self._tester.create_ticket('RegressionTestTicket7821 var')
self._tester.go_to_query()
# $USER in default_query
@@ -1606,7 +2005,6 @@ class RegressionTestTicket7821var(Functi
env.config.set('query', 'default_query', saved_default_query)
env.config.set('ticket', 'restrict_owner', saved_restrict_owner)
env.config.save()
- self._testenv.restart()
class RegressionTestTicket8247(FunctionalTwillTestCaseSetup):
@@ -1665,21 +2063,147 @@ class RegressionTestTicket9084(Functiona
class RegressionTestTicket9981(FunctionalTwillTestCaseSetup):
def runTest(self):
"""Test for regression of http://trac.edgewall.org/ticket/9981"""
- ticketid = self._tester.create_ticket()
- self._tester.add_comment(ticketid)
+ tid1 = self._tester.create_ticket()
+ self._tester.add_comment(tid1)
tc.formvalue('propertyform', 'action', 'resolve')
tc.submit('submit')
- comment = '[ticket:%s#comment:1]' % ticketid
- self._tester.add_comment(ticketid, comment=comment)
- self._tester.go_to_ticket(ticketid)
- tc.find('class="closed ticket".*ticket/%s#comment:1"' % ticketid)
+ tid2 = self._tester.create_ticket()
+ comment = '[comment:1:ticket:%s]' % tid1
+ self._tester.add_comment(tid2, comment)
+ self._tester.go_to_ticket(tid2)
+ tc.find('<a class="closed ticket"[ \t\n]+'
+ 'href="/ticket/%(num)s#comment:1"[ \t\n]+'
+ 'title="Comment 1 for Ticket #%(num)s"' % {'num': tid1})
+
+
+class RegressionTestTicket11028(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Test for regression of http://trac.edgewall.org/ticket/11028"""
+ self._tester.go_to_roadmap()
+
+ try:
+ # Check that a milestone is found on the roadmap,
+ # even for anonymous
+ tc.find('<a href="/milestone/milestone1">[ \n\t]*'
+ 'Milestone: <em>milestone1</em>[ \n\t]*</a>')
+ self._tester.logout()
+ tc.find('<a href="/milestone/milestone1">[ \n\t]*'
+ 'Milestone: <em>milestone1</em>[ \n\t]*</a>')
+
+ # Check that no milestones are found on the roadmap when
+ # MILESTONE_VIEW is revoked
+ self._testenv.revoke_perm('anonymous', 'MILESTONE_VIEW')
+ tc.reload()
+ tc.notfind('Milestone: <em>milestone\d+</em>')
+
+ # Check that roadmap can't be viewed without ROADMAP_VIEW
+
+ self._testenv.revoke_perm('anonymous', 'ROADMAP_VIEW')
+ self._tester.go_to_url(self._tester.url + '/roadmap')
+ tc.find('<h1>Error: Forbidden</h1>')
+ finally:
+ # Restore state prior to test execution
+ self._tester.login('admin')
+ self._testenv.grant_perm('anonymous',
+ ('ROADMAP_VIEW', 'MILESTONE_VIEW'))
+
+
+class RegressionTestTicket11153(FunctionalTwillTestCaseSetup):
+ def runTest(self):
+ """Test for regression of http://trac.edgewall.org/ticket/11153"""
+ # Check that "View Tickets" mainnav entry links to the report page
+ self._tester.go_to_view_tickets()
+
+ # Check that "View Tickets" mainnav entry links to the query page
+ # when the user doesn't have REPORT_VIEW, and that the mainnav entry
+ # is not present when the user doesn't have TICKET_VIEW.
+ try:
+ self._tester.logout()
+ self._testenv.revoke_perm('anonymous', 'REPORT_VIEW')
+ self._tester.go_to_view_tickets('query')
+
+ self._testenv.revoke_perm('anonymous', 'TICKET_VIEW')
+ self._tester.go_to_front()
+ tc.notfind('\\bView Tickets\\b')
+ finally:
+ self._testenv.grant_perm('anonymous',
+ ('REPORT_VIEW', 'TICKET_VIEW'))
+ self._tester.login('admin')
+
+ # Disable the ReportModule component and check that "View Tickets"
+ # mainnav entry links to the `/query` page.
+ env = self._testenv.get_trac_environment()
+ env.config.set('components', 'trac.ticket.report.ReportModule',
+ 'disabled')
+ env.config.save()
+
+ try:
+ self._tester.go_to_view_tickets('query')
+ finally:
+ env.config.remove('components', 'trac.ticket.report.ReportModule')
+ env.config.save()
+
+
+class RegressionTestTicket11176(FunctionalTestCaseSetup):
+ def runTest(self):
+ """Test for regression of http://trac.edgewall.org/ticket/11176
+ Fine-grained permission checks should be enforced on the Report list
+ page, the report pages and query pages."""
+ self._testenv.enable_authz_permpolicy("""
+ [report:1]
+ anonymous = REPORT_VIEW
+ [report:2]
+ anonymous = REPORT_VIEW
+ [report:*]
+ anonymous =
+ """)
+ self._tester.go_to_front()
+ self._tester.logout()
+ self._tester.go_to_view_tickets()
+ try:
+ # Check that permissions are enforced on the report list page
+ tc.find(r'<a title="View report" '
+ r'href="/report/1">[ \n\t]*<em>\{1\}</em>')
+ tc.find(r'<a title="View report" '
+ r'href="/report/2">[ \n\t]*<em>\{2\}</em>')
+ for report_num in range(3, 9):
+ tc.notfind(r'<a title="View report" '
+ r'href="/report/%(num)s">[ \n\t]*'
+ r'<em>\{%(num)s\}</em>' % {'num': report_num})
+ # Check that permissions are enforced on the report pages
+ tc.go(self._tester.url + '/report/1')
+ tc.find(r'<h1>\{1\} Active Tickets[ \n\t]*'
+ r'(<span class="numrows">\(\d+ matches\)</span>)?'
+ r'[ \n\t]*</h1>')
+ tc.go(self._tester.url + '/report/2')
+ tc.find(r'<h1>\{2\} Active Tickets by Version[ \n\t]*'
+ r'(<span class="numrows">\(\d+ matches\)</span>)?'
+ r'[ \n\t]*</h1>')
+ for report_num in range(3, 9):
+ tc.go(self._tester.url + '/report/%d' % report_num)
+ tc.find(r'<h1>Error: Forbidden</h1>')
+ # Check that permissions are enforced on the query pages
+ tc.go(self._tester.url + '/query?report=1')
+ tc.find(r'<h1>Active Tickets '
+ r'<span class="numrows">\(\d+ matches\)</span></h1>')
+ tc.go(self._tester.url + '/query?report=2')
+ tc.find(r'<h1>Active Tickets by Version '
+ r'<span class="numrows">\(\d+ matches\)</span></h1>')
+ for report_num in range(3, 9):
+ tc.go(self._tester.url + '/query?report=%d' % report_num)
+ tc.find(r'<h1>Error: Forbidden</h1>')
+ finally:
+ self._tester.login('admin')
+ self._testenv.disable_authz_permpolicy()
def functionalSuite(suite=None):
if not suite:
- import trac.tests.functional.testcases
- suite = trac.tests.functional.testcases.functionalSuite()
+ import trac.tests.functional
+ suite = trac.tests.functional.functionalSuite()
suite.addTest(TestTickets())
+ suite.addTest(TestTicketMaxSummarySize())
+ suite.addTest(TestTicketAddAttachment())
suite.addTest(TestTicketPreview())
suite.addTest(TestTicketNoSummary())
suite.addTest(TestTicketAltFormats())
@@ -1691,6 +2215,7 @@ def functionalSuite(suite=None):
suite.addTest(TestTicketHistory())
suite.addTest(TestTicketHistoryDiff())
suite.addTest(TestTicketQueryLinks())
+ suite.addTest(TestTicketQueryLinksQueryModuleDisabled())
suite.addTest(TestTicketQueryOrClause())
suite.addTest(TestTicketCustomFieldTextNoFormat())
suite.addTest(TestTicketCustomFieldTextWikiFormat())
@@ -1699,19 +2224,23 @@ def functionalSuite(suite=None):
suite.addTest(TestTicketCustomFieldTextReferenceFormat())
suite.addTest(TestTicketCustomFieldTextListFormat())
suite.addTest(RegressionTestTicket10828())
- suite.addTest(TestTimelineTicketDetails())
+ suite.addTest(TestTicketTimeline())
suite.addTest(TestAdminComponent())
+ suite.addTest(TestAdminComponentAuthorization())
suite.addTest(TestAdminComponentDuplicates())
suite.addTest(TestAdminComponentRemoval())
suite.addTest(TestAdminComponentNonRemoval())
suite.addTest(TestAdminComponentDefault())
suite.addTest(TestAdminComponentDetail())
+ suite.addTest(TestAdminComponentNoneDefined())
suite.addTest(TestAdminMilestone())
+ suite.addTest(TestAdminMilestoneAuthorization())
suite.addTest(TestAdminMilestoneSpace())
suite.addTest(TestAdminMilestoneDuplicates())
suite.addTest(TestAdminMilestoneDetail())
suite.addTest(TestAdminMilestoneDue())
suite.addTest(TestAdminMilestoneDetailDue())
+ suite.addTest(TestAdminMilestoneDetailRename())
suite.addTest(TestAdminMilestoneCompleted())
suite.addTest(TestAdminMilestoneCompletedFuture())
suite.addTest(TestAdminMilestoneRemove())
@@ -1719,6 +2248,7 @@ def functionalSuite(suite=None):
suite.addTest(TestAdminMilestoneNonRemoval())
suite.addTest(TestAdminMilestoneDefault())
suite.addTest(TestAdminPriority())
+ suite.addTest(TestAdminPriorityAuthorization())
suite.addTest(TestAdminPriorityModify())
suite.addTest(TestAdminPriorityRemove())
suite.addTest(TestAdminPriorityRemoveMulti())
@@ -1728,12 +2258,16 @@ def functionalSuite(suite=None):
suite.addTest(TestAdminPriorityRenumber())
suite.addTest(TestAdminPriorityRenumberDup())
suite.addTest(TestAdminResolution())
+ suite.addTest(TestAdminResolutionAuthorization())
suite.addTest(TestAdminResolutionDuplicates())
suite.addTest(TestAdminSeverity())
+ suite.addTest(TestAdminSeverityAuthorization())
suite.addTest(TestAdminSeverityDuplicates())
suite.addTest(TestAdminType())
+ suite.addTest(TestAdminTypeAuthorization())
suite.addTest(TestAdminTypeDuplicates())
suite.addTest(TestAdminVersion())
+ suite.addTest(TestAdminVersionAuthorization())
suite.addTest(TestAdminVersionDuplicates())
suite.addTest(TestAdminVersionDetail())
suite.addTest(TestAdminVersionDetailTime())
@@ -1744,6 +2278,11 @@ def functionalSuite(suite=None):
suite.addTest(TestAdminVersionDefault())
suite.addTest(TestNewReport())
suite.addTest(TestReportRealmDecoration())
+ suite.addTest(TestMilestone())
+ suite.addTest(TestMilestoneAddAttachment())
+ suite.addTest(TestMilestoneClose())
+ suite.addTest(TestMilestoneDelete())
+ suite.addTest(TestMilestoneRename())
suite.addTest(RegressionTestRev5665())
suite.addTest(RegressionTestRev5994())
@@ -1773,6 +2312,12 @@ def functionalSuite(suite=None):
suite.addTest(RegressionTestTicket8861())
suite.addTest(RegressionTestTicket9084())
suite.addTest(RegressionTestTicket9981())
+ suite.addTest(RegressionTestTicket11028())
+ suite.addTest(RegressionTestTicket11153())
+ if ConfigObj:
+ suite.addTest(RegressionTestTicket11176())
+ else:
+ print "SKIP: RegressionTestTicket11176 (ConfigObj not installed)"
return suite
Modified: bloodhound/vendor/trac/current/trac/ticket/tests/model.py
URL: http://svn.apache.org/viewvc/bloodhound/vendor/trac/current/trac/ticket/tests/model.py?rev=1567849&r1=1567848&r2=1567849&view=diff
==============================================================================
--- bloodhound/vendor/trac/current/trac/ticket/tests/model.py (original)
+++ bloodhound/vendor/trac/current/trac/ticket/tests/model.py Thu Feb 13 05:08:02 2014
@@ -1,7 +1,19 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2005-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
from __future__ import with_statement
from datetime import datetime, timedelta
-import os.path
from StringIO import StringIO
import tempfile
import shutil
@@ -11,6 +23,7 @@ from trac import core
from trac.attachment import Attachment
from trac.core import TracError, implements
from trac.resource import ResourceNotFound
+from trac.tests import compat
from trac.ticket.model import (
Ticket, Component, Milestone, Priority, Type, Version
)
@@ -117,9 +130,9 @@ class TicketTestCase(unittest.TestCase):
log = ticket3.get_changelog()
self.assertEqual(len(log), 3)
ok_vals = ['foo', 'summary', 'comment']
- self.failUnless(log[0][2] in ok_vals)
- self.failUnless(log[1][2] in ok_vals)
- self.failUnless(log[2][2] in ok_vals)
+ self.assertIn(log[0][2], ok_vals)
+ self.assertIn(log[1][2], ok_vals)
+ self.assertIn(log[2][2], ok_vals)
def test_create_ticket_5(self):
ticket3 = self._modify_a_ticket()
@@ -156,7 +169,7 @@ class TicketTestCase(unittest.TestCase):
ticket.save_changes()
for change in ticket.get_changelog():
- self.assertEqual(None, change[1])
+ self.assertIsNone(change[1])
def test_comment_with_whitespace_only_is_not_saved(self):
ticket = Ticket(self.env)
@@ -309,7 +322,7 @@ class TicketTestCase(unittest.TestCase):
self.assertEqual('john', ticket['reporter'])
# An unknown field
- assert ticket['bar'] is None
+ self.assertIsNone(ticket['bar'])
# Custom field
self.assertEqual('bar', ticket['foo'])
@@ -631,8 +644,8 @@ class TicketCommentDeleteTestCase(Ticket
ticket.delete_change(cnum=4, when=t)
self.assertEqual('a, b', ticket['keywords'])
self.assertEqual('change3', ticket['foo'])
- self.assertEqual(None, ticket.get_change(cnum=4))
- self.assertNotEqual(None, ticket.get_change(cnum=3))
+ self.assertIsNone(ticket.get_change(cnum=4))
+ self.assertIsNotNone(ticket.get_change(cnum=3))
self.assertEqual(t, ticket.time_changed)
def test_delete_last_comment_when_custom_field_gone(self):
@@ -650,13 +663,13 @@ class TicketCommentDeleteTestCase(Ticket
ticket.delete_change(cnum=4, when=t)
self.assertEqual('a, b', ticket['keywords'])
# 'foo' is no longer defined for the ticket
- self.assertEqual(None, ticket['foo'])
+ self.assertIsNone(ticket['foo'])
# however, 'foo=change3' is still in the database
self.assertEqual([('change3',)], self.env.db_query("""
SELECT value FROM ticket_custom WHERE ticket=%s AND name='foo'
""", (self.id,)))
- self.assertEqual(None, ticket.get_change(cnum=4))
- self.assertNotEqual(None, ticket.get_change(cnum=3))
+ self.assertIsNone(ticket.get_change(cnum=4))
+ self.assertIsNotNone(ticket.get_change(cnum=3))
self.assertEqual(t, ticket.time_changed)
def test_delete_last_comment_by_date(self):
@@ -667,8 +680,8 @@ class TicketCommentDeleteTestCase(Ticket
ticket.delete_change(cdate=self.t4, when=t)
self.assertEqual('a, b', ticket['keywords'])
self.assertEqual('change3', ticket['foo'])
- self.assertEqual(None, ticket.get_change(cdate=self.t4))
- self.assertNotEqual(None, ticket.get_change(cdate=self.t3))
+ self.assertIsNone(ticket.get_change(cdate=self.t4))
+ self.assertIsNotNone(ticket.get_change(cdate=self.t3))
self.assertEqual(t, ticket.time_changed)
def test_delete_mid_comment(self):
@@ -679,7 +692,7 @@ class TicketCommentDeleteTestCase(Ticket
foo=dict(author='joe', old='change3', new='change4'))
t = datetime.now(utc)
ticket.delete_change(cnum=3, when=t)
- self.assertEqual(None, ticket.get_change(cnum=3))
+ self.assertIsNone(ticket.get_change(cnum=3))
self.assertEqual('a', ticket['keywords'])
self.assertChange(ticket, 4, self.t4, 'joe',
comment=dict(author='joe', old='4', new='Comment 4'),
@@ -695,7 +708,7 @@ class TicketCommentDeleteTestCase(Ticket
foo=dict(author='joe', old='change3', new='change4'))
t = datetime.now(utc)
ticket.delete_change(cdate=self.t3, when=t)
- self.assertEqual(None, ticket.get_change(cdate=self.t3))
+ self.assertIsNone(ticket.get_change(cdate=self.t3))
self.assertEqual('a', ticket['keywords'])
self.assertChange(ticket, 4, self.t4, 'joe',
comment=dict(author='joe', old='4', new='Comment 4'),
@@ -717,7 +730,7 @@ class TicketCommentDeleteTestCase(Ticket
keywords=dict(author='joe', old='1, 2', new='a'),
foo=dict(author='joe', old='change3', new='change4'))
ticket.delete_change(3)
- self.assertEqual(None, ticket.get_change(3))
+ self.assertIsNone(ticket.get_change(3))
self.assertEqual('a', ticket['keywords'])
self.assertChange(ticket, 4, self.t4, 'joe',
comment=dict(author='joe', old='4', new='Comment 4'),
@@ -751,14 +764,14 @@ class EnumTestCase(unittest.TestCase):
prio = Priority(self.env)
prio.name = 'foo'
prio.insert()
- self.assertEqual(True, prio.exists)
+ self.assertTrue(prio.exists)
def test_priority_insert_with_value(self):
prio = Priority(self.env)
prio.name = 'bar'
prio.value = 100
prio.insert()
- self.assertEqual(True, prio.exists)
+ self.assertTrue(prio.exists)
def test_priority_update(self):
prio = Priority(self.env, 'major')
@@ -771,7 +784,7 @@ class EnumTestCase(unittest.TestCase):
prio = Priority(self.env, 'major')
self.assertEqual('3', prio.value)
prio.delete()
- self.assertEqual(False, prio.exists)
+ self.assertFalse(prio.exists)
self.assertRaises(TracError, Priority, self.env, 'major')
prio = Priority(self.env, 'minor')
self.assertEqual('3', prio.value)
@@ -806,8 +819,9 @@ class MilestoneTestCase(unittest.TestCas
def setUp(self):
self.env = EnvironmentStub(default_data=True)
- self.env.path = os.path.join(tempfile.gettempdir(), 'trac-tempenv')
- os.mkdir(self.env.path)
+ self.env.path = tempfile.mkdtemp(prefix='trac-tempenv-')
+ self.created_at = datetime(2001, 1, 1, tzinfo=utc)
+ self.updated_at = self.created_at + timedelta(seconds=1)
def tearDown(self):
shutil.rmtree(self.env.path)
@@ -819,12 +833,25 @@ class MilestoneTestCase(unittest.TestCas
setattr(milestone, k, v)
return milestone
+ def _insert_ticket(self, when=None, **kwargs):
+ ticket = Ticket(self.env)
+ for name, value in kwargs.iteritems():
+ ticket[name] = value
+ ticket.insert(when or self.created_at)
+ return ticket
+
+ def _update_ticket(self, ticket, author=None, comment=None, when=None,
+ **kwargs):
+ for name, value in kwargs.iteritems():
+ ticket[name] = value
+ ticket.save_changes(author, comment, when or self.updated_at)
+
def test_new_milestone(self):
milestone = Milestone(self.env)
- self.assertEqual(False, milestone.exists)
- self.assertEqual(None, milestone.name)
- self.assertEqual(None, milestone.due)
- self.assertEqual(None, milestone.completed)
+ self.assertFalse(milestone.exists)
+ self.assertIsNone(milestone.name)
+ self.assertIsNone(milestone.due)
+ self.assertIsNone(milestone.completed)
self.assertEqual('', milestone.description)
def test_new_milestone_empty_name(self):
@@ -833,20 +860,20 @@ class MilestoneTestCase(unittest.TestCas
milestone being correctly detected as non-existent.
"""
milestone = Milestone(self.env, '')
- self.assertEqual(False, milestone.exists)
- self.assertEqual(None, milestone.name)
- self.assertEqual(None, milestone.due)
- self.assertEqual(None, milestone.completed)
+ self.assertFalse(milestone.exists)
+ self.assertIsNone(milestone.name)
+ self.assertIsNone(milestone.due)
+ self.assertIsNone(milestone.completed)
self.assertEqual('', milestone.description)
def test_existing_milestone(self):
self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
milestone = Milestone(self.env, 'Test')
- self.assertEqual(True, milestone.exists)
+ self.assertTrue(milestone.exists)
self.assertEqual('Test', milestone.name)
- self.assertEqual(None, milestone.due)
- self.assertEqual(None, milestone.completed)
+ self.assertIsNone(milestone.due)
+ self.assertIsNone(milestone.completed)
self.assertEqual('', milestone.description)
def test_create_and_update_milestone(self):
@@ -867,35 +894,105 @@ class MilestoneTestCase(unittest.TestCas
WHERE name='Test'
"""))
+ def test_move_tickets(self):
+ self.env.db_transaction.executemany(
+ "INSERT INTO milestone (name) VALUES (%s)",
+ [('Test',), ('Testing',)])
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ self._update_ticket(tkt2, status='closed', resolution='fixed')
+ milestone = Milestone(self.env, 'Test')
+ milestone.move_tickets('Testing', 'anonymous', 'Move tickets')
+
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('Testing', tkt1['milestone'])
+ self.assertEqual('Testing', tkt2['milestone'])
+ self.assertEqual(tkt1['changetime'], tkt2['changetime'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
+
+ def test_move_tickets_exclude_closed(self):
+ self.env.db_transaction.executemany(
+ "INSERT INTO milestone (name) VALUES (%s)",
+ [('Test',), ('Testing',)])
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ self._update_ticket(tkt2, status='closed', resolution='fixed')
+ milestone = Milestone(self.env, 'Test')
+ milestone.move_tickets('Testing', 'anonymous', 'Move tickets',
+ exclude_closed=True)
+
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('Testing', tkt1['milestone'])
+ self.assertEqual('Test', tkt2['milestone'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
+ self.assertEqual(self.updated_at, tkt2['changetime'])
+
+ def test_move_tickets_target_doesnt_exist(self):
+ self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ milestone = Milestone(self.env, 'Test')
+ self.assertRaises(ResourceNotFound, milestone.move_tickets,
+ 'Testing', 'anonymous')
+
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('Test', tkt1['milestone'])
+ self.assertEqual('Test', tkt2['milestone'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
+ self.assertNotEqual(self.updated_at, tkt2['changetime'])
+
def test_create_milestone_without_name(self):
milestone = Milestone(self.env)
self.assertRaises(TracError, milestone.insert)
def test_delete_milestone(self):
self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
-
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ self._update_ticket(tkt2, status='closed', resolution='fixed')
milestone = Milestone(self.env, 'Test')
milestone.delete()
- self.assertEqual(False, milestone.exists)
+ self.assertFalse(milestone.exists)
self.assertEqual([],
self.env.db_query("SELECT * FROM milestone WHERE name='Test'"))
- def test_delete_milestone_retarget_tickets(self):
- self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
-
- tkt1 = Ticket(self.env)
- tkt1.populate({'summary': 'Foo', 'milestone': 'Test'})
- tkt1.insert()
- tkt2 = Ticket(self.env)
- tkt2.populate({'summary': 'Bar', 'milestone': 'Test'})
- tkt2.insert()
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('', tkt1['milestone'])
+ self.assertEqual('', tkt2['milestone'])
+ self.assertEqual(tkt1['changetime'], tkt2['changetime'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
+ def test_delete_milestone_retarget_tickets(self):
+ self.env.db_transaction.executemany(
+ "INSERT INTO milestone (name) VALUES (%s)",
+ [('Test',), ('Other',)])
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ self._update_ticket(tkt2, status='closed', resolution='fixed')
milestone = Milestone(self.env, 'Test')
milestone.delete(retarget_to='Other')
- self.assertEqual(False, milestone.exists)
+ self.assertFalse(milestone.exists)
- self.assertEqual('Other', Ticket(self.env, tkt1.id)['milestone'])
- self.assertEqual('Other', Ticket(self.env, tkt2.id)['milestone'])
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('Other', tkt1['milestone'])
+ self.assertEqual('Other', tkt2['milestone'])
+ self.assertEqual(tkt1['changetime'], tkt2['changetime'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
def test_update_milestone(self):
self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
@@ -919,23 +1016,6 @@ class MilestoneTestCase(unittest.TestCas
milestone.name = None
self.assertRaises(TracError, milestone.update)
- def test_update_milestone_update_tickets(self):
- self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
-
- tkt1 = Ticket(self.env)
- tkt1.populate({'summary': 'Foo', 'milestone': 'Test'})
- tkt1.insert()
- tkt2 = Ticket(self.env)
- tkt2.populate({'summary': 'Bar', 'milestone': 'Test'})
- tkt2.insert()
-
- milestone = Milestone(self.env, 'Test')
- milestone.name = 'Testing'
- milestone.update()
-
- self.assertEqual('Testing', Ticket(self.env, tkt1.id)['milestone'])
- self.assertEqual('Testing', Ticket(self.env, tkt2.id)['milestone'])
-
def test_rename_milestone(self):
milestone = Milestone(self.env)
milestone.name = 'OldName'
@@ -957,6 +1037,24 @@ class MilestoneTestCase(unittest.TestCas
self.assertEqual('foo.txt', attachments.next().filename)
self.assertRaises(StopIteration, attachments.next)
+ def test_rename_milestone_retarget_tickets(self):
+ self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
+ tkt1 = self._insert_ticket(status='new', summary='Foo',
+ milestone='Test')
+ tkt2 = self._insert_ticket(status='new', summary='Bar',
+ milestone='Test')
+ self._update_ticket(tkt2, status='closed', resolution='fixed')
+ milestone = Milestone(self.env, 'Test')
+ milestone.name = 'Testing'
+ milestone.update()
+
+ tkt1 = Ticket(self.env, tkt1.id)
+ tkt2 = Ticket(self.env, tkt2.id)
+ self.assertEqual('Testing', tkt1['milestone'])
+ self.assertEqual('Testing', tkt2['milestone'])
+ self.assertEqual(tkt1['changetime'], tkt2['changetime'])
+ self.assertNotEqual(self.updated_at, tkt1['changetime'])
+
def test_select_milestones(self):
self.env.db_transaction.executemany(
"INSERT INTO milestone (name) VALUES (%s)",
@@ -964,9 +1062,9 @@ class MilestoneTestCase(unittest.TestCas
milestones = list(Milestone.select(self.env))
self.assertEqual('1.0', milestones[0].name)
- assert milestones[0].exists
+ self.assertTrue(milestones[0].exists)
self.assertEqual('2.0', milestones[1].name)
- assert milestones[1].exists
+ self.assertTrue(milestones[1].exists)
def test_change_listener_created(self):
listener = TestMilestoneChangeListener(self.env)
@@ -998,10 +1096,10 @@ class MilestoneTestCase(unittest.TestCas
listener = TestMilestoneChangeListener(self.env)
milestone = self._create_milestone(name='Milestone 1')
milestone.insert()
- self.assertEqual(True, milestone.exists)
+ self.assertTrue(milestone.exists)
milestone.delete()
self.assertEqual('Milestone 1', milestone.name)
- self.assertEqual(False, milestone.exists)
+ self.assertFalse(milestone.exists)
self.assertEqual('deleted', listener.action)
self.assertEqual(milestone, listener.milestone)
@@ -1078,13 +1176,13 @@ class VersionTestCase(unittest.TestCase)
def suite():
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(TicketTestCase, 'test'))
- suite.addTest(unittest.makeSuite(TicketCommentEditTestCase, 'test'))
- suite.addTest(unittest.makeSuite(TicketCommentDeleteTestCase, 'test'))
- suite.addTest(unittest.makeSuite(EnumTestCase, 'test'))
- suite.addTest(unittest.makeSuite(MilestoneTestCase, 'test'))
- suite.addTest(unittest.makeSuite(ComponentTestCase, 'test'))
- suite.addTest(unittest.makeSuite(VersionTestCase, 'test'))
+ suite.addTest(unittest.makeSuite(TicketTestCase))
+ suite.addTest(unittest.makeSuite(TicketCommentEditTestCase))
+ suite.addTest(unittest.makeSuite(TicketCommentDeleteTestCase))
+ suite.addTest(unittest.makeSuite(EnumTestCase))
+ suite.addTest(unittest.makeSuite(MilestoneTestCase))
+ suite.addTest(unittest.makeSuite(ComponentTestCase))
+ suite.addTest(unittest.makeSuite(VersionTestCase))
return suite
if __name__ == '__main__':