Files
update-server/tests/test_admin_update_flow.py
T

193 lines
6.7 KiB
Python

import base64
import asyncio
import json
from types import SimpleNamespace
from fastapi import HTTPException
def fake_request(**kwargs):
return SimpleNamespace(
headers=kwargs.get("headers", {}),
client=SimpleNamespace(host=kwargs.get("host", "127.0.0.1")),
state=SimpleNamespace(**kwargs.get("state", {})),
)
def add_app(app_id="testapp", app_name="Test App"):
from app.api.routes import admin_app_channel
from app.schemas.app_channel import AppCreateRequest
response = admin_app_channel.admin_add_app(AppCreateRequest(app_id=app_id, app_name=app_name))
assert response["msg"] == "应用创建成功"
def create_license(app_id="testapp", channel="stable"):
from app.api.routes import admin_license
from app.schemas.license import LicenseCreateRequest
response = admin_license.admin_license_create(
LicenseCreateRequest(
app_id=app_id,
channel=channel,
customer_name="自动化测试客户",
max_devices=1,
valid_until="2099-12-31T23:59:59Z",
)
)
return response["license_key"]
def encode_device_credential(issue_response: dict) -> str:
wrapper = {
"identity_text": issue_response["identity_text"],
"signature": issue_response["signature"],
}
return base64.b64encode(json.dumps(wrapper, separators=(",", ":")).encode()).decode()
async def run_admin_login_license_and_device_issue(server_module):
async with server_module.lifespan(server_module.app):
from app.api.routes import admin_auth, admin_license, client_update
from app.schemas.admin_auth import AdminLoginRequest
from app.schemas.client_update import CheckUpdateRequest, DeviceIssueRequest
login = admin_auth.login(
AdminLoginRequest(username="admin", password="AdminPass2026"),
fake_request(headers={"user-agent": "pytest"}),
)
assert login["success"] is True
assert login["data"]["accessToken"]
add_app()
license_key = create_license()
issue_data = await client_update.issue_device(
fake_request(),
DeviceIssueRequest(
app_id="testapp",
channel="stable",
license_key=license_key,
installation_id="install-test-000001",
machine_hash="ab" * 32,
),
)
assert issue_data["identity"]["app_id"] == "testapp"
assert issue_data["identity"]["channel"] == "stable"
credential = encode_device_credential(issue_data)
assert credential
check_data = await client_update.check_update(
fake_request(state={"device_identity": issue_data["identity"]}),
CheckUpdateRequest(
app_id="testapp",
channel="stable",
current_version="1.0.0",
client_protocol=3,
),
)
assert check_data["allow_run"] is True
assert check_data["release_available"] is False
licenses = admin_license.admin_license_list(app_id="testapp")
assert licenses["list"][0]["used_devices"] == 1
def test_admin_login_license_and_device_issue(server_module):
asyncio.run(run_admin_login_license_and_device_issue(server_module))
async def run_git_tags_policy_gate(server_module, monkeypatch):
async with server_module.lifespan(server_module.app):
from app.api.routes import admin_policy, client_update, git_tags
from app.schemas.client_update import DeviceIssueRequest, GitTagsRequest
from app.schemas.policy import PolicySaveRequest
add_app("gitapp", "Git App")
license_key = create_license("gitapp", "stable")
issue_data = await client_update.issue_device(
fake_request(),
DeviceIssueRequest(
app_id="gitapp",
channel="stable",
license_key=license_key,
installation_id="install-git-tags-000001",
machine_hash="cd" * 32,
),
)
request = fake_request(state={"device_identity": issue_data["identity"]})
body = GitTagsRequest(app_id="gitapp", channel="stable")
try:
git_tags.client_git_tags(request, body)
assert False, "Git tags should be blocked before the policy is enabled"
except HTTPException as exc:
assert exc.status_code == 403
assert exc.detail["error"] == "git_tags_disabled"
admin_policy.admin_save_policy(
PolicySaveRequest(
app_id="gitapp",
channel="stable",
valid_until="2099-12-31T23:59:59Z",
git_tags_enabled=True,
)
)
monkeypatch.setattr(
git_tags,
"load_git_tags",
lambda force_refresh=False: {
"generated_at": "2026-07-20T00:00:00Z",
"repo_count": 1,
"tag_count": 2,
"tags_text": "[owner/repo]\nv1.0.0\nv1.0.1\n",
},
)
result = git_tags.client_git_tags(request, body)
assert result["repo_count"] == 1
assert result["tag_count"] == 2
assert "v1.0.1" in result["tags_text"]
def test_git_tags_policy_gate(server_module, monkeypatch):
asyncio.run(run_git_tags_policy_gate(server_module, monkeypatch))
async def run_publish_payload_creates_version(server_module, tmp_path):
async with server_module.lifespan(server_module.app):
from app.api.routes import admin_version
from app.services import publish_service
add_app("publishapp", "Publish App")
release_dir = tmp_path / "release"
bin_dir = release_dir / "bin"
bin_dir.mkdir(parents=True)
exe_path = bin_dir / "SimCAE.exe"
readme_path = release_dir / "README.txt"
exe_path.write_bytes(b"fake exe")
readme_path.write_text("hello", encoding="utf-8")
result = await publish_service.publish_payload(
{
"upload_items": [
{"path": "bin/SimCAE.exe", "local_path": exe_path},
{"path": "README.txt", "local_path": readme_path},
],
"archive_upload": None,
"archive_temp_dir": None,
"app_id": "publishapp",
"channel": "stable",
"version": "1.0.1",
"client_protocol": 3,
}
)
assert result["file_count"] == 2
versions = admin_version.admin_get_version_list("publishapp")
assert any(item["version"] == "1.0.1" for item in versions["list"])
def test_publish_payload_creates_version(server_module, tmp_path):
asyncio.run(run_publish_payload_creates_version(server_module, tmp_path))