1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-17 01:22:19 +03:00

Merge pull request from EDCD/fix/tests/TestJournalLock.test_release_lock

Finally(?) ensure all the tests work, no contamination or races
This commit is contained in:
Athanasius 2022-09-07 14:19:56 +01:00 committed by GitHub
commit 3deb6e2d4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,33 +1,4 @@
"""
Tests for journal_lock.py code.
Tests:
- Is file actually locked after obtain_lock(). Problem: We opened the
file in a manner which means nothing else can open it. Also I assume
that the same process will either be allowed to lock it 'again' or
overwrite the lock.
Expected failures if:
1. Lock already held (elsewhere).
2. Can't open lock file 'w+'.
3. Path to lock file doesn't exist.
4. journaldir is None (default on Linux).
- Does release_lock() work? Easier to test, if it's worked....
1. return True if not locked.
2. return True if locked, but successful unlock.
3. return False otherwise.
- JournalLock.set_path_from_journaldir
1. When journaldir is None.
2. Succeeds otherwise?
- Can any string to pathlib.Path result in an invalid path for other
operations?
- Not sure about testing JournalAlreadyLocked class.
"""
"""Tests for journal_lock.py code."""
import multiprocessing as mp
import os
import pathlib
@ -70,6 +41,7 @@ def other_process_lock(continue_q: mp.Queue, exit_q: mp.Queue, lockfile: pathlib
exit_q.get(block=True, timeout=None)
# And clean up
_release_lock('sub-process', lf)
os.unlink(lockfile / 'edmc-journal-lock.txt')
@ -104,6 +76,40 @@ def _obtain_lock(prefix: str, filehandle) -> bool:
return False
return True
def _release_lock(prefix: str, filehandle) -> bool:
"""
Release the JournalLock.
:param prefix: str - what to prefix output with.
:param filehandle: File handle already open on the lockfile.
:return: bool - True if we released the lock.
"""
if sys.platform == 'win32':
print(f'{prefix}: On win32')
import msvcrt
try:
print(f'{prefix}: Trying msvcrt.locking() ...')
filehandle.seek(0)
msvcrt.locking(filehandle.fileno(), msvcrt.LK_UNLCK, 4096)
except Exception as e:
print(f'{prefix}: Unable to unlock file: {e!r}')
return False
else:
import fcntl
print(f'{prefix}: Not win32, using fcntl')
try:
fcntl.flock(filehandle, fcntl.LOCK_UN)
except Exception as e:
print(f'{prefix}: Unable to unlock file: {e!r}')
return False
return True
###########################################################################
@ -292,9 +298,13 @@ class TestJournalLock:
# Now attempt to lock with to-test code
jlock = JournalLock()
second_attempt = jlock.obtain_lock()
# Fails on Linux, because flock(2) is per process, so we'd need to
# use multiprocessing to test this.
assert second_attempt == JournalLockResult.ALREADY_LOCKED
# Need to release any handles on the lockfile else the sub-process
# might not be able to clean up properly, and that will impact
# on later tests.
jlock.journal_dir_lockfile.close()
print('Telling sub-process to quit...')
exit_q.put('quit')
print('Waiting for sub-process...')
@ -316,6 +326,7 @@ class TestJournalLock:
# And finally check it actually IS unlocked.
with open(mock_journaldir.getbasetemp() / 'edmc-journal-lock.txt', mode='w+') as lf:
assert _obtain_lock('release-lock', lf)
assert _release_lock('release-lock', lf)
# Cleanup, to avoid side-effect on other tests
os.unlink(str(jlock.journal_dir_lockfile_name))