Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement django tests with custom runner #22222

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 47 additions & 0 deletions pythonFiles/unittestadapter/django_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import subprocess
import os
import pathlib
import sys
from typing import Union

from pythonFiles.unittestadapter.execution import VSCodeUnittestError

Check failure on line 7 in pythonFiles/unittestadapter/django_runner.py

View workflow job for this annotation

GitHub Actions / Check Python types

Import "pythonFiles.unittestadapter.execution" could not be resolved (reportMissingImports)


def django_execution_runner(start_dir: Union[str, None]):
# Get path to manage.py if set as an env var, otherwise use the default
manage_py_path = os.environ.get("MANAGE_PY_PATH")

if manage_py_path is None:
# Search for default manage.py path at the root of the workspace
if not start_dir:
print(
"Error running Django, no start_dir provided or value for MANAGE_PY_PATH"
)

cwd = os.path.abspath(start_dir)

Check failure on line 21 in pythonFiles/unittestadapter/django_runner.py

View workflow job for this annotation

GitHub Actions / Check Python types

Argument of type "str | None" cannot be assigned to parameter "path" of type "AnyStr@abspath" in function "abspath"   Type "str | None" cannot be assigned to type "AnyStr@abspath" (reportGeneralTypeIssues)
manage_py_path = os.path.join(cwd, "manage.py")

try:
# Get path to the custom_test_runner.py parent folder, add to sys.path.
custom_test_runner_dir = pathlib.Path(__file__).parent
sys.path.insert(0, custom_test_runner_dir)

Check failure on line 27 in pythonFiles/unittestadapter/django_runner.py

View workflow job for this annotation

GitHub Actions / Check Python types

Argument of type "Path" cannot be assigned to parameter "__object" of type "str" in function "insert"   "Path" is incompatible with "str" (reportGeneralTypeIssues)
custom_test_runner = "django_test_runner.CustomTestRunner"

# Build command to run 'python manage.py test'.
python_executable = sys.executable
command = [
python_executable,
"manage.py",
"test",
"--testrunner",
custom_test_runner,
]
print("Running Django run tests with command: ", command)
try:
subprocess.run(" ".join(command), shell=True, check=True)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a space as the join argument? I think I already put one in between the " but ill check

except subprocess.CalledProcessError as e:
print(f"Error running 'manage.py test': {e}")
raise VSCodeUnittestError(f"Error running 'manage.py test': {e}")
except Exception as e:
print(f"Error configuring Django test runner: {e}")
raise VSCodeUnittestError(f"Error configuring Django test runner: {e}")
21 changes: 21 additions & 0 deletions pythonFiles/unittestadapter/django_test_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.test.runner import DiscoverRunner
import sys
import os
import pathlib

script_dir = pathlib.Path(__file__).parent
sys.path.append(os.fspath(script_dir))

from execution import UnittestTestResult


class CustomTestRunner(DiscoverRunner):
def get_test_runner_kwargs(self):
print("get_test_runner_kwargs")
kwargs = super().get_test_runner_kwargs()
if kwargs["resultclass"] is not None:
raise ValueError(
"Resultclass already set, cannot use custom test runner design for VS Code compatibility."
)
kwargs["resultclass"] = UnittestTestResult
return kwargs
88 changes: 55 additions & 33 deletions pythonFiles/unittestadapter/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from testing_tools import process_json_util, socket_manager
from typing_extensions import Literal, NotRequired, TypeAlias, TypedDict
from unittestadapter.utils import parse_unittest_args
from django_runner import django_execution_runner

ErrorType = Union[
Tuple[Type[BaseException], BaseException, TracebackType], Tuple[None, None, None]
Expand All @@ -30,6 +31,13 @@
DEFAULT_PORT = 45454


class VSCodeUnittestError(Exception):
"""A custom exception class for pytest errors."""

def __init__(self, message):
super().__init__(message)


class TestOutcomeEnum(str, enum.Enum):
error = "error"
failure = "failure"
Expand Down Expand Up @@ -103,7 +111,6 @@
subtest: Union[unittest.TestCase, None] = None,
):
tb = None

message = ""
# error is a tuple of the form returned by sys.exc_info(): (type, value, traceback).
if error is not None:
Expand All @@ -128,9 +135,16 @@
"subtest": subtest.id() if subtest else None,
}
self.formatted[test_id] = result
if testPort == 0 or testUuid == 0:
print("Error sending response, port or uuid unknown to python server.")
send_run_data(result, testPort, testUuid)
testPort2 = int(os.environ.get("TEST_PORT", DEFAULT_PORT))
testUuid2 = os.environ.get("TEST_UUID")
if testPort2 == 0 or testUuid2 == 0:
print(
"Error sending response, port or uuid unknown to python server.",
testPort,
testUuid,
)

send_run_data(result, testPort2, testUuid2)


class TestExecutionStatus(str, enum.Enum):
Expand Down Expand Up @@ -303,36 +317,44 @@

testPort = int(os.environ.get("TEST_PORT", DEFAULT_PORT))
testUuid = os.environ.get("TEST_UUID")
if testPort is DEFAULT_PORT:
print(
"Error[vscode-unittest]: TEST_PORT is not set.",
" TEST_UUID = ",
testUuid,
)
if testUuid is None:
print(
"Error[vscode-unittest]: TEST_UUID is not set.",
" TEST_PORT = ",
testPort,
)
testUuid = "unknown"
if test_ids_from_buffer:
# Perform test execution.
payload = run_tests(
start_dir, test_ids_from_buffer, pattern, top_level_dir, testUuid
)
else:
cwd = os.path.abspath(start_dir)
status = TestExecutionStatus.error
try:
if testPort is DEFAULT_PORT:
raise VSCodeUnittestError(
"Error[vscode-unittest]: TEST_PORT is not set.",
" TEST_UUID = ",

Check failure on line 324 in pythonFiles/unittestadapter/execution.py

View workflow job for this annotation

GitHub Actions / Check Python types

Expected 1 positional argument (reportGeneralTypeIssues)
testUuid,
)
if testUuid is None:
raise VSCodeUnittestError(
"Error[vscode-unittest]: TEST_UUID is not set.",
" TEST_PORT = ",

Check failure on line 330 in pythonFiles/unittestadapter/execution.py

View workflow job for this annotation

GitHub Actions / Check Python types

Expected 1 positional argument (reportGeneralTypeIssues)
testPort,
)
if test_ids_from_buffer:
# Perform test execution.

# Check to see if we are running django tests.
django_test_enabled = os.environ.get("DJANGO_TEST_ENABLED")
print("DJANGO_TEST_ENABLED = ", django_test_enabled)
if django_test_enabled and django_test_enabled.lower() == "true":
# run django runner
print("running django runner")
django_execution_runner(start_dir)
else:
print("running unittest runner")
payload = run_tests(
start_dir, test_ids_from_buffer, pattern, top_level_dir, testUuid
)
else:
raise VSCodeUnittestError("No test ids received from buffer")
except Exception as exception:
payload: PayloadDict = {

Check failure on line 351 in pythonFiles/unittestadapter/execution.py

View workflow job for this annotation

GitHub Actions / Check Python types

Expression of type "dict[str, str | TestExecutionStatus | Exception | None]" cannot be assigned to declared type "PayloadDict"   Type "str | None" cannot be assigned to type "str"     Type "None" cannot be assigned to type "str"   "Exception" is incompatible with "str" (reportGeneralTypeIssues)
"cwd": cwd,
"status": status,
"error": "No test ids received from buffer",
"cwd": os.path.abspath(start_dir) if start_dir else None,
"status": TestExecutionStatus.error,
"error": exception,
"result": None,
}
post_response(payload, testPort, "unknown")

eot_payload: EOTPayloadDict = {"command_type": "execution", "eot": True}
if testUuid is None:
print("Error sending response, uuid unknown to python server.")
post_response(eot_payload, testPort, "unknown")
else:
post_response(eot_payload, testPort, testUuid)
post_response(eot_payload, testPort, testUuid)

Check failure on line 360 in pythonFiles/unittestadapter/execution.py

View workflow job for this annotation

GitHub Actions / Check Python types

Argument of type "str | None" cannot be assigned to parameter "uuid" of type "str" in function "post_response"   Type "str | None" cannot be assigned to type "str"     Type "None" cannot be assigned to type "str" (reportGeneralTypeIssues)
12 changes: 11 additions & 1 deletion src/client/testing/testController/common/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,24 @@ export class PythonTestServer implements ITestServer, Disposable {
mutableEnv.TEST_PORT = this.getPort().toString();
mutableEnv.RUN_TEST_IDS_PORT = runTestIdPort;

const isRun = runTestIdPort !== undefined;

// NEEDS TO BE UNCOMMENTED TO GET DJANGO WORKING
// if (isRun) {
// mutableEnv.DJANGO_TEST_ENABLED = 'true';
// mutableEnv.MANAGE_PY_PATH = [options.cwd, 'manage.py'].join('/');
// console.log('DJANGO_TEST_ENABLED', mutableEnv.DJANGO_TEST_ENABLED);
// console.log('MANAGE_PY_PATH', mutableEnv.MANAGE_PY_PATH);
// }

const spawnOptions: SpawnOptions = {
token: options.token,
cwd: options.cwd,
throwOnStdErr: true,
outputChannel: options.outChannel,
env: mutableEnv,
};
const isRun = runTestIdPort !== undefined;

// Create the Python environment in which to execute the command.
const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = {
allowEnvironmentFetchExceptions: false,
Expand Down