summaryrefslogtreecommitdiffstats
path: root/SCons
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2024-10-06 17:34:37 (GMT)
committerMats Wichmann <mats@linux.com>2024-10-19 14:25:14 (GMT)
commit80ff4c7530e9b01afa896423fa025f15fe91cb4a (patch)
tree756fc950159ca568bf1691343e8dae4a2ebad0bd /SCons
parentcc8ea0f91830a0a4d1ae5582343df58cc1bb126b (diff)
downloadSCons-80ff4c7530e9b01afa896423fa025f15fe91cb4a.zip
SCons-80ff4c7530e9b01afa896423fa025f15fe91cb4a.tar.gz
SCons-80ff4c7530e9b01afa896423fa025f15fe91cb4a.tar.bz2
Adjust tests in case running as root
Although validation tests are not normally run as root, there may be cicrumstances when it happens - one known case is when the test suite is run as part of a particular Linux distros package construction. It isn't too hard to avoid the few places where we counted on something failing because of permissions, which don't if the user is root - added a few skips. Signed-off-by: Mats Wichmann <mats@linux.com>
Diffstat (limited to 'SCons')
-rw-r--r--SCons/CacheDirTests.py41
-rw-r--r--SCons/Node/FSTests.py40
-rw-r--r--SCons/Variables/PathVariableTests.py32
3 files changed, 83 insertions, 30 deletions
diff --git a/SCons/CacheDirTests.py b/SCons/CacheDirTests.py
index 6ec9e84..e904788 100644
--- a/SCons/CacheDirTests.py
+++ b/SCons/CacheDirTests.py
@@ -34,6 +34,13 @@ import SCons.CacheDir
built_it = None
+IS_WINDOWS = sys.platform == 'win32'
+try:
+ IS_ROOT = os.geteuid() == 0
+except AttributeError:
+ IS_ROOT = False
+
+
class Action:
def __call__(self, targets, sources, env, **kw) -> int:
global built_it
@@ -85,7 +92,6 @@ class BaseTestCase(unittest.TestCase):
def tearDown(self) -> None:
os.remove(os.path.join(self._CacheDir.path, 'config'))
os.rmdir(self._CacheDir.path)
- # Should that be shutil.rmtree?
class CacheDirTestCase(BaseTestCase):
"""
@@ -124,20 +130,29 @@ class ExceptionTestCase(unittest.TestCase):
def tearDown(self) -> None:
shutil.rmtree(self.tmpdir)
- @unittest.skipIf(sys.platform.startswith("win"), "This fixture will not trigger an OSError on Windows")
+ @unittest.skipIf(
+ IS_WINDOWS,
+ "Skip privileged CacheDir test on Windows, cannot change directory rights",
+ )
+ @unittest.skipIf(
+ IS_ROOT,
+ "Skip privileged CacheDir test if running as root.",
+ )
def test_throws_correct_on_OSError(self) -> None:
- """Test that the correct error is thrown when cache directory cannot be created."""
+ """Test for correct error when cache directory cannot be created."""
+ test = TestCmd()
privileged_dir = os.path.join(self.tmpdir, "privileged")
- try:
- os.mkdir(privileged_dir)
- os.chmod(privileged_dir, stat.S_IREAD)
- cd = SCons.CacheDir.CacheDir(os.path.join(privileged_dir, "cache"))
- assert False, "Should have raised exception and did not"
- except SCons.Errors.SConsEnvironmentError as e:
- assert str(e) == "Failed to create cache directory {}".format(os.path.join(privileged_dir, "cache"))
- finally:
- os.chmod(privileged_dir, stat.S_IWRITE | stat.S_IEXEC | stat.S_IREAD)
- shutil.rmtree(privileged_dir)
+ cachedir_path = os.path.join(privileged_dir, "cache")
+ os.makedirs(privileged_dir, exist_ok=True)
+ test.writable(privileged_dir, False)
+ with self.assertRaises(SCons.Errors.SConsEnvironmentError) as cm:
+ cd = SCons.CacheDir.CacheDir(cachedir_path)
+ self.assertEqual(
+ str(cm.exception),
+ "Failed to create cache directory " + cachedir_path
+ )
+ test.writable(privileged_dir, True)
+ shutil.rmtree(privileged_dir)
def test_throws_correct_when_failed_to_write_configfile(self) -> None:
diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py
index 2036f92..0f20cd8 100644
--- a/SCons/Node/FSTests.py
+++ b/SCons/Node/FSTests.py
@@ -44,6 +44,11 @@ built_it = None
scanner_count = 0
+try:
+ IS_ROOT = os.geteuid() == 0
+except AttributeError:
+ IS_ROOT = False
+
class Scanner:
def __init__(self, node=None) -> None:
@@ -958,6 +963,8 @@ class FSTestCase(_tempdirTestCase):
This test case handles all of the file system node
tests in one environment, so we don't have to set up a
complicated directory structure for each test individually.
+ This isn't ideal: normally you want to separate tests a bit
+ more to make it easier to debug and not fail too fast.
"""
test = self.test
@@ -1550,27 +1557,30 @@ class FSTestCase(_tempdirTestCase):
assert r, r
assert not os.path.islink(symlink), "symlink was not removed"
- test.write('can_not_remove', "can_not_remove\n")
- test.writable(test.workpath('.'), 0)
- fp = open(test.workpath('can_not_remove'))
-
- f = fs.File('can_not_remove')
- exc_caught = 0
- try:
- r = f.remove()
- except OSError:
- exc_caught = 1
-
- fp.close()
-
- assert exc_caught, "Should have caught an OSError, r = " + str(r)
-
f = fs.Entry('foo/bar/baz')
assert f.for_signature() == 'baz', f.for_signature()
assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
f.get_string(0)
assert f.get_string(1) == 'baz', f.get_string(1)
+
+ @unittest.skipIf(IS_ROOT, "Skip file removal in protected dir if running as root.")
+ def test_remove_fail(self) -> None:
+ """Test failure when removing a file where permissions don't allow.
+
+ Split from :math:`test_runTest` to be able to skip on root.
+ We want to be able to skip only this one testcase and run the rest.
+ """
+ test = self.test
+ fs = SCons.Node.FS.FS()
+ test.write('can_not_remove', "can_not_remove\n")
+ test.writable(test.workpath('.'), False)
+ with open(test.workpath('can_not_remove')):
+ f = fs.File('can_not_remove')
+ with self.assertRaises(OSError, msg="Should have caught an OSError"):
+ r = f.remove()
+
+
def test_drive_letters(self) -> None:
"""Test drive-letter look-ups"""
diff --git a/SCons/Variables/PathVariableTests.py b/SCons/Variables/PathVariableTests.py
index 7fa8da1..87d6bdf 100644
--- a/SCons/Variables/PathVariableTests.py
+++ b/SCons/Variables/PathVariableTests.py
@@ -30,6 +30,12 @@ import SCons.Variables
import TestCmd
from TestCmd import IS_WINDOWS
+try:
+ IS_ROOT = os.geteuid() == 0
+except AttributeError:
+ IS_ROOT = False
+
+
class PathVariableTestCase(unittest.TestCase):
def test_PathVariable(self) -> None:
"""Test PathVariable creation"""
@@ -93,7 +99,7 @@ class PathVariableTestCase(unittest.TestCase):
self.assertEqual(str(e), f"Directory path for variable 'X' does not exist: {dne}")
def test_PathIsDirCreate(self):
- """Test the PathIsDirCreate validator"""
+ """Test the PathIsDirCreate validator."""
opts = SCons.Variables.Variables()
opts.Add(SCons.Variables.PathVariable('test',
'test build variable help',
@@ -115,6 +121,27 @@ class PathVariableTestCase(unittest.TestCase):
e = cm.exception
self.assertEqual(str(e), f"Path for variable 'X' is a file, not a directory: {f}")
+
+ @unittest.skipIf(IS_ROOT, "Skip creating bad directory if running as root.")
+ def test_PathIsDirCreate_bad_dir(self):
+ """Test the PathIsDirCreate validator with an uncreatable dir.
+
+ Split from :meth:`test_PathIsDirCreate` to be able to skip on root.
+ We want to be able to skip only this one testcase and run the rest.
+ """
+ opts = SCons.Variables.Variables()
+ opts.Add(
+ SCons.Variables.PathVariable(
+ 'test',
+ 'test build variable help',
+ '/default/path',
+ SCons.Variables.PathVariable.PathIsDirCreate,
+ )
+ )
+
+ test = TestCmd.TestCmd(workdir='')
+ o = opts.options[0]
+
# pick a directory path that can't be mkdir'd
if IS_WINDOWS:
f = r'\\noserver\noshare\yyy\zzz'
@@ -125,8 +152,9 @@ class PathVariableTestCase(unittest.TestCase):
e = cm.exception
self.assertEqual(str(e), f"Path for variable 'X' could not be created: {f}")
+
def test_PathIsFile(self):
- """Test the PathIsFile validator"""
+ """Test the PathIsFile validator."""
opts = SCons.Variables.Variables()
opts.Add(SCons.Variables.PathVariable('test',
'test build variable help',