Skip to content
Snippets Groups Projects
test_base.py 6.25 KiB
Newer Older
matrix.org's avatar
matrix.org committed
# -*- coding: utf-8 -*-
Matthew Hodgson's avatar
Matthew Hodgson committed
# Copyright 2014-2016 OpenMarket Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Amber Brown's avatar
Amber Brown committed
from collections import OrderedDict
from mock import Mock
Amber Brown's avatar
Amber Brown committed
from twisted.internet import defer
matrix.org's avatar
matrix.org committed

from synapse.storage._base import SQLBaseStore
Erik Johnston's avatar
Erik Johnston committed
from synapse.storage.database import Database
from synapse.storage.engines import create_engine
Amber Brown's avatar
Amber Brown committed
from tests import unittest
Richard van der Hoff's avatar
Richard van der Hoff committed
from tests.utils import TestHomeServer
Amber Brown's avatar
Amber Brown committed

matrix.org's avatar
matrix.org committed

class SQLBaseStoreTestCase(unittest.TestCase):
    """ Test the "simple" SQL generating methods in SQLBaseStore. """

    def setUp(self):
        self.db_pool = Mock(spec=["runInteraction"])
        self.mock_txn = Mock()
Erik Johnston's avatar
Erik Johnston committed
        self.mock_conn = Mock(spec_set=["cursor", "rollback", "commit"])
        self.mock_conn.cursor.return_value = self.mock_txn
Erik Johnston's avatar
Erik Johnston committed
        self.mock_conn.rollback.return_value = None
matrix.org's avatar
matrix.org committed
        # Our fake runInteraction just runs synchronously inline

        def runInteraction(func, *args, **kwargs):
            return defer.succeed(func(self.mock_txn, *args, **kwargs))
black's avatar
black committed

matrix.org's avatar
matrix.org committed
        self.db_pool.runInteraction = runInteraction

        def runWithConnection(func, *args, **kwargs):
            return defer.succeed(func(self.mock_conn, *args, **kwargs))
black's avatar
black committed

        self.db_pool.runWithConnection = runWithConnection

Mark Haines's avatar
Mark Haines committed
        config = Mock()
        config._disable_native_upserts = True
Mark Haines's avatar
Mark Haines committed
        config.event_cache_size = 1
        config.database_config = {"name": "sqlite3"}
        engine = create_engine(config.database_config)
        fake_engine = Mock(wraps=engine)
        fake_engine.can_native_upsert = False
Richard van der Hoff's avatar
Richard van der Hoff committed
        hs = TestHomeServer(
            "test", db_pool=self.db_pool, config=config, database_engine=fake_engine
Erik Johnston's avatar
Erik Johnston committed
        self.datastore = SQLBaseStore(Database(hs), None, hs)
matrix.org's avatar
matrix.org committed

    @defer.inlineCallbacks
    def test_insert_1col(self):
        self.mock_txn.rowcount = 1

        yield self.datastore.db.simple_insert(
black's avatar
black committed
            table="tablename", values={"columname": "Value"}
matrix.org's avatar
matrix.org committed
        )

        self.mock_txn.execute.assert_called_with(
            "INSERT INTO tablename (columname) VALUES(?)", ("Value",)
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_insert_3cols(self):
        self.mock_txn.rowcount = 1

        yield self.datastore.db.simple_insert(
            table="tablename",
            # Use OrderedDict() so we can assert on the SQL generated
black's avatar
black committed
            values=OrderedDict([("colA", 1), ("colB", 2), ("colC", 3)]),
matrix.org's avatar
matrix.org committed
        )

        self.mock_txn.execute.assert_called_with(
black's avatar
black committed
            "INSERT INTO tablename (colA, colB, colC) VALUES(?, ?, ?)", (1, 2, 3)
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_select_one_1col(self):
        self.mock_txn.rowcount = 1
        self.mock_txn.__iter__ = Mock(return_value=iter([("Value",)]))
        value = yield self.datastore.db.simple_select_one_onecol(
black's avatar
black committed
            table="tablename", keyvalues={"keycol": "TheKey"}, retcol="retcol"
matrix.org's avatar
matrix.org committed
        )

        self.assertEquals("Value", value)
        self.mock_txn.execute.assert_called_with(
            "SELECT retcol FROM tablename WHERE keycol = ?", ["TheKey"]
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_select_one_3col(self):
        self.mock_txn.rowcount = 1
        self.mock_txn.fetchone.return_value = (1, 2, 3)

        ret = yield self.datastore.db.simple_select_one(
            table="tablename",
            keyvalues={"keycol": "TheKey"},
black's avatar
black committed
            retcols=["colA", "colB", "colC"],
matrix.org's avatar
matrix.org committed
        )

        self.assertEquals({"colA": 1, "colB": 2, "colC": 3}, ret)
        self.mock_txn.execute.assert_called_with(
black's avatar
black committed
            "SELECT colA, colB, colC FROM tablename WHERE keycol = ?", ["TheKey"]
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_select_one_missing(self):
        self.mock_txn.rowcount = 0
        self.mock_txn.fetchone.return_value = None

        ret = yield self.datastore.db.simple_select_one(
            table="tablename",
            keyvalues={"keycol": "Not here"},
            retcols=["colA"],
black's avatar
black committed
            allow_none=True,
matrix.org's avatar
matrix.org committed
        )

        self.assertFalse(ret)

    @defer.inlineCallbacks
    def test_select_list(self):
        self.mock_txn.rowcount = 3
        self.mock_txn.__iter__ = Mock(return_value=iter([(1,), (2,), (3,)]))
black's avatar
black committed
        self.mock_txn.description = (("colA", None, None, None, None, None, None),)
        ret = yield self.datastore.db.simple_select_list(
black's avatar
black committed
            table="tablename", keyvalues={"keycol": "A set"}, retcols=["colA"]
matrix.org's avatar
matrix.org committed
        )

        self.assertEquals([{"colA": 1}, {"colA": 2}, {"colA": 3}], ret)
        self.mock_txn.execute.assert_called_with(
black's avatar
black committed
            "SELECT colA FROM tablename WHERE keycol = ?", ["A set"]
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_update_one_1col(self):
        self.mock_txn.rowcount = 1

        yield self.datastore.db.simple_update_one(
            table="tablename",
            keyvalues={"keycol": "TheKey"},
black's avatar
black committed
            updatevalues={"columnname": "New Value"},
matrix.org's avatar
matrix.org committed
        )

        self.mock_txn.execute.assert_called_with(
            "UPDATE tablename SET columnname = ? WHERE keycol = ?",
black's avatar
black committed
            ["New Value", "TheKey"],
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_update_one_4cols(self):
        self.mock_txn.rowcount = 1

        yield self.datastore.db.simple_update_one(
            table="tablename",
            keyvalues=OrderedDict([("colA", 1), ("colB", 2)]),
black's avatar
black committed
            updatevalues=OrderedDict([("colC", 3), ("colD", 4)]),
matrix.org's avatar
matrix.org committed
        )

        self.mock_txn.execute.assert_called_with(
black's avatar
black committed
            "UPDATE tablename SET colC = ?, colD = ? WHERE" " colA = ? AND colB = ?",
            [3, 4, 1, 2],
matrix.org's avatar
matrix.org committed
        )

    @defer.inlineCallbacks
    def test_delete_one(self):
        self.mock_txn.rowcount = 1

        yield self.datastore.db.simple_delete_one(
black's avatar
black committed
            table="tablename", keyvalues={"keycol": "Go away"}
matrix.org's avatar
matrix.org committed
        )

        self.mock_txn.execute.assert_called_with(
            "DELETE FROM tablename WHERE keycol = ?", ["Go away"]