From 7dbd894c8e365b5065e48d5e9a1d88b615aaaf9b Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Dec 2024 17:47:43 +1000 Subject: [PATCH] Ignore LC_ALL: cannot change locale when testing std output --- python/testing/__init__.py | 23 ++++++++ tests/src/python/test_qgsblockingprocess.py | 27 ++++++---- .../python/test_qgsprocessexecutable_pt1.py | 52 ++++++------------- .../python/test_qgsprocessexecutable_pt2.py | 49 ++++++----------- 4 files changed, 72 insertions(+), 79 deletions(-) diff --git a/python/testing/__init__.py b/python/testing/__init__.py index 33087f26de0..6b47a7d90df 100644 --- a/python/testing/__init__.py +++ b/python/testing/__init__.py @@ -316,6 +316,29 @@ class QgisTestCase(unittest.TestCase): file_path[1:] if file_path.startswith("/") else file_path ) + @staticmethod + def strip_std_ignorable_errors(output: str) -> str: + """ + Strips out ignorable warnings and errors from stdout/stderr output + """ + return "\n".join( + [ + e + for e in output.splitlines() + if e + not in ( + "Problem with GRASS installation: GRASS was not found or is not correctly installed", + "QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700", + "MESA: error: ZINK: failed to choose pdev", + "MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)", + "glx: failed to create drisw screen", + "failed to load driver: zink", + "QML debugging is enabled. Only use this in a safe environment.", + ) + and not "LC_ALL: cannot change locale" in e + ] + ) + def assertLayersEqual(self, layer_expected, layer_result, **kwargs): """ :param layer_expected: The first layer to compare diff --git a/tests/src/python/test_qgsblockingprocess.py b/tests/src/python/test_qgsblockingprocess.py index f08f79e0928..25818090022 100644 --- a/tests/src/python/test_qgsblockingprocess.py +++ b/tests/src/python/test_qgsblockingprocess.py @@ -55,7 +55,7 @@ class TestQgsBlockingProcess(QgisTestCase): self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) self.assertIn("GDAL", std_out.val) - self.assertEqual(std_err.val, "") + self.assertEqual(QgisTestCase.strip_std_ignorable_errors(std_err.val), "") def test_process_err(self): temp_folder = tempfile.mkdtemp() @@ -88,8 +88,12 @@ exit 1""" f = QgsFeedback() self.assertEqual(p.run(f), 1) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertIn("This goes to stdout", std_out.val) - self.assertIn("This goes to stderr", std_err.val) + self.assertIn( + "This goes to stdout", QgisTestCase.strip_std_ignorable_errors(std_out.val) + ) + self.assertIn( + "This goes to stderr", QgisTestCase.strip_std_ignorable_errors(std_err.val) + ) def test_process_crash(self): """ @@ -176,8 +180,8 @@ exit 1""" f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertFalse(std_out.val.strip()) - self.assertFalse(std_err.val.strip()) + self.assertFalse(QgisTestCase.strip_std_ignorable_errors(std_out.val).strip()) + self.assertFalse(QgisTestCase.strip_std_ignorable_errors(std_err.val).strip()) # set environment variable os.environ["my_var"] = "my test variable" @@ -190,8 +194,11 @@ exit 1""" f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertEqual(std_out.val.strip(), "my test variable") - self.assertFalse(std_err.val.strip()) + self.assertEqual( + QgisTestCase.strip_std_ignorable_errors(std_out.val).strip(), + "my test variable", + ) + self.assertFalse(QgisTestCase.strip_std_ignorable_errors(std_err.val).strip()) # test python changing path @@ -212,8 +219,10 @@ exit 1""" f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertEqual(std_out.val.strip(), new_path) - self.assertFalse(std_err.val.strip()) + self.assertEqual( + QgisTestCase.strip_std_ignorable_errors(std_out.val).strip(), new_path + ) + self.assertFalse(QgisTestCase.strip_std_ignorable_errors(std_err.val).strip()) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsprocessexecutable_pt1.py b/tests/src/python/test_qgsprocessexecutable_pt1.py index 364c10bd57a..1d8b830a6d6 100644 --- a/tests/src/python/test_qgsprocessexecutable_pt1.py +++ b/tests/src/python/test_qgsprocessexecutable_pt1.py @@ -19,8 +19,7 @@ import subprocess import sys import tempfile -from qgis.testing import unittest - +from qgis.testing import QgisTestCase, unittest from utilities import unitTestDataPath print("CTEST_FULL_OUTPUT") @@ -28,7 +27,7 @@ print("CTEST_FULL_OUTPUT") TEST_DATA_DIR = unitTestDataPath() -class TestQgsProcessExecutablePt1(unittest.TestCase): +class TestQgsProcessExecutablePt1(QgisTestCase): TMP_DIR = "" @@ -44,25 +43,6 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): super().tearDownClass() shutil.rmtree(cls.TMP_DIR, ignore_errors=True) - @staticmethod - def _strip_ignorable_errors(output: str): - return "\n".join( - [ - e - for e in output.splitlines() - if e - not in ( - "Problem with GRASS installation: GRASS was not found or is not correctly installed", - "QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700", - "MESA: error: ZINK: failed to choose pdev", - "MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)", - "glx: failed to create drisw screen", - "failed to load driver: zink", - "QML debugging is enabled. Only use this in a safe environment.", - ) - ] - ) - def run_process(self, arguments): call = [QGIS_PROCESS_BIN] + arguments print(" ".join(call)) @@ -100,7 +80,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): def testNoArgs(self): rc, output, err = self.run_process([]) self.assertIn("Available commands", output) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testPlugins(self): @@ -109,7 +89,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): self.assertIn("available plugins", output.lower()) self.assertIn("processing", output.lower()) self.assertNotIn("metasearch", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testPluginsSkipLoading(self): @@ -118,7 +98,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): self.assertIn("available plugins", output.lower()) self.assertIn("processing", output.lower()) self.assertNotIn("metasearch", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testPluginStatus(self): @@ -138,12 +118,12 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): rc, output, err = self.run_process(["plugins"]) self.assertIn("available plugins", output.lower()) self.assertIn("* grassprovider", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) # disable rc, output, err = self.run_process(["plugins", "disable", "grassprovider"]) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) # try to re-disable @@ -154,17 +134,17 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): rc, output, err = self.run_process(["plugins"]) self.assertIn("available plugins", output.lower()) self.assertNotIn("* grassprovider", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) rc, output, err = self.run_process(["plugins", "enable", "grassprovider"]) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) rc, output, err = self.run_process(["plugins"]) self.assertIn("available plugins", output.lower()) self.assertIn("* grassprovider", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) if not previously_enabled: @@ -198,7 +178,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): self.assertIn("available algorithms", output.lower()) self.assertIn("native:reprojectlayer", output.lower()) self.assertIn("gdal:translate", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmListNoPython(self): @@ -206,7 +186,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): self.assertIn("available algorithms", output.lower()) self.assertIn("native:reprojectlayer", output.lower()) self.assertNotIn("gdal:translate", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmsListJson(self): @@ -240,7 +220,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): rc, output, err = self.run_process(["help", "--no-python", "native:centroids"]) self.assertIn("representing the centroid", output.lower()) self.assertIn("argument type", output.lower()) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmHelpJson(self): @@ -293,7 +273,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): f"--OUTPUT={output_file}", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) self.assertIn("results", output.lower()) self.assertIn("OUTPUT:\t" + output_file, output) @@ -312,7 +292,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): f"OUTPUT={output_file}", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) self.assertIn("results", output.lower()) self.assertIn("OUTPUT:\t" + output_file, output) @@ -329,7 +309,7 @@ class TestQgsProcessExecutablePt1(unittest.TestCase): rc, output, err = self.run_process_stdin( ["run", "--no-python", "native:centroids", "-"], json.dumps(params) ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) res = json.loads(output) diff --git a/tests/src/python/test_qgsprocessexecutable_pt2.py b/tests/src/python/test_qgsprocessexecutable_pt2.py index ab393bc9875..7a85a1bf0ff 100644 --- a/tests/src/python/test_qgsprocessexecutable_pt2.py +++ b/tests/src/python/test_qgsprocessexecutable_pt2.py @@ -19,7 +19,7 @@ import subprocess import sys import tempfile -from qgis.testing import unittest +from qgis.testing import QgisTestCase, unittest from utilities import unitTestDataPath @@ -28,7 +28,7 @@ print("CTEST_FULL_OUTPUT") TEST_DATA_DIR = unitTestDataPath() -class TestQgsProcessExecutablePt2(unittest.TestCase): +class TestQgsProcessExecutablePt2(QgisTestCase): TMP_DIR = "" @@ -44,25 +44,6 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): super().tearDownClass() shutil.rmtree(cls.TMP_DIR, ignore_errors=True) - @staticmethod - def _strip_ignorable_errors(output: str): - return "\n".join( - [ - e - for e in output.splitlines() - if e - not in ( - "Problem with GRASS installation: GRASS was not found or is not correctly installed", - "QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700", - "MESA: error: ZINK: failed to choose pdev", - "MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)", - "glx: failed to create drisw screen", - "failed to load driver: zink", - "QML debugging is enabled. Only use this in a safe environment.", - ) - ] - ) - def run_process(self, arguments): call = [QGIS_PROCESS_BIN] + arguments print(" ".join(call)) @@ -192,7 +173,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process( ["help", "--no-python", TEST_DATA_DIR + "/test_model.model3"] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) self.assertIn("model description", output.lower()) self.assertIn("author of model", output.lower()) @@ -212,7 +193,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): f"native:centroids_1:CENTROIDS={output_file}", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) self.assertIn("results", output.lower()) @@ -232,7 +213,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): ["run", "--no-python", TEST_DATA_DIR + "/test_model.model3", "-"], json.dumps(params), ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) @@ -258,7 +239,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): f"native:centroids_1:CENTROIDS={output_file}", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) @@ -296,7 +277,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process( ["help", TEST_DATA_DIR + "/convert_to_upper.py"] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) self.assertIn("converts a string to upper case", output.lower()) @@ -304,7 +285,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process( ["run", TEST_DATA_DIR + "/convert_to_upper.py", "--", "INPUT=abc"] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) self.assertIn("Converted abc to ABC", output) self.assertIn("OUTPUT:\tABC", output) @@ -313,7 +294,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process( ["run", TEST_DATA_DIR + "/convert_to_upper.py", "--json", "--", "INPUT=abc"] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) @@ -334,7 +315,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process_stdin( ["run", TEST_DATA_DIR + "/convert_to_upper.py", "-"], json.dumps(params) ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) @@ -385,7 +366,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): "--another% complex# NaMe=def", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertIn("OUTPUT: abc:def", output) self.assertEqual(rc, 0) @@ -400,7 +381,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): f"--CONDITION=layer_property(load_layer('{TEST_DATA_DIR + '/points.shp'}','ogr'),'feature_count')>10", ] ) - self.assertIn("CONFIRMED", self._strip_ignorable_errors(err)) + self.assertIn("CONFIRMED", self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 1) @@ -417,7 +398,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): "--json", ] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) @@ -439,7 +420,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process_stdin( ["run", "native:buffer", "-"], json.dumps(params) ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) @@ -457,7 +438,7 @@ class TestQgsProcessExecutablePt2(unittest.TestCase): rc, output, err = self.run_process( ["run", TEST_DATA_DIR + "/report_style_initialization_status.py"] ) - self.assertFalse(self._strip_ignorable_errors(err)) + self.assertFalse(self.strip_std_ignorable_errors(err)) self.assertEqual(rc, 0) self.assertIn("IS_INITIALIZED: false", output)