chore: import upstream snapshot with attribution
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:03:19 +08:00
commit 91e75e620b
3227 changed files with 1307078 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
"""Pytest configuration and shared fixtures for computer package tests.
This file contains shared fixtures and configuration for all computer tests.
Following SRP: This file ONLY handles test setup/teardown.
"""
from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
@pytest.fixture
def mock_interface():
"""Mock computer interface for testing.
Use this fixture to test Computer logic without real OS calls.
"""
interface = AsyncMock()
interface.screenshot = AsyncMock(return_value=b"fake_screenshot")
interface.left_click = AsyncMock()
interface.right_click = AsyncMock()
interface.middle_click = AsyncMock()
interface.double_click = AsyncMock()
interface.type = AsyncMock()
interface.key = AsyncMock()
interface.move_mouse = AsyncMock()
interface.scroll = AsyncMock()
interface.get_screen_size = AsyncMock(return_value=(1920, 1080))
return interface
@pytest.fixture
def mock_cloud_provider():
"""Mock cloud provider for testing.
Use this fixture to test cloud provider logic without real API calls.
"""
provider = AsyncMock()
provider.start = AsyncMock()
provider.stop = AsyncMock()
provider.get_status = AsyncMock(return_value="running")
provider.execute_command = AsyncMock(return_value="command output")
return provider
@pytest.fixture
def mock_local_provider():
"""Mock local provider for testing.
Use this fixture to test local provider logic without real VM operations.
"""
provider = AsyncMock()
provider.start = AsyncMock()
provider.stop = AsyncMock()
provider.get_status = AsyncMock(return_value="running")
provider.execute_command = AsyncMock(return_value="command output")
return provider
@pytest.fixture
def disable_telemetry(monkeypatch):
"""Disable telemetry for tests.
Use this fixture to ensure no telemetry is sent during tests.
"""
monkeypatch.setenv("CUA_TELEMETRY_ENABLED", "false")
@@ -0,0 +1,67 @@
"""Unit tests for Computer class.
This file tests ONLY the Computer class initialization and context manager.
Following SRP: This file tests ONE class (Computer).
All external dependencies (providers, interfaces) are mocked.
"""
from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
class TestComputerImport:
"""Test Computer module imports (SRP: Only tests imports)."""
def test_computer_class_exists(self):
"""Test that Computer class can be imported."""
from computer import Computer
assert Computer is not None
def test_vm_provider_type_exists(self):
"""Test that VMProviderType enum can be imported."""
from computer import VMProviderType
assert VMProviderType is not None
class TestComputerInitialization:
"""Test Computer initialization (SRP: Only tests initialization)."""
def test_computer_class_can_be_imported(self, disable_telemetry):
"""Test that Computer class can be imported without errors."""
from computer import Computer
assert Computer is not None
def test_computer_has_required_methods(self, disable_telemetry):
"""Test that Computer class has required methods."""
from computer import Computer
assert hasattr(Computer, "__aenter__")
assert hasattr(Computer, "__aexit__")
class TestComputerContextManager:
"""Test Computer context manager protocol (SRP: Only tests context manager)."""
def test_computer_is_async_context_manager(self, disable_telemetry):
"""Test that Computer has async context manager methods."""
from computer import Computer
assert hasattr(Computer, "__aenter__")
assert hasattr(Computer, "__aexit__")
assert callable(Computer.__aenter__)
assert callable(Computer.__aexit__)
class TestComputerInterface:
"""Test Computer.interface property (SRP: Only tests interface access)."""
def test_computer_class_structure(self, disable_telemetry):
"""Test that Computer class has expected structure."""
from computer import Computer
# Verify Computer is a class
assert isinstance(Computer, type)
+478
View File
@@ -0,0 +1,478 @@
from computer.helpers import generate_source_code
class TestSimpleCases:
"""Test simple dependency cases"""
def test_simple_function_no_dependencies(self):
"""Test simple function with no dependencies"""
def simple_func():
return 42
code = generate_source_code(simple_func)
assert "def simple_func():" in code
assert "return 42" in code
def test_function_with_parameters(self):
"""Test function with parameters"""
def add(a, b):
return a + b
code = generate_source_code(add)
assert "def add(a, b):" in code
assert "return a + b" in code
def test_function_with_docstring(self):
"""Test function with docstring"""
def documented():
"""This is a docstring"""
return True
code = generate_source_code(documented)
assert "def documented():" in code
assert "This is a docstring" in code
class TestImports:
"""Test import handling"""
def test_stdlib_import_inside_function(self):
"""Test function with stdlib import inside"""
def with_stdlib():
import math
return math.sqrt(16)
code = generate_source_code(with_stdlib)
assert "import math" in code
assert "def with_stdlib():" in code
assert "math.sqrt(16)" in code
def test_multiple_stdlib_imports(self):
"""Test function with multiple stdlib imports"""
def with_multiple():
import json
import math
return json.dumps({"value": math.pi})
code = generate_source_code(with_multiple)
assert "import json" in code
assert "import math" in code
def test_from_import_stdlib(self):
"""Test from X import Y style"""
def with_from_import():
from math import pi, sqrt
return sqrt(16) + pi
code = generate_source_code(with_from_import)
assert "from math import" in code
assert "sqrt, pi" in code or ("sqrt" in code and "pi" in code)
def test_third_party_global_import(self):
"""Test globally imported third-party module"""
from requests import get
def with_requests():
return get
code = generate_source_code(with_requests)
assert "from requests import get" in code
assert "def with_requests():" in code
class TestHelperFunctions:
"""Test helper function dependencies"""
def test_single_helper_function(self):
"""Test function with one helper"""
def helper(x):
return x * 2
def main():
return helper(21)
code = generate_source_code(main)
assert "def helper(x):" in code
assert "return x * 2" in code
assert "def main():" in code
assert "return helper(21)" in code
def test_nested_helper_functions(self):
"""Test function with nested helpers"""
def helper_a(x):
return x + 1
def helper_b(x):
return helper_a(x) * 2
def main():
return helper_b(10)
code = generate_source_code(main)
assert "def helper_a(x):" in code
assert "def helper_b(x):" in code
assert "def main():" in code
def test_helper_dependency_ordering(self):
"""Test that helpers are ordered correctly (dependencies first)"""
def level_3(x):
return x + 1
def level_2(x):
return level_3(x) * 2
def level_1(x):
return level_2(x) + 5
code = generate_source_code(level_1)
# Check ordering
pos_3 = code.find("def level_3")
pos_2 = code.find("def level_2")
pos_1 = code.find("def level_1")
assert pos_3 < pos_2 < pos_1, "Functions not in correct dependency order"
def test_helper_with_import(self):
"""Test helper function that uses imports"""
import math
def helper(x):
return math.sqrt(x)
def main():
return helper(16)
code = generate_source_code(main)
assert "import math" in code
assert "def helper(x):" in code
assert "def main():" in code
class TestGlobalConstants:
"""Test global constant handling"""
def test_simple_constant(self):
"""Test function using simple constant"""
MY_CONSTANT = 42
def with_constant():
return MY_CONSTANT * 2
code = generate_source_code(with_constant)
assert "MY_CONSTANT = 42" in code
assert "def with_constant():" in code
def test_string_constant(self):
"""Test function using string constant"""
API_URL = "https://api.example.com"
def with_string():
return API_URL
code = generate_source_code(with_string)
assert "API_URL" in code
assert "https://api.example.com" in code
def test_multiple_constants(self):
"""Test function using multiple constants"""
BASE_URL = "https://example.com"
TIMEOUT = 30
def with_multiple():
return f"{BASE_URL}?timeout={TIMEOUT}"
code = generate_source_code(with_multiple)
assert "BASE_URL" in code
assert "TIMEOUT" in code
class TestClassDefinitions:
"""Test class definition handling"""
def test_simple_class(self):
"""Test function using simple class"""
class Calculator:
def __init__(self, value):
self.value = value
def add(self, x):
return self.value + x
def with_class():
calc = Calculator(10)
return calc.add(5)
code = generate_source_code(with_class)
assert "class Calculator:" in code
assert "__init__" in code
assert "def add" in code
assert "def with_class():" in code
def test_class_with_methods(self):
"""Test class with multiple methods"""
class Math:
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
def use_math():
m = Math()
return m.add(2, 3) + m.multiply(4, 5)
code = generate_source_code(use_math)
assert "class Math:" in code
assert "def add" in code
assert "def multiply" in code
class TestDecoratorRemoval:
"""Test decorator removal"""
def test_simple_decorator_removed(self):
"""Test that decorators are removed"""
def my_decorator(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
@my_decorator
def decorated():
return 42
code = generate_source_code(decorated)
assert "@my_decorator" not in code
assert "def decorated():" in code
assert "return 42" in code
def test_multiple_decorators_removed(self):
"""Test that multiple decorators are removed"""
def decorator1(f):
return f
def decorator2(f):
return f
@decorator1
@decorator2
def multi_decorated():
return True
code = generate_source_code(multi_decorated)
assert "@decorator1" not in code
assert "@decorator2" not in code
assert "def multi_decorated():" in code
class TestComplexScenarios:
"""Test complex real-world scenarios"""
def test_api_client_pattern(self):
"""Test typical API client pattern"""
import json
BASE_URL = "https://api.example.com"
def make_request(endpoint):
return f"{BASE_URL}/{endpoint}"
def parse_response(response):
return json.loads(response)
def get_user(user_id):
url = make_request(f"users/{user_id}")
response = f'{{"id": {user_id}}}'
return parse_response(response)
code = generate_source_code(get_user)
assert "import json" in code
assert "BASE_URL" in code
assert "def make_request" in code
assert "def parse_response" in code
assert "def get_user" in code
def test_data_processing_pipeline(self):
"""Test data processing pipeline"""
def validate_data(data):
return [x for x in data if x > 0]
def transform_data(data):
return [x * 2 for x in data]
def process_pipeline(raw_data):
valid = validate_data(raw_data)
return transform_data(valid)
code = generate_source_code(process_pipeline)
assert "def validate_data" in code
assert "def transform_data" in code
assert "def process_pipeline" in code
# Check ordering
validate_pos = code.find("def validate_data")
transform_pos = code.find("def transform_data")
pipeline_pos = code.find("def process_pipeline")
assert validate_pos < pipeline_pos
assert transform_pos < pipeline_pos
class TestEdgeCases:
"""Test edge cases"""
def test_function_with_default_args(self):
"""Test function with default arguments"""
def with_defaults(a, b=10, c=20):
return a + b + c
code = generate_source_code(with_defaults)
assert "def with_defaults(a, b=10, c=20):" in code
def test_function_with_kwargs(self):
"""Test function with *args and **kwargs"""
def with_varargs(*args, **kwargs):
return sum(args)
code = generate_source_code(with_varargs)
assert "def with_varargs(*args, **kwargs):" in code
def test_async_function(self):
"""Test async function"""
async def async_func():
return 42
code = generate_source_code(async_func)
assert "async def async_func():" in code
assert "return 42" in code
def test_lambda_works_in_files(self):
"""Test that lambda functions work when defined in files"""
lambda_func = lambda x: x * 2
# Lambda functions defined in files CAN have their source extracted
code = generate_source_code(lambda_func)
# Should include the lambda
assert "lambda" in code.lower() or "lambda_func" in code
class TestCaching:
"""Test caching mechanism"""
def test_cache_returns_same_result(self):
"""Test that cache returns identical results"""
def cached_func():
return 42
code1 = generate_source_code(cached_func)
code2 = generate_source_code(cached_func)
assert code1 == code2
def test_different_functions_different_cache(self):
"""Test that different functions have different cache entries"""
def func1():
return 1
def func2():
return 2
code1 = generate_source_code(func1)
code2 = generate_source_code(func2)
assert code1 != code2
assert "return 1" in code1
assert "return 2" in code2
class TestBuiltinHandling:
"""Test that builtins are handled correctly"""
def test_builtin_not_included(self):
"""Test that builtin functions are not included as dependencies"""
def uses_builtins():
data = list(range(10))
return len(data)
code = generate_source_code(uses_builtins)
# Should not include definitions for list, range, len
assert "def list" not in code
assert "def range" not in code
assert "def len" not in code
assert "def uses_builtins():" in code
class TestImportStylePreservation:
"""Test that import styles are preserved"""
def test_from_import_preserved(self):
"""Test from X import Y is preserved"""
from math import sqrt
def use_sqrt():
return sqrt(16)
code = generate_source_code(use_sqrt)
assert "from math import sqrt" in code
def test_import_as_preserved(self):
"""Test import X as Y is preserved"""
import json as j
def use_json():
return j.dumps({"key": "value"})
code = generate_source_code(use_json)
# The import style should be preserved
assert "import json" in code
@@ -0,0 +1,124 @@
"""Unit tests for direct-proxy support in the computer interface.
These tests verify that passing an explicit ``api_base_url`` (plus arbitrary
``api_headers``) makes the interface derive its REST/WebSocket/Playwright URLs
from that base URL -- preserving scheme, host, port and path prefix -- and sends
the extra headers. This is what allows connecting directly to a computer-server
behind an authenticated, path-prefixed reverse proxy (e.g. cyclops-cs) without a
localhost forwarder.
Following SRP: This file tests ONLY URL building and header propagation for the
interface layer.
"""
import pytest
from computer.interface.factory import InterfaceFactory
from computer.interface.windows import WindowsComputerInterface
PROXY_BASE = "https://run.cua.ai/api/svc/ns/sb-api"
class TestApiBaseUrlBuilding:
"""api_base_url should fully drive REST/WS/Playwright URLs."""
def test_rest_uri_uses_base_url(self):
iface = WindowsComputerInterface(
"ignored-ip", api_base_url=PROXY_BASE, api_headers={"Authorization": "Bearer t"}
)
assert iface.rest_uri == f"{PROXY_BASE}/cmd"
def test_ws_uri_swaps_scheme_and_keeps_prefix(self):
iface = WindowsComputerInterface("ignored-ip", api_base_url=PROXY_BASE)
assert iface.ws_uri == "wss://run.cua.ai/api/svc/ns/sb-api/ws"
def test_trailing_slash_is_stripped(self):
iface = WindowsComputerInterface("ignored-ip", api_base_url=PROXY_BASE + "/")
assert iface.rest_uri == f"{PROXY_BASE}/cmd"
assert iface.ws_uri == "wss://run.cua.ai/api/svc/ns/sb-api/ws"
def test_http_base_maps_to_ws(self):
iface = WindowsComputerInterface("ignored-ip", api_base_url="http://localhost:9999/prefix")
assert iface.rest_uri == "http://localhost:9999/prefix/cmd"
assert iface.ws_uri == "ws://localhost:9999/prefix/ws"
def test_api_headers_stored(self):
headers = {"Authorization": "Bearer secret"}
iface = WindowsComputerInterface("ignored-ip", api_base_url=PROXY_BASE, api_headers=headers)
assert iface._api_headers == headers
def test_factory_threads_params(self):
iface = InterfaceFactory.create_interface_for_os(
os="windows",
ip_address="ignored-ip",
api_base_url=PROXY_BASE,
api_headers={"Authorization": "Bearer t"},
)
assert iface.rest_uri == f"{PROXY_BASE}/cmd"
assert iface.ws_uri == "wss://run.cua.ai/api/svc/ns/sb-api/ws"
assert iface._api_headers == {"Authorization": "Bearer t"}
class TestBackwardCompatibility:
"""Without api_base_url, behavior is unchanged (ip_address + port)."""
def test_no_base_url_local(self):
iface = WindowsComputerInterface("192.168.1.5")
assert iface.rest_uri == "http://192.168.1.5:8000/cmd"
assert iface.ws_uri == "ws://192.168.1.5:8000/ws"
assert iface._api_headers == {}
def test_no_base_url_with_api_key(self):
iface = WindowsComputerInterface("192.168.1.5", api_key="abc", vm_name="vm")
assert iface.rest_uri == "https://192.168.1.5:8443/cmd"
assert iface.ws_uri == "wss://192.168.1.5:8443/ws"
def test_no_base_url_custom_port(self):
iface = WindowsComputerInterface("192.168.1.5", api_port=1234)
assert iface.rest_uri == "http://192.168.1.5:1234/cmd"
assert iface.ws_uri == "ws://192.168.1.5:1234/ws"
class TestRestHeaderMerging:
"""api_headers must be merged into REST requests."""
@pytest.mark.asyncio
async def test_send_command_rest_sends_headers(self, monkeypatch):
captured = {}
class FakeResp:
status = 200
async def __aenter__(self):
return self
async def __aexit__(self, *a):
return False
async def text(self):
return 'data: {"success": true}'
class FakeSession:
async def __aenter__(self):
return self
async def __aexit__(self, *a):
return False
def post(self, url, json=None, headers=None):
captured["url"] = url
captured["headers"] = headers
return FakeResp()
import aiohttp
monkeypatch.setattr(aiohttp, "ClientSession", lambda *a, **k: FakeSession())
iface = WindowsComputerInterface(
"ignored-ip",
api_base_url=PROXY_BASE,
api_headers={"Authorization": "Bearer secret"},
)
result = await iface._send_command_rest("version", {})
assert result.get("success") is True
assert captured["url"] == f"{PROXY_BASE}/cmd"
assert captured["headers"]["Authorization"] == "Bearer secret"