Example #1
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'"))
Example #2
0
File: model.py Project: t2y/trac
class VersionTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)

    def tearDown(self):
        self.env.reset_db()

    def test_exists_negative(self):
        def get_fake_version():
            return Version(self.env, "-1")
        self.assertRaises(TracError, get_fake_version)

    def test_exists(self):
        """
        http://trac.edgewall.org/ticket/4247
        """
        for v in Version.select(self.env):
            self.assertEqual(v.exists, True)

    def test_create_and_update(self):
        version = Version(self.env)
        version.name = 'Test'
        version.insert()

        self.assertEqual([('Test', 0, None)], self.env.db_query(
            "SELECT name, time, description FROM version WHERE name='Test'"))

        # Use the same model object to update the version
        version.description = 'Some text'
        version.update()
        self.assertEqual([('Test', 0, 'Some text')], self.env.db_query(
            "SELECT name, time, description FROM version WHERE name='Test'"))
Example #3
0
class ComponentTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)

    def tearDown(self):
        self.env.reset_db()

    def test_exists_negative(self):
        def get_fake_component():
            return Component(self.env, "Shrubbery")
        self.assertRaises(TracError, get_fake_component)

    def test_exists(self):
        """
        http://trac.edgewall.org/ticket/4247
        """
        for c in Component.select(self.env):
            self.assertEqual(c.exists, True)

    def test_create_and_update(self):
        component = Component(self.env)
        component.name = 'Test'
        component.insert()

        self.assertEqual([('Test', None, None)], self.env.db_query("""
            SELECT name, owner, description FROM component
            WHERE name='Test'"""))

        # Use the same model object to update the component
        component.owner = 'joe'
        component.update()
        self.assertEqual([('Test', 'joe', None)], self.env.db_query(
            "SELECT name, owner, description FROM component WHERE name='Test'"))
Example #4
0
class VersionTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)

    def tearDown(self):
        self.env.reset_db()

    def test_exists_negative(self):
        def get_fake_version():
            return Version(self.env, "-1")
        self.assertRaises(TracError, get_fake_version)

    def test_exists(self):
        """
        http://trac.edgewall.org/ticket/4247
        """
        for v in Version.select(self.env):
            self.assertEqual(v.exists, True)

    def test_create_and_update(self):
        version = Version(self.env)
        version.name = 'Test'
        version.insert()

        self.assertEqual([('Test', 0, None)], self.env.db_query(
            "SELECT name, time, description FROM version WHERE name='Test'"))

        # Use the same model object to update the version
        version.description = 'Some text'
        version.update()
        self.assertEqual([('Test', 0, 'Some text')], self.env.db_query(
            "SELECT name, time, description FROM version WHERE name='Test'"))
Example #5
0
File: model.py Project: t2y/trac
class ComponentTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)

    def tearDown(self):
        self.env.reset_db()

    def test_exists_negative(self):
        def get_fake_component():
            return Component(self.env, "Shrubbery")
        self.assertRaises(TracError, get_fake_component)

    def test_exists(self):
        """
        http://trac.edgewall.org/ticket/4247
        """
        for c in Component.select(self.env):
            self.assertEqual(c.exists, True)

    def test_create_and_update(self):
        component = Component(self.env)
        component.name = 'Test'
        component.insert()

        self.assertEqual([('Test', None, None)], self.env.db_query("""
            SELECT name, owner, description FROM component
            WHERE name='Test'"""))

        # Use the same model object to update the component
        component.owner = 'joe'
        component.update()
        self.assertEqual([('Test', 'joe', None)], self.env.db_query(
            "SELECT name, owner, description FROM component WHERE name='Test'"))
Example #6
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 #7
0
class DatabaseManagerTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        self.dbm = DatabaseManager(self.env)

    def tearDown(self):
        self.env.reset_db()

    def test_destroy_db(self):
        """Database doesn't exist after calling destroy_db."""
        self.env.db_query("SELECT name FROM system")
        self.assertIsNotNone(self.dbm._cnx_pool)
        self.dbm.destroy_db()
        self.assertIsNone(self.dbm._cnx_pool)  # No connection pool
        self.assertFalse(self.dbm.db_exists())

    def test_get_column_names(self):
        """Get column names for the default database."""
        for table in default_schema:
            column_names = [col.name for col in table.columns]
            self.assertEqual(column_names,
                             self.dbm.get_column_names(table.name))

    def test_get_default_database_version(self):
        """Get database version for the default entry named
        `database_version`.
        """
        self.assertEqual(default_db_version, self.dbm.get_database_version())

    def test_get_table_names(self):
        """Get table names for the default database."""
        self.assertEqual(sorted(table.name for table in default_schema),
                         sorted(self.dbm.get_table_names()))

    def test_set_default_database_version(self):
        """Set database version for the default entry named
        `database_version`.
        """
        new_db_version = default_db_version + 1
        self.dbm.set_database_version(new_db_version)
        self.assertEqual(new_db_version, self.dbm.get_database_version())

        # Restore the previous version to avoid destroying the database
        # on teardown
        self.dbm.set_database_version(default_db_version)
        self.assertEqual(default_db_version, self.dbm.get_database_version())

    def test_set_get_plugin_database_version(self):
        """Get and set database version for an entry with an
        arbitrary name.
        """
        name = 'a_trac_plugin_version'
        db_ver = 1

        self.assertFalse(self.dbm.get_database_version(name))
        self.dbm.set_database_version(db_ver, name)
        self.assertEqual(db_ver, self.dbm.get_database_version(name))
Example #8
0
class SystemInfoTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def test_database_backend_version(self):
        """Database backend is returned in system_info."""
        # closes the pooled connections to use `DatabaseManager.shutdown()`
        # instead of `env.shutdown()` to avoid `log.shutdown()`
        DatabaseManager(self.env).shutdown()
        info_before = self.env.system_info
        self.env.db_query("SELECT 42")  # just connects database
        info_after = self.env.system_info

        def get_info(system_info, name):
            for info in system_info:
                if info[0] == name:
                    return info[1]
            self.fail('Missing %r' % name)

        if self.env.dburi.startswith('mysql'):
            self.assertRegexpMatches(
                get_info(info_before, 'MySQL'), r'^server: \(not-connected\), '
                r'client: "\d+(\.\d+)+([-.].+)?", '
                r'thread-safe: True$')
            self.assertRegexpMatches(
                get_info(info_after, 'MySQL'),
                r'^server: "\d+(\.\d+)+([-.].+)?", '
                r'client: "\d+(\.\d+)+([-.].+)?", '
                r'thread-safe: True$')
            self.assertRegexpMatches(get_info(info_before, 'pymysql'),
                                     r'^\d+(\.\d+)+$')
            self.assertRegexpMatches(get_info(info_after, 'pymysql'),
                                     r'^\d+(\.\d+)+$')
        elif self.env.dburi.startswith('postgres'):
            self.assertRegexpMatches(
                get_info(info_before, 'PostgreSQL'),
                r'^server: \(not-connected\), '
                r'client: (\d+(\.\d+)+|\(unknown\))$')
            self.assertRegexpMatches(
                get_info(info_after, 'PostgreSQL'), r'^server: \d+(\.\d+)+, '
                r'client: (\d+(\.\d+)+|\(unknown\))$')
            self.assertRegexpMatches(get_info(info_before, 'psycopg2'),
                                     r'^\d+(\.\d+)+$')
            self.assertRegexpMatches(get_info(info_after, 'psycopg2'),
                                     r'^\d+(\.\d+)+$')
        elif self.env.dburi.startswith('sqlite'):
            self.assertEqual(info_before, info_after)
            self.assertRegexpMatches(get_info(info_before, 'SQLite'),
                                     r'^\d+(\.\d+)+$')
            self.assertRegexpMatches(get_info(info_before, 'pysqlite'),
                                     r'^\d+(\.\d+)+$')
        else:
            self.fail("Unknown value for dburi %s" % self.env.dburi)
Example #9
0
File: api.py Project: ohanar/trac
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])
Example #10
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])
Example #11
0
File: api.py Project: ohanar/trac
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 #12
0
File: env.py Project: miihael/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'))
Example #13
0
File: auth.py Project: zxfly/trac
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 #14
0
class SessionTestCase(unittest.TestCase):
    """Unit tests for the persistent session support."""

    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def test_new_session(self):
        """
        Verify that a session cookie gets sent back to the client for a new
        session.
        """
        cookie = Cookie()
        req = Mock(incookie=Cookie(), outcookie=cookie, authname='anonymous',
                   base_path='/')
        session = Session(self.env, req)
        self.assertEqual(session.sid, cookie['trac_session'].value)
        self.assertEqual(0, self.env.db_query(
                "SELECT COUNT(*) FROM session")[0][0])

    def test_anonymous_session(self):
        """
        Verify that session variables are stored in the database.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        outcookie = Cookie()
        req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                   outcookie=outcookie)
        session = Session(self.env, req)
        self.assertEquals('123456', session.sid)
        self.failIf(outcookie.has_key('trac_session'))

    def test_authenticated_session(self):
        """
        Verifies that a session cookie does not get used if the user is logged
        in, and that Trac expires the cookie.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        outcookie = Cookie()
        req = Mock(authname='john', base_path='/', incookie=incookie,
                   outcookie=outcookie)
        session = Session(self.env, req)
        self.assertEqual('john', session.sid)
        session['foo'] = 'bar'
        session.save()
        self.assertEquals(0, outcookie['trac_session']['expires'])

    def test_session_promotion(self):
        """
        Verifies that an existing anonymous session gets promoted to an
        authenticated session when the user logs in.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='john', base_path='/', incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            self.assertEqual('john', session.sid)
            session.save()

        self.assertEqual([('john', 1)], self.env.db_query(
            "SELECT sid, authenticated FROM session"))

    def test_new_session_promotion(self):
        """
        Verifies that even without a preexisting anonymous session,
        an authenticated session will be created when the user logs in.
        (same test as above without the initial INSERT)
        """
        with self.env.db_transaction as db:
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='john', base_path='/', incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            self.assertEqual('john', session.sid)
            session.save()

        self.assertEqual([('john', 1)], self.env.db_query(
                "SELECT sid, authenticated FROM session"))

    def test_add_anonymous_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an anonymous session.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()
        
        self.assertEqual('bar', self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0][0])

    def test_modify_anonymous_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES 
                ('123456', 0, 'foo', 'bar')
                """)
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()
        
        self.assertEqual('baz', self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0][0])

    def test_delete_anonymous_session_var(self):
        """
        Verify that modifying a variable updates the 'session' table accordingly
        for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES 
                ('123456', 0, 'foo', 'bar')
                """)
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()
        
        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='123456' AND name='foo'
            """)[0][0])

    def test_purge_anonymous_session(self):
        """
        Verify that old sessions get purged.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)", (0,))
            db("INSERT INTO session VALUES ('987654', 0, %s)",
               (int(time.time() - PURGE_AGE - 3600),))
            db("""
                INSERT INTO session_attribute
                VALUES ('987654', 0, 'foo', 'bar')
                """)
            
            # We need to modify a different session to trigger the purging
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            session['foo'] = 'bar'
            session.save()
        
        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='987654' AND authenticated=0
            """)[0][0])

    def test_delete_empty_session(self):
        """
        Verify that a session gets deleted when it doesn't have any data except
        for the 'last_visit' timestamp.
        """
        now = time.time()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)",
               (int(now - UPDATE_INTERVAL - 3600),))
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            del session['foo']
            session.save()

        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='123456' AND authenticated=0
            """)[0][0])

    def test_change_anonymous_session(self):
        """
        Verify that changing from one anonymous session to an inexisting
        anonymous session creates the new session and doesn't carry over
        variables from the previous session.
        """

        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        self.assertEqual({'foo': 'bar'}, session)
        
        session.get_session('7890')
        session['baz'] = 'moo'
        session.save()
        self.assertEqual({'baz': 'moo'}, session)

        with self.env.db_query as db:
            self.assertEqual(1, db("""
                SELECT COUNT(*) FROM session
                WHERE sid='7890' AND authenticated=0
                """)[0][0])
            self.assertEqual([('baz', 'moo')], db("""
                SELECT name, value FROM session_attribute
                WHERE sid='7890' AND authenticated=0
                """))

    def test_add_authenticated_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an authenticated session.
        """
        req = Mock(authname='john', base_path='/', incookie=Cookie())
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()
        
        self.assertEqual('bar', self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_modify_authenticated_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

            req = Mock(authname='john', base_path='/', incookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual('baz', self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_authenticated_session_independence_var(self):
        """
        Verify that an anonymous session with the same name as an authenticated
        session doesn't interfere with the latter.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

        self.assertEqual('bar', self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)[0][0])

        incookie = Cookie()
        incookie['trac_session'] = 'john'
        req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        self.assert_('foo' not in session)
        session['foo'] = 'baz'
        session.save()

        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('bar', rows[0][0])
        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=0 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('baz', rows[0][0])

    def test_delete_authenticated_session_var(self):
        """
        Verify that deleting a variable updates the 'session' table accordingly
        for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')")

            req = Mock(authname='john', base_path='/', incookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_update_session(self):
        """
        Verify that accessing a session after one day updates the sessions 
        'last_visit' variable so that the session doesn't get purged.
        """
        now = time.time()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 1)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='anonymous', base_path='/', incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            session['modified'] = True
            session.save() # updating does require modifications

            self.assertEqual(PURGE_AGE, outcookie['trac_session']['expires'])

        self.assertAlmostEqual(now, int(self.env.db_query("""
            SELECT last_visit FROM session
            WHERE sid='123456' AND authenticated=0
            """)[0][0]), -1)

    def test_modify_detached_session(self):
        """
        Verify that modifying a variable in a session not associated with a
        request updates the database accordingly.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')")

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual('baz', self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_delete_detached_session_var(self):
        """
        Verify that removing a variable in a session not associated with a
        request deletes the variable from the database.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')")

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()
         
        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_session_set(self):
        """Verify that setting a variable in a session to the default value
        removes it from the session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')")

        session = DetachedSession(self.env, 'john')
        self.assertEqual('bar', session['foo'])
            
        # Setting the variable to the default value removes the variable
        with self.env.db_transaction as db:
            session.set('foo', 'default', 'default')
            session.save()
        self.assertEqual(0, self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])
        
        # Setting the variable to a value different from the default sets it
        with self.env.db_transaction as db:
            session.set('foo', 'something', 'default')
            session.save()
        self.assertEqual('something', self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])
        
    def test_session_admin_list(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        # Verify the empty case
        self.assertRaises(StopIteration, sess_admin._get_list([]).next)

        self.assertEqual([i for i in sess_admin._get_list(['authenticated'])],
                         auth_list)
        self.assertEqual([i for i in sess_admin._get_list(['anonymous'])],
                         anon_list)
        self.assertEqual([i for i in sess_admin._get_list(['*'])], all_list)
        self.assertEqual([i for i in sess_admin._get_list(['name00'])][0],
                         auth_list[0])
        self.assertEqual([i for i in sess_admin._get_list(['name10:0'])][0],
                         anon_list[0])
        self.assertEqual([i for i in sess_admin._get_list(['name00', 'name01',
                                                           'name02'])],
                         all_list[:3])
            
    def test_session_admin_add(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        self.assertRaises(Exception, sess_admin._do_add, 'name00')
        sess_admin._do_add('john')
        result = get_session_info(self.env, 'john')
        self.assertEqual(result, ('john', None, None))
        sess_admin._do_add('john1', 'John1')
        result = get_session_info(self.env, 'john1')
        self.assertEqual(result, ('john1', 'John1', None))
        sess_admin._do_add('john2', 'John2', '*****@*****.**')
        result = get_session_info(self.env, 'john2')
        self.assertEqual(result, ('john2', 'John2', '*****@*****.**'))

    def test_session_admin_set(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        self.assertRaises(TracError, sess_admin._do_set, 'name', 'nothere',
                          'foo')
        sess_admin._do_set('name', 'name00', 'john')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, ('name00', 'john', 'val00'))
        sess_admin._do_set('email', 'name00', '*****@*****.**')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, ('name00', 'john', '*****@*****.**'))

    def test_session_admin_delete(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        sess_admin._do_delete('name00')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, (None, None, None))
        sess_admin._do_delete('nothere')
        result = get_session_info(self.env, 'nothere')
        self.assertEqual(result, (None, None, None))
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin._do_delete('anonymous')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list)

    def test_session_admin_purge(self):
        sess_admin = SessionAdmin(self.env)

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-02')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list)
        result = get_session_info(self.env, anon_list[0][0])
        self.assertEqual(result, ('name10', 'val10', 'val10'))
        result = get_session_info(self.env, anon_list[1][0])
        self.assertEqual(result, ('name11', 'val11', 'val11'))

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-12')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list[1:])
        rows = self.env.db_query("""
            SELECT name, value FROM session_attribute WHERE sid = %s
            """, (anon_list[0][0],))
        self.assertEqual([], rows)
        result = get_session_info(self.env, anon_list[1][0])
        self.assertEqual(result, ('name11', 'val11', 'val11'))
Example #15
0
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, db):
                return True

            def upgrade_environment(self, db):
                insert_value('value1', 1)

        class Participant2(Component):
            implements(IEnvironmentSetupParticipant)

            def environment_created(self):
                pass

            def environment_needs_upgrade(self, db):
                return True

            def upgrade_environment(self, db):
                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_needs_upgrade_legacy_participant(self):
        """For backward compatibility with plugin, environment_needs_upgrade
        with a `db` argument is deprecated but still allowed."""
        participants = self.env.setup_participants
        needs_upgrade = self.env.needs_upgrade()

        class LegacyParticipant(Component):
            implements(IEnvironmentSetupParticipant)

            def environment_created(self):
                pass

            def environment_needs_upgrade(self, db):
                return True

            def upgrade_environment(self, db):
                pass

        self.env.enable_component(LegacyParticipant)

        self.assertFalse(needs_upgrade)
        self.assertEqual(
            len(participants) + 1, len(self.env.setup_participants))
        self.assertTrue(self.env.needs_upgrade())

    def test_upgrade_legacy_participant(self):
        """For backward compatibility with plugin, upgrade with a `db`
        argument is deprecated but still allowed."""
        participants = self.env.setup_participants

        class LegacyParticipant(Component):
            implements(IEnvironmentSetupParticipant)

            def environment_created(self):
                pass

            def environment_needs_upgrade(self, db):
                return True

            def upgrade_environment(self, db):
                pass

        self.env.enable_component(LegacyParticipant)

        self.assertEqual(
            len(participants) + 1, len(self.env.setup_participants))
        self.assertTrue(self.env.needs_upgrade())
        self.assertTrue(self.env.upgrade())
Example #16
0
class PostgresConnectionTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()
        self.schema = [
            Table('test_simple', key='id')[Column('id', auto_increment=True),
                                           Column('username'),
                                           Column('email'),
                                           Column('enabled', type='int'),
                                           Column('extra'),
                                           Index(['username'], unique=True),
                                           Index(['email'], unique=False), ],
            Table('test_composite',
                  key=['id',
                       'name'])[Column('id', type='int'),
                                Column('name'),
                                Column('value'),
                                Column('enabled', type='int'),
                                Index(['name', 'value'], unique=False),
                                Index(['enabled', 'name'], unique=True), ],
        ]
        self.dbm = DatabaseManager(self.env)
        self.dbm.drop_tables(self.schema)
        self.dbm.create_tables(self.schema)
        self.dbm.insert_into_tables([
            ('test_simple', ('username', 'email', 'enabled'),
             [('joe', '*****@*****.**', 1), (u'joé', '*****@*****.**', 0)]),
            ('test_composite', ('id', 'name', 'value', 'enabled'),
             [(1, 'foo', '42', 1), (1, 'bar', '42', 1), (2, 'foo', '43', 0),
              (2, 'bar', '43', 0)]),
        ])

    def tearDown(self):
        DatabaseManager(self.env).drop_tables(self.schema)
        self.env.reset_db()

    def _drop_column(self, table, column):
        with self.env.db_transaction as db:
            db.drop_column(table, column)

    def _get_indices(self, table):
        with self.env.db_query:
            tab_oid = self._query(
                """
                SELECT tab.oid FROM pg_class tab
                INNER JOIN pg_namespace ns ON
                    ns.oid = tab.relnamespace AND
                    ns.nspname = ANY (current_schemas(false))
                WHERE tab.relname=%s AND tab.relkind = 'r'
                """, table)[0][0]
            column_names = self._query(
                """
                SELECT attnum, attname FROM pg_attribute
                WHERE attrelid=%s AND attnum >= 0 AND NOT attisdropped
                """, tab_oid)
            column_names = dict((row[0], row[1]) for row in column_names)
            indices = self._query(
                """
                SELECT ind.relname, d.indisprimary, d.indisunique, d.indkey
                FROM pg_index d
                INNER JOIN pg_class ind ON
                    d.indexrelid = ind.oid AND ind.relkind = 'i'
                WHERE d.indrelid=%s
                """, tab_oid)
            results = {}
            for index, pk, unique, indkey in indices:
                columns = [column_names[int(i)] for i in indkey.split()]
                results[index] = {
                    'pk': bool(pk),
                    'unique': bool(unique),
                    'columns': columns
                }
        return results

    def _query(self, stmt, *args):
        return self.env.db_query(stmt, args)

    def test_remove_simple_keys(self):
        indices_0 = self._get_indices('test_simple')
        self.assertEqual([
            'test_simple_email_idx', 'test_simple_pkey',
            'test_simple_username_idx'
        ], sorted(indices_0))
        self.assertEqual({
            'pk': False,
            'unique': True,
            'columns': ['username']
        }, indices_0['test_simple_username_idx'])
        self.assertEqual({
            'pk': True,
            'unique': True,
            'columns': ['id']
        }, indices_0['test_simple_pkey'])
        self.assertEqual({
            'pk': False,
            'unique': False,
            'columns': ['email']
        }, indices_0['test_simple_email_idx'])

        self._drop_column('test_simple', 'enabled')
        self.assertEqual(indices_0, self._get_indices('test_simple'))

        self._drop_column('test_simple', 'username')
        indices_1 = self._get_indices('test_simple')
        self.assertEqual(['test_simple_email_idx', 'test_simple_pkey'],
                         sorted(indices_1))

        self._drop_column('test_simple', 'email')
        indices_2 = self._get_indices('test_simple')
        self.assertEqual(['test_simple_pkey'], sorted(indices_2))

        self._drop_column('test_simple', 'id')
        indices_3 = self._get_indices('test_simple')
        self.assertEqual({}, indices_3)

    def test_remove_composite_keys(self):
        indices_0 = self._get_indices('test_composite')
        self.assertEqual([
            'test_composite_enabled_name_idx', 'test_composite_name_value_idx',
            'test_composite_pk'
        ], sorted(indices_0))
        self.assertEqual(
            {
                'pk': False,
                'unique': False,
                'columns': ['name', 'value']
            }, indices_0['test_composite_name_value_idx'])
        self.assertEqual(
            {
                'pk': False,
                'unique': True,
                'columns': ['enabled', 'name']
            }, indices_0['test_composite_enabled_name_idx'])
        self.assertEqual(
            {
                'pk': True,
                'unique': True,
                'columns': ['id', 'name']
            }, indices_0['test_composite_pk'])

        self._drop_column('test_composite', 'id')
        indices_1 = self._get_indices('test_composite')
        self.assertEqual([
            'test_composite_enabled_name_idx', 'test_composite_name_value_idx'
        ], sorted(indices_1))
        self.assertEqual(indices_0['test_composite_name_value_idx'],
                         indices_1['test_composite_name_value_idx'])
        self.assertEqual(indices_0['test_composite_enabled_name_idx'],
                         indices_1['test_composite_enabled_name_idx'])
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY name, value, enabled""")
        self.assertEqual([('bar', '42', 1), ('bar', '43', 0), ('foo', '42', 1),
                          ('foo', '43', 0)], rows)

        self._drop_column('test_composite', 'name')
        self.assertEqual({}, self._get_indices('test_composite'))
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY value, enabled""")
        self.assertEqual([('42', 1), ('42', 1), ('43', 0), ('43', 0)], rows)
Example #17
0
class SQLiteConnectionTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()
        self.schema = [
            Table('test_simple', key='id')[Column('id', auto_increment=True),
                                           Column('username'),
                                           Column('email'),
                                           Column('enabled', type='int'),
                                           Column('extra'),
                                           Index(['username'], unique=True),
                                           Index(['email'], unique=False), ],
            Table('test_composite',
                  key=['id',
                       'name'])[Column('id', type='int'),
                                Column('name'),
                                Column('value'),
                                Column('enabled', type='int'),
                                Index(['name', 'value'], unique=False),
                                Index(['name', 'enabled'], unique=True), ],
        ]
        self.dbm = DatabaseManager(self.env)
        self.dbm.drop_tables(self.schema)
        self.dbm.create_tables(self.schema)
        self.dbm.insert_into_tables([
            ('test_simple', ('username', 'email', 'enabled'),
             [('joe', '*****@*****.**', 1), (u'joé', '*****@*****.**', 0)]),
            ('test_composite', ('id', 'name', 'value', 'enabled'),
             [(1, 'foo', '42', 1), (1, 'bar', '42', 1), (2, 'foo', '43', 0),
              (2, 'bar', '43', 0)]),
        ])

    def tearDown(self):
        DatabaseManager(self.env).drop_tables(self.schema)
        self.env.reset_db()

    def _table_info(self, table):
        names = ('column', 'type', 'notnull', 'default', 'pk')
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("PRAGMA table_info(%s)" % db.quote(table))
            return [dict(zip(names, row[1:6])) for row in cursor]

    def _index_info(self, table):
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("PRAGMA index_list(%s)" % db.quote(table))
            results = {row[1]: {'unique': row[2]} for row in cursor}
            for index, info in results.iteritems():
                cursor.execute("PRAGMA index_info(%s)" % db.quote(index))
                info['columns'] = [row[2] for row in cursor]
        return results

    def _drop_column(self, table, column):
        with self.env.db_transaction as db:
            db.drop_column(table, column)

    def _query(self, stmt, *args):
        return self.env.db_query(stmt, args)

    def test_remove_simple_keys(self):
        coldef = {
            'id': {
                'column': 'id',
                'type': 'integer',
                'notnull': 0,
                'default': None,
                'pk': 1
            },
            'username': {
                'column': 'username',
                'type': 'text',
                'notnull': 0,
                'default': None,
                'pk': 0
            },
            'email': {
                'column': 'email',
                'type': 'text',
                'notnull': 0,
                'default': None,
                'pk': 0
            },
            'enabled': {
                'column': 'enabled',
                'type': 'integer',
                'notnull': 0,
                'default': None,
                'pk': 0
            },
            'extra': {
                'column': 'extra',
                'type': 'text',
                'notnull': 0,
                'default': None,
                'pk': 0
            },
        }
        columns_0 = self._table_info('test_simple')
        self.assertEqual([
            coldef['id'], coldef['username'], coldef['email'],
            coldef['enabled'], coldef['extra']
        ], columns_0)
        indices_0 = self._index_info('test_simple')
        self.assertEqual(['test_simple_email_idx', 'test_simple_username_idx'],
                         sorted(indices_0))

        self._drop_column('test_simple', 'extra')
        columns_1 = self._table_info('test_simple')
        indices_1 = self._index_info('test_simple')
        self.assertEqual([
            coldef['id'], coldef['username'], coldef['email'],
            coldef['enabled']
        ], columns_1)
        self.assertEqual(indices_1, indices_0)

        self._drop_column('test_simple', 'id')
        columns_2 = self._table_info('test_simple')
        indices_2 = self._index_info('test_simple')
        self.assertEqual(
            [coldef['username'], coldef['email'], coldef['enabled']],
            columns_2)
        self.assertEqual(indices_2, indices_0)

        self._drop_column('test_simple', 'username')
        columns_3 = self._table_info('test_simple')
        indices_3 = self._index_info('test_simple')
        self.assertEqual([coldef['email'], coldef['enabled']], columns_3)
        self.assertEqual(['test_simple_email_idx'], sorted(indices_3))

        self._drop_column('test_simple', 'email')
        columns_4 = self._table_info('test_simple')
        indices_4 = self._index_info('test_simple')
        self.assertEqual([coldef['enabled']], columns_4)
        self.assertEqual({}, indices_4)

    def test_remove_composite_keys(self):
        indices_0 = self._index_info('test_composite')
        self.assertEqual([
            'sqlite_autoindex_test_composite_1',
            'test_composite_name_enabled_idx', 'test_composite_name_value_idx'
        ], sorted(indices_0))
        self.assertEqual({
            'unique': 1,
            'columns': ['id', 'name']
        }, indices_0['sqlite_autoindex_test_composite_1'])
        self.assertEqual({
            'unique': 0,
            'columns': ['name', 'value']
        }, indices_0['test_composite_name_value_idx'])
        self.assertEqual({
            'unique': 1,
            'columns': ['name', 'enabled']
        }, indices_0['test_composite_name_enabled_idx'])

        self._drop_column('test_composite', 'id')
        indices_1 = self._index_info('test_composite')
        self.assertEqual([
            'test_composite_name_enabled_idx', 'test_composite_name_value_idx'
        ], sorted(indices_1))
        self.assertEqual(indices_0['test_composite_name_value_idx'],
                         indices_1['test_composite_name_value_idx'])
        self.assertEqual(indices_0['test_composite_name_enabled_idx'],
                         indices_1['test_composite_name_enabled_idx'])
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY name, value, enabled""")
        self.assertEqual([('bar', '42', 1), ('bar', '43', 0), ('foo', '42', 1),
                          ('foo', '43', 0)], rows)

        self._drop_column('test_composite', 'name')
        self.assertEqual({}, self._index_info('test_composite'))
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY value, enabled""")
        self.assertEqual([('42', 1), ('42', 1), ('43', 0), ('43', 0)], rows)
Example #18
0
class NotificationPreferencesTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub()
        self.prefs_mod = PreferencesModule(self.env)
        ids = self._add_subscriptions([
            {'sid': 'foo', 'class_': 'TicketOwnerSubscriber'},
            {'sid': 'foo', 'class_': 'CarbonCopySubscriber'},
            {'sid': 'foo', 'class_': 'TicketReporterSubscriber'},
            {'sid': 'bar', 'class_': 'CarbonCopySubscriber'},
        ])
        self.foo_rule0 = ids[0]
        self.foo_rule1 = ids[1]
        self.foo_rule2 = ids[2]
        self.bar_rule0 = ids[3]

    def tearDown(self):
        self.env.reset_db()

    def _add_subscription(self, **kwargs):
        props = {'sid': None, 'authenticated': 1, 'distributor': 'email',
                 'format': 'text/plain', 'adverb': 'always',
                 'class': 'TicketOwnerSubscriber'}
        props.update((k.rstrip('_'),
                      (v or None) if isinstance(v, basestring) else v)
                     for k, v in kwargs.iteritems())
        assert props['sid'] is not None
        return Subscription.add(self.env, props)

    def _add_subscriptions(self, rows):
        with self.env.db_transaction:
            return [self._add_subscription(**row) for row in rows]

    def _get_rules(self, sid, authenticated=1):
        return self.env.db_query("""
            SELECT distributor, format, priority, adverb, class
            FROM notify_subscription
            WHERE sid=%s AND authenticated=1
            ORDER BY distributor, priority
            """, (sid,))

    def _request(self, **kwargs):
        kwargs.setdefault('method', 'POST')
        kwargs.setdefault('path_info', '/prefs/notification')
        return MockRequest(self.env, **kwargs)

    def _process(self, req):
        self.assertTrue(self.prefs_mod.match_request(req))
        return self.prefs_mod.process_request(req)

    def test_add_rule(self):
        args = {'action': 'add-rule_email', 'new-adverb-email': 'never',
                'format-email': '', 'new-rule-email': 'TicketOwnerSubscriber'}
        req = self._request(authname='baz', args=args)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', None, 1, 'never', 'TicketOwnerSubscriber')],
            self._get_rules('baz'))

        args = {'action': 'add-rule_email', 'new-adverb-email': 'always',
                'format-email': 'text/plain',
                'new-rule-email': 'CarbonCopySubscriber'}
        req = self._request(authname='baz', args=args)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', None, 1, 'never', 'TicketOwnerSubscriber'),
             ('email', 'text/plain', 2, 'always', 'CarbonCopySubscriber')],
            self._get_rules('baz'))

    def test_delete_rule(self):
        req = self._request(authname='foo',
                            args={'action': 'delete-rule_%d' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'TicketOwnerSubscriber'),
             ('email', 'text/plain', 2, 'always', 'TicketReporterSubscriber')],
            self._get_rules('foo'))

        # try to delete non-existent rule
        rules = self._get_rules('foo')
        req = self._request(authname='foo',
                            args={'action': 'delete-rule_%d' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        # try to delete non-owned rules
        rules = self._get_rules('bar')
        req = self._request(authname='foo',
                            args={'action': 'delete-rule_%d' % self.bar_rule0})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('bar'))

    def test_move_rule(self):
        # move to last
        req = self._request(authname='foo',
                            args={'action': 'move-rule_%d-3' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'TicketOwnerSubscriber'),
             ('email', 'text/plain', 2, 'always', 'TicketReporterSubscriber'),
             ('email', 'text/plain', 3, 'always', 'CarbonCopySubscriber')],
            self._get_rules('foo'))
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'CarbonCopySubscriber')],
            self._get_rules('bar'))

        # move to first
        req = self._request(authname='foo',
                            args={'action': 'move-rule_%d-1' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'CarbonCopySubscriber'),
             ('email', 'text/plain', 2, 'always', 'TicketOwnerSubscriber'),
             ('email', 'text/plain', 3, 'always', 'TicketReporterSubscriber')],
            self._get_rules('foo'))

        # move to same position
        rules = self._get_rules('foo')
        req = self._request(authname='foo',
                            args={'action': 'move-rule_%d-1' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        # try to move to out of range
        rules = self._get_rules('foo')
        req = self._request(authname='foo', args={'action': 'move-rule_%d-42' %
                                                            self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        # try to move non-owned rules
        rules = self._get_rules('foo')
        req = self._request(authname='bar',
                            args={'action': 'move-rule_%d-3' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        rules = self._get_rules('foo')

        # try to move non-existent rule
        req = self._request(authname='foo', args={'action': 'move-rule_42-1'})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        # invalid id
        req = self._request(authname='foo',
                            args={'action': 'move-rule_0-1'})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))
        req = self._request(authname='foo',
                            args={'action': 'move-rule_a-1'})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

        # invalid priority
        req = self._request(authname='foo',
                            args={'action': 'move-rule_%d-0' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))
        req = self._request(authname='foo',
                            args={'action': 'move-rule_%d-a' % self.foo_rule1})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(rules, self._get_rules('foo'))

    def test_set_format(self):
        # set text/html
        req = self._request(authname='foo', args={'action': 'set-format_email',
                                                  'format-email': 'text/html'})
        self.assertNotIn('notification.format.email', req.session)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', 'text/html', 1, 'always', 'TicketOwnerSubscriber'),
             ('email', 'text/html', 2, 'always', 'CarbonCopySubscriber'),
             ('email', 'text/html', 3, 'always', 'TicketReporterSubscriber')],
            self._get_rules('foo'))
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'CarbonCopySubscriber')],
            self._get_rules('bar'))
        self.assertEqual('text/html', req.session['notification.format.email'])

        # set default format
        req = self._request(authname='foo', args={'action': 'set-format_email',
                                                  'format-email': ''})
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', None, 1, 'always', 'TicketOwnerSubscriber'),
             ('email', None, 2, 'always', 'CarbonCopySubscriber'),
             ('email', None, 3, 'always', 'TicketReporterSubscriber')],
            self._get_rules('foo'))
        self.assertNotIn('notification.format.email', req.session)

    def test_replace(self):
        arg_list = [
            ('action', 'replace_all'),
            ('format-email', 'text/plain'),
            ('adverb-email', 'always'),
            ('adverb-email', 'never'),
            ('adverb-email', 'always'),
            ('adverb-email', 'always'),
            ('class-email', 'TicketOwnerSubscriber'),
            ('class-email', 'CarbonCopySubscriber'),
            ('class-email', 'TicketReporterSubscriber'),
            ('class-email', 'TicketUpdaterSubscriber'),
        ]
        req = self._request(authname='foo', arg_list=arg_list)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'TicketOwnerSubscriber'),
             ('email', 'text/plain', 2, 'never', 'CarbonCopySubscriber'),
             ('email', 'text/plain', 3, 'always', 'TicketReporterSubscriber'),
             ('email', 'text/plain', 4, 'always', 'TicketUpdaterSubscriber')],
            self._get_rules('foo'))
        self.assertEqual(
            [('email', 'text/plain', 1, 'always', 'CarbonCopySubscriber')],
            self._get_rules('bar'))

        arg_list = [
            ('action', 'replace_all'), ('format-email', ''),
            ('adverb-email', 'always'),
            ('class-email', 'TicketOwnerSubscriber'),
        ]
        req = self._request(authname='foo', arg_list=arg_list)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual(
            [('email', None, 1, 'always', 'TicketOwnerSubscriber')],
            self._get_rules('foo'))

        arg_list = [('action', 'replace_all'), ('format-email', '')]
        req = self._request(authname='foo', arg_list=arg_list)
        self.assertRaises(RequestDone, self._process, req)
        self.assertEqual([], self._get_rules('foo'))
Example #19
0
class CacheTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub()
        self.log = self.env.log
        self.env.db_transaction.executemany(
            "INSERT INTO repository (id, name, value) VALUES (%s, %s, %s)",
            [(1, 'name', 'test-repos'),
             (1, 'youngest_rev', '')])

    def tearDown(self):
        self.env.reset_db()

    # Helpers

    def get_repos(self, get_changeset=None, youngest_rev=1):
        if get_changeset is None:
            def no_changeset(rev):
                raise NoSuchChangeset(rev)
            get_changeset = no_changeset
        return Mock(Repository, 'test-repos', {'name': 'test-repos', 'id': 1},
                    self.log,
                    get_changeset=get_changeset,
                    get_oldest_rev=lambda: 0,
                    get_youngest_rev=lambda: youngest_rev,
                    normalize_rev=lambda x: get_changeset(x).rev,
                    next_rev=(lambda x: int(x) < youngest_rev and x + 1 \
                              or None))

    def preset_cache(self, *args):
        """Each arg is a (rev tuple, changes list of tuples) pair."""
        with self.env.db_transaction as db:
            for rev, changes in args:
                db("""INSERT INTO revision (repos, rev, time, author, message)
                      VALUES (1,%s,%s,%s,%s)
                      """, rev)
                if changes:
                    db.executemany("""
                          INSERT INTO node_change (repos, rev, path, node_type,
                                                   change_type, base_path,
                                                   base_rev)
                          VALUES (1, %s, %s, %s, %s, %s, %s)
                          """, [(rev[0],) + change for change in changes])
            db("""UPDATE repository SET value=%s
                  WHERE id=1 AND name='youngest_rev'
                  """, (args[-1][0][0],))

    # Tests

    def test_initial_sync_with_empty_repos(self):
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEqual([], db(
                "SELECT rev, time, author, message FROM revision"))
            self.assertEqual(0, db("SELECT COUNT(*) FROM node_change")[0][0])

    def test_initial_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=1)
        changes = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                   ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changesets = [Mock(Changeset, repos, 0, '', '', t1,
                           get_changes=lambda: []),
                      Mock(Changeset, repos, 1, 'Import', 'joe', t2,
                           get_changes=lambda: iter(changes))]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            rows = db("SELECT rev, time, author, message FROM revision")
            self.assertEqual(len(rows), 2)
            self.assertEqual(('0', to_utimestamp(t1), '', ''), rows[0])
            self.assertEqual(('1', to_utimestamp(t2), 'joe', 'Import'),
                             rows[1])
            rows = db("""
                SELECT rev, path, node_type, change_type, base_path, base_rev
                FROM node_change""")
            self.assertEqual(len(rows), 2)
            self.assertEqual(('1', 'trunk', 'D', 'A', None, None), rows[0])
            self.assertEqual(('1', 'trunk/README', 'F', 'A', None, None),
                             rows[1])

    def test_update_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'),
             [('trunk', 'D', 'A', None, None),
              ('trunk/README', 'F', 'A', None, None)]),
            )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=2)
        changes = [('trunk/README', Node.FILE, Changeset.EDIT, 'trunk/README',
                    1)]
        changesets = [
            None,
            Mock(Changeset, repos, 1, '', '', t2, get_changes=lambda: []),
            Mock(Changeset, repos, 2, 'Update', 'joe', t3,
                 get_changes=lambda: iter(changes))
            ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEqual([(to_utimestamp(t3), 'joe', 'Update')],
                db("SELECT time, author, message FROM revision WHERE rev='2'"))
            self.assertEqual([('trunk/README', 'F', 'E', 'trunk/README',
                               '1')],
                    db("""SELECT path, node_type, change_type, base_path,
                                 base_rev
                          FROM node_change WHERE rev='2'"""))

    def test_clean_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'),
             [('trunk', 'D', 'A', None, None),
              ('trunk/README', 'F', 'A', None, None)]),
            )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=2)
        changes1 = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                    ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changes2 = [('trunk/README', Node.FILE, Changeset.EDIT, 'trunk/README',
                     1)]
        changesets = [
            Mock(Changeset, repos, 0, '**empty**', 'joe', t1,
                 get_changes=lambda: []),
            Mock(Changeset, repos, 1, 'Initial Import', 'joe', t2,
                 get_changes=lambda: iter(changes1)),
            Mock(Changeset, repos, 2, 'Update', 'joe', t3,
                 get_changes=lambda: iter(changes2))
            ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync(clean=True)

        rows = self.env.db_query("""
            SELECT time, author, message FROM revision ORDER BY rev
            """)
        self.assertEqual(3, len(rows))
        self.assertEqual((to_utimestamp(t1), 'joe', '**empty**'), rows[0])
        self.assertEqual((to_utimestamp(t2), 'joe', 'Initial Import'),
                         rows[1])
        self.assertEqual((to_utimestamp(t3), 'joe', 'Update'), rows[2])

        rows = self.env.db_query("""
            SELECT rev, path, node_type, change_type, base_path, base_rev
            FROM node_change ORDER BY rev, path""")
        self.assertEqual(3, len(rows))
        self.assertEqual(('1', 'trunk', 'D', 'A', None, None), rows[0])
        self.assertEqual(('1', 'trunk/README', 'F', 'A', None, None), rows[1])
        self.assertEqual(('2', 'trunk/README', 'F', 'E', 'trunk/README', '1'),
                         rows[2])

    def test_sync_changeset(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'),
             [('trunk', 'D', 'A', None, None),
              ('trunk/README', 'F', 'A', None, None)]),
            )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=1)
        changes1 = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                    ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changesets = [
            Mock(Changeset, repos, 0, '**empty**', 'joe', t1,
                 get_changes=lambda: []),
            Mock(Changeset, repos, 1, 'Initial Import', 'joe', t2,
                 get_changes=lambda: iter(changes1)),
            ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync_changeset(0)


        rows = self.env.db_query(
                "SELECT time, author, message FROM revision ORDER BY rev")
        self.assertEqual(2, len(rows))
        self.assertEqual((to_utimestamp(t1), 'joe', '**empty**'), rows[0])
        self.assertEqual((to_utimestamp(t2), 'joe', 'Import'), rows[1])

    def test_sync_changeset_if_not_exists(self):
        t = [
            datetime(2001, 1, 1, 1, 1, 1, 0, utc), # r0
            datetime(2002, 1, 1, 1, 1, 1, 0, utc), # r1
            datetime(2003, 1, 1, 1, 1, 1, 0, utc), # r2
            datetime(2004, 1, 1, 1, 1, 1, 0, utc), # r3
        ]
        self.preset_cache(
            (('0', to_utimestamp(t[0]), 'joe', '**empty**'), []),
            (('1', to_utimestamp(t[1]), 'joe', 'Import'),
             [('trunk', 'D', 'A', None, None),
              ('trunk/README', 'F', 'A', None, None)]),
            # not exists r2
            (('3', to_utimestamp(t[3]), 'joe', 'Add COPYING'),
             [('trunk/COPYING', 'F', 'A', None, None)]),
            )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=3)
        changes = [
            None,                                                       # r0
            [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),      # r1
             ('trunk/README', Node.FILE, Changeset.ADD, None, None)],
            [('branches', Node.DIRECTORY, Changeset.ADD, None, None),   # r2
             ('tags', Node.DIRECTORY, Changeset.ADD, None, None)],
            [('trunk/COPYING', Node.FILE, Changeset.ADD, None, None)],  # r3
        ]
        changesets = [
            Mock(Changeset, repos, 0, '**empty**', 'joe', t[0],
                 get_changes=lambda: []),
            Mock(Changeset, repos, 1, 'Initial Import', 'joe', t[1],
                 get_changes=lambda: iter(changes[1])),
            Mock(Changeset, repos, 2, 'Created directories', 'john', t[2],
                 get_changes=lambda: iter(changes[2])),
            Mock(Changeset, repos, 3, 'Add COPYING', 'joe', t[3],
                 get_changes=lambda: iter(changes[3])),
            ]
        cache = CachedRepository(self.env, repos, self.log)
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)
        cache.sync()
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)

        self.assertIsNone(cache.sync_changeset(2))
        cset = cache.get_changeset(2)
        self.assertEqual('john', cset.author)
        self.assertEqual('Created directories', cset.message)
        self.assertEqual(t[2], cset.date)
        cset_changes = cset.get_changes()
        self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None,
                          None),
                         cset_changes.next())
        self.assertEqual(('tags', Node.DIRECTORY, Changeset.ADD, None, None),
                         cset_changes.next())
        self.assertRaises(StopIteration, cset_changes.next)

        rows = self.env.db_query(
                "SELECT time,author,message FROM revision ORDER BY rev")
        self.assertEqual(4, len(rows))
        self.assertEqual((to_utimestamp(t[0]), 'joe', '**empty**'), rows[0])
        self.assertEqual((to_utimestamp(t[1]), 'joe', 'Import'), rows[1])
        self.assertEqual((to_utimestamp(t[2]), 'john', 'Created directories'),
                         rows[2])
        self.assertEqual((to_utimestamp(t[3]), 'joe', 'Add COPYING'), rows[3])

    def test_sync_changeset_with_string_rev(self):  # ticket:11660

        class MockCachedRepository(CachedRepository):
            def db_rev(self, rev):
                return '%010d' % rev

        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=1)
        changesets = [
            Mock(Changeset, repos, 0, 'empty', 'joe', t1,
                 get_changes=lambda: []),
            Mock(Changeset, repos, 1, 'first', 'joe', t2,
                 get_changes=lambda: []),
            ]
        cache = MockCachedRepository(self.env, repos, self.log)

        cache.sync_changeset('0')   # not cached yet
        cache.sync_changeset(u'1')  # not cached yet
        rows = self.env.db_query(
            "SELECT rev,author FROM revision ORDER BY rev")
        self.assertEqual(2, len(rows))
        self.assertEquals(('0000000000', 'joe'), rows[0])
        self.assertEquals(('0000000001', 'joe'), rows[1])

        cache.sync_changeset(u'0')  # cached
        cache.sync_changeset('1')   # cached
        rows = self.env.db_query(
            "SELECT rev,author FROM revision ORDER BY rev")
        self.assertEqual(2, len(rows))
        self.assertEquals(('0000000000', 'joe'), rows[0])
        self.assertEquals(('0000000001', 'joe'), rows[1])

    def test_get_changes(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'),
             [('trunk', 'D', 'A', None, None),
              ('trunk/RDME', 'F', 'A', None, None)]),
            )
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        self.assertEqual('1', cache.youngest_rev)
        changeset = cache.get_changeset(1)
        self.assertEqual('joe', changeset.author)
        self.assertEqual('Import', changeset.message)
        self.assertEqual(t2, changeset.date)
        changes = changeset.get_changes()
        self.assertEqual(('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                         changes.next())
        self.assertEqual(('trunk/RDME', Node.FILE, Changeset.ADD, None, None),
                         changes.next())
        self.assertRaises(StopIteration, changes.next)
Example #20
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 #21
0
class SessionTestCase(unittest.TestCase):
    """Unit tests for the persistent session support."""
    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def test_new_session(self):
        """
        Verify that a session cookie gets sent back to the client for a new
        session.
        """
        req = MockRequest(self.env, authname='anonymous')
        session = Session(self.env, req)
        self.assertEqual(session.sid, req.outcookie['trac_session'].value)
        self.assertEqual(
            0,
            self.env.db_query("SELECT COUNT(*) FROM session")[0][0])

    def test_anonymous_session(self):
        """
        Verify that session variables are stored in the database.
        """
        req = MockRequest(self.env, authname='anonymous')
        req.incookie['trac_session'] = '123456'
        session = Session(self.env, req)
        self.assertEqual('123456', session.sid)
        self.assertNotIn('trac_session', req.outcookie)

    def _test_authenticated_session(self, username):
        """
        Verifies that a session cookie does not get used if the user is logged
        in, and that Trac expires the cookie.
        """
        req = MockRequest(self.env, authname=username)
        req.incookie['trac_session'] = '123456'
        session = Session(self.env, req)
        self.assertEqual(username, session.sid)
        session['foo'] = 'bar'
        session.save()
        self.assertEqual(0, req.outcookie['trac_session']['expires'])

    def test_authenticated_session(self):
        self._test_authenticated_session('john')
        self._test_authenticated_session('j.smith')
        self._test_authenticated_session(u'Jöhn')  # non-ascii username
        self._test_authenticated_session('*****@*****.**')  # LDAP username

    def _test_session_promotion(self, username):
        """
        Verifies that an existing anonymous session gets promoted to an
        authenticated session when the user logs in.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            req = MockRequest(self.env, authname=username)
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            self.assertEqual(username, session.sid)
            session.save()

        self.assertEqual([(username, 1)],
                         self.env.db_query(
                             """SELECT sid, authenticated FROM session
                                 WHERE sid=%s""", (username, )))

    def test_session_promotion(self):
        self._test_session_promotion('john')
        self._test_session_promotion('j.smith')
        self._test_session_promotion(u'Jöhn')  # non-ascii username
        self._test_session_promotion('*****@*****.**')  # LDAP username

        sessions = self.env.db_query("SELECT sid, authenticated FROM session")
        self.assertEqual(
            set([('john', 1), ('j.smith', 1), (u'Jöhn', 1),
                 ('*****@*****.**', 1)]), set(sessions))

    def _test_new_session_promotion(self, username):
        """
        Verifies that even without a preexisting anonymous session,
        an authenticated session will be created when the user logs in.
        (same test as above without the initial INSERT)
        """
        with self.env.db_transaction:
            req = MockRequest(self.env, authname=username)
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            self.assertEqual(username, session.sid)
            session.save()

        self.assertEqual([(username, 1)],
                         self.env.db_query(
                             """SELECT sid, authenticated FROM session
                                 WHERE sid=%s""", (username, )))

    def test_new_session_promotion(self):
        self._test_new_session_promotion('john')
        self._test_new_session_promotion('j.smith')
        self._test_new_session_promotion(u'Jöhn')  # non-ascii username
        self._test_new_session_promotion('*****@*****.**')  # LDAP username

        sessions = self.env.db_query("SELECT sid, authenticated FROM session")
        self.assertEqual(
            set([('john', 1), ('j.smith', 1), (u'Jöhn', 1),
                 ('*****@*****.**', 1)]), set(sessions))

    def test_as_int(self):
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 1, 0)")
            db.executemany(
                """
                INSERT INTO session_attribute VALUES (%s,%s,%s,%s)
                """, (('123456', 1, 'foo', 'bar'), ('123456', 1, 'baz', 3)))

        req = MockRequest(self.env, authname='123456')
        session = Session(self.env, req)

        self.assertEqual('bar', session.get('foo'))
        self.assertEqual(2, session.as_int('foo', 2))
        self.assertEqual(3, session.as_int('baz', 1))
        self.assertEqual(2, session.as_int('baz', 1, max=2))
        self.assertEqual(4, session.as_int('baz', 1, min=4))
        self.assertIsNone(session.as_int('bat'))

    def test_as_bool(self):
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 1, 0)")
            db.executemany(
                """
                INSERT INTO session_attribute VALUES (%s,%s,%s,%s)
                """, (('123456', 1, 'foo', 'bar'), ('123456', 1, 'baz', 1)))

        req = MockRequest(self.env, authname='123456')
        session = Session(self.env, req)

        self.assertEqual('bar', session.get('foo'))
        self.assertIsNone(session.as_bool('foo', None))
        self.assertTrue(session.as_int('baz'))
        self.assertTrue(session.as_int('baz', False))
        self.assertIsNone(session.as_bool('bat'))

    def test_add_anonymous_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an anonymous session.
        """
        req = MockRequest(self.env, authname='anonymous')
        req.incookie['trac_session'] = '123456'
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()

        self.assertEqual(
            'bar',
            self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0]
            [0])

    def test_modify_anonymous_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES
                ('123456', 0, 'foo', 'bar')
                """)
            req = MockRequest(self.env, authname='anonymous')
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0]
            [0])

    def test_delete_anonymous_session_var(self):
        """
        Verify that modifying a variable updates the 'session' table accordingly
        for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES
                ('123456', 0, 'foo', 'bar')
                """)
            req = MockRequest(self.env, authname='anonymous')
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='123456' AND name='foo'
            """)[0][0])

    def test_purge_anonymous_session(self):
        """
        Verify that old sessions get purged.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)", (0, ))
            db("INSERT INTO session VALUES ('987654', 0, %s)",
               (int(time_now() - PURGE_AGE - 3600), ))
            db("""
                INSERT INTO session_attribute
                VALUES ('987654', 0, 'foo', 'bar')
                """)

            # We need to modify a different session to trigger the purging
            req = MockRequest(self.env, authname='anonymous')
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            session['foo'] = 'bar'
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='987654' AND authenticated=0
            """)[0][0])

    def test_delete_empty_session(self):
        """
        Verify that a session gets deleted when it doesn't have any data except
        for the 'last_visit' timestamp.
        """
        now = time_now()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)",
               (int(now - UPDATE_INTERVAL - 3600), ))
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            req = MockRequest(self.env, authname='anonymous')
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='123456' AND authenticated=0
            """)[0][0])

    def test_change_anonymous_session(self):
        """
        Verify that changing from one anonymous session to an inexisting
        anonymous session creates the new session and doesn't carry over
        variables from the previous session.
        """

        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

        req = MockRequest(self.env, authname='anonymous')
        req.incookie['trac_session'] = '123456'
        session = Session(self.env, req)
        self.assertEqual({'foo': 'bar'}, session)

        session.get_session('7890')
        session['baz'] = 'moo'
        session.save()
        self.assertEqual({'baz': 'moo'}, session)

        with self.env.db_query as db:
            self.assertEqual(
                1,
                db("""
                SELECT COUNT(*) FROM session
                WHERE sid='7890' AND authenticated=0
                """)[0][0])
            self.assertEqual([('baz', 'moo')],
                             db("""
                SELECT name, value FROM session_attribute
                WHERE sid='7890' AND authenticated=0
                """))

    def test_add_authenticated_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an authenticated session.
        """
        req = MockRequest(self.env, authname='john')
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()

        self.assertEqual(
            'bar',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_modify_authenticated_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

            req = MockRequest(self.env, authname='john')
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_authenticated_session_independence_var(self):
        """
        Verify that an anonymous session with the same name as an authenticated
        session doesn't interfere with the latter.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

        self.assertEqual(
            'bar',
            self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)[0][0])

        req = MockRequest(self.env, authname='anonymous')
        req.incookie['trac_session'] = 'john'
        session = Session(self.env, req)
        self.assertTrue('foo' not in session)
        session['foo'] = 'baz'
        session.save()

        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('bar', rows[0][0])
        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=0 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('baz', rows[0][0])

    def test_delete_authenticated_session_var(self):
        """
        Verify that deleting a variable updates the 'session' table accordingly
        for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            req = MockRequest(self.env, authname='john')
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_update_session(self):
        """
        Verify that accessing a session after one day updates the sessions
        'last_visit' variable so that the session doesn't get purged.
        """
        now = time_now()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 1)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            req = MockRequest(self.env, authname='anonymous')
            req.incookie['trac_session'] = '123456'
            session = Session(self.env, req)
            session['modified'] = True
            session.save()  # updating does require modifications

            self.assertEqual(PURGE_AGE,
                             req.outcookie['trac_session']['expires'])

        self.assertAlmostEqual(
            now,
            int(
                self.env.db_query("""
            SELECT last_visit FROM session
            WHERE sid='123456' AND authenticated=0
            """)[0][0]), -1)

    def test_modify_detached_session(self):
        """
        Verify that modifying a variable in a session not associated with a
        request updates the database accordingly.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_delete_detached_session_var(self):
        """
        Verify that removing a variable in a session not associated with a
        request deletes the variable from the database.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_session_set(self):
        """Verify that setting a variable in a session to the default value
        removes it from the session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

        session = DetachedSession(self.env, 'john')
        self.assertEqual('bar', session['foo'])

        # Setting the variable to the default value removes the variable
        with self.env.db_transaction as db:
            session.set('foo', 'default', 'default')
            session.save()
        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

        # Setting the variable to a value different from the default sets it
        with self.env.db_transaction as db:
            session.set('foo', 'something', 'default')
            session.save()
        self.assertEqual(
            'something',
            self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_session_set_email(self):
        """Setting session email invalidates known_users cache."""
        session = DetachedSession(self.env, 'user')
        session['email'] = '*****@*****.**'

        self.assertEqual([], list(self.env.get_known_users()))
        session.save()
        email = None
        for sid, name, email in self.env.get_known_users():
            if sid == 'user':
                break
        self.assertEqual(session['email'], email)

    def test_session_set_name(self):
        """Setting session name invalidates known_users cache."""
        session = DetachedSession(self.env, 'user')
        session['name'] = 'The User'

        self.assertEqual([], list(self.env.get_known_users()))
        session.save()
        name = None
        for sid, name, email in self.env.get_known_users():
            if sid == 'user':
                break
        self.assertEqual(session['name'], name)

    def test_session_admin_list(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        # Verify the empty case
        self.assertRaises(StopIteration, sess_admin._get_list([]).next)

        self.assertEqual([i for i in sess_admin._get_list(['authenticated'])],
                         auth_list)
        self.assertEqual([i for i in sess_admin._get_list(['anonymous'])],
                         anon_list)
        self.assertEqual([i for i in sess_admin._get_list(['*'])], all_list)
        self.assertEqual([i for i in sess_admin._get_list(['name00'])][0],
                         auth_list[0])
        self.assertEqual([i for i in sess_admin._get_list(['name10:0'])][0],
                         anon_list[0])
        self.assertEqual(
            [i for i in sess_admin._get_list(['name00', 'name01', 'name02'])],
            all_list[:3])

    def test_session_admin_add(self):
        _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        self.assertRaises(Exception, sess_admin._do_add, 'name00')

        sess_admin._do_add('john')
        self.assertEqual({}, get_session_attrs(self.env, 'john'))
        self.assertIn(('john', None, None), list(self.env.get_known_users()))

        sess_admin._do_add('john1', 'John1')
        self.assertEqual({'name': 'John1'},
                         get_session_attrs(self.env, 'john1'))
        self.assertIn(('john1', 'John1', None),
                      list(self.env.get_known_users()))

        sess_admin._do_add('john2', 'John2', '*****@*****.**')
        self.assertEqual({
            'name': 'John2',
            'email': '*****@*****.**'
        }, get_session_attrs(self.env, 'john2'))
        self.assertIn(('john2', 'John2', '*****@*****.**'),
                      list(self.env.get_known_users()))

        sess_admin._do_add('alice1', None, '*****@*****.**')
        self.assertEqual({'email': '*****@*****.**'},
                         get_session_attrs(self.env, 'alice1'))
        sess_admin._do_add('alice2', '', '*****@*****.**')
        self.assertEqual({'email': '*****@*****.**'},
                         get_session_attrs(self.env, 'alice2'))
        sess_admin._do_add('bob1', 'Bob 1', None)
        self.assertEqual({'name': 'Bob 1'},
                         get_session_attrs(self.env, 'bob1'))
        sess_admin._do_add('bob2', 'Bob 2', '')
        self.assertEqual({'name': 'Bob 2'},
                         get_session_attrs(self.env, 'bob2'))
        sess_admin._do_add('charlie1', '', '')
        self.assertEqual({}, get_session_attrs(self.env, 'charlie1'))
        sess_admin._do_add('charlie2', None, None)
        self.assertEqual({}, get_session_attrs(self.env, 'charlie2'))

    def test_session_admin_set(self):
        _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        self.assertRaises(TracError, sess_admin._do_set, 'name', 'nothere',
                          'foo')

        self.env.get_known_users()  # Prep the cache
        self.assertIn(('name00', 'val00', 'val00'),
                      list(self.env.get_known_users()))
        sess_admin._do_set('name', 'name00', 'john')
        self.assertEqual({
            'name': 'john',
            'email': 'val00'
        }, get_session_attrs(self.env, 'name00'))
        self.assertIn(('name00', 'john', 'val00'),
                      list(self.env.get_known_users()))

        sess_admin._do_set('email', 'name00', '*****@*****.**')
        self.assertEqual({
            'name': 'john',
            'email': '*****@*****.**'
        }, get_session_attrs(self.env, 'name00'))
        self.assertIn(('name00', 'john', '*****@*****.**'),
                      list(self.env.get_known_users()))
        sess_admin._do_set('default_handler', 'name00', 'SearchModule')
        self.assertEqual(
            {
                'name': 'john',
                'email': '*****@*****.**',
                'default_handler': 'SearchModule'
            }, get_session_attrs(self.env, 'name00'))

        sess_admin._do_set('name', 'name00', '')
        self.assertEqual(
            {
                'email': '*****@*****.**',
                'default_handler': 'SearchModule'
            }, get_session_attrs(self.env, 'name00'))
        sess_admin._do_set('email', 'name00', '')
        self.assertEqual({'default_handler': 'SearchModule'},
                         get_session_attrs(self.env, 'name00'))
        sess_admin._do_set('default_handler', 'name00', '')
        self.assertEqual({}, get_session_attrs(self.env, 'name00'))

    def test_session_admin_delete(self):
        _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        self.assertIn(('name00', 'val00', 'val00'),
                      list(self.env.get_known_users()))
        sess_admin._do_delete('name00')
        self.assertEqual(None, get_session_attrs(self.env, 'name00'))
        self.assertNotIn(('name00', 'val00', 'val00'),
                         list(self.env.get_known_users()))

        sess_admin._do_delete('nothere')
        self.assertEqual(None, get_session_attrs(self.env, 'nothere'))

        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin._do_delete('anonymous')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list)

    def test_session_admin_purge(self):
        sess_admin = SessionAdmin(self.env)

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-02')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list)
        self.assertEqual({
            'name': 'val10',
            'email': 'val10'
        }, get_session_attrs(self.env, anon_list[0][0]))
        self.assertEqual({
            'name': 'val11',
            'email': 'val11'
        }, get_session_attrs(self.env, anon_list[1][0]))

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-12')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list[1:])
        rows = self.env.db_query(
            """
            SELECT name, value FROM session_attribute WHERE sid = %s
            """, (anon_list[0][0], ))
        self.assertEqual([], rows)
        self.assertEqual(None, get_session_attrs(self.env, anon_list[0][0]))
        self.assertEqual({
            'name': 'val11',
            'email': 'val11'
        }, get_session_attrs(self.env, anon_list[1][0]))

    def test_session_get_session_with_invalid_sid(self):
        req = MockRequest(self.env, authname='anonymous')
        session = Session(self.env, req)
        session.get_session('0123456789')
        self.assertEqual('0123456789', session.sid)
        session.get_session('abcxyz')
        self.assertEqual('abcxyz', session.sid)
        session.get_session('abc123xyz')
        self.assertEqual('abc123xyz', session.sid)
        self.assertRaises(TracError, session.get_session, 'abc 123 xyz')
        self.assertRaises(TracError, session.get_session, 'abc-123-xyz')
        self.assertRaises(TracError, session.get_session, 'abc<i>123</i>xyz')
        self.assertRaises(TracError, session.get_session, u'abc123xÿz')
        self.assertRaises(TracError, session.get_session,
                          u'abc¹₂³xyz')  # Unicode digits

    def test_session_change_id_with_invalid_sid(self):
        req = MockRequest(self.env, authname='anonymous', base_path='/')
        session = Session(self.env, req)
        session.change_sid('0123456789')
        self.assertEqual('0123456789', session.sid)
        session.change_sid('abcxyz')
        self.assertEqual('abcxyz', session.sid)
        session.change_sid('abc123xyz')
        self.assertEqual('abc123xyz', session.sid)
        self.assertRaises(TracError, session.change_sid, 'abc 123 xyz')
        self.assertRaises(TracError, session.change_sid, 'abc-123-xyz')
        self.assertRaises(TracError, session.change_sid, 'abc<i>123</i>xyz')
        self.assertRaises(TracError, session.change_sid, u'abc123xÿz')
        self.assertRaises(TracError, session.change_sid,
                          u'abc¹₂³xyz')  # Unicode digits
Example #22
0
File: api.py Project: zxfly/trac
class DatabaseManagerTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        self.dbm = DatabaseManager(self.env)

    def tearDown(self):
        self.env.reset_db()

    def test_destroy_db(self):
        """Database doesn't exist after calling destroy_db."""
        self.env.db_query("SELECT name FROM system")
        self.assertIsNotNone(self.dbm._cnx_pool)
        self.dbm.destroy_db()
        self.assertIsNone(self.dbm._cnx_pool)  # No connection pool
        scheme, params = parse_connection_uri(get_dburi())
        if scheme != 'postgres' or params.get('schema', 'public') != 'public':
            self.assertFalse(self.dbm.db_exists())
        else:
            self.assertEqual([], self.dbm.get_table_names())

    def test_get_column_names(self):
        """Get column names for the default database."""
        for table in default_schema:
            column_names = [col.name for col in table.columns]
            self.assertEqual(column_names,
                             self.dbm.get_column_names(table.name))

    def test_get_default_database_version(self):
        """Get database version for the default entry named
        `database_version`.
        """
        self.assertEqual(default_db_version, self.dbm.get_database_version())

    def test_get_table_names(self):
        """Get table names for the default database."""
        self.assertEqual(sorted(table.name for table in default_schema),
                         sorted(self.dbm.get_table_names()))

    def test_has_table(self):
        self.assertIs(True, self.dbm.has_table('system'))
        self.assertIs(True, self.dbm.has_table('wiki'))
        self.assertIs(False, self.dbm.has_table('trac'))
        self.assertIs(False, self.dbm.has_table('blah.blah'))

    def test_set_default_database_version(self):
        """Set database version for the default entry named
        `database_version`.
        """
        new_db_version = default_db_version + 1
        self.dbm.set_database_version(new_db_version)
        self.assertEqual(new_db_version, self.dbm.get_database_version())

        # Restore the previous version to avoid destroying the database
        # on teardown
        self.dbm.set_database_version(default_db_version)
        self.assertEqual(default_db_version, self.dbm.get_database_version())

    def test_set_get_plugin_database_version(self):
        """Get and set database version for an entry with an
        arbitrary name.
        """
        name = 'a_trac_plugin_version'
        db_ver = 1

        self.assertFalse(self.dbm.get_database_version(name))
        self.dbm.set_database_version(db_ver, name)
        self.assertEqual(db_ver, self.dbm.get_database_version(name))

    def test_get_sequence_names(self):
        sequence_names = []
        if self.dbm.connection_uri.startswith('postgres'):
            for table in default_schema:
                for column in table.columns:
                    if column.name == 'id' and column.auto_increment:
                        sequence_names.append(table.name)
            sequence_names.sort()

        self.assertEqual(sequence_names, self.dbm.get_sequence_names())
Example #23
0
File: model.py Project: t2y/trac
class MilestoneTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        self.env.path = tempfile.mkdtemp(prefix='trac-tempenv-')
        self.created_at = datetime(2001, 1, 1, tzinfo=utc)
        self.updated_at = self.created_at + timedelta(seconds=1)

    def tearDown(self):
        shutil.rmtree(self.env.path)
        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 _insert_ticket(self, when=None, **kwargs):
        ticket = Ticket(self.env)
        for name, value in kwargs.iteritems():
            ticket[name] = value
        ticket.insert(when or self.created_at)
        return ticket

    def _update_ticket(self, ticket, author=None, comment=None, when=None,
                       **kwargs):
        for name, value in kwargs.iteritems():
            ticket[name] = value
        ticket.save_changes(author, comment, when or self.updated_at)

    def test_new_milestone(self):
        milestone = Milestone(self.env)
        self.assertFalse(milestone.exists)
        self.assertIsNone(milestone.name)
        self.assertIsNone(milestone.due)
        self.assertIsNone(milestone.completed)
        self.assertEqual('', milestone.description)

    def test_new_milestone_empty_name(self):
        """
        Verifies that specifying an empty milestone name results in the
        milestone being correctly detected as non-existent.
        """
        milestone = Milestone(self.env, '')
        self.assertFalse(milestone.exists)
        self.assertIsNone(milestone.name)
        self.assertIsNone(milestone.due)
        self.assertIsNone(milestone.completed)
        self.assertEqual('', milestone.description)

    def test_existing_milestone(self):
        self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")

        milestone = Milestone(self.env, 'Test')
        self.assertTrue(milestone.exists)
        self.assertEqual('Test', milestone.name)
        self.assertIsNone(milestone.due)
        self.assertIsNone(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_move_tickets(self):
        self.env.db_transaction.executemany(
            "INSERT INTO milestone (name) VALUES (%s)",
            [('Test',), ('Testing',)])
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        self._update_ticket(tkt2, status='closed', resolution='fixed')
        milestone = Milestone(self.env, 'Test')
        milestone.move_tickets('Testing', 'anonymous', 'Move tickets')

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('Testing', tkt1['milestone'])
        self.assertEqual('Testing', tkt2['milestone'])
        self.assertEqual(tkt1['changetime'], tkt2['changetime'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])

    def test_move_tickets_exclude_closed(self):
        self.env.db_transaction.executemany(
            "INSERT INTO milestone (name) VALUES (%s)",
            [('Test',), ('Testing',)])
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        self._update_ticket(tkt2, status='closed', resolution='fixed')
        milestone = Milestone(self.env, 'Test')
        milestone.move_tickets('Testing', 'anonymous', 'Move tickets',
                               exclude_closed=True)

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('Testing', tkt1['milestone'])
        self.assertEqual('Test', tkt2['milestone'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])
        self.assertEqual(self.updated_at, tkt2['changetime'])

    def test_move_tickets_target_doesnt_exist(self):
        self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        milestone = Milestone(self.env, 'Test')
        self.assertRaises(ResourceNotFound, milestone.move_tickets,
                          'Testing', 'anonymous')

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('Test', tkt1['milestone'])
        self.assertEqual('Test', tkt2['milestone'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])
        self.assertNotEqual(self.updated_at, tkt2['changetime'])

    def test_create_milestone_without_name(self):
        milestone = Milestone(self.env)
        self.assertRaises(TracError, milestone.insert)

    def test_delete_milestone(self):
        self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        self._update_ticket(tkt2, status='closed', resolution='fixed')
        milestone = Milestone(self.env, 'Test')
        milestone.delete()
        self.assertFalse(milestone.exists)
        self.assertEqual([],
            self.env.db_query("SELECT * FROM milestone WHERE name='Test'"))

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('', tkt1['milestone'])
        self.assertEqual('', tkt2['milestone'])
        self.assertEqual(tkt1['changetime'], tkt2['changetime'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])

    def test_delete_milestone_with_attachment(self):
        milestone = Milestone(self.env)
        milestone.name = 'MilestoneWithAttachment'
        milestone.insert()
        
        attachment = Attachment(self.env, 'milestone', milestone.name)
        attachment.insert('foo.txt', StringIO(), 0, 1)

        milestone.delete()
        self.assertEqual(False, milestone.exists)

        attachments = Attachment.select(self.env, 'milestone', milestone.name)
        self.assertRaises(StopIteration, attachments.next)

    def test_delete_milestone_retarget_tickets(self):
        self.env.db_transaction.executemany(
            "INSERT INTO milestone (name) VALUES (%s)",
            [('Test',), ('Other',)])
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        self._update_ticket(tkt2, status='closed', resolution='fixed')
        milestone = Milestone(self.env, 'Test')
        milestone.delete(retarget_to='Other')
        self.assertFalse(milestone.exists)

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('Other', tkt1['milestone'])
        self.assertEqual('Other', tkt2['milestone'])
        self.assertEqual(tkt1['changetime'], tkt2['changetime'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])

    def test_update_milestone(self):
        self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")

        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_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_rename_milestone_retarget_tickets(self):
        self.env.db_transaction("INSERT INTO milestone (name) VALUES ('Test')")
        tkt1 = self._insert_ticket(status='new', summary='Foo',
                                   milestone='Test')
        tkt2 = self._insert_ticket(status='new', summary='Bar',
                                   milestone='Test')
        self._update_ticket(tkt2, status='closed', resolution='fixed')
        milestone = Milestone(self.env, 'Test')
        milestone.name = 'Testing'
        milestone.update()

        tkt1 = Ticket(self.env, tkt1.id)
        tkt2 = Ticket(self.env, tkt2.id)
        self.assertEqual('Testing', tkt1['milestone'])
        self.assertEqual('Testing', tkt2['milestone'])
        self.assertEqual(tkt1['changetime'], tkt2['changetime'])
        self.assertNotEqual(self.updated_at, tkt1['changetime'])

    def test_select_milestones(self):
        self.env.db_transaction.executemany(
            "INSERT INTO milestone (name) VALUES (%s)",
            [('1.0',), ('2.0',)])

        milestones = list(Milestone.select(self.env))
        self.assertEqual('1.0', milestones[0].name)
        self.assertTrue(milestones[0].exists)
        self.assertEqual('2.0', milestones[1].name)
        self.assertTrue(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.assertTrue(milestone.exists)
        milestone.delete()
        self.assertEqual('Milestone 1', milestone.name)
        self.assertFalse(milestone.exists)
        self.assertEqual('deleted', listener.action)
        self.assertEqual(milestone, listener.milestone)
Example #24
0
File: model.py Project: t2y/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.assertIsNone(ticket.get_change(cnum=4))
        self.assertIsNotNone(ticket.get_change(cnum=3))
        self.assertEqual(t, ticket.time_changed)

    def test_delete_last_comment_when_custom_field_gone(self):
        """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.assertIsNone(ticket['foo'])
        # however, 'foo=change3' is still in the database
        self.assertEqual([('change3',)], self.env.db_query("""
            SELECT value FROM ticket_custom WHERE ticket=%s AND name='foo'
            """, (self.id,)))
        self.assertIsNone(ticket.get_change(cnum=4))
        self.assertIsNotNone(ticket.get_change(cnum=3))
        self.assertEqual(t, ticket.time_changed)

    def test_delete_last_comment_by_date(self):
        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.assertIsNone(ticket.get_change(cdate=self.t4))
        self.assertIsNotNone(ticket.get_change(cdate=self.t3))
        self.assertEqual(t, ticket.time_changed)

    def test_delete_mid_comment(self):
        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.assertIsNone(ticket.get_change(cnum=3))
        self.assertEqual('a', ticket['keywords'])
        self.assertChange(ticket, 4, self.t4, 'joe',
            comment=dict(author='joe', old='4', new='Comment 4'),
            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.assertIsNone(ticket.get_change(cdate=self.t3))
        self.assertEqual('a', ticket['keywords'])
        self.assertChange(ticket, 4, self.t4, 'joe',
            comment=dict(author='joe', old='4', new='Comment 4'),
            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.assertIsNone(ticket.get_change(3))
        self.assertEqual('a', ticket['keywords'])
        self.assertChange(ticket, 4, self.t4, 'joe',
            comment=dict(author='joe', old='4', new='Comment 4'),
            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 #25
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 #26
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_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 #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_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))
Example #28
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 #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'))

    def tearDown(self):
        self.dbm.drop_tables(self.schema)
        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_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
File: cache.py Project: ohanar/trac
class CacheTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()
        self.log = self.env.log
        self.env.db_transaction.executemany(
            "INSERT INTO repository (id, name, value) VALUES (%s, %s, %s)",
            [(1, 'name', 'test-repos'), (1, 'youngest_rev', '')])

    def tearDown(self):
        self.env.reset_db()

    # Helpers

    def get_repos(self, get_changeset=None, youngest_rev=1):
        if get_changeset is None:

            def no_changeset(rev):
                raise NoSuchChangeset(rev)

            get_changeset = no_changeset
        return Mock(Repository, 'test-repos', {'name': 'test-repos', 'id': 1},
                    self.log,
                    get_changeset=get_changeset,
                    get_oldest_rev=lambda: 0,
                    get_youngest_rev=lambda: youngest_rev,
                    normalize_rev=lambda x: get_changeset(x).rev,
                    next_rev=(lambda x: int(x) < youngest_rev and x + 1 \
                              or None))

    def preset_cache(self, *args):
        """Each arg is a (rev tuple, changes list of tuples) pair."""
        with self.env.db_transaction as db:
            for rev, changes in args:
                db(
                    """INSERT INTO revision (repos, rev, time, author, message)
                      VALUES (1,%s,%s,%s,%s)
                      """, rev)
                if changes:
                    db.executemany(
                        """
                          INSERT INTO node_change (repos, rev, path, node_type,
                                                   change_type, base_path,
                                                   base_rev)
                          VALUES (1, %s, %s, %s, %s, %s, %s)
                          """, [(rev[0], ) + change for change in changes])
            db(
                """UPDATE repository SET value=%s
                  WHERE id=1 AND name='youngest_rev'
                  """, (args[-1][0][0], ))

    # Tests

    def test_initial_sync_with_empty_repos(self):
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEquals(
                [], db("SELECT rev, time, author, message FROM revision"))
            self.assertEquals(0, db("SELECT COUNT(*) FROM node_change")[0][0])

    def test_initial_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=1)
        changes = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                   ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changesets = [
            Mock(Changeset, repos, 0, '', '', t1, get_changes=lambda: []),
            Mock(Changeset,
                 repos,
                 1,
                 'Import',
                 'joe',
                 t2,
                 get_changes=lambda: iter(changes))
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            rows = db("SELECT rev, time, author, message FROM revision")
            self.assertEquals(len(rows), 2)
            self.assertEquals(('0', to_utimestamp(t1), '', ''), rows[0])
            self.assertEquals(('1', to_utimestamp(t2), 'joe', 'Import'),
                              rows[1])
            rows = db("""
                SELECT rev, path, node_type, change_type, base_path, base_rev
                FROM node_change""")
            self.assertEquals(len(rows), 2)
            self.assertEquals(('1', 'trunk', 'D', 'A', None, None), rows[0])
            self.assertEquals(('1', 'trunk/README', 'F', 'A', None, None),
                              rows[1])

    def test_update_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'), [
                ('trunk', 'D', 'A', None, None),
                ('trunk/README', 'F', 'A', None, None)
            ]),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=2)
        changes = [('trunk/README', Node.FILE, Changeset.EDIT, 'trunk/README',
                    1)]
        changesets = [
            None,
            Mock(Changeset, repos, 1, '', '', t2, get_changes=lambda: []),
            Mock(Changeset,
                 repos,
                 2,
                 'Update',
                 'joe',
                 t3,
                 get_changes=lambda: iter(changes))
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEquals(
                [(to_utimestamp(t3), 'joe', 'Update')],
                db("SELECT time, author, message FROM revision WHERE rev='2'"))
            self.assertEquals(
                [('trunk/README', 'F', 'E', 'trunk/README', '1')],
                db("""SELECT path, node_type, change_type, base_path,
                                 base_rev
                          FROM node_change WHERE rev='2'"""))

    def test_clean_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'), [
                ('trunk', 'D', 'A', None, None),
                ('trunk/README', 'F', 'A', None, None)
            ]),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=2)
        changes1 = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                    ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changes2 = [('trunk/README', Node.FILE, Changeset.EDIT, 'trunk/README',
                     1)]
        changesets = [
            Mock(Changeset,
                 repos,
                 0,
                 '**empty**',
                 'joe',
                 t1,
                 get_changes=lambda: []),
            Mock(Changeset,
                 repos,
                 1,
                 'Initial Import',
                 'joe',
                 t2,
                 get_changes=lambda: iter(changes1)),
            Mock(Changeset,
                 repos,
                 2,
                 'Update',
                 'joe',
                 t3,
                 get_changes=lambda: iter(changes2))
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync(clean=True)

        rows = self.env.db_query("""
            SELECT time, author, message FROM revision ORDER BY rev
            """)
        self.assertEquals(3, len(rows))
        self.assertEquals((to_utimestamp(t1), 'joe', '**empty**'), rows[0])
        self.assertEquals((to_utimestamp(t2), 'joe', 'Initial Import'),
                          rows[1])
        self.assertEquals((to_utimestamp(t3), 'joe', 'Update'), rows[2])

        rows = self.env.db_query("""
            SELECT rev, path, node_type, change_type, base_path, base_rev
            FROM node_change ORDER BY rev, path""")
        self.assertEquals(3, len(rows))
        self.assertEquals(('1', 'trunk', 'D', 'A', None, None), rows[0])
        self.assertEquals(('1', 'trunk/README', 'F', 'A', None, None), rows[1])
        self.assertEquals(('2', 'trunk/README', 'F', 'E', 'trunk/README', '1'),
                          rows[2])

    def test_sync_changeset(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'), [
                ('trunk', 'D', 'A', None, None),
                ('trunk/README', 'F', 'A', None, None)
            ]),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=1)
        changes1 = [('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                    ('trunk/README', Node.FILE, Changeset.ADD, None, None)]
        changesets = [
            Mock(Changeset,
                 repos,
                 0,
                 '**empty**',
                 'joe',
                 t1,
                 get_changes=lambda: []),
            Mock(Changeset,
                 repos,
                 1,
                 'Initial Import',
                 'joe',
                 t2,
                 get_changes=lambda: iter(changes1)),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync_changeset(0)

        rows = self.env.db_query(
            "SELECT time, author, message FROM revision ORDER BY rev")
        self.assertEquals(2, len(rows))
        self.assertEquals((to_utimestamp(t1), 'joe', '**empty**'), rows[0])
        self.assertEquals((to_utimestamp(t2), 'joe', 'Import'), rows[1])

    def test_sync_changeset_if_not_exists(self):
        t = [
            datetime(2001, 1, 1, 1, 1, 1, 0, utc),  # r0
            datetime(2002, 1, 1, 1, 1, 1, 0, utc),  # r1
            datetime(2003, 1, 1, 1, 1, 1, 0, utc),  # r2
            datetime(2004, 1, 1, 1, 1, 1, 0, utc),  # r3
        ]
        self.preset_cache(
            (('0', to_utimestamp(t[0]), 'joe', '**empty**'), []),
            (('1', to_utimestamp(t[1]), 'joe', 'Import'), [
                ('trunk', 'D', 'A', None, None),
                ('trunk/README', 'F', 'A', None, None)
            ]),
            # not exists r2
            (('3', to_utimestamp(t[3]), 'joe', 'Add COPYING'), [
                ('trunk/COPYING', 'F', 'A', None, None)
            ]),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)],
                               youngest_rev=3)
        changes = [
            None,  # r0
            [
                ('trunk', Node.DIRECTORY, Changeset.ADD, None, None),  # r1
                ('trunk/README', Node.FILE, Changeset.ADD, None, None)
            ],
            [
                ('branches', Node.DIRECTORY, Changeset.ADD, None, None),  # r2
                ('tags', Node.DIRECTORY, Changeset.ADD, None, None)
            ],
            [('trunk/COPYING', Node.FILE, Changeset.ADD, None, None)],  # r3
        ]
        changesets = [
            Mock(Changeset,
                 repos,
                 0,
                 '**empty**',
                 'joe',
                 t[0],
                 get_changes=lambda: []),
            Mock(Changeset,
                 repos,
                 1,
                 'Initial Import',
                 'joe',
                 t[1],
                 get_changes=lambda: iter(changes[1])),
            Mock(Changeset,
                 repos,
                 2,
                 'Created directories',
                 'john',
                 t[2],
                 get_changes=lambda: iter(changes[2])),
            Mock(Changeset,
                 repos,
                 3,
                 'Add COPYING',
                 'joe',
                 t[3],
                 get_changes=lambda: iter(changes[3])),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)
        cache.sync()
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)

        self.assertEqual(None, cache.sync_changeset(2))
        cset = cache.get_changeset(2)
        self.assertEqual('john', cset.author)
        self.assertEqual('Created directories', cset.message)
        self.assertEqual(t[2], cset.date)
        cset_changes = cset.get_changes()
        self.assertEqual(
            ('branches', Node.DIRECTORY, Changeset.ADD, None, None),
            cset_changes.next())
        self.assertEqual(('tags', Node.DIRECTORY, Changeset.ADD, None, None),
                         cset_changes.next())
        self.assertRaises(StopIteration, cset_changes.next)

        rows = self.env.db_query(
            "SELECT time,author,message FROM revision ORDER BY rev")
        self.assertEquals(4, len(rows))
        self.assertEquals((to_utimestamp(t[0]), 'joe', '**empty**'), rows[0])
        self.assertEquals((to_utimestamp(t[1]), 'joe', 'Import'), rows[1])
        self.assertEquals((to_utimestamp(t[2]), 'john', 'Created directories'),
                          rows[2])
        self.assertEquals((to_utimestamp(t[3]), 'joe', 'Add COPYING'), rows[3])

    def test_get_changes(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (('0', to_utimestamp(t1), '', ''), []),
            (('1', to_utimestamp(t2), 'joe', 'Import'), [
                ('trunk', 'D', 'A', None, None),
                ('trunk/RDME', 'F', 'A', None, None)
            ]),
        )
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        self.assertEqual('1', cache.youngest_rev)
        changeset = cache.get_changeset(1)
        self.assertEqual('joe', changeset.author)
        self.assertEqual('Import', changeset.message)
        self.assertEqual(t2, changeset.date)
        changes = changeset.get_changes()
        self.assertEqual(('trunk', Node.DIRECTORY, Changeset.ADD, None, None),
                         changes.next())
        self.assertEqual(('trunk/RDME', Node.FILE, Changeset.ADD, None, None),
                         changes.next())
        self.assertRaises(StopIteration, changes.next)
Example #31
0
class UpgradeTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(path=mkdtemp())
        self.dbm = DatabaseManager(self.env)
        with self.env.db_transaction:
            self.dbm.drop_tables(new_schema)
            self.dbm.create_tables(old_schema)
            self.dbm.set_database_version(VERSION - 1)

    def tearDown(self):
        self.env.reset_db_and_disk()

    def test_attachment_table_upgraded(self):
        """The ipnr column is removed from the attachment table."""
        db42.do_upgrade(self.env, VERSION, None)

        column_names = [col.name for col in new_attachment_schema.columns]
        self.assertEqual(column_names, self.dbm.get_column_names('attachment'))

    def test_wiki_table_upgraded(self):
        """The ipnr column is removed from the wiki table."""
        db42.do_upgrade(self.env, VERSION, None)

        column_names = [col.name for col in new_wiki_schema.columns]
        self.assertEqual(column_names, self.dbm.get_column_names('wiki'))

    def test_attachments_data_migrated(self):
        """Attachment data is migrated on table upgrade."""
        now = to_utimestamp(datetime_now(utc))
        attachment_column_names = \
            [col.name for col in old_attachment_schema.columns]
        attachment_data = (('ticket', '1', 'file1', 10, now, 'desc1', 'user1',
                            '::1'), ('wiki', 'WikiStart', 'file2', 20, now,
                                     'desc2', 'user2', '::2'))
        self.dbm.insert_into_tables(
            (('attachment', attachment_column_names, attachment_data), ))

        db42.do_upgrade(self.env, VERSION, None)

        ipnr_col = attachment_column_names.index('ipnr')
        i = 0
        for i, data in enumerate(
                self.env.db_query("""
                SELECT * FROM attachment ORDER BY type
                """)):
            self.assertEqual(
                attachment_data[i][:ipnr_col] +
                attachment_data[i][ipnr_col + 1:], data)
        self.assertEqual(len(attachment_data), i + 1)

    def test_wiki_data_migrated(self):
        """Wiki data is migrated on table upgrade."""
        now = to_utimestamp(datetime_now(utc))
        wiki_column_names = \
            [col.name for col in old_wiki_schema.columns]
        wiki_data = (('TracGuide', 2, now, 'user2', '::4', 'The guide', 'Edit',
                      0), ('WikiStart', 1, now, 'user1', '::3', 'The page',
                           'Init', 1))
        self.dbm.insert_into_tables((('wiki', wiki_column_names, wiki_data), ))

        db42.do_upgrade(self.env, VERSION, None)

        ipnr_col = wiki_column_names.index('ipnr')
        i = 0
        for i, data in enumerate(
                self.env.db_query("""
                SELECT * FROM wiki ORDER BY name
                """)):
            self.assertEqual(
                wiki_data[i][:ipnr_col] + wiki_data[i][ipnr_col + 1:], data)
        self.assertEqual(len(wiki_data), i + 1)
Example #32
0
class SubscriptionTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def _add_subscriber(self,
                        req,
                        class_,
                        distributor='email',
                        format='text/plain',
                        adverb='always'):
        session = req.session
        args = {
            'sid': session.sid,
            'authenticated': session.authenticated,
            'distributor': distributor,
            'format': format,
            'adverb': adverb,
            'class': class_
        }
        return Subscription.add(self.env, args)

    def _insert_rows(self):
        rows = [
            ('joe', 1, 'email', 'text/plain', 1, 'always', 'EmailSubscriber1'),
            ('joe', 1, 'email', 'text/html', 2, 'always', 'EmailSubscriber2'),
            ('joe', 1, 'email', 'text/plain', 3, 'always', 'EmailSubscriber3'),
            ('joe', 1, 'xmpp', 'text/html', 1, 'always', 'XmppSubscriber1'),
            ('joe', 1, 'xmpp', 'text/plain', 2, 'never', 'XmppSubscriber2'),
            ('joe', 1, 'xmpp', 'text/html', 3, 'never', 'XmppSubscriber3'),
            ('joe', 1, 'irc', 'text/plain', 1, 'never', 'IrcSubscriber1'),
            ('joe', 1, 'irc', 'text/plain', 2, 'never', 'IrcSubscriber2'),
            ('joe', 1, 'irc', 'text/plain', 3, 'never', 'IrcSubscriber3'),
            ('jes', 1, 'email', 'text/html', 1, 'always', 'EmailSubscriber1'),
            ('jes', 1, 'email', 'text/plain', 2, 'never', 'EmailSubscriber2'),
            ('jes', 1, 'email', 'text/html', 3, 'always', 'EmailSubscriber3'),
            ('jan', 1, 'xmpp', 'text/plain', 1, 'always', 'XmppSubscriber1'),
            ('jan', 1, 'xmpp', 'text/html', 2, 'never', 'XmppSubscriber2'),
            ('jan', 1, 'xmpp', 'text/plain', 3, 'never', 'XmppSubscriber3'),
            ('jim', 1, 'irc', 'text/html', 1, 'always', 'IrcSubscriber1'),
            ('jim', 1, 'irc', 'text/plain', 2, 'never', 'IrcSubscriber2'),
            ('jim', 1, 'irc', 'text/html', 3, 'always', 'IrcSubscriber3'),
        ]
        ts = to_utimestamp(datetime(2016, 2, 3, 12, 34, 56, 987654, utc))
        with self.env.db_transaction as db:
            cursor = db.cursor()
            cursor.executemany(
                """
                INSERT INTO notify_subscription (
                    time, changetime, sid, authenticated, distributor,
                    format, priority, adverb, class)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)""",
                [(ts + idx, ts + idx * 2) + row
                 for idx, row in enumerate(rows)])

    def _props(self, items, name):
        return [item[name] for item in items]

    def test_add(self):
        req = MockRequest(self.env, authname='joe')
        with self.env.db_transaction:
            self._add_subscriber(req, 'TicketSubscriber1', format='text/html')
            self._add_subscriber(req, 'TicketSubscriber2')
            self._add_subscriber(req, 'TicketSubscriber3', format='text/html')
            self._add_subscriber(req,
                                 'XmppSubscriber1',
                                 distributor='xmpp',
                                 adverb='never')
        self.assertEqual([(u'joe', 1, u'email', u'text/html', 1, u'always',
                           u'TicketSubscriber1'),
                          (u'joe', 1, u'email', u'text/plain', 2, u'always',
                           u'TicketSubscriber2'),
                          (u'joe', 1, u'email', u'text/html', 3, u'always',
                           u'TicketSubscriber3'),
                          (u'joe', 1, u'xmpp', u'text/plain', 1, u'never',
                           u'XmppSubscriber1')],
                         self.env.db_query(
                             """\
                SELECT sid, authenticated, distributor, format, priority,
                       adverb, class
                FROM notify_subscription
                WHERE sid=%s AND authenticated=%s
                ORDER BY distributor, priority""", ('joe', 1)))

    def test_delete(self):
        req = MockRequest(self.env, authname='joe')
        with self.env.db_transaction:
            ids = [
                self._add_subscriber(req, 'TicketSubscriber1'),
                self._add_subscriber(req, 'TicketSubscriber2'),
                self._add_subscriber(req, 'TicketSubscriber3'),
                self._add_subscriber(req,
                                     'XmppSubscriber1',
                                     distributor='xmpp',
                                     adverb='never'),
                self._add_subscriber(req,
                                     'XmppSubscriber2',
                                     distributor='xmpp')
            ]
        self.assertEqual(
            5,
            self.env.db_query(
                """\
            SELECT COUNT(*) FROM notify_subscription
            WHERE sid=%s AND authenticated=%s""", ('joe', 1))[0][0])

        Subscription.delete(self.env, ids[1])
        rows = self.env.db_query(
            """\
            SELECT id, distributor, priority, class FROM notify_subscription
            WHERE sid=%s AND authenticated=%s
            ORDER BY distributor, priority""", ('joe', 1))
        self.assertEqual((ids[0], 'email', 1, 'TicketSubscriber1'), rows[0])
        self.assertEqual((ids[2], 'email', 2, 'TicketSubscriber3'), rows[1])
        self.assertEqual((ids[3], 'xmpp', 1, 'XmppSubscriber1'), rows[2])
        self.assertEqual((ids[4], 'xmpp', 2, 'XmppSubscriber2'), rows[3])
        self.assertEqual(4, len(rows))

    def test_find_by_sid_and_distributor(self):
        self._insert_rows()
        items = Subscription.find_by_sid_and_distributor(
            self.env, 'joe', True, 'xmpp')
        self.assertEqual(['joe'] * 3, self._props(items, 'sid'))
        self.assertEqual([1] * 3, self._props(items, 'authenticated'))
        self.assertEqual(['xmpp'] * 3, self._props(items, 'distributor'))
        self.assertEqual(['text/html', 'text/plain', 'text/html'],
                         self._props(items, 'format'))
        self.assertEqual([1, 2, 3], self._props(items, 'priority'))
        self.assertEqual(['always', 'never', 'never'],
                         self._props(items, 'adverb'))
        self.assertEqual(
            ['XmppSubscriber1', 'XmppSubscriber2', 'XmppSubscriber3'],
            self._props(items, 'class'))

    def test_find_by_sids_and_class(self):
        self._insert_rows()
        sids = [('joe', True), ('jes', True), ('jan', True), ('jim', True)]
        items = Subscription.find_by_sids_and_class(self.env, sids,
                                                    'IrcSubscriber3')
        self.assertEqual(['joe', 'jim'], self._props(items, 'sid'))
        self.assertEqual([1] * 2, self._props(items, 'authenticated'))
        self.assertEqual(['irc'] * 2, self._props(items, 'distributor'))
        self.assertEqual(['text/plain', 'text/html'],
                         self._props(items, 'format'))
        self.assertEqual([3, 3], self._props(items, 'priority'))
        self.assertEqual(['never', 'always'], self._props(items, 'adverb'))
        self.assertEqual(['IrcSubscriber3', 'IrcSubscriber3'],
                         self._props(items, 'class'))

    def test_move(self):
        def query_subs():
            return self.env.db_query(
                """\
                SELECT distributor, priority, class
                FROM notify_subscription WHERE sid=%s AND authenticated=%s
                ORDER BY distributor, priority""", ('joe', 1))

        req = MockRequest(self.env, authname='joe')
        with self.env.db_transaction:
            rule_ids = {}
            for class_, distributor in [('EmailSubscriber1', 'email'),
                                        ('EmailSubscriber2', 'email'),
                                        ('EmailSubscriber3', 'email'),
                                        ('EmailSubscriber4', 'email'),
                                        ('XmppSubscriber1', 'xmpp'),
                                        ('XmppSubscriber2', 'xmpp')]:
                rule_ids[(class_, distributor)] = \
                    self._add_subscriber(req, class_, distributor)
        self.assertEqual([
            ('email', 1, 'EmailSubscriber1'),
            ('email', 2, 'EmailSubscriber2'),
            ('email', 3, 'EmailSubscriber3'),
            ('email', 4, 'EmailSubscriber4'),
            ('xmpp', 1, 'XmppSubscriber1'),
            ('xmpp', 2, 'XmppSubscriber2'),
        ], query_subs())

        Subscription.move(self.env, rule_ids[('EmailSubscriber3', 'email')], 1)
        self.assertEqual([
            ('email', 1, 'EmailSubscriber3'),
            ('email', 2, 'EmailSubscriber1'),
            ('email', 3, 'EmailSubscriber2'),
            ('email', 4, 'EmailSubscriber4'),
            ('xmpp', 1, 'XmppSubscriber1'),
            ('xmpp', 2, 'XmppSubscriber2'),
        ], query_subs())

        Subscription.move(self.env, rule_ids[('EmailSubscriber1', 'email')], 4)
        self.assertEqual([
            ('email', 1, 'EmailSubscriber3'),
            ('email', 2, 'EmailSubscriber2'),
            ('email', 3, 'EmailSubscriber4'),
            ('email', 4, 'EmailSubscriber1'),
            ('xmpp', 1, 'XmppSubscriber1'),
            ('xmpp', 2, 'XmppSubscriber2'),
        ], query_subs())

        Subscription.move(self.env, rule_ids[('EmailSubscriber3', 'email')], 3)
        self.assertEqual([
            ('email', 1, 'EmailSubscriber2'),
            ('email', 2, 'EmailSubscriber4'),
            ('email', 3, 'EmailSubscriber3'),
            ('email', 4, 'EmailSubscriber1'),
            ('xmpp', 1, 'XmppSubscriber1'),
            ('xmpp', 2, 'XmppSubscriber2'),
        ], query_subs())

    def test_replace_all(self):
        def query(sid, authenticated):
            return self.env.db_query(
                """\
                SELECT distributor, format, priority, adverb, class
                FROM notify_subscription
                WHERE sid=%s AND authenticated=%s
                ORDER BY distributor, priority""", (sid, authenticated))

        req = MockRequest(self.env, authname='joe')
        sess = req.session
        items = [
            ('email', 'text/plain', 'always', 'TicketSubscriber1'),
            ('email', 'text/html', 'always', 'TicketSubscriber2'),
            ('email', 'text/html', 'always', 'TicketSubscriber3'),
            ('xmpp', 'text/html', 'never', 'XmppSubscriber1'),
            ('xmpp', 'text/plain', 'always', 'XmppSubscriber2'),
        ]
        items = [
            dict(zip(('distributor', 'format', 'adverb', 'class'), item))
            for item in items
        ]
        Subscription.replace_all(self.env, sess.sid, sess.authenticated, items)
        rows = query('joe', 1)
        expected = [
            ('email', 'text/plain', 1, 'always', 'TicketSubscriber1'),
            ('email', 'text/html', 2, 'always', 'TicketSubscriber2'),
            ('email', 'text/html', 3, 'always', 'TicketSubscriber3'),
            ('xmpp', 'text/html', 1, 'never', 'XmppSubscriber1'),
            ('xmpp', 'text/plain', 2, 'always', 'XmppSubscriber2'),
        ]
        self.assertEqual(expected, rows)

        items = [
            ('email', 'text/plain', 'never', 'TicketSubscriber3'),
            ('xmpp', 'text/html', 'always', 'XmppSubscriber1'),
        ]
        items = [
            dict(zip(('distributor', 'format', 'adverb', 'class'), item))
            for item in items
        ]
        Subscription.replace_all(self.env, sess.sid, sess.authenticated, items)
        rows = query('joe', 1)
        expected = [
            ('email', 'text/plain', 1, 'never', 'TicketSubscriber3'),
            ('xmpp', 'text/html', 1, 'always', 'XmppSubscriber1'),
        ]
        self.assertEqual(expected, rows)

        Subscription.replace_all(self.env, sess.sid, sess.authenticated, [])
        self.assertEqual([], query('joe', 1))

    def test_update_format_by_distributor_and_sid(self):
        self._insert_rows()
        Subscription.update_format_by_distributor_and_sid(
            self.env, 'email', 'joe', True, 'application/pdf')
        rows = self.env.db_query(
            """\
            SELECT distributor, format, priority, adverb, class
            FROM notify_subscription
            WHERE sid=%s AND authenticated=%s
            ORDER BY distributor, priority""", ('joe', 1))
        expected = [
            ('email', 'application/pdf', 1, 'always', 'EmailSubscriber1'),
            ('email', 'application/pdf', 2, 'always', 'EmailSubscriber2'),
            ('email', 'application/pdf', 3, 'always', 'EmailSubscriber3'),
            ('irc', 'text/plain', 1, 'never', 'IrcSubscriber1'),
            ('irc', 'text/plain', 2, 'never', 'IrcSubscriber2'),
            ('irc', 'text/plain', 3, 'never', 'IrcSubscriber3'),
            ('xmpp', 'text/html', 1, 'always', 'XmppSubscriber1'),
            ('xmpp', 'text/plain', 2, 'never', 'XmppSubscriber2'),
            ('xmpp', 'text/html', 3, 'never', 'XmppSubscriber3'),
        ]
        self.assertEqual(expected, rows)
Example #33
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 #34
0
class TicketTagProviderTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True,
                                   enable=['trac.*', 'tractags.*'])
        self.env.path = tempfile.mkdtemp()
        self.perms = PermissionSystem(self.env)

        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()

        self.provider = TicketTagProvider(self.env)
        self.realm = 'ticket'
        self.tag_sys = TagSystem(self.env)
        self.tags = ['tag1', 'tag2']

        # Populate tables with initial test data.
        self._create_ticket(self.tags)

        # Mock an anonymous request.
        self.anon_req = Mock()
        self.anon_req.perm = PermissionCache(self.env)

        self.req = Mock(authname='editor')
        self.req.authname = 'editor'
        self.req.perm = PermissionCache(self.env, username='******')

    def tearDown(self):
        self.env.shutdown()
        shutil.rmtree(self.env.path)

    # Helpers

    def _create_ticket(self, tags, **kwargs):
        ticket = Ticket(self.env)
        ticket['keywords'] = u' '.join(sorted(map(to_unicode, tags)))
        ticket['summary'] = 'summary'
        ticket['reporter'] = 'admin'
        for name, value in kwargs.iteritems():
            ticket[name] = value
        ticket.insert()
        return ticket

    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_tagged_resources(self):
        # No tags, no restrictions, all resources.
        self.assertEquals(
            [r for r in
             self.provider.get_tagged_resources(self.req, None)][0][1],
            set(self.tags))
        # Force fine-grained perm-check check for all tags, not just the one
        # from query.
        self.provider.fast_permcheck = False
        self.assertEquals(
            [r for r in
             self.provider.get_tagged_resources(self.req,
                                                set(self.tags[:1]))][0][1],
            set(self.tags))

    def test_get_tags(self):
        resource = Resource('ticket', 2)
        self.assertRaises(ResourceNotFound, self.provider.get_resource_tags,
                          self.req, resource)
        self._create_ticket(self.tags)
        self.assertEquals(
            [tag for tag in
             self.provider.get_resource_tags(self.req, resource)], self.tags)
        #ignore_closed_tickets

    def test_set_tags(self):
        tags = ['tag3']
        ticket = Ticket(self.env, 1)
        ticket['keywords'] = tags[0]
        # Tags get updated by TicketChangeListener method.
        ticket.save_changes(self.req.authname)
        self.assertEquals(self.tag_sys.get_all_tags(self.req).keys(), tags)

    def test_remove_tags(self):
        resource = Resource('ticket', 1)
        # Anonymous lacks required permissions.
        self.assertRaises(PermissionError, self.provider.remove_resource_tags,
                          self.anon_req, resource)
        # Shouldn't raise an error with appropriate permission.
        self.provider.remove_resource_tags(self.req, resource, 'comment')
        ticket = Ticket(self.env, 1)
        self.assertEquals(ticket['keywords'], '')

    def test_describe_tagged_resource(self):
        resource = Resource('ticket', 1)
        self.assertEquals(
            self.provider.describe_tagged_resource(self.req, resource),
            'defect: summary')

    def test_create_ticket_by_anonymous(self):
        ticket = self._create_ticket(self.tags, reporter='anonymous')
        tags = self.provider.get_resource_tags(self.req, ticket.resource)
        self.assertEquals(tags, set(self.tags))

    def test_update_ticket_by_anonymous(self):
        ticket = self._create_ticket([])
        tags = self.provider.get_resource_tags(self.req, ticket.resource)
        self.assertEquals(tags, set([]))

        ticket['keywords'] = ', '.join(self.tags)
        ticket.save_changes('anonymous', comment='Adding keywords')
        tags = self.provider.get_resource_tags(self.req, ticket.resource)
        self.assertEquals(tags, set(self.tags))
Example #35
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 #36
0
class TicketTagProviderTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(default_data=True,
                                   enable=['trac.*', 'tractags.*'])
        self.env.path = tempfile.mkdtemp()
        self.perms = PermissionSystem(self.env)

        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()

        self.provider = TicketTagProvider(self.env)
        self.realm = 'ticket'
        self.tag_sys = TagSystem(self.env)
        self.tags = ['tag1', 'tag2']

        # Populate tables with initial test data.
        self._create_ticket(self.tags)

    def tearDown(self):
        self.env.shutdown()
        shutil.rmtree(self.env.path)

    # Helpers

    def _create_ticket(self, tags, **kwargs):
        ticket = Ticket(self.env)
        ticket['keywords'] = u' '.join(sorted(map(to_unicode, tags)))
        ticket['summary'] = 'summary'
        ticket['reporter'] = 'admin'
        for name, value in kwargs.iteritems():
            ticket[name] = value
        ticket.insert()
        return ticket

    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_tagged_resources(self):
        # No tags, no restrictions, all resources.
        req = MockRequest(self.env, authname='editor')
        self.assertEquals(
            [r for r in self.provider.get_tagged_resources(req, None)][0][1],
            set(self.tags))
        # Force fine-grained perm-check check for all tags, not just the one
        # from query.
        self.provider.fast_permcheck = False
        self.assertEquals([
            r for r in self.provider.get_tagged_resources(
                req, set(self.tags[:1]))
        ][0][1], set(self.tags))

    def test_get_tags(self):
        req = MockRequest(self.env, authname='editor')
        resource = Resource('ticket', 2)
        self.assertRaises(ResourceNotFound, self.provider.get_resource_tags,
                          req, resource)
        self._create_ticket(self.tags)
        self.assertEquals(
            [tag for tag in self.provider.get_resource_tags(req, resource)],
            self.tags)

    def test_set_tags(self):
        req = MockRequest(self.env, authname='editor')
        tags = ['tag3']
        ticket = Ticket(self.env, 1)
        ticket['keywords'] = tags[0]
        # Tags get updated by TicketChangeListener method.
        ticket.save_changes(req.authname)
        self.assertEquals(self.tag_sys.get_all_tags(req).keys(), tags)

    def test_remove_tags(self):
        req = MockRequest(self.env, authname='editor')
        anon_req = MockRequest(self.env, authname='anonymous')
        resource = Resource('ticket', 1)
        # Anonymous lacks required permissions.
        self.assertRaises(PermissionError, self.provider.remove_resource_tags,
                          anon_req, resource)
        # Shouldn't raise an error with appropriate permission.
        self.provider.remove_resource_tags(req, resource, 'comment')
        ticket = Ticket(self.env, 1)
        self.assertEquals(ticket['keywords'], '')

    def test_describe_tagged_resource(self):
        req = MockRequest(self.env, authname='editor')
        resource = Resource('ticket', 1)
        self.assertEquals(
            self.provider.describe_tagged_resource(req, resource),
            'defect: summary')

    def test_create_ticket_by_anonymous(self):
        req = MockRequest(self.env, authname='editor')
        ticket = self._create_ticket(self.tags, reporter='anonymous')
        tags = self.provider.get_resource_tags(req, ticket.resource)
        self.assertEquals(tags, set(self.tags))

    def test_update_ticket_by_anonymous(self):
        req = MockRequest(self.env, authname='editor')
        ticket = self._create_ticket([])
        tags = self.provider.get_resource_tags(req, ticket.resource)
        self.assertEquals(tags, set([]))

        ticket['keywords'] = ', '.join(self.tags)
        ticket.save_changes('anonymous', comment='Adding keywords')
        tags = self.provider.get_resource_tags(req, ticket.resource)
        self.assertEquals(tags, set(self.tags))
Example #37
0
class StringsTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def test_insert_unicode(self):
        self.env.db_transaction(
                "INSERT INTO system (name,value) VALUES (%s,%s)",
                ('test-unicode', u'ünicöde'))
        self.assertEqual([(u'ünicöde',)], self.env.db_query(
            "SELECT value FROM system WHERE name='test-unicode'"))

    def test_insert_empty(self):
        from trac.util.text import empty
        self.env.db_transaction(
                "INSERT INTO system (name,value) VALUES (%s,%s)",
                ('test-empty', empty))
        self.assertEqual([(u'',)], self.env.db_query(
            "SELECT value FROM system WHERE name='test-empty'"))

    def test_insert_markup(self):
        from genshi.core import Markup
        self.env.db_transaction(
                "INSERT INTO system (name,value) VALUES (%s,%s)",
                ('test-markup', Markup(u'<em>märkup</em>')))
        self.assertEqual([(u'<em>märkup</em>',)], self.env.db_query(
            "SELECT value FROM system WHERE name='test-markup'"))

    def test_quote(self):
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute('SELECT 1 AS %s' % \
                           db.quote(r'alpha\`\"\'\\beta``gamma""delta'))
            self.assertEqual(r'alpha\`\"\'\\beta``gamma""delta',
                             get_column_names(cursor)[0])

    def test_quoted_id_with_percent(self):
        name = """%?`%s"%'%%"""

        def test(logging=False):
            with self.env.db_query as db:
                cursor = db.cursor()
                if logging:
                    cursor.log = self.env.log

                cursor.execute('SELECT 1 AS ' + db.quote(name))
                self.assertEqual(name, get_column_names(cursor)[0])
                cursor.execute('SELECT %s AS ' + db.quote(name), (42,))
                self.assertEqual(name, get_column_names(cursor)[0])
                cursor.executemany("UPDATE system SET value=%s WHERE "
                                   "1=(SELECT 0 AS " + db.quote(name) + ")",
                                   [])
                cursor.executemany("UPDATE system SET value=%s WHERE "
                                   "1=(SELECT 0 AS " + db.quote(name) + ")",
                                   [('42',), ('43',)])

        test()
        test(True)

    def test_prefix_match_case_sensitive(self):
        with self.env.db_transaction as db:
            db.executemany("INSERT INTO system (name,value) VALUES (%s,1)",
                           [('blahblah',), ('BlahBlah',), ('BLAHBLAH',),
                            (u'BlähBlah',), (u'BlahBläh',)])

        with self.env.db_query as db:
            names = sorted(name for name, in db(
                "SELECT name FROM system WHERE name %s"
                % db.prefix_match(),
                (db.prefix_match_value('Blah'),)))
        self.assertEqual('BlahBlah', names[0])
        self.assertEqual(u'BlahBläh', names[1])
        self.assertEqual(2, len(names))

    def test_prefix_match_metachars(self):
        def do_query(prefix):
            with self.env.db_query as db:
                return [name for name, in db(
                    "SELECT name FROM system WHERE name %s "
                    "ORDER BY name" % db.prefix_match(),
                    (db.prefix_match_value(prefix),))]

        values = ['foo*bar', 'foo*bar!', 'foo?bar', 'foo?bar!',
                  'foo[bar', 'foo[bar!', 'foo]bar', 'foo]bar!',
                  'foo%bar', 'foo%bar!', 'foo_bar', 'foo_bar!',
                  'foo/bar', 'foo/bar!', 'fo*ob?ar[fo]ob%ar_fo/obar']
        with self.env.db_transaction as db:
            db.executemany("INSERT INTO system (name,value) VALUES (%s,1)",
                           [(value,) for value in values])

        self.assertEqual(['foo*bar', 'foo*bar!'], do_query('foo*'))
        self.assertEqual(['foo?bar', 'foo?bar!'], do_query('foo?'))
        self.assertEqual(['foo[bar', 'foo[bar!'], do_query('foo['))
        self.assertEqual(['foo]bar', 'foo]bar!'], do_query('foo]'))
        self.assertEqual(['foo%bar', 'foo%bar!'], do_query('foo%'))
        self.assertEqual(['foo_bar', 'foo_bar!'], do_query('foo_'))
        self.assertEqual(['foo/bar', 'foo/bar!'], do_query('foo/'))
        self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'], do_query('fo*'))
        self.assertEqual(['fo*ob?ar[fo]ob%ar_fo/obar'],
                         do_query('fo*ob?ar[fo]ob%ar_fo/obar'))
Example #38
0
class MySQLConnectionTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()
        self.schema = [
            Table('test_simple', key='id')[Column('id', auto_increment=True),
                                           Column('username'),
                                           Column('email'),
                                           Column('enabled', type='int'),
                                           Column('extra'),
                                           Index(['username'], unique=True),
                                           Index(['email'], unique=False), ],
            Table('test_composite',
                  key=['id',
                       'name'])[Column('id', type='int'),
                                Column('name'),
                                Column('value'),
                                Column('enabled', type='int'),
                                Index(['name', 'value'], unique=False),
                                Index(['name', 'enabled'], unique=True), ],
        ]
        self.dbm = DatabaseManager(self.env)
        self.dbm.drop_tables(self.schema)
        self.dbm.create_tables(self.schema)
        self.dbm.insert_into_tables([
            ('test_simple', ('username', 'email', 'enabled'),
             [('joe', '*****@*****.**', 1), ('joé', '*****@*****.**', 0)]),
            ('test_composite', ('id', 'name', 'value', 'enabled'),
             [(1, 'foo', '42', 1), (1, 'bar', '42', 1), (2, 'foo', '43', 0),
              (2, 'bar', '43', 0)]),
        ])

    def tearDown(self):
        DatabaseManager(self.env).drop_tables(self.schema)
        self.env.reset_db()

    def _show_index(self, table):
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("SHOW INDEX FROM " + db.quote(table))
            columns = get_column_names(cursor)
            rows = [dict(zip(columns, row)) for row in cursor]
            results = {}
            for index, group in itertools.groupby(rows,
                                                  lambda v: v['Key_name']):
                group = list(group)
                results[index] = {
                    'unique': not group[0]['Non_unique'],
                    'columns': [row['Column_name'] for row in group],
                }
            return results

    def _drop_column(self, table, column):
        with self.env.db_transaction as db:
            db.drop_column(table, column)

    def _query(self, stmt, *args):
        return self.env.db_query(stmt, args)

    def test_remove_simple_keys(self):
        indices_0 = self._show_index('test_simple')
        self.assertEqual(
            ['PRIMARY', 'test_simple_email_idx', 'test_simple_username_idx'],
            sorted(indices_0))
        self.assertEqual({
            'unique': True,
            'columns': ['id']
        }, indices_0['PRIMARY'])
        self.assertEqual({
            'unique': True,
            'columns': ['username']
        }, indices_0['test_simple_username_idx'])
        self.assertEqual({
            'unique': False,
            'columns': ['email']
        }, indices_0['test_simple_email_idx'])

        self._drop_column('test_simple', 'enabled')
        self.assertEqual(indices_0, self._show_index('test_simple'))

        self._drop_column('test_simple', 'username')
        indices_1 = self._show_index('test_simple')
        self.assertEqual(['PRIMARY', 'test_simple_email_idx'],
                         sorted(indices_1))

        self._drop_column('test_simple', 'email')
        indices_2 = self._show_index('test_simple')
        self.assertEqual(['PRIMARY'], sorted(indices_2))

        self._drop_column('test_simple', 'id')
        indices_3 = self._show_index('test_simple')
        self.assertEqual({}, indices_3)

    def test_remove_composite_keys(self):
        indices_0 = self._show_index('test_composite')
        self.assertEqual([
            'PRIMARY', 'test_composite_name_enabled_idx',
            'test_composite_name_value_idx'
        ], sorted(indices_0))
        self.assertEqual({
            'unique': True,
            'columns': ['id', 'name']
        }, indices_0['PRIMARY'])
        self.assertEqual({
            'unique': False,
            'columns': ['name', 'value']
        }, indices_0['test_composite_name_value_idx'])
        self.assertEqual({
            'unique': True,
            'columns': ['name', 'enabled']
        }, indices_0['test_composite_name_enabled_idx'])

        self._drop_column('test_composite', 'id')
        indices_1 = self._show_index('test_composite')
        self.assertEqual([
            'test_composite_name_enabled_idx', 'test_composite_name_value_idx'
        ], sorted(indices_1))
        self.assertEqual(indices_0['test_composite_name_value_idx'],
                         indices_1['test_composite_name_value_idx'])
        self.assertEqual(indices_0['test_composite_name_enabled_idx'],
                         indices_1['test_composite_name_enabled_idx'])
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY name, value, enabled""")
        self.assertEqual([('bar', '42', 1), ('bar', '43', 0), ('foo', '42', 1),
                          ('foo', '43', 0)], rows)

        self._drop_column('test_composite', 'name')
        self.assertEqual({}, self._show_index('test_composite'))
        rows = self._query("""SELECT * FROM test_composite
                              ORDER BY value, enabled""")
        self.assertEqual([('42', 1), ('42', 1), ('43', 0), ('43', 0)], rows)
Example #39
0
class UpgradeTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(path=mkdtemp())
        self.env.config.filename = os.path.join(self.env.path, 'trac.ini')
        self.env.config.set('trac', 'repository_sync_per_request',
                            'repos1, repos3, repos5')

    def tearDown(self):
        self.env.reset_db_and_disk()

    def test_saves_backup(self):
        """Backup file is saved during upgrade."""
        config = self.env.config
        db32.do_upgrade(self.env, VERSION, None)

        self.assertTrue(os.path.exists(config.filename + '.db32.bak'))

    def test_repository_sync_per_request_default_value(self):
        """The default repository sync_per_request attribute is set to true
        when repository_sync_per_request is not set in trac.ini.
        """
        self.env.config.remove('trac', 'repository_sync_per_request')
        repositories = self.env.config['repositories']
        repositories.set('.dir', '/var/svn')
        repositories.set('.type', 'svn')
        repositories.set('git.dir', '/var/git')
        repositories.set('git.type', 'git')

        db32.do_upgrade(self.env, VERSION, None)

        repositories = self.env.config['repositories']
        self.assertIn('.sync_per_request', repositories)
        self.assertTrue(repositories.getbool('.sync_per_request'))
        self.assertNotIn('git.sync_per_request', repositories)
        self.assertFalse(repositories.getbool('git.sync_per_request'))

    def test_repository_sync_per_request_default_value_with_db(self):
        """The default repository sync_per_request attribute is set to
        true when repository_sync_per_request is not set in trac.ini.
        """
        self.env.config.remove('trac', 'repository_sync_per_request')
        # directly insert repository records instead of DbRepositoryProvider
        # to avoid a TracError "The repository type 'svn' is not supported"
        with self.env.db_transaction as db:
            db.executemany(
                """INSERT INTO repository (id,name,value)
                              VALUES (%s,%s,%s)""", [(1, 'name', ''),
                                                     (1, 'dir', '/var/svn'),
                                                     (1, 'type', 'svn'),
                                                     (2, 'name', 'git'),
                                                     (2, 'dir', '/var/git'),
                                                     (2, 'type', 'git')])

        db32.do_upgrade(self.env, VERSION, None)

        repos = RepositoryManager(self.env).get_all_repositories()
        self.assertIn('', repos)
        self.assertTrue(repos['']['sync_per_request'])
        self.assertEqual(
            '1',
            self.env.db_query("""
            SELECT value FROM repository
            WHERE id=1 AND name='sync_per_request'""")[0][0])
        self.assertIn('git', repos)
        self.assertFalse(repos['git']['sync_per_request'])
        self.assertIsNone(
            self.env.db_query("""
            SELECT value FROM repository
            WHERE id=2 AND name='sync_per_request'""")[0][0])

    def test_gitweb_configuration_moved(self):
        """The Gitweb configuration is moved from the [git] section to
        the [gitweb-repositories] section.
        """
        projects_list = os.path.join(self.env.path, 'projects_list')
        projects_base = os.path.dirname(projects_list)
        projects_url = 'http://localhost/%s'
        with open(projects_list, 'w') as f:
            f.write("""
            repos1 user1+<*****@*****.**>
            repos2
            """)
        config = self.env.config['git']
        config.set('projects_list', projects_list)
        config.set('projects_base', projects_base)
        config.set('projects_url', projects_url)
        repos1_dir = os.path.join(projects_base, 'repos1')
        repos2_dir = os.path.join(projects_base, 'repos2')

        db32.do_upgrade(self.env, VERSION, None)

        repos = RepositoryManager(self.env).get_all_repositories()
        self.assertIn('repos1', repos)
        self.assertTrue(repos['repos1']['sync_per_request'])
        self.assertEqual(repos1_dir, repos['repos1']['dir'])
        self.assertEqual('http://localhost/repos1', repos['repos1']['url'])
        self.assertIn('repos2', repos)
        self.assertFalse(repos['repos2']['sync_per_request'])
        self.assertEqual(repos2_dir, repos['repos2']['dir'])
        self.assertEqual('http://localhost/repos2', repos['repos2']['url'])
        config = self.env.config['gitweb-repositories']
        self.assertNotIn('projects_list', self.env.config)
        self.assertNotIn('projects_base', self.env.config)
        self.assertNotIn('projects_url', self.env.config)
        self.assertNotIn('repository_sync_per_request', self.env.config)
        self.assertEqual(projects_list, config.get('projects_list'))
        self.assertEqual(projects_base, config.get('projects_base'))
        self.assertEqual(projects_url, config.get('projects_url'))
        self.assertEqual('repos1', config.get('sync_per_request'))

    def test_repository_providers_disabled(self):
        """Repository configuration is rewritten when repository providers
        are disabled.
        """
        projects_list = os.path.join(self.env.path, 'projects_list')
        projects_base = os.path.dirname(projects_list)
        projects_url = 'http://localhost/%s'
        with open(projects_list, 'w') as f:
            f.write("""
            repos1 user1+<*****@*****.**>
            repos2
            """)
        config = self.env.config['git']
        config.set('projects_list', projects_list)
        config.set('projects_base', projects_base)
        config.set('projects_url', projects_url)
        db_provider = DbRepositoryProvider(self.env)
        db_provider.add_repository('repos3', '/var/git/repos3', 'git')
        db_provider.add_repository('repos4', '/var/git/repos4', 'git')
        config = self.env.config['repositories']
        config.set('repos5.dir', '/var/svn/repos4')
        config.set('repos5.type', 'svn')
        config.set('repos6.dir', '/var/svn/repos5')
        config.set('repos6.type', 'svn')
        self.env.disable_component(GitwebProjectsRepositoryProvider)
        self.env.disable_component(DbRepositoryProvider)
        self.env.disable_component(RepositoryManager)

        db32.do_upgrade(self.env, VERSION, None)

        self.env.enable_component(GitwebProjectsRepositoryProvider)
        self.env.enable_component(DbRepositoryProvider)
        self.env.enable_component(RepositoryManager)
        repos = RepositoryManager(self.env).get_all_repositories()
        config = self.env.config['gitweb-repositories']
        self.assertEqual(projects_list, config.get('projects_list'))
        self.assertEqual(projects_base, config.get('projects_base'))
        self.assertEqual(projects_url, config.get('projects_url'))
        self.assertEqual('repos1', config.get('sync_per_request'))
        self.assertIn('repos1', repos)
        self.assertTrue(repos['repos1']['sync_per_request'])
        self.assertIn('repos2', repos)
        self.assertFalse(repos['repos2']['sync_per_request'])
        self.assertIn('repos3', repos)
        self.assertTrue(repos['repos3']['sync_per_request'])
        self.assertIn('repos4', repos)
        self.assertFalse(repos['repos4']['sync_per_request'])
        self.assertIn('repos5', repos)
        self.assertTrue(repos['repos5']['sync_per_request'])
        self.assertIn('repos6', repos)
        self.assertFalse(repos['repos6']['sync_per_request'])
Example #40
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 #41
0
class CacheTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub()
        self.log = self.env.log
        self.env.db_transaction.executemany(
            "INSERT INTO repository (id, name, value) VALUES (%s, %s, %s)",
            [(1, "name", "test-repos"), (1, "youngest_rev", "")],
        )

    def tearDown(self):
        self.env.reset_db()

    # Helpers

    def get_repos(self, get_changeset=None, youngest_rev=1):
        if get_changeset is None:

            def no_changeset(rev):
                raise NoSuchChangeset(rev)

            get_changeset = no_changeset
        return Mock(
            Repository,
            "test-repos",
            {"name": "test-repos", "id": 1},
            self.log,
            get_changeset=get_changeset,
            get_oldest_rev=lambda: 0,
            get_youngest_rev=lambda: youngest_rev,
            normalize_rev=lambda x: get_changeset(x).rev,
            next_rev=(lambda x: int(x) < youngest_rev and x + 1 or None),
        )

    def preset_cache(self, *args):
        """Each arg is a (rev tuple, changes list of tuples) pair."""
        with self.env.db_transaction as db:
            for rev, changes in args:
                db(
                    """INSERT INTO revision (repos, rev, time, author, message)
                      VALUES (1,%s,%s,%s,%s)
                      """,
                    rev,
                )
                if changes:
                    db.executemany(
                        """
                          INSERT INTO node_change (repos, rev, path, node_type,
                                                   change_type, base_path,
                                                   base_rev)
                          VALUES (1, %s, %s, %s, %s, %s, %s)
                          """,
                        [(rev[0],) + change for change in changes],
                    )
            db(
                """UPDATE repository SET value=%s
                  WHERE id=1 AND name='youngest_rev'
                  """,
                (args[-1][0][0],),
            )

    # Tests

    def test_initial_sync_with_empty_repos(self):
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEquals([], db("SELECT rev, time, author, message FROM revision"))
            self.assertEquals(0, db("SELECT COUNT(*) FROM node_change")[0][0])

    def test_initial_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)], youngest_rev=1)
        changes = [
            ("trunk", Node.DIRECTORY, Changeset.ADD, None, None),
            ("trunk/README", Node.FILE, Changeset.ADD, None, None),
        ]
        changesets = [
            Mock(Changeset, repos, 0, "", "", t1, get_changes=lambda: []),
            Mock(Changeset, repos, 1, "Import", "joe", t2, get_changes=lambda: iter(changes)),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            rows = db("SELECT rev, time, author, message FROM revision")
            self.assertEquals(len(rows), 2)
            self.assertEquals(("0", to_utimestamp(t1), "", ""), rows[0])
            self.assertEquals(("1", to_utimestamp(t2), "joe", "Import"), rows[1])
            rows = db(
                """
                SELECT rev, path, node_type, change_type, base_path, base_rev
                FROM node_change"""
            )
            self.assertEquals(len(rows), 2)
            self.assertEquals(("1", "trunk", "D", "A", None, None), rows[0])
            self.assertEquals(("1", "trunk/README", "F", "A", None, None), rows[1])

    def test_update_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (("0", to_utimestamp(t1), "", ""), []),
            (
                ("1", to_utimestamp(t2), "joe", "Import"),
                [("trunk", "D", "A", None, None), ("trunk/README", "F", "A", None, None)],
            ),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)], youngest_rev=2)
        changes = [("trunk/README", Node.FILE, Changeset.EDIT, "trunk/README", 1)]
        changesets = [
            None,
            Mock(Changeset, repos, 1, "", "", t2, get_changes=lambda: []),
            Mock(Changeset, repos, 2, "Update", "joe", t3, get_changes=lambda: iter(changes)),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync()

        with self.env.db_query as db:
            self.assertEquals(
                [(to_utimestamp(t3), "joe", "Update")], db("SELECT time, author, message FROM revision WHERE rev='2'")
            )
            self.assertEquals(
                [("trunk/README", "F", "E", "trunk/README", "1")],
                db(
                    """SELECT path, node_type, change_type, base_path,
                                 base_rev
                          FROM node_change WHERE rev='2'"""
                ),
            )

    def test_clean_sync(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (("0", to_utimestamp(t1), "", ""), []),
            (
                ("1", to_utimestamp(t2), "joe", "Import"),
                [("trunk", "D", "A", None, None), ("trunk/README", "F", "A", None, None)],
            ),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)], youngest_rev=2)
        changes1 = [
            ("trunk", Node.DIRECTORY, Changeset.ADD, None, None),
            ("trunk/README", Node.FILE, Changeset.ADD, None, None),
        ]
        changes2 = [("trunk/README", Node.FILE, Changeset.EDIT, "trunk/README", 1)]
        changesets = [
            Mock(Changeset, repos, 0, "**empty**", "joe", t1, get_changes=lambda: []),
            Mock(Changeset, repos, 1, "Initial Import", "joe", t2, get_changes=lambda: iter(changes1)),
            Mock(Changeset, repos, 2, "Update", "joe", t3, get_changes=lambda: iter(changes2)),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync(clean=True)

        rows = self.env.db_query(
            """
            SELECT time, author, message FROM revision ORDER BY rev
            """
        )
        self.assertEquals(3, len(rows))
        self.assertEquals((to_utimestamp(t1), "joe", "**empty**"), rows[0])
        self.assertEquals((to_utimestamp(t2), "joe", "Initial Import"), rows[1])
        self.assertEquals((to_utimestamp(t3), "joe", "Update"), rows[2])

        rows = self.env.db_query(
            """
            SELECT rev, path, node_type, change_type, base_path, base_rev
            FROM node_change ORDER BY rev, path"""
        )
        self.assertEquals(3, len(rows))
        self.assertEquals(("1", "trunk", "D", "A", None, None), rows[0])
        self.assertEquals(("1", "trunk/README", "F", "A", None, None), rows[1])
        self.assertEquals(("2", "trunk/README", "F", "E", "trunk/README", "1"), rows[2])

    def test_sync_changeset(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (("0", to_utimestamp(t1), "", ""), []),
            (
                ("1", to_utimestamp(t2), "joe", "Import"),
                [("trunk", "D", "A", None, None), ("trunk/README", "F", "A", None, None)],
            ),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)], youngest_rev=1)
        changes1 = [
            ("trunk", Node.DIRECTORY, Changeset.ADD, None, None),
            ("trunk/README", Node.FILE, Changeset.ADD, None, None),
        ]
        changesets = [
            Mock(Changeset, repos, 0, "**empty**", "joe", t1, get_changes=lambda: []),
            Mock(Changeset, repos, 1, "Initial Import", "joe", t2, get_changes=lambda: iter(changes1)),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        cache.sync_changeset(0)

        rows = self.env.db_query("SELECT time, author, message FROM revision ORDER BY rev")
        self.assertEquals(2, len(rows))
        self.assertEquals((to_utimestamp(t1), "joe", "**empty**"), rows[0])
        self.assertEquals((to_utimestamp(t2), "joe", "Import"), rows[1])

    def test_sync_changeset_if_not_exists(self):
        t = [
            datetime(2001, 1, 1, 1, 1, 1, 0, utc),  # r0
            datetime(2002, 1, 1, 1, 1, 1, 0, utc),  # r1
            datetime(2003, 1, 1, 1, 1, 1, 0, utc),  # r2
            datetime(2004, 1, 1, 1, 1, 1, 0, utc),  # r3
        ]
        self.preset_cache(
            (("0", to_utimestamp(t[0]), "joe", "**empty**"), []),
            (
                ("1", to_utimestamp(t[1]), "joe", "Import"),
                [("trunk", "D", "A", None, None), ("trunk/README", "F", "A", None, None)],
            ),
            # not exists r2
            (("3", to_utimestamp(t[3]), "joe", "Add COPYING"), [("trunk/COPYING", "F", "A", None, None)]),
        )
        repos = self.get_repos(get_changeset=lambda x: changesets[int(x)], youngest_rev=3)
        changes = [
            None,  # r0
            [
                ("trunk", Node.DIRECTORY, Changeset.ADD, None, None),  # r1
                ("trunk/README", Node.FILE, Changeset.ADD, None, None),
            ],
            [
                ("branches", Node.DIRECTORY, Changeset.ADD, None, None),  # r2
                ("tags", Node.DIRECTORY, Changeset.ADD, None, None),
            ],
            [("trunk/COPYING", Node.FILE, Changeset.ADD, None, None)],  # r3
        ]
        changesets = [
            Mock(Changeset, repos, 0, "**empty**", "joe", t[0], get_changes=lambda: []),
            Mock(Changeset, repos, 1, "Initial Import", "joe", t[1], get_changes=lambda: iter(changes[1])),
            Mock(Changeset, repos, 2, "Created directories", "john", t[2], get_changes=lambda: iter(changes[2])),
            Mock(Changeset, repos, 3, "Add COPYING", "joe", t[3], get_changes=lambda: iter(changes[3])),
        ]
        cache = CachedRepository(self.env, repos, self.log)
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)
        cache.sync()
        self.assertRaises(NoSuchChangeset, cache.get_changeset, 2)

        self.assertEqual(None, cache.sync_changeset(2))
        cset = cache.get_changeset(2)
        self.assertEqual("john", cset.author)
        self.assertEqual("Created directories", cset.message)
        self.assertEqual(t[2], cset.date)
        cset_changes = cset.get_changes()
        self.assertEqual(("branches", Node.DIRECTORY, Changeset.ADD, None, None), cset_changes.next())
        self.assertEqual(("tags", Node.DIRECTORY, Changeset.ADD, None, None), cset_changes.next())
        self.assertRaises(StopIteration, cset_changes.next)

        rows = self.env.db_query("SELECT time,author,message FROM revision ORDER BY rev")
        self.assertEquals(4, len(rows))
        self.assertEquals((to_utimestamp(t[0]), "joe", "**empty**"), rows[0])
        self.assertEquals((to_utimestamp(t[1]), "joe", "Import"), rows[1])
        self.assertEquals((to_utimestamp(t[2]), "john", "Created directories"), rows[2])
        self.assertEquals((to_utimestamp(t[3]), "joe", "Add COPYING"), rows[3])

    def test_get_changes(self):
        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
        self.preset_cache(
            (("0", to_utimestamp(t1), "", ""), []),
            (
                ("1", to_utimestamp(t2), "joe", "Import"),
                [("trunk", "D", "A", None, None), ("trunk/RDME", "F", "A", None, None)],
            ),
        )
        repos = self.get_repos()
        cache = CachedRepository(self.env, repos, self.log)
        self.assertEqual("1", cache.youngest_rev)
        changeset = cache.get_changeset(1)
        self.assertEqual("joe", changeset.author)
        self.assertEqual("Import", changeset.message)
        self.assertEqual(t2, changeset.date)
        changes = changeset.get_changes()
        self.assertEqual(("trunk", Node.DIRECTORY, Changeset.ADD, None, None), changes.next())
        self.assertEqual(("trunk/RDME", Node.FILE, Changeset.ADD, None, None), changes.next())
        self.assertRaises(StopIteration, changes.next)
Example #42
0
class WikiTagProviderTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(default_data=True,
                                   path=tempfile.mkdtemp(),
                                   enable=['trac.*', 'tractags.*'])
        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.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')
        req = MockRequest(self.env, authname='editor')
        self.assertEquals([tag for tag in
                           self.tag_wp.get_resource_tags(req, resource)],
                          self.tags)

    def test_exclude_template_tags(self):
        # Populate table with more test data.
        req = MockRequest(self.env, authname='editor')
        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(req).keys(), self.tags)
        self.env.config.set('tags', 'query_exclude_wiki_templates', False)
        self.assertEquals(self.tag_s.get_all_tags(req).keys(), tags)

    def test_set_tags_no_perms(self):
        resource = Resource('wiki', 'TaggedPage')
        req = MockRequest(self.env, authname='anonymous')
        self.assertRaises(PermissionError, self.tag_wp.set_resource_tags,
                          req, resource, self.tags)

    def test_set_tags(self):
        resource = Resource('wiki', 'TaggedPage')
        req = MockRequest(self.env, authname='editor')
        # Shouldn't raise an error with appropriate permission.
        self.tag_wp.set_resource_tags(req, resource, self.tags)
        self.tag_wp.set_resource_tags(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 #43
0
class SessionTestCase(unittest.TestCase):
    """Unit tests for the persistent session support."""
    def setUp(self):
        self.env = EnvironmentStub()

    def tearDown(self):
        self.env.reset_db()

    def test_new_session(self):
        """
        Verify that a session cookie gets sent back to the client for a new
        session.
        """
        cookie = Cookie()
        req = Mock(incookie=Cookie(),
                   outcookie=cookie,
                   authname='anonymous',
                   base_path='/')
        session = Session(self.env, req)
        self.assertEqual(session.sid, cookie['trac_session'].value)
        self.assertEqual(
            0,
            self.env.db_query("SELECT COUNT(*) FROM session")[0][0])

    def test_anonymous_session(self):
        """
        Verify that session variables are stored in the database.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        outcookie = Cookie()
        req = Mock(authname='anonymous',
                   base_path='/',
                   incookie=incookie,
                   outcookie=outcookie)
        session = Session(self.env, req)
        self.assertEquals('123456', session.sid)
        self.failIf(outcookie.has_key('trac_session'))

    def test_authenticated_session(self):
        """
        Verifies that a session cookie does not get used if the user is logged
        in, and that Trac expires the cookie.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        outcookie = Cookie()
        req = Mock(authname='john',
                   base_path='/',
                   incookie=incookie,
                   outcookie=outcookie)
        session = Session(self.env, req)
        self.assertEqual('john', session.sid)
        session['foo'] = 'bar'
        session.save()
        self.assertEquals(0, outcookie['trac_session']['expires'])

    def test_session_promotion(self):
        """
        Verifies that an existing anonymous session gets promoted to an
        authenticated session when the user logs in.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='john',
                       base_path='/',
                       incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            self.assertEqual('john', session.sid)
            session.save()

        self.assertEqual(
            [('john', 1)],
            self.env.db_query("SELECT sid, authenticated FROM session"))

    def test_new_session_promotion(self):
        """
        Verifies that even without a preexisting anonymous session,
        an authenticated session will be created when the user logs in.
        (same test as above without the initial INSERT)
        """
        with self.env.db_transaction as db:
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='john',
                       base_path='/',
                       incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            self.assertEqual('john', session.sid)
            session.save()

        self.assertEqual(
            [('john', 1)],
            self.env.db_query("SELECT sid, authenticated FROM session"))

    def test_add_anonymous_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an anonymous session.
        """
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname='anonymous',
                   base_path='/',
                   incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()

        self.assertEqual(
            'bar',
            self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0]
            [0])

    def test_modify_anonymous_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES 
                ('123456', 0, 'foo', 'bar')
                """)
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous',
                       base_path='/',
                       incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query(
                "SELECT value FROM session_attribute WHERE sid='123456'")[0]
            [0])

    def test_delete_anonymous_session_var(self):
        """
        Verify that modifying a variable updates the 'session' table accordingly
        for an anonymous session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute VALUES 
                ('123456', 0, 'foo', 'bar')
                """)
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous',
                       base_path='/',
                       incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='123456' AND name='foo'
            """)[0][0])

    def test_purge_anonymous_session(self):
        """
        Verify that old sessions get purged.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)", (0, ))
            db("INSERT INTO session VALUES ('987654', 0, %s)",
               (int(time.time() - PURGE_AGE - 3600), ))
            db("""
                INSERT INTO session_attribute
                VALUES ('987654', 0, 'foo', 'bar')
                """)

            # We need to modify a different session to trigger the purging
            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous',
                       base_path='/',
                       incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            session['foo'] = 'bar'
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='987654' AND authenticated=0
            """)[0][0])

    def test_delete_empty_session(self):
        """
        Verify that a session gets deleted when it doesn't have any data except
        for the 'last_visit' timestamp.
        """
        now = time.time()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, %s)",
               (int(now - UPDATE_INTERVAL - 3600), ))
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            incookie = Cookie()
            incookie['trac_session'] = '123456'
            req = Mock(authname='anonymous',
                       base_path='/',
                       incookie=incookie,
                       outcookie=Cookie())
            session = Session(self.env, req)
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session WHERE sid='123456' AND authenticated=0
            """)[0][0])

    def test_change_anonymous_session(self):
        """
        Verify that changing from one anonymous session to an inexisting
        anonymous session creates the new session and doesn't carry over
        variables from the previous session.
        """

        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 0)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname='anonymous',
                   base_path='/',
                   incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        self.assertEqual({'foo': 'bar'}, session)

        session.get_session('7890')
        session['baz'] = 'moo'
        session.save()
        self.assertEqual({'baz': 'moo'}, session)

        with self.env.db_query as db:
            self.assertEqual(
                1,
                db("""
                SELECT COUNT(*) FROM session
                WHERE sid='7890' AND authenticated=0
                """)[0][0])
            self.assertEqual([('baz', 'moo')],
                             db("""
                SELECT name, value FROM session_attribute
                WHERE sid='7890' AND authenticated=0
                """))

    def test_add_authenticated_session_var(self):
        """
        Verify that new variables are inserted into the 'session' table in the
        database for an authenticated session.
        """
        req = Mock(authname='john', base_path='/', incookie=Cookie())
        session = Session(self.env, req)
        session['foo'] = 'bar'
        session.save()

        self.assertEqual(
            'bar',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_modify_authenticated_session_var(self):
        """
        Verify that modifying an existing variable updates the 'session' table
        accordingly for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

            req = Mock(authname='john', base_path='/', incookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_authenticated_session_independence_var(self):
        """
        Verify that an anonymous session with the same name as an authenticated
        session doesn't interfere with the latter.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john',1,'foo','bar')")

        self.assertEqual(
            'bar',
            self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)[0][0])

        incookie = Cookie()
        incookie['trac_session'] = 'john'
        req = Mock(authname='anonymous',
                   base_path='/',
                   incookie=incookie,
                   outcookie=Cookie())
        session = Session(self.env, req)
        self.assert_('foo' not in session)
        session['foo'] = 'baz'
        session.save()

        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=1 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('bar', rows[0][0])
        rows = self.env.db_query("""
            SELECT value FROM session_attribute
            WHERE sid='john' AND authenticated=0 AND name='foo'
            """)
        self.assertEqual(1, len(rows))
        self.assertEqual('baz', rows[0][0])

    def test_delete_authenticated_session_var(self):
        """
        Verify that deleting a variable updates the 'session' table accordingly
        for an authenticated session.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            req = Mock(authname='john', base_path='/', incookie=Cookie())
            session = Session(self.env, req)
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_update_session(self):
        """
        Verify that accessing a session after one day updates the sessions 
        'last_visit' variable so that the session doesn't get purged.
        """
        now = time.time()

        # Make sure the session has data so that it doesn't get dropped
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('123456', 0, 1)")
            db("""
                INSERT INTO session_attribute
                VALUES ('123456', 0, 'foo', 'bar')
                """)

            incookie = Cookie()
            incookie['trac_session'] = '123456'
            outcookie = Cookie()
            req = Mock(authname='anonymous',
                       base_path='/',
                       incookie=incookie,
                       outcookie=outcookie)
            session = Session(self.env, req)
            session['modified'] = True
            session.save()  # updating does require modifications

            self.assertEqual(PURGE_AGE, outcookie['trac_session']['expires'])

        self.assertAlmostEqual(
            now,
            int(
                self.env.db_query("""
            SELECT last_visit FROM session
            WHERE sid='123456' AND authenticated=0
            """)[0][0]), -1)

    def test_modify_detached_session(self):
        """
        Verify that modifying a variable in a session not associated with a
        request updates the database accordingly.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            session['foo'] = 'baz'
            session.save()

        self.assertEqual(
            'baz',
            self.env.db_query("""
            SELECT value FROM session_attribute WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_delete_detached_session_var(self):
        """
        Verify that removing a variable in a session not associated with a
        request deletes the variable from the database.
        """
        with self.env.db_transaction as db:
            db("INSERT INTO session VALUES ('john', 1, 0)")
            db("INSERT INTO session_attribute VALUES ('john', 1, 'foo', 'bar')"
               )

            session = DetachedSession(self.env, 'john')
            self.assertEqual('bar', session['foo'])
            del session['foo']
            session.save()

        self.assertEqual(
            0,
            self.env.db_query("""
            SELECT COUNT(*) FROM session_attribute
            WHERE sid='john' AND name='foo'
            """)[0][0])

    def test_session_admin_list(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)

        # Verify the empty case
        self.assertRaises(StopIteration, sess_admin._get_list([]).next)

        self.assertEqual([i for i in sess_admin._get_list(['authenticated'])],
                         auth_list)
        self.assertEqual([i for i in sess_admin._get_list(['anonymous'])],
                         anon_list)
        self.assertEqual([i for i in sess_admin._get_list(['*'])], all_list)
        self.assertEqual([i for i in sess_admin._get_list(['name00'])][0],
                         auth_list[0])
        self.assertEqual([i for i in sess_admin._get_list(['name10:0'])][0],
                         anon_list[0])
        self.assertEqual(
            [i for i in sess_admin._get_list(['name00', 'name01', 'name02'])],
            all_list[:3])

    def test_session_admin_add(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        self.assertRaises(Exception, sess_admin._do_add, 'name00')
        sess_admin._do_add('john')
        result = get_session_info(self.env, 'john')
        self.assertEqual(result, ('john', None, None))
        sess_admin._do_add('john1', 'John1')
        result = get_session_info(self.env, 'john1')
        self.assertEqual(result, ('john1', 'John1', None))
        sess_admin._do_add('john2', 'John2', '*****@*****.**')
        result = get_session_info(self.env, 'john2')
        self.assertEqual(result, ('john2', 'John2', '*****@*****.**'))

    def test_session_admin_set(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        self.assertRaises(TracError, sess_admin._do_set, 'name', 'nothere',
                          'foo')
        sess_admin._do_set('name', 'name00', 'john')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, ('name00', 'john', 'val00'))
        sess_admin._do_set('email', 'name00', '*****@*****.**')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, ('name00', 'john', '*****@*****.**'))

    def test_session_admin_delete(self):
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin = SessionAdmin(self.env)
        sess_admin._do_delete('name00')
        result = get_session_info(self.env, 'name00')
        self.assertEqual(result, (None, None, None))
        sess_admin._do_delete('nothere')
        result = get_session_info(self.env, 'nothere')
        self.assertEqual(result, (None, None, None))
        auth_list, anon_list, all_list = _prep_session_table(self.env)
        sess_admin._do_delete('anonymous')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list)

    def test_session_admin_purge(self):
        sess_admin = SessionAdmin(self.env)

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-02')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list)
        result = get_session_info(self.env, anon_list[0][0])
        self.assertEqual(result, ('name10', 'val10', 'val10'))
        result = get_session_info(self.env, anon_list[1][0])
        self.assertEqual(result, ('name11', 'val11', 'val11'))

        auth_list, anon_list, all_list = \
            _prep_session_table(self.env, spread_visits=True)
        sess_admin._do_purge('2010-01-12')
        result = [i for i in sess_admin._get_list(['*'])]
        self.assertEqual(result, auth_list + anon_list[1:])
        rows = self.env.db_query(
            """
            SELECT name, value FROM session_attribute WHERE sid = %s
            """, (anon_list[0][0], ))
        self.assertEqual([], rows)
        result = get_session_info(self.env, anon_list[1][0])
        self.assertEqual(result, ('name11', 'val11', 'val11'))
Example #44
0
class TagSetupTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(enable=['trac.*'])
        self.env.path = tempfile.mkdtemp()
        self.db_mgr = DatabaseManager(self.env)

    def tearDown(self):
        self.env.shutdown()
        shutil.rmtree(self.env.path)

    # Helpers

    def _get_cursor_description(self, cursor):
        # Cursors don't look the same across Trac versions
        if trac_version < '0.12':
            return cursor.description
        else:
            return cursor.cursor.description

    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 get_db_version(self):
        for version, in self.env.db_query("""
                SELECT value FROM system
                WHERE name='tags_version'
                """):
            return int(version)

    # Tests

    def test_new_install(self):
        setup = TagSetup(self.env)
        # Current tractags schema is setup with enabled component anyway.
        #   Revert these changes for clean install testing.
        self._revert_tractags_schema_init()
        self.assertEquals(0, setup.get_schema_version())
        self.assertTrue(setup.environment_needs_upgrade())

        setup.upgrade_environment()
        self.assertFalse(setup.environment_needs_upgrade())
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("SELECT * FROM tags")
            cols = [col[0] for col in self._get_cursor_description(cursor)]
            self.assertEquals([], cursor.fetchall())
            self.assertEquals(['tagspace', 'name', 'tag'], cols)
        self.assertEquals(db_default.schema_version, self.get_db_version())

    def test_upgrade_schema_v1(self):
        # Ancient, unversioned schema - wiki only.
        schema = [
            Table('wiki_namespace')[
                Column('name'),
                Column('namespace'),
                Index(['name', 'namespace']),
            ]
        ]
        setup = TagSetup(self.env)
        # Current tractags schema is setup with enabled component anyway.
        #   Revert these changes for clean install testing.
        self._revert_tractags_schema_init()

        connector = self.db_mgr._get_connector()[0]
        with self.env.db_transaction as db:
            for table in schema:
                for stmt in connector.to_sql(table):
                    db(stmt)
            # Populate table with migration test data.
            db("""INSERT INTO wiki_namespace (name, namespace)
                  VALUES ('WikiStart', 'tag')""")

        tags = self.env.db_query("SELECT * FROM wiki_namespace")
        self.assertEquals([('WikiStart', 'tag')], tags)
        self.assertEquals(1, setup.get_schema_version())
        self.assertTrue(setup.environment_needs_upgrade())

        setup.upgrade_environment()
        self.assertFalse(setup.environment_needs_upgrade())
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("SELECT * FROM tags")
            tags = cursor.fetchall()
            cols = [col[0] for col in self._get_cursor_description(cursor)]
            # Db content should be migrated.
            self.assertEquals([('wiki', 'WikiStart', 'tag')], tags)
            self.assertEquals(['tagspace', 'name', 'tag'], cols)
            self.assertEquals(db_default.schema_version, self.get_db_version())

    def test_upgrade_schema_v2(self):
        # Just register a current, but unversioned schema.
        schema = [
            Table('tags', key=('tagspace', 'name', 'tag'))[
                Column('tagspace'),
                Column('name'),
                Column('tag'),
                Index(['tagspace', 'name']),
                Index(['tagspace', 'tag']),
            ]
        ]
        setup = TagSetup(self.env)
        # Current tractags schema is setup with enabled component anyway.
        #   Revert these changes for clean install testing.
        self._revert_tractags_schema_init()

        connector = self.db_mgr._get_connector()[0]
        with self.env.db_transaction as db:
            for table in schema:
                for stmt in connector.to_sql(table):
                    db(stmt)
            # Populate table with test data.
            db("""INSERT INTO tags (tagspace, name, tag)
                  VALUES ('wiki', 'WikiStart', 'tag')""")

        tags = self.env.db_query("SELECT * FROM tags")
        self.assertEquals([('wiki', 'WikiStart', 'tag')], tags)
        self.assertEquals(2, setup.get_schema_version())
        self.assertTrue(setup.environment_needs_upgrade())

        setup.upgrade_environment()
        self.assertFalse(setup.environment_needs_upgrade())
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("SELECT * FROM tags")
            tags = cursor.fetchall()
            cols = [col[0] for col in self._get_cursor_description(cursor)]
            # Db should be unchanged.
            self.assertEquals([('wiki', 'WikiStart', 'tag')], tags)
            self.assertEquals(['tagspace', 'name', 'tag'], cols)
            self.assertEquals(db_default.schema_version, self.get_db_version())

    def test_upgrade_schema_v3(self):
        # Add table for tag change records to the schema.
        schema = [
            Table('tags', key=('tagspace', 'name', 'tag'))[
                Column('tagspace'),
                Column('name'),
                Column('tag'),
                Index(['tagspace', 'name']),
                Index(['tagspace', 'tag']),
            ]
        ]
        setup = TagSetup(self.env)
        # Current tractags schema is setup with enabled component anyway.
        #   Revert these changes for clean install testing.
        self._revert_tractags_schema_init()

        connector = self.db_mgr._get_connector()[0]
        with self.env.db_transaction as db:
            for table in schema:
                for stmt in connector.to_sql(table):
                    db(stmt)
            # Preset system db table with old version.
            db("""INSERT INTO system (name, value)
                  VALUES ('tags_version', '3')""")

        self.assertEquals(3, setup.get_schema_version())
        self.assertTrue(setup.environment_needs_upgrade())

        setup.upgrade_environment()
        self.assertFalse(setup.environment_needs_upgrade())
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("SELECT * FROM tags_change")
            cols = [col[0] for col in self._get_cursor_description(cursor)]
            self.assertEquals(['tagspace', 'name', 'time', 'author',
                               'oldtags', 'newtags'], cols)
        self.assertEquals(db_default.schema_version, self.get_db_version())