Example #1
0
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)
Example #3
0
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)
Example #4
0
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])
Example #5
0
File: api.py Project: pkdevbox/trac
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'))
Example #6
0
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)
Example #7
0
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)
Example #8
0
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)
Example #9
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
Example #10
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 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'))
Example #11
0
File: env.py Project: zxfly/trac
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)
Example #12
0
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))
Example #13
0
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)
Example #14
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):
        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)
Example #15
0
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)
Example #16
0
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'])
Example #17
0
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])
Example #18
0
File: model.py Project: ohanar/trac
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)
Example #19
0
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)
Example #20
0
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'])
Example #21
0
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'))
Example #22
0
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&amp;reporter=user1">User One</a>',
            unicode(data['reporter_link']))
        self.assertEqual(
            u'<a class="trac-author-user" href="/trac.cgi/query?'
            u'status=!closed&amp;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]))
Example #23
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
Example #24
0
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'))
Example #25
0
File: perm.py Project: hanotch/trac
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)
Example #26
0
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())
Example #27
0
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'))
Example #28
0
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])
Example #29
0
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")))
Example #30
0
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)
Example #31
0
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)
Example #32
0
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)
Example #33
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 = 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'"))
Example #34
0
File: api.py Project: pkdevbox/trac
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)
Example #35
0
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&amp;reporter=user1">User One</a>',
                         unicode(data['reporter_link']))
        self.assertEqual(u'<a class="trac-author-user" href="/trac.cgi/query?'
                         u'status=!closed&amp;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)
Example #36
0
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)
Example #37
0
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))