Example #1
0
 def test_run_quick_check_fails(self):
     """Quick check fails for non SQLite dtabase files."""
     with tempfile.NamedTemporaryFile() as db_file:
         db_file.write('this is a text file, not a database file')
         db_file.flush()
         with Database(db_file.name) as database:
             self.assertFalse(database.run_quick_check())
Example #2
0
    def paths(self):
        """Return paths to valid databases found under directory.

        :return: Paths to valid databases
        :rtype: list(str)

        """
        db_paths = self._explore()
        logger.debug(
            '%d database paths found under %s:\n%s',
            len(db_paths),
            self.directory,
            '\n'.join(os.path.relpath(db_path, self.directory)
                      for db_path in db_paths))

        # Filter out files that don't pass sqlite's quick check
        # that just can't be opened
        valid_paths = []
        for db_path in db_paths:
            try:
                with Database(db_path) as database:
                    if database.run_quick_check():
                        valid_paths.append(db_path)
            except OperationalError:
                logger.warning('Unable to open: %s', db_path)
                continue

        logger.debug(
            '%d database paths passed the integrity check:\n%s',
            len(valid_paths),
            '\n'.join(os.path.relpath(valid_path, self.directory)
                      for valid_path in valid_paths))
        return valid_paths
Example #3
0
    def test_ignore_fts_tables(self):
        """FTS database tables are ignored."""
        expected_table_names = ['messages', 'calls', 'events', 'pictures']
        fts_table_names = [
            '{}_search'.format(table_name)
            for table_name in expected_table_names
        ]

        with tempfile.NamedTemporaryFile() as db_file:
            self.create_tables(
                db_file.name,
                expected_table_names,
                fts_table_names,
            )

            with Database(db_file.name) as database:
                db_reader = DBReader(database)
                table_names = [table_name for table_name in db_reader.tables()]

                # Check ignored tables are indeed in the database
                master_table = database['sqlite_master']
                query = (select([master_table.c.name
                                 ]).where(master_table.c.type == 'table'))
                result = database.connection.execute(query)
                all_table_names = set(row[0] for row in result.fetchall())
                for table_name in fts_table_names:
                    self.assertIn(table_name, all_table_names)

                self.assertListEqual(sorted(table_names),
                                     sorted(expected_table_names))
Example #4
0
    def test_run_quick_check_passes(self):
        """Quick check passes for SQLite database."""
        with tempfile.NamedTemporaryFile() as db_file:
            with closing(sqlite3.connect(db_file.name)) as connection:
                with closing(connection.cursor()) as cursor:
                    cursor.execute(
                        'CREATE TABLE messages (id INTEGER, message TEXT)')

            with Database(db_file.name) as database:
                self.assertTrue(database.run_quick_check())
Example #5
0
    def test_tables(self):
        """Database tables are correctly retrieved."""
        expected_table_names = sorted(
            ['messages', 'calls', 'events', 'pictures'])

        with tempfile.NamedTemporaryFile() as db_file:
            self.create_tables(db_file.name, expected_table_names)
            with Database(db_file.name) as database:
                db_reader = DBReader(database)
                table_names = sorted(db_reader.tables())
                self.assertListEqual(table_names, expected_table_names)
Example #6
0
    def test_type_error_on_wrong_table_name(self):
        """TypeError raised when table name is not a string."""
        with tempfile.NamedTemporaryFile() as db_file:
            with closing(sqlite3.connect(db_file.name)) as connection:
                with closing(connection.cursor()) as cursor:
                    cursor.execute(
                        'CREATE TABLE messages (id INTEGER, message TEXT)')

            database = Database(db_file.name)

            with self.assertRaises(TypeError):
                database[0]
Example #7
0
    def test_get_unknown_table_metadata(self):
        """NoSuchTableError raised when table name is not found."""
        with tempfile.NamedTemporaryFile() as db_file:
            with closing(sqlite3.connect(db_file.name)) as connection:
                with closing(connection.cursor()) as cursor:
                    cursor.execute(
                        'CREATE TABLE messages (id INTEGER, message TEXT)')

            database = Database(db_file.name)

            with self.assertRaises(NoSuchTableError):
                database['unknown']
Example #8
0
    def test_context_manager(self):
        """Connection is opened/closed when used as a context manager."""
        database = Database(':memory:')

        # Connection is None when database object is created
        self.assertIsNone(database.connection)

        with database:
            # Connection is not closed inside the context
            self.assertFalse(database.connection.closed)

        # Connection is closed outside the context
        self.assertTrue(database.connection.closed)
Example #9
0
    def test_get_table_metadata(self):
        """Table metadata can be retrieved using index notation."""
        with tempfile.NamedTemporaryFile() as db_file:
            with closing(sqlite3.connect(db_file.name)) as connection:
                with closing(connection.cursor()) as cursor:
                    cursor.execute(
                        'CREATE TABLE messages (id INTEGER, message TEXT)')

            database = Database(db_file.name)
            table = database['messages']
            schema = {
                column.name: type(column.type)
                for column in table.columns
            }
            self.assertDictEqual(schema, {'id': INTEGER, 'message': TEXT})
Example #10
0
    def _index_directory(self, directory):
        """Index all databases under a given directory.

        :param directory: Path to the directory to explore
        :type directory: str
        :return: Documents indexed for this directory
        :rtype: int

        """
        documents_indexed = 0

        self._recreate_index(self.INDEX_NAME)

        tree_explorer = TreeExplorer(directory)
        for db_path in tree_explorer.paths():
            with Database(db_path) as database:
                documents_indexed += self._index_database(database)

        return documents_indexed
Example #11
0
    def setUpClass(cls):
        """Create test database.

        Database is reused between test cases because they just read data
        without chaning the database in any way.

        """
        with tempfile.NamedTemporaryFile(delete=False) as cls.db_file:
            with closing(sqlite3.connect(cls.db_file.name)) as connection:
                with closing(connection.cursor()) as cursor:
                    cursor.execute(
                        'CREATE TABLE messages (id INTEGER, message TEXT);')

                    cls.message_values = [(1, 'one message'),
                                          (2, 'another message'),
                                          (3, 'one more message')]
                    cursor.executemany('INSERT INTO messages VALUES(?, ?);',
                                       cls.message_values)

                    cursor.execute(
                        'CREATE TABLE calls (_id INTEGER, number TEXT);')
                    cls.call_values = [(1, '123456789'), (2, '234567890'),
                                       (3, '345678901')]
                    cursor.executemany('INSERT INTO calls VALUES(?, ?);',
                                       cls.call_values)

                    cursor.execute(
                        'CREATE TABLE events (_id INTEGER, description TEXT);')
                    cls.event_values = [(1, 'holiday'), (2, 'meeting'),
                                        (1, 'reminder')]
                    cursor.executemany('INSERT INTO events VALUES(?, ?);',
                                       cls.event_values)

                    cursor.execute('CREATE TABLE pictures '
                                   '(id INTEGER, raw_data BLOB);')
                    cls.picture_values = [(1, ''), (2, ''), (3, '')]
                    cursor.executemany('INSERT INTO pictures VALUES(?, ?);',
                                       cls.picture_values)
                connection.commit()

            cls.database = Database(cls.db_file.name)
            cls.database.connect()