From b9cd09a229036b71b20ee378d3805295c611240b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 29 Aug 2024 22:20:43 +0100 Subject: [PATCH 1/5] tox: Stop setting skipsdist This is not compatible with tox 4 and has a different meaning there. Signed-off-by: Stephen Finucane --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 4730fba..940917e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [tox] -minversion = 1.6 +minversion = 3.18.0 envlist = py312,py311,py310,py39,py38,pep8 -skipsdist = True [testenv] usedevelop = True From 9df13d85ec9b3d0d2edbb3180bd6b39676b3c71e Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 29 Aug 2024 22:47:20 +0100 Subject: [PATCH 2/5] tox: Stop setting envdir, VIRTUALENV envvar Different testenv's can't share an envdir in tox 4. In addition, there's no reason to set the VIRTUALENV envvar. Stop doing both. Signed-off-by: Stephen Finucane --- tox.ini | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tox.ini b/tox.ini index 940917e..e24bbc8 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ envlist = py312,py311,py310,py39,py38,pep8 [testenv] usedevelop = True install_command = pip install -U --force-reinstall {opts} {packages} -setenv = VIRTUAL_ENV={envdir} allowlist_externals = find stestr @@ -22,18 +21,14 @@ commands = black --check {posargs} stestr tools doc setup.py [testenv:black] -envdir = .tox/pep8 commands = black {posargs} stestr tools doc setup.py - - [testenv:venv] commands = {posargs} [testenv:cover] setenv = - VIRTUAL_ENV={envdir} PYTHON=coverage run --source stestr commands = coverage run stestr/cli.py run {posargs} @@ -42,7 +37,6 @@ commands = [testenv:coverxml] setenv = - VIRTUAL_ENV={envdir} PYTHON=coverage run --source stestr commands = coverage run stestr/cli.py run {posargs} From 2fc4bcc52d3d93ac3d535bf42000a86b393887ce Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 29 Aug 2024 22:02:37 +0100 Subject: [PATCH 3/5] run: Use OS native path separator Windows users are likely to pass Windows-style paths. Handle this correctly. This highlight a lot of naive use of *nix style paths in tests, but cleaning those up is a job for another day/PR. Signed-off-by: Stephen Finucane --- stestr/commands/run.py | 25 +++++++++++++++++-------- stestr/tests/test_return_codes.py | 24 ++++++++++++++++++------ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/stestr/commands/run.py b/stestr/commands/run.py index 8c02b24..ecac79c 100644 --- a/stestr/commands/run.py +++ b/stestr/commands/run.py @@ -16,6 +16,7 @@ import functools import io import os +import os.path import subprocess import sys @@ -521,11 +522,15 @@ def run_command( if no_discover: ids = no_discover + klass = None if "::" in ids: - ids = ids.replace("::", ".") - if ids.find("/") != -1: - root = ids.replace(".py", "") - ids = root.replace("/", ".") + ids, klass = ids.split("::", 1) + klass = ".".join(klass.split("::")) + if ids.find(os.path.sep) != -1: + root, _ = os.path.splitext(ids) + ids = ".".join(root.split(os.path.sep)) + if klass: + ids = f"{ids}.{klass}" stestr_python = sys.executable if os.environ.get("PYTHON"): python_bin = os.environ.get("PYTHON") @@ -584,11 +589,15 @@ def run_tests(): if pdb: ids = pdb + klass = None if "::" in ids: - ids = ids.replace("::", ".") - if ids.find("/") != -1: - root = ids.replace(".py", "") - ids = root.replace("/", ".") + ids, klass = ids.split("::", 1) + klass = ".".join(klass.split("::")) + if ids.find(os.path.sep) != -1: + root, _ = os.path.splitext(ids) + ids = ".".join(root.split(os.path.sep)) + if klass: + ids = f"{ids}.{klass}" runner = subunit_run.SubunitTestRunner stream = io.BytesIO() program.TestProgram( diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index 99c1e3c..820d8cb 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -471,21 +471,33 @@ def test_list_from_func(self): self.assertEqual(0, list_cmd.list_command(stdout=stdout.stream)) def test_run_no_discover_pytest_path(self): - passing_string = "tests/test_passing.py::FakeTestClass::test_pass_list" + passing_string = "::".join( + [ + os.path.join("tests", "test_passing.py"), + "FakeTestClass", + "test_pass_list", + ] + ) out, err = self.assertRunExit("stestr run -n %s" % passing_string, 0) lines = out.decode("utf8").splitlines() self.assertIn(" - Passed: 1", lines) self.assertIn(" - Failed: 0", lines) def test_run_no_discover_pytest_path_failing(self): - passing_string = "tests/test_failing.py::FakeTestClass::test_pass_list" - out, err = self.assertRunExit("stestr run -n %s" % passing_string, 1) + failing_string = "::".join( + [ + os.path.join("tests", "test_failing.py"), + "FakeTestClass", + "test_pass_list", + ] + ) + out, err = self.assertRunExit("stestr run -n %s" % failing_string, 1) lines = out.decode("utf8").splitlines() self.assertIn(" - Passed: 0", lines) self.assertIn(" - Failed: 1", lines) def test_run_no_discover_file_path(self): - passing_string = "tests/test_passing.py" + passing_string = os.path.join("tests", "test_passing.py") out, err = self.assertRunExit("stestr run -n %s" % passing_string, 0) lines = out.decode("utf8").splitlines() self.assertIn(" - Passed: 2", lines) @@ -493,8 +505,8 @@ def test_run_no_discover_file_path(self): self.assertIn(" - Expected Fail: 1", lines) def test_run_no_discover_file_path_failing(self): - passing_string = "tests/test_failing.py" - out, err = self.assertRunExit("stestr run -n %s" % passing_string, 1) + failing_string = os.path.join("tests", "test_failing.py") + out, err = self.assertRunExit("stestr run -n %s" % failing_string, 1) lines = out.decode("utf8").splitlines() self.assertIn(" - Passed: 0", lines) self.assertIn(" - Failed: 2", lines) From 2180f192bc53afc7da6c9b7283cb9959865151fc Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 28 Aug 2024 11:55:13 +0100 Subject: [PATCH 4/5] run: Normalize paths Fixes #364. Signed-off-by: Stephen Finucane --- stestr/commands/run.py | 4 ++-- stestr/tests/test_return_codes.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/stestr/commands/run.py b/stestr/commands/run.py index ecac79c..2bf4b32 100644 --- a/stestr/commands/run.py +++ b/stestr/commands/run.py @@ -527,7 +527,7 @@ def run_command( ids, klass = ids.split("::", 1) klass = ".".join(klass.split("::")) if ids.find(os.path.sep) != -1: - root, _ = os.path.splitext(ids) + root, _ = os.path.splitext(os.path.normpath(ids)) ids = ".".join(root.split(os.path.sep)) if klass: ids = f"{ids}.{klass}" @@ -594,7 +594,7 @@ def run_tests(): ids, klass = ids.split("::", 1) klass = ".".join(klass.split("::")) if ids.find(os.path.sep) != -1: - root, _ = os.path.splitext(ids) + root, _ = os.path.splitext(os.path.normpath(ids)) ids = ".".join(root.split(os.path.sep)) if klass: ids = f"{ids}.{klass}" diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index 820d8cb..56fd7ed 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -512,6 +512,24 @@ def test_run_no_discover_file_path_failing(self): self.assertIn(" - Failed: 2", lines) self.assertIn(" - Unexpected Success: 1", lines) + def test_run_no_discover_unnormalized_file_path(self): + # we don't use os.path.join since we want an unnormalized path + passing_string = f"tests{os.path.sep}{os.path.sep}test_passing.py" + out, err = self.assertRunExit("stestr run -n %s" % passing_string, 0) + lines = out.decode("utf8").splitlines() + self.assertIn(" - Passed: 2", lines) + self.assertIn(" - Failed: 0", lines) + self.assertIn(" - Expected Fail: 1", lines) + + def test_run_no_discover_unnormalized_file_path_failing(self): + # we don't use os.path.join since we want an unnormalized path + failing_string = f"tests{os.path.sep}{os.path.sep}test_failing.py" + out, err = self.assertRunExit("stestr run -n %s" % failing_string, 1) + lines = out.decode("utf8").splitlines() + self.assertIn(" - Passed: 0", lines) + self.assertIn(" - Failed: 2", lines) + self.assertIn(" - Unexpected Success: 1", lines) + class TestReturnCodesToxIni(TestReturnCodes): def setUp(self): From 901bc62bafd569199b9eba5043282b5e4070c4f3 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 29 Aug 2024 22:37:32 +0100 Subject: [PATCH 5/5] tests: Print command that failed Signed-off-by: Stephen Finucane --- stestr/tests/test_return_codes.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index 56fd7ed..dcd8ce5 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -97,15 +97,17 @@ def assertRunExit(self, cmd, expected, subunit=False, stdin=None): if not subunit: self.assertEqual( - p.returncode, expected, "Stdout: {}; Stderr: {}".format(out, err) + p.returncode, + expected, + "Command: {}; Stdout: {}; Stderr: {}".format(cmd, out, err), ) return (out, err) else: self.assertEqual( p.returncode, expected, - "Expected return code: %s doesn't match actual " - "return code of: %s" % (expected, p.returncode), + "Expected return code: {} doesn't match actual " + "return code of: {}. Command: {}".format(expected, p.returncode, cmd), ) output_stream = io.BytesIO(out) stream = subunit_lib.ByteStreamToStreamResult(output_stream)