class ConnectionTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def tearDown(self): self.env.reset_db() def test_get_last_id(self): id1 = id2 = None q = "INSERT INTO report (author) VALUES ('anonymous')" with self.env.db_transaction as db: cursor = db.cursor() cursor.execute(q) # Row ID correct before... id1 = db.get_last_id(cursor, 'report') self.assertNotEqual(0, id1) db.commit() cursor.execute(q) # ... and after commit() db.commit() id2 = db.get_last_id(cursor, 'report') self.assertEqual(id1 + 1, id2) def test_update_sequence(self): self.env.db_transaction( "INSERT INTO report (id, author) VALUES (42, 'anonymous')") with self.env.db_transaction as db: cursor = db.cursor() db.update_sequence(cursor, 'report', 'id') self.env.db_transaction( "INSERT INTO report (author) VALUES ('next-id')") self.assertEqual(43, self.env.db_query( "SELECT id FROM report WHERE author='next-id'")[0][0])
class SubscriberTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub( enable=['trac.*', 'announcer.opt.subscribers.*']) self.env.path = tempfile.mkdtemp() self.db_mgr = DatabaseManager(self.env) AnnouncementSystem(self.env).upgrade_environment() def tearDown(self): self.env.db_transaction("DROP table 'subscription'") self.env.db_transaction("DROP table 'subscription_attribute'") self.env.shutdown() shutil.rmtree(self.env.path)
class TagRPCTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock(authname='editor') # Mock an anonymous request. self.req.perm = PermissionCache(self.env) def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): with self.env.db_transaction as db: db("DROP TABLE IF EXISTS tags") db("DROP TABLE IF EXISTS tags_change") db("DELETE FROM system WHERE name='tags_version'") db("DELETE FROM permission WHERE action %s" % db.like(), ('TAGS_%',)) # Tests def test_init(self): TagRPC(self.env)
class StringsTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def test_insert_unicode(self): self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-unicode', u'ünicöde')) self.assertEqual([(u'ünicöde',)], self.env.db_query( "SELECT value FROM system WHERE name='test-unicode'")) def test_insert_empty(self): from trac.util.text import empty self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-empty', empty)) self.assertEqual([(u'',)], self.env.db_query( "SELECT value FROM system WHERE name='test-empty'")) def test_insert_markup(self): from genshi.core import Markup self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-markup', Markup(u'<em>märkup</em>'))) self.assertEqual([(u'<em>märkup</em>',)], self.env.db_query( "SELECT value FROM system WHERE name='test-markup'")) def test_quote(self): db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute('SELECT 1 AS %s' % \ db.quote(r'alpha\`\"\'\\beta``gamma""delta')) self.assertEqual(r'alpha\`\"\'\\beta``gamma""delta', get_column_names(cursor)[0])
class StringsTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def tearDown(self): self.env.reset_db() def test_insert_unicode(self): self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-unicode', u'ünicöde')) self.assertEqual([(u'ünicöde',)], self.env.db_query( "SELECT value FROM system WHERE name='test-unicode'")) def test_insert_empty(self): from trac.util.text import empty self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-empty', empty)) self.assertEqual([(u'',)], self.env.db_query( "SELECT value FROM system WHERE name='test-empty'")) def test_insert_markup(self): from genshi.core import Markup self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-markup', Markup(u'<em>märkup</em>'))) self.assertEqual([(u'<em>märkup</em>',)], self.env.db_query( "SELECT value FROM system WHERE name='test-markup'")) def test_quote(self): with self.env.db_query as db: cursor = db.cursor() cursor.execute('SELECT 1 AS %s' % \ db.quote(r'alpha\`\"\'\\beta``gamma""delta')) self.assertEqual(r'alpha\`\"\'\\beta``gamma""delta', get_column_names(cursor)[0]) def test_quoted_id_with_percent(self): name = """%?`%s"%'%%""" def test(logging=False): with self.env.db_query as db: cursor = db.cursor() if logging: cursor.log = self.env.log cursor.execute('SELECT 1 AS ' + db.quote(name)) self.assertEqual(name, get_column_names(cursor)[0]) cursor.execute('SELECT %s AS ' + db.quote(name), (42,)) self.assertEqual(name, get_column_names(cursor)[0]) cursor.executemany("UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", []) cursor.executemany("UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", [('42',), ('43',)]) test() test(True) def test_prefix_match_case_sensitive(self): with self.env.db_transaction as db: db.executemany("INSERT INTO system (name,value) VALUES (%s,1)", [('blahblah',), ('BlahBlah',), ('BLAHBLAH',), (u'BlähBlah',), (u'BlahBläh',)]) with self.env.db_query as db: names = sorted(name for name, in db( "SELECT name FROM system WHERE name %s" % db.prefix_match(), (db.prefix_match_value('Blah'),))) self.assertEqual('BlahBlah', names[0]) self.assertEqual(u'BlahBläh', names[1]) self.assertEqual(2, len(names)) def test_prefix_match_metachars(self): def do_query(prefix): with self.env.db_query as db: return [name for name, in db( "SELECT name FROM system WHERE name %s " "ORDER BY name" % db.prefix_match(), (db.prefix_match_value(prefix),))] values = ['foo*bar', 'foo*bar!', 'foo?bar', 'foo?bar!', 'foo[bar', 'foo[bar!', 'foo]bar', 'foo]bar!', 'foo%bar', 'foo%bar!', 'foo_bar', 'foo_bar!', 'foo/bar', 'foo/bar!', 'fo*ob?ar[fo]ob%ar_fo/obar'] with self.env.db_transaction as db: db.executemany("INSERT INTO system (name,value) VALUES (%s,1)", [(value,) for value in values]) self.assertEqual(['foo*bar', 'foo*bar!'], do_query('foo*')) self.assertEqual(['foo?bar', 'foo?bar!'], do_query('foo?')) self.assertEqual(['foo[bar', 'foo[bar!'], do_query('foo[')) self.assertEqual(['foo]bar', 'foo]bar!'], do_query('foo]')) self.assertEqual(['foo%bar', 'foo%bar!'], do_query('foo%')) self.assertEqual(['foo_bar', 'foo_bar!'], do_query('foo_')) self.assertEqual(['foo/bar', 'foo/bar!'], do_query('foo/')) self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'], do_query('fo*')) self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'], do_query('fo*ob?ar[fo]ob%ar_fo/obar'))
class TicketTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('ticket-custom', 'foo', 'text') self.env.config.set('ticket-custom', 'cbon', 'checkbox') self.env.config.set('ticket-custom', 'cboff', 'checkbox') def tearDown(self): self.env.reset_db() def _insert_ticket(self, summary, **kw): """Helper for inserting a ticket into the database""" ticket = Ticket(self.env) for k, v in kw.items(): ticket[k] = v return ticket.insert() def _create_a_ticket(self): # 1. Creating ticket ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['foo'] = 'This is a custom field' return ticket def test_invalid_ticket_id(self): self.assertEqual(Ticket.id_is_valid(-1), False) self.assertEqual(Ticket.id_is_valid(0), False) self.assertEqual(Ticket.id_is_valid(1), True) self.assertEqual(Ticket.id_is_valid(1L << 31), True) self.assertEqual(Ticket.id_is_valid(1L << 32), False) self.assertRaises(ResourceNotFound, Ticket, self.env, -1) self.assertRaises(ResourceNotFound, Ticket, self.env, 1L << 32) def test_create_ticket_1(self): ticket = self._create_a_ticket() self.assertEqual('santa', ticket['reporter']) self.assertEqual('Foo', ticket['summary']) self.assertEqual('This is a custom field', ticket['foo']) ticket.insert() def test_create_ticket_2(self): ticket = self._create_a_ticket() ticket.insert() self.assertEqual(1, ticket.id) # Retrieving ticket ticket2 = Ticket(self.env, 1) self.assertEqual(1, ticket2.id) self.assertEqual('santa', ticket2['reporter']) self.assertEqual('Foo', ticket2['summary']) self.assertEqual('This is a custom field', ticket2['foo']) def _modify_a_ticket(self): ticket2 = self._create_a_ticket() ticket2.insert() ticket2['summary'] = 'Bar' ticket2['foo'] = 'New value' ticket2.save_changes('santa', 'this is my comment') return ticket2 def test_create_ticket_3(self): self._modify_a_ticket() # Retrieving ticket ticket3 = Ticket(self.env, 1) self.assertEqual(1, ticket3.id) self.assertEqual(ticket3['reporter'], 'santa') self.assertEqual(ticket3['summary'], 'Bar') self.assertEqual(ticket3['foo'], 'New value') def test_create_ticket_4(self): ticket3 = self._modify_a_ticket() # Testing get_changelog() 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) def test_create_ticket_5(self): ticket3 = self._modify_a_ticket() # Testing delete() ticket3.delete() log = ticket3.get_changelog() self.assertEqual(len(log), 0) self.assertRaises(TracError, Ticket, self.env, 1) def test_ticket_id_is_always_int(self): ticket_id = self._insert_ticket('Foo') self.assertEqual(ticket_id, int(ticket_id)) ticket = Ticket(self.env, str(ticket_id)) self.assertEqual(ticket_id, ticket.id) self.assertEqual(ticket.resource.id, ticket_id) def test_can_save_ticket_without_explicit_comment(self): ticket = Ticket(self.env) ticket.insert() ticket['summary'] = 'another summary' ticket.save_changes('foo') changes = ticket.get_changelog() comment_change = [c for c in changes if c[2] == 'comment'][0] self.assertEqual('1', comment_change[3]) self.assertEqual('', comment_change[4]) def test_can_save_ticket_without_explicit_username(self): ticket = Ticket(self.env) ticket.insert() ticket['summary'] = 'another summary' ticket.save_changes() for change in ticket.get_changelog(): self.assertEqual(None, change[1]) def test_comment_with_whitespace_only_is_not_saved(self): ticket = Ticket(self.env) ticket.insert() ticket.save_changes(comment='\n \n ') self.assertEqual(0, len(ticket.get_changelog())) def test_prop_whitespace_change_is_not_saved(self): ticket = Ticket(self.env) ticket.populate({'summary': 'ticket summary'}) ticket.insert() ticket['summary'] = ' ticket summary ' ticket.save_changes() self.assertEqual(0, len(ticket.get_changelog())) def test_ticket_default_values(self): """ Verify that a ticket uses default values specified in the configuration when created. """ # Set defaults for some standard fields self.env.config.set('ticket', 'default_type', 'defect') self.env.config.set('ticket', 'default_component', 'component1') # Add a custom field of type 'text' with a default value self.env.config.set('ticket-custom', 'foo', 'text') self.env.config.set('ticket-custom', 'foo.value', 'Something') # Add a custom field of type 'select' with a default value specified as # the value itself self.env.config.set('ticket-custom', 'bar', 'select') self.env.config.set('ticket-custom', 'bar.options', 'one|two|three') self.env.config.set('ticket-custom', 'bar.value', 'two') # Add a custom field of type 'select' with a default value specified as # index into the options list self.env.config.set('ticket-custom', 'baz', 'select') self.env.config.set('ticket-custom', 'baz.options', 'one|two|three') self.env.config.set('ticket-custom', 'baz.value', '2') ticket = Ticket(self.env) self.assertEqual('defect', ticket['type']) self.assertEqual('component1', ticket['component']) self.assertEqual('Something', ticket['foo']) self.assertEqual('two', ticket['bar']) self.assertEqual('three', ticket['baz']) def test_set_field_stripped(self): """ Verify that whitespace around ticket fields is stripped, except for textarea fields. """ ticket = Ticket(self.env) ticket['component'] = ' foo ' ticket['description'] = ' bar ' self.assertEqual('foo', ticket['component']) self.assertEqual(' bar ', ticket['description']) def test_set_field_multi(self): """ Ticket fields can't yet be multi-valued """ ticket = Ticket(self.env) def set_multi_valued(): ticket['component'] = [' foo ', ' bar '] self.assertRaises(TracError, set_multi_valued) def test_owner_from_component(self): """ Verify that the owner of a new ticket is set to the owner of the component. """ component = Component(self.env) component.name = 'test' component.owner = 'joe' component.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test' ticket.insert() self.assertEqual('joe', ticket['owner']) def test_owner_from_changed_component(self): """ Verify that the owner of a new ticket is updated when the component is changed. """ component1 = Component(self.env) component1.name = 'test1' component1.owner = 'joe' component1.insert() component2 = Component(self.env) component2.name = 'test2' component2.owner = 'kate' component2.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test1' ticket['status'] = 'new' tktid = ticket.insert() ticket = Ticket(self.env, tktid) ticket['component'] = 'test2' ticket.save_changes('jane', 'Testing') self.assertEqual('kate', ticket['owner']) def test_no_disown_from_changed_component(self): """ Verify that a ticket is not disowned when the component is changed to a non-assigned component. """ component1 = Component(self.env) component1.name = 'test1' component1.owner = 'joe' component1.insert() component2 = Component(self.env) component2.name = 'test2' component2.owner = '' component2.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test1' ticket['status'] = 'new' tktid = ticket.insert() ticket = Ticket(self.env, tktid) ticket['component'] = 'test2' ticket.save_changes('jane', 'Testing') self.assertEqual('joe', ticket['owner']) def test_populate_ticket(self): data = {'summary': 'Hello world', 'reporter': 'john', 'foo': 'bar', 'checkbox_cbon': '', 'cbon': 'on', 'checkbox_cboff': ''} ticket = Ticket(self.env) ticket.populate(data) # Standard fields self.assertEqual('Hello world', ticket['summary']) self.assertEqual('john', ticket['reporter']) # An unknown field assert ticket['bar'] is None # Custom field self.assertEqual('bar', ticket['foo']) # Custom field of type 'checkbox' self.assertEqual('on', ticket['cbon']) self.assertEqual('0', ticket['cboff']) def test_changelog(self): tkt_id = self._insert_ticket('Test', reporter='joe', component='foo', milestone='bar') ticket = Ticket(self.env, tkt_id) ticket['component'] = 'bar' ticket['milestone'] = 'foo' now = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', now) changelog = sorted(ticket.get_changelog()) self.assertEqual([(now, 'jane', 'comment', '1', 'Testing', True), (now, 'jane', 'component', 'foo', 'bar', True), (now, 'jane', 'milestone', 'bar', 'foo', True)], changelog) def test_changelog_with_attachment(self): """Verify ordering of attachments and comments in the changelog.""" tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', t1) t2 = datetime(2001, 1, 1, 1, 1, 2, 0, utc) self.env.db_transaction(""" INSERT INTO attachment (type, id, filename, size, time, description, author, ipnr) VALUES ('ticket',%s,'file.txt',1234,%s, 'My file','mark','') """, (str(tkt_id), to_utimestamp(t2))) t3 = datetime(2001, 1, 1, 1, 1, 3, 0, utc) ticket.save_changes('jim', 'Other', t3) log = ticket.get_changelog() self.assertEqual(4, len(log)) self.assertEqual((t1, 'jane', 'comment', '1', 'Testing', True), log[0]) self.assertEqual([(t2, 'mark', 'attachment', '', 'file.txt', False), (t2, 'mark', 'comment', '', 'My file', False)], sorted(log[1:3])) self.assertEqual((t3, 'jim', 'comment', '2', 'Other', True), log[3]) def test_subsecond_change(self): """Perform two ticket changes within a second.""" tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) t1 = datetime(2001, 1, 1, 1, 1, 1, 123456, utc) ticket.save_changes('jane', 'Testing', t1) t2 = datetime(2001, 1, 1, 1, 1, 1, 123789, utc) ticket.save_changes('jim', 'Other', t2) log = ticket.get_changelog() self.assertEqual(2, len(log)) self.assertEqual((t1, 'jane', 'comment', '1', 'Testing', True), log[0]) self.assertEqual((t2, 'jim', 'comment', '2', 'Other', True), log[1]) def test_changelog_with_reverted_change(self): tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) ticket['component'] = 'bar' ticket['component'] = 'foo' now = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', now) self.assertEqual([(now, 'jane', 'comment', '1', 'Testing', True)], list(ticket.get_changelog())) def test_change_listener_created(self): listener = TestTicketChangeListener(self.env) ticket = self._create_a_ticket() ticket.insert() self.assertEqual('created', listener.action) self.assertEqual(ticket, listener.ticket) self.assertEqual(ticket.id, ticket.resource.id) def test_change_listener_changed(self): listener = TestTicketChangeListener(self.env) data = {'component': 'foo', 'milestone': 'bar'} tkt_id = self._insert_ticket('Hello World', reporter='john', **data) ticket = Ticket(self.env, tkt_id) ticket['component'] = 'new component' ticket['milestone'] = 'new milestone' comment = 'changing ticket' ticket.save_changes('author', comment) self.assertEqual('changed', listener.action) self.assertEqual(comment, listener.comment) self.assertEqual('author', listener.author) for key, value in data.iteritems(): self.assertEqual(value, listener.old_values[key]) def test_change_listener_deleted(self): listener = TestTicketChangeListener(self.env) ticket = self._create_a_ticket() ticket.insert() ticket.delete() self.assertEqual('deleted', listener.action) self.assertEqual(ticket, listener.ticket)
class TicketCommentDeleteTestCase(TicketCommentTestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('ticket-custom', 'foo', 'text') self.created = datetime(2001, 1, 1, 1, 0, 0, 0, utc) self._insert_ticket('Test ticket', self.created, owner='john', keywords='a, b, c', foo='initial') self.t1 = self.created + timedelta(seconds=1) self._modify_ticket('jack', 'Comment 1', self.t1, '1', foo='change 1') self.t2 = self.created + timedelta(seconds=2) self._modify_ticket('john', 'Comment 2', self.t2, '1.2', owner='jack', foo='change2') self.t3 = self.created + timedelta(seconds=3) self._modify_ticket('jim', 'Comment 3', self.t3, '3', keywords='a, b', foo='change3') self.t4 = self.created + timedelta(seconds=4) self._modify_ticket('joe', 'Comment 4', self.t4, '4', keywords='a', foo='change4') def tearDown(self): self.env.reset_db() def test_delete_last_comment(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) t = datetime.now(utc) 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.assertEqual(t, ticket.time_changed) def test_delete_last_comment_when_custom_field_gone(self): """Regression test for http://trac.edgewall.org/ticket/10858""" ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) # we simulate the removal of the definition of the 'foo' custom field self.env.config.remove('ticket-custom', 'foo') del TicketSystem(self.env).fields del TicketSystem(self.env).custom_fields ticket = Ticket(self.env, self.id) # t = datetime.now(utc) 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']) # 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.assertEqual(t, ticket.time_changed) def test_delete_last_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) t = datetime.now(utc) 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.assertEqual(t, ticket.time_changed) def test_delete_mid_comment(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(t, ticket.time_changed) def test_delete_mid_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(t, ticket.time_changed) def test_delete_mid_comment_inconsistent(self): # Make oldvalue on keywords for change 4 inconsistent. This should # result in no change in oldvalue when deleting change 3. The # oldvalue of foo should change normally. self.env.db_transaction(""" UPDATE ticket_change SET oldvalue='1, 2' WHERE field='keywords' AND oldvalue='a, b' """) ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='1, 2', new='a'), foo=dict(author='joe', old='change2', new='change4')) def test_delete_all_comments(self): ticket = Ticket(self.env, self.id) ticket.delete_change(4) ticket.delete_change(3) ticket.delete_change(2) t = datetime.now(utc) ticket.delete_change(1, when=t) self.assertEqual(t, ticket.time_changed)
class TicketTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('ticket-custom', 'foo', 'text') self.env.config.set('ticket-custom', 'cbon', 'checkbox') self.env.config.set('ticket-custom', 'cboff', 'checkbox') def tearDown(self): self.env.reset_db() def _insert_ticket(self, summary, **kw): """Helper for inserting a ticket into the database""" ticket = Ticket(self.env) for k, v in kw.items(): ticket[k] = v return ticket.insert() def _create_a_ticket(self): # 1. Creating ticket ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['foo'] = 'This is a custom field' return ticket def test_invalid_ticket_id(self): self.assertEqual(Ticket.id_is_valid(-1), False) self.assertEqual(Ticket.id_is_valid(0), False) self.assertEqual(Ticket.id_is_valid(1), True) self.assertEqual(Ticket.id_is_valid(1L << 31), True) self.assertEqual(Ticket.id_is_valid(1L << 32), False) self.assertRaises(ResourceNotFound, Ticket, self.env, -1) self.assertRaises(ResourceNotFound, Ticket, self.env, 1L << 32) def test_create_ticket_1(self): ticket = self._create_a_ticket() self.assertEqual('santa', ticket['reporter']) self.assertEqual('Foo', ticket['summary']) self.assertEqual('This is a custom field', ticket['foo']) ticket.insert() def test_create_ticket_2(self): ticket = self._create_a_ticket() ticket.insert() self.assertEqual(1, ticket.id) # Retrieving ticket ticket2 = Ticket(self.env, 1) self.assertEqual(1, ticket2.id) self.assertEqual('santa', ticket2['reporter']) self.assertEqual('Foo', ticket2['summary']) self.assertEqual('This is a custom field', ticket2['foo']) def _modify_a_ticket(self): ticket2 = self._create_a_ticket() ticket2.insert() ticket2['summary'] = 'Bar' ticket2['foo'] = 'New value' ticket2.save_changes('santa', 'this is my comment') return ticket2 def test_create_ticket_3(self): self._modify_a_ticket() # Retrieving ticket ticket3 = Ticket(self.env, 1) self.assertEqual(1, ticket3.id) self.assertEqual(ticket3['reporter'], 'santa') self.assertEqual(ticket3['summary'], 'Bar') self.assertEqual(ticket3['foo'], 'New value') def test_create_ticket_4(self): ticket3 = self._modify_a_ticket() # Testing get_changelog() 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) def test_create_ticket_5(self): ticket3 = self._modify_a_ticket() # Testing delete() ticket3.delete() log = ticket3.get_changelog() self.assertEqual(len(log), 0) self.assertRaises(TracError, Ticket, self.env, 1) def test_ticket_id_is_always_int(self): ticket_id = self._insert_ticket('Foo') self.assertEqual(ticket_id, int(ticket_id)) ticket = Ticket(self.env, str(ticket_id)) self.assertEqual(ticket_id, ticket.id) self.assertEqual(ticket.resource.id, ticket_id) def test_can_save_ticket_without_explicit_comment(self): ticket = Ticket(self.env) ticket.insert() ticket['summary'] = 'another summary' ticket.save_changes('foo') changes = ticket.get_changelog() comment_change = [c for c in changes if c[2] == 'comment'][0] self.assertEqual('1', comment_change[3]) self.assertEqual('', comment_change[4]) def test_can_save_ticket_without_explicit_username(self): ticket = Ticket(self.env) ticket.insert() ticket['summary'] = 'another summary' ticket.save_changes() for change in ticket.get_changelog(): self.assertEqual(None, change[1]) def test_comment_with_whitespace_only_is_not_saved(self): ticket = Ticket(self.env) ticket.insert() ticket.save_changes(comment='\n \n ') self.assertEqual(0, len(ticket.get_changelog())) def test_prop_whitespace_change_is_not_saved(self): ticket = Ticket(self.env) ticket.populate({'summary': 'ticket summary'}) ticket.insert() ticket['summary'] = ' ticket summary ' ticket.save_changes() self.assertEqual(0, len(ticket.get_changelog())) def test_ticket_default_values(self): """ Verify that a ticket uses default values specified in the configuration when created. """ # Set defaults for some standard fields self.env.config.set('ticket', 'default_type', 'defect') self.env.config.set('ticket', 'default_component', 'component1') # Add a custom field of type 'text' with a default value self.env.config.set('ticket-custom', 'foo', 'text') self.env.config.set('ticket-custom', 'foo.value', 'Something') # Add a custom field of type 'select' with a default value specified as # the value itself self.env.config.set('ticket-custom', 'bar', 'select') self.env.config.set('ticket-custom', 'bar.options', 'one|two|three') self.env.config.set('ticket-custom', 'bar.value', 'two') # Add a custom field of type 'select' with a default value specified as # index into the options list self.env.config.set('ticket-custom', 'baz', 'select') self.env.config.set('ticket-custom', 'baz.options', 'one|two|three') self.env.config.set('ticket-custom', 'baz.value', '2') ticket = Ticket(self.env) self.assertEqual('defect', ticket['type']) self.assertEqual('component1', ticket['component']) self.assertEqual('Something', ticket['foo']) self.assertEqual('two', ticket['bar']) self.assertEqual('three', ticket['baz']) def test_set_field_stripped(self): """ Verify that whitespace around ticket fields is stripped, except for textarea fields. """ ticket = Ticket(self.env) ticket['component'] = ' foo ' ticket['description'] = ' bar ' self.assertEqual('foo', ticket['component']) self.assertEqual(' bar ', ticket['description']) def test_set_field_multi(self): """ Ticket fields can't yet be multi-valued """ ticket = Ticket(self.env) def set_multi_valued(): ticket['component'] = [' foo ', ' bar '] self.assertRaises(TracError, set_multi_valued) def test_owner_from_component(self): """ Verify that the owner of a new ticket is set to the owner of the component. """ component = Component(self.env) component.name = 'test' component.owner = 'joe' component.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test' ticket.insert() self.assertEqual('joe', ticket['owner']) def test_owner_from_changed_component(self): """ Verify that the owner of a new ticket is updated when the component is changed. """ component1 = Component(self.env) component1.name = 'test1' component1.owner = 'joe' component1.insert() component2 = Component(self.env) component2.name = 'test2' component2.owner = 'kate' component2.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test1' ticket['status'] = 'new' tktid = ticket.insert() ticket = Ticket(self.env, tktid) ticket['component'] = 'test2' ticket.save_changes('jane', 'Testing') self.assertEqual('kate', ticket['owner']) def test_no_disown_from_changed_component(self): """ Verify that a ticket is not disowned when the component is changed to a non-assigned component. """ component1 = Component(self.env) component1.name = 'test1' component1.owner = 'joe' component1.insert() component2 = Component(self.env) component2.name = 'test2' component2.owner = '' component2.insert() ticket = Ticket(self.env) ticket['reporter'] = 'santa' ticket['summary'] = 'Foo' ticket['component'] = 'test1' ticket['status'] = 'new' tktid = ticket.insert() ticket = Ticket(self.env, tktid) ticket['component'] = 'test2' ticket.save_changes('jane', 'Testing') self.assertEqual('joe', ticket['owner']) def test_populate_ticket(self): data = {'summary': 'Hello world', 'reporter': 'john', 'foo': 'bar', 'checkbox_cbon': '', 'cbon': 'on', 'checkbox_cboff': ''} ticket = Ticket(self.env) ticket.populate(data) # Standard fields self.assertEqual('Hello world', ticket['summary']) self.assertEqual('john', ticket['reporter']) # An unknown field assert ticket['bar'] is None # Custom field self.assertEqual('bar', ticket['foo']) # Custom field of type 'checkbox' self.assertEqual('on', ticket['cbon']) self.assertEqual('0', ticket['cboff']) def test_custom_time(self): # Add a custom field of type 'time' self.env.config.set('ticket-custom', 'due', 'time') ticket = Ticket(self.env) self.assertFalse('due' in ticket.std_fields) self.assertTrue('due' in ticket.time_fields) ticket['reporter'] = 'john' ticket['summary'] = 'Task1' tktid = ticket.insert() ticket = Ticket(self.env, tktid) # Empty string is default value, but not a time stamp self.assertEqual(None, ticket['due']) ts = datetime(2011, 11, 11, 0, 0, 0, 0, utc) ticket['due'] = ts t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('joe', when=t1) self.assertEqual(ts, ticket['due']) ticket['due'] = '' t2 = datetime(2001, 1, 1, 1, 1, 2, 0, utc) ticket.save_changes('joe', when=t2) self.assertEqual('', ticket['due']) def test_changelog(self): tkt_id = self._insert_ticket('Test', reporter='joe', component='foo', milestone='bar') ticket = Ticket(self.env, tkt_id) ticket['component'] = 'bar' ticket['milestone'] = 'foo' now = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', now) changelog = sorted(ticket.get_changelog()) self.assertEqual([(now, 'jane', 'comment', '1', 'Testing', True), (now, 'jane', 'component', 'foo', 'bar', True), (now, 'jane', 'milestone', 'bar', 'foo', True)], changelog) def test_changelog_with_attachment(self): """Verify ordering of attachments and comments in the changelog.""" tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', t1) t2 = datetime(2001, 1, 1, 1, 1, 2, 0, utc) self.env.db_transaction(""" INSERT INTO attachment (type, id, filename, size, time, description, author, ipnr) VALUES ('ticket',%s,'file.txt',1234,%s, 'My file','mark','') """, (str(tkt_id), to_utimestamp(t2))) t3 = datetime(2001, 1, 1, 1, 1, 3, 0, utc) ticket.save_changes('jim', 'Other', t3) log = ticket.get_changelog() self.assertEqual(4, len(log)) self.assertEqual((t1, 'jane', 'comment', '1', 'Testing', True), log[0]) self.assertEqual([(t2, 'mark', 'attachment', '', 'file.txt', False), (t2, 'mark', 'comment', '', 'My file', False)], sorted(log[1:3])) self.assertEqual((t3, 'jim', 'comment', '2', 'Other', True), log[3]) def test_subsecond_change(self): """Perform two ticket changes within a second.""" tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) t1 = datetime(2001, 1, 1, 1, 1, 1, 123456, utc) ticket.save_changes('jane', 'Testing', t1) t2 = datetime(2001, 1, 1, 1, 1, 1, 123789, utc) ticket.save_changes('jim', 'Other', t2) log = ticket.get_changelog() self.assertEqual(2, len(log)) self.assertEqual((t1, 'jane', 'comment', '1', 'Testing', True), log[0]) self.assertEqual((t2, 'jim', 'comment', '2', 'Other', True), log[1]) def test_changelog_with_reverted_change(self): tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') ticket = Ticket(self.env, tkt_id) ticket['component'] = 'bar' ticket['component'] = 'foo' now = datetime(2001, 1, 1, 1, 1, 1, 0, utc) ticket.save_changes('jane', 'Testing', now) self.assertEqual([(now, 'jane', 'comment', '1', 'Testing', True)], list(ticket.get_changelog())) def test_change_listener_created(self): listener = TestTicketChangeListener(self.env) ticket = self._create_a_ticket() ticket.insert() self.assertEqual('created', listener.action) self.assertEqual(ticket, listener.ticket) self.assertEqual(ticket.id, ticket.resource.id) def test_change_listener_changed(self): listener = TestTicketChangeListener(self.env) data = {'component': 'foo', 'milestone': 'bar'} tkt_id = self._insert_ticket('Hello World', reporter='john', **data) ticket = Ticket(self.env, tkt_id) ticket['component'] = 'new component' ticket['milestone'] = 'new milestone' comment = 'changing ticket' ticket.save_changes('author', comment) self.assertEqual('changed', listener.action) self.assertEqual(comment, listener.comment) self.assertEqual('author', listener.author) for key, value in data.iteritems(): self.assertEqual(value, listener.old_values[key]) def test_change_listener_deleted(self): listener = TestTicketChangeListener(self.env) ticket = self._create_a_ticket() ticket.insert() ticket.delete() self.assertEqual('deleted', listener.action) self.assertEqual(ticket, listener.ticket)
class LoginModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.module = LoginModule(self.env) def tearDown(self): self.env.reset_db() def test_anonymous_access(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) def test_unknown_cookie_access(self): incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=Cookie(), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) def test_known_cookie_access(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(incookie=incookie, outcookie=outcookie, href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user=None) self.assertEqual('john', self.module.authenticate(req)) self.failIf('auth_cookie' in req.outcookie) def test_known_cookie_ip_check_enabled(self): self.env.config.set('trac', 'check_auth_ip', 'yes') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=outcookie, remote_addr='192.168.0.100', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) self.failIf('trac_auth' not in req.outcookie) def test_known_cookie_ip_check_disabled(self): self.env.config.set('trac', 'check_auth_ip', 'no') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(incookie=incookie, outcookie=outcookie, href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='192.168.0.100', remote_user=None) self.assertEqual('john', self.module.authenticate(req)) self.failIf('auth_cookie' in req.outcookie) def test_login(self): outcookie = Cookie() # remote_user must be upper case to test that by default, case is # preserved. req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=outcookie, remote_addr='127.0.0.1', remote_user='******', authname='john', base_path='/trac.cgi') self.module._do_login(req) assert outcookie.has_key('trac_auth'), '"trac_auth" Cookie not set' auth_cookie = outcookie['trac_auth'].value self.assertEquals([('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie,))) def test_login_ignore_case(self): """ Test that login is succesful when the usernames differ in case, but case is ignored. """ self.env.config.set('trac', 'ignore_auth_case', 'yes') outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=outcookie, remote_addr='127.0.0.1', remote_user='******', authname='anonymous', base_path='/trac.cgi') self.module._do_login(req) assert outcookie.has_key('trac_auth'), '"trac_auth" Cookie not set' auth_cookie = outcookie['trac_auth'].value self.assertEquals([('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie,))) def test_login_no_username(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertRaises(TracError, self.module._do_login, req) def test_already_logged_in_same_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(incookie=incookie, outcookie=Cookie(), href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user='******', authname='john') self.module._do_login(req) # this shouldn't raise an error def test_already_logged_in_different_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(incookie=incookie, authname='john', href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user='******') self.assertRaises(AssertionError, self.module._do_login, req) def test_logout(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=outcookie, remote_addr='127.0.0.1', remote_user=None, authname='john', base_path='/trac.cgi') self.module._do_logout(req) self.failIf('trac_auth' not in outcookie) self.failIf(self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE name='john'")) def test_logout_not_logged_in(self): req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=Cookie(), remote_addr='127.0.0.1', remote_user=None, authname='anonymous', base_path='/trac.cgi') self.module._do_logout(req) # this shouldn't raise an error
class StringsTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def tearDown(self): self.env.reset_db() def test_insert_unicode(self): self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-unicode', u'ünicöde')) self.assertEqual( [(u'ünicöde', )], self.env.db_query( "SELECT value FROM system WHERE name='test-unicode'")) def test_insert_empty(self): from trac.util.text import empty self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-empty', empty)) self.assertEqual( [(u'', )], self.env.db_query( "SELECT value FROM system WHERE name='test-empty'")) def test_insert_markup(self): from trac.util.html import Markup self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-markup', Markup(u'<em>märkup</em>'))) self.assertEqual( [(u'<em>märkup</em>', )], self.env.db_query( "SELECT value FROM system WHERE name='test-markup'")) def test_quote(self): with self.env.db_query as db: cursor = db.cursor() cursor.execute('SELECT 1 AS %s' % \ db.quote(r'alpha\`\"\'\\beta``gamma""delta')) self.assertEqual(r'alpha\`\"\'\\beta``gamma""delta', get_column_names(cursor)[0]) def test_quoted_id_with_percent(self): name = """%?`%s"%'%%""" def test(logging=False): with self.env.db_query as db: cursor = db.cursor() if logging: cursor.log = self.env.log cursor.execute('SELECT 1 AS ' + db.quote(name)) self.assertEqual(name, get_column_names(cursor)[0]) cursor.execute('SELECT %s AS ' + db.quote(name), (42, )) self.assertEqual(name, get_column_names(cursor)[0]) cursor.executemany( "UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", []) cursor.executemany( "UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", [('42', ), ('43', )]) test() test(True) def test_prefix_match_case_sensitive(self): with self.env.db_transaction as db: db.executemany("INSERT INTO system (name,value) VALUES (%s,1)", [('blahblah', ), ('BlahBlah', ), ('BLAHBLAH', ), (u'BlähBlah', ), (u'BlahBläh', )]) with self.env.db_query as db: names = sorted(name for name, in db( "SELECT name FROM system WHERE name %s" % db.prefix_match(), (db.prefix_match_value('Blah'), ))) self.assertEqual('BlahBlah', names[0]) self.assertEqual(u'BlahBläh', names[1]) self.assertEqual(2, len(names)) def test_prefix_match_metachars(self): def do_query(prefix): with self.env.db_query as db: return [ name for name, in db( "SELECT name FROM system WHERE name %s " "ORDER BY name" % db.prefix_match(), (db.prefix_match_value(prefix), )) ] values = [ 'foo*bar', 'foo*bar!', 'foo?bar', 'foo?bar!', 'foo[bar', 'foo[bar!', 'foo]bar', 'foo]bar!', 'foo%bar', 'foo%bar!', 'foo_bar', 'foo_bar!', 'foo/bar', 'foo/bar!', 'fo*ob?ar[fo]ob%ar_fo/obar' ] with self.env.db_transaction as db: db.executemany("INSERT INTO system (name,value) VALUES (%s,1)", [(value, ) for value in values]) self.assertEqual(['foo*bar', 'foo*bar!'], do_query('foo*')) self.assertEqual(['foo?bar', 'foo?bar!'], do_query('foo?')) self.assertEqual(['foo[bar', 'foo[bar!'], do_query('foo[')) self.assertEqual(['foo]bar', 'foo]bar!'], do_query('foo]')) self.assertEqual(['foo%bar', 'foo%bar!'], do_query('foo%')) self.assertEqual(['foo_bar', 'foo_bar!'], do_query('foo_')) self.assertEqual(['foo/bar', 'foo/bar!'], do_query('foo/')) self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'], do_query('fo*')) self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'], do_query('fo*ob?ar[fo]ob%ar_fo/obar'))
class EnvironmentUpgradeTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def tearDown(self): self.env.reset_db() def test_multiple_upgrade_participants(self): class Participant1(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self): return True def upgrade_environment(self): insert_value('value1', 1) class Participant2(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self): return True def upgrade_environment(self): insert_value('value2', 2) def insert_value(name, value): self.env.db_transaction( """ INSERT INTO system (name, value) VALUES (%s, %s) """, (name, value)) def select_value(name): for value, in self.env.db_query( """ SELECT value FROM system WHERE name=%s """, (name, )): return value self.env.enable_component(Participant1) self.env.enable_component(Participant2) self.assertTrue(self.env.needs_upgrade()) self.assertTrue(self.env.upgrade()) self.assertEqual('1', select_value('value1')) self.assertEqual('2', select_value('value2')) def test_upgrade_environment(self): """EnvironmentSetupParticipants are called only if environment_needs_upgrade returns True for the participant. """ class SetupParticipantA(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return True def upgrade_environment(self): self.called = True class SetupParticipantB(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return False def upgrade_environment(self): self.called = True self.env.enable_component(SetupParticipantA) self.env.enable_component(SetupParticipantB) participant_a = SetupParticipantA(self.env) participant_b = SetupParticipantB(self.env) self.assertTrue(self.env.needs_upgrade()) self.env.upgrade() self.assertTrue(participant_a.called) self.assertFalse(participant_b.called)
class _BaseTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(enable=['trac.*', 'acct_mgr.*']) self.env.config.set('account-manager', 'password_store', 'SessionStore') self.store = SessionStore(self.env) def test_get_users(self): with self.env.db_transaction as db: db.executemany( """ INSERT INTO session_attribute (sid,authenticated,name,value) VALUES (%s,1,'password',%s) """, [('a', 'a'), ('b', 'b'), ('c', 'c')]) self.assertEqual(set(['a', 'b', 'c']), set(self.store.get_users())) def test_has_user(self): self.env.db_transaction( """ INSERT INTO session_attribute (sid,authenticated,name,value) VALUES (%s,'1','password',%s) """, ('bar', 'bar')) self.assertFalse(self.store.has_user('foo')) self.assertTrue(self.store.has_user('bar')) def test_create_user(self): self.assertFalse(self.store.has_user('foo')) self.store.set_password('foo', 'password') self.assertTrue(self.store.has_user('foo')) def test_overwrite(self): self.assertTrue(self.store.set_password('foo', 'pass1')) self.assertFalse( self.store.set_password('foo', 'pass2', overwrite=False)) self.assertTrue(self.store.check_password('foo', 'pass1')) self.assertTrue(self.store.set_password('bar', 'pass', overwrite=False)) def test_update_password(self): self.store.set_password('foo', 'pass1') self.assertFalse(self.store.check_password('foo', 'pass2')) self.store.set_password('foo', 'pass2') self.assertTrue(self.store.check_password('foo', 'pass2')) self.store.set_password('foo', 'pass3', 'pass2') self.assertTrue(self.store.check_password('foo', 'pass3')) def test_delete_user(self): self.store.set_password('foo', 'password') self.assertTrue(self.store.has_user('foo')) self.assertTrue(self.store.delete_user('foo')) self.assertFalse(self.store.has_user('foo')) def test_delete_nonexistant_user(self): self.assertFalse(self.store.has_user('foo')) self.assertFalse(self.store.delete_user('foo')) def test_unicode_username_and_password(self): username = u'\u4e60' password = u'\u4e61' self.store.set_password(username, password) self.assertTrue(self.store.check_password(username, password))
class ConnectionTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.schema = [ Table('HOURS', key='ID')[ Column('ID', auto_increment=True), Column('AUTHOR')], Table('blog', key='bid')[ Column('bid', auto_increment=True), Column('author') ] ] self.env.global_databasemanager.drop_tables(self.schema) self.env.global_databasemanager.create_tables(self.schema) def tearDown(self): self.env.global_databasemanager.drop_tables(self.schema) self.env.reset_db() def test_get_last_id(self): q = "INSERT INTO report (author) VALUES ('anonymous')" with self.env.db_transaction as db: cursor = db.cursor() cursor.execute(q) # Row ID correct before... id1 = db.get_last_id(cursor, 'report') db.commit() cursor.execute(q) # ... and after commit() db.commit() id2 = db.get_last_id(cursor, 'report') self.assertNotEqual(0, id1) self.assertEqual(id1 + 1, id2) def test_update_sequence_default_column(self): with self.env.db_transaction as db: db("INSERT INTO report (id, author) VALUES (42, 'anonymous')") cursor = db.cursor() db.update_sequence(cursor, 'report', 'id') self.env.db_transaction( "INSERT INTO report (author) VALUES ('next-id')") self.assertEqual(43, self.env.db_query( "SELECT id FROM report WHERE author='next-id'")[0][0]) def test_update_sequence_nondefault_column(self): with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO blog (bid, author) VALUES (42, 'anonymous')") db.update_sequence(cursor, 'blog', 'bid') self.env.db_transaction( "INSERT INTO blog (author) VALUES ('next-id')") self.assertEqual(43, self.env.db_query( "SELECT bid FROM blog WHERE author='next-id'")[0][0]) def test_identifiers_need_quoting(self): """Test for regression described in comment:4:ticket:11512.""" with self.env.db_transaction as db: db("INSERT INTO %s (%s, %s) VALUES (42, 'anonymous')" % (db.quote('HOURS'), db.quote('ID'), db.quote('AUTHOR'))) cursor = db.cursor() db.update_sequence(cursor, 'HOURS', 'ID') with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO %s (%s) VALUES ('next-id')" % (db.quote('HOURS'), db.quote('AUTHOR'))) last_id = db.get_last_id(cursor, 'HOURS', 'ID') self.assertEqual(43, last_id) def test_table_names(self): schema = default_schema + self.schema with self.env.db_query as db: db_tables = db.get_table_names() self.assertEqual(len(schema), len(db_tables)) for table in schema: self.assertIn(table.name, db_tables) def test_get_column_names(self): schema = default_schema + self.schema with self.env.db_transaction as db: for table in schema: db_columns = db.get_column_names(table.name) self.assertEqual(len(table.columns), len(db_columns)) for column in table.columns: self.assertIn(column.name, db_columns)
class StringsTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() def tearDown(self): self.env.reset_db() def test_insert_unicode(self): self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-unicode', u'ünicöde')) self.assertEqual([(u'ünicöde',)], self.env.db_query( "SELECT value FROM system WHERE name='test-unicode'")) def test_insert_empty(self): from trac.util.text import empty self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-empty', empty)) self.assertEqual([(u'',)], self.env.db_query( "SELECT value FROM system WHERE name='test-empty'")) def test_insert_markup(self): from genshi.core import Markup self.env.db_transaction( "INSERT INTO system (name,value) VALUES (%s,%s)", ('test-markup', Markup(u'<em>märkup</em>'))) self.assertEqual([(u'<em>märkup</em>',)], self.env.db_query( "SELECT value FROM system WHERE name='test-markup'")) def test_quote(self): db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute('SELECT 1 AS %s' % \ db.quote(r'alpha\`\"\'\\beta``gamma""delta')) self.assertEqual(r'alpha\`\"\'\\beta``gamma""delta', get_column_names(cursor)[0]) def test_quoted_id_with_percent(self): db = self.env.get_read_db() name = """%?`%s"%'%%""" def test(db, logging=False): cursor = db.cursor() if logging: cursor.log = self.env.log cursor.execute('SELECT 1 AS ' + db.quote(name)) self.assertEqual(name, get_column_names(cursor)[0]) cursor.execute('SELECT %s AS ' + db.quote(name), (42,)) self.assertEqual(name, get_column_names(cursor)[0]) cursor.executemany("UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", []) cursor.executemany("UPDATE system SET value=%s WHERE " "1=(SELECT 0 AS " + db.quote(name) + ")", [('42',), ('43',)]) test(db) test(db, logging=True)
class MilestoneTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') os.mkdir(self.env.path) def tearDown(self): shutil.rmtree(self.env.path) self.env.reset_db() def _create_milestone(self, **values): milestone = Milestone(self.env) for k, v in values.iteritems(): setattr(milestone, k, v) return milestone 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.assertEqual('', milestone.description) def test_new_milestone_empty_name(self): """ Verifies that specifying an empty milestone name results in the 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.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.assertEqual('Test', milestone.name) self.assertEqual(None, milestone.due) self.assertEqual(None, milestone.completed) self.assertEqual('', milestone.description) def test_create_and_update_milestone(self): milestone = Milestone(self.env) milestone.name = 'Test' milestone.insert() self.assertEqual([('Test', 0, 0, '')], self.env.db_query(""" SELECT name, due, completed, description FROM milestone WHERE name='Test' """)) # Use the same model object to update the milestone milestone.description = 'Some text' milestone.update() self.assertEqual([('Test', 0, 0, 'Some text')], self.env.db_query(""" SELECT name, due, completed, description FROM milestone WHERE name='Test' """)) 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')") milestone = Milestone(self.env, 'Test') milestone.delete() self.assertEqual(False, 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() milestone = Milestone(self.env, 'Test') milestone.delete(retarget_to='Other') self.assertEqual(False, milestone.exists) self.assertEqual('Other', Ticket(self.env, tkt1.id)['milestone']) self.assertEqual('Other', Ticket(self.env, tkt2.id)['milestone']) def test_update_milestone(self): self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')") milestone = Milestone(self.env, 'Test') t1 = datetime(2001, 01, 01, tzinfo=utc) t2 = datetime(2002, 02, 02, tzinfo=utc) milestone.due = t1 milestone.completed = t2 milestone.description = 'Foo bar' milestone.update() self.assertEqual( [('Test', to_utimestamp(t1), to_utimestamp(t2), 'Foo bar')], self.env.db_query("SELECT * FROM milestone WHERE name='Test'")) def test_update_milestone_without_name(self): self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')") milestone = Milestone(self.env, 'Test') 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' milestone.insert() attachment = Attachment(self.env, 'milestone', 'OldName') attachment.insert('foo.txt', StringIO(), 0, 1) milestone = Milestone(self.env, 'OldName') milestone.name = 'NewName' milestone.update() self.assertRaises(ResourceNotFound, Milestone, self.env, 'OldName') self.assertEqual('NewName', Milestone(self.env, 'NewName').name) attachments = Attachment.select(self.env, 'milestone', 'OldName') self.assertRaises(StopIteration, attachments.next) attachments = Attachment.select(self.env, 'milestone', 'NewName') self.assertEqual('foo.txt', attachments.next().filename) self.assertRaises(StopIteration, attachments.next) def test_select_milestones(self): self.env.db_transaction.executemany( "INSERT INTO milestone (name) VALUES (%s)", [('1.0',), ('2.0',)]) milestones = list(Milestone.select(self.env)) self.assertEqual('1.0', milestones[0].name) assert milestones[0].exists self.assertEqual('2.0', milestones[1].name) assert milestones[1].exists def test_change_listener_created(self): listener = TestMilestoneChangeListener(self.env) milestone = self._create_milestone(name='Milestone 1') milestone.insert() self.assertEqual('created', listener.action) self.assertEqual(milestone, listener.milestone) def test_change_listener_changed(self): listener = TestMilestoneChangeListener(self.env) milestone = self._create_milestone( name='Milestone 1', due=datetime(2001, 01, 01, tzinfo=utc), description='The milestone description') milestone.insert() milestone.name = 'Milestone 2' milestone.completed = datetime(2001, 02, 03, tzinfo=utc) milestone.description = 'The changed description' milestone.update() self.assertEqual('changed', listener.action) self.assertEqual(milestone, listener.milestone) self.assertEqual({'name': 'Milestone 1', 'completed': None, 'description': 'The milestone description'}, listener.old_values) def test_change_listener_deleted(self): listener = TestMilestoneChangeListener(self.env) milestone = self._create_milestone(name='Milestone 1') milestone.insert() self.assertEqual(True, milestone.exists) milestone.delete() self.assertEqual('Milestone 1', milestone.name) self.assertEqual(False, milestone.exists) self.assertEqual('deleted', listener.action) self.assertEqual(milestone, listener.milestone)
class TicketCommentDeleteTestCase(TicketCommentTestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('ticket-custom', 'foo', 'text') self.created = datetime(2001, 1, 1, 1, 0, 0, 0, utc) self._insert_ticket('Test ticket', self.created, owner='john', keywords='a, b, c', foo='initial') self.t1 = self.created + timedelta(seconds=1) self._modify_ticket('jack', 'Comment 1', self.t1, '1', foo='change 1') self.t2 = self.created + timedelta(seconds=2) self._modify_ticket('john', 'Comment 2', self.t2, '1.2', owner='jack', foo='change2') self.t3 = self.created + timedelta(seconds=3) self._modify_ticket('jim', 'Comment 3', self.t3, '3', keywords='a, b', foo='change3') self.t4 = self.created + timedelta(seconds=4) self._modify_ticket('joe', 'Comment 4', self.t4, '4', keywords='a', foo='change4') def tearDown(self): self.env.reset_db() def test_delete_last_comment(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) ticket.delete_change(cnum=4) 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.assertEqual(self.t3, ticket.time_changed) def test_delete_last_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) ticket.delete_change(cdate=self.t4) 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.assertEqual(self.t3, ticket.time_changed) def test_delete_mid_comment(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), foo=dict(author='joe', old='change3', new='change4')) ticket.delete_change(cnum=3) self.assertEqual(None, 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'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(self.t4, ticket.time_changed) def test_delete_mid_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), foo=dict(author='joe', old='change3', new='change4')) ticket.delete_change(cdate=self.t3) self.assertEqual(None, 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'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(self.t4, ticket.time_changed) def test_delete_mid_comment_inconsistent(self): # Make oldvalue on keywords for change 4 inconsistent. This should # result in no change in oldvalue when deleting change 3. The # oldvalue of foo should change normally. self.env.db_transaction(""" UPDATE ticket_change SET oldvalue='1, 2' WHERE field='keywords' AND oldvalue='a, b' """) ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='1, 2', new='a'), foo=dict(author='joe', old='change2', new='change4')) def test_delete_all_comments(self): # See ticket:10338 ticket = Ticket(self.env, self.id) ticket.delete_change(4) ticket.delete_change(3) ticket.delete_change(2) ticket.delete_change(1) self.assertEquals(ticket['time'], ticket['changetime'])
class TicketCommentEditTestCase(TicketCommentTestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.created = datetime(2001, 1, 1, 1, 0, 0, 0, utc) self._insert_ticket('Test ticket', self.created, owner='john', keywords='a, b, c') self.t1 = self.created + timedelta(seconds=1) self._modify_ticket('jack', 'Comment 1', self.t1, '1') self.t2 = self.created + timedelta(seconds=2) self._modify_ticket('john', 'Comment 2', self.t2, '1.2', owner='jack') self.t3 = self.created + timedelta(seconds=3) self._modify_ticket('jim', 'Comment 3', self.t3, '3', keywords='a, b') def tearDown(self): self.env.reset_db() def test_modify_comment(self): """Check modification of a "standalone" comment""" ticket = Ticket(self.env, self.id) self.assertChange(ticket, 1, self.t1, 'jack', comment=dict(author='jack', old='1', new='Comment 1')) self.assertChange(ticket, 2, self.t2, 'john', owner=dict(author='john', old='john', new='jack'), comment=dict(author='john', old='1.2', new='Comment 2')) self.assertChange(ticket, 3, self.t3, 'jim', keywords=dict(author='jim', old='a, b, c', new='a, b'), comment=dict(author='jim', old='3', new='Comment 3')) t = self.created + timedelta(seconds=10) ticket.modify_comment(self._find_change(ticket, 1), 'joe', 'New comment 1', t) self.assertChange(ticket, 1, self.t1, 'jack', comment=dict(author='jack', old='1', new='New comment 1'), _comment0=dict(author='joe', old='Comment 1', new=str(to_utimestamp(t)))) self.assertEqual(t, Ticket(self.env, self.id)['changetime']) def test_threading(self): """Check modification of a "threaded" comment""" ticket = Ticket(self.env, self.id) t = self.created + timedelta(seconds=20) ticket.modify_comment(self._find_change(ticket, 2), 'joe', 'New comment 2', t) self.assertChange(ticket, 2, self.t2, 'john', owner=dict(author='john', old='john', new='jack'), comment=dict(author='john', old='1.2', new='New comment 2'), _comment0=dict(author='joe', old='Comment 2', new=str(to_utimestamp(t)))) def test_modify_missing_cnum(self): """Editing a comment with no cnum in oldvalue""" self.env.db_transaction( "UPDATE ticket_change SET oldvalue='' WHERE oldvalue='3'") ticket = Ticket(self.env, self.id) t = self.created + timedelta(seconds=30) ticket.modify_comment(self._find_change(ticket, 3), 'joe', 'New comment 3', t) self.assertChange(ticket, 3, self.t3, 'jim', keywords=dict(author='jim', old='a, b, c', new='a, b'), comment=dict(author='jim', old='', new='New comment 3'), _comment0=dict(author='joe', old='Comment 3', new=str(to_utimestamp(t)))) def test_modify_missing_comment(self): """Editing a comment where the comment field is missing""" self.env.db_transaction(""" DELETE FROM ticket_change WHERE field='comment' AND oldvalue='1.2' """) ticket = Ticket(self.env, self.id) t = self.created + timedelta(seconds=40) ticket.modify_comment(self._find_change(ticket, 2), 'joe', 'New comment 2', t) self.assertChange(ticket, 2, self.t2, 'john', owner=dict(author='john', old='john', new='jack'), comment=dict(author='john', old='', new='New comment 2'), _comment0=dict(author='joe', old='', new=str(to_utimestamp(t)))) def test_modify_missing_cnums_and_comment(self): """Editing a comment when all cnums are missing and one comment field is missing """ with self.env.db_transaction as db: db("UPDATE ticket_change SET oldvalue='' WHERE oldvalue='1'") db("""DELETE FROM ticket_change WHERE field='comment' AND oldvalue='1.2'""") db("UPDATE ticket_change SET oldvalue='' WHERE oldvalue='3'") # Modify after missing comment ticket = Ticket(self.env, self.id) t = self.created + timedelta(seconds=50) ticket.modify_comment(self._find_change(ticket, 3), 'joe', 'New comment 3', t) self.assertChange(ticket, 3, self.t3, 'jim', keywords=dict(author='jim', old='a, b, c', new='a, b'), comment=dict(author='jim', old='', new='New comment 3'), _comment0=dict(author='joe', old='Comment 3', new=str(to_utimestamp(t)))) # Modify missing comment t = self.created + timedelta(seconds=60) ticket.modify_comment(self._find_change(ticket, 2), 'joe', 'New comment 2', t) self.assertChange(ticket, 2, self.t2, 'john', owner=dict(author='john', old='john', new='jack'), comment=dict(author='john', old='', new='New comment 2'), _comment0=dict(author='joe', old='', new=str(to_utimestamp(t)))) def test_missing_comment_edit(self): """Modify a comment where one edit is missing""" ticket = Ticket(self.env, self.id) t1 = self.created + timedelta(seconds=70) ticket.modify_comment(self._find_change(ticket, 1), 'joe', 'New comment 1', t1) t2 = self.created + timedelta(seconds=80) ticket.modify_comment(self._find_change(ticket, 1), 'joe', 'Other comment 1', t2) self.assertChange(ticket, 1, self.t1, 'jack', comment=dict(author='jack', old='1', new='Other comment 1'), _comment0=dict(author='joe', old='Comment 1', new=str(to_utimestamp(t1))), _comment1=dict(author='joe', old='New comment 1', new=str(to_utimestamp(t2)))) self.env.db_transaction( "DELETE FROM ticket_change WHERE field='_comment0'") t3 = self.created + timedelta(seconds=90) ticket.modify_comment(self._find_change(ticket, 1), 'joe', 'Newest comment 1', t3) self.assertChange(ticket, 1, self.t1, 'jack', comment=dict(author='jack', old='1', new='Newest comment 1'), _comment1=dict(author='joe', old='New comment 1', new=str(to_utimestamp(t2))), _comment2=dict(author='joe', old='Other comment 1', new=str(to_utimestamp(t3)))) def test_comment_history(self): """Check the generation of the comment history""" ticket = Ticket(self.env, self.id) t = [self.t1] for i in range(1, 32): t.append(self.created + timedelta(minutes=i)) ticket.modify_comment(self._find_change(ticket, 1), 'joe (%d)' % i, 'Comment 1 (%d)' % i, t[-1]) history = ticket.get_comment_history(cnum=1) self.assertEqual((0, t[0], 'jack', 'Comment 1'), history[0]) for i in range(1, len(history)): self.assertEqual((i, t[i], 'joe (%d)' % i, 'Comment 1 (%d)' % i), history[i]) history = ticket.get_comment_history(cdate=self.t1) self.assertEqual((0, t[0], 'jack', 'Comment 1'), history[0]) for i in range(1, len(history)): self.assertEqual((i, t[i], 'joe (%d)' % i, 'Comment 1 (%d)' % i), history[i])
class TicketCommentDeleteTestCase(TicketCommentTestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('ticket-custom', 'foo', 'text') self.created = datetime(2001, 1, 1, 1, 0, 0, 0, utc) self._insert_ticket('Test ticket', self.created, owner='john', keywords='a, b, c', foo='initial') self.t1 = self.created + timedelta(seconds=1) self._modify_ticket('jack', 'Comment 1', self.t1, '1', foo='change 1') self.t2 = self.created + timedelta(seconds=2) self._modify_ticket('john', 'Comment 2', self.t2, '1.2', owner='jack', foo='change2') self.t3 = self.created + timedelta(seconds=3) self._modify_ticket('jim', 'Comment 3', self.t3, '3', keywords='a, b', foo='change3') self.t4 = self.created + timedelta(seconds=4) self._modify_ticket('joe', 'Comment 4', self.t4, '4', keywords='a', foo='change4') def tearDown(self): self.env.reset_db() def test_delete_last_comment(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) t = datetime.now(utc) 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.assertEqual(t, ticket.time_changed) def test_delete_last_comment_when_custom_field_gone(self): """Regression test for http://trac.edgewall.org/ticket/10858""" ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) # we simulate the removal of the definition of the 'foo' custom field self.env.config.remove('ticket-custom', 'foo') del TicketSystem(self.env).fields del TicketSystem(self.env).custom_fields ticket = Ticket(self.env, self.id) # t = datetime.now(utc) 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']) # 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.assertEqual(t, ticket.time_changed) def test_delete_last_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertEqual('a', ticket['keywords']) self.assertEqual('change4', ticket['foo']) t = datetime.now(utc) 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.assertEqual(t, ticket.time_changed) def test_delete_mid_comment(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(t, ticket.time_changed) def test_delete_mid_comment_by_date(self): ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b', new='a'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='a, b, c', new='a'), foo=dict(author='joe', old='change2', new='change4')) self.assertEqual(t, ticket.time_changed) def test_delete_mid_comment_inconsistent(self): # Make oldvalue on keywords for change 4 inconsistent. This should # result in no change in oldvalue when deleting change 3. The # oldvalue of foo should change normally. self.env.db_transaction(""" UPDATE ticket_change SET oldvalue='1, 2' WHERE field='keywords' AND oldvalue='a, b' """) ticket = Ticket(self.env, self.id) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), 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.assertEqual('a', ticket['keywords']) self.assertChange(ticket, 4, self.t4, 'joe', comment=dict(author='joe', old='4', new='Comment 4'), keywords=dict(author='joe', old='1, 2', new='a'), foo=dict(author='joe', old='change2', new='change4')) def test_delete_all_comments(self): ticket = Ticket(self.env, self.id) ticket.delete_change(4) ticket.delete_change(3) ticket.delete_change(2) t = datetime.now(utc) ticket.delete_change(1, when=t) self.assertEqual(t, ticket.time_changed)
class WikiPageTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') os.mkdir(self.env.path) def tearDown(self): shutil.rmtree(self.env.path) self.env.reset_db() def test_new_page(self): page = WikiPage(self.env) self.assertEqual(False, page.exists) self.assertEqual(None, page.name) self.assertEqual(0, page.version) self.assertEqual('', page.text) self.assertEqual(0, page.readonly) self.assertEqual('', page.author) self.assertEqual('', page.comment) self.assertEqual(None, page.time) def test_existing_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') self.assertEqual(True, page.exists) self.assertEqual('TestPage', page.name) self.assertEqual(1, page.version) self.assertEqual(None, page.resource.version) # FIXME: Intentional? self.assertEqual('Bla bla', page.text) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) history = list(page.get_history()) self.assertEqual(1, len(history)) self.assertEqual((1, t, 'joe', 'Testing', '::1'), history[0]) page = WikiPage(self.env, 'TestPage', 1) self.assertEqual(1, page.resource.version) def test_create_page(self): page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', '::1', t) self.assertEqual(True, page.exists) self.assertEqual(1, page.version) self.assertEqual(1, page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) self.assertEqual( [(1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.added[0]) def test_update_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.text = 'Bla' page.save('kate', 'Changing', '192.168.0.101', t2) self.assertEqual(2, page.version) self.assertEqual(2, page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('kate', page.author) self.assertEqual('Changing', page.comment) self.assertEqual(t2, page.time) with self.env.db_query as db: rows = db( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', )) self.assertEqual(2, len(rows)) self.assertEqual( (1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), rows[0]) self.assertEqual((2, to_utimestamp(t2), 'kate', '192.168.0.101', 'Bla', 'Changing', 0), rows[1]) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 2, t2, 'Changing', 'kate', '192.168.0.101'), listener.changed[0]) page = WikiPage(self.env, 'TestPage') history = list(page.get_history()) self.assertEqual(2, len(history)) self.assertEqual((2, t2, 'kate', 'Changing', '192.168.0.101'), history[0]) self.assertEqual((1, t, 'joe', 'Testing', '::1'), history[1]) def test_delete_page(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete() self.assertEqual(False, page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_delete_page_version(self): self.env.db_transaction.executemany( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", [('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0), ('TestPage', 2, 43, 'kate', '192.168.0.11', 'Bla', 'Changing', 0) ]) page = WikiPage(self.env, 'TestPage') page.delete(version=2) self.assertEqual(True, page.exists) self.assertEqual([(1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted_version[0]) def test_delete_page_last_version(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete(version=1) self.assertEqual(False, page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_rename_page(self): data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', ) + data) attachment = Attachment(self.env, 'wiki', 'TestPage') attachment.insert('foo.txt', StringIO(), 0, 1) page = WikiPage(self.env, 'TestPage') page.rename('PageRenamed') self.assertEqual('PageRenamed', page.name) self.assertEqual([data], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('PageRenamed', ))) attachments = Attachment.select(self.env, 'wiki', 'PageRenamed') self.assertEqual('foo.txt', attachments.next().filename) self.assertRaises(StopIteration, attachments.next) Attachment.delete_all(self.env, 'wiki', 'PageRenamed') old_page = WikiPage(self.env, 'TestPage') self.assertEqual(False, old_page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0]) def test_invalid_page_name(self): invalid_names = ('../Page', 'Page/..', 'Page/////SubPage', 'Page/./SubPage', '/PagePrefix', 'PageSuffix/') for name in invalid_names: page = WikiPage(self.env) page.name = name page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.assertRaises(TracError, page.save, 'joe', 'Testing', '::1', t) page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', '::1', t) for name in invalid_names: page = WikiPage(self.env, 'TestPage') self.assertRaises(TracError, page.rename, name)
class WikiTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) self.tag_wp = WikiTagProvider(self.env) # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock(authname='editor') # Mock an anonymous request. self.req.perm = PermissionCache(self.env) self.realm = 'wiki' self.tags = ['tag1'] def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): _revert_tractags_schema_init(self.env) # Tests def test_get_tags(self): resource = Resource('wiki', 'WikiStart') self.assertEquals( [tag for tag in self.tag_wp.get_resource_tags(self.req, resource)], self.tags) def test_exclude_template_tags(self): # Populate table with more test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'PageTemplates/Template', 'tag2') """) tags = ['tag1', 'tag2'] self.assertEquals(self.tag_s.get_all_tags(self.req).keys(), self.tags) self.env.config.set('tags', 'query_exclude_wiki_templates', False) self.assertEquals(self.tag_s.get_all_tags(self.req).keys(), tags) def test_set_tags_no_perms(self): resource = Resource('wiki', 'TaggedPage') self.assertRaises(PermissionError, self.tag_wp.set_resource_tags, self.req, resource, self.tags) def test_set_tags(self): resource = Resource('wiki', 'TaggedPage') self.req.perm = PermissionCache(self.env, username='******') # Shouldn't raise an error with appropriate permission. self.tag_wp.set_resource_tags(self.req, resource, self.tags) self.tag_wp.set_resource_tags(self.req, resource, ['tag2']) # Check change records. rows = self.env.db_query( """ SELECT author,oldtags,newtags FROM tags_change WHERE tagspace=%s AND name=%s ORDER by time DESC """, ('wiki', 'TaggedPage')) self.assertEqual(rows[0], ('editor', 'tag1', 'tag2')) self.assertEqual(rows[1], ('editor', '', 'tag1'))
class TicketModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.config.set( 'trac', 'permission_policies', 'DefaultTicketPolicy, DefaultPermissionPolicy, ' 'LegacyAttachmentPolicy') self.ticket_module = TicketModule(self.env) def tearDown(self): self.env.reset_db() def _create_ticket_with_change(self, old_props, new_props, author='anonymous'): """Create a ticket with `old_props` and apply properties in `new_props`. """ t = Ticket(self.env) t.populate(old_props) t.insert() comment = new_props.pop('comment', None) t.populate(new_props) t.save_changes(author, comment=comment) return t def _insert_ticket(self, **kw): """Helper for inserting a ticket into the database""" return insert_ticket(self.env, **kw) def test_ticket_module_as_default_handler(self): """The New Ticket mainnav entry is active when TicketModule is the `default_handler` and navigating to the base url. Test for regression of http://trac.edgewall.org/ticket/8791. """ req = MockRequest(self.env) chrome = Chrome(self.env).prepare_request(req, self.ticket_module) name = None for item in chrome['nav']['mainnav']: if item['active'] is True: name = item['name'] break self.assertEqual('newticket', name) def test_reporter_and_owner_full_name_is_displayed(self): """Full name of reporter and owner are used in ticket properties.""" self.env.insert_users([('user1', 'User One', ''), ('user2', 'User Two', '')]) ticket = self._insert_ticket(reporter='user1', owner='user2') PermissionSystem(self.env).grant_permission('user2', 'TICKET_VIEW') req = MockRequest(self.env, authname='user2', method='GET', args={ 'id': ticket.id, 'replyto': '1' }) data = self.ticket_module.process_request(req)[1] self.assertEqual( u'<a class="trac-author" href="/trac.cgi/query?' u'status=!closed&reporter=user1">User One</a>', unicode(data['reporter_link'])) self.assertEqual( u'<a class="trac-author-user" href="/trac.cgi/query?' u'status=!closed&owner=user2">User Two</a>', unicode(data['owner_link'])) def test_quoted_reply_author_is_obfuscated(self): """Reply-to author is obfuscated in a quoted reply.""" author = 'author <*****@*****.**>' tkt = self._create_ticket_with_change({}, {'comment': 'the comment'}, author) req = MockRequest(self.env, method='GET', args={ 'id': tkt.id, 'replyto': '1' }) data = self.ticket_module.process_request(req)[1] comment = u"Replying to [comment:1 author <author@\u2026>]:\n> " \ u"the comment\n" self.assertEqual(comment, data['comment']) self.assertEqual(comment, data['change_preview']['comment']) def test_quoted_reply_author_full_name_is_displayed(self): """Full name of reply-to author is used in quoted reply.""" self.env.insert_users([('author', 'The Author', '*****@*****.**')]) tkt = self._create_ticket_with_change({}, {'comment': 'the comment'}, 'author') req = MockRequest(self.env, method='GET', args={ 'id': tkt.id, 'replyto': '1' }) data = self.ticket_module.process_request(req)[1] comment = u"Replying to [comment:1 The Author]:\n> " \ u"the comment\n" self.assertEqual(comment, data['comment']) self.assertEqual(comment, data['change_preview']['comment']) def test_ticket_property_diff_owner_change(self): """Property diff message when ticket owner is changed.""" t = self._create_ticket_with_change({'owner': 'owner1'}, {'owner': 'owner2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual("changed from <em>owner1</em> to <em>owner2</em>", unicode(field['rendered'])) def test_ticket_property_diff_owner_add(self): """Property diff message when ticket owner is added.""" t = self._create_ticket_with_change({'owner': ''}, {'owner': 'owner2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual("set to <em>owner2</em>", unicode(field['rendered'])) def test_ticket_property_diff_owner_remove(self): """Property diff message when ticket owner is removed.""" t = self._create_ticket_with_change({'owner': 'owner1'}, {'owner': ''}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual("<em>owner1</em> deleted", unicode(field['rendered'])) def test_ticket_property_diff_reporter_change(self): """Property diff message when ticket reporter is changed.""" t = self._create_ticket_with_change({'reporter': 'reporter1'}, {'reporter': 'reporter2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual( "changed from <em>reporter1</em> to " "<em>reporter2</em>", unicode(field['rendered'])) def test_ticket_property_diff_reporter_add(self): """Property diff message when ticket reporter is added.""" t = self._create_ticket_with_change({'reporter': ''}, {'reporter': 'reporter2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual("set to <em>reporter2</em>", unicode(field['rendered'])) def test_ticket_property_diff_reporter_remove(self): """Property diff message when ticket reporter is removed.""" t = self._create_ticket_with_change({'reporter': 'reporter1'}, {'reporter': ''}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual("<em>reporter1</em> deleted", unicode(field['rendered'])) def _test_invalid_cnum_raises(self, action, cnum=None): self._insert_ticket() req = MockRequest(self.env, args={'action': action, 'id': '1'}) if cnum is not None: req.args.update({'cnum': cnum}) self.assertRaises(HTTPBadRequest, self.ticket_module.process_request, req) def test_comment_history_cnum_missing_raises(self): self._test_invalid_cnum_raises('comment-history') def test_comment_history_cnum_invalid_type_raises(self): self._test_invalid_cnum_raises('comment-history', 'a') def test_comment_history_cnum_empty_raises(self): self._test_invalid_cnum_raises('comment-history', '') def test_comment_history_cnum_out_of_range(self): """Out of range cnum returns an empty history.""" self._insert_ticket() req = MockRequest(self.env, args={ 'action': 'comment-history', 'id': '1', 'cnum': '1' }) resp = self.ticket_module.process_request(req) self.assertEqual([], resp[1]['history']) def test_comment_diff_cnum_missing_raises(self): self._test_invalid_cnum_raises('comment-diff') def test_comment_diff_cnum_invalid_type_raises(self): self._test_invalid_cnum_raises('comment-diff', 'a') def test_comment_diff_cnum_empty_raises(self): self._test_invalid_cnum_raises('comment-diff', '') def test_comment_diff_cnum_out_of_range_raises(self): self._insert_ticket() req = MockRequest(self.env, args={ 'action': 'comment-diff', 'id': '1', 'cnum': '1' }) self.assertRaises(ResourceNotFound, self.ticket_module.process_request, req) def test_edit_comment_cnum_missing_raises(self): ticket = self._insert_ticket() req = MockRequest(self.env, method='POST', path_info='/ticket/%d' % ticket.id, args={ 'edit_comment': 'Submit changes', 'cnum_edit': '42' }) self.assertTrue(self.ticket_module.match_request(req)) with self.assertRaises(TracError) as cm: self.ticket_module.process_request(req) self.assertEqual('Comment 42 not found', unicode(cm.exception)) def test_edit_comment_validate_max_comment_size(self): """The [ticket] max_comment_size attribute is validated during ticket comment edit. """ perm_sys = PermissionSystem(self.env) perm_sys.grant_permission('user1', 'TICKET_VIEW') perm_sys.grant_permission('user1', 'TICKET_APPEND') self.env.config.set('ticket', 'max_comment_size', 5) ticket = self._insert_ticket(summary='the summary') ticket.save_changes('user1', '12345') req = MockRequest(self.env, method='POST', authname='user1', path_info='/ticket/%d' % ticket.id, args={ 'id': '1', 'edit_comment': True, 'cnum_edit': '1', 'edited_comment': '123456' }) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertIn( "Ticket comment is too long (must be less than 5 " "characters)", unicode(req.chrome['warnings'][0])) def test_preview_comment_validate_max_comment_size(self): """The [ticket] max_comment_size attribute is validated during ticket comment edit preview. """ perm_sys = PermissionSystem(self.env) perm_sys.grant_permission('user1', 'TICKET_VIEW') perm_sys.grant_permission('user1', 'TICKET_APPEND') self.env.config.set('ticket', 'max_comment_size', 5) ticket = self._insert_ticket(summary='the summary') ticket.save_changes('user1', '12345') req = MockRequest(self.env, method='POST', authname='user1', path_info='/ticket/%d' % ticket.id, args={ 'id': '1', 'preview_comment': True, 'cnum_edit': '1', 'edited_comment': '123456' }) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertIn( "Ticket comment is too long (must be less than 5 " "characters)", unicode(req.chrome['warnings'][0])) def _test_template_data_for_time_field(self, req, value, expected, format): self.env.config.set('ticket-custom', 'timefield', 'time') if format: self.env.config.set('ticket-custom', 'timefield.format', format) self._insert_ticket(summary='Time fields', timefield=value) self.assertEqual(value, Ticket(self.env, 1)['timefield']) self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] for f in data['fields']: if f['name'] == 'timefield': self.assertEqual(expected, f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_time_field_with_formats(self): gmt12 = timezone('GMT +12:00') req = MockRequest(self.env, method='GET', path_info='/ticket/1', tz=gmt12) value = datetime(2016, 1, 2, 23, 34, 45, tzinfo=utc) expected = user_time(req, format_datetime, value) self.assertIn('11', expected) # check 11 in hour part self._test_template_data_for_time_field(req, value, expected, None) self._test_template_data_for_time_field(req, value, expected, 'datetime') self._test_template_data_for_time_field(req, value, expected, 'relative') def test_template_data_for_time_field_with_date_format(self): value = datetime(2016, 2, 22, 22, 22, 22, tzinfo=utc) self.env.config.set('ticket-custom', 'timefield', 'time') self.env.config.set('ticket-custom', 'timefield.format', 'date') self._insert_ticket(summary='Time fields', timefield=value) self.assertEqual(value, Ticket(self.env, 1)['timefield']) gmt12 = timezone('GMT +12:00') req = MockRequest(self.env, method='GET', path_info='/ticket/1', tz=gmt12) expected = user_time(req, format_date, value) self.assertIn('23', expected) # check 23 in day part self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] for f in data['fields']: if f['name'] == 'timefield': self.assertEqual(expected, f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_invalid_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') self._insert_ticket(summary='Time fields', timefield=datetime_now(utc)) self.env.db_transaction("UPDATE ticket_custom SET value='invalid' " "WHERE ticket=1 AND name='timefield'") self.assertIsNone(Ticket(self.env, 1)['timefield']) req = MockRequest(self.env, method='GET', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] self.assertIsNone(data['ticket']['timefield']) for f in data['fields']: if f['name'] == 'timefield': self.assertEqual('', f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_invalid_time_field_on_newticket(self): self.env.config.set('ticket-custom', 'timefield', 'time') req = MockRequest(self.env, method='GET', path_info='/newticket') req.args['timefield'] = 'invalid' self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] self.assertEqual('invalid', data['ticket']['timefield']) for f in data['fields']: if f['name'] == 'timefield': self.assertEqual('invalid', f['edit']) break else: self.fail('Missing timefield field') def test_template_data_changes_for_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') dt1 = datetime(2015, 7, 8, tzinfo=utc) dt2 = datetime(2015, 12, 11, tzinfo=utc) with self.env.db_transaction: self._insert_ticket(summary='Time fields', timefield=datetime_now(utc)) self.env.db_transaction(""" UPDATE ticket_custom SET value='invalid' WHERE ticket=1 AND name='timefield' """) t = Ticket(self.env, 1) t['timefield'] = dt1 t.save_changes('anonymous') t = Ticket(self.env, 1) t['timefield'] = dt2 t.save_changes('anonymous') req = MockRequest(self.env, method='GET', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] changes = data['changes'] dt1_text = user_time(req, format_datetime, dt1) dt2_text = user_time(req, format_datetime, dt2) self.assertEqual(2, len(changes)) self.assertEqual('', changes[0]['fields']['timefield']['old']) self.assertEqual(dt1_text, changes[0]['fields']['timefield']['new']) self.assertEqual(dt1_text, changes[1]['fields']['timefield']['old']) self.assertEqual(dt2_text, changes[1]['fields']['timefield']['new']) def test_submit_with_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') self._insert_ticket(summary='Time fields', timefield='') ticket = Ticket(self.env, 1) args_base = { 'submit': '*', 'action': 'leave', 'id': '1', 'field_summary': ticket['summary'], 'field_reporter': ticket['reporter'], 'field_description': ticket['description'], 'view_time': str(to_utimestamp(ticket['changetime'])) } for f in ticket.fields: args_base['field_%s' % f['name']] = ticket[f['name']] or '' args = args_base.copy() args['field_timefield'] = 'invalid datetime' req = MockRequest(self.env, method='POST', path_info='/ticket/1', args=args) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) warnings = req.chrome['warnings'] self.assertNotEqual([], warnings) self.assertEqual(1, len(warnings)) self.assertIn('is an invalid date, or the date format is not known.', unicode(warnings[0])) ticket = Ticket(self.env, 1) self.assertIsNone(ticket['timefield']) args = args_base.copy() args['field_timefield'] = '2016-01-02T12:34:56Z' req = MockRequest(self.env, method='POST', path_info='/ticket/1', args=args) self.assertTrue(self.ticket_module.match_request(req)) self.assertRaises(RequestDone, self.ticket_module.process_request, req) ticket = Ticket(self.env, 1) self.assertEqual(datetime(2016, 1, 2, 12, 34, 56, tzinfo=utc), ticket['timefield']) def _test_render_time_field(self, format, req, value, expected): self.env.config.set('ticket-custom', 'timefield', 'time') self.env.config.set('ticket-custom', 'timefield.format', format) def timefield_text(): self.assertTrue(self.ticket_module.match_request(req)) template, data = self.ticket_module.process_request(req) content = Chrome(self.env).render_fragment(req, template, data) # select('//td[@headers="h_timefield"') replacement class TimefieldExtractor(HTMLTransform): pick_next_text = False value = '' def handle_starttag(self, tag, attrs): if tag == 'td': for name, value in attrs: if name == 'headers' and value == 'h_timefield': self.pick_next_text = True def handle_data(self, data): if self.pick_next_text: self.value += data def handle_endtag(self, tag): if self.pick_next_text: self.pick_next_text = False extractor = TimefieldExtractor(io.BytesIO()) extractor.feed(content.encode('utf-8')) return extractor.value.decode('utf-8').strip() self._insert_ticket(summary='Time fields') self.assertEqual('', timefield_text()) ticket = Ticket(self.env, 1) ticket['timefield'] = value ticket.save_changes('anonymous') self.assertEqual(expected, timefield_text()) def test_render_time_field_date(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime(2015, 7, 8, tzinfo=utc) expected = user_time(req, format_date, value) self._test_render_time_field('date', req, value, expected) def test_render_time_field_datetime(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime(2015, 7, 8, 12, 34, 56, tzinfo=utc) expected = user_time(req, format_datetime, value) self._test_render_time_field('datetime', req, value, expected) def test_render_time_field_relative(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime_now(utc) - timedelta(days=1) self._test_render_time_field('relative', req, value, '24 hours ago') def _test_newticket_with_enum_as_custom_field(self, field_name): self.env.config.set('ticket-custom', field_name, 'text') self.env.config.set('ticket-custom', '%s.label' % field_name, '(%s)' % field_name) with self.env.db_transaction as db: if field_name in ('milestone', 'component', 'version'): db("DELETE FROM %s" % field_name) elif field_name == 'type': db("DELETE FROM enum WHERE type='ticket_type'") else: db("DELETE FROM enum WHERE type=%s", (field_name, )) tktsys = TicketSystem(self.env) tktsys.reset_ticket_fields() del tktsys.custom_fields req = MockRequest(self.env, path_info='/newticket') self.assertTrue(self.ticket_module.match_request(req)) resp = self.ticket_module.process_request(req) for field in resp[1]['fields']: if field['name'] == field_name: self.assertEqual('(%s)' % field_name, field['label']) self.assertTrue(field['custom']) self.assertFalse(field['options']) self.assertFalse(field.get('optgroups')) break else: self.fail('Missing %s in fields' % field_name) def test_newticket_with_component_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('component') def test_newticket_with_milestone_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('milestone') def test_newticket_with_priority_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('priority') def test_newticket_with_resolution_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('resolution') def test_newticket_with_severity_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('severity') def test_newticket_with_type_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('type') def test_newticket_with_version_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('version') def test_add_comment_requires_ticket_append(self): """Adding a ticket comment requires TICKET_APPEND.""" ps = PermissionSystem(self.env) ps.grant_permission('user1', 'TICKET_VIEW') ps.grant_permission('user1', 'TICKET_APPEND') ps.grant_permission('user2', 'TICKET_VIEW') ps.grant_permission('user2', 'TICKET_CHGPROP') ticket = self._insert_ticket(summary='the summary') comment = 'the comment' def make_req(authname): change_time = Ticket(self.env, 1)['changetime'] return MockRequest(self.env, authname=authname, method='POST', path_info='/ticket/1', args={ 'comment': comment, 'action': 'leave', 'submit': True, 'view_time': unicode(to_utimestamp(change_time)) }) req = make_req('user1') self.assertTrue(self.ticket_module.match_request(req)) self.assertRaises(RequestDone, self.ticket_module.process_request, req) self.assertEqual([], req.chrome['warnings']) self.assertEqual(comment, ticket.get_change(1)['fields']['comment']['new']) req = make_req('user2') self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertEqual(1, len(req.chrome['warnings'])) self.assertEqual("No permissions to add a comment.", unicode(req.chrome['warnings'][0]))
class LoginModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.module = LoginModule(self.env) def tearDown(self): self.env.reset_db() def test_anonymous_access(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) def test_unknown_cookie_access(self): incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=Cookie(), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) def test_known_cookie_access(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(incookie=incookie, outcookie=outcookie, href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user=None) self.assertEqual('john', self.module.authenticate(req)) self.failIf('auth_cookie' in req.outcookie) def test_known_cookie_ip_check_enabled(self): self.env.config.set('trac', 'check_auth_ip', 'yes') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=outcookie, remote_addr='192.168.0.100', remote_user=None, base_path='/trac.cgi') self.assertEqual(None, self.module.authenticate(req)) self.failIf('trac_auth' not in req.outcookie) def test_known_cookie_ip_check_disabled(self): self.env.config.set('trac', 'check_auth_ip', 'no') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(incookie=incookie, outcookie=outcookie, href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='192.168.0.100', remote_user=None) self.assertEqual('john', self.module.authenticate(req)) self.failIf('auth_cookie' in req.outcookie) def test_login(self): outcookie = Cookie() # remote_user must be upper case to test that by default, case is # preserved. req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=outcookie, remote_addr='127.0.0.1', remote_user='******', authname='john', base_path='/trac.cgi') self.module._do_login(req) assert outcookie.has_key('trac_auth'), '"trac_auth" Cookie not set' auth_cookie = outcookie['trac_auth'].value self.assertEquals( [('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie, ))) def test_login_ignore_case(self): """ Test that login is succesful when the usernames differ in case, but case is ignored. """ self.env.config.set('trac', 'ignore_auth_case', 'yes') outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=outcookie, remote_addr='127.0.0.1', remote_user='******', authname='anonymous', base_path='/trac.cgi') self.module._do_login(req) assert outcookie.has_key('trac_auth'), '"trac_auth" Cookie not set' auth_cookie = outcookie['trac_auth'].value self.assertEquals( [('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie, ))) def test_login_no_username(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertRaises(TracError, self.module._do_login, req) def test_already_logged_in_same_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(incookie=incookie, outcookie=Cookie(), href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user='******', authname='john') self.module._do_login(req) # this shouldn't raise an error def test_already_logged_in_different_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' req = Mock(incookie=incookie, authname='john', href=Href('/trac.cgi'), base_path='/trac.cgi', remote_addr='127.0.0.1', remote_user='******') self.assertRaises(AssertionError, self.module._do_login, req) def test_logout(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") incookie = Cookie() incookie['trac_auth'] = '123' outcookie = Cookie() req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=incookie, outcookie=outcookie, remote_addr='127.0.0.1', remote_user=None, authname='john', base_path='/trac.cgi') self.module._do_logout(req) self.failIf('trac_auth' not in outcookie) self.failIf( self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE name='john'")) def test_logout_not_logged_in(self): req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=Cookie(), remote_addr='127.0.0.1', remote_user=None, authname='anonymous', base_path='/trac.cgi') self.module._do_logout(req) # this shouldn't raise an error
class WikiTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) self.tag_wp = WikiTagProvider(self.env) # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock(authname='editor') # Mock an anonymous request. self.req.perm = PermissionCache(self.env) self.realm = 'wiki' self.tags = ['tag1'] def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): _revert_tractags_schema_init(self.env) # Tests def test_get_tags(self): resource = Resource('wiki', 'WikiStart') self.assertEquals([tag for tag in self.tag_wp.get_resource_tags(self.req, resource)], self.tags) def test_exclude_template_tags(self): # Populate table with more test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'PageTemplates/Template', 'tag2') """) tags = ['tag1', 'tag2'] self.assertEquals(self.tag_s.get_all_tags(self.req).keys(), self.tags) self.env.config.set('tags', 'query_exclude_wiki_templates', False) self.assertEquals(self.tag_s.get_all_tags(self.req).keys(), tags) def test_set_tags_no_perms(self): resource = Resource('wiki', 'TaggedPage') self.assertRaises(PermissionError, self.tag_wp.set_resource_tags, self.req, resource, self.tags) def test_set_tags(self): resource = Resource('wiki', 'TaggedPage') self.req.perm = PermissionCache(self.env, username='******') # Shouldn't raise an error with appropriate permission. self.tag_wp.set_resource_tags(self.req, resource, self.tags) self.tag_wp.set_resource_tags(self.req, resource, ['tag2']) # Check change records. rows = self.env.db_query(""" SELECT author,oldtags,newtags FROM tags_change WHERE tagspace=%s AND name=%s ORDER by time DESC """, ('wiki', 'TaggedPage')) self.assertEqual(rows[0], ('editor', 'tag1', 'tag2')) self.assertEqual(rows[1], ('editor', '', 'tag1'))
class TracAdminTestCase(TracAdminTestCaseBase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.admin = TracAdmin() self.admin.env_set('', self.env) def tearDown(self): self.env.reset_db() self.env = None def test_permission_list_ok(self): """Tests the 'permission list' command in trac-admin.""" rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_list_includes_undefined_actions(self): """Undefined actions are included in the User Action table, but not in the Available Actions list. """ self.env.disable_component(trac.search.web_ui.SearchModule) rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_add_one_action_ok(self): """ Tests the 'permission add' command in trac-admin. This particular test passes valid arguments to add one permission and checks for success. """ self.execute('permission add test_user WIKI_VIEW') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_add_multiple_actions_ok(self): """ Tests the 'permission add' command in trac-admin. This particular test passes valid arguments to add multiple permissions and checks for success. """ self.execute('permission add test_user LOG_VIEW FILE_VIEW') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_add_already_exists(self): """ Tests the 'permission add' command in trac-admin. This particular test passes a permission that already exists and checks for the message. Other permissions passed are added. """ rv, output = self.execute('permission add anonymous WIKI_CREATE ' 'WIKI_VIEW WIKI_MODIFY') self.assertEqual(0, rv, output) rv, output2 = self.execute('permission list') self.assertEqual(0, rv, output2) self.assertExpectedResult(output + output2) def test_permission_add_subject_already_in_group(self): """ Tests the 'permission add' command in trac-admin. This particular test passes a group that the subject is already a member of and checks for the message. Other permissions passed are added. """ rv, output1 = self.execute('permission add user1 group2') self.assertEqual(0, rv, output1) rv, output2 = self.execute('permission add user1 group1 group2 ' 'group3') self.assertEqual(0, rv, output2) rv, output3 = self.execute('permission list') self.assertEqual(0, rv, output3) self.assertExpectedResult(output2 + output3) def test_permission_add_differs_from_action_by_casing(self): """ Tests the 'permission add' command in trac-admin. This particular test passes a permission that differs from an action by casing and checks for the message. None of the permissions in the list are granted. """ rv, output = self.execute('permission add joe WIKI_CREATE ' 'Trac_Admin WIKI_MODIFY') self.assertEqual(2, rv, output) rv, output2 = self.execute('permission list') self.assertEqual(0, rv, output2) self.assertExpectedResult(output + output2) def test_permission_add_unknown_action(self): """ Tests the 'permission add' command in trac-admin. This particular test tries granting NOT_A_PERM to a user. NOT_A_PERM does not exist in the system. None of the permissions in the list are granted. """ rv, output = self.execute('permission add joe WIKI_CREATE ' 'NOT_A_PERM WIKI_MODIFY') self.assertEqual(2, rv, output) rv, output2 = self.execute('permission list') self.assertEqual(0, rv, output2) self.assertExpectedResult(output + output2) def test_permission_remove_one_action_ok(self): """ Tests the 'permission remove' command in trac-admin. This particular test passes valid arguments to remove one permission and checks for success. """ self.execute('permission remove anonymous TICKET_MODIFY') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_remove_multiple_actions_ok(self): """ Tests the 'permission remove' command in trac-admin. This particular test passes valid arguments to remove multiple permission and checks for success. """ self.execute('permission remove anonymous WIKI_CREATE WIKI_MODIFY') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_remove_all_actions_for_user(self): """ Tests the 'permission remove' command in trac-admin. This particular test removes all permissions for anonymous. """ self.execute('permission remove anonymous *') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_remove_action_for_all_users(self): """ Tests the 'permission remove' command in trac-admin. This particular test removes the TICKET_CREATE permission from all users. """ self.execute('permission add anonymous TICKET_CREATE') self.execute('permission remove * TICKET_CREATE') rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_remove_unknown_user(self): """ Tests the 'permission remove' command in trac-admin. This particular test tries removing a permission from an unknown user. """ rv, output = self.execute('permission remove joe TICKET_VIEW') self.assertEqual(2, rv, output) self.assertExpectedResult(output) def test_permission_remove_action_not_granted(self): """ Tests the 'permission remove' command in trac-admin. This particular test tries removing TICKET_CREATE from user anonymous, who doesn't have that permission. """ rv, output = self.execute('permission remove anonymous TICKET_CREATE') self.assertEqual(2, rv, output) self.assertExpectedResult(output) def test_permission_remove_action_granted_through_meta_permission(self): """ Tests the 'permission remove' command in trac-admin. This particular test tries removing WIKI_VIEW from a user. WIKI_VIEW has been granted through user anonymous.""" self.execute('permission add joe TICKET_VIEW') rv, output = self.execute('permission remove joe WIKI_VIEW') self.assertEqual(2, rv, output) self.assertExpectedResult(output) def test_permission_remove_unknown_action(self): """ Tests the 'permission remove' command in trac-admin. This particular test tries removing NOT_A_PERM from a user. NOT_A_PERM does not exist in the system.""" rv, output = self.execute('permission remove joe NOT_A_PERM') self.assertEqual(2, rv, output) self.assertExpectedResult(output) def test_permission_remove_unknown_action_granted(self): """ Tests the 'permission remove' command in trac-admin. This particular test tries removing NOT_A_PERM from a user. NOT_A_PERM does not exist in the system, but the user possesses the permission.""" self.env.db_transaction( """ INSERT INTO permission VALUES (%s, %s) """, ('joe', 'NOT_A_PERM')) rv, output = self.execute('permission remove joe NOT_A_PERM') self.assertEqual(0, rv, output) rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_export_ok(self): """ Tests the 'permission export' command in trac-admin. This particular test exports the default permissions to stdout. """ rv, output = self.execute('permission export') self.assertEqual(0, rv, output) self.assertExpectedResult(output) def test_permission_import_ok(self): """ Tests the 'permission import' command in trac-admin. This particular test exports additional permissions, removes them and imports them back. """ user = u'test_user\u0250' self.execute('permission add ' + user + ' WIKI_VIEW') self.execute('permission add ' + user + ' TICKET_VIEW') rv, output = self.execute('permission export') self.execute('permission remove ' + user + ' *') rv, output = self.execute('permission import', input=output) self.assertEqual(0, rv, output) self.assertEqual('', output) rv, output = self.execute('permission list') self.assertEqual(0, rv, output) self.assertExpectedResult(output)
class TagModelTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.req = Mock(authname='editor') self.check_perm = WikiTagProvider(self.env).check_permission setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment() # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.realm = 'wiki' def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): with self.env.db_transaction as db: db("DROP TABLE IF EXISTS tags") db("DROP TABLE IF EXISTS tags_change") db("DELETE FROM system WHERE name='tags_version'") db("DELETE FROM permission WHERE action %s" % db.like(), ('TAGS_%',)) def _tags(self): tags = {} for name, tag in self.env.db_query(""" SELECT name,tag FROM tags """): if name in tags: tags[name].add(tag) else: tags[name] = set([tag]) return tags # Tests def test_get_tags(self): resource = Resource(self.realm, 'WikiStart') self.assertEquals([tag for tag in resource_tags(self.env, resource)], ['tag1']) def test_get_tagged_resource_no_perm(self): self.perms.revoke_permission('anonymous', 'WIKI_VIEW') perm = PermissionCache(self.env) tags = set(['tag1']) # Don't yield resource without permission - 'WIKI_VIEW' here. self.assertEqual([(res, tags) for res, tags in tagged_resources(self.env, self.check_perm, perm, self.realm, tags)], []) def test_get_tagged_resource(self): perm = PermissionCache(self.env) resource = Resource(self.realm, 'WikiStart') tags = set(['tag1']) self.assertEqual([(res, tags) for res, tags in tagged_resources(self.env, self.check_perm, perm, self.realm, tags)], [(resource, tags)]) def test_reparent(self): resource = Resource(self.realm, 'TaggedPage') old_name = 'WikiStart' tag_resource(self.env, resource, 'WikiStart', self.req.authname) self.assertEquals(dict(TaggedPage=set(['tag1'])), self._tags()) def test_tag_changes(self): # Add previously untagged resource. resource = Resource(self.realm, 'TaggedPage') tags = set(['tag1']) tag_resource(self.env, resource, author=self.req.authname, tags=tags) self.assertEquals(dict(TaggedPage=tags, WikiStart=tags), self._tags()) # Add new tag to already tagged resource. resource = Resource(self.realm, 'WikiStart') tags = set(['tag1', 'tag2']) tag_resource(self.env, resource, author=self.req.authname, tags=tags) self.assertEquals(dict(TaggedPage=set(['tag1']), WikiStart=tags), self._tags()) # Exchange tags for already tagged resource. tags = set(['tag1', 'tag3']) tag_resource(self.env, resource, author=self.req.authname, tags=tags) self.assertEquals(dict(TaggedPage=set(['tag1']), WikiStart=tags), self._tags()) # Delete a subset of tags for already tagged resource. tags = set(['tag3']) tag_resource(self.env, resource, author=self.req.authname, tags=tags) self.assertEquals(dict(TaggedPage=set(['tag1']), WikiStart=tags), self._tags()) # Empty tag iterable deletes all resource tag references. tags = tuple() tag_resource(self.env, resource, author=self.req.authname, tags=tags) self.assertEquals(dict(TaggedPage=set(['tag1'])), self._tags())
class ConnectionTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.schema = [ Table('HOURS', key='ID')[Column('ID', auto_increment=True), Column('AUTHOR')], Table('blog', key='bid')[Column('bid', auto_increment=True), Column('author'), Column('comment')] ] self.dbm = DatabaseManager(self.env) self.dbm.drop_tables(self.schema) self.dbm.create_tables(self.schema) def tearDown(self): DatabaseManager(self.env).drop_tables(self.schema) self.env.reset_db() def test_drop_column(self): """Data is preserved when column is dropped.""" table_data = [ ('blog', ('author', 'comment'), (('author1', 'comment one'), ('author2', 'comment two'))), ] self.dbm.insert_into_tables(table_data) with self.env.db_transaction as db: db.drop_column('blog', 'comment') data = list(self.env.db_query("SELECT * FROM blog")) self.assertEqual((1, 'author1'), data[0]) self.assertEqual((2, 'author2'), data[1]) def test_drop_column_no_exists(self): """Error is not raised when dropping non-existent column.""" table_data = [ ('blog', ('author', 'comment'), (('author1', 'comment one'), ('author2', 'comment two'))), ] self.dbm.insert_into_tables(table_data) with self.env.db_transaction as db: db.drop_column('blog', 'tags') data = list(self.env.db_query("SELECT * FROM blog")) self.assertEqual((1, 'author1', 'comment one'), data[0]) self.assertEqual((2, 'author2', 'comment two'), data[1]) def test_rollback_transaction_on_exception(self): """Transaction is rolled back when an exception occurs in the transaction context manager. """ insert_sql = "INSERT INTO blog (bid, author) VALUES (42, 'anonymous')" try: with self.env.db_transaction as db: db(insert_sql) db(insert_sql) except self.env.db_exc.IntegrityError: pass for _, in self.env.db_query(""" SELECT author FROM blog WHERE bid=42 """): self.fail("Transaction was not rolled back") def test_rollback_nested_transaction_on_exception(self): """Transaction is rolled back when an exception occurs in the inner transaction context manager. """ sql = "INSERT INTO blog (bid, author) VALUES (42, 'anonymous')" try: with self.env.db_transaction as db_outer: db_outer(sql) with self.env.db_transaction as db_inner: db_inner(sql) except self.env.db_exc.IntegrityError: pass for _, in self.env.db_query(""" SELECT author FROM blog WHERE bid=42 """): self.fail("Transaction was not rolled back") def test_get_last_id(self): q = "INSERT INTO report (author) VALUES ('anonymous')" with self.env.db_transaction as db: cursor = db.cursor() cursor.execute(q) # Row ID correct before... id1 = db.get_last_id(cursor, 'report') db.commit() cursor.execute(q) # ... and after commit() db.commit() id2 = db.get_last_id(cursor, 'report') self.assertNotEqual(0, id1) self.assertEqual(id1 + 1, id2) def test_update_sequence_default_column_name(self): with self.env.db_transaction as db: db("INSERT INTO report (id, author) VALUES (42, 'anonymous')") cursor = db.cursor() db.update_sequence(cursor, 'report') self.env.db_transaction( "INSERT INTO report (author) VALUES ('next-id')") self.assertEqual( 43, self.env.db_query("SELECT id FROM report WHERE author='next-id'") [0][0]) def test_update_sequence_nondefault_column_name(self): with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO blog (bid, author) VALUES (42, 'anonymous')") db.update_sequence(cursor, 'blog', 'bid') self.env.db_transaction("INSERT INTO blog (author) VALUES ('next-id')") self.assertEqual( 43, self.env.db_query("SELECT bid FROM blog WHERE author='next-id'")[0] [0]) def test_identifiers_need_quoting(self): """Test for regression described in comment:4:ticket:11512.""" with self.env.db_transaction as db: db("INSERT INTO %s (%s, %s) VALUES (42, 'anonymous')" % (db.quote('HOURS'), db.quote('ID'), db.quote('AUTHOR'))) cursor = db.cursor() db.update_sequence(cursor, 'HOURS', 'ID') with self.env.db_transaction as db: cursor = db.cursor() cursor.execute("INSERT INTO %s (%s) VALUES ('next-id')" % (db.quote('HOURS'), db.quote('AUTHOR'))) last_id = db.get_last_id(cursor, 'HOURS', 'ID') self.assertEqual(43, last_id) def test_get_table_names(self): schema = default_schema + self.schema with self.env.db_query as db: # Some DB (e.g. MariaDB) normalize the table names to lower case self.assertEqual( sorted(table.name.lower() for table in schema), sorted(name.lower() for name in db.get_table_names())) def test_get_column_names(self): schema = default_schema + self.schema with self.env.db_query as db: for table in schema: column_names = [col.name for col in table.columns] self.assertEqual(column_names, db.get_column_names(table.name)) def test_get_column_names_non_existent_table(self): with self.assertRaises(self.env.db_exc.OperationalError) as cm: self.dbm.get_column_names('blah') self.assertIn(unicode(cm.exception), ('Table "blah" not found', 'Table `blah` not found'))
class ModifyTableTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.dbm = DatabaseManager(self.env) self.schema = [ Table('table1', key='col1')[Column('col1', auto_increment=True), Column('col2'), Column('col3'), ], Table('table2', key='col1')[Column('col1'), Column('col2'), ], Table('table3', key='col2')[Column('col1'), Column('col2', type='int'), Column('col3')] ] self.dbm.create_tables(self.schema) self.new_schema = copy.deepcopy([self.schema[0], self.schema[2]]) self.new_schema[0].remove_columns(('col2', )) self.new_schema[1].columns.append(Column('col4')) self.new_schema.append(Table('table4')[Column('col1'), ]) def tearDown(self): self.dbm.drop_tables(['table1', 'table2', 'table3', 'table4']) self.env.reset_db() def _insert_data(self): table_data = [ ('table1', ('col2', 'col3'), (('data1', 'data2'), ('data3', 'data4'))), ('table2', ('col1', 'col2'), (('data5', 'data6'), ('data7', 'data8'))), ('table3', ('col1', 'col2', 'col3'), (('data9', 10, 'data11'), ('data12', 13, 'data14'))), ] self.dbm.insert_into_tables(table_data) def test_drop_columns(self): """Data is preserved when column is dropped.""" self._insert_data() self.dbm.drop_columns('table1', ('col2', )) self.assertEqual(['col1', 'col3'], self.dbm.get_column_names('table1')) data = list(self.env.db_query("SELECT * FROM table1")) self.assertEqual((1, 'data2'), data[0]) self.assertEqual((2, 'data4'), data[1]) def test_drop_columns_multiple_columns(self): """Data is preserved when columns are dropped.""" self._insert_data() self.dbm.drop_columns('table3', ('col1', 'col3')) self.assertEqual(['col2'], self.dbm.get_column_names('table3')) data = list(self.env.db_query("SELECT * FROM table3")) self.assertEqual((10, ), data[0]) self.assertEqual((13, ), data[1]) def test_drop_columns_non_existent_table(self): with self.assertRaises(self.env.db_exc.OperationalError) as cm: self.dbm.drop_columns('blah', ('col1', )) self.assertIn(unicode(cm.exception), ('Table "blah" not found', 'Table `blah` not found')) def test_upgrade_tables_have_new_schema(self): """The upgraded tables have the new schema.""" self.dbm.upgrade_tables(self.new_schema) for table in self.new_schema: self.assertEqual([col.name for col in table.columns], self.dbm.get_column_names(table.name)) def test_upgrade_tables_data_is_migrated(self): """The data is migrated to the upgraded tables.""" self._insert_data() self.dbm.upgrade_tables(self.new_schema) self.env.db_transaction(""" INSERT INTO table1 (col3) VALUES ('data12') """) data = list(self.env.db_query("SELECT * FROM table1")) self.assertEqual((1, 'data2'), data[0]) self.assertEqual((2, 'data4'), data[1]) self.assertEqual( 3, self.env.db_query(""" SELECT col1 FROM table1 WHERE col3='data12'""")[0][0]) data = list(self.env.db_query("SELECT * FROM table2")) self.assertEqual(('data5', 'data6'), data[0]) self.assertEqual(('data7', 'data8'), data[1]) data = list(self.env.db_query("SELECT * FROM table3")) self.assertEqual(('data9', 10, 'data11', None), data[0]) self.assertEqual(('data12', 13, 'data14', None), data[1]) def test_upgrade_tables_no_common_columns(self): schema = [ Table('table1', key='id')[Column('id', auto_increment=True), Column('name'), Column('value'), ], ] self.dbm.upgrade_tables(schema) self.assertEqual(['id', 'name', 'value'], self.dbm.get_column_names('table1')) self.assertEqual([], list(self.env.db_query("SELECT * FROM table1")))
class WikiPageTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(path=mkdtemp()) def tearDown(self): self.env.reset_db_and_disk() def test_new_page(self): page = WikiPage(self.env) self.assertFalse(page.exists) self.assertIsNone(page.name) self.assertEqual(0, page.version) self.assertEqual('', page.text) self.assertEqual(0, page.readonly) self.assertEqual('', page.author) self.assertEqual('', page.comment) self.assertIsNone(page.time) self.assertEqual('<WikiPage None>', repr(page)) def test_existing_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') self.assertTrue(page.exists) self.assertEqual('TestPage', page.name) self.assertEqual(1, page.version) self.assertIsNone(page.resource.version) self.assertEqual('Bla bla', page.text) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) self.assertEqual("<WikiPage u'TestPage@1'>", repr(page)) history = list(page.get_history()) self.assertEqual(1, len(history)) self.assertEqual((1, t, 'joe', 'Testing'), history[0]) page = WikiPage(self.env, 'TestPage', 1) self.assertEqual(1, page.resource.version) self.assertEqual(1, page.version) resource = Resource('wiki', 'TestPage') page = WikiPage(self.env, resource, 1) self.assertEqual(1, page.version) def test_create_page(self): page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', t) self.assertTrue(page.exists) self.assertEqual(1, page.version) self.assertIsNone(page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) self.assertEqual( [(1, to_utimestamp(t), 'joe', 'Bla bla', 'Testing', 0)], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.added[0]) def test_update_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.text = 'Bla' page.save('kate', 'Changing', t2) self.assertEqual(2, page.version) self.assertIsNone(page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('kate', page.author) self.assertEqual('Changing', page.comment) self.assertEqual(t2, page.time) with self.env.db_query as db: rows = db( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s ORDER BY version """, ('TestPage', )) self.assertEqual(2, len(rows)) self.assertEqual( (1, to_utimestamp(t), 'joe', 'Bla bla', 'Testing', 0), rows[0]) self.assertEqual( (2, to_utimestamp(t2), 'kate', 'Bla', 'Changing', 0), rows[1]) listener = TestLegacyWikiChangeListener(self.env) self.assertEqual((page, 2, t2, 'Changing', 'kate'), listener.changed[0]) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 2, t2, 'Changing', 'kate'), listener.changed[0]) page = WikiPage(self.env, 'TestPage') history = list(page.get_history()) self.assertEqual(2, len(history)) self.assertEqual((2, t2, 'kate', 'Changing'), history[0]) self.assertEqual((1, t, 'joe', 'Testing'), history[1]) def test_delete_page(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete() self.assertFalse(page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_delete_page_version(self): self.env.db_transaction.executemany( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", [('TestPage', 1, 42, 'joe', 'Bla bla', 'Testing', 0), ('TestPage', 2, 43, 'kate', 'Bla', 'Changing', 0)]) page = WikiPage(self.env, 'TestPage') page.delete(version=2) self.assertTrue(page.exists) self.assertEqual([(1, 42, 'joe', 'Bla bla', 'Testing', 0)], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted_version[0]) def test_delete_page_last_version(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete(version=1) self.assertFalse(page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_rename_page(self): data = (1, 42, 'joe', 'Bla bla', 'Testing', 0) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', ) + data) attachment = Attachment(self.env, 'wiki', 'TestPage') attachment.insert('foo.txt', io.BytesIO(), 0, 1) page = WikiPage(self.env, 'TestPage') page.rename('PageRenamed') self.assertEqual('PageRenamed', page.name) self.assertEqual('PageRenamed', page.resource.id) self.assertEqual([data], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('PageRenamed', ))) attachments = Attachment.select(self.env, 'wiki', 'PageRenamed') self.assertEqual('foo.txt', next(attachments).filename) self.assertRaises(StopIteration, next, attachments) Attachment.delete_all(self.env, 'wiki', 'PageRenamed') old_page = WikiPage(self.env, 'TestPage') self.assertFalse(old_page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0]) def test_edit_comment_of_page_version(self): self.env.db_transaction.executemany( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", [('TestPage', 1, 42, 'joe', 'Bla bla', 'old 1', 0), ('TestPage', 2, 43, 'kate', 'Bla', 'old 2', 0)]) page = WikiPage(self.env, 'TestPage') page.edit_comment('edited comment two') old_page = WikiPage(self.env, 'TestPage', 1) old_page.edit_comment('new comment one') self.assertEqual('edited comment two', page.comment) self.assertEqual('new comment one', old_page.comment) self.assertEqual([(1, 42, 'joe', 'Bla bla', 'new comment one', 0), (2, 43, 'kate', 'Bla', 'edited comment two', 0)], self.env.db_query( """ SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s ORDER BY version """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'old 2'), listener.comment_modified[0]) self.assertEqual((old_page, 'old 1'), listener.comment_modified[1]) def test_invalid_page_name(self): invalid_names = ('../Page', 'Page/..', 'Page/////SubPage', 'Page/./SubPage', '/PagePrefix', 'PageSuffix/') for name in invalid_names: page = WikiPage(self.env) page.name = name page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.assertRaises(TracError, page.save, 'joe', 'Testing', t) page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', t) for name in invalid_names: page = WikiPage(self.env, 'TestPage') self.assertRaises(TracError, page.rename, name) def test_invalid_version(self): data = [(1, 42, 'joe', 'First revision', 'Rev1', 0), (2, 42, 'joe', 'Second revision', 'Rev2', 0)] with self.env.db_transaction as db: for d in data: db("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s)", ('TestPage', ) + d) page = WikiPage(self.env, 'TestPage', '1abc') self.assertEqual(2, page.version) resource = Resource('wiki', 'TestPage') page = WikiPage(self.env, resource, '1abc') self.assertEqual(2, page.version) resource = Resource('wiki', 'TestPage', '1abc') page = WikiPage(self.env, resource) self.assertEqual(2, page.version) resource = Resource('wiki', 'TestPage', 1) page = WikiPage(self.env, resource) self.assertEqual(1, page.version) resource = Resource('wiki', 'TestPage', 2) page = WikiPage(self.env, resource, 1) self.assertEqual(1, page.version)
class WikiPageTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.path = tempfile.mkdtemp(prefix='trac-tempenv-') def tearDown(self): shutil.rmtree(self.env.path) self.env.reset_db() def test_new_page(self): page = WikiPage(self.env) self.assertFalse(page.exists) self.assertIsNone(page.name) self.assertEqual(0, page.version) self.assertEqual('', page.text) self.assertEqual(0, page.readonly) self.assertEqual('', page.author) self.assertEqual('', page.comment) self.assertIsNone(page.time) def test_existing_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') self.assertTrue(page.exists) self.assertEqual('TestPage', page.name) self.assertEqual(1, page.version) self.assertIsNone(page.resource.version) # FIXME: Intentional? self.assertEqual('Bla bla', page.text) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) history = list(page.get_history()) self.assertEqual(1, len(history)) self.assertEqual((1, t, 'joe', 'Testing', '::1'), history[0]) page = WikiPage(self.env, 'TestPage', 1) self.assertEqual(1, page.resource.version) self.assertEqual(1, page.version) resource = Resource('wiki', 'TestPage') page = WikiPage(self.env, resource, 1) self.assertEqual(1, page.version) def test_create_page(self): page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', '::1', t) self.assertTrue(page.exists) self.assertEqual(1, page.version) self.assertEqual(1, page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('joe', page.author) self.assertEqual('Testing', page.comment) self.assertEqual(t, page.time) self.assertEqual( [(1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage',))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.added[0]) def test_update_page(self): t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.text = 'Bla' page.save('kate', 'Changing', '192.168.0.101', t2) self.assertEqual(2, page.version) self.assertEqual(2, page.resource.version) self.assertEqual(0, page.readonly) self.assertEqual('kate', page.author) self.assertEqual('Changing', page.comment) self.assertEqual(t2, page.time) with self.env.db_query as db: rows = db(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s ORDER BY version """, ('TestPage',)) self.assertEqual(2, len(rows)) self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), rows[0]) self.assertEqual((2, to_utimestamp(t2), 'kate', '192.168.0.101', 'Bla', 'Changing', 0), rows[1]) listener = TestLegacyWikiChangeListener(self.env) self.assertEqual((page, 2, t2, 'Changing', 'kate', '192.168.0.101'), listener.changed[0]) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 2, t2, 'Changing', 'kate'), listener.changed[0]) page = WikiPage(self.env, 'TestPage') history = list(page.get_history()) self.assertEqual(2, len(history)) self.assertEqual((2, t2, 'kate', 'Changing', '192.168.0.101'), history[0]) self.assertEqual((1, t, 'joe', 'Testing', '::1'), history[1]) def test_delete_page(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete() self.assertFalse(page.exists) self.assertEqual([], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage',))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_delete_page_version(self): self.env.db_transaction.executemany( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", [('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0), ('TestPage', 2, 43, 'kate', '192.168.0.11', 'Bla', 'Changing', 0)]) page = WikiPage(self.env, 'TestPage') page.delete(version=2) self.assertTrue(page.exists) self.assertEqual( [(1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage',))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted_version[0]) def test_delete_page_last_version(self): self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', 1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0)) page = WikiPage(self.env, 'TestPage') page.delete(version=1) self.assertFalse(page.exists) self.assertEqual([], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage',))) listener = TestWikiChangeListener(self.env) self.assertEqual(page, listener.deleted[0]) def test_rename_page(self): data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage',) + data) attachment = Attachment(self.env, 'wiki', 'TestPage') attachment.insert('foo.txt', StringIO(), 0, 1) page = WikiPage(self.env, 'TestPage') page.rename('PageRenamed') self.assertEqual('PageRenamed', page.name) self.assertEqual('PageRenamed', page.resource.id) self.assertEqual([data], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('PageRenamed',))) attachments = Attachment.select(self.env, 'wiki', 'PageRenamed') self.assertEqual('foo.txt', attachments.next().filename) self.assertRaises(StopIteration, attachments.next) Attachment.delete_all(self.env, 'wiki', 'PageRenamed') old_page = WikiPage(self.env, 'TestPage') self.assertFalse(old_page.exists) self.assertEqual([], self.env.db_query(""" SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage',))) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0]) def test_invalid_page_name(self): invalid_names = ('../Page', 'Page/..', 'Page/////SubPage', 'Page/./SubPage', '/PagePrefix', 'PageSuffix/') for name in invalid_names: page = WikiPage(self.env) page.name = name page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) self.assertRaises(TracError, page.save, 'joe', 'Testing', '::1', t) page = WikiPage(self.env) page.name = 'TestPage' page.text = 'Bla bla' t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) page.save('joe', 'Testing', '::1', t) for name in invalid_names: page = WikiPage(self.env, 'TestPage') self.assertRaises(TracError, page.rename, name) def test_invalid_version(self): data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage',) + data) self.assertRaises(ValueError, WikiPage, self.env, 'TestPage', '1abc') resource = Resource('wiki', 'TestPage') self.assertRaises(ValueError, WikiPage, self.env, resource, '1abc') resource = Resource('wiki', 'TestPage', '1abc') page = WikiPage(self.env, resource) self.assertEqual(1, page.version)
class LoginModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.module = LoginModule(self.env) def tearDown(self): self.env.reset_db() def test_anonymous_access(self): req = MockRequest(self.env, remote_user=None) self.assertIsNone(self.module.authenticate(req)) def test_unknown_cookie_access(self): incookie = Cookie() incookie['trac_auth'] = '123' req = MockRequest(self.env, remote_user=None) self.assertIsNone(self.module.authenticate(req)) def test_known_cookie_access(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, remote_user=None) req.incookie['trac_auth'] = '123' self.assertEqual('john', self.module.authenticate(req)) self.assertNotIn('auth_cookie', req.outcookie) def test_known_cookie_ip_check_enabled(self): self.env.config.set('trac', 'check_auth_ip', 'yes') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, remote_addr='192.168.0.100', remote_user=None) req.incookie['trac_auth'] = '123' self.assertIsNone(self.module.authenticate(req)) self.assertIn('trac_auth', req.outcookie) def test_known_cookie_ip_check_disabled(self): self.env.config.set('trac', 'check_auth_ip', 'no') self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, remote_addr='192.168.0.100', remote_user=None) req.incookie['trac_auth'] = '123' self.assertEqual('john', self.module.authenticate(req)) self.assertNotIn('auth_cookie', req.outcookie) def test_login(self): # remote_user must be upper case to test that by default, case is # preserved. req = MockRequest(self.env, authname='john') self.module._do_login(req) self.assertIn('trac_auth', req.outcookie, '"trac_auth" Cookie not set') auth_cookie = req.outcookie['trac_auth'].value self.assertEqual([('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie,))) def test_login_ignore_case(self): """ Test that login is succesful when the usernames differ in case, but case is ignored. """ self.env.config.set('trac', 'ignore_auth_case', 'yes') req = MockRequest(self.env, remote_user='******') self.module._do_login(req) self.assertIn('trac_auth', req.outcookie, '"trac_auth" Cookie not set') auth_cookie = req.outcookie['trac_auth'].value self.assertEqual([('john', '127.0.0.1')], self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE cookie=%s", (auth_cookie,))) def test_login_no_username(self): req = MockRequest(self.env, remote_user=None) self.assertRaises(TracError, self.module._do_login, req) def test_already_logged_in_same_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, authname='john') self.module._do_login(req) # this shouldn't raise an error def test_already_logged_in_different_user(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, authname='john', remote_user='******') self.assertRaises(TracError, self.module._do_login, req) def test_logout(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, authname='john', method='POST') self.module._do_logout(req) self.assertIn('trac_auth', req.outcookie) self.assertFalse(self.env.db_query( "SELECT name, ipnr FROM auth_cookie WHERE name='john'")) def test_logout_not_logged_in(self): req = MockRequest(self.env, method='POST') self.module._do_logout(req) # this shouldn't raise an error def test_logout_protect(self): self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr) VALUES ('123', 'john', '127.0.0.1')""") req = MockRequest(self.env, authname='john') self.module._do_logout(req) self.assertNotIn('trac_auth', req.outcookie) self.assertEqual( [('john', '127.0.0.1')], self.env.db_query("SELECT name, ipnr FROM auth_cookie " "WHERE cookie='123'"))
class ConnectionTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.schema = [ Table('HOURS', key='ID')[ Column('ID', auto_increment=True), Column('AUTHOR')], Table('blog', key='bid')[ Column('bid', auto_increment=True), Column('author') ] ] self.env.global_databasemanager.drop_tables(self.schema) self.env.global_databasemanager.create_tables(self.schema) def tearDown(self): self.env.global_databasemanager.drop_tables(self.schema) self.env.reset_db() def test_get_last_id(self): q = "INSERT INTO report (author) VALUES ('anonymous')" with self.env.db_transaction as db: cursor = db.cursor() cursor.execute(q) # Row ID correct before... id1 = db.get_last_id(cursor, 'report') db.commit() cursor.execute(q) # ... and after commit() db.commit() id2 = db.get_last_id(cursor, 'report') self.assertNotEqual(0, id1) self.assertEqual(id1 + 1, id2) def test_update_sequence_default_column(self): with self.env.db_transaction as db: db("INSERT INTO report (id, author) VALUES (42, 'anonymous')") cursor = db.cursor() db.update_sequence(cursor, 'report', 'id') self.env.db_transaction( "INSERT INTO report (author) VALUES ('next-id')") self.assertEqual(43, self.env.db_query( "SELECT id FROM report WHERE author='next-id'")[0][0]) def test_update_sequence_nondefault_column(self): with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO blog (bid, author) VALUES (42, 'anonymous')") db.update_sequence(cursor, 'blog', 'bid') self.env.db_transaction( "INSERT INTO blog (author) VALUES ('next-id')") self.assertEqual(43, self.env.db_query( "SELECT bid FROM blog WHERE author='next-id'")[0][0]) def test_identifiers_need_quoting(self): """Test for regression described in comment:4:ticket:11512.""" with self.env.db_transaction as db: db("INSERT INTO %s (%s, %s) VALUES (42, 'anonymous')" % (db.quote('HOURS'), db.quote('ID'), db.quote('AUTHOR'))) cursor = db.cursor() db.update_sequence(cursor, 'HOURS', 'ID') with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO %s (%s) VALUES ('next-id')" % (db.quote('HOURS'), db.quote('AUTHOR'))) last_id = db.get_last_id(cursor, 'HOURS', 'ID') self.assertEqual(43, last_id) def test_get_table_names(self): schema = default_schema + self.schema with self.env.db_query as db: self.assertEqual(sorted(table.name for table in schema), sorted(db.get_table_names())) def test_get_column_names(self): schema = default_schema + self.schema with self.env.db_transaction as db: for table in schema: db_columns = db.get_column_names(table.name) self.assertEqual(len(table.columns), len(db_columns)) for column in table.columns: self.assertIn(column.name, db_columns)
class TicketModuleTestCase(unittest.TestCase): mock_ticket_operation = None @classmethod def setUpClass(cls): class MockTicketOperation(Component): implements(ITicketActionController) def __init__(self): self.side_effect_count = 0 def get_ticket_actions(self, req, ticket): return [(0, 'mock')] def get_all_status(self): return [] def render_ticket_action_control(self, req, ticket, action): return 'test', '', "This is a mock operation." def get_ticket_changes(self, req, ticket, action): return {} def apply_action_side_effects(self, req, ticket, action): if action == 'mock': self.side_effect_count += 1 cls.mock_ticket_operation = MockTicketOperation @classmethod def tearDownClass(cls): from trac.core import ComponentMeta ComponentMeta.deregister(cls.mock_ticket_operation) def setUp(self): self.env = EnvironmentStub(default_data=True) self.env.config.set('trac', 'permission_policies', 'DefaultTicketPolicy, DefaultPermissionPolicy, ' 'LegacyAttachmentPolicy') self.ticket_module = TicketModule(self.env) def tearDown(self): self.env.reset_db() def _create_ticket_with_change(self, old_props, new_props, author='anonymous'): """Create a ticket with `old_props` and apply properties in `new_props`. """ t = insert_ticket(self.env, **old_props) comment = new_props.pop('comment', None) t.populate(new_props) t.save_changes(author, comment=comment) return t def _has_auto_preview(self, req): return any('/trac.cgi/chrome/common/js/auto_preview.js' in s['attrs']['src'] for s in req.chrome['scripts']) def _insert_ticket(self, **kw): """Helper for inserting a ticket into the database""" return insert_ticket(self.env, **kw) def _get_field_by_name(self, data, name): for field in data['fields']: if field['name'] == name: return field def test_get_moved_attributes(self): """The attributes `max_comment_size`, `max_description_size` and `max_summary_size` have been moved to TicketSystem but are accessible on TicketModule for backward compatibility. """ ts = TicketSystem(self.env) tm = TicketModule(self.env) self.assertEqual(ts.max_comment_size, tm.max_comment_size) self.assertEqual(ts.max_description_size, tm.max_description_size) self.assertEqual(ts.max_summary_size, tm.max_summary_size) def test_ticket_module_as_default_handler(self): """The New Ticket mainnav entry is active when TicketModule is the `default_handler` and navigating to the base url. Test for regression of http://trac.edgewall.org/ticket/8791. """ req = MockRequest(self.env) chrome = Chrome(self.env).prepare_request(req, self.ticket_module) name = None for item in chrome['nav']['mainnav']: if item['active'] is True: name = item['name'] break self.assertEqual('newticket', name) def test_reporter_and_owner_full_name_is_displayed(self): """Full name of reporter and owner are used in ticket properties.""" self.env.insert_users([('user1', 'User One', ''), ('user2', 'User Two', '')]) ticket = self._insert_ticket(reporter='user1', owner='user2') PermissionSystem(self.env).grant_permission('user2', 'TICKET_VIEW') req = MockRequest(self.env, authname='user2', method='GET', args={'id': ticket.id, 'replyto': '1'}) data = self.ticket_module.process_request(req)[1] self.assertEqual(u'<a class="trac-author" href="/trac.cgi/query?' u'status=!closed&reporter=user1">User One</a>', unicode(data['reporter_link'])) self.assertEqual(u'<a class="trac-author-user" href="/trac.cgi/query?' u'status=!closed&owner=user2">User Two</a>', unicode(data['owner_link'])) def test_version_release_date_displayed(self): """Version release date is shown in ticket properties.""" v1 = Version(self.env) v1.name = 'v1' v1.time = datetime_now(utc) - timedelta(weeks=2) v1.insert() v2 = Version(self.env) v2.name = 'v2' v2.insert() ticket = [self._insert_ticket(summary='ticket 1', version='v1'), self._insert_ticket(summary='ticket 2', version='v2'), self._insert_ticket(summary='ticket 3', version='v3')] def version_field(data): for field in data['fields']: if field['name'] == 'version': return field # Version with release data. req = MockRequest(self.env, method='GET', args={'id': ticket[0].id}) data = self.ticket_module.process_request(req)[1] self.assertIn(u'title="Released ', unicode(version_field(data)['rendered'])) # Version without release data. req = MockRequest(self.env, method='GET', args={'id': ticket[1].id}) data = self.ticket_module.process_request(req)[1] self.assertNotIn(u'title="Released ', unicode(version_field(data)['rendered'])) # Non-existent version. req = MockRequest(self.env, method='GET', args={'id': ticket[2].id}) data = self.ticket_module.process_request(req)[1] self.assertNotIn(u'title="Released ', unicode(version_field(data)['rendered'])) def test_quoted_reply_author_is_obfuscated(self): """Reply-to author is obfuscated in a quoted reply.""" author = 'author <*****@*****.**>' tkt = self._create_ticket_with_change({}, {'comment': 'the comment'}, author) req = MockRequest(self.env, method='GET', args={'id': tkt.id, 'replyto': '1'}) data = self.ticket_module.process_request(req)[1] comment = u"Replying to [comment:1 author <author@\u2026>]:\n> " \ u"the comment\n" self.assertEqual(comment, data['comment']) self.assertEqual(comment, data['change_preview']['comment']) def test_quoted_reply_author_full_name_is_displayed(self): """Full name of reply-to author is used in quoted reply.""" self.env.insert_users([('author', 'The Author', '*****@*****.**')]) tkt = self._create_ticket_with_change({}, {'comment': 'the comment'}, 'author') req = MockRequest(self.env, method='GET', args={'id': tkt.id, 'replyto': '1'}) data = self.ticket_module.process_request(req)[1] comment = u"Replying to [comment:1 The Author]:\n> " \ u"the comment\n" self.assertEqual(comment, data['comment']) self.assertEqual(comment, data['change_preview']['comment']) def test_ticket_property_diff_owner_change(self): """Property diff message when ticket owner is changed.""" t = self._create_ticket_with_change({'owner': 'owner1'}, {'owner': 'owner2'}) PermissionSystem(self.env).grant_permission('owner1', 'TICKET_VIEW') req = MockRequest(self.env, authname='owner1', args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual('changed from <span class="trac-author-user">owner1' '</span> to <span class="trac-author">owner2</span>', unicode(field['rendered'])) def test_ticket_property_diff_owner_change_from_anonymous(self): """Property diff message when ticket owner is changed from anonymous. """ t = self._create_ticket_with_change({'owner': 'anonymous'}, {'owner': 'owner1'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual('changed from <span class="trac-author-anonymous">' 'anonymous</span> to <span class="trac-author">' 'owner1</span>', unicode(field['rendered'])) def test_ticket_property_diff_owner_add(self): """Property diff message when ticket owner is added.""" t = self._create_ticket_with_change({'owner': ''}, {'owner': 'owner2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual('set to <span class="trac-author">owner2</span>', unicode(field['rendered'])) def test_ticket_property_diff_owner_remove(self): """Property diff message when ticket owner is removed.""" t = self._create_ticket_with_change({'owner': 'owner1'}, {'owner': ''}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['owner'] self.assertEqual('<span class="trac-author">owner1</span> removed', unicode(field['rendered'])) def test_ticket_property_diff_reporter_change(self): """Property diff message when ticket reporter is changed.""" t = self._create_ticket_with_change({'reporter': 'reporter1'}, {'reporter': 'reporter2'}) PermissionSystem(self.env).grant_permission('reporter2', 'TICKET_VIEW') req = MockRequest(self.env, authname='reporter2', args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual('changed from <span class="trac-author">reporter1' '</span> to <span class="trac-author-user">reporter2' '</span>', unicode(field['rendered'])) def test_ticket_property_diff_reporter_add(self): """Property diff message when ticket reporter is added.""" t = self._create_ticket_with_change({'reporter': ''}, {'reporter': 'reporter2'}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual('set to <span class="trac-author">reporter2</span>', unicode(field['rendered'])) def test_ticket_property_diff_reporter_remove(self): """Property diff message when ticket reporter is removed.""" t = self._create_ticket_with_change({'reporter': 'reporter1'}, {'reporter': ''}) req = MockRequest(self.env, args={'id': t.id}) data = self.ticket_module.process_request(req)[1] field = data['changes'][0]['fields']['reporter'] self.assertEqual('<span class="trac-author">reporter1</span> removed', unicode(field['rendered'])) def _test_invalid_cnum_raises(self, action, cnum=None): self._insert_ticket() req = MockRequest(self.env, args={'action': action, 'id': '1'}) if cnum is not None: req.args.update({'cnum': cnum}) self.assertRaises(HTTPBadRequest, self.ticket_module.process_request, req) def test_comment_history_cnum_missing_raises(self): self._test_invalid_cnum_raises('comment-history') def test_comment_history_cnum_invalid_type_raises(self): self._test_invalid_cnum_raises('comment-history', 'a') def test_comment_history_cnum_empty_raises(self): self._test_invalid_cnum_raises('comment-history', '') def test_comment_history_cnum_out_of_range(self): """Out of range cnum returns an empty history.""" self._insert_ticket() req = MockRequest(self.env, args={'action': 'comment-history', 'id': '1', 'cnum': '1'}) resp = self.ticket_module.process_request(req) self.assertEqual([], resp[1]['history']) def test_comment_diff_cnum_missing_raises(self): self._test_invalid_cnum_raises('comment-diff') def test_comment_diff_cnum_invalid_type_raises(self): self._test_invalid_cnum_raises('comment-diff', 'a') def test_comment_diff_cnum_empty_raises(self): self._test_invalid_cnum_raises('comment-diff', '') def test_comment_diff_cnum_out_of_range_raises(self): self._insert_ticket() req = MockRequest(self.env, args={'action': 'comment-diff', 'id': '1', 'cnum': '1'}) self.assertRaises(ResourceNotFound, self.ticket_module.process_request, req) def test_edit_comment_cnum_missing_raises(self): ticket = self._insert_ticket() req = MockRequest( self.env, method='POST', path_info='/ticket/%d' % ticket.id, args={'edit_comment': 'Submit changes', 'cnum_edit': '42'}) self.assertTrue(self.ticket_module.match_request(req)) with self.assertRaises(TracError) as cm: self.ticket_module.process_request(req) self.assertEqual('Comment 42 not found', unicode(cm.exception)) def test_edit_comment_validate_max_comment_size(self): """The [ticket] max_comment_size attribute is validated during ticket comment edit. """ perm_sys = PermissionSystem(self.env) perm_sys.grant_permission('user1', 'TICKET_VIEW') perm_sys.grant_permission('user1', 'TICKET_APPEND') self.env.config.set('ticket', 'max_comment_size', 5) ticket = self._insert_ticket(summary='the summary') ticket.save_changes('user1', '12345') req = MockRequest( self.env, method='POST', authname='user1', path_info='/ticket/%d' % ticket.id, args={'id': '1', 'edit_comment': True, 'cnum_edit': '1', 'edited_comment': '123456'}) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertEqual("The ticket comment is invalid: Must be less than or " "equal to 5 characters", unicode(req.chrome['warnings'][0])) def test_preview_comment_validate_max_comment_size(self): """The [ticket] max_comment_size attribute is validated during ticket comment edit preview. """ perm_sys = PermissionSystem(self.env) perm_sys.grant_permission('user1', 'TICKET_VIEW') perm_sys.grant_permission('user1', 'TICKET_APPEND') self.env.config.set('ticket', 'max_comment_size', 5) ticket = self._insert_ticket(summary='the summary') ticket.save_changes('user1', '12345') req = MockRequest( self.env, method='POST', authname='user1', path_info='/ticket/%d' % ticket.id, args={'id': '1', 'preview_comment': True, 'cnum_edit': '1', 'edited_comment': '123456'}) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertEqual("The ticket comment is invalid: Must be less than or " "equal to 5 characters", unicode(req.chrome['warnings'][0])) def _test_template_data_for_time_field(self, req, value, expected, format): self.env.config.set('ticket-custom', 'timefield', 'time') if format: self.env.config.set('ticket-custom', 'timefield.format', format) self._insert_ticket(summary='Time fields', timefield=value) self.assertEqual(value, Ticket(self.env, 1)['timefield']) self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] for f in data['fields']: if f['name'] == 'timefield': self.assertEqual(expected, f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_time_field_with_formats(self): gmt12 = timezone('GMT +12:00') req = MockRequest(self.env, method='GET', path_info='/ticket/1', tz=gmt12) value = datetime(2016, 1, 2, 23, 34, 45, tzinfo=utc) expected = user_time(req, format_datetime, value) self.assertIn('11', expected) # check 11 in hour part self._test_template_data_for_time_field(req, value, expected, None) self._test_template_data_for_time_field(req, value, expected, 'datetime') self._test_template_data_for_time_field(req, value, expected, 'relative') def test_template_data_for_time_field_with_date_format(self): value = datetime(2016, 2, 22, 22, 22, 22, tzinfo=utc) self.env.config.set('ticket-custom', 'timefield', 'time') self.env.config.set('ticket-custom', 'timefield.format', 'date') self._insert_ticket(summary='Time fields', timefield=value) self.assertEqual(value, Ticket(self.env, 1)['timefield']) gmt12 = timezone('GMT +12:00') req = MockRequest(self.env, method='GET', path_info='/ticket/1', tz=gmt12) expected = user_time(req, format_date, value) self.assertIn('23', expected) # check 23 in day part self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] for f in data['fields']: if f['name'] == 'timefield': self.assertEqual(expected, f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_invalid_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') self._insert_ticket(summary='Time fields', timefield=datetime_now(utc)) self.env.db_transaction("UPDATE ticket_custom SET value='invalid' " "WHERE ticket=1 AND name='timefield'") self.assertIsNone(Ticket(self.env, 1)['timefield']) req = MockRequest(self.env, method='GET', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] self.assertIsNone(data['ticket']['timefield']) for f in data['fields']: if f['name'] == 'timefield': self.assertEqual('', f['edit']) break else: self.fail('Missing timefield field') def test_template_data_for_invalid_time_field_on_newticket(self): self.env.config.set('ticket-custom', 'timefield', 'time') req = MockRequest(self.env, method='GET', path_info='/newticket') req.args['timefield'] = 'invalid' self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] self.assertEqual('invalid', data['ticket']['timefield']) for f in data['fields']: if f['name'] == 'timefield': self.assertEqual('invalid', f['edit']) break else: self.fail('Missing timefield field') def test_template_data_changes_for_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') dt1 = datetime(2015, 7, 8, tzinfo=utc) dt2 = datetime(2015, 12, 11, tzinfo=utc) with self.env.db_transaction: self._insert_ticket(summary='Time fields', timefield=datetime_now(utc)) self.env.db_transaction(""" UPDATE ticket_custom SET value='invalid' WHERE ticket=1 AND name='timefield' """) t = Ticket(self.env, 1) t['timefield'] = dt1 t.save_changes('anonymous') t = Ticket(self.env, 1) t['timefield'] = dt2 t.save_changes('anonymous') req = MockRequest(self.env, method='GET', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] changes = data['changes'] dt1_text = user_time(req, format_datetime, dt1) dt2_text = user_time(req, format_datetime, dt2) self.assertEqual(2, len(changes)) self.assertEqual(u'\u2192 <span class="trac-field-new">%s</span>' % dt1_text, unicode(changes[0]['fields']['timefield']['rendered'])) self.assertEqual(u'<span class="trac-field-old">%s</span> \u2192 ' u'<span class="trac-field-new">%s</span>' % (dt1_text, dt2_text), unicode(changes[1]['fields']['timefield']['rendered'])) def test_submit_with_time_field(self): self.env.config.set('ticket-custom', 'timefield', 'time') self._insert_ticket(summary='Time fields', timefield='') ticket = Ticket(self.env, 1) args_base = {'submit': '*', 'action': 'leave', 'id': '1', 'field_summary': ticket['summary'], 'field_reporter': ticket['reporter'], 'field_description': ticket['description'], 'view_time': str(to_utimestamp(ticket['changetime']))} for f in ticket.fields: args_base['field_%s' % f['name']] = ticket[f['name']] or '' args = args_base.copy() args['field_timefield'] = 'invalid datetime' req = MockRequest(self.env, method='POST', path_info='/ticket/1', args=args) self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) warnings = req.chrome['warnings'] self.assertNotEqual([], warnings) self.assertEqual(1, len(warnings)) self.assertIn('is an invalid date, or the date format is not known.', unicode(warnings[0])) ticket = Ticket(self.env, 1) self.assertIsNone(ticket['timefield']) args = args_base.copy() args['field_timefield'] = '2016-01-02T12:34:56Z' req = MockRequest(self.env, method='POST', path_info='/ticket/1', args=args) self.assertTrue(self.ticket_module.match_request(req)) self.assertRaises(RequestDone, self.ticket_module.process_request, req) ticket = Ticket(self.env, 1) self.assertEqual(datetime(2016, 1, 2, 12, 34, 56, tzinfo=utc), ticket['timefield']) def _test_render_time_field(self, format, req, value, expected): self.env.config.set('ticket-custom', 'timefield', 'time') self.env.config.set('ticket-custom', 'timefield.format', format) def timefield_text(): self.assertTrue(self.ticket_module.match_request(req)) template, data = self.ticket_module.process_request(req) content = Chrome(self.env).render_fragment(req, template, data) # select('//td[@headers="h_timefield"') replacement class TimefieldExtractor(HTMLTransform): pick_next_text = False value = '' def handle_starttag(self, tag, attrs): if tag == 'td': for name, value in attrs: if name == 'headers' and value == 'h_timefield': self.pick_next_text = True def handle_data(self, data): if self.pick_next_text: self.value += data def handle_endtag(self, tag): if self.pick_next_text: self.pick_next_text = False extractor = TimefieldExtractor(io.BytesIO()) extractor.feed(content.encode('utf-8')) return extractor.value.decode('utf-8').strip() self._insert_ticket(summary='Time fields') self.assertEqual('', timefield_text()) ticket = Ticket(self.env, 1) ticket['timefield'] = value ticket.save_changes('anonymous') self.assertEqual(expected, timefield_text()) def test_render_time_field_date(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime(2015, 7, 8, tzinfo=utc) expected = user_time(req, format_date, value) self._test_render_time_field('date', req, value, expected) def test_render_time_field_datetime(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime(2015, 7, 8, 12, 34, 56, tzinfo=utc) expected = user_time(req, format_datetime, value) self._test_render_time_field('datetime', req, value, expected) def test_render_time_field_relative(self): req = MockRequest(self.env, method='GET', path_info='/ticket/1') value = datetime_now(utc) - timedelta(days=1) self._test_render_time_field('relative', req, value, '24 hours ago') def _test_newticket_with_enum_as_custom_field(self, field_name): self.env.config.set('ticket-custom', field_name, 'text') self.env.config.set('ticket-custom', '%s.label' % field_name, '(%s)' % field_name) with self.env.db_transaction as db: if field_name in ('milestone', 'component', 'version'): db("DELETE FROM %s" % field_name) elif field_name == 'type': db("DELETE FROM enum WHERE type='ticket_type'") else: db("DELETE FROM enum WHERE type=%s", (field_name,)) tktsys = TicketSystem(self.env) tktsys.reset_ticket_fields() del tktsys.custom_fields req = MockRequest(self.env, path_info='/newticket') self.assertTrue(self.ticket_module.match_request(req)) resp = self.ticket_module.process_request(req) for field in resp[1]['fields']: if field['name'] == field_name: self.assertEqual('(%s)' % field_name, field['label']) self.assertTrue(field['custom']) self.assertFalse(field['options']) self.assertFalse(field.get('optgroups')) break else: self.fail('Missing %s in fields' % field_name) def test_newticket_with_component_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('component') def test_newticket_with_milestone_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('milestone') def test_newticket_with_priority_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('priority') def test_newticket_with_resolution_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('resolution') def test_newticket_with_severity_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('severity') def test_newticket_with_type_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('type') def test_newticket_with_version_as_custom_field(self): self._test_newticket_with_enum_as_custom_field('version') def test_add_comment_requires_ticket_append(self): """Adding a ticket comment requires TICKET_APPEND.""" ps = PermissionSystem(self.env) ps.revoke_permission('authenticated', 'TICKET_MODIFY') ps.grant_permission('user1', 'TICKET_APPEND') ps.grant_permission('user2', 'TICKET_CHGPROP') ticket = self._insert_ticket(summary='the summary') comment = 'the comment' def make_req(authname): change_time = Ticket(self.env, 1)['changetime'] return MockRequest( self.env, authname=authname, method='POST', path_info='/ticket/1', args={'comment': comment, 'action': 'leave', 'submit': True, 'view_time': unicode(to_utimestamp(change_time))}) req = make_req('user1') self.assertTrue(self.ticket_module.match_request(req)) self.assertRaises(RequestDone, self.ticket_module.process_request, req) self.assertEqual([], req.chrome['warnings']) self.assertEqual(comment, ticket.get_change(1)['fields']['comment']['new']) req = make_req('user2') self.assertTrue(self.ticket_module.match_request(req)) self.ticket_module.process_request(req) self.assertEqual(1, len(req.chrome['warnings'])) self.assertEqual("No permissions to add a comment.", unicode(req.chrome['warnings'][0])) def test_change_milestone_requires_milestone_view(self): """Changing ticket milestone requires MILESTONE_VIEW.""" perm_sys = PermissionSystem(self.env) perm_sys.revoke_permission('anonymous', 'MILESTONE_VIEW') perm_sys.grant_permission('user_w_mv', 'MILESTONE_VIEW') self._insert_ticket(summary='the summary') def make_req(authname): return MockRequest(self.env, authname=authname, method='GET', path_info='/ticket/1') def get_milestone_field(fields): for field in fields: if 'milestone' == field['name']: return field req = make_req('user') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] milestone_field = get_milestone_field(data['fields']) self.assertFalse(milestone_field['editable']) self.assertEqual([], milestone_field['optgroups'][0]['options']) self.assertEqual([], milestone_field['optgroups'][1]['options']) req = make_req('user_w_mv') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] milestone_field = get_milestone_field(data['fields']) self.assertTrue(milestone_field['editable']) self.assertEqual([], milestone_field['optgroups'][0]['options']) self.assertEqual(['milestone1', 'milestone2', 'milestone3', 'milestone4'], milestone_field['optgroups'][1]['options']) def test_newticket_has_auto_preview(self): """New ticket page has autopreview.""" req = MockRequest(self.env, method='GET', path_info='/newticket') self.assertTrue(self.ticket_module.process_request(req)) self.ticket_module.process_request(req) self.assertTrue(self._has_auto_preview(req)) def test_newticket_autopreview_disabled_when_no_workflow_actions(self): """Newticket autopreview disabled when no workflow actions.""" config = self.env.config config.remove('ticket-workflow', 'create') config.remove('ticket-workflow', 'create_and_assign') req = MockRequest(self.env, method='GET', path_info='/newticket') self.assertTrue(self.ticket_module.process_request(req)) data = self.ticket_module.process_request(req)[1] self.assertEqual([], data['action_controls']) self.assertFalse(self._has_auto_preview(req)) self.assertTrue(data['disable_submit']) def test_ticket_autopreview_disabled_when_no_workflow_actions(self): """Ticket autopreview disabled when no workflow actions.""" config = self.env.config for option in config.options('ticket-workflow'): if not option[0].startswith('leave'): config.remove('ticket-workflow', option[0]) req = MockRequest(self.env, method='GET', path_info='/ticket/1') self.assertTrue(self.ticket_module.process_request(req)) data = self.ticket_module.process_request(req)[1] self.assertEqual([], data['action_controls']) self.assertFalse(self._has_auto_preview(req)) self.assertTrue(data['disable_submit']) def test_new_ticket_ticket_edit_cc(self): """CC field can be modified for new ticket.""" PermissionSystem(self.env).grant_permission('user', 'TICKET_CREATE') req = MockRequest(self.env, authname='user', path_info='/newticket') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] cc_field = self._get_field_by_name(data, 'cc') self.assertNotIn('cc_entry', cc_field) self.assertNotIn('cc_action', cc_field) def test_existing_ticket_no_ticket_edit_cc(self): """User without TICKET_EDIT_CC can only add self to CC field.""" PermissionSystem(self.env).grant_permission('user', 'TICKET_VIEW') self._insert_ticket(reporter='reporter') req = MockRequest(self.env, authname='user', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] cc_field = self._get_field_by_name(data, 'cc') self.assertIn('cc_entry', cc_field) self.assertEqual('user', cc_field['cc_entry']) self.assertIn('cc_action', cc_field) self.assertEqual('add', cc_field['cc_action']) def test_existing_ticket_ticket_edit_cc(self): """User with TICKET_EDIT_CC can modify the CC field.""" ps = PermissionSystem(self.env) for perm in ('TICKET_EDIT_CC', 'TICKET_VIEW'): ps.grant_permission('user', perm) self._insert_ticket(reporter='reporter') req = MockRequest(self.env, authname='user', path_info='/ticket/1') self.assertTrue(self.ticket_module.match_request(req)) data = self.ticket_module.process_request(req)[1] cc_field = self._get_field_by_name(data, 'cc') self.assertNotIn('cc_entry', cc_field) self.assertNotIn('cc_action', cc_field) def test_action_side_effects_applied(self): self.env.config.set('ticket', 'workflow', 'ConfigurableTicketWorkflow, ' 'MockTicketOperation') ticket = self._insert_ticket( reporter='reporter', summary='the summary', status='new') change_time = Ticket(self.env, ticket.id)['changetime'] view_time = str(to_utimestamp(change_time)) req = MockRequest( self.env, method='POST', path_info='/ticket/1', args={'submit': True, 'action': 'mock', 'id': '1', 'view_time': view_time}) operation = self.mock_ticket_operation(self.env) self.assertEqual(0, operation.side_effect_count) self.assertTrue(self.ticket_module.match_request(req)) with self.assertRaises(RequestDone): self.ticket_module.process_request(req) self.assertEqual(1, operation.side_effect_count) self.assertIn(('DEBUG', "Side effect for MockTicketOperation"), self.env.log_messages)
class PermissionAdminPanelTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.panel = PermissionAdminPanel(self.env) def tearDown(self): self.env.reset_db() def _test_invalid_user(self, subject='', action='', target='', group=''): req = MockRequest(self.env, method='POST', args={ 'add': True, 'subject': subject, 'target': target, 'group': group, 'action': action }) with self.assertRaises(TracError) as cm: self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertEqual( "All upper-cased tokens are reserved for permission " "names.", unicode(cm.exception)) def test_grant_permission_invalid_username(self): self._test_invalid_user(subject='USER', action='WIKI_VIEW') def test_add_subject_to_group_invalid_subject_or_group(self): self._test_invalid_user(subject='user', group='GROUP') self._test_invalid_user(subject='USER', group='group') def test_copy_permissions_invalid_subject_or_target(self): self._test_invalid_user(subject='user1', target='USER2') self._test_invalid_user(subject='USER1', target='user2') def test_grant_permission_action_already_granted(self): """Warning is added when granting an action that has already been granted. """ req = MockRequest(self.env, method='POST', args={ 'add': True, 'subject': 'anonymous', 'action': 'WIKI_VIEW' }) with self.assertRaises(RequestDone): self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertIn("The user anonymous already has permission WIKI_VIEW.", req.chrome['warnings']) def test_grant_permission_group_already_granted(self): """Warning is added when adding a subject to a group and the subject is already a member of the group. """ PermissionSystem(self.env).grant_permission('user1', 'group1') req = MockRequest(self.env, method='POST', args={ 'add': True, 'subject': 'user1', 'group': 'group1' }) with self.assertRaises(RequestDone): self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertIn("The user user1 is already in the group group1.", req.chrome['warnings']) def test_grant_permission_with_permission_grant(self): """User can only grant permissions they possess.""" ps = PermissionSystem(self.env) ps.grant_permission('user1', 'PERMISSION_GRANT') ps.grant_permission('group1', 'WIKI_ADMIN') req = MockRequest(self.env, method='POST', authname='user1', args={ 'add': True, 'subject': 'user2', 'group': 'group1' }) with self.assertRaises(PermissionError) as cm: self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertEqual( "The subject <strong>user2</strong> was not added " "to the group <strong>group1</strong>. The " "group has <strong>WIKI_ADMIN</strong> permission " "and you cannot grant permissions you don't possess.", unicode(cm.exception)) def test_grant_undefined_permission_with_permission_grant(self): """Undefined permission is granted without checking granter.""" ps = PermissionSystem(self.env) ps.grant_permission('user1', 'PERMISSION_GRANT') self.env.db_transaction(""" INSERT INTO permission VALUES ('group1', 'TEST_PERM') """) req = MockRequest(self.env, method='POST', authname='user1', args={ 'add': True, 'subject': 'user2', 'group': 'group1' }) with self.assertRaises(RequestDone): self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertIn('TEST_PERM', ps.get_user_permissions('group1', undefined=True)) self.assertIn('user2', ps.get_groups_dict()['group1']) def test_copy_permissions_to_subject(self): """Copy permissions to subject. Undefined actions are skipped. """ ps = PermissionSystem(self.env) ps.grant_permission('user1', 'WIKI_VIEW') ps.grant_permission('user1', 'TICKET_VIEW') self.env.db_transaction(""" INSERT INTO permission VALUES ('user1', 'TEST_PERM') """) req = MockRequest(self.env, method='POST', args={ 'copy': True, 'subject': 'user1', 'target': 'user2' }) with self.assertRaises(RequestDone): self.panel.render_admin_panel(req, 'general', 'perm', None) self.assertEqual(['TICKET_VIEW', 'WIKI_VIEW'], ps.get_users_dict().get('user2')) self.assertEqual(2, len(req.chrome['notices'])) self.assertIn( "The subject user2 has been granted the permission " "TICKET_VIEW.", req.chrome['notices']) self.assertIn( "The subject user2 has been granted the permission " "WIKI_VIEW.", req.chrome['notices']) self.assertIn(("WARNING", "Skipped granting TEST_PERM to user2: " "permission unavailable."), self.env.log_messages) self.assertIn(("INFO", "Granted permission for TICKET_VIEW to user2"), self.env.log_messages) self.assertIn(("INFO", "Granted permission for TICKET_VIEW to user2"), self.env.log_messages)
class _BaseTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(enable=['trac.*', 'acct_mgr.*']) self.env.config.set('account-manager', 'password_store', 'SessionStore') self.store = SessionStore(self.env) def test_get_users(self): with self.env.db_transaction as db: db.executemany(""" INSERT INTO session_attribute (sid,authenticated,name,value) VALUES (%s,1,'password',%s) """, [('a', 'a'), ('b', 'b'), ('c', 'c')]) self.assertEqual(set(['a', 'b', 'c']), set(self.store.get_users())) def test_has_user(self): self.env.db_transaction(""" INSERT INTO session_attribute (sid,authenticated,name,value) VALUES (%s,'1','password',%s) """, ('bar', 'bar')) self.assertFalse(self.store.has_user('foo')) self.assertTrue(self.store.has_user('bar')) def test_create_user(self): self.assertFalse(self.store.has_user('foo')) self.store.set_password('foo', 'password') self.assertTrue(self.store.has_user('foo')) def test_overwrite(self): self.assertTrue(self.store.set_password('foo', 'pass1')) self.assertFalse(self.store.set_password('foo', 'pass2', overwrite=False)) self.assertTrue(self.store.check_password('foo', 'pass1')) self.assertTrue(self.store.set_password('bar', 'pass', overwrite=False)) def test_update_password(self): self.store.set_password('foo', 'pass1') self.assertFalse(self.store.check_password('foo', 'pass2')) self.store.set_password('foo', 'pass2') self.assertTrue(self.store.check_password('foo', 'pass2')) self.store.set_password('foo', 'pass3', 'pass2') self.assertTrue(self.store.check_password('foo', 'pass3')) def test_delete_user(self): self.store.set_password('foo', 'password') self.assertTrue(self.store.has_user('foo')) self.assertTrue(self.store.delete_user('foo')) self.assertFalse(self.store.has_user('foo')) def test_delete_nonexistant_user(self): self.assertFalse(self.store.has_user('foo')) self.assertFalse(self.store.delete_user('foo')) def test_unicode_username_and_password(self): username = u'\u4e60' password = u'\u4e61' self.store.set_password(username, password) self.assertTrue(self.store.check_password(username, password))