Промежуточная версия
в которой надо дорабоать 1. Исправить ошибки и сделать что бы работала вторая слева вкладка. ТОесть АПИ для сервера я сделал (пока они возвращают весь список сообщений целиком - всем большим списком сообщений в канал - для мвп это устраивает,и по этому только три АПИ функции добавилось) Там какието ошибки на клиенте ( я только сгенерил код - но гдето вылетает) по UI можешь исправлять переделывать - моешь оставить калечное как есть - мне пока не важно. Важно увидить что каналы и сообщения и публичная переписка в каналах блокчейна работает 2. потестировать и сделать корректное завершение сессии (там есть глюки при завершении сесии)
This commit is contained in:
parent
78e62997d1
commit
8a83ac85d9
@ -169,7 +169,7 @@ tasks.register('deployServer', JavaExec) {
|
||||
// можно переопределить при запуске:
|
||||
// ./gradlew deployServer -Dit.remoteHost=... -Dit.wsUri=...
|
||||
dependsOn shadowJar
|
||||
systemProperty "it.remoteHost", System.getProperty("it.remoteHost", "10.147.20.7")
|
||||
systemProperty "it.remoteHost", System.getProperty("it.remoteHost", "194.87.0.247")
|
||||
systemProperty "it.remoteUser", System.getProperty("it.remoteUser", "user")
|
||||
systemProperty "it.remoteDir", System.getProperty("it.remoteDir", "/home/user/docker/shine-server")
|
||||
systemProperty "it.remoteDataDir", System.getProperty("it.remoteDataDir", "/home/user/docker/shine-server/data")
|
||||
|
||||
105
shine-UI/js/services/client-error-reporter.js
Normal file
105
shine-UI/js/services/client-error-reporter.js
Normal file
@ -0,0 +1,105 @@
|
||||
const MAX_CONTEXT_LEN = 2000;
|
||||
const RECENT_WINDOW_MS = 5000;
|
||||
|
||||
let transport = null;
|
||||
let transportDepth = 0;
|
||||
const recentFingerprints = new Map();
|
||||
|
||||
function nowTs() {
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function cleanString(value, maxLen = 1000) {
|
||||
if (value == null) return '';
|
||||
const normalized = String(value).replace(/\s+/g, ' ').trim();
|
||||
if (normalized.length <= maxLen) return normalized;
|
||||
return `${normalized.slice(0, Math.max(0, maxLen - 3))}...`;
|
||||
}
|
||||
|
||||
function stringifyContext(context) {
|
||||
if (context == null) return '';
|
||||
try {
|
||||
const raw = JSON.stringify(context);
|
||||
if (!raw) return '';
|
||||
if (raw.length <= MAX_CONTEXT_LEN) return raw;
|
||||
return `${raw.slice(0, MAX_CONTEXT_LEN - 3)}...`;
|
||||
} catch (error) {
|
||||
return cleanString(`context_json_error:${error?.message || error}`, MAX_CONTEXT_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
function makeFingerprint(payload) {
|
||||
return [
|
||||
payload.kind,
|
||||
payload.message,
|
||||
payload.sourceUrl,
|
||||
payload.lineNumber,
|
||||
payload.columnNumber,
|
||||
payload.requestOp,
|
||||
].join('|');
|
||||
}
|
||||
|
||||
function isDuplicate(fingerprint) {
|
||||
const ts = nowTs();
|
||||
const prev = recentFingerprints.get(fingerprint);
|
||||
recentFingerprints.set(fingerprint, ts);
|
||||
|
||||
for (const [key, time] of recentFingerprints.entries()) {
|
||||
if (ts - time > RECENT_WINDOW_MS) {
|
||||
recentFingerprints.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
return prev != null && ts - prev < RECENT_WINDOW_MS;
|
||||
}
|
||||
|
||||
function buildPayload(details = {}) {
|
||||
return {
|
||||
kind: cleanString(details.kind || 'client_error', 64),
|
||||
message: cleanString(details.message || details.reason || 'Unknown client error', 500),
|
||||
stack: cleanString(details.stack || details.error?.stack || '', 8000),
|
||||
sourceUrl: cleanString(details.sourceUrl || details.fileName || '', 240),
|
||||
lineNumber: Number.isFinite(details.lineNumber) ? details.lineNumber : null,
|
||||
columnNumber: Number.isFinite(details.columnNumber) ? details.columnNumber : null,
|
||||
route: cleanString(details.route || window.location?.hash || '', 200),
|
||||
href: cleanString(details.href || window.location?.href || '', 240),
|
||||
userAgent: cleanString(details.userAgent || navigator.userAgent || '', 240),
|
||||
clientTs: Number.isFinite(details.clientTs) ? details.clientTs : nowTs(),
|
||||
requestOp: cleanString(details.requestOp || '', 64),
|
||||
requestIdRef: cleanString(details.requestIdRef || '', 128),
|
||||
contextJson: stringifyContext({
|
||||
title: document.title || '',
|
||||
pageVisibility: document.visibilityState || '',
|
||||
...details.context,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function setClientErrorTransport(fn) {
|
||||
transport = typeof fn === 'function' ? fn : null;
|
||||
}
|
||||
|
||||
export async function captureClientError(details = {}) {
|
||||
const payload = buildPayload(details);
|
||||
if (!payload.message) return false;
|
||||
|
||||
const fingerprint = details.dedupeKey || makeFingerprint(payload);
|
||||
if (isDuplicate(fingerprint)) return false;
|
||||
|
||||
console.error('[client-error]', payload.kind, payload.message, details.error || '');
|
||||
|
||||
if (!transport || details.skipTransport === true || transportDepth > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
transportDepth += 1;
|
||||
await transport(payload);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn('client error transport failed', error);
|
||||
return false;
|
||||
} finally {
|
||||
transportDepth = Math.max(0, transportDepth - 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientErrorLog_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientErrorLog_Response;
|
||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* ClientErrorLog — технический endpoint для фронтенд-ошибок.
|
||||
* Не требует авторизации: клиент должен иметь возможность отправить ошибку
|
||||
* даже если логин/сессия ещё не установлены.
|
||||
*/
|
||||
public class Net_ClientErrorLog_Handler implements JsonMessageHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Net_ClientErrorLog_Handler.class);
|
||||
|
||||
@Override
|
||||
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
|
||||
Net_ClientErrorLog_Request req = (Net_ClientErrorLog_Request) baseRequest;
|
||||
|
||||
if (req.getMessage() == null || req.getMessage().isBlank()) {
|
||||
return NetExceptionResponseFactory.error(
|
||||
req,
|
||||
WireCodes.Status.BAD_REQUEST,
|
||||
"BAD_FIELDS",
|
||||
"Поле message обязательно для ClientErrorLog"
|
||||
);
|
||||
}
|
||||
|
||||
long serverTs = System.currentTimeMillis();
|
||||
String login = safe(ctx != null ? ctx.getLogin() : null);
|
||||
String sessionId = safe(ctx != null ? ctx.getSessionId() : null);
|
||||
String remote = safe(remoteAddress(ctx));
|
||||
|
||||
log.error(
|
||||
"CLIENT_FRONTEND_ERROR kind={} clientTs={} serverTs={} login={} sessionId={} remote={} route={} href={} sourceUrl={} line={} column={} requestOp={} requestIdRef={} message={} userAgent={} context={}",
|
||||
clip(req.getKind(), 64),
|
||||
req.getClientTs(),
|
||||
serverTs,
|
||||
clip(login, 64),
|
||||
clip(sessionId, 128),
|
||||
clip(remote, 128),
|
||||
clip(req.getRoute(), 200),
|
||||
clip(req.getHref(), 240),
|
||||
clip(req.getSourceUrl(), 240),
|
||||
req.getLineNumber(),
|
||||
req.getColumnNumber(),
|
||||
clip(req.getRequestOp(), 64),
|
||||
clip(req.getRequestIdRef(), 128),
|
||||
clip(req.getMessage(), 500),
|
||||
clip(req.getUserAgent(), 240),
|
||||
clip(req.getContextJson(), 2000)
|
||||
);
|
||||
|
||||
if (req.getStack() != null && !req.getStack().isBlank()) {
|
||||
log.error("CLIENT_FRONTEND_ERROR_STACK requestId={} stack={}",
|
||||
clip(req.getRequestId(), 128),
|
||||
clip(req.getStack(), 8000));
|
||||
}
|
||||
|
||||
Net_ClientErrorLog_Response resp = new Net_ClientErrorLog_Response();
|
||||
resp.setOp(req.getOp());
|
||||
resp.setRequestId(req.getRequestId());
|
||||
resp.setStatus(WireCodes.Status.OK);
|
||||
resp.setAccepted(true);
|
||||
resp.setServerTs(serverTs);
|
||||
return resp;
|
||||
}
|
||||
|
||||
private static String remoteAddress(ConnectionContext ctx) {
|
||||
if (ctx == null) return "";
|
||||
Session ws = ctx.getWsSession();
|
||||
if (ws == null) return "";
|
||||
SocketAddress remote = ws.getRemoteAddress();
|
||||
return remote != null ? remote.toString() : "";
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private static String clip(String value, int maxLen) {
|
||||
String cleaned = safe(value)
|
||||
.replace('\n', ' ')
|
||||
.replace('\r', ' ');
|
||||
if (cleaned.length() <= maxLen) {
|
||||
return cleaned;
|
||||
}
|
||||
return cleaned.substring(0, Math.max(0, maxLen - 3)) + "...";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system;
|
||||
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetServerInfo_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetServerInfo_Response;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
import utils.config.AppConfig;
|
||||
|
||||
/**
|
||||
* GetServerInfo — технический запрос без авторизации.
|
||||
* Возвращает базовую публичную информацию о сервере, чтобы клиент
|
||||
* мог проверить доступность узла и показать его в списке серверов.
|
||||
*/
|
||||
public class Net_GetServerInfo_Handler implements JsonMessageHandler {
|
||||
|
||||
private static final AppConfig CONFIG = AppConfig.getInstance();
|
||||
|
||||
@Override
|
||||
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
|
||||
Net_GetServerInfo_Request req = (Net_GetServerInfo_Request) baseRequest;
|
||||
|
||||
Net_GetServerInfo_Response resp = new Net_GetServerInfo_Response();
|
||||
resp.setOp(req.getOp());
|
||||
resp.setRequestId(req.getRequestId());
|
||||
resp.setStatus(WireCodes.Status.OK);
|
||||
resp.setUrl(CONFIG.getStringOrEmpty("server.info.url"));
|
||||
resp.setVersion(CONFIG.getStringOrEmpty("server.version"));
|
||||
resp.setPhysicalRegion(CONFIG.getStringOrEmpty("server.info.physicalRegion"));
|
||||
resp.setDescription(CONFIG.getStringOrEmpty("server.info.description"));
|
||||
resp.setOrigin(CONFIG.getStringOrEmpty("server.info.origin"));
|
||||
resp.setExtraInfo(CONFIG.getStringOrEmpty("server.info.extraInfo"));
|
||||
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
/**
|
||||
* ClientErrorLog:
|
||||
* {
|
||||
* "op": "ClientErrorLog",
|
||||
* "requestId": "req-1",
|
||||
* "payload": {
|
||||
* "kind": "global_error",
|
||||
* "message": "...",
|
||||
* "stack": "...",
|
||||
* "sourceUrl": "...",
|
||||
* "lineNumber": 10,
|
||||
* "columnNumber": 20,
|
||||
* "route": "#/channel-view/own-0",
|
||||
* "href": "https://example/#/channel-view/own-0",
|
||||
* "userAgent": "...",
|
||||
* "clientTs": 1700000000123,
|
||||
* "requestOp": "GetChannelMessages",
|
||||
* "requestIdRef": "GetChannelMessages-123",
|
||||
* "contextJson": "{...}"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public class Net_ClientErrorLog_Request extends Net_Request {
|
||||
|
||||
private String kind;
|
||||
private String message;
|
||||
private String stack;
|
||||
private String sourceUrl;
|
||||
private Integer lineNumber;
|
||||
private Integer columnNumber;
|
||||
private String route;
|
||||
private String href;
|
||||
private String userAgent;
|
||||
private Long clientTs;
|
||||
private String requestOp;
|
||||
private String requestIdRef;
|
||||
private String contextJson;
|
||||
|
||||
public String getKind() { return kind; }
|
||||
public void setKind(String kind) { this.kind = kind; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public String getStack() { return stack; }
|
||||
public void setStack(String stack) { this.stack = stack; }
|
||||
|
||||
public String getSourceUrl() { return sourceUrl; }
|
||||
public void setSourceUrl(String sourceUrl) { this.sourceUrl = sourceUrl; }
|
||||
|
||||
public Integer getLineNumber() { return lineNumber; }
|
||||
public void setLineNumber(Integer lineNumber) { this.lineNumber = lineNumber; }
|
||||
|
||||
public Integer getColumnNumber() { return columnNumber; }
|
||||
public void setColumnNumber(Integer columnNumber) { this.columnNumber = columnNumber; }
|
||||
|
||||
public String getRoute() { return route; }
|
||||
public void setRoute(String route) { this.route = route; }
|
||||
|
||||
public String getHref() { return href; }
|
||||
public void setHref(String href) { this.href = href; }
|
||||
|
||||
public String getUserAgent() { return userAgent; }
|
||||
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
|
||||
|
||||
public Long getClientTs() { return clientTs; }
|
||||
public void setClientTs(Long clientTs) { this.clientTs = clientTs; }
|
||||
|
||||
public String getRequestOp() { return requestOp; }
|
||||
public void setRequestOp(String requestOp) { this.requestOp = requestOp; }
|
||||
|
||||
public String getRequestIdRef() { return requestIdRef; }
|
||||
public void setRequestIdRef(String requestIdRef) { this.requestIdRef = requestIdRef; }
|
||||
|
||||
public String getContextJson() { return contextJson; }
|
||||
public void setContextJson(String contextJson) { this.contextJson = contextJson; }
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
public class Net_ClientErrorLog_Response extends Net_Response {
|
||||
|
||||
private long serverTs;
|
||||
private boolean accepted;
|
||||
|
||||
public long getServerTs() { return serverTs; }
|
||||
public void setServerTs(long serverTs) { this.serverTs = serverTs; }
|
||||
|
||||
public boolean isAccepted() { return accepted; }
|
||||
public void setAccepted(boolean accepted) { this.accepted = accepted; }
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
/**
|
||||
* GetServerInfo:
|
||||
* {
|
||||
* "op": "GetServerInfo",
|
||||
* "requestId": "req-1",
|
||||
* "payload": {}
|
||||
* }
|
||||
*/
|
||||
public class Net_GetServerInfo_Request extends Net_Request {
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.system.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
/**
|
||||
* Ответ GetServerInfo:
|
||||
* {
|
||||
* "op": "GetServerInfo",
|
||||
* "requestId": "req-1",
|
||||
* "status": 200,
|
||||
* "payload": {
|
||||
* "url": "...",
|
||||
* "version": "...",
|
||||
* "physicalRegion": "...",
|
||||
* "description": "...",
|
||||
* "origin": "...",
|
||||
* "extraInfo": "..."
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public class Net_GetServerInfo_Response extends Net_Response {
|
||||
|
||||
private String url;
|
||||
private String version;
|
||||
private String physicalRegion;
|
||||
private String description;
|
||||
private String origin;
|
||||
private String extraInfo;
|
||||
|
||||
public String getUrl() { return url; }
|
||||
public void setUrl(String url) { this.url = url; }
|
||||
|
||||
public String getVersion() { return version; }
|
||||
public void setVersion(String version) { this.version = version; }
|
||||
|
||||
public String getPhysicalRegion() { return physicalRegion; }
|
||||
public void setPhysicalRegion(String physicalRegion) { this.physicalRegion = physicalRegion; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getOrigin() { return origin; }
|
||||
public void setOrigin(String origin) { this.origin = origin; }
|
||||
|
||||
public String getExtraInfo() { return extraInfo; }
|
||||
public void setExtraInfo(String extraInfo) { this.extraInfo = extraInfo; }
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package server.logic.ws_protocol.JSON.utils;
|
||||
|
||||
import server.logic.ws_protocol.Base64Ws;
|
||||
|
||||
/**
|
||||
* Утилиты для строковых публичных ключей, используемых в auth/session API.
|
||||
*
|
||||
* Поддерживаемые форматы:
|
||||
* - legacy: BASE64(32 bytes)
|
||||
* - explicit: ed25519/BASE64(32 bytes)
|
||||
*/
|
||||
public final class AuthKeyUtils {
|
||||
|
||||
private AuthKeyUtils() {}
|
||||
|
||||
public static String normalize(String key, String fieldName) {
|
||||
if (key == null) throw new IllegalArgumentException(fieldName + " is null");
|
||||
String trimmed = key.trim();
|
||||
if (trimmed.isEmpty()) throw new IllegalArgumentException(fieldName + " is empty");
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public static byte[] parseEd25519PublicKey(String key, String fieldName) {
|
||||
String normalized = normalize(key, fieldName);
|
||||
|
||||
int slash = normalized.indexOf('/');
|
||||
if (slash < 0) {
|
||||
return Base64Ws.decodeLen(normalized, 32, fieldName);
|
||||
}
|
||||
|
||||
String algorithm = normalized.substring(0, slash).trim();
|
||||
String encodedKey = normalized.substring(slash + 1).trim();
|
||||
|
||||
if (algorithm.isEmpty() || encodedKey.isEmpty()) {
|
||||
throw new IllegalArgumentException(fieldName + " has bad algorithm/key format");
|
||||
}
|
||||
|
||||
if (!"ed25519".equalsIgnoreCase(algorithm)) {
|
||||
throw new UnsupportedOperationException(fieldName + " algorithm is not supported: " + algorithm);
|
||||
}
|
||||
|
||||
return Base64Ws.decodeLen(encodedKey, 32, fieldName);
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@ import java.util.Objects;
|
||||
public class IT_DeployRestartAndRunRemoteMain {
|
||||
|
||||
// ====== НАСТРОЙКИ (можно переопределять systemProperty) ======
|
||||
private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "10.147.20.7");
|
||||
private static final String REMOTE_HOST = System.getProperty("it.remoteHost", "194.87.0.247");
|
||||
private static final String REMOTE_USER = System.getProperty("it.remoteUser", "user");
|
||||
|
||||
private static final String REMOTE_DIR = System.getProperty("it.remoteDir", "/home/user/docker/shine-server");
|
||||
|
||||
94
src/test/java/test/it/cases/IT_00_TechnicalRequests.java
Normal file
94
src/test/java/test/it/cases/IT_00_TechnicalRequests.java
Normal file
@ -0,0 +1,94 @@
|
||||
package test.it.cases;
|
||||
|
||||
import test.it.utils.json.JsonBuilders;
|
||||
import test.it.utils.json.JsonParsers;
|
||||
import test.it.utils.log.TestResult;
|
||||
import test.it.utils.ws.WsSession;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* IT_00_TechnicalRequests
|
||||
* Проверяет технические запросы без авторизации:
|
||||
* - Ping
|
||||
* - GetServerInfo
|
||||
*/
|
||||
public class IT_00_TechnicalRequests {
|
||||
|
||||
public static void main(String[] args) {
|
||||
String summary = run();
|
||||
System.out.println(summary);
|
||||
}
|
||||
|
||||
public static String run() {
|
||||
TestResult r = new TestResult("IT_00_TechnicalRequests");
|
||||
Duration t = Duration.ofSeconds(5);
|
||||
|
||||
try (WsSession ws = WsSession.open()) {
|
||||
checkPing(r, ws, t);
|
||||
checkGetServerInfo(r, ws, t);
|
||||
} catch (Throwable e) {
|
||||
r.fail("IT_00_TechnicalRequests упал: " + e.getMessage());
|
||||
}
|
||||
|
||||
return r.summaryLine();
|
||||
}
|
||||
|
||||
private static void checkPing(TestResult r, WsSession ws, Duration t) {
|
||||
String resp = ws.call("Ping", JsonBuilders.ping(System.currentTimeMillis()), t);
|
||||
|
||||
if (JsonParsers.status(resp) != 200) {
|
||||
r.fail("Ping: ожидали status=200, resp=" + resp);
|
||||
fail("Ping unexpected status");
|
||||
}
|
||||
if (!Boolean.TRUE.equals(JsonParsers.ok(resp))) {
|
||||
r.fail("Ping: ожидали ok=true, resp=" + resp);
|
||||
fail("Ping unexpected ok");
|
||||
}
|
||||
|
||||
Long ts = JsonParsers.pingTs(resp);
|
||||
if (ts == null || ts <= 0) {
|
||||
r.fail("Ping: сервер не вернул payload.ts, resp=" + resp);
|
||||
fail("Ping missing ts");
|
||||
}
|
||||
|
||||
r.ok("Ping: OK, ts=" + ts);
|
||||
}
|
||||
|
||||
private static void checkGetServerInfo(TestResult r, WsSession ws, Duration t) {
|
||||
String resp = ws.call("GetServerInfo", JsonBuilders.getServerInfo(), t);
|
||||
|
||||
if (JsonParsers.status(resp) != 200) {
|
||||
r.fail("GetServerInfo: ожидали status=200, resp=" + resp);
|
||||
fail("GetServerInfo unexpected status");
|
||||
}
|
||||
if (!Boolean.TRUE.equals(JsonParsers.ok(resp))) {
|
||||
r.fail("GetServerInfo: ожидали ok=true, resp=" + resp);
|
||||
fail("GetServerInfo unexpected ok");
|
||||
}
|
||||
if (!JsonParsers.payloadIsObject(resp)) {
|
||||
r.fail("GetServerInfo: payload должен быть объектом, resp=" + resp);
|
||||
fail("GetServerInfo payload is not object");
|
||||
}
|
||||
|
||||
assertStringField(resp, "url", r);
|
||||
String version = assertStringField(resp, "version", r);
|
||||
assertStringField(resp, "physicalRegion", r);
|
||||
assertStringField(resp, "description", r);
|
||||
assertStringField(resp, "origin", r);
|
||||
assertStringField(resp, "extraInfo", r);
|
||||
|
||||
r.ok("GetServerInfo: OK, version=" + version);
|
||||
}
|
||||
|
||||
private static String assertStringField(String resp, String field, TestResult r) {
|
||||
String value = JsonParsers.payloadText(resp, field);
|
||||
if (value == null) {
|
||||
r.fail("GetServerInfo: отсутствует поле payload." + field + ", resp=" + resp);
|
||||
fail("GetServerInfo missing field: " + field);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user