Files
neuron-tai/tests/test_dashboard.py
2026-07-14 15:55:24 +02:00

415 lines
15 KiB
Python

"""US-035: tracker web dashboard — served from any tracker, embedded asset."""
import http.client
import json
import time
import urllib.request
from meshnet_contracts import LocalSolanaContracts
from meshnet_tracker.accounts import AccountStore
from meshnet_tracker.billing import BillingLedger
from meshnet_tracker.server import TrackerServer
PANELS = [
"Tracker hive", "Nodes & coverage", "Client balances",
"Node pending payouts", "Settlement history",
"Strikes / bans / forfeitures", "Model usage", "Call wall",
"Usage summary", "Node throughput", "Request history",
"Chat / inference",
"Console output",
"Test run status", "Tests & suites", "Test output",
]
def test_dashboard_served_with_all_panels():
"Dashboard served with all panels\n\nTags: dashboard, http"
tracker = TrackerServer(billing=BillingLedger())
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
for panel in PANELS:
assert panel in html
assert '<link rel="icon" type="image/svg+xml" href="/favicon.svg">' in html
favicon = urllib.request.urlopen(f"http://127.0.0.1:{port}/favicon.svg").read()
assert favicon.startswith(b"<svg")
assert b"meshnet" in favicon
assert "<script>" in html # polling client embedded, no build step
assert "resolveModelGroup" in html
assert "buildModelAliasMap" in html
assert "modelAliasKey(raw)" in html
assert "@media (min-width:900px)" in html
assert "grid-template-columns:repeat(4,minmax(0,1fr));" in html
assert ".wide { grid-column:span 2; }" in html
assert 'onclick="clearConsole()"' in html
assert "let consoleClearedAt = 0;" in html
finally:
tracker.stop()
def test_tracker_root_redirects_to_dashboard():
"Tracker root redirects to dashboard\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
connection = http.client.HTTPConnection("127.0.0.1", port)
connection.request("GET", "/")
response = connection.getresponse()
location = response.getheader("Location")
response.read()
connection.close()
finally:
tracker.stop()
assert response.status == 302
assert location == "/dashboard"
def test_dashboard_chat_uses_streaming_fetch():
"Dashboard chat uses streaming fetch\n\nTags: dashboard, http, streaming"
tracker = TrackerServer(billing=BillingLedger())
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
assert "stream: true" in html
assert ".body.getReader()" in html
assert '=== "[DONE]"' in html
assert 'console.error("chat stream failed", err)' in html
assert "preloadChatModels" in html
assert "renderChatModels(true)" in html
def test_dashboard_allows_admin_to_request_selected_model_load():
"Dashboard allows admin to request selected model load\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
assert 'id="request-model-load"' in html
assert "requestSelectedModelLoad" in html
assert '"/v1/models/load"' in html
assert '$("request-model-load").style.display = enabled ? "" : "none"' in html
def test_dashboard_exposes_admin_model_inventory_and_release_controls():
"Admin placement controls show the full model inventory and can release capacity."
html = _dashboard_html()
assert 'id="admin-model-placement"' in html
assert "renderAdminModelPlacement" in html
assert '"/v1/models/release"' in html
assert "requestAdminModelLoad" in html
assert "releaseAdminModel" in html
def test_network_map_includes_node_friendly_name():
"Network map includes node friendly name\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
body = json.dumps({
"endpoint": "http://127.0.0.1:9010",
"model": "stub-model",
"shard_start": 0,
"shard_end": 3,
"hardware_profile": {},
"friendly_name": "Kitchen GPU",
}).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/nodes/register",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
urllib.request.urlopen(req).read()
network = json.loads(
urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/network/map").read()
)
finally:
tracker.stop()
assert network["nodes"][0]["friendly_name"] == "Kitchen GPU"
def test_dashboard_chat_model_selector_shows_health_and_speed():
"Dashboard chat model selector shows health and speed\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
assert "chatModelHealthHp" in html
assert "modelServedCopiesFromMap" in html
assert "nodeDisplayName" in html
assert "accountDisplayName" in html
assert "saveNickname" in html
assert "chatModelTypicalTps" in html
assert "chatStreamStatsText" in html
assert "chat-stream-stats" in html
assert "chatMessageRowHtml" in html
assert "chatModelOptionLabel" in html
assert "findRoutingForModel" in html
assert "tok/s" in html
assert "toFixed(2)}HP" in html or '${copies(v)}HP' in html
def test_dashboard_chat_sessions_use_delegated_handlers():
"Dashboard chat sessions use delegated handlers\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
assert "bindChatSessionList" in html
assert "dataset.sessionId" in html
assert "dataset.deleteSession" in html
assert '[data-session-id]' in html
assert 'onclick="selectChatSession(' not in html
assert 'onclick="deleteChatSession(' not in html
def test_dashboard_incremental_refresh_helpers():
"Dashboard incremental refresh helpers\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
html = urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
assert "renderIfChanged" in html
assert "syncKeyedList" in html
assert "refreshBlocked" in html
assert "patchAccountPanelView" in html
assert "buildAccountPanelShell" in html
assert "refreshActiveTab" in html
assert "TAB_FETCHERS" in html
assert "loadAccountSummary" in html
assert "loadAccountUsage" in html
assert "fetchOverviewTab" in html
assert "pollCallWallIfIdle" in html
assert "pendingChatModelRefresh" in html
assert 'renderChatHistory(true)' in html
assert "renderChatHistory();" not in html
assert "refreshIfIdle" not in html
assert "refreshAccountIfIdle" not in html
assert "setInterval(refreshIfIdle" not in html
def test_dashboard_served_by_follower():
"A tracker that is not the leader (unreachable peers → never elected)\n\nTags: dashboard, http"
tracker = TrackerServer(
billing=BillingLedger(),
cluster_peers=["http://127.0.0.1:1", "http://127.0.0.1:2"],
)
port = tracker.start()
try:
response = urllib.request.urlopen(f"http://127.0.0.1:{port}/dashboard")
assert response.status == 200
assert "meshnet tracker" in response.read().decode()
finally:
tracker.stop()
def test_registry_wallets_endpoint():
"Registry wallets endpoint\n\nTags: dashboard, http, security, wallet"
contracts = LocalSolanaContracts()
contracts.registry.submit_stake("wallet-a", 100)
contracts.registry.record_strike("wallet-a")
accounts = AccountStore()
admin = accounts.register(email="admin@example.com", password="admin-pass-123")
session = accounts.create_session(admin["account_id"])
tracker = TrackerServer(contracts=contracts, accounts=accounts)
port = tracker.start()
try:
req = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/registry/wallets",
headers={"Authorization": f"Bearer {session}"},
)
data = json.loads(urllib.request.urlopen(req).read())
assert data["wallets"]["wallet-a"]["strike_count"] == 1
assert data["wallets"]["wallet-a"]["banned"] is False
finally:
tracker.stop()
def test_console_endpoint_exposes_tracker_events():
"Console endpoint exposes tracker events\n\nTags: dashboard, http"
tracker = TrackerServer()
port = tracker.start()
try:
body = json.dumps({
"endpoint": "http://127.0.0.1:9001",
"model": "stub-model",
"shard_start": 0,
"shard_end": 3,
"hardware_profile": {},
}).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/nodes/register",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
urllib.request.urlopen(req).read()
data = json.loads(urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/console").read())
finally:
tracker.stop()
assert any(event["message"] == "node registered" for event in data["events"])
def test_console_node_lifecycle_events_include_model_health():
"Console node lifecycle events include model health\n\nTags: dashboard, http"
tracker = TrackerServer(heartbeat_timeout=0.05)
port = tracker.start()
try:
body = json.dumps({
"endpoint": "http://127.0.0.1:9002",
"model": "console-health-test",
"hf_repo": "example/console-health-test",
"num_layers": 4,
"shard_start": 0,
"shard_end": 1,
"hardware_profile": {},
}).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/nodes/register",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
urllib.request.urlopen(req).read()
registered = json.loads(urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/console").read())
registered_event = next(
event for event in registered["events"]
if event["message"] == "node registered"
)
assert registered_event["fields"]["model_health"]["served_model_copies"] == 0.5
assert registered_event["fields"]["model_health"]["coverage_percentage"] == 50.0
time.sleep(0.06)
urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/network/map").read()
expired = json.loads(urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/console").read())
expired_event = next(
event for event in expired["events"]
if event["message"] == "node expired"
)
assert expired_event["fields"]["model_health"]["served_model_copies"] == 0.0
assert expired_event["fields"]["model_health"]["coverage_percentage"] == 0.0
finally:
tracker.stop()
def _dashboard_html(**kwargs) -> str:
tracker = TrackerServer(**kwargs)
port = tracker.start()
try:
return urllib.request.urlopen(
f"http://127.0.0.1:{port}/dashboard"
).read().decode()
finally:
tracker.stop()
def test_dashboard_testing_tab_is_admin_only():
"US-002: the Testing tab ships hidden and is only revealed for admins.\n\nTags: dashboard, http"
html = _dashboard_html()
# Tab button exists but is hidden until setAdminMode(true) reveals it.
assert '<button id="tab-testing" style="display:none"' in html
assert "switchDashboardTab('testing')" in html
assert '$("tab-testing").style.display = enabled ? "" : "none"' in html
# Every Testing panel is data-admin-only, so updateSectionVisibility()
# (adminOnly && !isAdmin -> hidden) keeps them hidden for non-admins.
for panel in ("testing-status", "testing-targets", "testing-log"):
assert f'id="{panel}"' in html
assert html.count('data-tab="testing" data-admin-only') == 3
# Selecting the tab without admin rights falls back to overview, and losing
# admin rights while on it kicks the user out.
assert 'if ((name === "admin" || name === "testing") && !isAdmin) name = "overview";' in html
assert 'if (!enabled && (dashboardTab === "admin" || dashboardTab === "testing"))' in html
def test_dashboard_testing_tab_uses_dynamic_api_and_run_controls():
"US-002: targets come from the API, never a hardcoded list.\n\nTags: dashboard, http"
html = _dashboard_html()
# Dynamic collection + run + status endpoints from US-001.
assert 'apiCall(`/v1/tests${refresh ? "?refresh=1" : ""}`)' in html
assert 'apiCall("/v1/tests/run", "POST", { target })' in html
assert 'apiCall("/v1/tests/status")' in html
assert "fetchTestingTab" in html
assert "testing: fetchTestingTab" in html # registered in TAB_FETCHERS
# Targets are rendered from the API payload (tests + suites), not literals.
assert "testCollection.suites" in html
assert "testCollection.tests" in html
assert "testCollection.test_metadata" in html
assert "testCollection.tags" in html
assert 'data-test-target="suite:all"' in html
assert 'id="testing-tag-filter"' in html
assert "Run ${esc(t.name)}" in html
assert "renderTestTargets" in html
# Run buttons are per-target and delegated; disabled while a run is active.
assert 'data-test-target="${esc(t.id)}"' in html
assert "const disabled = testRunActive() ? \" disabled\" : \"\";" in html
assert "if (testRunActive()) return;" in html # runTest() guards re-entry
assert 'button = event.target.closest("[data-test-target]")' in html
# API errors are surfaced rather than swallowed.
assert "showTestingError" in html
assert "testingErrorText" in html
assert 'id="testing-error"' in html
def test_dashboard_testing_tab_renders_status_and_bounded_log():
"US-002: state, timings, exit code, outcome and an auto-refreshing log.\n\nTags: dashboard, http"
html = _dashboard_html()
assert "renderTestRunStatus" in html
assert "renderTestLog" in html
for field in ("target", "state", "outcome", "started", "ended", "elapsed", "exit code"):
assert f'"{field}"' in html
assert "testRun.exit_code" in html
assert "testRun.started_at" in html
assert "testRun.finished_at" in html
assert "testRun.elapsed_seconds" in html
assert "fmtElapsed" in html
# Success/failure is derived from the run status, not guessed from the log.
assert '<span class="ok">success</span>' in html
assert '<span class="bad">failure</span>' in html
# Bounded log view + auto-refresh while the run is in flight.
assert "TEST_LOG_MAX_LINES" in html
assert "lines.slice(-TEST_LOG_MAX_LINES)" in html
assert "pollTestRunIfActive" in html
assert "setInterval(pollTestRunIfActive, TEST_RUN_POLL_MS)" in html