Skip to content

Commit e703f10

Browse files
committed
fix(tests): improve casual failures
1 parent ea3e9a4 commit e703f10

File tree

9 files changed

+255
-179
lines changed

9 files changed

+255
-179
lines changed

bandit-baseline.json

Lines changed: 126 additions & 96 deletions
Large diffs are not rendered by default.

src/sqlitecloud/dbapi2.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,10 @@ class Connection:
225225
Represents a DB-API 2.0 connection to the SQLite Cloud database.
226226
227227
Args:
228-
SQLiteCloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
228+
sqlitecloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
229229
230230
Attributes:
231-
_driver (Driver): The driver object used for database operations.
232-
SQLiteCloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
231+
sqlitecloud_connection (SQLiteCloudConnect): The SQLite Cloud connection object.
233232
"""
234233

235234
def __init__(
@@ -246,16 +245,6 @@ def __init__(
246245

247246
self.total_changes = 0
248247

249-
@property
250-
def sqlcloud_connection(self) -> SQLiteCloudConnect:
251-
"""
252-
Returns the SQLite Cloud connection object.
253-
254-
Returns:
255-
SQLiteCloudConnect: The SQLite Cloud connection object.
256-
"""
257-
return self.sqlitecloud_connection
258-
259248
@property
260249
def autocommit(self) -> bool:
261250
"""Autocommit enabled is the only currently supported option in SQLite Cloud."""
@@ -351,6 +340,15 @@ def close(self):
351340
"""
352341
self._driver.disconnect(self.sqlitecloud_connection, True)
353342

343+
def is_connected(self) -> bool:
344+
"""
345+
Check if the connection to SQLite Cloud database is still open.
346+
347+
Returns:
348+
bool: True if the connection is open, False otherwise.
349+
"""
350+
return self._driver.is_connected(self.sqlitecloud_connection)
351+
354352
def commit(self):
355353
"""
356354
Commit any pending transactions on database.
@@ -583,7 +581,7 @@ def execute(
583581
parameters = self._named_to_question_mark_parameters(sql, parameters)
584582

585583
result = self._driver.execute_statement(
586-
sql, parameters, self.connection.sqlcloud_connection
584+
sql, parameters, self.connection.sqlitecloud_connection
587585
)
588586

589587
self._resultset = None
@@ -729,8 +727,8 @@ def _ensure_connection(self):
729727
Raises:
730728
SQLiteCloudException: If the cursor is closed.
731729
"""
732-
if not self._connection:
733-
raise SQLiteCloudProgrammingError("The cursor is closed.")
730+
if not self._connection or not self._connection.is_connected():
731+
raise SQLiteCloudProgrammingError("The cursor is closed.", code=1)
734732

735733
def _adapt_parameters(self, parameters: Union[Dict, Tuple]) -> Union[Dict, Tuple]:
736734
if isinstance(parameters, dict):

src/tests/integration/test_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ def test_big_rowset(self):
642642
account.dbname = os.getenv("SQLITE_DB")
643643

644644
client = SQLiteCloudClient(cloud_account=account)
645-
client.config.timeout = 100
645+
client.config.timeout = 120
646646

647647
connection = client.open_connection()
648648

src/tests/integration/test_dbapi2.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import pytest
55

66
import sqlitecloud
7-
from sqlitecloud.datatypes import SQLITECLOUD_INTERNAL_ERRCODE, SQLiteCloudAccount
8-
from sqlitecloud.exceptions import SQLiteCloudError, SQLiteCloudException
7+
from sqlitecloud.datatypes import SQLiteCloudAccount
8+
from sqlitecloud.exceptions import SQLiteCloudError, SQLiteCloudProgrammingError
99

1010

1111
class TestDBAPI2:
@@ -46,11 +46,11 @@ def test_disconnect(self):
4646

4747
assert isinstance(connection, sqlitecloud.Connection)
4848

49-
with pytest.raises(SQLiteCloudException) as e:
49+
with pytest.raises(SQLiteCloudProgrammingError) as e:
5050
connection.execute("SELECT 1")
5151

52-
assert e.value.errcode == SQLITECLOUD_INTERNAL_ERRCODE.NETWORK
53-
assert e.value.errmsg == "The connection is closed."
52+
assert e.value.errcode == 1
53+
assert e.value.errmsg == "The cursor is closed."
5454

5555
def test_select(self, sqlitecloud_dbapi2_connection):
5656
connection = sqlitecloud_dbapi2_connection
@@ -432,3 +432,12 @@ def test_last_rowid_and_rowcount_with_executemany_deletes(
432432
assert cursor.fetchone() is None
433433
assert cursor.lastrowid == cursor_insert.lastrowid
434434
assert cursor.rowcount == 1
435+
436+
def test_connection_is_connected(self, sqlitecloud_dbapi2_connection):
437+
connection = sqlitecloud_dbapi2_connection
438+
439+
assert connection.is_connected()
440+
441+
connection.close()
442+
443+
assert not connection.is_connected()

src/tests/integration/test_driver.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import random
22
import tempfile
3+
import uuid
34

45
from sqlitecloud.driver import Driver
56
from sqlitecloud.resultset import SQLiteCloudOperationResult, SQLiteCloudResult
@@ -48,7 +49,7 @@ def test_prepare_statement_insert(self, sqlitecloud_connection):
4849

4950
connection, _ = sqlitecloud_connection
5051

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

src/tests/integration/test_pubsub.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,16 @@ def assert_callback(conn, result, data):
133133
assert pubsub.is_connected(connection)
134134

135135
connection2 = client.open_connection()
136-
pubsub2 = SQLiteCloudPubSub()
137-
pubsub2.notify_channel(connection2, channel, "message-in-a-bottle")
136+
try:
137+
pubsub2 = SQLiteCloudPubSub()
138+
pubsub2.notify_channel(connection2, channel, "message-in-a-bottle")
138139

139-
client.disconnect(connection2)
140+
# wait for callback to be called
141+
flag.wait(30)
140142

141-
# wait for callback to be called
142-
flag.wait(30)
143-
144-
assert callback_called
143+
assert callback_called
144+
finally:
145+
client.disconnect(connection2)
145146

146147
def test_listen_table_for_update(self, sqlitecloud_connection):
147148
connection, client = sqlitecloud_connection

src/tests/integration/test_sqlalchemy.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,33 @@ def sqlitecloud_connection_string():
3939
database = os.getenv("SQLITE_DB")
4040
apikey = os.getenv("SQLITE_API_KEY")
4141

42-
return f"{connection_string}/{database}?apikey={apikey}"
42+
engine = db.create_engine(f"{connection_string}/{database}?apikey={apikey}")
43+
Session = sessionmaker(bind=engine)
44+
session = Session()
45+
46+
yield session
47+
48+
session.close()
49+
engine.dispose()
4350

4451

4552
@pytest.fixture()
4653
def sqlite_connection_string():
47-
return "sqlite:///src/tests/assets/chinook.sqlite"
54+
engine = db.create_engine("sqlite:///src/tests/assets/chinook.sqlite")
55+
Session = sessionmaker(bind=engine)
56+
session = Session()
57+
58+
yield session
59+
60+
session.close()
61+
engine.dispose()
4862

4963

5064
@pytest.mark.parametrize(
51-
"connection_string", ["sqlitecloud_connection_string", "sqlite_connection_string"]
65+
"session", ["sqlitecloud_connection_string", "sqlite_connection_string"]
5266
)
53-
def test_insert_and_select(connection_string, request):
54-
connection_string = request.getfixturevalue(connection_string)
55-
56-
engine = db.create_engine(connection_string)
57-
Session = sessionmaker(bind=engine)
58-
session = Session()
67+
def test_insert_and_select(session, request):
68+
session = request.getfixturevalue(session)
5969

6070
name = "Mattew" + str(uuid.uuid4())
6171
query = db.insert(Artist).values(Name=name)

src/tests/integration/test_sqlite_parity.py

Lines changed: 70 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pytest
1010

1111
import sqlitecloud
12-
from sqlitecloud.exceptions import SQLiteCloudException, SQLiteCloudProgrammingError
12+
from sqlitecloud.exceptions import SQLiteCloudProgrammingError
1313
from tests.conftest import (
1414
close_generator,
1515
get_sqlite3_connection,
@@ -18,59 +18,81 @@
1818

1919

2020
class TestSQLiteFeatureParity:
21-
def test_connection_close(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
22-
sqlitecloud_connection = sqlitecloud_dbapi2_connection
21+
@pytest.mark.parametrize(
22+
"connection, expected",
23+
[
24+
("sqlitecloud_dbapi2_connection", SQLiteCloudProgrammingError),
25+
("sqlite3_connection", sqlite3.ProgrammingError),
26+
],
27+
)
28+
def test_connection_close(self, connection, expected, request):
29+
connection = request.getfixturevalue(connection)
2330

24-
sqlitecloud_connection.close()
25-
sqlite3_connection.close()
31+
connection.close()
2632

27-
with pytest.raises(SQLiteCloudException) as e:
28-
sqlitecloud_connection.execute("SELECT 1")
33+
with pytest.raises(expected) as e:
34+
connection.execute("SELECT 1")
2935

30-
assert isinstance(e.value, SQLiteCloudException)
36+
assert isinstance(e.value, expected)
3137

32-
with pytest.raises(sqlite3.ProgrammingError) as e:
33-
sqlite3_connection.execute("SELECT 1")
38+
@pytest.mark.parametrize(
39+
"connection, expected",
40+
[
41+
("sqlitecloud_dbapi2_connection", SQLiteCloudProgrammingError),
42+
("sqlite3_connection", sqlite3.ProgrammingError),
43+
],
44+
)
45+
def test_cursor_close(self, connection, expected, request):
46+
connection = request.getfixturevalue(connection)
3447

35-
assert isinstance(e.value, sqlite3.ProgrammingError)
48+
cursor = connection.cursor()
3649

37-
def test_ping_select(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
38-
sqlitecloud_connection = sqlitecloud_dbapi2_connection
50+
cursor.close()
3951

40-
sqlitecloud_cursor = sqlitecloud_connection.execute("SELECT 1")
41-
sqlite3_cursor = sqlite3_connection.execute("SELECT 1")
52+
with pytest.raises(expected) as e:
53+
cursor.execute("SELECT 1")
4254

43-
sqlitecloud_cursor = sqlitecloud_cursor.fetchall()
44-
sqlite3_cursor = sqlite3_cursor.fetchall()
55+
assert isinstance(e.value, expected)
4556

46-
assert sqlitecloud_cursor == sqlite3_cursor
57+
@pytest.mark.parametrize(
58+
"connection", ["sqlitecloud_dbapi2_connection", "sqlite3_connection"]
59+
)
60+
def test_ping_select(self, connection, request):
61+
connection = request.getfixturevalue(connection)
62+
63+
cursor = connection.execute("SELECT 1")
64+
65+
cursor = cursor.fetchall()
66+
67+
assert cursor == [(1,)]
4768

4869
@pytest.mark.parametrize(
4970
"connection", ["sqlitecloud_dbapi2_connection", "sqlite3_connection"]
5071
)
5172
def test_create_table_and_insert_many(self, connection, request):
5273
connection = request.getfixturevalue(connection)
5374

54-
create_table_query = "CREATE TABLE IF NOT EXISTS sqlitetest (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
55-
connection.execute(create_table_query)
56-
57-
truncate_table_query = "DELETE FROM sqlitetest"
58-
connection.execute(truncate_table_query)
75+
table = "sqlitetest" + str(random.randint(0, 99999))
76+
try:
77+
create_table_query = f"CREATE TABLE IF NOT EXISTS {table} (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
78+
connection.execute(create_table_query)
5979

60-
insert_query = "INSERT INTO sqlitetest (name, age) VALUES (?, ?)"
61-
params = [("Alice", 25), ("Bob", 30)]
62-
connection.executemany(insert_query, params)
80+
insert_query = f"INSERT INTO {table} (name, age) VALUES (?, ?)"
81+
params = [("Alice", 25), ("Bob", 30)]
82+
connection.executemany(insert_query, params)
6383

64-
select_query = "SELECT * FROM sqlitetest"
65-
cursor = connection.execute(select_query)
84+
select_query = f"SELECT * FROM {table}"
85+
cursor = connection.execute(select_query)
6686

67-
results = cursor.fetchall()
87+
results = cursor.fetchall()
6888

69-
assert len(results) == 2
70-
assert results[0][1] == "Alice"
71-
assert results[0][2] == 25
72-
assert results[1][1] == "Bob"
73-
assert results[1][2] == 30
89+
assert len(results) == 2
90+
assert results[0][1] == "Alice"
91+
assert results[0][2] == 25
92+
assert results[1][1] == "Bob"
93+
assert results[1][2] == 30
94+
finally:
95+
connection.execute(f"DROP TABLE IF EXISTS {table}")
7496

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

176198
assert connection.total_changes == 2
177199

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

@@ -375,13 +394,18 @@ def test_cursor_description_with_explicit_decltype(
375394
"""Since py3.7 the parsed of `[decltype]` disabled when PARSE_COLNAMES.
376395
See bpo-39652 https://github.com/python/cpython/issues/83833"""
377396
if parse_colnames:
378-
connection = next(connection(module.PARSE_COLNAMES))
397+
connection_gen = connection(module.PARSE_COLNAMES)
379398
else:
380-
connection = next(connection())
399+
connection_gen = connection()
381400

382-
cursor = connection.execute(f"SELECT {value}")
401+
connection = next(connection_gen)
402+
403+
try:
404+
cursor = connection.execute(f"SELECT {value}")
383405

384-
assert cursor.description[0][0] == expected
406+
assert cursor.description[0][0] == expected
407+
finally:
408+
close_generator(connection_gen)
385409

386410
def test_fetch_one(self, sqlitecloud_dbapi2_connection, sqlite3_connection):
387411
sqlitecloud_connection = sqlitecloud_dbapi2_connection
@@ -508,7 +532,7 @@ def test_explicit_transaction_to_commit(
508532
sqlitecloud_dbapi2_connection: sqlitecloud.Connection,
509533
sqlite3_connection: sqlite3.Connection,
510534
):
511-
seed = str(int(time.time()))
535+
seed = str(uuid.uuid4())
512536

513537
sqlitecloud_conn_gen = get_sqlitecloud_dbapi2_connection()
514538
sqlite_conn_gen = get_sqlite3_connection()
@@ -878,7 +902,9 @@ def adapt_point(point):
878902
],
879903
)
880904
def test_parse_decltypes(self, connection, module):
881-
connection = next(connection(module.PARSE_DECLTYPES))
905+
connection_gen = connection(module.PARSE_DECLTYPES)
906+
907+
connection = next(connection_gen)
882908

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

913940
@pytest.mark.parametrize(
914941
"connection, module",

src/tests/unit/test_driver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def test_compression_enabled_by_default(self, mocker: MockerFixture):
147147

148148
driver.connect("myhost", 8860, config)
149149

150-
expected_buffer = "SET CLIENT KEY COMPRESSION TO 1;"
150+
expected_buffer = b"SET CLIENT KEY COMPRESSION TO 1;"
151151

152152
run_command_mock.assert_called_once()
153153
assert expected_buffer in run_command_mock.call_args[0][1]

0 commit comments

Comments
 (0)