From a0a6cfbf1faa45326c4c0f9678705b434da2a262 Mon Sep 17 00:00:00 2001 From: Adam Yoblick Date: Tue, 16 Jul 2024 18:36:13 -0500 Subject: [PATCH] Add tests for environment switches --- CONTRIBUTING.md | 2 +- src/debugpy/server/cli.py | 17 ++++++++++++----- tests/debugpy/server/test_cli.py | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6418e95d..b0121d12 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,7 @@ The tests are run concurrently, and the default number of workers is 8. You can ### Running tests without tox -While tox is the recommended way to run the test suite, pytest can also be invoked directly from the root of the repository. This requires packages in tests/test_requirements.txt to be installed first. +While tox is the recommended way to run the test suite, pytest can also be invoked directly from the root of the repository. This requires packages in tests/requirements.txt to be installed first. ## Using modified debugpy in Visual Studio Code To test integration between debugpy and Visual Studio Code, the latter can be directed to use a custom version of debugpy in lieu of the one bundled with the Python extension. This is done by specifying `"debugAdapterPath"` in `launch.json` - it must point at the root directory of the *package*, which is `src/debugpy` inside the repository: diff --git a/src/debugpy/server/cli.py b/src/debugpy/server/cli.py index a061aba1..098b84a1 100644 --- a/src/debugpy/server/cli.py +++ b/src/debugpy/server/cli.py @@ -192,9 +192,9 @@ switches = [ # Consume all the args from a given list def consume_args(args: list): - while len(args) >= 2: - value = args[1] - del args[1] + while len(args) >= 1: + value = args[0] + del args[0] yield value # Parse the args from the command line, then from the environment. @@ -207,6 +207,9 @@ def parse_args(): parse_args_from_command_line(seen) parse_args_from_environment(seen) + #print("options:", file=sys.stderr) + #print(options.__dict__, file=sys.stderr) + if options.target is None: raise ValueError("missing target: " + TARGET) @@ -222,14 +225,18 @@ def parse_args(): assert options.address is not None def parse_args_from_command_line(seen: set): - parse_args_helper(sys.argv, seen) + parse_args_helper(sys.argv[1:], seen) def parse_args_from_environment(seenFromCommandLine: set): - args = os.getenv("DEBUGPY_EXTRA_ARGV") + args = os.environ.get("DEBUGPY_EXTRA_ARGV") if (not args): return argsList = args.split() + + #print("args:", file=sys.stderr) + #print(*argsList, file=sys.stderr) + seenFromEnvironment = set() parse_args_helper(argsList, seenFromCommandLine, seenFromEnvironment, True) diff --git a/tests/debugpy/server/test_cli.py b/tests/debugpy/server/test_cli.py index a095af42..fd50e847 100644 --- a/tests/debugpy/server/test_cli.py +++ b/tests/debugpy/server/test_cli.py @@ -2,11 +2,13 @@ # Licensed under the MIT License. See LICENSE in the project root # for license information. +import os import pickle import pytest import subprocess import sys +from unittest import mock from debugpy.common import log from tests.patterns import some @@ -43,14 +45,19 @@ def cli(pyfile): "wait_for_client", ] } + + # Serialize the command line args and the options to stdout os.write(1, pickle.dumps([sys.argv[1:], options])) def parse(args): log.debug("Parsing argv: {0!r}", args) try: + # Run the CLI parser in a subprocess, and capture its output. output = subprocess.check_output( [sys.executable, "-u", cli_parser.strpath] + args ) + + # Deserialize the output and return the parsed argv and options. argv, options = pickle.loads(output) except subprocess.CalledProcessError as exc: raise pickle.loads(exc.output) @@ -116,7 +123,6 @@ def test_targets(cli, target_kind, mode, address, wait_for_client, script_args): script_args = [] argv, options = cli(args) - assert argv == script_args assert options == some.dict.containing(expected_options) @@ -165,4 +171,26 @@ def test_duplicate_switch(cli): with pytest.raises(ValueError) as ex: cli(["--listen", "8888", "--listen", "9999", "spam.py"]) - assert "duplicate switch on command line: --listen" in str(ex.value) \ No newline at end of file + assert "duplicate switch on command line: --listen" in str(ex.value) + +# Test that switches can be read from the environment +@mock.patch.dict(os.environ, {"DEBUGPY_EXTRA_ARGV": "--connect 5678"}) +def test_read_switches_from_environment(cli): + args = ["spam.py"] + + _, options = cli(args) + + assert options["mode"] == "connect" + assert options["address"] == ("127.0.0.1", 5678) + assert options["target"] == "spam.py" + +# Test that command line switches override environment variables +@mock.patch.dict(os.environ, {"DEBUGPY_EXTRA_ARGV": "--connect 5678"}) +def test_override_environment_switch(cli): + args = ["--connect", "8888", "spam.py"] + + _, options = cli(args) + + assert options["mode"] == "connect" + assert options["address"] == ("127.0.0.1", 8888) + assert options["target"] == "spam.py" \ No newline at end of file