Skip to content

Commit ae897d2

Browse files
committed
Update fixture generator and fixture for Django 2.x
1 parent ebb80bf commit ae897d2

File tree

9 files changed

+77
-64
lines changed

9 files changed

+77
-64
lines changed

conftest.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,14 @@
5858
D1_SKIP_LIST = 'skip_passed/list'
5959
D1_SKIP_COUNT = 'skip_passed/count'
6060

61+
# Dict lookup keys matching the keys in settings_test.DATABASE
6162
TEMPLATE_DB_KEY = 'template'
6263
TEST_DB_KEY = 'default'
6364

64-
GMN_DB_FIXTURE_LABEL = 'db_fixture'
65-
6665
# Allow redefinition of functions. Pytest allows multiple hooks with the same
6766
# name.
6867
# flake8: noqa: F811
6968

70-
# template_db_lock = threading.Lock()
71-
template_db_lock = multiprocessing.Lock()
72-
7369
# Hack to get access to print and logging output when running under pytest-xdist
7470
# and pytest-catchlog. Without this, only output from failed tests is displayed.
7571
sys.stdout = sys.stderr
@@ -112,7 +108,7 @@ def pytest_addoption(parser):
112108

113109
parser.addoption(
114110
'--fixture-refresh', action='store_true',
115-
help='Drop and create GMN template database from JSON fixture file'
111+
help='Drop and recreate GMN template database from JSON fixture file'
116112
)
117113

118114
# Skip passed tests
@@ -417,7 +413,8 @@ def enable_db_access(db):
417413

418414

419415
@pytest.yield_fixture(scope='session', autouse=True)
420-
def django_db_setup(request):
416+
@pytest.mark.django_db
417+
def django_db_setup(request, django_db_blocker):
421418
"""Set up DB fixture
422419
When running in parallel with xdist, this is called once for each worker,
423420
causing a separate database to be set up for each worker.
@@ -426,46 +423,47 @@ def django_db_setup(request):
426423

427424
db_set_unique_db_name(request)
428425

429-
# Regular multiprocessing.Lock() context manager did not work here. Also
430-
# tried creating the lock at module scope, and also directly calling
431-
# acquire() and release(). It's probably related to how the worker processes
432-
# relate to each other when launched by pytest-xdist as compared to what the
433-
# multiprocessing module expects.
434-
with posix_ipc.Semaphore(
435-
'/{}'.format(__name__), flags=posix_ipc.O_CREAT, initial_value=1
436-
):
437-
logging.warning(
438-
'LOCK BEGIN {} {}'.format(
439-
db_get_name_by_key(TEMPLATE_DB_KEY), d1_common.date_time.utc_now()
426+
with django_db_blocker.unblock():
427+
# Regular multiprocessing.Lock() context manager did not work here. Also
428+
# tried creating the lock at module scope, and also directly calling
429+
# acquire() and release(). It's probably related to how the worker processes
430+
# relate to each other when launched by pytest-xdist as compared to what the
431+
# multiprocessing module expects.
432+
with posix_ipc.Semaphore(
433+
'/{}'.format(__name__), flags=posix_ipc.O_CREAT, initial_value=1
434+
):
435+
logging.warning(
436+
'LOCK BEGIN {} {}'.format(
437+
db_get_name_by_key(TEMPLATE_DB_KEY), d1_common.date_time.utc_now()
438+
)
440439
)
441-
)
442440

443-
if not db_exists(TEMPLATE_DB_KEY):
444-
db_create_blank(TEMPLATE_DB_KEY)
445-
db_migrate(TEMPLATE_DB_KEY)
446-
db_populate_by_json(TEMPLATE_DB_KEY)
447-
db_migrate(TEMPLATE_DB_KEY)
441+
if not db_exists(TEMPLATE_DB_KEY):
442+
db_create_blank(TEMPLATE_DB_KEY)
443+
db_migrate(TEMPLATE_DB_KEY)
444+
db_populate_by_json(TEMPLATE_DB_KEY)
445+
db_migrate(TEMPLATE_DB_KEY)
448446

449-
logging.warning(
450-
'LOCK END {} {}'.format(
451-
db_get_name_by_key(TEMPLATE_DB_KEY), d1_common.date_time.utc_now()
447+
logging.warning(
448+
'LOCK END {} {}'.format(
449+
db_get_name_by_key(TEMPLATE_DB_KEY), d1_common.date_time.utc_now()
450+
)
452451
)
453-
)
454452

455-
db_drop(TEST_DB_KEY)
456-
db_create_from_template()
457-
# db_migrate(TEST_DB_KEY)
453+
db_drop(TEST_DB_KEY)
454+
db_create_from_template()
455+
# db_migrate(TEST_DB_KEY)
458456

459-
# Haven't found out how to prevent transactions from being started. so
460-
# closing the implicit transaction here so that template fixture remains
461-
# available.
462-
# django.db.connections[test_db_key].commit()
457+
# Haven't found out how to prevent transactions from being started. so
458+
# closing the implicit transaction here so that template fixture remains
459+
# available.
460+
# django.db.connections[TEST_DB_KEY].commit()
463461

464-
logging.debug(django.conf.settings)
462+
# print(django.conf.settings)
465463

466-
yield
464+
yield
467465

468-
db_drop(TEST_DB_KEY)
466+
db_drop(TEST_DB_KEY)
469467

470468

471469
def db_get_name_by_key(db_key):
@@ -501,8 +499,10 @@ def db_populate_by_json(db_key):
501499
logging.debug('db_populate_by_json() {}'.format(db_key))
502500
django.core.management.call_command(
503501
'loaddata',
504-
GMN_DB_FIXTURE_LABEL,
505-
database=db_key #, commit=True
502+
d1_test.sample.get_path('db_fixture.json.bz2'),
503+
database=db_key,
504+
# verbosity=0,
505+
# commit=False,
506506
)
507507
db_commit_and_close(db_key)
508508

-244 KB
Binary file not shown.
-27.3 KB
Binary file not shown.

gmn/src/d1_gmn/app/middleware/response_handler.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import d1_gmn.app.util
2929
import d1_gmn.app.views.slice
3030
import d1_gmn.app.views.util
31-
import d1_gmn.app.xslt
3231

3332
import d1_common.const
3433
import d1_common.date_time

gmn/src/d1_gmn/settings_test.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,20 @@
1515
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616
# See the License for the specific language governing permissions and
1717
# limitations under the License.
18-
"""Test settings for GMN
18+
"""Test and debug settings for GMN
1919
- These settings are in effect when GMN is called through unit tests.
2020
"""
2121

2222
# noinspection PyUnresolvedReferences
2323
# flake8: noqa: F403,F401
2424

2525
import logging
26-
# When running tests, turn Django's RuntimeWarning into exception
2726
import warnings
27+
import d1_common.util
2828

2929
from d1_gmn.app.settings_default import *
3030

31-
import d1_common.util
32-
31+
# When running tests, turn Django's RuntimeWarning into exception
3332
warnings.filterwarnings(
3433
'error', r"DateTimeField .* received a naive datetime", RuntimeWarning,
3534
r'django\.db\.models\.fields'
@@ -79,6 +78,17 @@
7978
NUM_CHUNK_BYTES = 1024**2
8079
MAX_SLICE_ITEMS = 5000
8180

81+
# mk_db_fixture:
82+
# - Uses DATABASES.default
83+
# - The default database is flushed then populated with test data by
84+
# mk_db_fixture
85+
#
86+
# Unit tests:
87+
# - Use DATABASES.default.NAME as a base name for temporary databases created
88+
# from the template database.
89+
# - Use DATABASES.template.NAME as the source database name when creating
90+
# databases from template.
91+
8292
DATABASES = {
8393
'default': {
8494
'ENGINE': 'django.db.backends.postgresql_psycopg2',
@@ -87,15 +97,8 @@
8797
'PASSWORD': '',
8898
'HOST': '',
8999
'PORT': '',
90-
# Transactions
91-
#
92-
# ATOMIC_REQUESTS is always True when running in production as implicit
93-
# transactions form the basis of concurrency control in GMN. However, during
94-
# debugging, uncommitted changes are hidden inside the transaction, making
95-
# it impossible (?) to see the changes made so far by the code being
96-
# debugged.
97100
'ATOMIC_REQUESTS': False,
98-
'AUTOCOMMIT': False,
101+
# 'AUTOCOMMIT': False,
99102
},
100103
'template': {
101104
'ENGINE': 'django.db.backends.postgresql_psycopg2',
@@ -105,7 +108,7 @@
105108
'HOST': '',
106109
'PORT': '',
107110
'ATOMIC_REQUESTS': False,
108-
'AUTOCOMMIT': False,
111+
# 'AUTOCOMMIT': False,
109112
},
110113
}
111114

gmn/src/d1_gmn/tests/mk_db_fixture.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1919
# See the License for the specific language governing permissions and
2020
# limitations under the License.
21-
"""Create database entries for a set of test objects
21+
"""Create database fixture JSON file
2222
23-
This creates the db entries by calling the GMN D1 APIs, then uses Django to dump
24-
the database to JSON.
23+
This creates the db entries for a set of test objects by calling the GMN D1
24+
APIs, then uses Django to dump the database to JSON.
2525
2626
Objects are randomly distributed between categories:
2727
- Standalone, no SID
@@ -32,7 +32,7 @@
3232
Though object bytes are also created, they are not captured in the db fixture.
3333
See the README.md for more info on the fixtures.
3434
35-
The django init needs to occur before the django and gmn_test_case imports, so
35+
The Django init needs to occur before the django and gmn_test_case imports, so
3636
we're stuck with a bit of a messy import section that isort and flake8 don't
3737
like.
3838
@@ -69,7 +69,9 @@
6969
import d1_test.instance_generator.system_metadata
7070
import d1_test.instance_generator.user_agent
7171

72+
# Dict lookup key matching the default key in settings_test.DATABASE
7273
TEST_DB_KEY = 'default'
74+
7375
N_OBJECTS = 1000
7476
N_READ_EVENTS = 2 * N_OBJECTS
7577

@@ -170,10 +172,19 @@ def save_compressed_db_fixture(self):
170172
with bz2.BZ2File(
171173
fixture_file_path, 'w', buffering=1024, compresslevel=9
172174
) as bz2_file:
173-
django.core.management.call_command('dumpdata', stdout=bz2_file)
175+
django.core.management.call_command(
176+
'dumpdata',
177+
exclude=['auth.permission', 'contenttypes'],
178+
database=TEST_DB_KEY,
179+
stdout=io.TextIOWrapper(bz2_file),
180+
)
174181

175182
def save_pid_list_sample(self, chunk_size=500, **list_objects_kwargs):
176-
"""Get list of all PIDs in the DB fixture"""
183+
"""Get list of all PIDs in the DB fixture
184+
185+
These are for use in any tests that need to know which PIDs and SIDs are
186+
available in the DB.
187+
"""
177188
client = self.client_v2
178189
with d1_gmn.tests.gmn_mock.disable_auth():
179190
start_idx = 0

gmn/src/d1_gmn/tests/test_get_log_records.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ def test_1020(self, gmn_client_v1_v2):
7070
"""getLogRecords(): Slicing: Retrieve middle section
7171
"""
7272
with d1_gmn.tests.gmn_mock.disable_auth():
73-
log = gmn_client_v1_v2.getLogRecords(start=2000, count=7)
73+
n_events = self.get_total_log_records(gmn_client_v1_v2)
74+
log = gmn_client_v1_v2.getLogRecords(start=n_events // 2, count=7)
7475
self.norm_entry_id(log)
7576
self.sample.assert_equals(log, 'middle_section', gmn_client_v1_v2)
7677

lib_common/src/d1_common/date_time.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class UTC(datetime.tzinfo):
4646
A naive Python datetime can be fixed to UTC by attaching it to this
4747
timezoneinfo based class.
4848
"""
49-
5049
def __repr__(self):
5150
return self.tzname(0)
5251

test_utilities/src/d1_test/d1_test_case.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,8 @@ def dt_from_ts(ts, tz=None):
342342
"""Convert POSIX timestamp to a datetime
343343
- If {tz} supplied: The dt is adjusted to that tz before being returned.
344344
- If {tz} not supplied: the dt is returned as naive.
345-
- Keeping this function out of d1_common.date_time since we only need
346-
naive datetimes for testing.
345+
- Keeping this function out of d1_common.date_time since naive datetimes
346+
are only needed for testing.
347347
"""
348348
return datetime.datetime.fromtimestamp(ts, tz)
349349

0 commit comments

Comments
 (0)