Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changes/newsfragments/+test-sqlite-sync.underthehood
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The test suite runs faster, especially on Windows: test databases are now opened with SQLite's
``PRAGMA synchronous=OFF`` so that commits are not flushed to disk.
2 changes: 2 additions & 0 deletions docs/changes/newsfragments/8749.underthehood
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
All temporary files created by the test suite are now placed under pytest's temporary directory
root, so setting ``PYTEST_DEBUG_TEMPROOT`` (or ``--basetemp``) relocates all of them.
28 changes: 27 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys
import threading
import weakref
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

import matplotlib
import pytest
Expand All @@ -16,6 +16,7 @@
from qcodes.dataset import get_open_connections, initialise_database, new_data_set
from qcodes.dataset.descriptions.dependencies import InterDependencies_
from qcodes.dataset.experiment_container import Experiment, new_experiment
from qcodes.dataset.sqlite.connection import AtomicConnection
from qcodes.instrument import Instrument
from qcodes.monitor.monitor import Monitor
from qcodes.parameters import ParamSpecBase
Expand Down Expand Up @@ -54,6 +55,31 @@ def matplotlib_set_backend() -> None:
matplotlib.use("agg")


@pytest.fixture(scope="session", autouse=True)
def disable_sqlite_disk_sync() -> Generator[None, None, None]:
"""
Open every QCoDeS database connection with ``PRAGMA synchronous=OFF``.

By default SQLite flushes the database to disk on every commit, which
protects against data loss on OS crashes or power failures. Test databases
are thrown away after the test, so these flushes only cost time. This is
especially slow on Windows, and less so where the temporary directory
is a RAM disk (e.g. ``/tmp`` on many Linux systems). Turning this off
does not change what other connections or processes can read.
"""
original_init = AtomicConnection.__init__

def init_without_disk_sync(
self: AtomicConnection, *args: Any, **kwargs: Any
) -> None:
original_init(self, *args, **kwargs)
self.execute("PRAGMA synchronous=OFF")

with pytest.MonkeyPatch.context() as mp:
mp.setattr(AtomicConnection, "__init__", init_without_disk_sync)
yield


@pytest.fixture(scope="session", autouse=True)
def default_session_config(
tmp_path_factory: pytest.TempPathFactory,
Expand Down
26 changes: 13 additions & 13 deletions tests/dataset/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import os
import shutil
import tempfile
from contextlib import contextmanager
from enum import StrEnum
from typing import TYPE_CHECKING, Any
Expand Down Expand Up @@ -94,29 +93,30 @@ def two_empty_temp_db_connections(

@contextmanager
def temporarily_copied_DB(
filepath: str, **kwargs: Any
filepath: str, tmp_path: Path, **kwargs: Any
) -> Generator[AtomicConnection, None, None]:
"""
Make a temporary copy of a db-file and delete it after use. Meant to be
used together with the old version database fixtures, lest we change the
fixtures on disk. Yields the connection object
Copy a db-file into ``tmp_path`` and yield a connection to the copy,
closing it after use. Meant to be used together with the old version
database fixtures, lest we change the fixtures on disk. The copy keeps the
file name of the original, so each file can only be copied once per test.

Args:
filepath: path to the db-file
tmp_path: the test's ``tmp_path`` fixture, the directory to copy into
**kwargs: to be passed to connect

"""
with tempfile.TemporaryDirectory() as tmpdir:
dbname_new = os.path.join(tmpdir, "temp.db")
shutil.copy2(filepath, dbname_new)
dbname_new = tmp_path / os.path.basename(filepath)
shutil.copy2(filepath, dbname_new)

conn = connect(dbname_new, **kwargs)
conn = connect(dbname_new, **kwargs)

try:
yield conn
try:
yield conn

finally:
conn.close()
finally:
conn.close()


@pytest.fixture(name="scalar_dataset")
Expand Down
58 changes: 29 additions & 29 deletions tests/dataset/test_database_creation_and_upgrading.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def test_initialised_database_at_with_journal_mode_none(tmp_path: Path) -> None:
assert os.path.exists(db_location)


def test_perform_actual_upgrade_0_to_1() -> None:
def test_perform_actual_upgrade_0_to_1(tmp_path: Path) -> None:
# we cannot use the empty_temp_db, since that has already called connect
# and is therefore latest version already

Expand All @@ -287,7 +287,7 @@ def test_perform_actual_upgrade_0_to_1() -> None:

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=0) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=0) as conn:
assert get_user_version(conn) == 0

guid_table_query = "SELECT guid FROM runs"
Expand All @@ -304,14 +304,14 @@ def test_perform_actual_upgrade_0_to_1() -> None:
assert len(c.fetchall()) == 0


def test_perform_actual_upgrade_1_to_2() -> None:
def test_perform_actual_upgrade_1_to_2(tmp_path: Path) -> None:
v1fixpath = os.path.join(fixturepath, "db_files", "version1")

dbname_old = os.path.join(v1fixpath, "empty.db")

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=1) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=1) as conn:
assert get_user_version(conn) == 1

guid_table_query = "SELECT guid FROM runs"
Expand All @@ -330,14 +330,14 @@ def test_perform_actual_upgrade_1_to_2() -> None:
assert len(c.fetchall()) == 2


def test_perform_actual_upgrade_2_to_3_empty() -> None:
def test_perform_actual_upgrade_2_to_3_empty(tmp_path: Path) -> None:
v2fixpath = os.path.join(fixturepath, "db_files", "version2")

dbname_old = os.path.join(v2fixpath, "empty.db")

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=2) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=2) as conn:
assert get_user_version(conn) == 2

desc_query = "SELECT run_description FROM runs"
Expand All @@ -355,25 +355,25 @@ def test_perform_actual_upgrade_2_to_3_empty() -> None:
assert len(c.fetchall()) == 0


def test_perform_actual_upgrade_2_to_3_empty_runs() -> None:
def test_perform_actual_upgrade_2_to_3_empty_runs(tmp_path: Path) -> None:
v2fixpath = os.path.join(fixturepath, "db_files", "version2")

dbname_old = os.path.join(v2fixpath, "empty_runs.db")

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=2) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=2) as conn:
perform_db_upgrade_2_to_3(conn)


def test_perform_actual_upgrade_2_to_3_some_runs() -> None:
def test_perform_actual_upgrade_2_to_3_some_runs(tmp_path: Path) -> None:
v2fixpath = os.path.join(fixturepath, "db_files", "version2")

dbname_old = os.path.join(v2fixpath, "some_runs.db")

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=2) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=2) as conn:
assert get_user_version(conn) == 2

perform_db_upgrade_2_to_3(conn)
Expand Down Expand Up @@ -450,7 +450,7 @@ def test_perform_actual_upgrade_2_to_3_some_runs() -> None:
assert p5.unit == "unit 5"


def test_perform_upgrade_v2_v3_to_v4_fixes() -> None:
def test_perform_upgrade_v2_v3_to_v4_fixes(tmp_path: Path) -> None:
"""
Test that a db that was upgraded from v2 to v3 with a buggy
version will be corrected when upgraded to v4.
Expand All @@ -462,7 +462,7 @@ def test_perform_upgrade_v2_v3_to_v4_fixes() -> None:

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=3) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=3) as conn:
assert get_user_version(conn) == 3

sql = """
Expand Down Expand Up @@ -591,7 +591,7 @@ def test_perform_upgrade_v2_v3_to_v4_fixes() -> None:
assert p5.unit == "unit 5"


def test_perform_upgrade_v3_to_v4() -> None:
def test_perform_upgrade_v3_to_v4(tmp_path: Path) -> None:
"""
Test that a db upgrade from v2 to v4 works correctly.
"""
Expand All @@ -602,7 +602,7 @@ def test_perform_upgrade_v3_to_v4() -> None:

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=3) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=3) as conn:
assert get_user_version(conn) == 3

sql = """
Expand Down Expand Up @@ -763,15 +763,15 @@ def _assert_loc_station(
@pytest.mark.parametrize(
"db_file", ["empty", "with_runs_but_no_snapshots", "with_runs_and_snapshots"]
)
def test_perform_actual_upgrade_4_to_5(db_file: str) -> None:
def test_perform_actual_upgrade_4_to_5(db_file: str, tmp_path: Path) -> None:
v4fixpath = os.path.join(fixturepath, "db_files", "version4")

db_file += ".db"
dbname_old = os.path.join(v4fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=4) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=4) as conn:
# firstly, assert the situation with 'snapshot' column of 'runs' table
if "with_runs_and_snapshots" in db_file:
assert is_column_in_table(conn, "runs", "snapshot")
Expand All @@ -785,22 +785,22 @@ def test_perform_actual_upgrade_4_to_5(db_file: str) -> None:
assert is_column_in_table(conn, "runs", "snapshot")


def test_perform_actual_upgrade_5_to_6() -> None:
def test_perform_actual_upgrade_5_to_6(tmp_path: Path) -> None:
fixpath = os.path.join(fixturepath, "db_files", "version5")

db_file = "empty.db"
dbname_old = os.path.join(fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=5) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=5) as conn:
perform_db_upgrade_5_to_6(conn)
assert get_user_version(conn) == 6

db_file = "some_runs.db"
dbname_old = os.path.join(fixpath, db_file)

with temporarily_copied_DB(dbname_old, debug=False, version=5) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=5) as conn:
perform_db_upgrade_5_to_6(conn)
assert get_user_version(conn) == 6

Expand All @@ -818,28 +818,28 @@ def test_perform_actual_upgrade_5_to_6() -> None:
assert desc._version == 3


def test_perform_upgrade_6_7() -> None:
def test_perform_upgrade_6_7(tmp_path: Path) -> None:
fixpath = os.path.join(fixturepath, "db_files", "version6")

db_file = "empty.db"
dbname_old = os.path.join(fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=6) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=6) as conn:
perform_db_upgrade_6_to_7(conn)
assert get_user_version(conn) == 7


def test_perform_actual_upgrade_6_to_7() -> None:
def test_perform_actual_upgrade_6_to_7(tmp_path: Path) -> None:
fixpath = os.path.join(fixturepath, "db_files", "version6")

db_file = "some_runs.db"
dbname_old = os.path.join(fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=6) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=6) as conn:
assert isinstance(conn, AtomicConnection)
perform_db_upgrade_6_to_7(conn)
assert get_user_version(conn) == 7
Expand Down Expand Up @@ -881,7 +881,7 @@ def test_perform_actual_upgrade_6_to_7() -> None:
assert ds2.counter == ds2.captured_counter


def test_perform_actual_upgrade_6_to_newest_add_new_data() -> None:
def test_perform_actual_upgrade_6_to_newest_add_new_data(tmp_path: Path) -> None:
"""
Insert new runs on top of existing runs upgraded and verify that they
get the correct captured_run_id and captured_counter
Expand All @@ -894,7 +894,7 @@ def test_perform_actual_upgrade_6_to_newest_add_new_data() -> None:

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=6) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=6) as conn:
assert isinstance(conn, AtomicConnection)
perform_db_upgrade(conn)
assert get_user_version(conn) >= 7
Expand Down Expand Up @@ -980,15 +980,15 @@ def test_perform_actual_upgrade_6_to_newest_add_new_data() -> None:


@pytest.mark.parametrize("db_file", ["empty", "some_runs"])
def test_perform_actual_upgrade_7_to_8(db_file: str) -> None:
def test_perform_actual_upgrade_7_to_8(db_file: str, tmp_path: Path) -> None:
v7fixpath = os.path.join(fixturepath, "db_files", "version7")

db_file += ".db"
dbname_old = os.path.join(v7fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=7) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=7) as conn:
perform_db_upgrade_7_to_8(conn)

assert is_column_in_table(conn, "runs", "parent_datasets")
Expand Down Expand Up @@ -1027,15 +1027,15 @@ def test_getting_db_version(version: int) -> None:


@pytest.mark.parametrize("db_file", ["empty", "some_runs"])
def test_perform_actual_upgrade_8_to_9(db_file: str) -> None:
def test_perform_actual_upgrade_8_to_9(db_file: str, tmp_path: Path) -> None:
v8fixpath = os.path.join(fixturepath, "db_files", "version8")

db_file += ".db"
dbname_old = os.path.join(v8fixpath, db_file)

skip_if_no_fixtures(dbname_old)

with temporarily_copied_DB(dbname_old, debug=False, version=8) as conn:
with temporarily_copied_DB(dbname_old, tmp_path, debug=False, version=8) as conn:
index_query = "PRAGMA index_list(runs)"

c = atomic_transaction(conn, index_query)
Expand Down
Loading
Loading