Skip to content

Commit

Permalink
fix(tests): improve casual failures
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniele Briggi committed Aug 26, 2024
1 parent b40400b commit e4ba7a5
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 178 deletions.
222 changes: 126 additions & 96 deletions bandit-baseline.json

Large diffs are not rendered by default.

30 changes: 14 additions & 16 deletions src/sqlitecloud/dbapi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,10 @@ class Connection:
Represents a DB-API 2.0 connection to the SQLite Cloud database.
Args:
SQLiteCloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
sqlitecloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
Attributes:
_driver (Driver): The driver object used for database operations.
SQLiteCloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
sqlitecloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
"""

def __init__(
Expand All @@ -246,16 +245,6 @@ def __init__(

self.total_changes = 0

@property
def sqlcloud_connection(self) -> SQLiteCloudConnect:
"""
Returns the SQLite Cloud connection object.
Returns:
SQLiteCloudConnect: The SQLite Cloud connection object.
"""
return self.sqlitecloud_connection

@property
def autocommit(self) -> bool:
"""Autocommit enabled is the only currently supported option in SQLite Cloud."""
Expand Down Expand Up @@ -351,6 +340,15 @@ def close(self):
"""
self._driver.disconnect(self.sqlitecloud_connection, True)

def is_connected(self) -> bool:
"""
Check if the connection to SQLite Cloud database is still open.
Returns:
bool: True if the connection is open, False otherwise.
"""
return self._driver.is_connected(self.sqlitecloud_connection)

def commit(self):
"""
Commit any pending transactions on database.
Expand Down Expand Up @@ -583,7 +581,7 @@ def execute(
parameters = self._named_to_question_mark_parameters(sql, parameters)

result = self._driver.execute_statement(
sql, parameters, self.connection.sqlcloud_connection
sql, parameters, self.connection.sqlitecloud_connection
)

self._resultset = None
Expand Down Expand Up @@ -729,8 +727,8 @@ def _ensure_connection(self):
Raises:
SQLiteCloudException: If the cursor is closed.
"""
if not self._connection:
raise SQLiteCloudProgrammingError("The cursor is closed.")
if not self._connection or not self._connection.is_connected():
raise SQLiteCloudProgrammingError("The cursor is closed.", code=1)

def _adapt_parameters(self, parameters: Union[Dict, Tuple]) -> Union[Dict, Tuple]:
if isinstance(parameters, dict):
Expand Down
2 changes: 1 addition & 1 deletion src/tests/integration/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ def test_big_rowset(self):
account.dbname = os.getenv("SQLITE_DB")

client = SQLiteCloudClient(cloud_account=account)
client.config.timeout = 100
client.config.timeout = 120

connection = client.open_connection()

Expand Down
19 changes: 14 additions & 5 deletions src/tests/integration/test_dbapi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import pytest

import sqlitecloud
from sqlitecloud.datatypes import SQLITECLOUD_INTERNAL_ERRCODE, SQLiteCloudAccount
from sqlitecloud.exceptions import SQLiteCloudError, SQLiteCloudException
from sqlitecloud.datatypes import SQLiteCloudAccount
from sqlitecloud.exceptions import SQLiteCloudError, SQLiteCloudProgrammingError


class TestDBAPI2:
Expand Down Expand Up @@ -46,11 +46,11 @@ def test_disconnect(self):

assert isinstance(connection, sqlitecloud.Connection)

with pytest.raises(SQLiteCloudException) as e:
with pytest.raises(SQLiteCloudProgrammingError) as e:
connection.execute("SELECT 1")

assert e.value.errcode == SQLITECLOUD_INTERNAL_ERRCODE.NETWORK
assert e.value.errmsg == "The connection is closed."
assert e.value.errcode == 1
assert e.value.errmsg == "The cursor is closed."

def test_select(self, sqlitecloud_dbapi2_connection):
connection = sqlitecloud_dbapi2_connection
Expand Down Expand Up @@ -432,3 +432,12 @@ def test_last_rowid_and_rowcount_with_executemany_deletes(
assert cursor.fetchone() is None
assert cursor.lastrowid == cursor_insert.lastrowid
assert cursor.rowcount == 1

def test_connection_is_connected(self, sqlitecloud_dbapi2_connection):
connection = sqlitecloud_dbapi2_connection

assert connection.is_connected()

connection.close()

assert not connection.is_connected()
3 changes: 2 additions & 1 deletion src/tests/integration/test_driver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import random
import tempfile
import uuid

from sqlitecloud.driver import Driver
from sqlitecloud.resultset import SQLiteCloudOperationResult, SQLiteCloudResult
Expand Down Expand Up @@ -48,7 +49,7 @@ def test_prepare_statement_insert(self, sqlitecloud_connection):

connection, _ = sqlitecloud_connection

name = "MyGenre" + str(random.randint(0, 1000))
name = "MyGenre" + str(uuid.uuid4())
query = "INSERT INTO genres (Name) VALUES (?)"
bindings = [name]

Expand Down
15 changes: 8 additions & 7 deletions src/tests/integration/test_pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,16 @@ def assert_callback(conn, result, data):
assert pubsub.is_connected(connection)

connection2 = client.open_connection()
pubsub2 = SQLiteCloudPubSub()
pubsub2.notify_channel(connection2, channel, "message-in-a-bottle")
try:
pubsub2 = SQLiteCloudPubSub()
pubsub2.notify_channel(connection2, channel, "message-in-a-bottle")

client.disconnect(connection2)
# wait for callback to be called
flag.wait(30)

# wait for callback to be called
flag.wait(30)

assert callback_called
assert callback_called
finally:
client.disconnect(connection2)

def test_listen_table_for_update(self, sqlitecloud_connection):
connection, client = sqlitecloud_connection
Expand Down
28 changes: 19 additions & 9 deletions src/tests/integration/test_sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,33 @@ def sqlitecloud_connection_string():
database = os.getenv("SQLITE_DB")
apikey = os.getenv("SQLITE_API_KEY")

return f"{connection_string}/{database}?apikey={apikey}"
engine = db.create_engine(f"{connection_string}/{database}?apikey={apikey}")
Session = sessionmaker(bind=engine)
session = Session()

yield session

session.close()
engine.dispose()


@pytest.fixture()
def sqlite_connection_string():
return "sqlite:///src/tests/assets/chinook.sqlite"
engine = db.create_engine("sqlite:///src/tests/assets/chinook.sqlite")
Session = sessionmaker(bind=engine)
session = Session()

yield session

session.close()
engine.dispose()


@pytest.mark.parametrize(
"connection_string", ["sqlitecloud_connection_string", "sqlite_connection_string"]
"session", ["sqlitecloud_connection_string", "sqlite_connection_string"]
)
def test_insert_and_select(connection_string, request):
connection_string = request.getfixturevalue(connection_string)

engine = db.create_engine(connection_string)
Session = sessionmaker(bind=engine)
session = Session()
def test_insert_and_select(session, request):
session = request.getfixturevalue(session)

name = "Mattew" + str(uuid.uuid4())
query = db.insert(Artist).values(Name=name)
Expand Down
113 changes: 70 additions & 43 deletions src/tests/integration/test_sqlite_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest

import sqlitecloud
from sqlitecloud.exceptions import SQLiteCloudException, SQLiteCloudProgrammingError
from sqlitecloud.exceptions import SQLiteCloudProgrammingError
from tests.conftest import (
close_generator,
get_sqlite3_connection,
Expand All @@ -18,59 +18,81 @@


class TestSQLiteFeatureParity:
def test_connection_close(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
sqlitecloud_connection = sqlitecloud_dbapi2_connection
@pytest.mark.parametrize(
"connection, expected",
[
("sqlitecloud_dbapi2_connection", SQLiteCloudProgrammingError),
("sqlite3_connection", sqlite3.ProgrammingError),
],
)
def test_connection_close(self, connection, expected, request):
connection = request.getfixturevalue(connection)

sqlitecloud_connection.close()
sqlite3_connection.close()
connection.close()

with pytest.raises(SQLiteCloudException) as e:
sqlitecloud_connection.execute("SELECT 1")
with pytest.raises(expected) as e:
connection.execute("SELECT 1")

assert isinstance(e.value, SQLiteCloudException)
assert isinstance(e.value, expected)

with pytest.raises(sqlite3.ProgrammingError) as e:
sqlite3_connection.execute("SELECT 1")
@pytest.mark.parametrize(
"connection, expected",
[
("sqlitecloud_dbapi2_connection", SQLiteCloudProgrammingError),
("sqlite3_connection", sqlite3.ProgrammingError),
],
)
def test_cursor_close(self, connection, expected, request):
connection = request.getfixturevalue(connection)

assert isinstance(e.value, sqlite3.ProgrammingError)
cursor = connection.cursor()

def test_ping_select(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
sqlitecloud_connection = sqlitecloud_dbapi2_connection
cursor.close()

sqlitecloud_cursor = sqlitecloud_connection.execute("SELECT 1")
sqlite3_cursor = sqlite3_connection.execute("SELECT 1")
with pytest.raises(expected) as e:
cursor.execute("SELECT 1")

sqlitecloud_cursor = sqlitecloud_cursor.fetchall()
sqlite3_cursor = sqlite3_cursor.fetchall()
assert isinstance(e.value, expected)

assert sqlitecloud_cursor == sqlite3_cursor
@pytest.mark.parametrize(
"connection", ["sqlitecloud_dbapi2_connection", "sqlite3_connection"]
)
def test_ping_select(self, connection, request):
connection = request.getfixturevalue(connection)

cursor = connection.execute("SELECT 1")

cursor = cursor.fetchall()

assert cursor == [(1,)]

@pytest.mark.parametrize(
"connection", ["sqlitecloud_dbapi2_connection", "sqlite3_connection"]
)
def test_create_table_and_insert_many(self, connection, request):
connection = request.getfixturevalue(connection)

create_table_query = "CREATE TABLE IF NOT EXISTS sqlitetest (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
connection.execute(create_table_query)

truncate_table_query = "DELETE FROM sqlitetest"
connection.execute(truncate_table_query)
table = "sqlitetest" + str(random.randint(0, 99999))
try:
create_table_query = f"CREATE TABLE IF NOT EXISTS {table} (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
connection.execute(create_table_query)

insert_query = "INSERT INTO sqlitetest (name, age) VALUES (?, ?)"
params = [("Alice", 25), ("Bob", 30)]
connection.executemany(insert_query, params)
insert_query = f"INSERT INTO {table} (name, age) VALUES (?, ?)"
params = [("Alice", 25), ("Bob", 30)]
connection.executemany(insert_query, params)

select_query = "SELECT * FROM sqlitetest"
cursor = connection.execute(select_query)
select_query = f"SELECT * FROM {table}"
cursor = connection.execute(select_query)

results = cursor.fetchall()
results = cursor.fetchall()

assert len(results) == 2
assert results[0][1] == "Alice"
assert results[0][2] == 25
assert results[1][1] == "Bob"
assert results[1][2] == 30
assert len(results) == 2
assert results[0][1] == "Alice"
assert results[0][2] == 25
assert results[1][1] == "Bob"
assert results[1][2] == 30
finally:
connection.execute(f"DROP TABLE IF EXISTS {table}")

@pytest.mark.parametrize(
"connection", ["sqlitecloud_dbapi2_connection", "sqlite3_connection"]
Expand Down Expand Up @@ -175,9 +197,6 @@ def test_executemany_with_named_param_style(self, connection, request):

assert connection.total_changes == 2

@pytest.mark.skip(
reason="Rowcount does not contain the number of inserted rows yet"
)
def test_insert_result(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
sqlitecloud_connection = sqlitecloud_dbapi2_connection

Expand Down Expand Up @@ -375,13 +394,18 @@ def test_cursor_description_with_explicit_decltype(
"""Since py3.7 the parsed of `[decltype]` disabled when PARSE_COLNAMES.
See bpo-39652 https://github.com/python/cpython/issues/83833"""
if parse_colnames:
connection = next(connection(module.PARSE_COLNAMES))
connection_gen = connection(module.PARSE_COLNAMES)
else:
connection = next(connection())
connection_gen = connection()

cursor = connection.execute(f"SELECT {value}")
connection = next(connection_gen)

try:
cursor = connection.execute(f"SELECT {value}")

assert cursor.description[0][0] == expected
assert cursor.description[0][0] == expected
finally:
close_generator(connection_gen)

def test_fetch_one(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
sqlitecloud_connection = sqlitecloud_dbapi2_connection
Expand Down Expand Up @@ -508,7 +532,7 @@ def test_explicit_transaction_to_commit(
sqlitecloud_dbapi2_connection: sqlitecloud.Connection,
sqlite3_connection: sqlite3.Connection,
):
seed = str(int(time.time()))
seed = str(uuid.uuid4())

sqlitecloud_conn_gen = get_sqlitecloud_dbapi2_connection()
sqlite_conn_gen = get_sqlite3_connection()
Expand Down Expand Up @@ -878,7 +902,9 @@ def adapt_point(point):
],
)
def test_parse_decltypes(self, connection, module):
connection = next(connection(module.PARSE_DECLTYPES))
connection_gen = connection(module.PARSE_DECLTYPES)

connection = next(connection_gen)

class Point:
def __init__(self, x, y):
Expand Down Expand Up @@ -909,6 +935,7 @@ def convert_point(s):
assert result[0].y == p.y
finally:
connection.execute(f"DROP TABLE IF EXISTS {tableName}")
close_generator(connection_gen)

@pytest.mark.parametrize(
"connection, module",
Expand Down

0 comments on commit e4ba7a5

Please sign in to comment.