make test run faster
This commit is contained in:
2
PLAN.md
2
PLAN.md
@@ -413,7 +413,7 @@ The fix was NOT a code change but a sequencing fix in `ensureNodeSelected()`:
|
|||||||
All items from the original blocker resolved. Remaining minor issues:
|
All items from the original blocker resolved. Remaining minor issues:
|
||||||
- `listScenegraphNodes` first-call fill stability — first call may show "Loading..." for deep nodes (RemoteModel lazy-fetch behavior); second call returns the full tree. The `primeAndWait()` loop handles this transparently, but single-call would be nicer.
|
- `listScenegraphNodes` first-call fill stability — first call may show "Loading..." for deep nodes (RemoteModel lazy-fetch behavior); second call returns the full tree. The `primeAndWait()` loop handles this transparently, but single-call would be nicer.
|
||||||
- `walkItemChildren` `flagsToJson` uses hardcoded flag bit values (1,2,4,8,16,32,64) — fragile if GammaRay's `ItemFlags` enum changes. Should read from `common/quickitemmodelroles.h` if it were installed.
|
- `walkItemChildren` `flagsToJson` uses hardcoded flag bit values (1,2,4,8,16,32,64) — fragile if GammaRay's `ItemFlags` enum changes. Should read from `common/quickitemmodelroles.h` if it were installed.
|
||||||
- Full test suite takes ~8 minutes due to probe start/stop overhead and 500-1500ms settle delays per tool call. Could be optimized with module-scoped bridge fixtures and shared probe process.
|
- Full test suite ~3.5 min (session-scoped probe + module-scoped bridge + 0.5s settle delays). Connection tests still get fresh bridges per test (function-scoped).
|
||||||
|
|
||||||
## Step 7: Launch and run
|
## Step 7: Launch and run
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ before calling pytest. If you prefer to run pytest directly, set these:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -24,7 +25,6 @@ from mcp_client import McpClient
|
|||||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
# All paths read from env vars, with sensible project-local defaults.
|
# All paths read from env vars, with sensible project-local defaults.
|
||||||
# Users only need to override these when GammaRay is installed elsewhere.
|
|
||||||
GAMMARAY_BIN = Path(os.environ.get(
|
GAMMARAY_BIN = Path(os.environ.get(
|
||||||
"GAMMARAY_BIN",
|
"GAMMARAY_BIN",
|
||||||
str(PROJECT_ROOT / "install-prefix" / "bin" / "gammaray"),
|
str(PROJECT_ROOT / "install-prefix" / "bin" / "gammaray"),
|
||||||
@@ -88,9 +88,22 @@ def run_script_path() -> Path:
|
|||||||
return BRIDGE_RUN_SCRIPT
|
return BRIDGE_RUN_SCRIPT
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
def _probe_accepting_connections(timeout: int = 20) -> bool:
|
||||||
|
"""Check if the probe is accepting connections via raw TCP."""
|
||||||
|
deadline = time.monotonic() + timeout
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
try:
|
||||||
|
s = socket.create_connection(("127.0.0.1", 11732), timeout=2)
|
||||||
|
s.close()
|
||||||
|
return True
|
||||||
|
except (OSError, socket.timeout):
|
||||||
|
time.sleep(1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
def probe_process(request) -> subprocess.Popen | None:
|
def probe_process(request) -> subprocess.Popen | None:
|
||||||
"""Start a GammaRay probe process (session-scoped, one per test run)."""
|
"""Start a GammaRay probe process (session-scoped, one per entire test run)."""
|
||||||
if request.config.getoption("--no-probe"):
|
if request.config.getoption("--no-probe"):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -105,10 +118,6 @@ def probe_process(request) -> subprocess.Popen | None:
|
|||||||
env["QT_QPA_PLATFORM"] = "offscreen"
|
env["QT_QPA_PLATFORM"] = "offscreen"
|
||||||
env["LD_LIBRARY_PATH"] = GAMMARAY_LIB_DIR
|
env["LD_LIBRARY_PATH"] = GAMMARAY_LIB_DIR
|
||||||
|
|
||||||
proc = None
|
|
||||||
used_systemd = False
|
|
||||||
|
|
||||||
# Try systemd-run first for clean detachment
|
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["systemctl", "--user", "stop", "gammaray-probe-test.service"],
|
["systemctl", "--user", "stop", "gammaray-probe-test.service"],
|
||||||
capture_output=True, timeout=5,
|
capture_output=True, timeout=5,
|
||||||
@@ -133,83 +142,51 @@ def probe_process(request) -> subprocess.Popen | None:
|
|||||||
],
|
],
|
||||||
capture_output=True, text=True, timeout=10,
|
capture_output=True, text=True, timeout=10,
|
||||||
)
|
)
|
||||||
if result.returncode == 0:
|
|
||||||
used_systemd = True
|
timeout = request.config.getoption("--probe-timeout")
|
||||||
proc = subprocess.Popen(["true"]) # sentinel: probe is external
|
if not _probe_accepting_connections(timeout):
|
||||||
else:
|
|
||||||
# Fallback: direct spawn
|
# Fallback: direct spawn
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
[str(GAMMARAY_BIN), "--inject-only", "--listen", "tcp://127.0.0.1:11732",
|
[str(GAMMARAY_BIN), "--inject-only", "--listen", "tcp://127.0.0.1:11732",
|
||||||
"--injector", "preload", str(QML_RUNNER), str(TEST_QML)],
|
"--injector", "preload", str(QML_RUNNER), str(TEST_QML)],
|
||||||
env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||||
)
|
)
|
||||||
|
if not _probe_accepting_connections(timeout):
|
||||||
|
pytest.fail(f"Probe did not become ready within {timeout}s")
|
||||||
|
else:
|
||||||
|
proc = subprocess.Popen(["true"])
|
||||||
|
|
||||||
def cleanup():
|
def cleanup():
|
||||||
if proc:
|
subprocess.run(
|
||||||
proc.terminate()
|
["systemctl", "--user", "stop", "gammaray-probe-test.service"],
|
||||||
try:
|
capture_output=True, timeout=5,
|
||||||
proc.wait(timeout=5)
|
)
|
||||||
except subprocess.TimeoutExpired:
|
subprocess.run(
|
||||||
proc.kill()
|
["systemctl", "--user", "reset-failed", "gammaray-probe-test.service"],
|
||||||
if used_systemd:
|
capture_output=True, timeout=5,
|
||||||
subprocess.run(
|
)
|
||||||
["systemctl", "--user", "stop", "gammaray-probe-test.service"],
|
|
||||||
capture_output=True, timeout=5,
|
|
||||||
)
|
|
||||||
subprocess.run(
|
|
||||||
["systemctl", "--user", "reset-failed", "gammaray-probe-test.service"],
|
|
||||||
capture_output=True, timeout=5,
|
|
||||||
)
|
|
||||||
|
|
||||||
request.addfinalizer(cleanup)
|
request.addfinalizer(cleanup)
|
||||||
|
|
||||||
# Wait for probe to be ready
|
|
||||||
timeout = request.config.getoption("--probe-timeout")
|
|
||||||
deadline = time.monotonic() + timeout
|
|
||||||
while time.monotonic() < deadline:
|
|
||||||
try:
|
|
||||||
c = McpClient(bridge_path=BRIDGE_EXE)
|
|
||||||
c.initialize()
|
|
||||||
result = c.call_tool("connectProbeDefault")
|
|
||||||
c.close()
|
|
||||||
if isinstance(result, dict) and result.get("connected"):
|
|
||||||
break
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
time.sleep(1)
|
|
||||||
else:
|
|
||||||
pytest.fail(f"Probe did not become ready within {timeout}s")
|
|
||||||
|
|
||||||
return proc
|
return proc
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture(scope="module")
|
||||||
def bridge(run_script_path) -> McpClient:
|
def bridge(run_script_path) -> McpClient:
|
||||||
"""Start a fresh bridge instance per test."""
|
"""Start a bridge instance per module, reused across tests in the module."""
|
||||||
c = McpClient(bridge_path=run_script_path)
|
c = McpClient(bridge_path=run_script_path)
|
||||||
c.initialize()
|
c.initialize()
|
||||||
yield c
|
yield c
|
||||||
# Gracefully disconnect from the probe before killing the bridge.
|
|
||||||
# GammaRay's QTcpSocket::disconnectFromHost() is asynchronous — the
|
|
||||||
# Endpoint::disconnected signal (which clears m_socket) fires on a later
|
|
||||||
# event loop iteration. If we kill the bridge (SIGTERM) while m_socket is
|
|
||||||
# still set, the probe does not immediately detect the disconnection, and
|
|
||||||
# the next test's bridge cannot connect. Sending disconnectProbe() first
|
|
||||||
# triggers a clean GammaRay protocol-level shutdown that waits for the
|
|
||||||
# async disconnect to complete, releasing the probe for the next test.
|
|
||||||
try:
|
try:
|
||||||
c.call_tool("disconnectProbe", timeout=5)
|
c.call_tool("disconnectProbe", timeout=5)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # bridge may have already crashed; best-effort
|
pass
|
||||||
c.close()
|
c.close()
|
||||||
# Allow the probe to detect the disconnection before the next test
|
time.sleep(0.2)
|
||||||
# connects.
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture(scope="module")
|
||||||
def connected_bridge(bridge, probe_process) -> McpClient:
|
def connected_bridge(bridge, probe_process) -> McpClient:
|
||||||
"""Bridge connected to a running probe (retries on transient failures)."""
|
"""Bridge connected to a running probe (module-scoped, reused across tests)."""
|
||||||
if probe_process is None:
|
if probe_process is None:
|
||||||
pytest.skip("No probe available (try --no-probe to skip probe-dependent tests)")
|
pytest.skip("No probe available (try --no-probe to skip probe-dependent tests)")
|
||||||
deadline = time.monotonic() + 30
|
deadline = time.monotonic() + 30
|
||||||
@@ -219,5 +196,5 @@ def connected_bridge(bridge, probe_process) -> McpClient:
|
|||||||
if isinstance(result, dict) and result.get("connected"):
|
if isinstance(result, dict) and result.get("connected"):
|
||||||
return bridge
|
return bridge
|
||||||
last_error = result
|
last_error = result
|
||||||
time.sleep(3)
|
time.sleep(1)
|
||||||
raise AssertionError(f"Failed to connect to probe after 30s: {last_error}")
|
raise AssertionError(f"Failed to connect to probe after 30s: {last_error}")
|
||||||
@@ -1,67 +1,89 @@
|
|||||||
"""Tests for connection management tools."""
|
"""Tests for connection management tools.
|
||||||
|
|
||||||
|
These tests need function-scoped bridges because they explicitly test
|
||||||
|
connect/disconnect/reconnect lifecycle. The conftest.py module-scoped
|
||||||
|
fixtures would not work here since they share a single connection.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from mcp_client import McpClient
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def local_bridge(run_script_path) -> McpClient:
|
||||||
|
c = McpClient(bridge_path=run_script_path)
|
||||||
|
c.initialize()
|
||||||
|
yield c
|
||||||
|
try:
|
||||||
|
c.call_tool("disconnectProbe", timeout=5)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
c.close()
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def local_connected_bridge(local_bridge, probe_process) -> McpClient:
|
||||||
|
if probe_process is None:
|
||||||
|
pytest.skip("No probe available")
|
||||||
|
deadline = time.monotonic() + 30
|
||||||
|
last_error = None
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
result = local_bridge.call_tool("connectProbeDefault")
|
||||||
|
if isinstance(result, dict) and result.get("connected"):
|
||||||
|
return local_bridge
|
||||||
|
last_error = result
|
||||||
|
time.sleep(1)
|
||||||
|
raise AssertionError(f"Failed to connect to probe after 30s: {last_error}")
|
||||||
|
|
||||||
|
|
||||||
class TestConnection:
|
class TestConnection:
|
||||||
"""Verify connectProbe, probeStatus, disconnectProbe work."""
|
"""Verify connectProbe, probeStatus, disconnectProbe work."""
|
||||||
|
|
||||||
def test_tools_listed(self, bridge):
|
def test_tools_listed(self, local_bridge):
|
||||||
tools = bridge.list_tools()
|
tools = local_bridge.list_tools()
|
||||||
names = [t["name"] for t in tools]
|
names = [t["name"] for t in tools]
|
||||||
for expected in ["connectProbe", "connectProbeDefault",
|
for expected in ["connectProbe", "connectProbeDefault",
|
||||||
"disconnectProbe", "probeStatus"]:
|
"disconnectProbe", "probeStatus"]:
|
||||||
assert expected in names, f"Missing tool: {expected}"
|
assert expected in names, f"Missing tool: {expected}"
|
||||||
|
|
||||||
def test_probe_status_disconnected(self, bridge):
|
def test_probe_status_disconnected(self, local_bridge):
|
||||||
status = bridge.call_tool("probeStatus")
|
status = local_bridge.call_tool("probeStatus")
|
||||||
assert isinstance(status, dict)
|
assert isinstance(status, dict)
|
||||||
assert status.get("state") in ("disconnected", "connecting")
|
assert status.get("state") in ("disconnected", "connecting")
|
||||||
assert status.get("ready") is False
|
assert status.get("ready") is False
|
||||||
|
|
||||||
def test_connect_and_disconnect(self, bridge, probe_process):
|
def test_connect_and_disconnect(self, local_bridge, probe_process):
|
||||||
if probe_process is None:
|
if probe_process is None:
|
||||||
pytest.skip("No probe available")
|
pytest.skip("No probe available")
|
||||||
# Connect
|
result = local_bridge.call_tool("connectProbeDefault")
|
||||||
result = bridge.call_tool("connectProbeDefault")
|
|
||||||
assert isinstance(result, dict), f"connectProbeDefault failed: {result}"
|
assert isinstance(result, dict), f"connectProbeDefault failed: {result}"
|
||||||
assert result.get("connected"), f"Not connected: {result}"
|
assert result.get("connected"), f"Not connected: {result}"
|
||||||
# Verify status
|
status = local_bridge.call_tool("probeStatus")
|
||||||
status = bridge.call_tool("probeStatus")
|
|
||||||
assert isinstance(status, dict)
|
assert isinstance(status, dict)
|
||||||
assert status.get("state") == "ready"
|
assert status.get("state") == "ready"
|
||||||
assert status.get("ready") is True
|
assert status.get("ready") is True
|
||||||
assert "tcp://" in status.get("url", "")
|
assert "tcp://" in status.get("url", "")
|
||||||
# Now disconnect
|
result = local_bridge.call_tool("disconnectProbe")
|
||||||
result = bridge.call_tool("disconnectProbe")
|
|
||||||
assert isinstance(result, dict)
|
assert isinstance(result, dict)
|
||||||
assert result.get("state") == "disconnected"
|
assert result.get("state") == "disconnected"
|
||||||
|
|
||||||
def test_reconnect(self, bridge, probe_process):
|
def test_reconnect(self, local_bridge, probe_process):
|
||||||
if probe_process is None:
|
if probe_process is None:
|
||||||
pytest.skip("No probe available")
|
pytest.skip("No probe available")
|
||||||
bridge.call_tool("connectProbeDefault")
|
local_bridge.call_tool("connectProbeDefault")
|
||||||
# Disconnect
|
local_bridge.call_tool("disconnectProbe")
|
||||||
bridge.call_tool("disconnectProbe")
|
result = local_bridge.call_tool("connectProbe",
|
||||||
# Reconnect with explicit args
|
{"host": "127.0.0.1", "port": 11732})
|
||||||
result = bridge.call_tool("connectProbe",
|
|
||||||
{"host": "127.0.0.1", "port": 11732})
|
|
||||||
assert isinstance(result, dict)
|
assert isinstance(result, dict)
|
||||||
assert result.get("connected") is True
|
assert result.get("connected") is True
|
||||||
assert result.get("state") == "ready"
|
assert result.get("state") == "ready"
|
||||||
|
|
||||||
def test_connect_default_after_disconnect(self, bridge, probe_process):
|
def test_reconnect_default_after_disconnect(self, local_connected_bridge):
|
||||||
if probe_process is None:
|
local_connected_bridge.call_tool("disconnectProbe")
|
||||||
pytest.skip("No probe available")
|
result = local_connected_bridge.call_tool("connectProbeDefault")
|
||||||
bridge.call_tool("connectProbeDefault")
|
|
||||||
bridge.call_tool("disconnectProbe")
|
|
||||||
result = bridge.call_tool("connectProbeDefault")
|
|
||||||
assert isinstance(result, dict)
|
|
||||||
assert result.get("connected") is True
|
|
||||||
assert result.get("state") == "ready"
|
|
||||||
|
|
||||||
def test_connect_default_after_disconnect(self, connected_bridge):
|
|
||||||
connected_bridge.call_tool("disconnectProbe")
|
|
||||||
result = connected_bridge.call_tool("connectProbeDefault")
|
|
||||||
assert isinstance(result, dict)
|
assert isinstance(result, dict)
|
||||||
assert result.get("connected") is True
|
assert result.get("connected") is True
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
"""Tests for QML item selection and property inspection."""
|
"""Tests for QML item selection and property inspection."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
class TestItemProperties:
|
class TestItemProperties:
|
||||||
@@ -18,7 +17,7 @@ class TestItemProperties:
|
|||||||
def test_select_quick_item(self, connected_bridge):
|
def test_select_quick_item(self, connected_bridge):
|
||||||
# First get items
|
# First get items
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
assert isinstance(items, list) and len(items) > 0, "No items found"
|
assert isinstance(items, list) and len(items) > 0, "No items found"
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ class TestItemProperties:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_get_item_properties(self, connected_bridge):
|
def test_get_item_properties(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
|
|
||||||
def find_any_item(items_list):
|
def find_any_item(items_list):
|
||||||
@@ -74,7 +73,7 @@ class TestItemProperties:
|
|||||||
def test_item_has_position(self, connected_bridge):
|
def test_item_has_position(self, connected_bridge):
|
||||||
"""Verify that a Button item has x, y, width, height properties."""
|
"""Verify that a Button item has x, y, width, height properties."""
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
|
|
||||||
# Find a Button_QMLTYPE item
|
# Find a Button_QMLTYPE item
|
||||||
@@ -102,7 +101,7 @@ class TestItemProperties:
|
|||||||
def test_item_has_visual_properties(self, connected_bridge):
|
def test_item_has_visual_properties(self, connected_bridge):
|
||||||
"""Verify items have opacity, visible, z, rotation, scale."""
|
"""Verify items have opacity, visible, z, rotation, scale."""
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
|
|
||||||
def find_addr(items_list):
|
def find_addr(items_list):
|
||||||
@@ -128,7 +127,7 @@ class TestItemProperties:
|
|||||||
def test_property_model_has_groups(self, connected_bridge):
|
def test_property_model_has_groups(self, connected_bridge):
|
||||||
"""Verify items have nested property groups (background, contentItem, etc.)."""
|
"""Verify items have nested property groups (background, contentItem, etc.)."""
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
|
|
||||||
def find_button(items_list):
|
def find_button(items_list):
|
||||||
|
|||||||
@@ -30,23 +30,16 @@ class TestNavigation:
|
|||||||
|
|
||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_list_items(self, connected_bridge):
|
def test_list_items(self, connected_bridge):
|
||||||
# Select window first so item model populates
|
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
import time
|
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
assert isinstance(items, list)
|
assert isinstance(items, list)
|
||||||
# May be empty if model hasn't populated yet; that's OK
|
|
||||||
if items:
|
if items:
|
||||||
assert isinstance(items[0], dict)
|
assert isinstance(items[0], dict)
|
||||||
assert "type" in items[0]
|
assert "type" in items[0]
|
||||||
|
|
||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_list_items_with_window_count(self, connected_bridge):
|
def test_list_items_with_window_count(self, connected_bridge):
|
||||||
"""Collect all items and verify at least some are found."""
|
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
import time
|
|
||||||
time.sleep(1)
|
|
||||||
items = connected_bridge.call_tool("listQuickItems")
|
items = connected_bridge.call_tool("listQuickItems")
|
||||||
|
|
||||||
def count_all(items_list):
|
def count_all(items_list):
|
||||||
@@ -63,21 +56,15 @@ class TestNavigation:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_list_scenegraph_nodes(self, connected_bridge):
|
def test_list_scenegraph_nodes(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
import time
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
assert isinstance(nodes, list)
|
assert isinstance(nodes, list)
|
||||||
if nodes:
|
if nodes:
|
||||||
assert isinstance(nodes[0], dict)
|
assert isinstance(nodes[0], dict)
|
||||||
# Root should be "Root Node"
|
|
||||||
assert nodes[0].get("type") == "Root Node"
|
assert nodes[0].get("type") == "Root Node"
|
||||||
|
|
||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_scenegraph_has_geometry_nodes(self, connected_bridge):
|
def test_scenegraph_has_geometry_nodes(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
import time
|
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
def find_geometry(items_list):
|
def find_geometry(items_list):
|
||||||
@@ -90,4 +77,4 @@ class TestNavigation:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
geo = find_geometry(nodes)
|
geo = find_geometry(nodes)
|
||||||
assert geo is not None, "No Geometry Node found in SG tree"
|
assert geo is not None, "No Geometry Node found in SG tree"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""Tests for SceneGraph node selection and geometry/material tools."""
|
"""Tests for SceneGraph node selection and geometry/material tools."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
class TestSceneGraph:
|
class TestSceneGraph:
|
||||||
@@ -21,7 +20,7 @@ class TestSceneGraph:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_select_scenegraph_node(self, connected_bridge):
|
def test_select_scenegraph_node(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
# Find first Geometry Node
|
# Find first Geometry Node
|
||||||
@@ -47,7 +46,7 @@ class TestSceneGraph:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_get_node_vertices(self, connected_bridge):
|
def test_get_node_vertices(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
def find_geo(items_list):
|
def find_geo(items_list):
|
||||||
@@ -71,7 +70,7 @@ class TestSceneGraph:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_get_node_adjacency(self, connected_bridge):
|
def test_get_node_adjacency(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
def find_geo(items_list):
|
def find_geo(items_list):
|
||||||
@@ -94,7 +93,7 @@ class TestSceneGraph:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_get_material_shaders(self, connected_bridge):
|
def test_get_material_shaders(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
def find_geo(items_list):
|
def find_geo(items_list):
|
||||||
@@ -118,7 +117,7 @@ class TestSceneGraph:
|
|||||||
@pytest.mark.probe
|
@pytest.mark.probe
|
||||||
def test_get_material_properties(self, connected_bridge):
|
def test_get_material_properties(self, connected_bridge):
|
||||||
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
connected_bridge.call_tool("selectQuickWindow", {"index": 0})
|
||||||
time.sleep(1)
|
|
||||||
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
nodes = connected_bridge.call_tool("listScenegraphNodes")
|
||||||
|
|
||||||
def find_geo(items_list):
|
def find_geo(items_list):
|
||||||
|
|||||||
Reference in New Issue
Block a user