Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conda/recipes/cuopt-server/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ tests:
imports:
- cuopt_server
pip_check: false
- package_contents:
files:
- bin/cuopt_grpc_server

about:
homepage: ${{ load_from_file("python/cuopt_server/pyproject.toml").project.urls.Homepage }}
Expand Down
18 changes: 18 additions & 0 deletions python/cuopt_server/cuopt_server/_grpc_server_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import os
import subprocess
import sys


def main():
"""
Wrapper that launches the cuopt_grpc_server binary from the libcuopt package.
"""
import libcuopt

server_path = os.path.join(
os.path.dirname(libcuopt.__file__), "bin", "cuopt_grpc_server"
)
sys.exit(subprocess.call([server_path] + sys.argv[1:]))
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import shutil
import subprocess


def test_cuopt_grpc_server_on_path():
assert shutil.which("cuopt_grpc_server") is not None, (
"cuopt_grpc_server should be on PATH after installing cuopt-server"
)


def test_cuopt_grpc_server_help():
result = subprocess.run(
["cuopt_grpc_server", "--help"],
capture_output=True,
text=True,
timeout=10,
)
assert result.returncode == 0, (
f"cuopt_grpc_server --help failed (rc={result.returncode}): {result.stderr}"
)
assert "cuopt_grpc_server" in result.stdout, (
f"Expected 'cuopt_grpc_server' in --help output, got: {result.stdout}"
)
Comment on lines +14 to +26
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make test_cuopt_grpc_server_help self-contained and stream-agnostic.

On Line 16, invoking the bare command can raise FileNotFoundError when this test runs independently in a misconfigured environment, and Line 24 only inspects stdout even though many CLIs print help to stderr.

Proposed test hardening
 def test_cuopt_grpc_server_help():
+    exe = shutil.which("cuopt_grpc_server")
+    assert exe is not None, "cuopt_grpc_server should be on PATH before help test"
+
     result = subprocess.run(
-        ["cuopt_grpc_server", "--help"],
+        [exe, "--help"],
         capture_output=True,
         text=True,
         timeout=10,
     )
     assert result.returncode == 0, (
         f"cuopt_grpc_server --help failed (rc={result.returncode}): {result.stderr}"
     )
-    assert "cuopt_grpc_server" in result.stdout, (
-        f"Expected 'cuopt_grpc_server' in --help output, got: {result.stdout}"
+    output = f"{result.stdout}\n{result.stderr}"
+    assert "cuopt_grpc_server" in output, (
+        f"Expected 'cuopt_grpc_server' in --help output, got: {output}"
     )

As per coding guidelines, "Ensure test isolation: prevent GPU state, cached memory, and global variables from leaking between test cases; verify each test independently initializes its environment".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py`
around lines 14 - 26, The test_cuopt_grpc_server_help currently calls
subprocess.run on the bare "cuopt_grpc_server" and only checks stdout, which can
raise FileNotFoundError and miss help output printed to stderr; update the test
to first locate the executable with shutil.which("cuopt_grpc_server") and call
pytest.skip if not found, or alternatively invoke the module via sys.executable
-m if an importable entrypoint exists, then call subprocess.run with
stderr=subprocess.STDOUT (or combine stdout/stderr) and a controlled env (e.g.,
env=os.environ.copy() with GPU vars like CUDA_VISIBLE_DEVICES cleared) so the
call is stream-agnostic and environment-isolated, and assert on the combined
output and returncode.

3 changes: 3 additions & 0 deletions python/cuopt_server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ test = [
"requests",
] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.

[project.scripts]
cuopt_grpc_server = "cuopt_server._grpc_server_wrapper:main"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@tmckayus Would we need a test for this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added, and realize I left out the wrapper


[project.urls]
Homepage = "https://docs.nvidia.com/cuopt/introduction.html"
Source = "https://github.com/nvidia/cuopt"
Expand Down
Loading