tests: Separate tests for llnl.util.lock and spack.util.lock
- llnl.util.lock tests are now independent of Spack
This commit is contained in:
parent
7626ec4579
commit
b9af52a888
@ -96,7 +96,7 @@ def test(parser, args, unknown_args):
|
|||||||
pytest.main(['-h'])
|
pytest.main(['-h'])
|
||||||
return
|
return
|
||||||
|
|
||||||
# pytest.ini lives in the root of the spack repository.
|
# pytest.ini lives in lib/spack/spack/test
|
||||||
with working_dir(spack.paths.test_path):
|
with working_dir(spack.paths.test_path):
|
||||||
# --list and --long-list print the test output better.
|
# --list and --long-list print the test output better.
|
||||||
if args.list or args.long_list:
|
if args.list or args.long_list:
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
##############################################################################
|
|
||||||
# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
|
|
||||||
# Produced at the Lawrence Livermore National Laboratory.
|
|
||||||
#
|
|
||||||
# This file is part of Spack.
|
|
||||||
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
|
||||||
# LLNL-CODE-647188
|
|
||||||
#
|
|
||||||
# For details, see https://github.com/spack/spack
|
|
||||||
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License (as
|
|
||||||
# published by the Free Software Foundation) version 2.1, February 1999.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but
|
|
||||||
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
|
||||||
# conditions of the GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
##############################################################################
|
|
@ -72,11 +72,9 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import llnl.util.lock as lk
|
||||||
import llnl.util.multiproc as mp
|
import llnl.util.multiproc as mp
|
||||||
from llnl.util.filesystem import touch, group_ids
|
from llnl.util.filesystem import touch
|
||||||
|
|
||||||
import spack.util.lock
|
|
||||||
from spack.util.lock import Lock, WriteTransaction, ReadTransaction, LockError
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -267,7 +265,7 @@ def wait(self):
|
|||||||
#
|
#
|
||||||
def acquire_write(lock_path, start=0, length=0):
|
def acquire_write(lock_path, start=0, length=0):
|
||||||
def fn(barrier):
|
def fn(barrier):
|
||||||
lock = Lock(lock_path, start, length)
|
lock = lk.Lock(lock_path, start, length)
|
||||||
lock.acquire_write() # grab exclusive lock
|
lock.acquire_write() # grab exclusive lock
|
||||||
barrier.wait()
|
barrier.wait()
|
||||||
barrier.wait() # hold the lock until timeout in other procs.
|
barrier.wait() # hold the lock until timeout in other procs.
|
||||||
@ -276,7 +274,7 @@ def fn(barrier):
|
|||||||
|
|
||||||
def acquire_read(lock_path, start=0, length=0):
|
def acquire_read(lock_path, start=0, length=0):
|
||||||
def fn(barrier):
|
def fn(barrier):
|
||||||
lock = Lock(lock_path, start, length)
|
lock = lk.Lock(lock_path, start, length)
|
||||||
lock.acquire_read() # grab shared lock
|
lock.acquire_read() # grab shared lock
|
||||||
barrier.wait()
|
barrier.wait()
|
||||||
barrier.wait() # hold the lock until timeout in other procs.
|
barrier.wait() # hold the lock until timeout in other procs.
|
||||||
@ -285,9 +283,9 @@ def fn(barrier):
|
|||||||
|
|
||||||
def timeout_write(lock_path, start=0, length=0):
|
def timeout_write(lock_path, start=0, length=0):
|
||||||
def fn(barrier):
|
def fn(barrier):
|
||||||
lock = Lock(lock_path, start, length)
|
lock = lk.Lock(lock_path, start, length)
|
||||||
barrier.wait() # wait for lock acquire in first process
|
barrier.wait() # wait for lock acquire in first process
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
barrier.wait()
|
barrier.wait()
|
||||||
return fn
|
return fn
|
||||||
@ -295,9 +293,9 @@ def fn(barrier):
|
|||||||
|
|
||||||
def timeout_read(lock_path, start=0, length=0):
|
def timeout_read(lock_path, start=0, length=0):
|
||||||
def fn(barrier):
|
def fn(barrier):
|
||||||
lock = Lock(lock_path, start, length)
|
lock = lk.Lock(lock_path, start, length)
|
||||||
barrier.wait() # wait for lock acquire in first process
|
barrier.wait() # wait for lock acquire in first process
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait()
|
barrier.wait()
|
||||||
return fn
|
return fn
|
||||||
@ -552,7 +550,7 @@ def test_upgrade_read_to_write(private_lock_path):
|
|||||||
# to begin wtih.
|
# to begin wtih.
|
||||||
touch(private_lock_path)
|
touch(private_lock_path)
|
||||||
|
|
||||||
lock = Lock(private_lock_path)
|
lock = lk.Lock(private_lock_path)
|
||||||
assert lock._reads == 0
|
assert lock._reads == 0
|
||||||
assert lock._writes == 0
|
assert lock._writes == 0
|
||||||
|
|
||||||
@ -577,16 +575,14 @@ def test_upgrade_read_to_write(private_lock_path):
|
|||||||
assert lock._file is None
|
assert lock._file is None
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test that read-only file can be read-locked but not write-locked.
|
|
||||||
#
|
|
||||||
def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
|
def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
|
||||||
# ensure lock file exists the first time, so we open it read-only
|
"""Test that read-only file can be read-locked but not write-locked."""
|
||||||
# to begin wtih.
|
# ensure lock file exists the first time
|
||||||
touch(private_lock_path)
|
touch(private_lock_path)
|
||||||
|
|
||||||
|
# open it read-only to begin wtih.
|
||||||
with read_only(private_lock_path):
|
with read_only(private_lock_path):
|
||||||
lock = Lock(private_lock_path)
|
lock = lk.Lock(private_lock_path)
|
||||||
assert lock._reads == 0
|
assert lock._reads == 0
|
||||||
assert lock._writes == 0
|
assert lock._writes == 0
|
||||||
|
|
||||||
@ -595,7 +591,8 @@ def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
|
|||||||
assert lock._writes == 0
|
assert lock._writes == 0
|
||||||
assert lock._file.mode == 'r'
|
assert lock._file.mode == 'r'
|
||||||
|
|
||||||
with pytest.raises(LockError):
|
# upgrade to writ here
|
||||||
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write()
|
lock.acquire_write()
|
||||||
|
|
||||||
|
|
||||||
@ -605,7 +602,7 @@ def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path):
|
|||||||
#
|
#
|
||||||
def test_complex_acquire_and_release_chain(lock_path):
|
def test_complex_acquire_and_release_chain(lock_path):
|
||||||
def p1(barrier):
|
def p1(barrier):
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
lock.acquire_write()
|
lock.acquire_write()
|
||||||
barrier.wait() # ---------------------------------------- 1
|
barrier.wait() # ---------------------------------------- 1
|
||||||
@ -613,7 +610,7 @@ def p1(barrier):
|
|||||||
barrier.wait() # ---------------------------------------- 2
|
barrier.wait() # ---------------------------------------- 2
|
||||||
lock.release_write() # release and others acquire read
|
lock.release_write() # release and others acquire read
|
||||||
barrier.wait() # ---------------------------------------- 3
|
barrier.wait() # ---------------------------------------- 3
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
lock.acquire_read()
|
lock.acquire_read()
|
||||||
barrier.wait() # ---------------------------------------- 4
|
barrier.wait() # ---------------------------------------- 4
|
||||||
@ -622,9 +619,9 @@ def p1(barrier):
|
|||||||
|
|
||||||
# p2 upgrades read to write
|
# p2 upgrades read to write
|
||||||
barrier.wait() # ---------------------------------------- 6
|
barrier.wait() # ---------------------------------------- 6
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 7
|
barrier.wait() # ---------------------------------------- 7
|
||||||
# p2 releases write and read
|
# p2 releases write and read
|
||||||
@ -634,9 +631,9 @@ def p1(barrier):
|
|||||||
barrier.wait() # ---------------------------------------- 9
|
barrier.wait() # ---------------------------------------- 9
|
||||||
# p3 upgrades read to write
|
# p3 upgrades read to write
|
||||||
barrier.wait() # ---------------------------------------- 10
|
barrier.wait() # ---------------------------------------- 10
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 11
|
barrier.wait() # ---------------------------------------- 11
|
||||||
# p3 releases locks
|
# p3 releases locks
|
||||||
@ -646,13 +643,13 @@ def p1(barrier):
|
|||||||
lock.release_read()
|
lock.release_read()
|
||||||
|
|
||||||
def p2(barrier):
|
def p2(barrier):
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
# p1 acquires write
|
# p1 acquires write
|
||||||
barrier.wait() # ---------------------------------------- 1
|
barrier.wait() # ---------------------------------------- 1
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 2
|
barrier.wait() # ---------------------------------------- 2
|
||||||
lock.acquire_read()
|
lock.acquire_read()
|
||||||
@ -674,9 +671,9 @@ def p2(barrier):
|
|||||||
barrier.wait() # ---------------------------------------- 9
|
barrier.wait() # ---------------------------------------- 9
|
||||||
# p3 upgrades read to write
|
# p3 upgrades read to write
|
||||||
barrier.wait() # ---------------------------------------- 10
|
barrier.wait() # ---------------------------------------- 10
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 11
|
barrier.wait() # ---------------------------------------- 11
|
||||||
# p3 releases locks
|
# p3 releases locks
|
||||||
@ -686,13 +683,13 @@ def p2(barrier):
|
|||||||
lock.release_read()
|
lock.release_read()
|
||||||
|
|
||||||
def p3(barrier):
|
def p3(barrier):
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
# p1 acquires write
|
# p1 acquires write
|
||||||
barrier.wait() # ---------------------------------------- 1
|
barrier.wait() # ---------------------------------------- 1
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 2
|
barrier.wait() # ---------------------------------------- 2
|
||||||
lock.acquire_read()
|
lock.acquire_read()
|
||||||
@ -704,9 +701,9 @@ def p3(barrier):
|
|||||||
|
|
||||||
# p2 upgrades read to write
|
# p2 upgrades read to write
|
||||||
barrier.wait() # ---------------------------------------- 6
|
barrier.wait() # ---------------------------------------- 6
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_write(lock_fail_timeout)
|
lock.acquire_write(lock_fail_timeout)
|
||||||
with pytest.raises(LockError):
|
with pytest.raises(lk.LockError):
|
||||||
lock.acquire_read(lock_fail_timeout)
|
lock.acquire_read(lock_fail_timeout)
|
||||||
barrier.wait() # ---------------------------------------- 7
|
barrier.wait() # ---------------------------------------- 7
|
||||||
# p2 releases write & read
|
# p2 releases write & read
|
||||||
@ -736,9 +733,9 @@ def exit_fn(t, v, tb):
|
|||||||
vals['exited'] = True
|
vals['exited'] = True
|
||||||
vals['exception'] = (t or v or tb)
|
vals['exception'] = (t or v or tb)
|
||||||
|
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
vals = {'entered': False, 'exited': False, 'exception': False}
|
vals = {'entered': False, 'exited': False, 'exception': False}
|
||||||
with ReadTransaction(lock, enter_fn, exit_fn):
|
with lk.ReadTransaction(lock, enter_fn, exit_fn):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -746,7 +743,7 @@ def exit_fn(t, v, tb):
|
|||||||
assert not vals['exception']
|
assert not vals['exception']
|
||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exception': False}
|
vals = {'entered': False, 'exited': False, 'exception': False}
|
||||||
with WriteTransaction(lock, enter_fn, exit_fn):
|
with lk.WriteTransaction(lock, enter_fn, exit_fn):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -762,14 +759,14 @@ def exit_fn(t, v, tb):
|
|||||||
vals['exited'] = True
|
vals['exited'] = True
|
||||||
vals['exception'] = (t or v or tb)
|
vals['exception'] = (t or v or tb)
|
||||||
|
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
def do_read_with_exception():
|
def do_read_with_exception():
|
||||||
with ReadTransaction(lock, enter_fn, exit_fn):
|
with lk.ReadTransaction(lock, enter_fn, exit_fn):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
def do_write_with_exception():
|
def do_write_with_exception():
|
||||||
with WriteTransaction(lock, enter_fn, exit_fn):
|
with lk.WriteTransaction(lock, enter_fn, exit_fn):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exception': False}
|
vals = {'entered': False, 'exited': False, 'exception': False}
|
||||||
@ -801,11 +798,11 @@ def exit_fn(t, v, tb):
|
|||||||
vals['exited_fn'] = True
|
vals['exited_fn'] = True
|
||||||
vals['exception_fn'] = (t or v or tb)
|
vals['exception_fn'] = (t or v or tb)
|
||||||
|
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
||||||
'exception': False, 'exception_fn': False}
|
'exception': False, 'exception_fn': False}
|
||||||
with ReadTransaction(lock, TestContextManager, exit_fn):
|
with lk.ReadTransaction(lock, TestContextManager, exit_fn):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -816,7 +813,7 @@ def exit_fn(t, v, tb):
|
|||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
||||||
'exception': False, 'exception_fn': False}
|
'exception': False, 'exception_fn': False}
|
||||||
with ReadTransaction(lock, TestContextManager):
|
with lk.ReadTransaction(lock, TestContextManager):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -827,7 +824,7 @@ def exit_fn(t, v, tb):
|
|||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
||||||
'exception': False, 'exception_fn': False}
|
'exception': False, 'exception_fn': False}
|
||||||
with WriteTransaction(lock, TestContextManager, exit_fn):
|
with lk.WriteTransaction(lock, TestContextManager, exit_fn):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -838,7 +835,7 @@ def exit_fn(t, v, tb):
|
|||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
||||||
'exception': False, 'exception_fn': False}
|
'exception': False, 'exception_fn': False}
|
||||||
with WriteTransaction(lock, TestContextManager):
|
with lk.WriteTransaction(lock, TestContextManager):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert vals['entered']
|
assert vals['entered']
|
||||||
@ -861,14 +858,14 @@ def exit_fn(t, v, tb):
|
|||||||
vals['exited_fn'] = True
|
vals['exited_fn'] = True
|
||||||
vals['exception_fn'] = (t or v or tb)
|
vals['exception_fn'] = (t or v or tb)
|
||||||
|
|
||||||
lock = Lock(lock_path)
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
def do_read_with_exception(exit_fn):
|
def do_read_with_exception(exit_fn):
|
||||||
with ReadTransaction(lock, TestContextManager, exit_fn):
|
with lk.ReadTransaction(lock, TestContextManager, exit_fn):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
def do_write_with_exception(exit_fn):
|
def do_write_with_exception(exit_fn):
|
||||||
with WriteTransaction(lock, TestContextManager, exit_fn):
|
with lk.WriteTransaction(lock, TestContextManager, exit_fn):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
vals = {'entered': False, 'exited': False, 'exited_fn': False,
|
||||||
@ -910,91 +907,3 @@ def do_write_with_exception(exit_fn):
|
|||||||
assert vals['exception']
|
assert vals['exception']
|
||||||
assert not vals['exited_fn']
|
assert not vals['exited_fn']
|
||||||
assert not vals['exception_fn']
|
assert not vals['exception_fn']
|
||||||
|
|
||||||
|
|
||||||
def test_disable_locking(private_lock_path):
|
|
||||||
"""Ensure that locks do no real locking when disabled."""
|
|
||||||
old_value = spack.config.get('config:locks')
|
|
||||||
|
|
||||||
with spack.config.override('config:locks', False):
|
|
||||||
lock = Lock(private_lock_path)
|
|
||||||
|
|
||||||
lock.acquire_read()
|
|
||||||
assert not os.path.exists(private_lock_path)
|
|
||||||
|
|
||||||
lock.acquire_write()
|
|
||||||
assert not os.path.exists(private_lock_path)
|
|
||||||
|
|
||||||
lock.release_write()
|
|
||||||
assert not os.path.exists(private_lock_path)
|
|
||||||
|
|
||||||
lock.release_read()
|
|
||||||
assert not os.path.exists(private_lock_path)
|
|
||||||
|
|
||||||
assert old_value == spack.config.get('config:locks')
|
|
||||||
|
|
||||||
|
|
||||||
def test_lock_checks_user(tmpdir):
|
|
||||||
"""Ensure lock checks work with a self-owned, self-group repo."""
|
|
||||||
uid = os.getuid()
|
|
||||||
if uid not in group_ids():
|
|
||||||
pytest.skip("user has no group with gid == uid")
|
|
||||||
|
|
||||||
# self-owned, own group
|
|
||||||
tmpdir.chown(uid, uid)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
path = str(tmpdir)
|
|
||||||
tmpdir.chmod(0o744)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
tmpdir.chmod(0o774)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# unsafe
|
|
||||||
tmpdir.chmod(0o777)
|
|
||||||
with pytest.raises(spack.error.SpackError):
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
tmpdir.chmod(0o474)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
tmpdir.chmod(0o477)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
|
|
||||||
def test_lock_checks_group(tmpdir):
|
|
||||||
"""Ensure lock checks work with a self-owned, non-self-group repo."""
|
|
||||||
uid = os.getuid()
|
|
||||||
gid = next((g for g in group_ids() if g != uid), None)
|
|
||||||
if not gid:
|
|
||||||
pytest.skip("user has no group with gid != uid")
|
|
||||||
|
|
||||||
# self-owned, another group
|
|
||||||
tmpdir.chown(uid, gid)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
path = str(tmpdir)
|
|
||||||
tmpdir.chmod(0o744)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# unsafe
|
|
||||||
tmpdir.chmod(0o774)
|
|
||||||
with pytest.raises(spack.error.SpackError):
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# unsafe
|
|
||||||
tmpdir.chmod(0o777)
|
|
||||||
with pytest.raises(spack.error.SpackError):
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
tmpdir.chmod(0o474)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
|
||||||
# safe
|
|
||||||
tmpdir.chmod(0o477)
|
|
||||||
spack.util.lock.check_lock_safety(path)
|
|
||||||
|
123
lib/spack/spack/test/util/spack_lock_wrapper.py
Normal file
123
lib/spack/spack/test/util/spack_lock_wrapper.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/spack/spack
|
||||||
|
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
"""Tests for Spack's wrapper module around llnl.util.lock."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from llnl.util.filesystem import group_ids
|
||||||
|
|
||||||
|
import spack.config
|
||||||
|
import spack.util.lock as lk
|
||||||
|
|
||||||
|
|
||||||
|
def test_disable_locking(tmpdir):
|
||||||
|
"""Ensure that locks do no real locking when disabled."""
|
||||||
|
lock_path = str(tmpdir.join('lockfile'))
|
||||||
|
|
||||||
|
old_value = spack.config.get('config:locks')
|
||||||
|
|
||||||
|
with spack.config.override('config:locks', False):
|
||||||
|
lock = lk.Lock(lock_path)
|
||||||
|
|
||||||
|
lock.acquire_read()
|
||||||
|
assert not os.path.exists(lock_path)
|
||||||
|
|
||||||
|
lock.acquire_write()
|
||||||
|
assert not os.path.exists(lock_path)
|
||||||
|
|
||||||
|
lock.release_write()
|
||||||
|
assert not os.path.exists(lock_path)
|
||||||
|
|
||||||
|
lock.release_read()
|
||||||
|
assert not os.path.exists(lock_path)
|
||||||
|
|
||||||
|
assert old_value == spack.config.get('config:locks')
|
||||||
|
|
||||||
|
|
||||||
|
def test_lock_checks_user(tmpdir):
|
||||||
|
"""Ensure lock checks work with a self-owned, self-group repo."""
|
||||||
|
uid = os.getuid()
|
||||||
|
if uid not in group_ids():
|
||||||
|
pytest.skip("user has no group with gid == uid")
|
||||||
|
|
||||||
|
# self-owned, own group
|
||||||
|
tmpdir.chown(uid, uid)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
path = str(tmpdir)
|
||||||
|
tmpdir.chmod(0o744)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
tmpdir.chmod(0o774)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# unsafe
|
||||||
|
tmpdir.chmod(0o777)
|
||||||
|
with pytest.raises(spack.error.SpackError):
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
tmpdir.chmod(0o474)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
tmpdir.chmod(0o477)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_lock_checks_group(tmpdir):
|
||||||
|
"""Ensure lock checks work with a self-owned, non-self-group repo."""
|
||||||
|
uid = os.getuid()
|
||||||
|
gid = next((g for g in group_ids() if g != uid), None)
|
||||||
|
if not gid:
|
||||||
|
pytest.skip("user has no group with gid != uid")
|
||||||
|
|
||||||
|
# self-owned, another group
|
||||||
|
tmpdir.chown(uid, gid)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
path = str(tmpdir)
|
||||||
|
tmpdir.chmod(0o744)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# unsafe
|
||||||
|
tmpdir.chmod(0o774)
|
||||||
|
with pytest.raises(spack.error.SpackError):
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# unsafe
|
||||||
|
tmpdir.chmod(0o777)
|
||||||
|
with pytest.raises(spack.error.SpackError):
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
tmpdir.chmod(0o474)
|
||||||
|
lk.check_lock_safety(path)
|
||||||
|
|
||||||
|
# safe
|
||||||
|
tmpdir.chmod(0o477)
|
||||||
|
lk.check_lock_safety(path)
|
Loading…
Reference in New Issue
Block a user